v3 RC1 #1

Merged
danieljsummers merged 25 commits from merge-projects into main 2024-01-06 20:51:49 +00:00
7 changed files with 2037 additions and 1257 deletions
Showing only changes of commit 18ec31d16b - Show all commits

View File

@ -18,11 +18,13 @@ module Configuration =
let mutable private dataSourceValue : NpgsqlDataSource option = None let mutable private dataSourceValue : NpgsqlDataSource option = None
/// Register a data source to use for query execution (disposes the current one if it exists) /// Register a data source to use for query execution (disposes the current one if it exists)
[<CompiledName "UseDataSource">]
let useDataSource source = let useDataSource source =
if Option.isSome dataSourceValue then dataSourceValue.Value.Dispose() if Option.isSome dataSourceValue then dataSourceValue.Value.Dispose()
dataSourceValue <- Some source dataSourceValue <- Some source
/// Retrieve the currently configured data source /// Retrieve the currently configured data source
[<CompiledName "DataSource">]
let dataSource () = let dataSource () =
match dataSourceValue with match dataSourceValue with
| Some source -> source | Some source -> source
@ -85,8 +87,8 @@ module Query =
Query.Definition.ensureTableFor name "JSONB" Query.Definition.ensureTableFor name "JSONB"
/// SQL statement to create an index on JSON documents in the specified table /// SQL statement to create an index on JSON documents in the specified table
[<CompiledName "EnsureJsonIndex">] [<CompiledName "EnsureDocumentIndex">]
let ensureJsonIndex (name: string) idxType = let ensureDocumentIndex (name: string) idxType =
let extraOps = match idxType with Full -> "" | Optimized -> " jsonb_path_ops" let extraOps = match idxType with Full -> "" | Optimized -> " jsonb_path_ops"
let tableName = name.Split '.' |> Array.last let tableName = name.Split '.' |> Array.last
$"CREATE INDEX IF NOT EXISTS idx_{tableName}_document ON {name} USING GIN (data{extraOps})" $"CREATE INDEX IF NOT EXISTS idx_{tableName}_document ON {name} USING GIN (data{extraOps})"
@ -266,9 +268,9 @@ module WithProps =
} }
/// Create an index on documents in the specified table /// Create an index on documents in the specified table
[<CompiledName "EnsureJsonIndex">] [<CompiledName "EnsureDocumentIndex">]
let ensureJsonIndex name idxType sqlProps = let ensureDocumentIndex name idxType sqlProps =
Custom.nonQuery (Query.Definition.ensureJsonIndex name idxType) [] sqlProps Custom.nonQuery (Query.Definition.ensureDocumentIndex name idxType) [] sqlProps
/// Create an index on field(s) within documents in the specified table /// Create an index on field(s) within documents in the specified table
[<CompiledName "EnsureFieldIndex">] [<CompiledName "EnsureFieldIndex">]
@ -549,9 +551,9 @@ module Definition =
WithProps.Definition.ensureTable name (fromDataSource ()) WithProps.Definition.ensureTable name (fromDataSource ())
/// Create an index on documents in the specified table /// Create an index on documents in the specified table
[<CompiledName "EnsureJsonIndex">] [<CompiledName "EnsureDocumentIndex">]
let ensureJsonIndex name idxType = let ensureDocumentIndex name idxType =
WithProps.Definition.ensureJsonIndex name idxType (fromDataSource ()) WithProps.Definition.ensureDocumentIndex name idxType (fromDataSource ())
/// Create an index on field(s) within documents in the specified table /// Create an index on field(s) within documents in the specified table
[<CompiledName "EnsureFieldIndex">] [<CompiledName "EnsureFieldIndex">]

View File

