Browse Source

Change how local databases are loaded

This patch addresses issues with inability to define and create a new
database from scratch from configs, as well as invalid definition of
database links that required them to contain "/" character.
pull/8/head
Anton Tarasenko 3 years ago
parent
commit
ca21077fe1
  1. 57
      sources/Data/Database/DBAPI.uc
  2. 11
      sources/Data/Database/Local/LocalDatabase.uc
  3. 13
      sources/Data/Database/Tests/TEST_DatabaseCommon.uc

57
sources/Data/Database/DBAPI.uc

@ -37,10 +37,12 @@ private final function CreateLocalDBMapIfMissing()
/**
* Loads database based on the link.
*
* Links have the form of "<type>:<db_name>", followed by the JSON pointer
* (possibly empty one) to the object inside it. "<type>" can be either "local"
* or "remote" and "<db_name>" refers to the database that we are expected
* to load. This name has to consist of numbers and latin letters only.
* Links have the form of "<db_name>:" (or, optionally, "[<type>]<db_name>:"),
* followed by the JSON pointer (possibly empty one) to the object inside it.
* "<type>" can be either "local" or "remote" and is necessary only when both
* local and remote database have the same name (which should be avoided).
* "<db_name>" refers to the database that we are expected
* to load, it has to consist of numbers and latin letters only.
*
* @param databaseLink Link from which to extract database's name.
* @return Database named "<db_name>" of type "<type>" from the `databaseLink`.
@ -55,14 +57,16 @@ public final function Database Load(Text databaseLink)
}
parser = _.text.Parse(databaseLink);
// Only local DBs are supported for now!
parser.Match(P("local:"));
// So just consume this prefix, if it's present.
parser.Match(P("[local]")).Confirm();
parser.R().MUntil(databaseName, _.text.GetCharacter(":")).MatchS(":");
if (!parser.Ok())
{
parser.FreeSelf();
return none;
}
parser.MUntil(databaseName, _.text.GetCharacter("/"));
result = LoadLocal(databaseName);
parser.FreeSelf();
databaseName.FreeSelf();
return result;
}
@ -70,14 +74,18 @@ public final function Database Load(Text databaseLink)
/**
* Extracts `JSONPointer` from the database path, given by `databaseLink`.
*
* Links have the form of "<type>:<db_name>", followed by the JSON pointer
* (possibly empty one) to the object inside it. "<type>" can be either "local"
* or "remote" and "<db_name>" refers to the database that we are to use to
* get the data, specified in the link.
* Links have the form of "<db_name>:" (or, optionally, "[<type>]<db_name>:"),
* followed by the JSON pointer (possibly empty one) to the object inside it.
* "<type>" can be either "local" or "remote" and is necessary only when both
* local and remote database have the same name (which should be avoided).
* "<db_name>" refers to the database that we are expected
* to load, it has to consist of numbers and latin letters only.
* This method returns `JSONPointer` that comes after type-name pair.
*
* @param Link from which to extract `JSONPointer`.
* @return `JSONPointer` from the database link.
* Guaranteed to not be `none` if provided argument `databaseLink`
* is not `none`.
*/
public final function JSONPointer GetPointer(Text databaseLink)
{
@ -87,11 +95,11 @@ public final function JSONPointer GetPointer(Text databaseLink)
if (databaseLink == none) {
return none;
}
slashIndex = databaseLink.IndexOf(P("/"));
slashIndex = databaseLink.IndexOf(P(":"));
if (slashIndex < 0) {
return JSONPointer(_.memory.Allocate(class'JSONPointer'));
}
textPointer = databaseLink.Copy(slashIndex);
textPointer = databaseLink.Copy(slashIndex + 1);
result = _.json.Pointer(textPointer);
textPointer.FreeSelf();
return result;
@ -157,14 +165,27 @@ public final function LocalDatabaseInstance LoadLocal(Text databaseName)
// No need to check `databaseName` for being valid,
// since `Load()` will just return `none` if it is not.
newConfig = class'LocalDatabase'.static.Load(databaseName);
if (newConfig == none) return none;
if (!newConfig.HasDefinedRoot()) return none;
if (newConfig == none) {
return none;
}
if (!newConfig.HasDefinedRoot() && !newConfig.ShouldCreateIfMissing()) {
return none;
}
newLocalDBInstance = LocalDatabaseInstance(_.memory.Allocate(localDBClass));
loadedLocalDatabases.SetItem(databaseName.Copy(), newLocalDBInstance);
rootRecordName = newConfig.GetRootName();
rootRecord = class'DBRecord'.static
.LoadRecord(rootRecordName, databaseName);
if (newConfig.HasDefinedRoot())
{
rootRecordName = newConfig.GetRootName();
rootRecord = class'DBRecord'.static
.LoadRecord(rootRecordName, databaseName);
}
else
{
rootRecord = class'DBRecord'.static.NewRecord(databaseName);
rootRecordName = _.text.FromString(string(rootRecord.name));
newConfig.SetRootName(rootRecordName);
newConfig.Save();
}
newLocalDBInstance.Initialize(newConfig, rootRecord);
_.memory.Free(rootRecordName);
return newLocalDBInstance;

11
sources/Data/Database/Local/LocalDatabase.uc

@ -26,6 +26,7 @@ class LocalDatabase extends AcediaObject
config(AcediaDB);
var config private string root;
var config private bool createIfMissing;
var config private bool enforceAcediaStructure;
public final function Text GetPackageName()
@ -78,7 +79,7 @@ public final static function LocalDatabase Load(Text databaseName)
/**
* Updates `LocalDatabase` record inside it's config file. If caller
* `LocalDatabase` does not have defined root `HasDefinedRoot() == none`,
* then this method will erase it's record from the config.
* then this method will erase its record from the config.
*/
public final function Save()
{
@ -90,6 +91,11 @@ public final function Save()
}
}
public final function bool ShouldCreateIfMissing()
{
return createIfMissing;
}
/**
* Forgets all information stored in the caller `LocalDatabase` and erases it
* from the config files. After this call, creating `LocalDatabase` object
@ -104,5 +110,6 @@ public final function DeleteSelf()
defaultproperties
{
enforceAcediaStructure = false
enforceAcediaStructure = false
createIfMissing = false
}

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

@ -25,17 +25,20 @@ protected static function TESTS()
local JSONPointer pointer;
Context("Testing extracting `JSONPointer` from database link.");
Issue("`JSONPointer` is incorrectly extracted.");
pointer =
__().db.GetPointer(__().text.FromString("local:default/huh/what/is/"));
pointer = __().db.GetPointer(
__().text.FromString("[local]default:/huh/what/is/"));
TEST_ExpectNotNone(pointer);
TEST_ExpectTrue(pointer.ToText().ToString() == "/huh/what/is/");
pointer = __().db.GetPointer(__().text.FromString("remote:db"));
pointer = __().db.GetPointer(__().text.FromString("[remote]db:"));
TEST_ExpectNotNone(pointer);
TEST_ExpectTrue(pointer.ToText().ToString() == "");
pointer = __().db.GetPointer(__().text.FromString("remote:"));
pointer = __().db.GetPointer(__().text.FromString("[remote]:"));
TEST_ExpectNotNone(pointer);
TEST_ExpectTrue(pointer.ToText().ToString() == "");
pointer = __().db.GetPointer(__().text.FromString("/just/a/pointer"));
pointer = __().db.GetPointer(__().text.FromString("db:/just/a/pointer"));
TEST_ExpectNotNone(pointer);
TEST_ExpectTrue(pointer.ToText().ToString() == "/just/a/pointer");
pointer = __().db.GetPointer(__().text.FromString(":/just/a/pointer"));
TEST_ExpectNotNone(pointer);
TEST_ExpectTrue(pointer.ToText().ToString() == "/just/a/pointer");
}

Loading…
Cancel
Save