v3 RC1 #1

Merged
danieljsummers merged 25 commits from merge-projects into main 2024-01-06 20:51:49 +00:00
12 changed files with 1317 additions and 1256 deletions
Showing only changes of commit f2bb1c4aba - Show all commits

View File

@ -13,6 +13,8 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "BitBadger.Documents.Sqlite"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BitBadger.Documents.Tests.CSharp", "Tests.CSharp\BitBadger.Documents.Tests.CSharp.csproj", "{AB58418C-7F90-467E-8F67-F4E0AD9D8875}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BitBadger.Documents.Tests.CSharp", "Tests.CSharp\BitBadger.Documents.Tests.CSharp.csproj", "{AB58418C-7F90-467E-8F67-F4E0AD9D8875}"
EndProject 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 Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU 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}.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.ActiveCfg = Release|Any CPU
{AB58418C-7F90-467E-8F67-F4E0AD9D8875}.Release|Any CPU.Build.0 = 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 EndGlobalSection
EndGlobal EndGlobal

View File

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<Compile Include="Library.fs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Sqlite\BitBadger.Documents.Sqlite.fsproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,216 @@
namespace BitBadger.Documents.Sqlite
open Microsoft.Data.Sqlite
/// F# extensions for the SqliteConnection type
[<AutoOpen>]
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
[<Extension>]
type SqliteConnectionCSharpExtensions =
/// Execute a query that returns a list of results
[<Extension>]
static member inline CustomList<'TDoc>(conn, query, parameters, mapFunc: System.Func<SqliteDataReader, 'TDoc>) =
WithConn.Custom.List<'TDoc>(query, parameters, mapFunc, conn)
/// Execute a query that returns one or no results
[<Extension>]
static member inline CustomSingle<'TDoc when 'TDoc: null>(
conn, query, parameters, mapFunc: System.Func<SqliteDataReader, 'TDoc>) =
WithConn.Custom.Single<'TDoc>(query, parameters, mapFunc, conn)
/// Execute a query that does not return a value
[<Extension>]
static member inline CustomNonQuery(conn, query, parameters) =
WithConn.Custom.nonQuery query parameters conn
/// Execute a query that returns a scalar value
[<Extension>]
static member inline CustomScalar<'T when 'T: struct>(
conn, query, parameters, mapFunc: System.Func<SqliteDataReader, 'T>) =
WithConn.Custom.Scalar<'T>(query, parameters, mapFunc, conn)
/// Create a document table
[<Extension>]
static member inline EnsureTable(conn, name) =
WithConn.Definition.ensureTable name conn
/// Create an index on one or more fields in a document table
[<Extension>]
static member inline EnsureIndex(conn, tableName, indexName, fields) =
WithConn.Definition.ensureIndex tableName indexName fields conn
/// Insert a new document
[<Extension>]
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")
[<Extension>]
static member inline Save<'TDoc>(conn, tableName, document: 'TDoc) =
WithConn.save<'TDoc> tableName document conn
/// Count all documents in a table
[<Extension>]
static member inline CountAll(conn, tableName) =
WithConn.Count.all tableName conn
/// Count matching documents using a comparison on a JSON field
[<Extension>]
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
[<Extension>]
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
[<Extension>]
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
[<Extension>]
static member inline FindAll<'TDoc>(conn, tableName) =
WithConn.Find.All<'TDoc>(tableName, conn)
/// Retrieve a document by its ID
[<Extension>]
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
[<Extension>]
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
[<Extension>]
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
[<Extension>]
static member inline UpdateFull<'TKey, 'TDoc>(conn, tableName, docId: 'TKey, document: 'TDoc) =
WithConn.Update.full tableName docId document conn
/// Update an entire document
[<Extension>]
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
[<Extension>]
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
[<Extension>]
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
[<Extension>]
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
[<Extension>]
static member inline DeleteByField(conn, tableName, fieldName, op, value: obj) =
WithConn.Delete.byField tableName fieldName op value conn

View File

@ -519,217 +519,3 @@ module Delete =
let byField tableName fieldName op (value: obj) = let byField tableName fieldName op (value: obj) =
use conn = Configuration.dbConn () use conn = Configuration.dbConn ()
WithConn.Delete.byField tableName fieldName op value conn WithConn.Delete.byField tableName fieldName op value conn
/// F# extensions for the SqliteConnection type
[<AutoOpen>]
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
[<Extension>]
type SqliteConnectionCSharpExtensions =
/// Execute a query that returns a list of results
[<Extension>]
static member inline CustomList<'TDoc>(conn, query, parameters, mapFunc: System.Func<SqliteDataReader, 'TDoc>) =
WithConn.Custom.List<'TDoc>(query, parameters, mapFunc, conn)
/// Execute a query that returns one or no results
[<Extension>]
static member inline CustomSingle<'TDoc when 'TDoc: null>(
conn, query, parameters, mapFunc: System.Func<SqliteDataReader, 'TDoc>) =
WithConn.Custom.Single<'TDoc>(query, parameters, mapFunc, conn)
/// Execute a query that does not return a value
[<Extension>]
static member inline CustomNonQuery(conn, query, parameters) =
WithConn.Custom.nonQuery query parameters conn
/// Execute a query that returns a scalar value
[<Extension>]
static member inline CustomScalar<'T when 'T: struct>(
conn, query, parameters, mapFunc: System.Func<SqliteDataReader, 'T>) =
WithConn.Custom.Scalar<'T>(query, parameters, mapFunc, conn)
/// Create a document table
[<Extension>]
static member inline EnsureTable(conn, name) =
WithConn.Definition.ensureTable name conn
/// Create an index on one or more fields in a document table
[<Extension>]
static member inline EnsureIndex(conn, tableName, indexName, fields) =
WithConn.Definition.ensureIndex tableName indexName fields conn
/// Insert a new document
[<Extension>]
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")
[<Extension>]
static member inline Save<'TDoc>(conn, tableName, document: 'TDoc) =
WithConn.save<'TDoc> tableName document conn
/// Count all documents in a table
[<Extension>]
static member inline CountAll(conn, tableName) =
WithConn.Count.all tableName conn
/// Count matching documents using a comparison on a JSON field
[<Extension>]
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
[<Extension>]
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
[<Extension>]
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
[<Extension>]
static member inline FindAll<'TDoc>(conn, tableName) =
WithConn.Find.All<'TDoc>(tableName, conn)
/// Retrieve a document by its ID
[<Extension>]
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
[<Extension>]
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
[<Extension>]
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
[<Extension>]
static member inline UpdateFull<'TKey, 'TDoc>(conn, tableName, docId: 'TKey, document: 'TDoc) =
WithConn.Update.full tableName docId document conn
/// Update an entire document
[<Extension>]
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
[<Extension>]
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
[<Extension>]
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
[<Extension>]
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
[<Extension>]
static member inline DeleteByField(conn, tableName, fieldName, op, value: obj) =
WithConn.Delete.byField tableName fieldName op value conn

View File

@ -7,6 +7,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Common\BitBadger.Documents.Common.fsproj" /> <ProjectReference Include="..\Common\BitBadger.Documents.Common.fsproj" />
<ProjectReference Include="..\Sqlite.Extensions\BitBadger.Documents.Sqlite.Extensions.fsproj" />
<ProjectReference Include="..\Sqlite\BitBadger.Documents.Sqlite.fsproj" /> <ProjectReference Include="..\Sqlite\BitBadger.Documents.Sqlite.fsproj" />
</ItemGroup> </ItemGroup>

View File

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

View File

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

View File

@ -6,7 +6,9 @@
<ItemGroup> <ItemGroup>
<Compile Include="CommonTests.fs" /> <Compile Include="CommonTests.fs" />
<Compile Include="Types.fs" />
<Compile Include="SqliteTests.fs" /> <Compile Include="SqliteTests.fs" />
<Compile Include="SqliteExtensionTests.fs" />
<Compile Include="Program.fs" /> <Compile Include="Program.fs" />
</ItemGroup> </ItemGroup>
@ -16,6 +18,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Common\BitBadger.Documents.Common.fsproj" /> <ProjectReference Include="..\Common\BitBadger.Documents.Common.fsproj" />
<ProjectReference Include="..\Sqlite.Extensions\BitBadger.Documents.Sqlite.Extensions.fsproj" />
<ProjectReference Include="..\Sqlite\BitBadger.Documents.Sqlite.fsproj" /> <ProjectReference Include="..\Sqlite\BitBadger.Documents.Sqlite.fsproj" />
<ProjectReference Include="..\Tests.CSharp\BitBadger.Documents.Tests.CSharp.csproj" /> <ProjectReference Include="..\Tests.CSharp\BitBadger.Documents.Tests.CSharp.csproj" />
</ItemGroup> </ItemGroup>

View File

@ -7,7 +7,9 @@ let allTests =
[ CommonTests.all [ CommonTests.all
CommonCSharpTests.Unit CommonCSharpTests.Unit
SqliteTests.all SqliteTests.all
SqliteCSharpTests.All ] testSequenced SqliteExtensionTests.integrationTests
SqliteCSharpTests.All
testSequenced SqliteCSharpExtensionTests.Integration ]
[<EntryPoint>] [<EntryPoint>]
let main args = runTestsWithCLIArgs [] args allTests let main args = runTestsWithCLIArgs [] args allTests

View File

@ -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<SubDocument> 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<JsonDocument> 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<JsonDocument> 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<JsonDocument> 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<string, JsonDocument> 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<string, JsonDocument> 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<SubDocument> 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<SubDocument> 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<string, JsonDocument> 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<string, JsonDocument> 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<JsonDocument> 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<JsonDocument> 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<JsonDocument> 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<JsonDocument> 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<JsonDocument> 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<string, JsonDocument> 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<JsonDocument> 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<string, JsonDocument> 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<JsonDocument> 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<string, JsonDocument> 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<SubDocument> 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<SubDocument> 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<JsonDocument>
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<JsonDocument>
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<JsonDocument>
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<JsonDocument>
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:"
}
]