@ -23,218 +23,216 @@ public static class CommonCSharpTests
/// Unit tests /// Unit tests
/// </summary> /// </summary>
[Tests] [Tests]
public static Test Unit = public static readonly Test Unit = TestList("Common.C# Unit", new[]
TestList("Common.C# Unit", new[] {
{ TestSequenced(
TestSequenced( TestList("Configuration", new[]
TestList("Configuration", new[]
{
TestCase("UseSerializer succeeds", () =>
{
try
{
Configuration.UseSerializer(new TestSerializer());
var serialized = Configuration.Serializer().Serialize(new SubDocument
{
Foo = "howdy",
Bar = "bye"
});
Expect.equal(serialized, "{\"Overridden\":true}", "Specified serializer was not used");
var deserialized = Configuration.Serializer()
.Deserialize<object>("{\"Something\":\"here\"}");
Expect.isNull(deserialized, "Specified serializer should have returned null");
}
finally
{
Configuration.UseSerializer(DocumentSerializer.Default);
}
}),
TestCase("Serializer returns configured serializer", () =>
{
Expect.isTrue(ReferenceEquals(DocumentSerializer.Default, Configuration.Serializer()),
"Serializer should have been the same");
}),
TestCase("UseIdField / IdField succeeds", () =>
{
try
{
Expect.equal(Configuration.IdField(), "Id",
"The default configured ID field was incorrect");
Configuration.UseIdField("id");
Expect.equal(Configuration.IdField(), "id", "UseIdField did not set the ID field");
}
finally
{
Configuration.UseIdField("Id");
}
})
})),
TestList("Op", new[]
{ {
TestCase("EQ succeeds", () => TestCase("UseSerializer succeeds", () =>
{ {
Expect.equal(Op.EQ.ToString(), "=", "The equals operator was not correct"); try
{
Configuration.UseSerializer(new TestSerializer());
var serialized = Configuration.Serializer().Serialize(new SubDocument
{
Foo = "howdy",
Bar = "bye"
});
Expect.equal(serialized, "{\"Overridden\":true}", "Specified serializer was not used");
var deserialized = Configuration.Serializer()
.Deserialize<object>("{\"Something\":\"here\"}");
Expect.isNull(deserialized, "Specified serializer should have returned null");
}
finally
{
Configuration.UseSerializer(DocumentSerializer.Default);
}
}), }),
TestCase("GT succeeds", () => TestCase("Serializer returns configured serializer", () =>
{ {
Expect.equal(Op.GT.ToString(), ">", "The greater than operator was not correct"); Expect.isTrue(ReferenceEquals(DocumentSerializer.Default, Configuration.Serializer()),
"Serializer should have been the same");
}), }),
TestCase("GE succeeds", () => TestCase("UseIdField / IdField succeeds", () =>
{ {
Expect.equal(Op.GE.ToString(), ">=", "The greater than or equal to operator was not correct"); try
{
Expect.equal(Configuration.IdField(), "Id",
"The default configured ID field was incorrect");
Configuration.UseIdField("id");
Expect.equal(Configuration.IdField(), "id", "UseIdField did not set the ID field");
}
finally
{
Configuration.UseIdField("Id");
}
})
})),
TestList("Op", new[]
{
TestCase("EQ succeeds", () =>
{
Expect.equal(Op.EQ.ToString(), "=", "The equals operator was not correct");
}),
TestCase("GT succeeds", () =>
{
Expect.equal(Op.GT.ToString(), ">", "The greater than operator was not correct");
}),
TestCase("GE succeeds", () =>
{
Expect.equal(Op.GE.ToString(), ">=", "The greater than or equal to operator was not correct");
}),
TestCase("LT succeeds", () =>
{
Expect.equal(Op.LT.ToString(), "<", "The less than operator was not correct");
}),
TestCase("LE succeeds", () =>
{
Expect.equal(Op.LE.ToString(), "<=", "The less than or equal to operator was not correct");
}),
TestCase("NE succeeds", () =>
{
Expect.equal(Op.NE.ToString(), "<>", "The not equal to operator was not correct");
}),
TestCase("EX succeeds", () =>
{
Expect.equal(Op.EX.ToString(), "IS NOT NULL", "The \"exists\" operator was not correct");
}),
TestCase("NEX succeeds", () =>
{
Expect.equal(Op.NEX.ToString(), "IS NULL", "The \"not exists\" operator was not correct");
})
}),
TestList("Query", new[]
{
TestCase("SelectFromTable succeeds", () =>
{
Expect.equal(Query.SelectFromTable("test.table"), "SELECT data FROM test.table",
"SELECT statement not correct");
}),
TestCase("WhereById succeeds", () =>
{
Expect.equal(Query.WhereById("@id"), "data ->> 'Id' = @id", "WHERE clause not correct");
}),
TestList("WhereByField", new[]
{
TestCase("succeeds when a logical operator is passed", () =>
{
Expect.equal(Query.WhereByField("theField", Op.GT, "@test"), "data ->> 'theField' > @test",
"WHERE clause not correct");
}), }),
TestCase("LT succeeds", () => TestCase("succeeds when an existence operator is passed", () =>
{ {
Expect.equal(Op.LT.ToString(), "<", "The less than operator was not correct"); Expect.equal(Query.WhereByField("thatField", Op.NEX, ""), "data ->> 'thatField' IS NULL",
}), "WHERE clause not correct");
TestCase("LE succeeds", () =>
{
Expect.equal(Op.LE.ToString(), "<=", "The less than or equal to operator was not correct");
}),
TestCase("NE succeeds", () =>
{
Expect.equal(Op.NE.ToString(), "<>", "The not equal to operator was not correct");
}),
TestCase("EX succeeds", () =>
{
Expect.equal(Op.EX.ToString(), "IS NOT NULL", "The \"exists\" operator was not correct");
}),
TestCase("NEX succeeds", () =>
{
Expect.equal(Op.NEX.ToString(), "IS NULL", "The \"not exists\" operator was not correct");
}) })
}), }),
TestList("Query", new[] TestList("Definition", new[]
{ {
TestCase("SelectFromTable succeeds", () => TestCase("EnsureTableFor succeeds", () =>
{ {
Expect.equal(Query.SelectFromTable("test.table"), "SELECT data FROM test.table", Expect.equal(Query.Definition.EnsureTableFor("my.table", "JSONB"),
"SELECT statement not correct"); "CREATE TABLE IF NOT EXISTS my.table (data JSONB NOT NULL)",
"CREATE TABLE statement not constructed correctly");
}), }),
TestCase("WhereById succeeds", () => TestList("EnsureKey", new[]
{ {
Expect.equal(Query.WhereById("@id"), "data ->> 'Id' = @id", "WHERE clause not correct"); TestCase("succeeds when a schema is present", () =>
}),
TestList("WhereByField", new[]
{
TestCase("succeeds when a logical operator is passed", () =>
{ {
Expect.equal(Query.WhereByField("theField", Op.GT, "@test"), "data ->> 'theField' > @test", Expect.equal(Query.Definition.EnsureKey("test.table"),
"WHERE clause not correct"); "CREATE UNIQUE INDEX IF NOT EXISTS idx_table_key ON test.table ((data ->> 'Id'))",
"CREATE INDEX for key statement with schema not constructed correctly");
}), }),
TestCase("succeeds when an existence operator is passed", () => TestCase("succeeds when a schema is not present", () =>
{ {
Expect.equal(Query.WhereByField("thatField", Op.NEX, ""), "data ->> 'thatField' IS NULL", Expect.equal(Query.Definition.EnsureKey("table"),
"WHERE clause not correct"); "CREATE UNIQUE INDEX IF NOT EXISTS idx_table_key ON table ((data ->> 'Id'))",
"CREATE INDEX for key statement without schema not constructed correctly");
}) })
}), }),
TestList("Definition", new[] TestCase("EnsureIndexOn succeeds for multiple fields and directions", () =>
{ {
TestCase("EnsureTableFor succeeds", () => Expect.equal(
{ Query.Definition.EnsureIndexOn("test.table", "gibberish",
Expect.equal(Query.Definition.EnsureTableFor("my.table", "JSONB"), new[] { "taco", "guac DESC", "salsa ASC" }),
"CREATE TABLE IF NOT EXISTS my.table (data JSONB NOT NULL)", "CREATE INDEX IF NOT EXISTS idx_table_gibberish ON test.table "
"CREATE TABLE statement not constructed correctly"); + "((data ->> 'taco'), (data ->> 'guac') DESC, (data ->> 'salsa') ASC)",
}), "CREATE INDEX for multiple field statement incorrect");
TestList("EnsureKey", new[] })
{ }),
TestCase("succeeds when a schema is present", () => TestCase("Insert succeeds", () =>
{ {
Expect.equal(Query.Definition.EnsureKey("test.table"), Expect.equal(Query.Insert("tbl"), "INSERT INTO tbl VALUES (@data)", "INSERT statement not correct");
"CREATE UNIQUE INDEX IF NOT EXISTS idx_table_key ON test.table ((data ->> 'Id'))", }),
"CREATE INDEX for key statement with schema not constructed correctly"); TestCase("Save succeeds", () =>
}), {
TestCase("succeeds when a schema is not present", () => Expect.equal(Query.Save("tbl"),
{ $"INSERT INTO tbl VALUES (@data) ON CONFLICT ((data ->> 'Id')) DO UPDATE SET data = EXCLUDED.data",
Expect.equal(Query.Definition.EnsureKey("table"), "INSERT ON CONFLICT UPDATE statement not correct");
"CREATE UNIQUE INDEX IF NOT EXISTS idx_table_key ON table ((data ->> 'Id'))", }),
"CREATE INDEX for key statement without schema not constructed correctly"); TestList("Count", new[]
}) {
}), TestCase("All succeeds", () =>
TestCase("EnsureIndexOn succeeds for multiple fields and directions", () => {
{ Expect.equal(Query.Count.All("tbl"), "SELECT COUNT(*) AS it FROM tbl", "Count query not correct");
Expect.equal(
Query.Definition.EnsureIndexOn("test.table", "gibberish",
new[] { "taco", "guac DESC", "salsa ASC" }),
"CREATE INDEX IF NOT EXISTS idx_table_gibberish ON test.table "
+ "((data ->> 'taco'), (data ->> 'guac') DESC, (data ->> 'salsa') ASC)",
"CREATE INDEX for multiple field statement incorrect");
})
}), }),
TestCase("Insert succeeds", () => TestCase("ByField succeeds", () =>
{ {
Expect.equal(Query.Insert("tbl"), "INSERT INTO tbl VALUES (@data)", "INSERT statement not correct"); Expect.equal(Query.Count.ByField("tbl", "thatField", Op.EQ),
"SELECT COUNT(*) AS it FROM tbl WHERE data ->> 'thatField' = @field",
"JSON field text comparison count query not correct");
})
}),
TestList("Exists", new[]
{
TestCase("ById succeeds", () =>
{
Expect.equal(Query.Exists.ById("tbl"),
"SELECT EXISTS (SELECT 1 FROM tbl WHERE data ->> 'Id' = @id) AS it",
"ID existence query not correct");
}), }),
TestCase("Save succeeds", () => TestCase("ByField succeeds", () =>
{ {
Expect.equal(Query.Save("tbl"), Expect.equal(Query.Exists.ByField("tbl", "Test", Op.LT),
$"INSERT INTO tbl VALUES (@data) ON CONFLICT ((data ->> 'Id')) DO UPDATE SET data = EXCLUDED.data", "SELECT EXISTS (SELECT 1 FROM tbl WHERE data ->> 'Test' < @field) AS it",
"INSERT ON CONFLICT UPDATE statement not correct"); "JSON field text comparison exists query not correct");
})
}),
TestList("Find", new[]
{
TestCase("ById succeeds", () =>
{
Expect.equal(Query.Find.ById("tbl"), "SELECT data FROM tbl WHERE data ->> 'Id' = @id",
"SELECT by ID query not correct");
}), }),
TestList("Count", new[] TestCase("ByField succeeds", () =>
{ {
TestCase("All succeeds", () => Expect.equal(Query.Find.ByField("tbl", "Golf", Op.GE),
{ "SELECT data FROM tbl WHERE data ->> 'Golf' >= @field",
Expect.equal(Query.Count.All("tbl"), "SELECT COUNT(*) AS it FROM tbl", "SELECT by JSON comparison query not correct");
"Count query not correct"); })
}), }),
TestCase("ByField succeeds", () => TestCase("Update.Full succeeds", () =>
{ {
Expect.equal(Query.Count.ByField("tbl", "thatField", Op.EQ), Expect.equal(Query.Update.Full("tbl"), "UPDATE tbl SET data = @data WHERE data ->> 'Id' = @id",
"SELECT COUNT(*) AS it FROM tbl WHERE data ->> 'thatField' = @field", "UPDATE full statement not correct");
"JSON field text comparison count query not correct"); }),
}) TestList("Delete", new[]
{
TestCase("ById succeeds", () =>
{
Expect.equal(Query.Delete.ById("tbl"), "DELETE FROM tbl WHERE data ->> 'Id' = @id",
"DELETE by ID query not correct");
}), }),
TestList("Exists", new[] TestCase("ByField succeeds", () =>
{ {
TestCase("ById succeeds", () => Expect.equal(Query.Delete.ByField("tbl", "gone", Op.NEX),
{ "DELETE FROM tbl WHERE data ->> 'gone' IS NULL",
Expect.equal(Query.Exists.ById("tbl"), "DELETE by JSON comparison query not correct");
"SELECT EXISTS (SELECT 1 FROM tbl WHERE data ->> 'Id' = @id) AS it",
"ID existence query not correct");
}),
TestCase("ByField succeeds", () =>
{
Expect.equal(Query.Exists.ByField("tbl", "Test", Op.LT),
"SELECT EXISTS (SELECT 1 FROM tbl WHERE data ->> 'Test' < @field) AS it",
"JSON field text comparison exists query not correct");
})
}),
TestList("Find", new[]
{
TestCase("ById succeeds", () =>
{
Expect.equal(Query.Find.ById("tbl"), "SELECT data FROM tbl WHERE data ->> 'Id' = @id",
"SELECT by ID query not correct");
}),
TestCase("ByField succeeds", () =>
{
Expect.equal(Query.Find.ByField("tbl", "Golf", Op.GE),
"SELECT data FROM tbl WHERE data ->> 'Golf' >= @field",
"SELECT by JSON comparison query not correct");
})
}),
TestCase("Update.Full succeeds", () =>
{
Expect.equal(Query.Update.Full("tbl"), "UPDATE tbl SET data = @data WHERE data ->> 'Id' = @id",
"UPDATE full statement not correct");
}),
TestList("Delete", new[]
{
TestCase("ById succeeds", () =>
{
Expect.equal(Query.Delete.ById("tbl"), "DELETE FROM tbl WHERE data ->> 'Id' = @id",
"DELETE by ID query not correct");
}),
TestCase("ByField succeeds", () =>
{
Expect.equal(Query.Delete.ByField("tbl", "gone", Op.NEX),
"DELETE FROM tbl WHERE data ->> 'gone' IS NULL",
"DELETE by JSON comparison query not correct");
})
}) })
}) })
}); })
});
} }

