Move extensions to separate project
- Move tests into separate files
This commit is contained in:
parent
a6d179d401
commit
f2bb1c4aba
|
@ -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
|
||||||
|
|
|
@ -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>
|
216
src/Sqlite.Extensions/Library.fs
Normal file
216
src/Sqlite.Extensions/Library.fs
Normal 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
|
|
@ -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
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
511
src/Tests.CSharp/SqliteCSharpExtensionTests.cs
Normal file
511
src/Tests.CSharp/SqliteCSharpExtensionTests.cs
Normal 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:"))
|
||||||
|
});
|
||||||
|
}
|
|
@ -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:"))
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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
|
||||||
|
|
467
src/Tests/SqliteExtensionTests.fs
Normal file
467
src/Tests/SqliteExtensionTests.fs
Normal 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:"
|
||||||
|
}
|
||||||
|
]
|
|
@ -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
13
src/Tests/Types.fs
Normal 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 }
|
Loading…
Reference in New Issue
Block a user