View File

@ -1,26 +1,11 @@
module SqliteTests 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
open BitBadger.Documents.Sqlite open BitBadger.Documents.Sqlite
open BitBadger.Documents.Tests open BitBadger.Documents.Tests
open Expecto open Expecto
open Microsoft.Data.Sqlite open Microsoft.Data.Sqlite
open Types
/// Unit tests for the SQLite library /// Unit tests for the SQLite library
let unitTests = let unitTests =
@ -99,6 +84,81 @@ let integrationTests =
Configuration.useIdField "Id" 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<JsonDocument>
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<JsonDocument>
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<JsonDocument>
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<JsonDocument>
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" [ testList "Definition" [
testTask "ensureTable succeeds" { testTask "ensureTable succeeds" {
use! db = SqliteDb.BuildDb() use! db = SqliteDb.BuildDb()
@ -160,13 +220,13 @@ let integrationTests =
do! insert SqliteDb.TableName testDoc do! insert SqliteDb.TableName testDoc
let! before = Find.byId<string, JsonDocument> SqliteDb.TableName "test" let! before = Find.byId<string, JsonDocument> 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" Expect.equal before.Value testDoc "The document is not correct"
let upd8Doc = { testDoc with Sub = Some { Foo = "c"; Bar = "d" } } let upd8Doc = { testDoc with Sub = Some { Foo = "c"; Bar = "d" } }
do! save SqliteDb.TableName upd8Doc do! save SqliteDb.TableName upd8Doc
let! after = Find.byId<string, JsonDocument> SqliteDb.TableName "test" let! after = Find.byId<string, JsonDocument> 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" 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" } } let testDoc = { emptyDoc with Id = "one"; Sub = Some { Foo = "blue"; Bar = "red" } }
do! Update.full SqliteDb.TableName "one" testDoc do! Update.full SqliteDb.TableName "one" testDoc
let! after = Find.byId<string, JsonDocument> SqliteDb.TableName "one" let! after = Find.byId<string, JsonDocument> SqliteDb.TableName "one"
if Option.isNone after then Expect.isSome after "There should have been a document returned post-update"
Expect.isTrue false "There should have been a document returned post-update"
Expect.equal after.Value testDoc "The updated document is not correct" Expect.equal after.Value testDoc "The updated document is not correct"
} }
testTask "succeeds when no document is updated" { testTask "succeeds when no document is updated" {
use! db = SqliteDb.BuildDb() use! db = SqliteDb.BuildDb()
let! before = Find.all<JsonDocument> SqliteDb.TableName let! before = Find.all<JsonDocument> 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 // This not raising an exception is the test
do! Update.full do! Update.full
@ -335,8 +394,7 @@ let integrationTests =
do! Update.fullFunc SqliteDb.TableName (_.Id) { Id = "one"; Value = "le un"; NumValue = 1; Sub = None } do! Update.fullFunc SqliteDb.TableName (_.Id) { Id = "one"; Value = "le un"; NumValue = 1; Sub = None }
let! after = Find.byId<string, JsonDocument> SqliteDb.TableName "one" let! after = Find.byId<string, JsonDocument> SqliteDb.TableName "one"
if Option.isNone after then Expect.isSome after "There should have been a document returned post-update"
Expect.isTrue false "There should have been a document returned post-update"
Expect.equal Expect.equal
after.Value after.Value
{ Id = "one"; Value = "le un"; NumValue = 1; Sub = None } { Id = "one"; Value = "le un"; NumValue = 1; Sub = None }
@ -346,7 +404,7 @@ let integrationTests =
use! db = SqliteDb.BuildDb() use! db = SqliteDb.BuildDb()
let! before = Find.all<JsonDocument> SqliteDb.TableName let! before = Find.all<JsonDocument> 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 // This not raising an exception is the test
do! Update.fullFunc SqliteDb.TableName (_.Id) { Id = "one"; Value = "le un"; NumValue = 1; Sub = None } 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 |} do! Update.partialById SqliteDb.TableName "one" {| NumValue = 44 |}
let! after = Find.byId<string, JsonDocument> SqliteDb.TableName "one" let! after = Find.byId<string, JsonDocument> SqliteDb.TableName "one"
if Option.isNone after then Expect.isSome after "There should have been a document returned post-update"
Expect.isTrue false "There should have been a document returned post-update"
Expect.equal after.Value.NumValue 44 "The updated document is not correct" Expect.equal after.Value.NumValue 44 "The updated document is not correct"
} }
testTask "succeeds when no document is updated" { testTask "succeeds when no document is updated" {
use! db = SqliteDb.BuildDb() use! db = SqliteDb.BuildDb()
let! before = Find.all<SubDocument> SqliteDb.TableName let! before = Find.all<SubDocument> 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 // This not raising an exception is the test
do! Update.partialById SqliteDb.TableName "test" {| Foo = "green" |} do! Update.partialById SqliteDb.TableName "test" {| Foo = "green" |}
@ -386,7 +443,7 @@ let integrationTests =
use! db = SqliteDb.BuildDb() use! db = SqliteDb.BuildDb()
let! before = Find.all<SubDocument> SqliteDb.TableName let! before = Find.all<SubDocument> 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 // This not raising an exception is the test
do! Update.partialByField SqliteDb.TableName "Value" EQ "burgundy" {| Foo = "green" |} 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<JsonDocument>
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<JsonDocument>
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<JsonDocument>
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<JsonDocument>
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<SubDocument> 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<JsonDocument> 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<JsonDocument> 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<JsonDocument> 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<string, JsonDocument> 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<string, JsonDocument> 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<SubDocument> 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<SubDocument> 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<string, JsonDocument> 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<string, JsonDocument> 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<JsonDocument> 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<JsonDocument> 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<JsonDocument> 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<JsonDocument> 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<JsonDocument> 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<string, JsonDocument> 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<JsonDocument> 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<string, JsonDocument> 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<JsonDocument> 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<string, JsonDocument> 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<SubDocument> 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<SubDocument> 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<JsonDocument>
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<JsonDocument>
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<JsonDocument>
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<JsonDocument>
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" { test "clean up database" {
Configuration.useConnectionString "data source=:memory:" Configuration.useConnectionString "data source=:memory:"
} }

13
src/Tests/Types.fs Normal file
View File

@ -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 }