Browse Source

Add support for "-" JSON index to db operations

pull/8/head
Anton Tarasenko 3 years ago
parent
commit
627d3db6f2
  1. 5
      sources/Data/Database/Database.uc
  2. 32
      sources/Data/Database/Local/DBRecord.uc
  3. 13
      sources/Data/Database/Tests/TEST_LocalDatabase.uc

5
sources/Data/Database/Database.uc

@ -104,6 +104,8 @@ public function DBReadTask ReadData(
* *
* @param pointer JSON pointer to the location in the database, where `data` * @param pointer JSON pointer to the location in the database, where `data`
* should be written (as a JSON value). * should be written (as a JSON value).
* This JSON pointer can make use of "-" index for JSON arrays that allows
* appending data at their end.
* `none` is always treated as an invalid JSON pointer. * `none` is always treated as an invalid JSON pointer.
* @param data Data that needs to be written at the specified location * @param data Data that needs to be written at the specified location
* inside the database. For method to succeed this object needs to have * inside the database. For method to succeed this object needs to have
@ -273,6 +275,9 @@ public function DBKeysTask GetDataKeys(JSONPointer pointer)
* @param pointer JSON pointer to the location in the database, where * @param pointer JSON pointer to the location in the database, where
* data should be incremented (by `increment`). * data should be incremented (by `increment`).
* `none` is always treated as an invalid JSON pointer. * `none` is always treated as an invalid JSON pointer.
* This JSON pointer can make use of "-" index for JSON arrays that allows
* to add `none` value at the end of that array and then "increment" it
* with `increment` parameter.
* @param increment JSON-compatible value to be used as an increment for * @param increment JSON-compatible value to be used as an increment for
* the data at the specified location inside the database. * the data at the specified location inside the database.
* @return Task object that corresponds to this `IncrementData()` call. * @return Task object that corresponds to this `IncrementData()` call.

32
sources/Data/Database/Local/DBRecord.uc

@ -133,8 +133,9 @@ struct StorageItem
}; };
var private config array<StorageItem> storage; var private config array<StorageItem> storage;
var private const int LATIN_LETTERS_AMOUNT; var private const int LATIN_LETTERS_AMOUNT;
var private const int LOWER_A_CODEPOINT, UPPER_A_CODEPOINT; var private const int LOWER_A_CODEPOINT, UPPER_A_CODEPOINT;
var private const string JSONPOINTER_NEW_ARRAY_ELEMENT;
/** /**
* Since `DBRecord` represents JSON array or object, we can use * Since `DBRecord` represents JSON array or object, we can use
@ -422,16 +423,18 @@ public final function bool SaveObject(
return false; return false;
} }
directContainer = pointer.record; directContainer = pointer.record;
itemKey = __().text.ToString(jsonPointer.Pop(true));
if (directContainer.isJSONArray) if (directContainer.isJSONArray)
{ {
index = jsonPointer.PopNumeric(true); index = jsonPointer.PopNumeric(true);
if (index < 0 && itemKey == JSONPOINTER_NEW_ARRAY_ELEMENT) {
index = directContainer.GetStorageLength();
}
if (index < 0) { if (index < 0) {
return false; return false;
} }
} }
else else {
{
itemKey = __().text.ToString(jsonPointer.Pop(true));
index = directContainer.FindItem(itemKey); index = directContainer.FindItem(itemKey);
} }
directContainer.SetItem(index, ConvertObjectToItem(newItem), itemKey); directContainer.SetItem(index, ConvertObjectToItem(newItem), itemKey);
@ -624,16 +627,18 @@ public final function Database.DBQueryResult IncrementObject(
return DBR_InvalidPointer; return DBR_InvalidPointer;
} }
directContainer = pointer.record; directContainer = pointer.record;
itemKey = __().text.ToString(jsonPointer.Pop(true));
if (directContainer.isJSONArray) if (directContainer.isJSONArray)
{ {
index = jsonPointer.PopNumeric(true); index = jsonPointer.PopNumeric(true);
if (index < 0 && itemKey == JSONPOINTER_NEW_ARRAY_ELEMENT) {
index = directContainer.GetStorageLength();
}
if (index < 0) { if (index < 0) {
return DBR_InvalidPointer; return DBR_InvalidPointer;
} }
} }
else else {
{
itemKey = __().text.ToString(jsonPointer.Pop(true));
index = directContainer.FindItem(itemKey); index = directContainer.FindItem(itemKey);
} }
if (directContainer.IncrementItem(index, object, itemKey)) { if (directContainer.IncrementItem(index, object, itemKey)) {
@ -752,6 +757,8 @@ private final function bool IncrementItem(
} }
if (IncrementItemByObject(itemToIncrement, object)) if (IncrementItemByObject(itemToIncrement, object))
{ {
// Increment object cannot overwrite existing `DBRecord` with
// other value, so it's safe to skip cleaning check
storage[index] = itemToIncrement; storage[index] = itemToIncrement;
storage[index].k = itemName; storage[index].k = itemName;
return true; return true;
@ -1154,7 +1161,10 @@ private final function bool ReadNumericObjectInto(
// Add storing bytes // Add storing bytes
defaultproperties defaultproperties
{ {
LATIN_LETTERS_AMOUNT = 26 LATIN_LETTERS_AMOUNT = 26
LOWER_A_CODEPOINT = 97 LOWER_A_CODEPOINT = 97
UPPER_A_CODEPOINT = 65 UPPER_A_CODEPOINT = 65
// JSON Pointers allow using "-" as an indicator that element must be
// added at the end of the array
JSONPOINTER_NEW_ARRAY_ELEMENT = "-"
} }

13
sources/Data/Database/Tests/TEST_LocalDatabase.uc

@ -710,6 +710,7 @@ protected static function SubTest_WritingArrayIndicies(LocalDatabaseInstance db)
db.WriteData(__().json.Pointer(P("")), templateObject); db.WriteData(__().json.Pointer(P("")), templateObject);
db.WriteData(__().json.Pointer(P("/A")), templateArray); db.WriteData(__().json.Pointer(P("/A")), templateArray);
db.WriteData(__().json.Pointer(P("/A/100")), __().box.int(-342)); db.WriteData(__().json.Pointer(P("/A/100")), __().box.int(-342));
db.WriteData(__().json.Pointer(P("/A/-")), __().box.int(95));
Issue("Database allows writing data into negative JSON array indices."); Issue("Database allows writing data into negative JSON array indices.");
writeTask = db.WriteData(__().json.Pointer(P("/A/-5")), __().box.int(1202)); writeTask = db.WriteData(__().json.Pointer(P("/A/-5")), __().box.int(1202));
@ -717,12 +718,13 @@ protected static function SubTest_WritingArrayIndicies(LocalDatabaseInstance db)
writeTask.TryCompleting(); writeTask.TryCompleting();
Issue("Database cannot extend stored JSON array's length by assigning to" Issue("Database cannot extend stored JSON array's length by assigning to"
@ "the out-of-bounds index."); @ "the out-of-bounds index or \"-\".");
ReadFromDB(db, "/A"); ReadFromDB(db, "/A");
resultArray = DynamicArray(default.resultObject); resultArray = DynamicArray(default.resultObject);
TEST_ExpectTrue(resultArray.GetLength() == 101); TEST_ExpectTrue(resultArray.GetLength() == 102);
TEST_ExpectNone(resultArray.GetItem(99)); TEST_ExpectNone(resultArray.GetItem(99));
TEST_ExpectTrue(resultArray.GetInt(100) == -342); TEST_ExpectTrue(resultArray.GetInt(100) == -342);
TEST_ExpectTrue(resultArray.GetInt(101) == 95);
TEST_ExpectTrue(resultArray.GetBool(0)); TEST_ExpectTrue(resultArray.GetBool(0));
} }
@ -1221,14 +1223,17 @@ protected static function SubTest_IncrementMissing(LocalDatabaseInstance db)
task.connect = DBIncrementHandler; task.connect = DBIncrementHandler;
task.TryCompleting(); task.TryCompleting();
TEST_ExpectTrue(default.resultType == DBR_Success); TEST_ExpectTrue(default.resultType == DBR_Success);
task = db.IncrementData(__().json.Pointer(P("/B/A/1//10")), none); db.IncrementData(__().json.Pointer(P("/B/A/1//10")), none);
task = db.IncrementData(__().json.Pointer(P("/B/A/1//-")),
__().box.int(85));
task.connect = DBIncrementHandler; task.connect = DBIncrementHandler;
task.TryCompleting(); task.TryCompleting();
TEST_ExpectTrue(default.resultType == DBR_Success); TEST_ExpectTrue(default.resultType == DBR_Success);
db.CheckDataType(__().json.Pointer(P("/L"))).connect = DBCheckHandler; db.CheckDataType(__().json.Pointer(P("/L"))).connect = DBCheckHandler;
ReadFromDB(db, "/B/A/1/"); ReadFromDB(db, "/B/A/1/");
TEST_ExpectTrue(default.resultDataType == JSON_Number); TEST_ExpectTrue(default.resultDataType == JSON_Number);
TEST_ExpectTrue(DynamicArray(default.resultObject).GetLength() == 11); TEST_ExpectTrue(DynamicArray(default.resultObject).GetLength() == 12);
TEST_ExpectTrue(DynamicArray(default.resultObject).GetInt(11) == 85);
} }
defaultproperties defaultproperties

Loading…
Cancel
Save