File diff suppressed because it is too large Load Diff

View File

@ -137,7 +137,7 @@ public static class PostgresDb
Sql.executeNonQuery(Sql.query(Postgres.Query.Definition.EnsureTable(TableName), sqlProps)); Sql.executeNonQuery(Sql.query(Postgres.Query.Definition.EnsureTable(TableName), sqlProps));
Sql.executeNonQuery(Sql.query(Query.Definition.EnsureKey(TableName), sqlProps)); Sql.executeNonQuery(Sql.query(Query.Definition.EnsureKey(TableName), sqlProps));
Postgres.Configuration.useDataSource(MkDataSource(database.ConnectionString)); Postgres.Configuration.UseDataSource(MkDataSource(database.ConnectionString));
return new ThrowawayPostgresDb(database); return new ThrowawayPostgresDb(database);
} }

View File

@ -14,498 +14,492 @@ public static class SqliteCSharpExtensionTests
{ {
private static Task LoadDocs() => SqliteCSharpTests.LoadDocs(); private static Task LoadDocs() => SqliteCSharpTests.LoadDocs();
/// <summary>
/// Integration tests for the SQLite extension methods
/// </summary>
[Tests] [Tests]
public static Test Integration = public static readonly Test Integration = TestList("Extensions", new[]
TestList("Extensions", new[] {
TestList("CustomSingle", new[]
{ {
TestList("CustomSingle", new[] TestCase("succeeds when a row is found", async () =>
{
TestCase("succeeds when a row is found", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
var doc = await conn.CustomSingle(
$"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'Id' = @id",
new[] { Parameters.Id("one") }, Results.FromData<JsonDocument>);
Expect.isNotNull(doc, "There should have been a document returned");
Expect.equal(doc!.Id, "one", "The incorrect document was returned");
}),
TestCase("succeeds when a row is not found", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
var doc = await conn.CustomSingle(
$"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'Id' = @id",
new[] { Parameters.Id("eighty") }, Results.FromData<JsonDocument>);
Expect.isNull(doc, "There should not have been a document returned");
})
}),
TestList("CustomList", new[]
{
TestCase("succeeds when data is found", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
var docs = await conn.CustomList(Query.SelectFromTable(SqliteDb.TableName), Parameters.None,
Results.FromData<JsonDocument>);
Expect.equal(docs.Count, 5, "There should have been 5 documents returned");
}),
TestCase("succeeds when data is not found", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
var docs = await conn.CustomList(
$"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'NumValue' > @value",
new[] { new SqliteParameter("@value", 100) }, Results.FromData<JsonDocument>);
Expect.isEmpty(docs, "There should have been no documents returned");
})
}),
TestList("CustomNonQuery", new[]
{
TestCase("succeeds when operating on data", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
await conn.CustomNonQuery($"DELETE FROM {SqliteDb.TableName}", Parameters.None);
var remaining = await conn.CountAll(SqliteDb.TableName);
Expect.equal(remaining, 0L, "There should be no documents remaining in the table");
}),
TestCase("succeeds when no data matches where clause", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
await conn.CustomNonQuery(
$"DELETE FROM {SqliteDb.TableName} WHERE data ->> 'NumValue' > @value",
new[] { new SqliteParameter("@value", 100) });
var remaining = await conn.CountAll(SqliteDb.TableName);
Expect.equal(remaining, 5L, "There should be 5 documents remaining in the table");
})
}),
TestCase("CustomScalar succeeds", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
var nbr = await conn.CustomScalar("SELECT 5 AS test_value", Parameters.None, rdr => rdr.GetInt32(0));
Expect.equal(nbr, 5, "The query should have returned the number 5");
}),
TestCase("EnsureTable succeeds", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
Func<string, ValueTask<bool>> itExists = async name =>
{
var result = await conn.CustomScalar(
$"SELECT EXISTS (SELECT 1 FROM {SqliteDb.Catalog} WHERE name = @name) AS it",
new SqliteParameter[] { new("@name", name) }, rdr => rdr.GetInt64(0));
return result > 0L;
};
var exists = await itExists("ensured");
var alsoExists = await itExists("idx_ensured_key");
Expect.isFalse(exists, "The table should not exist already");
Expect.isFalse(alsoExists, "The key index should not exist already");
await conn.EnsureTable("ensured");
exists = await itExists("ensured");
alsoExists = await itExists("idx_ensured_key");
Expect.isTrue(exists, "The table should now exist");
Expect.isTrue(alsoExists, "The key index should now exist");
}),
TestList("Insert", new[]
{
TestCase("succeeds", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
var before = await conn.FindAll<SubDocument>(SqliteDb.TableName);
Expect.isEmpty(before, "There should be no documents in the table");
await conn.Insert(SqliteDb.TableName,
new JsonDocument { Id = "turkey", Sub = new() { Foo = "gobble", Bar = "gobble" } });
var after = await conn.FindAll<JsonDocument>(SqliteDb.TableName);
Expect.equal(after.Count, 1, "There should have been one document inserted");
}),
TestCase("fails for duplicate key", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await conn.Insert(SqliteDb.TableName, new JsonDocument { Id = "test" });
try
{
await Document.Insert(SqliteDb.TableName, new JsonDocument { Id = "test" });
Expect.isTrue(false, "An exception should have been raised for duplicate document ID insert");
}
catch (Exception)
{
// This is what is supposed to happen
}
})
}),
TestList("Save", new[]
{
TestCase("succeeds when a document is inserted", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
var before = await conn.FindAll<JsonDocument>(SqliteDb.TableName);
Expect.isEmpty(before, "There should be no documents in the table");
await conn.Save(SqliteDb.TableName,
new JsonDocument { Id = "test", Sub = new() { Foo = "a", Bar = "b" } });
var after = await conn.FindAll<JsonDocument>(SqliteDb.TableName);
Expect.equal(after.Count, 1, "There should have been one document inserted");
}),
TestCase("succeeds when a document is updated", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await conn.Insert(SqliteDb.TableName,
new JsonDocument { Id = "test", Sub = new() { Foo = "a", Bar = "b" } });
var before = await conn.FindById<string, JsonDocument>(SqliteDb.TableName, "test");
Expect.isNotNull(before, "There should have been a document returned");
Expect.equal(before!.Id, "test", "The document is not correct");
Expect.isNotNull(before.Sub, "There should have been a sub-document");
Expect.equal(before.Sub!.Foo, "a", "The document is not correct");
Expect.equal(before.Sub.Bar, "b", "The document is not correct");
await conn.Save(SqliteDb.TableName, new JsonDocument { Id = "test" });
var after = await conn.FindById<string, JsonDocument>(SqliteDb.TableName, "test");
Expect.isNotNull(after, "There should have been a document returned post-update");
Expect.equal(after!.Id, "test", "The updated document is not correct");
Expect.isNull(after.Sub, "There should not have been a sub-document in the updated document");
})
}),
TestCase("CountAll succeeds", async () =>
{ {
await using var db = await SqliteDb.BuildDb(); await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn(); await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs(); await LoadDocs();
var theCount = await conn.CountAll(SqliteDb.TableName); var doc = await conn.CustomSingle($"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'Id' = @id",
Expect.equal(theCount, 5L, "There should have been 5 matching documents"); new[] { Parameters.Id("one") }, Results.FromData<JsonDocument>);
Expect.isNotNull(doc, "There should have been a document returned");
Expect.equal(doc!.Id, "one", "The incorrect document was returned");
}), }),
TestCase("CountByField succeeds", async () => TestCase("succeeds when a row is not found", async () =>
{ {
await using var db = await SqliteDb.BuildDb(); await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn(); await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs(); await LoadDocs();
var theCount = await conn.CountByField(SqliteDb.TableName, "Value", Op.EQ, "purple"); var doc = await conn.CustomSingle($"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'Id' = @id",
Expect.equal(theCount, 2L, "There should have been 2 matching documents"); new[] { Parameters.Id("eighty") }, Results.FromData<JsonDocument>);
}), Expect.isNull(doc, "There should not have been a document returned");
TestList("ExistsById", new[] })
}),
TestList("CustomList", new[]
{
TestCase("succeeds when data is found", async () =>
{ {
TestCase("succeeds when a document exists", async () => await using var db = await SqliteDb.BuildDb();
{ await using var conn = Sqlite.Configuration.DbConn();
await using var db = await SqliteDb.BuildDb(); await LoadDocs();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
var exists = await conn.ExistsById(SqliteDb.TableName, "three"); var docs = await conn.CustomList(Query.SelectFromTable(SqliteDb.TableName), Parameters.None,
Expect.isTrue(exists, "There should have been an existing document"); Results.FromData<JsonDocument>);
}), Expect.equal(docs.Count, 5, "There should have been 5 documents returned");
TestCase("succeeds when a document does not exist", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
var exists = await conn.ExistsById(SqliteDb.TableName, "seven");
Expect.isFalse(exists, "There should not have been an existing document");
})
}), }),
TestList("ExistsByField", new[] TestCase("succeeds when data is not found", async () =>
{ {
TestCase("succeeds when documents exist", async () => await using var db = await SqliteDb.BuildDb();
{ await using var conn = Sqlite.Configuration.DbConn();
await using var db = await SqliteDb.BuildDb(); await LoadDocs();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
var exists = await conn.ExistsByField(SqliteDb.TableName, "NumValue", Op.GE, 10); var docs = await conn.CustomList(
Expect.isTrue(exists, "There should have been existing documents"); $"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'NumValue' > @value",
}), new[] { new SqliteParameter("@value", 100) }, Results.FromData<JsonDocument>);
TestCase("succeeds when no matching documents exist", async () => Expect.isEmpty(docs, "There should have been no documents returned");
{ })
await using var db = await SqliteDb.BuildDb(); }),
await using var conn = Sqlite.Configuration.DbConn(); TestList("CustomNonQuery", new[]
await LoadDocs(); {
TestCase("succeeds when operating on data", async () =>
var exists = await conn.ExistsByField(SqliteDb.TableName, "Nothing", Op.EQ, "none");
Expect.isFalse(exists, "There should not have been any existing documents");
})
}),
TestList("FindAll", new[]
{ {
TestCase("succeeds when there is data", async () => await using var db = await SqliteDb.BuildDb();
{ await using var conn = Sqlite.Configuration.DbConn();
await using var db = await SqliteDb.BuildDb(); await LoadDocs();
await using var conn = Sqlite.Configuration.DbConn();
await conn.Insert(SqliteDb.TableName, new JsonDocument { Id = "one", Value = "two" }); await conn.CustomNonQuery($"DELETE FROM {SqliteDb.TableName}", Parameters.None);
await conn.Insert(SqliteDb.TableName, new JsonDocument { Id = "three", Value = "four" });
await conn.Insert(SqliteDb.TableName, new JsonDocument { Id = "five", Value = "six" });
var results = await conn.FindAll<JsonDocument>(SqliteDb.TableName); var remaining = await conn.CountAll(SqliteDb.TableName);
Expect.equal(results.Count, 3, "There should have been 3 documents returned"); Expect.equal(remaining, 0L, "There should be no documents remaining in the table");
}),
TestCase("succeeds when there is no data", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
var results = await conn.FindAll<JsonDocument>(SqliteDb.TableName);
Expect.isEmpty(results, "There should have been no documents returned");
})
}), }),
TestList("FindById", new[] TestCase("succeeds when no data matches where clause", async () =>
{ {
TestCase("succeeds when a document is found", async () => await using var db = await SqliteDb.BuildDb();
{ await using var conn = Sqlite.Configuration.DbConn();
await using var db = await SqliteDb.BuildDb(); await LoadDocs();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
var doc = await conn.FindById<string, JsonDocument>(SqliteDb.TableName, "two"); await conn.CustomNonQuery($"DELETE FROM {SqliteDb.TableName} WHERE data ->> 'NumValue' > @value",
Expect.isNotNull(doc, "There should have been a document returned"); new[] { new SqliteParameter("@value", 100) });
Expect.equal(doc!.Id, "two", "The incorrect document was returned");
}),
TestCase("succeeds when a document is not found", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
var doc = await conn.FindById<string, JsonDocument>(SqliteDb.TableName, "eighty-seven"); var remaining = await conn.CountAll(SqliteDb.TableName);
Expect.isNull(doc, "There should not have been a document returned"); Expect.equal(remaining, 5L, "There should be 5 documents remaining in the table");
}) })
}), }),
TestList("FindByField", new[] TestCase("CustomScalar succeeds", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
var nbr = await conn.CustomScalar("SELECT 5 AS test_value", Parameters.None, rdr => rdr.GetInt32(0));
Expect.equal(nbr, 5, "The query should have returned the number 5");
}),
TestCase("EnsureTable succeeds", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
Func<string, ValueTask<bool>> itExists = async name =>
{ {
TestCase("succeeds when documents are found", async () => var result = await conn.CustomScalar(
{ $"SELECT EXISTS (SELECT 1 FROM {SqliteDb.Catalog} WHERE name = @name) AS it",
await using var db = await SqliteDb.BuildDb(); new SqliteParameter[] { new("@name", name) }, rdr => rdr.GetInt64(0));
await using var conn = Sqlite.Configuration.DbConn(); return result > 0L;
await LoadDocs(); };
var docs = await conn.FindByField<JsonDocument>(SqliteDb.TableName, "NumValue", Op.GT, 15); var exists = await itExists("ensured");
Expect.equal(docs.Count, 2, "There should have been two documents returned"); var alsoExists = await itExists("idx_ensured_key");
}), Expect.isFalse(exists, "The table should not exist already");
TestCase("succeeds when documents are not found", async () => Expect.isFalse(alsoExists, "The key index should not exist already");
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
var docs = await conn.FindByField<JsonDocument>(SqliteDb.TableName, "Value", Op.EQ, "mauve"); await conn.EnsureTable("ensured");
Expect.isEmpty(docs, "There should have been no documents returned");
}) exists = await itExists("ensured");
}), alsoExists = await itExists("idx_ensured_key");
TestList("FindFirstByField", new[] Expect.isTrue(exists, "The table should now exist");
Expect.isTrue(alsoExists, "The key index should now exist");
}),
TestList("Insert", new[]
{
TestCase("succeeds", async () =>
{ {
TestCase("succeeds when a document is found", async () => await using var db = await SqliteDb.BuildDb();
{ await using var conn = Sqlite.Configuration.DbConn();
await using var db = await SqliteDb.BuildDb(); var before = await conn.FindAll<SubDocument>(SqliteDb.TableName);
await using var conn = Sqlite.Configuration.DbConn(); Expect.isEmpty(before, "There should be no documents in the table");
await LoadDocs(); await conn.Insert(SqliteDb.TableName,
new JsonDocument { Id = "turkey", Sub = new() { Foo = "gobble", Bar = "gobble" } });
var doc = await conn.FindFirstByField<JsonDocument>(SqliteDb.TableName, "Value", Op.EQ, var after = await conn.FindAll<JsonDocument>(SqliteDb.TableName);
"another"); Expect.equal(after.Count, 1, "There should have been one document inserted");
Expect.isNotNull(doc, "There should have been a document returned");
Expect.equal(doc!.Id, "two", "The incorrect document was returned");
}),
TestCase("succeeds when multiple documents are found", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
var doc = await conn.FindFirstByField<JsonDocument>(SqliteDb.TableName, "Sub.Foo", Op.EQ,
"green");
Expect.isNotNull(doc, "There should have been a document returned");
Expect.contains(new[] { "two", "four" }, doc!.Id, "An incorrect document was returned");
}),
TestCase("succeeds when a document is not found", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
var doc = await conn.FindFirstByField<JsonDocument>(SqliteDb.TableName, "Value", Op.EQ,
"absent");
Expect.isNull(doc, "There should not have been a document returned");
})
}), }),
TestList("UpdateFull", new[] TestCase("fails for duplicate key", async () =>
{ {
TestCase("succeeds when a document is updated", async () => await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await conn.Insert(SqliteDb.TableName, new JsonDocument { Id = "test" });
try
{ {
await using var db = await SqliteDb.BuildDb(); await Document.Insert(SqliteDb.TableName, new JsonDocument { Id = "test" });
await using var conn = Sqlite.Configuration.DbConn(); Expect.isTrue(false, "An exception should have been raised for duplicate document ID insert");
await LoadDocs(); }
catch (Exception)
var testDoc = new JsonDocument { Id = "one", Sub = new() { Foo = "blue", Bar = "red" } };
await conn.UpdateFull(SqliteDb.TableName, "one", testDoc);
var after = await conn.FindById<string, JsonDocument>(SqliteDb.TableName, "one");
Expect.isNotNull(after, "There should have been a document returned post-update");
Expect.equal(after.Id, "one", "The updated document is not correct");
Expect.isNotNull(after.Sub, "The updated document should have had a sub-document");
Expect.equal(after.Sub!.Foo, "blue", "The updated sub-document is not correct");
Expect.equal(after.Sub.Bar, "red", "The updated sub-document is not correct");
}),
TestCase("succeeds when no document is updated", async () =>
{ {
await using var db = await SqliteDb.BuildDb(); // This is what is supposed to happen
await using var conn = Sqlite.Configuration.DbConn(); }
var before = await conn.FindAll<JsonDocument>(SqliteDb.TableName); })
Expect.isEmpty(before, "There should have been no documents returned"); }),
TestList("Save", new[]
// This not raising an exception is the test {
await conn.UpdateFull(SqliteDb.TableName, "test", TestCase("succeeds when a document is inserted", async () =>
new JsonDocument { Id = "x", Sub = new() { Foo = "blue", Bar = "red" } });
})
}),
TestList("UpdateFullFunc", new[]
{ {
TestCase("succeeds when a document is updated", async () => await using var db = await SqliteDb.BuildDb();
{ await using var conn = Sqlite.Configuration.DbConn();
await using var db = await SqliteDb.BuildDb(); var before = await conn.FindAll<JsonDocument>(SqliteDb.TableName);
await using var conn = Sqlite.Configuration.DbConn(); Expect.isEmpty(before, "There should be no documents in the table");
await LoadDocs();
await conn.UpdateFullFunc(SqliteDb.TableName, doc => doc.Id, await conn.Save(SqliteDb.TableName,
new JsonDocument { Id = "one", Value = "le un", NumValue = 1 }); new JsonDocument { Id = "test", Sub = new() { Foo = "a", Bar = "b" } });
var after = await conn.FindById<string, JsonDocument>(SqliteDb.TableName, "one"); var after = await conn.FindAll<JsonDocument>(SqliteDb.TableName);
Expect.isNotNull(after, "There should have been a document returned post-update"); Expect.equal(after.Count, 1, "There should have been one document inserted");
Expect.equal(after.Id, "one", "The updated document is incorrect");
Expect.equal(after.Value, "le un", "The updated document is incorrect");
Expect.equal(after.NumValue, 1, "The updated document is incorrect");
Expect.isNull(after.Sub, "The updated document should not have a sub-document");
}),
TestCase("succeeds when no document is updated", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
var before = await conn.FindAll<JsonDocument>(SqliteDb.TableName);
Expect.isEmpty(before, "There should have been no documents returned");
// This not raising an exception is the test
await conn.UpdateFullFunc(SqliteDb.TableName, doc => doc.Id,
new JsonDocument { Id = "one", Value = "le un", NumValue = 1 });
})
}), }),
TestList("UpdatePartialById", new[] TestCase("succeeds when a document is updated", async () =>
{ {
TestCase("succeeds when a document is updated", async () => await using var db = await SqliteDb.BuildDb();
{ await using var conn = Sqlite.Configuration.DbConn();
await using var db = await SqliteDb.BuildDb(); await conn.Insert(SqliteDb.TableName,
await using var conn = Sqlite.Configuration.DbConn(); new JsonDocument { Id = "test", Sub = new() { Foo = "a", Bar = "b" } });
await LoadDocs();
await conn.UpdatePartialById(SqliteDb.TableName, "one", new { NumValue = 44 }); var before = await conn.FindById<string, JsonDocument>(SqliteDb.TableName, "test");
var after = await conn.FindById<string, JsonDocument>(SqliteDb.TableName, "one"); Expect.isNotNull(before, "There should have been a document returned");
Expect.isNotNull(after, "There should have been a document returned post-update"); Expect.equal(before!.Id, "test", "The document is not correct");
Expect.equal(after.Id, "one", "The updated document is not correct"); Expect.isNotNull(before.Sub, "There should have been a sub-document");
Expect.equal(after.NumValue, 44, "The updated document is not correct"); Expect.equal(before.Sub!.Foo, "a", "The document is not correct");
}), Expect.equal(before.Sub.Bar, "b", "The document is not correct");
TestCase("succeeds when no document is updated", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
var before = await conn.FindAll<JsonDocument>(SqliteDb.TableName);
Expect.isEmpty(before, "There should have been no documents returned");
// This not raising an exception is the test await conn.Save(SqliteDb.TableName, new JsonDocument { Id = "test" });
await conn.UpdatePartialById(SqliteDb.TableName, "test", new { Foo = "green" }); var after = await conn.FindById<string, JsonDocument>(SqliteDb.TableName, "test");
}) Expect.isNotNull(after, "There should have been a document returned post-update");
}), Expect.equal(after!.Id, "test", "The updated document is not correct");
TestList("UpdatePartialByField", new[] Expect.isNull(after.Sub, "There should not have been a sub-document in the updated document");
})
}),
TestCase("CountAll succeeds", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
var theCount = await conn.CountAll(SqliteDb.TableName);
Expect.equal(theCount, 5L, "There should have been 5 matching documents");
}),
TestCase("CountByField succeeds", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
var theCount = await conn.CountByField(SqliteDb.TableName, "Value", Op.EQ, "purple");
Expect.equal(theCount, 2L, "There should have been 2 matching documents");
}),
TestList("ExistsById", new[]
{
TestCase("succeeds when a document exists", async () =>
{ {
TestCase("succeeds when a document is updated", async () => await using var db = await SqliteDb.BuildDb();
{ await using var conn = Sqlite.Configuration.DbConn();
await using var db = await SqliteDb.BuildDb(); await LoadDocs();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
await conn.UpdatePartialByField(SqliteDb.TableName, "Value", Op.EQ, "purple", var exists = await conn.ExistsById(SqliteDb.TableName, "three");
new { NumValue = 77 }); Expect.isTrue(exists, "There should have been an existing document");
var after = await conn.CountByField(SqliteDb.TableName, "NumValue", Op.EQ, 77);
Expect.equal(after, 2L, "There should have been 2 documents returned");
}),
TestCase("succeeds when no document is updated", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
var before = await conn.FindAll<JsonDocument>(SqliteDb.TableName);
Expect.isEmpty(before, "There should have been no documents returned");
// This not raising an exception is the test
await conn.UpdatePartialByField(SqliteDb.TableName, "Value", Op.EQ, "burgundy",
new { Foo = "green" });
})
}), }),
TestList("DeleteById", new[] TestCase("succeeds when a document does not exist", async () =>
{ {
TestCase("succeeds when a document is deleted", async () => await using var db = await SqliteDb.BuildDb();
{ await using var conn = Sqlite.Configuration.DbConn();
await using var db = await SqliteDb.BuildDb(); await LoadDocs();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
await conn.DeleteById(SqliteDb.TableName, "four"); var exists = await conn.ExistsById(SqliteDb.TableName, "seven");
var remaining = await conn.CountAll(SqliteDb.TableName); Expect.isFalse(exists, "There should not have been an existing document");
Expect.equal(remaining, 4L, "There should have been 4 documents remaining"); })
}), }),
TestCase("succeeds when a document is not deleted", async () => TestList("ExistsByField", new[]
{ {
await using var db = await SqliteDb.BuildDb(); TestCase("succeeds when documents exist", async () =>
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
await conn.DeleteById(SqliteDb.TableName, "thirty");
var remaining = await conn.CountAll(SqliteDb.TableName);
Expect.equal(remaining, 5L, "There should have been 5 documents remaining");
})
}),
TestList("DeleteByField", new[]
{ {
TestCase("succeeds when documents are deleted", async () => await using var db = await SqliteDb.BuildDb();
{ await using var conn = Sqlite.Configuration.DbConn();
await using var db = await SqliteDb.BuildDb(); await LoadDocs();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
await conn.DeleteByField(SqliteDb.TableName, "Value", Op.NE, "purple"); var exists = await conn.ExistsByField(SqliteDb.TableName, "NumValue", Op.GE, 10);
var remaining = await conn.CountAll(SqliteDb.TableName); Expect.isTrue(exists, "There should have been existing documents");
Expect.equal(remaining, 2L, "There should have been 2 documents remaining");
}),
TestCase("succeeds when documents are not deleted", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
await conn.DeleteByField(SqliteDb.TableName, "Value", Op.EQ, "crimson");
var remaining = await conn.CountAll(SqliteDb.TableName);
Expect.equal(remaining, 5L, "There should have been 5 documents remaining");
})
}), }),
TestCase("Clean up database", () => Sqlite.Configuration.UseConnectionString("data source=:memory:")) TestCase("succeeds when no matching documents exist", async () =>
}); {
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
var exists = await conn.ExistsByField(SqliteDb.TableName, "Nothing", Op.EQ, "none");
Expect.isFalse(exists, "There should not have been any existing documents");
})
}),
TestList("FindAll", new[]
{
TestCase("succeeds when there is data", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await conn.Insert(SqliteDb.TableName, new JsonDocument { Id = "one", Value = "two" });
await conn.Insert(SqliteDb.TableName, new JsonDocument { Id = "three", Value = "four" });
await conn.Insert(SqliteDb.TableName, new JsonDocument { Id = "five", Value = "six" });
var results = await conn.FindAll<JsonDocument>(SqliteDb.TableName);
Expect.equal(results.Count, 3, "There should have been 3 documents returned");
}),
TestCase("succeeds when there is no data", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
var results = await conn.FindAll<JsonDocument>(SqliteDb.TableName);
Expect.isEmpty(results, "There should have been no documents returned");
})
}),
TestList("FindById", new[]
{
TestCase("succeeds when a document is found", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
var doc = await conn.FindById<string, JsonDocument>(SqliteDb.TableName, "two");
Expect.isNotNull(doc, "There should have been a document returned");
Expect.equal(doc!.Id, "two", "The incorrect document was returned");
}),
TestCase("succeeds when a document is not found", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
var doc = await conn.FindById<string, JsonDocument>(SqliteDb.TableName, "eighty-seven");
Expect.isNull(doc, "There should not have been a document returned");
})
}),
TestList("FindByField", new[]
{
TestCase("succeeds when documents are found", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
var docs = await conn.FindByField<JsonDocument>(SqliteDb.TableName, "NumValue", Op.GT, 15);
Expect.equal(docs.Count, 2, "There should have been two documents returned");
}),
TestCase("succeeds when documents are not found", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
var docs = await conn.FindByField<JsonDocument>(SqliteDb.TableName, "Value", Op.EQ, "mauve");
Expect.isEmpty(docs, "There should have been no documents returned");
})
}),
TestList("FindFirstByField", new[]
{
TestCase("succeeds when a document is found", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
var doc = await conn.FindFirstByField<JsonDocument>(SqliteDb.TableName, "Value", Op.EQ, "another");
Expect.isNotNull(doc, "There should have been a document returned");
Expect.equal(doc!.Id, "two", "The incorrect document was returned");
}),
TestCase("succeeds when multiple documents are found", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
var doc = await conn.FindFirstByField<JsonDocument>(SqliteDb.TableName, "Sub.Foo", Op.EQ, "green");
Expect.isNotNull(doc, "There should have been a document returned");
Expect.contains(new[] { "two", "four" }, doc!.Id, "An incorrect document was returned");
}),
TestCase("succeeds when a document is not found", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
var doc = await conn.FindFirstByField<JsonDocument>(SqliteDb.TableName, "Value", Op.EQ, "absent");
Expect.isNull(doc, "There should not have been a document returned");
})
}),
TestList("UpdateFull", new[]
{
TestCase("succeeds when a document is updated", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
var testDoc = new JsonDocument { Id = "one", Sub = new() { Foo = "blue", Bar = "red" } };
await conn.UpdateFull(SqliteDb.TableName, "one", testDoc);
var after = await conn.FindById<string, JsonDocument>(SqliteDb.TableName, "one");
Expect.isNotNull(after, "There should have been a document returned post-update");
Expect.equal(after.Id, "one", "The updated document is not correct");
Expect.isNotNull(after.Sub, "The updated document should have had a sub-document");
Expect.equal(after.Sub!.Foo, "blue", "The updated sub-document is not correct");
Expect.equal(after.Sub.Bar, "red", "The updated sub-document is not correct");
}),
TestCase("succeeds when no document is updated", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
var before = await conn.FindAll<JsonDocument>(SqliteDb.TableName);
Expect.isEmpty(before, "There should have been no documents returned");
// This not raising an exception is the test
await conn.UpdateFull(SqliteDb.TableName, "test",
new JsonDocument { Id = "x", Sub = new() { Foo = "blue", Bar = "red" } });
})
}),
TestList("UpdateFullFunc", new[]
{
TestCase("succeeds when a document is updated", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
await conn.UpdateFullFunc(SqliteDb.TableName, doc => doc.Id,
new JsonDocument { Id = "one", Value = "le un", NumValue = 1 });
var after = await conn.FindById<string, JsonDocument>(SqliteDb.TableName, "one");
Expect.isNotNull(after, "There should have been a document returned post-update");
Expect.equal(after.Id, "one", "The updated document is incorrect");
Expect.equal(after.Value, "le un", "The updated document is incorrect");
Expect.equal(after.NumValue, 1, "The updated document is incorrect");
Expect.isNull(after.Sub, "The updated document should not have a sub-document");
}),
TestCase("succeeds when no document is updated", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
var before = await conn.FindAll<JsonDocument>(SqliteDb.TableName);
Expect.isEmpty(before, "There should have been no documents returned");
// This not raising an exception is the test
await conn.UpdateFullFunc(SqliteDb.TableName, doc => doc.Id,
new JsonDocument { Id = "one", Value = "le un", NumValue = 1 });
})
}),
TestList("UpdatePartialById", new[]
{
TestCase("succeeds when a document is updated", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
await conn.UpdatePartialById(SqliteDb.TableName, "one", new { NumValue = 44 });
var after = await conn.FindById<string, JsonDocument>(SqliteDb.TableName, "one");
Expect.isNotNull(after, "There should have been a document returned post-update");
Expect.equal(after.Id, "one", "The updated document is not correct");
Expect.equal(after.NumValue, 44, "The updated document is not correct");
}),
TestCase("succeeds when no document is updated", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
var before = await conn.FindAll<JsonDocument>(SqliteDb.TableName);
Expect.isEmpty(before, "There should have been no documents returned");
// This not raising an exception is the test
await conn.UpdatePartialById(SqliteDb.TableName, "test", new { Foo = "green" });
})
}),
TestList("UpdatePartialByField", new[]
{
TestCase("succeeds when a document is updated", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
await conn.UpdatePartialByField(SqliteDb.TableName, "Value", Op.EQ, "purple", new { NumValue = 77 });
var after = await conn.CountByField(SqliteDb.TableName, "NumValue", Op.EQ, 77);
Expect.equal(after, 2L, "There should have been 2 documents returned");
}),
TestCase("succeeds when no document is updated", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
var before = await conn.FindAll<JsonDocument>(SqliteDb.TableName);
Expect.isEmpty(before, "There should have been no documents returned");
// This not raising an exception is the test
await conn.UpdatePartialByField(SqliteDb.TableName, "Value", Op.EQ, "burgundy", new { Foo = "green" });
})
}),
TestList("DeleteById", new[]
{
TestCase("succeeds when a document is deleted", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
await conn.DeleteById(SqliteDb.TableName, "four");
var remaining = await conn.CountAll(SqliteDb.TableName);
Expect.equal(remaining, 4L, "There should have been 4 documents remaining");
}),
TestCase("succeeds when a document is not deleted", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
await conn.DeleteById(SqliteDb.TableName, "thirty");
var remaining = await conn.CountAll(SqliteDb.TableName);
Expect.equal(remaining, 5L, "There should have been 5 documents remaining");
})
}),
TestList("DeleteByField", new[]
{
TestCase("succeeds when documents are deleted", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
await conn.DeleteByField(SqliteDb.TableName, "Value", Op.NE, "purple");
var remaining = await conn.CountAll(SqliteDb.TableName);
Expect.equal(remaining, 2L, "There should have been 2 documents remaining");
}),
TestCase("succeeds when documents are not deleted", async () =>
{
await using var db = await SqliteDb.BuildDb();
await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs();
await conn.DeleteByField(SqliteDb.TableName, "Value", Op.EQ, "crimson");
var remaining = await conn.CountAll(SqliteDb.TableName);
Expect.equal(remaining, 5L, "There should have been 5 documents remaining");
})
}),
TestCase("Clean up database", () => Sqlite.Configuration.UseConnectionString("data source=:memory:"))
});
} }

