diff --git a/src/BitBadger.Documents.sln b/src/BitBadger.Documents.sln
index f3d49d0..00d5639 100644
--- a/src/BitBadger.Documents.sln
+++ b/src/BitBadger.Documents.sln
@@ -13,6 +13,8 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "BitBadger.Documents.Sqlite"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BitBadger.Documents.Tests.CSharp", "Tests.CSharp\BitBadger.Documents.Tests.CSharp.csproj", "{AB58418C-7F90-467E-8F67-F4E0AD9D8875}"
EndProject
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "BitBadger.Documents.Sqlite.Extensions", "Sqlite.Extensions\BitBadger.Documents.Sqlite.Extensions.fsproj", "{D416A5C8-B746-4FDF-8EC9-9CA0B8DA1384}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -42,5 +44,9 @@ Global
{AB58418C-7F90-467E-8F67-F4E0AD9D8875}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AB58418C-7F90-467E-8F67-F4E0AD9D8875}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AB58418C-7F90-467E-8F67-F4E0AD9D8875}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D416A5C8-B746-4FDF-8EC9-9CA0B8DA1384}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D416A5C8-B746-4FDF-8EC9-9CA0B8DA1384}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D416A5C8-B746-4FDF-8EC9-9CA0B8DA1384}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D416A5C8-B746-4FDF-8EC9-9CA0B8DA1384}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
diff --git a/src/Sqlite.Extensions/BitBadger.Documents.Sqlite.Extensions.fsproj b/src/Sqlite.Extensions/BitBadger.Documents.Sqlite.Extensions.fsproj
new file mode 100644
index 0000000..e01f9dc
--- /dev/null
+++ b/src/Sqlite.Extensions/BitBadger.Documents.Sqlite.Extensions.fsproj
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Sqlite.Extensions/Library.fs b/src/Sqlite.Extensions/Library.fs
new file mode 100644
index 0000000..011746e
--- /dev/null
+++ b/src/Sqlite.Extensions/Library.fs
@@ -0,0 +1,216 @@
+namespace BitBadger.Documents.Sqlite
+
+open Microsoft.Data.Sqlite
+
+/// F# extensions for the SqliteConnection type
+[]
+module Extensions =
+
+ type SqliteConnection with
+
+ /// Execute a query that returns a list of results
+ member conn.customList<'TDoc> query parameters mapFunc =
+ WithConn.Custom.list<'TDoc> query parameters mapFunc conn
+
+ /// Execute a query that returns one or no results
+ member conn.customSingle<'TDoc> query parameters mapFunc =
+ WithConn.Custom.single<'TDoc> query parameters mapFunc conn
+
+ /// Execute a query that does not return a value
+ member conn.customNonQuery query parameters =
+ WithConn.Custom.nonQuery query parameters conn
+
+ /// Execute a query that returns a scalar value
+ member conn.customScalar<'T when 'T: struct> query parameters mapFunc =
+ WithConn.Custom.scalar<'T> query parameters mapFunc conn
+
+ /// Create a document table
+ member conn.ensureTable name =
+ WithConn.Definition.ensureTable name conn
+
+ /// Create an index on a document table
+ member conn.ensureIndex tableName indexName fields =
+ WithConn.Definition.ensureIndex tableName indexName fields conn
+
+ /// Insert a new document
+ member conn.insert<'TDoc> tableName (document: 'TDoc) =
+ WithConn.insert<'TDoc> tableName document conn
+
+ /// Save a document, inserting it if it does not exist and updating it if it does (AKA "upsert")
+ member conn.save<'TDoc> tableName (document: 'TDoc) =
+ WithConn.save tableName document conn
+
+ /// Count all documents in a table
+ member conn.countAll tableName =
+ WithConn.Count.all tableName conn
+
+ /// Count matching documents using a comparison on a JSON field
+ member conn.countByField tableName fieldName op (value: obj) =
+ WithConn.Count.byField tableName fieldName op value conn
+
+ /// Determine if a document exists for the given ID
+ member conn.existsById tableName (docId: 'TKey) =
+ WithConn.Exists.byId tableName docId conn
+
+ /// Determine if a document exists using a comparison on a JSON field
+ member conn.existsByField tableName fieldName op (value: obj) =
+ WithConn.Exists.byField tableName fieldName op value conn
+
+ /// Retrieve all documents in the given table
+ member conn.findAll<'TDoc> tableName =
+ WithConn.Find.all<'TDoc> tableName conn
+
+ /// Retrieve a document by its ID
+ member conn.findById<'TKey, 'TDoc> tableName (docId: 'TKey) =
+ WithConn.Find.byId<'TKey, 'TDoc> tableName docId conn
+
+ /// Retrieve documents via a comparison on a JSON field
+ member conn.findByField<'TDoc> tableName fieldName op (value: obj) =
+ WithConn.Find.byField<'TDoc> tableName fieldName op value conn
+
+ /// Retrieve documents via a comparison on a JSON field, returning only the first result
+ member conn.findFirstByField<'TDoc> tableName fieldName op (value: obj) =
+ WithConn.Find.firstByField<'TDoc> tableName fieldName op value conn
+
+ /// Update an entire document
+ member conn.updateFull tableName (docId: 'TKey) (document: 'TDoc) =
+ WithConn.Update.full tableName docId document conn
+
+ /// Update an entire document
+ member conn.updateFullFunc tableName (idFunc: 'TDoc -> 'TKey) (document: 'TDoc) =
+ WithConn.Update.fullFunc tableName idFunc document conn
+
+ /// Update a partial document
+ member conn.updatePartialById tableName (docId: 'TKey) (partial: 'TPatch) =
+ WithConn.Update.partialById tableName docId partial conn
+
+ /// Update partial documents using a comparison on a JSON field
+ member conn.updatePartialByField tableName fieldName op (value: obj) (partial: 'TPatch) =
+ WithConn.Update.partialByField tableName fieldName op value partial conn
+
+ /// Delete a document by its ID
+ member conn.deleteById tableName (docId: 'TKey) =
+ WithConn.Delete.byId tableName docId conn
+
+ /// Delete documents by matching a comparison on a JSON field
+ member conn.deleteByField tableName fieldName op (value: obj) =
+ WithConn.Delete.byField tableName fieldName op value conn
+
+
+open System.Runtime.CompilerServices
+
+/// C# extensions on the SqliteConnection type
+[]
+type SqliteConnectionCSharpExtensions =
+
+ /// Execute a query that returns a list of results
+ []
+ static member inline CustomList<'TDoc>(conn, query, parameters, mapFunc: System.Func) =
+ WithConn.Custom.List<'TDoc>(query, parameters, mapFunc, conn)
+
+ /// Execute a query that returns one or no results
+ []
+ static member inline CustomSingle<'TDoc when 'TDoc: null>(
+ conn, query, parameters, mapFunc: System.Func) =
+ WithConn.Custom.Single<'TDoc>(query, parameters, mapFunc, conn)
+
+ /// Execute a query that does not return a value
+ []
+ static member inline CustomNonQuery(conn, query, parameters) =
+ WithConn.Custom.nonQuery query parameters conn
+
+ /// Execute a query that returns a scalar value
+ []
+ static member inline CustomScalar<'T when 'T: struct>(
+ conn, query, parameters, mapFunc: System.Func) =
+ WithConn.Custom.Scalar<'T>(query, parameters, mapFunc, conn)
+
+ /// Create a document table
+ []
+ static member inline EnsureTable(conn, name) =
+ WithConn.Definition.ensureTable name conn
+
+ /// Create an index on one or more fields in a document table
+ []
+ static member inline EnsureIndex(conn, tableName, indexName, fields) =
+ WithConn.Definition.ensureIndex tableName indexName fields conn
+
+ /// Insert a new document
+ []
+ static member inline Insert<'TDoc>(conn, tableName, document: 'TDoc) =
+ WithConn.insert<'TDoc> tableName document conn
+
+ /// Save a document, inserting it if it does not exist and updating it if it does (AKA "upsert")
+ []
+ static member inline Save<'TDoc>(conn, tableName, document: 'TDoc) =
+ WithConn.save<'TDoc> tableName document conn
+
+ /// Count all documents in a table
+ []
+ static member inline CountAll(conn, tableName) =
+ WithConn.Count.all tableName conn
+
+ /// Count matching documents using a comparison on a JSON field
+ []
+ static member inline CountByField(conn, tableName, fieldName, op, value: obj) =
+ WithConn.Count.byField tableName fieldName op value conn
+
+ /// Determine if a document exists for the given ID
+ []
+ static member inline ExistsById<'TKey>(conn, tableName, docId: 'TKey) =
+ WithConn.Exists.byId tableName docId conn
+
+ /// Determine if a document exists using a comparison on a JSON field
+ []
+ static member inline ExistsByField(conn, tableName, fieldName, op, value: obj) =
+ WithConn.Exists.byField tableName fieldName op value conn
+
+ /// Retrieve all documents in the given table
+ []
+ static member inline FindAll<'TDoc>(conn, tableName) =
+ WithConn.Find.All<'TDoc>(tableName, conn)
+
+ /// Retrieve a document by its ID
+ []
+ static member inline FindById<'TKey, 'TDoc when 'TDoc: null>(conn, tableName, docId: 'TKey) =
+ WithConn.Find.ById<'TKey, 'TDoc>(tableName, docId, conn)
+
+ /// Retrieve documents via a comparison on a JSON field
+ []
+ static member inline FindByField<'TDoc>(conn, tableName, fieldName, op, value) =
+ WithConn.Find.ByField<'TDoc>(tableName, fieldName, op, value, conn)
+
+ /// Retrieve documents via a comparison on a JSON field, returning only the first result
+ []
+ static member inline FindFirstByField<'TDoc when 'TDoc: null>(conn, tableName, fieldName, op, value: obj) =
+ WithConn.Find.FirstByField<'TDoc>(tableName, fieldName, op, value, conn)
+
+ /// Update an entire document
+ []
+ static member inline UpdateFull<'TKey, 'TDoc>(conn, tableName, docId: 'TKey, document: 'TDoc) =
+ WithConn.Update.full tableName docId document conn
+
+ /// Update an entire document
+ []
+ static member inline UpdateFullFunc<'TKey, 'TDoc>(conn, tableName, idFunc: System.Func<'TDoc, 'TKey>, doc: 'TDoc) =
+ WithConn.Update.FullFunc(tableName, idFunc, doc, conn)
+
+ /// Update a partial document
+ []
+ static member inline UpdatePartialById<'TKey, 'TPatch>(conn, tableName, docId: 'TKey, partial: 'TPatch) =
+ WithConn.Update.partialById tableName docId partial conn
+
+ /// Update partial documents using a comparison on a JSON field
+ []
+ static member inline UpdatePartialByField<'TPatch>(conn, tableName, fieldName, op, value: obj, partial: 'TPatch) =
+ WithConn.Update.partialByField tableName fieldName op value partial conn
+
+ /// Delete a document by its ID
+ []
+ static member inline DeleteById<'TKey>(conn, tableName, docId: 'TKey) =
+ WithConn.Delete.byId tableName docId conn
+
+ /// Delete documents by matching a comparison on a JSON field
+ []
+ static member inline DeleteByField(conn, tableName, fieldName, op, value: obj) =
+ WithConn.Delete.byField tableName fieldName op value conn
diff --git a/src/Sqlite/Library.fs b/src/Sqlite/Library.fs
index abee0aa..7f372db 100644
--- a/src/Sqlite/Library.fs
+++ b/src/Sqlite/Library.fs
@@ -519,217 +519,3 @@ module Delete =
let byField tableName fieldName op (value: obj) =
use conn = Configuration.dbConn ()
WithConn.Delete.byField tableName fieldName op value conn
-
-
-/// F# extensions for the SqliteConnection type
-[]
-module Extensions =
-
- type SqliteConnection with
-
- /// Execute a query that returns a list of results
- member conn.customList<'TDoc> query parameters mapFunc =
- WithConn.Custom.list<'TDoc> query parameters mapFunc conn
-
- /// Execute a query that returns one or no results
- member conn.customSingle<'TDoc> query parameters mapFunc =
- WithConn.Custom.single<'TDoc> query parameters mapFunc conn
-
- /// Execute a query that does not return a value
- member conn.customNonQuery query parameters =
- WithConn.Custom.nonQuery query parameters conn
-
- /// Execute a query that returns a scalar value
- member conn.customScalar<'T when 'T: struct> query parameters mapFunc =
- WithConn.Custom.scalar<'T> query parameters mapFunc conn
-
- /// Create a document table
- member conn.ensureTable name =
- WithConn.Definition.ensureTable name conn
-
- /// Create an index on a document table
- member conn.ensureIndex tableName indexName fields =
- WithConn.Definition.ensureIndex tableName indexName fields conn
-
- /// Insert a new document
- member conn.insert<'TDoc> tableName (document: 'TDoc) =
- WithConn.insert<'TDoc> tableName document conn
-
- /// Save a document, inserting it if it does not exist and updating it if it does (AKA "upsert")
- member conn.save<'TDoc> tableName (document: 'TDoc) =
- WithConn.save tableName document conn
-
- /// Count all documents in a table
- member conn.countAll tableName =
- WithConn.Count.all tableName conn
-
- /// Count matching documents using a comparison on a JSON field
- member conn.countByField tableName fieldName op (value: obj) =
- WithConn.Count.byField tableName fieldName op value conn
-
- /// Determine if a document exists for the given ID
- member conn.existsById tableName (docId: 'TKey) =
- WithConn.Exists.byId tableName docId conn
-
- /// Determine if a document exists using a comparison on a JSON field
- member conn.existsByField tableName fieldName op (value: obj) =
- WithConn.Exists.byField tableName fieldName op value conn
-
- /// Retrieve all documents in the given table
- member conn.findAll<'TDoc> tableName =
- WithConn.Find.all<'TDoc> tableName conn
-
- /// Retrieve a document by its ID
- member conn.findById<'TKey, 'TDoc> tableName (docId: 'TKey) =
- WithConn.Find.byId<'TKey, 'TDoc> tableName docId conn
-
- /// Retrieve documents via a comparison on a JSON field
- member conn.findByField<'TDoc> tableName fieldName op (value: obj) =
- WithConn.Find.byField<'TDoc> tableName fieldName op value conn
-
- /// Retrieve documents via a comparison on a JSON field, returning only the first result
- member conn.findFirstByField<'TDoc> tableName fieldName op (value: obj) =
- WithConn.Find.firstByField<'TDoc> tableName fieldName op value conn
-
- /// Update an entire document
- member conn.updateFull tableName (docId: 'TKey) (document: 'TDoc) =
- WithConn.Update.full tableName docId document conn
-
- /// Update an entire document
- member conn.updateFullFunc tableName (idFunc: 'TDoc -> 'TKey) (document: 'TDoc) =
- WithConn.Update.fullFunc tableName idFunc document conn
-
- /// Update a partial document
- member conn.updatePartialById tableName (docId: 'TKey) (partial: 'TPatch) =
- WithConn.Update.partialById tableName docId partial conn
-
- /// Update partial documents using a comparison on a JSON field
- member conn.updatePartialByField tableName fieldName op (value: obj) (partial: 'TPatch) =
- WithConn.Update.partialByField tableName fieldName op value partial conn
-
- /// Delete a document by its ID
- member conn.deleteById tableName (docId: 'TKey) =
- WithConn.Delete.byId tableName docId conn
-
- /// Delete documents by matching a comparison on a JSON field
- member conn.deleteByField tableName fieldName op (value: obj) =
- WithConn.Delete.byField tableName fieldName op value conn
-
-
-open System.Runtime.CompilerServices
-
-/// C# extensions on the SqliteConnection type
-[]
-type SqliteConnectionCSharpExtensions =
-
- /// Execute a query that returns a list of results
- []
- static member inline CustomList<'TDoc>(conn, query, parameters, mapFunc: System.Func) =
- WithConn.Custom.List<'TDoc>(query, parameters, mapFunc, conn)
-
- /// Execute a query that returns one or no results
- []
- static member inline CustomSingle<'TDoc when 'TDoc: null>(
- conn, query, parameters, mapFunc: System.Func) =
- WithConn.Custom.Single<'TDoc>(query, parameters, mapFunc, conn)
-
- /// Execute a query that does not return a value
- []
- static member inline CustomNonQuery(conn, query, parameters) =
- WithConn.Custom.nonQuery query parameters conn
-
- /// Execute a query that returns a scalar value
- []
- static member inline CustomScalar<'T when 'T: struct>(
- conn, query, parameters, mapFunc: System.Func) =
- WithConn.Custom.Scalar<'T>(query, parameters, mapFunc, conn)
-
- /// Create a document table
- []
- static member inline EnsureTable(conn, name) =
- WithConn.Definition.ensureTable name conn
-
- /// Create an index on one or more fields in a document table
- []
- static member inline EnsureIndex(conn, tableName, indexName, fields) =
- WithConn.Definition.ensureIndex tableName indexName fields conn
-
- /// Insert a new document
- []
- static member inline Insert<'TDoc>(conn, tableName, document: 'TDoc) =
- WithConn.insert<'TDoc> tableName document conn
-
- /// Save a document, inserting it if it does not exist and updating it if it does (AKA "upsert")
- []
- static member inline Save<'TDoc>(conn, tableName, document: 'TDoc) =
- WithConn.save<'TDoc> tableName document conn
-
- /// Count all documents in a table
- []
- static member inline CountAll(conn, tableName) =
- WithConn.Count.all tableName conn
-
- /// Count matching documents using a comparison on a JSON field
- []
- static member inline CountByField(conn, tableName, fieldName, op, value: obj) =
- WithConn.Count.byField tableName fieldName op value conn
-
- /// Determine if a document exists for the given ID
- []
- static member inline ExistsById<'TKey>(conn, tableName, docId: 'TKey) =
- WithConn.Exists.byId tableName docId conn
-
- /// Determine if a document exists using a comparison on a JSON field
- []
- static member inline ExistsByField(conn, tableName, fieldName, op, value: obj) =
- WithConn.Exists.byField tableName fieldName op value conn
-
- /// Retrieve all documents in the given table
- []
- static member inline FindAll<'TDoc>(conn, tableName) =
- WithConn.Find.All<'TDoc>(tableName, conn)
-
- /// Retrieve a document by its ID
- []
- static member inline FindById<'TKey, 'TDoc when 'TDoc: null>(conn, tableName, docId: 'TKey) =
- WithConn.Find.ById<'TKey, 'TDoc>(tableName, docId, conn)
-
- /// Retrieve documents via a comparison on a JSON field
- []
- static member inline FindByField<'TDoc>(conn, tableName, fieldName, op, value) =
- WithConn.Find.ByField<'TDoc>(tableName, fieldName, op, value, conn)
-
- /// Retrieve documents via a comparison on a JSON field, returning only the first result
- []
- static member inline FindFirstByField<'TDoc when 'TDoc: null>(conn, tableName, fieldName, op, value: obj) =
- WithConn.Find.FirstByField<'TDoc>(tableName, fieldName, op, value, conn)
-
- /// Update an entire document
- []
- static member inline UpdateFull<'TKey, 'TDoc>(conn, tableName, docId: 'TKey, document: 'TDoc) =
- WithConn.Update.full tableName docId document conn
-
- /// Update an entire document
- []
- static member inline UpdateFullFunc<'TKey, 'TDoc>(conn, tableName, idFunc: System.Func<'TDoc, 'TKey>, doc: 'TDoc) =
- WithConn.Update.FullFunc(tableName, idFunc, doc, conn)
-
- /// Update a partial document
- []
- static member inline UpdatePartialById<'TKey, 'TPatch>(conn, tableName, docId: 'TKey, partial: 'TPatch) =
- WithConn.Update.partialById tableName docId partial conn
-
- /// Update partial documents using a comparison on a JSON field
- []
- static member inline UpdatePartialByField<'TPatch>(conn, tableName, fieldName, op, value: obj, partial: 'TPatch) =
- WithConn.Update.partialByField tableName fieldName op value partial conn
-
- /// Delete a document by its ID
- []
- static member inline DeleteById<'TKey>(conn, tableName, docId: 'TKey) =
- WithConn.Delete.byId tableName docId conn
-
- /// Delete documents by matching a comparison on a JSON field
- []
- static member inline DeleteByField(conn, tableName, fieldName, op, value: obj) =
- WithConn.Delete.byField tableName fieldName op value conn
diff --git a/src/Tests.CSharp/BitBadger.Documents.Tests.CSharp.csproj b/src/Tests.CSharp/BitBadger.Documents.Tests.CSharp.csproj
index c70e5b0..bb60bcd 100644
--- a/src/Tests.CSharp/BitBadger.Documents.Tests.CSharp.csproj
+++ b/src/Tests.CSharp/BitBadger.Documents.Tests.CSharp.csproj
@@ -7,6 +7,7 @@
+
diff --git a/src/Tests.CSharp/SqliteCSharpExtensionTests.cs b/src/Tests.CSharp/SqliteCSharpExtensionTests.cs
new file mode 100644
index 0000000..cabe980
--- /dev/null
+++ b/src/Tests.CSharp/SqliteCSharpExtensionTests.cs
@@ -0,0 +1,511 @@
+using Expecto.CSharp;
+using Expecto;
+using Microsoft.Data.Sqlite;
+using BitBadger.Documents.Sqlite;
+
+namespace BitBadger.Documents.Tests.CSharp;
+
+using static Runner;
+
+///
+/// C# tests for the extensions on the SqliteConnection class
+///
+public static class SqliteCSharpExtensionTests
+{
+ private static Task LoadDocs() => SqliteCSharpTests.LoadDocs();
+
+ [Tests]
+ public static Test Integration =
+ TestList("Extensions", new[]
+ {
+ TestList("CustomSingle", new[]
+ {
+ 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);
+ 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);
+ 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);
+ 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);
+ 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> 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(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(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(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(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(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(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 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 () =>
+ {
+ await using var db = await SqliteDb.BuildDb();
+ await using var conn = Sqlite.Configuration.DbConn();
+ await LoadDocs();
+
+ var exists = await conn.ExistsById(SqliteDb.TableName, "three");
+ Expect.isTrue(exists, "There should have been an existing document");
+ }),
+ 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 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, "NumValue", Op.GE, 10);
+ Expect.isTrue(exists, "There should have been existing documents");
+ }),
+ 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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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:"))
+ });
+}
diff --git a/src/Tests.CSharp/SqliteCSharpTests.cs b/src/Tests.CSharp/SqliteCSharpTests.cs
index 73baea0..f1c35c6 100644
--- a/src/Tests.CSharp/SqliteCSharpTests.cs
+++ b/src/Tests.CSharp/SqliteCSharpTests.cs
@@ -56,7 +56,7 @@ public static class SqliteCSharpTests
new() { Id = "five", Value = "purple", NumValue = 18 }
};
- private static async Task LoadDocs()
+ internal static async Task LoadDocs()
{
foreach (var doc in TestDocuments) await Document.Insert(SqliteDb.TableName, doc);
}
@@ -552,500 +552,6 @@ public static class SqliteCSharpTests
})
})
}),
- TestList("Extensions", new[]
- {
- TestList("CustomSingle", new[]
- {
- 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);
- 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);
- 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);
- 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);
- 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> 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(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(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(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(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(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(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 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 () =>
- {
- await using var db = await SqliteDb.BuildDb();
- await using var conn = Sqlite.Configuration.DbConn();
- await LoadDocs();
-
- var exists = await conn.ExistsById(SqliteDb.TableName, "three");
- Expect.isTrue(exists, "There should have been an existing document");
- }),
- 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 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, "NumValue", Op.GE, 10);
- Expect.isTrue(exists, "There should have been existing documents");
- }),
- 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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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:"))
});
diff --git a/src/Tests/BitBadger.Documents.Tests.fsproj b/src/Tests/BitBadger.Documents.Tests.fsproj
index 9dae8da..4792e95 100644
--- a/src/Tests/BitBadger.Documents.Tests.fsproj
+++ b/src/Tests/BitBadger.Documents.Tests.fsproj
@@ -6,7 +6,9 @@
+
+
@@ -16,6 +18,7 @@
+
diff --git a/src/Tests/Program.fs b/src/Tests/Program.fs
index 9480cb0..3d185f5 100644
--- a/src/Tests/Program.fs
+++ b/src/Tests/Program.fs
@@ -7,7 +7,9 @@ let allTests =
[ CommonTests.all
CommonCSharpTests.Unit
SqliteTests.all
- SqliteCSharpTests.All ]
+ testSequenced SqliteExtensionTests.integrationTests
+ SqliteCSharpTests.All
+ testSequenced SqliteCSharpExtensionTests.Integration ]
[]
let main args = runTestsWithCLIArgs [] args allTests
diff --git a/src/Tests/SqliteExtensionTests.fs b/src/Tests/SqliteExtensionTests.fs
new file mode 100644
index 0000000..dedf167
--- /dev/null
+++ b/src/Tests/SqliteExtensionTests.fs
@@ -0,0 +1,467 @@
+module SqliteExtensionTests
+
+open BitBadger.Documents
+open BitBadger.Documents.Sqlite
+open BitBadger.Documents.Tests
+open Expecto
+open Microsoft.Data.Sqlite
+open Types
+
+/// Integration tests for the F# extensions on the SqliteConnection data type
+let integrationTests =
+ let documents = [
+ { Id = "one"; Value = "FIRST!"; NumValue = 0; Sub = None }
+ { Id = "two"; Value = "another"; NumValue = 10; Sub = Some { Foo = "green"; Bar = "blue" } }
+ { Id = "three"; Value = ""; NumValue = 4; Sub = None }
+ { Id = "four"; Value = "purple"; NumValue = 17; Sub = Some { Foo = "green"; Bar = "red" } }
+ { Id = "five"; Value = "purple"; NumValue = 18; Sub = None }
+ ]
+ let loadDocs () = backgroundTask {
+ for doc in documents do do! insert SqliteDb.TableName doc
+ }
+ testList "Extensions" [
+ testTask "ensureTable succeeds" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+ let itExists (name: string) = task {
+ let! result =
+ conn.customScalar
+ $"SELECT EXISTS (SELECT 1 FROM {SqliteDb.Catalog} WHERE name = @name) AS it"
+ [ SqliteParameter("@name", name) ]
+ _.GetInt64(0)
+ return result > 0
+ }
+
+ let! exists = itExists "ensured"
+ let! alsoExists = itExists "idx_ensured_key"
+ Expect.isFalse exists "The table should not exist already"
+ Expect.isFalse alsoExists "The key index should not exist already"
+
+ do! conn.ensureTable "ensured"
+ let! exists' = itExists "ensured"
+ let! alsoExists' = itExists "idx_ensured_key"
+ Expect.isTrue exists' "The table should now exist"
+ Expect.isTrue alsoExists' "The key index should now exist"
+ }
+ testList "insert" [
+ testTask "succeeds" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+ let! before = conn.findAll SqliteDb.TableName
+ Expect.equal before [] "There should be no documents in the table"
+
+ let testDoc = { emptyDoc with Id = "turkey"; Sub = Some { Foo = "gobble"; Bar = "gobble" } }
+ do! conn.insert SqliteDb.TableName testDoc
+ let! after = conn.findAll SqliteDb.TableName
+ Expect.equal after [ testDoc ] "There should have been one document inserted"
+ }
+ testTask "fails for duplicate key" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+ do! conn.insert SqliteDb.TableName { emptyDoc with Id = "test" }
+ Expect.throws
+ (fun () ->
+ conn.insert SqliteDb.TableName {emptyDoc with Id = "test" }
+ |> Async.AwaitTask
+ |> Async.RunSynchronously)
+ "An exception should have been raised for duplicate document ID insert"
+ }
+ ]
+ testList "save" [
+ testTask "succeeds when a document is inserted" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+ let! before = conn.findAll SqliteDb.TableName
+ Expect.equal before [] "There should be no documents in the table"
+
+ let testDoc = { emptyDoc with Id = "test"; Sub = Some { Foo = "a"; Bar = "b" } }
+ do! conn.save SqliteDb.TableName testDoc
+ let! after = conn.findAll SqliteDb.TableName
+ Expect.equal after [ testDoc ] "There should have been one document inserted"
+ }
+ testTask "succeeds when a document is updated" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+ let testDoc = { emptyDoc with Id = "test"; Sub = Some { Foo = "a"; Bar = "b" } }
+ do! conn.insert SqliteDb.TableName testDoc
+
+ let! before = conn.findById SqliteDb.TableName "test"
+ if Option.isNone before then Expect.isTrue false "There should have been a document returned"
+ Expect.equal before.Value testDoc "The document is not correct"
+
+ let upd8Doc = { testDoc with Sub = Some { Foo = "c"; Bar = "d" } }
+ do! conn.save SqliteDb.TableName upd8Doc
+ let! after = conn.findById SqliteDb.TableName "test"
+ if Option.isNone after then
+ Expect.isTrue false "There should have been a document returned post-update"
+ Expect.equal after.Value upd8Doc "The updated document is not correct"
+ }
+ ]
+ testTask "countAll succeeds" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+ do! loadDocs ()
+
+ let! theCount = conn.countAll SqliteDb.TableName
+ Expect.equal theCount 5L "There should have been 5 matching documents"
+ }
+ testTask "countByField succeeds" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+ do! loadDocs ()
+
+ let! theCount = conn.countByField SqliteDb.TableName "Value" EQ "purple"
+ Expect.equal theCount 2L "There should have been 2 matching documents"
+ }
+ testList "existsById" [
+ testTask "succeeds when a document exists" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+ do! loadDocs ()
+
+ let! exists = conn.existsById SqliteDb.TableName "three"
+ Expect.isTrue exists "There should have been an existing document"
+ }
+ testTask "succeeds when a document does not exist" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+ do! loadDocs ()
+
+ let! exists = conn.existsById SqliteDb.TableName "seven"
+ Expect.isFalse exists "There should not have been an existing document"
+ }
+ ]
+ testList "existsByField" [
+ testTask "succeeds when documents exist" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+ do! loadDocs ()
+
+ let! exists = conn.existsByField SqliteDb.TableName "NumValue" EQ 10
+ Expect.isTrue exists "There should have been existing documents"
+ }
+ testTask "succeeds when no matching documents exist" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+ do! loadDocs ()
+
+ let! exists = conn.existsByField SqliteDb.TableName "Nothing" EQ "none"
+ Expect.isFalse exists "There should not have been any existing documents"
+ }
+ ]
+ testList "findAll" [
+ testTask "succeeds when there is data" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+
+ do! insert SqliteDb.TableName { Foo = "one"; Bar = "two" }
+ do! insert SqliteDb.TableName { Foo = "three"; Bar = "four" }
+ do! insert SqliteDb.TableName { Foo = "five"; Bar = "six" }
+
+ let! results = conn.findAll SqliteDb.TableName
+ let expected = [
+ { Foo = "one"; Bar = "two" }
+ { Foo = "three"; Bar = "four" }
+ { Foo = "five"; Bar = "six" }
+ ]
+ Expect.equal results expected "There should have been 3 documents returned"
+ }
+ testTask "succeeds when there is no data" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+ let! results = conn.findAll SqliteDb.TableName
+ Expect.equal results [] "There should have been no documents returned"
+ }
+ ]
+ testList "findById" [
+ testTask "succeeds when a document is found" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+ do! loadDocs ()
+
+ let! doc = conn.findById SqliteDb.TableName "two"
+ Expect.isTrue (Option.isSome doc) "There should have been a document returned"
+ Expect.equal doc.Value.Id "two" "The incorrect document was returned"
+ }
+ testTask "succeeds when a document is not found" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+ do! loadDocs ()
+
+ let! doc = conn.findById SqliteDb.TableName "three hundred eighty-seven"
+ Expect.isFalse (Option.isSome doc) "There should not have been a document returned"
+ }
+ ]
+ testList "findByField" [
+ testTask "succeeds when documents are found" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+ do! loadDocs ()
+
+ let! docs = conn.findByField SqliteDb.TableName "Sub.Foo" EQ "green"
+ Expect.equal (List.length docs) 2 "There should have been two documents returned"
+ }
+ testTask "succeeds when documents are not found" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+ do! loadDocs ()
+
+ let! docs = conn.findByField SqliteDb.TableName "Value" EQ "mauve"
+ Expect.isTrue (List.isEmpty docs) "There should have been no documents returned"
+ }
+ ]
+ testList "findFirstByField" [
+ testTask "succeeds when a document is found" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+ do! loadDocs ()
+
+ let! doc = conn.findFirstByField SqliteDb.TableName "Value" EQ "another"
+ Expect.isTrue (Option.isSome doc) "There should have been a document returned"
+ Expect.equal doc.Value.Id "two" "The incorrect document was returned"
+ }
+ testTask "succeeds when multiple documents are found" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+ do! loadDocs ()
+
+ let! doc = conn.findFirstByField SqliteDb.TableName "Sub.Foo" EQ "green"
+ Expect.isTrue (Option.isSome doc) "There should have been a document returned"
+ Expect.contains [ "two"; "four" ] doc.Value.Id "An incorrect document was returned"
+ }
+ testTask "succeeds when a document is not found" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+ do! loadDocs ()
+
+ let! doc = conn.findFirstByField SqliteDb.TableName "Value" EQ "absent"
+ Expect.isFalse (Option.isSome doc) "There should not have been a document returned"
+ }
+ ]
+ testList "updateFull" [
+ testTask "succeeds when a document is updated" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+ do! loadDocs ()
+
+ let testDoc = { emptyDoc with Id = "one"; Sub = Some { Foo = "blue"; Bar = "red" } }
+ do! conn.updateFull SqliteDb.TableName "one" testDoc
+ let! after = conn.findById SqliteDb.TableName "one"
+ if Option.isNone after then
+ Expect.isTrue false "There should have been a document returned post-update"
+ Expect.equal after.Value testDoc "The updated document is not correct"
+ }
+ testTask "succeeds when no document is updated" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+
+ let! before = conn.findAll SqliteDb.TableName
+ Expect.isEmpty before "There should have been no documents returned"
+
+ // This not raising an exception is the test
+ do! conn.updateFull
+ SqliteDb.TableName
+ "test"
+ { emptyDoc with Id = "x"; Sub = Some { Foo = "blue"; Bar = "red" } }
+ }
+ ]
+ testList "updateFullFunc" [
+ testTask "succeeds when a document is updated" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+ do! loadDocs ()
+
+ do! conn.updateFullFunc
+ SqliteDb.TableName
+ (_.Id)
+ { Id = "one"; Value = "le un"; NumValue = 1; Sub = None }
+ let! after = conn.findById SqliteDb.TableName "one"
+ if Option.isNone after then
+ Expect.isTrue false "There should have been a document returned post-update"
+ Expect.equal
+ after.Value
+ { Id = "one"; Value = "le un"; NumValue = 1; Sub = None }
+ "The updated document is not correct"
+ }
+ testTask "succeeds when no document is updated" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+
+ let! before = conn.findAll SqliteDb.TableName
+ Expect.isEmpty before "There should have been no documents returned"
+
+ // This not raising an exception is the test
+ do! conn.updateFullFunc
+ SqliteDb.TableName
+ (_.Id)
+ { Id = "one"; Value = "le un"; NumValue = 1; Sub = None }
+ }
+ ]
+ testList "updatePartialById" [
+ testTask "succeeds when a document is updated" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+ do! loadDocs ()
+
+ do! conn.updatePartialById SqliteDb.TableName "one" {| NumValue = 44 |}
+ let! after = conn.findById SqliteDb.TableName "one"
+ if Option.isNone after then
+ Expect.isTrue false "There should have been a document returned post-update"
+ Expect.equal after.Value.NumValue 44 "The updated document is not correct"
+ }
+ testTask "succeeds when no document is updated" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+
+ let! before = conn.findAll SqliteDb.TableName
+ Expect.isEmpty before "There should have been no documents returned"
+
+ // This not raising an exception is the test
+ do! conn.updatePartialById SqliteDb.TableName "test" {| Foo = "green" |}
+ }
+ ]
+ testList "updatePartialByField" [
+ testTask "succeeds when a document is updated" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+ do! loadDocs ()
+
+ do! conn.updatePartialByField SqliteDb.TableName "Value" EQ "purple" {| NumValue = 77 |}
+ let! after = conn.countByField SqliteDb.TableName "NumValue" EQ 77
+ Expect.equal after 2L "There should have been 2 documents returned"
+ }
+ testTask "succeeds when no document is updated" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+
+ let! before = conn.findAll SqliteDb.TableName
+ Expect.isEmpty before "There should have been no documents returned"
+
+ // This not raising an exception is the test
+ do! conn.updatePartialByField SqliteDb.TableName "Value" EQ "burgundy" {| Foo = "green" |}
+ }
+ ]
+ testList "deleteById" [
+ testTask "succeeds when a document is deleted" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+ do! loadDocs ()
+
+ do! conn.deleteById SqliteDb.TableName "four"
+ let! remaining = conn.countAll SqliteDb.TableName
+ Expect.equal remaining 4L "There should have been 4 documents remaining"
+ }
+ testTask "succeeds when a document is not deleted" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+ do! loadDocs ()
+
+ do! conn.deleteById SqliteDb.TableName "thirty"
+ let! remaining = conn.countAll SqliteDb.TableName
+ Expect.equal remaining 5L "There should have been 5 documents remaining"
+ }
+ ]
+ testList "deleteByField" [
+ testTask "succeeds when documents are deleted" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+ do! loadDocs ()
+
+ do! conn.deleteByField SqliteDb.TableName "Value" NE "purple"
+ let! remaining = conn.countAll SqliteDb.TableName
+ Expect.equal remaining 2L "There should have been 2 documents remaining"
+ }
+ testTask "succeeds when documents are not deleted" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+ do! loadDocs ()
+
+ do! conn.deleteByField SqliteDb.TableName "Value" EQ "crimson"
+ let! remaining = conn.countAll SqliteDb.TableName
+ Expect.equal remaining 5L "There should have been 5 documents remaining"
+ }
+ ]
+ testList "customSingle" [
+ testTask "succeeds when a row is found" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+ do! loadDocs ()
+
+ let! doc =
+ conn.customSingle
+ $"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'Id' = @id"
+ [ SqliteParameter("@id", "one") ]
+ fromData
+ Expect.isSome doc "There should have been a document returned"
+ Expect.equal doc.Value.Id "one" "The incorrect document was returned"
+ }
+ testTask "succeeds when a row is not found" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+ do! loadDocs ()
+
+ let! doc =
+ conn.customSingle
+ $"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'Id' = @id"
+ [ SqliteParameter("@id", "eighty") ]
+ fromData
+ Expect.isNone doc "There should not have been a document returned"
+ }
+ ]
+ testList "customList" [
+ testTask "succeeds when data is found" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+ do! loadDocs ()
+
+ let! docs = conn.customList (Query.selectFromTable SqliteDb.TableName) [] fromData
+ Expect.hasCountOf docs 5u (fun _ -> true) "There should have been 5 documents returned"
+ }
+ testTask "succeeds when data is not found" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+ do! loadDocs ()
+
+ let! docs =
+ conn.customList
+ $"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'NumValue' > @value"
+ [ SqliteParameter("@value", 100) ]
+ fromData
+ Expect.isEmpty docs "There should have been no documents returned"
+ }
+ ]
+ testList "customNonQuery" [
+ testTask "succeeds when operating on data" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+ do! loadDocs ()
+
+ do! conn.customNonQuery $"DELETE FROM {SqliteDb.TableName}" []
+
+ let! remaining = conn.countAll SqliteDb.TableName
+ Expect.equal remaining 0L "There should be no documents remaining in the table"
+ }
+ testTask "succeeds when no data matches where clause" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+ do! loadDocs ()
+
+ do! conn.customNonQuery
+ $"DELETE FROM {SqliteDb.TableName} WHERE data ->> 'NumValue' > @value"
+ [ SqliteParameter("@value", 100) ]
+
+ let! remaining = conn.countAll SqliteDb.TableName
+ Expect.equal remaining 5L "There should be 5 documents remaining in the table"
+ }
+ ]
+ testTask "customScalar succeeds" {
+ use! db = SqliteDb.BuildDb()
+ use conn = Configuration.dbConn ()
+
+ let! nbr = conn.customScalar "SELECT 5 AS test_value" [] _.GetInt32(0)
+ Expect.equal nbr 5 "The query should have returned the number 5"
+ }
+ test "clean up database" {
+ Configuration.useConnectionString "data source=:memory:"
+ }
+ ]
diff --git a/src/Tests/SqliteTests.fs b/src/Tests/SqliteTests.fs
index 56d925a..a632a35 100644
--- a/src/Tests/SqliteTests.fs
+++ b/src/Tests/SqliteTests.fs
@@ -1,26 +1,11 @@
module SqliteTests
-type SubDocument =
- { Foo: string
- Bar: string }
-
-type JsonDocument =
- { Id: string
- Value: string
- NumValue: int
- Sub: SubDocument option }
-
-let emptyDoc = { Id = ""; Value = ""; NumValue = 0; Sub = None }
-
-/// A function that always returns true
-let isTrue<'T> (_ : 'T) = true
-
-
open BitBadger.Documents
open BitBadger.Documents.Sqlite
open BitBadger.Documents.Tests
open Expecto
open Microsoft.Data.Sqlite
+open Types
/// Unit tests for the SQLite library
let unitTests =
@@ -99,6 +84,81 @@ let integrationTests =
Configuration.useIdField "Id"
}
]
+ testList "Custom" [
+ testList "single" [
+ testTask "succeeds when a row is found" {
+ use! db = SqliteDb.BuildDb()
+ do! loadDocs ()
+
+ let! doc =
+ Custom.single
+ $"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'Id' = @id"
+ [ SqliteParameter("@id", "one") ]
+ fromData
+ Expect.isSome doc "There should have been a document returned"
+ Expect.equal doc.Value.Id "one" "The incorrect document was returned"
+ }
+ testTask "succeeds when a row is not found" {
+ use! db = SqliteDb.BuildDb()
+ do! loadDocs ()
+
+ let! doc =
+ Custom.single
+ $"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'Id' = @id"
+ [ SqliteParameter("@id", "eighty") ]
+ fromData
+ Expect.isNone doc "There should not have been a document returned"
+ }
+ ]
+ testList "list" [
+ testTask "succeeds when data is found" {
+ use! db = SqliteDb.BuildDb()
+ do! loadDocs ()
+
+ let! docs = Custom.list (Query.selectFromTable SqliteDb.TableName) [] fromData
+ Expect.hasCountOf docs 5u (fun _ -> true) "There should have been 5 documents returned"
+ }
+ testTask "succeeds when data is not found" {
+ use! db = SqliteDb.BuildDb()
+ do! loadDocs ()
+
+ let! docs =
+ Custom.list
+ $"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'NumValue' > @value"
+ [ SqliteParameter("@value", 100) ]
+ fromData
+ Expect.isEmpty docs "There should have been no documents returned"
+ }
+ ]
+ testList "nonQuery" [
+ testTask "succeeds when operating on data" {
+ use! db = SqliteDb.BuildDb()
+ do! loadDocs ()
+
+ do! Custom.nonQuery $"DELETE FROM {SqliteDb.TableName}" []
+
+ let! remaining = Count.all SqliteDb.TableName
+ Expect.equal remaining 0L "There should be no documents remaining in the table"
+ }
+ testTask "succeeds when no data matches where clause" {
+ use! db = SqliteDb.BuildDb()
+ do! loadDocs ()
+
+ do! Custom.nonQuery
+ $"DELETE FROM {SqliteDb.TableName} WHERE data ->> 'NumValue' > @value"
+ [ SqliteParameter("@value", 100) ]
+
+ let! remaining = Count.all SqliteDb.TableName
+ Expect.equal remaining 5L "There should be 5 documents remaining in the table"
+ }
+ ]
+ testTask "scalar succeeds" {
+ use! db = SqliteDb.BuildDb()
+
+ let! nbr = Custom.scalar "SELECT 5 AS test_value" [] _.GetInt32(0)
+ Expect.equal nbr 5 "The query should have returned the number 5"
+ }
+ ]
testList "Definition" [
testTask "ensureTable succeeds" {
use! db = SqliteDb.BuildDb()
@@ -160,13 +220,13 @@ let integrationTests =
do! insert SqliteDb.TableName testDoc
let! before = Find.byId SqliteDb.TableName "test"
- if Option.isNone before then Expect.isTrue false "There should have been a document returned"
+ Expect.isSome before "There should have been a document returned"
Expect.equal before.Value testDoc "The document is not correct"
let upd8Doc = { testDoc with Sub = Some { Foo = "c"; Bar = "d" } }
do! save SqliteDb.TableName upd8Doc
let! after = Find.byId SqliteDb.TableName "test"
- if Option.isNone after then Expect.isTrue false "There should have been a document returned post-update"
+ Expect.isSome after "There should have been a document returned post-update"
Expect.equal after.Value upd8Doc "The updated document is not correct"
}
]
@@ -311,15 +371,14 @@ let integrationTests =
let testDoc = { emptyDoc with Id = "one"; Sub = Some { Foo = "blue"; Bar = "red" } }
do! Update.full SqliteDb.TableName "one" testDoc
let! after = Find.byId SqliteDb.TableName "one"
- if Option.isNone after then
- Expect.isTrue false "There should have been a document returned post-update"
+ Expect.isSome after "There should have been a document returned post-update"
Expect.equal after.Value testDoc "The updated document is not correct"
}
testTask "succeeds when no document is updated" {
use! db = SqliteDb.BuildDb()
let! before = Find.all SqliteDb.TableName
- Expect.hasCountOf before 0u isTrue "There should have been no documents returned"
+ Expect.isEmpty before "There should have been no documents returned"
// This not raising an exception is the test
do! Update.full
@@ -335,8 +394,7 @@ let integrationTests =
do! Update.fullFunc SqliteDb.TableName (_.Id) { Id = "one"; Value = "le un"; NumValue = 1; Sub = None }
let! after = Find.byId SqliteDb.TableName "one"
- if Option.isNone after then
- Expect.isTrue false "There should have been a document returned post-update"
+ Expect.isSome after "There should have been a document returned post-update"
Expect.equal
after.Value
{ Id = "one"; Value = "le un"; NumValue = 1; Sub = None }
@@ -346,7 +404,7 @@ let integrationTests =
use! db = SqliteDb.BuildDb()
let! before = Find.all SqliteDb.TableName
- Expect.hasCountOf before 0u isTrue "There should have been no documents returned"
+ Expect.isEmpty before "There should have been no documents returned"
// This not raising an exception is the test
do! Update.fullFunc SqliteDb.TableName (_.Id) { Id = "one"; Value = "le un"; NumValue = 1; Sub = None }
@@ -359,15 +417,14 @@ let integrationTests =
do! Update.partialById SqliteDb.TableName "one" {| NumValue = 44 |}
let! after = Find.byId SqliteDb.TableName "one"
- if Option.isNone after then
- Expect.isTrue false "There should have been a document returned post-update"
+ Expect.isSome after "There should have been a document returned post-update"
Expect.equal after.Value.NumValue 44 "The updated document is not correct"
}
testTask "succeeds when no document is updated" {
use! db = SqliteDb.BuildDb()
let! before = Find.all SqliteDb.TableName
- Expect.hasCountOf before 0u isTrue "There should have been no documents returned"
+ Expect.isEmpty before "There should have been no documents returned"
// This not raising an exception is the test
do! Update.partialById SqliteDb.TableName "test" {| Foo = "green" |}
@@ -386,7 +443,7 @@ let integrationTests =
use! db = SqliteDb.BuildDb()
let! before = Find.all SqliteDb.TableName
- Expect.hasCountOf before 0u isTrue "There should have been no documents returned"
+ Expect.isEmpty before "There should have been no documents returned"
// This not raising an exception is the test
do! Update.partialByField SqliteDb.TableName "Value" EQ "burgundy" {| Foo = "green" |}
@@ -431,524 +488,6 @@ let integrationTests =
}
]
]
- testList "Custom" [
- testList "single" [
- testTask "succeeds when a row is found" {
- use! db = SqliteDb.BuildDb()
- do! loadDocs ()
-
- let! doc =
- Custom.single
- $"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'Id' = @id"
- [ SqliteParameter("@id", "one") ]
- fromData
- Expect.isSome doc "There should have been a document returned"
- Expect.equal doc.Value.Id "one" "The incorrect document was returned"
- }
- testTask "succeeds when a row is not found" {
- use! db = SqliteDb.BuildDb()
- do! loadDocs ()
-
- let! doc =
- Custom.single
- $"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'Id' = @id"
- [ SqliteParameter("@id", "eighty") ]
- fromData
- Expect.isNone doc "There should not have been a document returned"
- }
- ]
- testList "list" [
- testTask "succeeds when data is found" {
- use! db = SqliteDb.BuildDb()
- do! loadDocs ()
-
- let! docs = Custom.list (Query.selectFromTable SqliteDb.TableName) [] fromData
- Expect.hasCountOf docs 5u isTrue "There should have been 5 documents returned"
- }
- testTask "succeeds when data is not found" {
- use! db = SqliteDb.BuildDb()
- do! loadDocs ()
-
- let! docs =
- Custom.list
- $"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'NumValue' > @value"
- [ SqliteParameter("@value", 100) ]
- fromData
- Expect.isEmpty docs "There should have been no documents returned"
- }
- ]
- testList "nonQuery" [
- testTask "succeeds when operating on data" {
- use! db = SqliteDb.BuildDb()
- do! loadDocs ()
-
- do! Custom.nonQuery $"DELETE FROM {SqliteDb.TableName}" []
-
- let! remaining = Count.all SqliteDb.TableName
- Expect.equal remaining 0L "There should be no documents remaining in the table"
- }
- testTask "succeeds when no data matches where clause" {
- use! db = SqliteDb.BuildDb()
- do! loadDocs ()
-
- do! Custom.nonQuery
- $"DELETE FROM {SqliteDb.TableName} WHERE data ->> 'NumValue' > @value"
- [ SqliteParameter("@value", 100) ]
-
- let! remaining = Count.all SqliteDb.TableName
- Expect.equal remaining 5L "There should be 5 documents remaining in the table"
- }
- ]
- testTask "scalar succeeds" {
- use! db = SqliteDb.BuildDb()
-
- let! nbr = Custom.scalar "SELECT 5 AS test_value" [] _.GetInt32(0)
- Expect.equal nbr 5 "The query should have returned the number 5"
- }
- ]
- testList "Extensions" [
- testTask "ensureTable succeeds" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
- let itExists (name: string) = task {
- let! result =
- conn.customScalar
- $"SELECT EXISTS (SELECT 1 FROM {SqliteDb.Catalog} WHERE name = @name) AS it"
- [ SqliteParameter("@name", name) ]
- _.GetInt64(0)
- return result > 0
- }
-
- let! exists = itExists "ensured"
- let! alsoExists = itExists "idx_ensured_key"
- Expect.isFalse exists "The table should not exist already"
- Expect.isFalse alsoExists "The key index should not exist already"
-
- do! conn.ensureTable "ensured"
- let! exists' = itExists "ensured"
- let! alsoExists' = itExists "idx_ensured_key"
- Expect.isTrue exists' "The table should now exist"
- Expect.isTrue alsoExists' "The key index should now exist"
- }
- testList "insert" [
- testTask "succeeds" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
- let! before = conn.findAll SqliteDb.TableName
- Expect.equal before [] "There should be no documents in the table"
-
- let testDoc = { emptyDoc with Id = "turkey"; Sub = Some { Foo = "gobble"; Bar = "gobble" } }
- do! conn.insert SqliteDb.TableName testDoc
- let! after = conn.findAll SqliteDb.TableName
- Expect.equal after [ testDoc ] "There should have been one document inserted"
- }
- testTask "fails for duplicate key" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
- do! conn.insert SqliteDb.TableName { emptyDoc with Id = "test" }
- Expect.throws
- (fun () ->
- conn.insert SqliteDb.TableName {emptyDoc with Id = "test" }
- |> Async.AwaitTask
- |> Async.RunSynchronously)
- "An exception should have been raised for duplicate document ID insert"
- }
- ]
- testList "save" [
- testTask "succeeds when a document is inserted" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
- let! before = conn.findAll SqliteDb.TableName
- Expect.equal before [] "There should be no documents in the table"
-
- let testDoc = { emptyDoc with Id = "test"; Sub = Some { Foo = "a"; Bar = "b" } }
- do! conn.save SqliteDb.TableName testDoc
- let! after = conn.findAll SqliteDb.TableName
- Expect.equal after [ testDoc ] "There should have been one document inserted"
- }
- testTask "succeeds when a document is updated" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
- let testDoc = { emptyDoc with Id = "test"; Sub = Some { Foo = "a"; Bar = "b" } }
- do! conn.insert SqliteDb.TableName testDoc
-
- let! before = conn.findById SqliteDb.TableName "test"
- if Option.isNone before then Expect.isTrue false "There should have been a document returned"
- Expect.equal before.Value testDoc "The document is not correct"
-
- let upd8Doc = { testDoc with Sub = Some { Foo = "c"; Bar = "d" } }
- do! conn.save SqliteDb.TableName upd8Doc
- let! after = conn.findById SqliteDb.TableName "test"
- if Option.isNone after then
- Expect.isTrue false "There should have been a document returned post-update"
- Expect.equal after.Value upd8Doc "The updated document is not correct"
- }
- ]
- testTask "countAll succeeds" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
- do! loadDocs ()
-
- let! theCount = conn.countAll SqliteDb.TableName
- Expect.equal theCount 5L "There should have been 5 matching documents"
- }
- testTask "countByField succeeds" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
- do! loadDocs ()
-
- let! theCount = conn.countByField SqliteDb.TableName "Value" EQ "purple"
- Expect.equal theCount 2L "There should have been 2 matching documents"
- }
- testList "existsById" [
- testTask "succeeds when a document exists" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
- do! loadDocs ()
-
- let! exists = conn.existsById SqliteDb.TableName "three"
- Expect.isTrue exists "There should have been an existing document"
- }
- testTask "succeeds when a document does not exist" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
- do! loadDocs ()
-
- let! exists = conn.existsById SqliteDb.TableName "seven"
- Expect.isFalse exists "There should not have been an existing document"
- }
- ]
- testList "existsByField" [
- testTask "succeeds when documents exist" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
- do! loadDocs ()
-
- let! exists = conn.existsByField SqliteDb.TableName "NumValue" EQ 10
- Expect.isTrue exists "There should have been existing documents"
- }
- testTask "succeeds when no matching documents exist" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
- do! loadDocs ()
-
- let! exists = conn.existsByField SqliteDb.TableName "Nothing" EQ "none"
- Expect.isFalse exists "There should not have been any existing documents"
- }
- ]
- testList "findAll" [
- testTask "succeeds when there is data" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
-
- do! insert SqliteDb.TableName { Foo = "one"; Bar = "two" }
- do! insert SqliteDb.TableName { Foo = "three"; Bar = "four" }
- do! insert SqliteDb.TableName { Foo = "five"; Bar = "six" }
-
- let! results = conn.findAll SqliteDb.TableName
- let expected = [
- { Foo = "one"; Bar = "two" }
- { Foo = "three"; Bar = "four" }
- { Foo = "five"; Bar = "six" }
- ]
- Expect.equal results expected "There should have been 3 documents returned"
- }
- testTask "succeeds when there is no data" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
- let! results = conn.findAll SqliteDb.TableName
- Expect.equal results [] "There should have been no documents returned"
- }
- ]
- testList "findById" [
- testTask "succeeds when a document is found" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
- do! loadDocs ()
-
- let! doc = conn.findById SqliteDb.TableName "two"
- Expect.isTrue (Option.isSome doc) "There should have been a document returned"
- Expect.equal doc.Value.Id "two" "The incorrect document was returned"
- }
- testTask "succeeds when a document is not found" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
- do! loadDocs ()
-
- let! doc = conn.findById SqliteDb.TableName "three hundred eighty-seven"
- Expect.isFalse (Option.isSome doc) "There should not have been a document returned"
- }
- ]
- testList "findByField" [
- testTask "succeeds when documents are found" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
- do! loadDocs ()
-
- let! docs = conn.findByField SqliteDb.TableName "Sub.Foo" EQ "green"
- Expect.equal (List.length docs) 2 "There should have been two documents returned"
- }
- testTask "succeeds when documents are not found" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
- do! loadDocs ()
-
- let! docs = conn.findByField SqliteDb.TableName "Value" EQ "mauve"
- Expect.isTrue (List.isEmpty docs) "There should have been no documents returned"
- }
- ]
- testList "findFirstByField" [
- testTask "succeeds when a document is found" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
- do! loadDocs ()
-
- let! doc = conn.findFirstByField SqliteDb.TableName "Value" EQ "another"
- Expect.isTrue (Option.isSome doc) "There should have been a document returned"
- Expect.equal doc.Value.Id "two" "The incorrect document was returned"
- }
- testTask "succeeds when multiple documents are found" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
- do! loadDocs ()
-
- let! doc = conn.findFirstByField SqliteDb.TableName "Sub.Foo" EQ "green"
- Expect.isTrue (Option.isSome doc) "There should have been a document returned"
- Expect.contains [ "two"; "four" ] doc.Value.Id "An incorrect document was returned"
- }
- testTask "succeeds when a document is not found" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
- do! loadDocs ()
-
- let! doc = conn.findFirstByField SqliteDb.TableName "Value" EQ "absent"
- Expect.isFalse (Option.isSome doc) "There should not have been a document returned"
- }
- ]
- testList "updateFull" [
- testTask "succeeds when a document is updated" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
- do! loadDocs ()
-
- let testDoc = { emptyDoc with Id = "one"; Sub = Some { Foo = "blue"; Bar = "red" } }
- do! conn.updateFull SqliteDb.TableName "one" testDoc
- let! after = conn.findById SqliteDb.TableName "one"
- if Option.isNone after then
- Expect.isTrue false "There should have been a document returned post-update"
- Expect.equal after.Value testDoc "The updated document is not correct"
- }
- testTask "succeeds when no document is updated" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
-
- let! before = conn.findAll SqliteDb.TableName
- Expect.hasCountOf before 0u isTrue "There should have been no documents returned"
-
- // This not raising an exception is the test
- do! conn.updateFull
- SqliteDb.TableName
- "test"
- { emptyDoc with Id = "x"; Sub = Some { Foo = "blue"; Bar = "red" } }
- }
- ]
- testList "updateFullFunc" [
- testTask "succeeds when a document is updated" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
- do! loadDocs ()
-
- do! conn.updateFullFunc
- SqliteDb.TableName
- (_.Id)
- { Id = "one"; Value = "le un"; NumValue = 1; Sub = None }
- let! after = conn.findById SqliteDb.TableName "one"
- if Option.isNone after then
- Expect.isTrue false "There should have been a document returned post-update"
- Expect.equal
- after.Value
- { Id = "one"; Value = "le un"; NumValue = 1; Sub = None }
- "The updated document is not correct"
- }
- testTask "succeeds when no document is updated" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
-
- let! before = conn.findAll SqliteDb.TableName
- Expect.hasCountOf before 0u isTrue "There should have been no documents returned"
-
- // This not raising an exception is the test
- do! conn.updateFullFunc
- SqliteDb.TableName
- (_.Id)
- { Id = "one"; Value = "le un"; NumValue = 1; Sub = None }
- }
- ]
- testList "updatePartialById" [
- testTask "succeeds when a document is updated" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
- do! loadDocs ()
-
- do! conn.updatePartialById SqliteDb.TableName "one" {| NumValue = 44 |}
- let! after = conn.findById SqliteDb.TableName "one"
- if Option.isNone after then
- Expect.isTrue false "There should have been a document returned post-update"
- Expect.equal after.Value.NumValue 44 "The updated document is not correct"
- }
- testTask "succeeds when no document is updated" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
-
- let! before = conn.findAll SqliteDb.TableName
- Expect.hasCountOf before 0u isTrue "There should have been no documents returned"
-
- // This not raising an exception is the test
- do! conn.updatePartialById SqliteDb.TableName "test" {| Foo = "green" |}
- }
- ]
- testList "updatePartialByField" [
- testTask "succeeds when a document is updated" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
- do! loadDocs ()
-
- do! conn.updatePartialByField SqliteDb.TableName "Value" EQ "purple" {| NumValue = 77 |}
- let! after = conn.countByField SqliteDb.TableName "NumValue" EQ 77
- Expect.equal after 2L "There should have been 2 documents returned"
- }
- testTask "succeeds when no document is updated" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
-
- let! before = conn.findAll SqliteDb.TableName
- Expect.hasCountOf before 0u isTrue "There should have been no documents returned"
-
- // This not raising an exception is the test
- do! conn.updatePartialByField SqliteDb.TableName "Value" EQ "burgundy" {| Foo = "green" |}
- }
- ]
- testList "deleteById" [
- testTask "succeeds when a document is deleted" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
- do! loadDocs ()
-
- do! conn.deleteById SqliteDb.TableName "four"
- let! remaining = conn.countAll SqliteDb.TableName
- Expect.equal remaining 4L "There should have been 4 documents remaining"
- }
- testTask "succeeds when a document is not deleted" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
- do! loadDocs ()
-
- do! conn.deleteById SqliteDb.TableName "thirty"
- let! remaining = conn.countAll SqliteDb.TableName
- Expect.equal remaining 5L "There should have been 5 documents remaining"
- }
- ]
- testList "deleteByField" [
- testTask "succeeds when documents are deleted" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
- do! loadDocs ()
-
- do! conn.deleteByField SqliteDb.TableName "Value" NE "purple"
- let! remaining = conn.countAll SqliteDb.TableName
- Expect.equal remaining 2L "There should have been 2 documents remaining"
- }
- testTask "succeeds when documents are not deleted" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
- do! loadDocs ()
-
- do! conn.deleteByField SqliteDb.TableName "Value" EQ "crimson"
- let! remaining = conn.countAll SqliteDb.TableName
- Expect.equal remaining 5L "There should have been 5 documents remaining"
- }
- ]
- testList "customSingle" [
- testTask "succeeds when a row is found" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
- do! loadDocs ()
-
- let! doc =
- conn.customSingle
- $"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'Id' = @id"
- [ SqliteParameter("@id", "one") ]
- fromData
- Expect.isSome doc "There should have been a document returned"
- Expect.equal doc.Value.Id "one" "The incorrect document was returned"
- }
- testTask "succeeds when a row is not found" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
- do! loadDocs ()
-
- let! doc =
- conn.customSingle
- $"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'Id' = @id"
- [ SqliteParameter("@id", "eighty") ]
- fromData
- Expect.isNone doc "There should not have been a document returned"
- }
- ]
- testList "customList" [
- testTask "succeeds when data is found" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
- do! loadDocs ()
-
- let! docs = conn.customList (Query.selectFromTable SqliteDb.TableName) [] fromData
- Expect.hasCountOf docs 5u isTrue "There should have been 5 documents returned"
- }
- testTask "succeeds when data is not found" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
- do! loadDocs ()
-
- let! docs =
- conn.customList
- $"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'NumValue' > @value"
- [ SqliteParameter("@value", 100) ]
- fromData
- Expect.isEmpty docs "There should have been no documents returned"
- }
- ]
- testList "customNonQuery" [
- testTask "succeeds when operating on data" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
- do! loadDocs ()
-
- do! conn.customNonQuery $"DELETE FROM {SqliteDb.TableName}" []
-
- let! remaining = conn.countAll SqliteDb.TableName
- Expect.equal remaining 0L "There should be no documents remaining in the table"
- }
- testTask "succeeds when no data matches where clause" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
- do! loadDocs ()
-
- do! conn.customNonQuery
- $"DELETE FROM {SqliteDb.TableName} WHERE data ->> 'NumValue' > @value"
- [ SqliteParameter("@value", 100) ]
-
- let! remaining = conn.countAll SqliteDb.TableName
- Expect.equal remaining 5L "There should be 5 documents remaining in the table"
- }
- ]
- testTask "customScalar succeeds" {
- use! db = SqliteDb.BuildDb()
- use conn = Configuration.dbConn ()
-
- let! nbr = conn.customScalar "SELECT 5 AS test_value" [] _.GetInt32(0)
- Expect.equal nbr 5 "The query should have returned the number 5"
- }
- ]
test "clean up database" {
Configuration.useConnectionString "data source=:memory:"
}
diff --git a/src/Tests/Types.fs b/src/Tests/Types.fs
new file mode 100644
index 0000000..e696a2a
--- /dev/null
+++ b/src/Tests/Types.fs
@@ -0,0 +1,13 @@
+module Types
+
+type SubDocument =
+ { Foo: string
+ Bar: string }
+
+type JsonDocument =
+ { Id: string
+ Value: string
+ NumValue: int
+ Sub: SubDocument option }
+
+let emptyDoc = { Id = ""; Value = ""; NumValue = 0; Sub = None }