File diff suppressed because it is too large Load Diff

View File

@ -39,15 +39,15 @@ let unitTests =
$"CREATE TABLE IF NOT EXISTS {PostgresDb.TableName} (data JSONB NOT NULL)" $"CREATE TABLE IF NOT EXISTS {PostgresDb.TableName} (data JSONB NOT NULL)"
"CREATE TABLE statement not constructed correctly" "CREATE TABLE statement not constructed correctly"
} }
test "ensureJsonIndex succeeds for full index" { test "ensureDocumentIndex succeeds for full index" {
Expect.equal Expect.equal
(Query.Definition.ensureJsonIndex "schema.tbl" Full) (Query.Definition.ensureDocumentIndex "schema.tbl" Full)
"CREATE INDEX IF NOT EXISTS idx_tbl_document ON schema.tbl USING GIN (data)" "CREATE INDEX IF NOT EXISTS idx_tbl_document ON schema.tbl USING GIN (data)"
"CREATE INDEX statement not constructed correctly" "CREATE INDEX statement not constructed correctly"
} }
test "ensureJsonIndex succeeds for JSONB Path Ops index" { test "ensureDocumentIndex succeeds for JSONB Path Ops index" {
Expect.equal Expect.equal
(Query.Definition.ensureJsonIndex PostgresDb.TableName Optimized) (Query.Definition.ensureDocumentIndex PostgresDb.TableName Optimized)
(sprintf "CREATE INDEX IF NOT EXISTS idx_%s_document ON %s USING GIN (data jsonb_path_ops)" (sprintf "CREATE INDEX IF NOT EXISTS idx_%s_document ON %s USING GIN (data jsonb_path_ops)"
PostgresDb.TableName PostgresDb.TableName) PostgresDb.TableName PostgresDb.TableName)
"CREATE INDEX statement not constructed correctly" "CREATE INDEX statement not constructed correctly"
@ -266,7 +266,7 @@ let integrationTests =
Expect.isTrue exists' "The table should now exist" Expect.isTrue exists' "The table should now exist"
Expect.isTrue alsoExists' "The key index should now exist" Expect.isTrue alsoExists' "The key index should now exist"
} }
testTask "ensureJsonIndex succeeds" { testTask "ensureDocumentIndex succeeds" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
let indexExists () = let indexExists () =
Custom.scalar Custom.scalar
@ -277,8 +277,8 @@ let integrationTests =
let! exists = indexExists () let! exists = indexExists ()
Expect.isFalse exists "The index should not exist already" Expect.isFalse exists "The index should not exist already"
do! Definition.ensureTable "ensured" do! Definition.ensureTable "ensured"
do! Definition.ensureJsonIndex "ensured" Optimized do! Definition.ensureDocumentIndex "ensured" Optimized
let! exists' = indexExists () let! exists' = indexExists ()
Expect.isTrue exists' "The index should now exist" Expect.isTrue exists' "The index should now exist"
} }
@ -730,7 +730,7 @@ let integrationTests =
Expect.equal before 0 "There should have been no documents returned" Expect.equal before 0 "There should have been no documents returned"
// This not raising an exception is the test // This not raising an exception is the test
do! Update.partialByContains PostgresDb.TableName {| Value = "burgundy" |} {| Foo = "green" |} do! Update.partialByJsonPath PostgresDb.TableName "$.NumValue ? (@ < 0)" {| Foo = "green" |}
} }
] ]
] ]