This encompasses:
- New behavior for SQLite
- Migrated behavior for PostrgeSQL (from BitBadger.Npgsql.FSharp.Documents)
- New "byField" behavior for PostgreSQL
- A unification of C# and F# centric implementations
This commit was merged in pull request #1.
This commit is contained in:
2024-01-06 15:51:48 -05:00
committed by GitHub
parent a0a4f6604c
commit 68ad874256
36 changed files with 8604 additions and 0 deletions

View File

@@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<Compile Include="CommonTests.fs" />
<Compile Include="Types.fs" />
<Compile Include="PostgresTests.fs" />
<Compile Include="PostgresExtensionTests.fs" />
<Compile Include="SqliteTests.fs" />
<Compile Include="SqliteExtensionTests.fs" />
<Compile Include="Program.fs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Expecto" Version="10.1.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Common\BitBadger.Documents.Common.fsproj" />
<ProjectReference Include="..\Postgres\BitBadger.Documents.Postgres.fsproj" />
<ProjectReference Include="..\Sqlite\BitBadger.Documents.Sqlite.fsproj" />
<ProjectReference Include="..\Tests.CSharp\BitBadger.Documents.Tests.CSharp.csproj" />
</ItemGroup>
</Project>

159
src/Tests/CommonTests.fs Normal file
View File

@@ -0,0 +1,159 @@
module CommonTests
open BitBadger.Documents
open Expecto
/// Test table name
let tbl = "test_table"
/// Tests which do not hit the database
let all =
testList "Common" [
testList "Op" [
test "EQ succeeds" {
Expect.equal (string EQ) "=" "The equals operator was not correct"
}
test "GT succeeds" {
Expect.equal (string GT) ">" "The greater than operator was not correct"
}
test "GE succeeds" {
Expect.equal (string GE) ">=" "The greater than or equal to operator was not correct"
}
test "LT succeeds" {
Expect.equal (string LT) "<" "The less than operator was not correct"
}
test "LE succeeds" {
Expect.equal (string LE) "<=" "The less than or equal to operator was not correct"
}
test "NE succeeds" {
Expect.equal (string NE) "<>" "The not equal to operator was not correct"
}
test "EX succeeds" {
Expect.equal (string EX) "IS NOT NULL" """The "exists" operator was not correct"""
}
test "NEX succeeds" {
Expect.equal (string NEX) "IS NULL" """The "not exists" operator was not correct"""
}
]
testList "Query" [
test "selectFromTable succeeds" {
Expect.equal (Query.selectFromTable tbl) $"SELECT data FROM {tbl}" "SELECT statement not correct"
}
test "whereById succeeds" {
Expect.equal (Query.whereById "@id") "data ->> 'Id' = @id" "WHERE clause not correct"
}
testList "whereByField" [
test "succeeds when a logical operator is passed" {
Expect.equal
(Query.whereByField "theField" GT "@test")
"data ->> 'theField' > @test"
"WHERE clause not correct"
}
test "succeeds when an existence operator is passed" {
Expect.equal
(Query.whereByField "thatField" NEX "")
"data ->> 'thatField' IS NULL"
"WHERE clause not correct"
}
]
testList "Definition" [
test "ensureTableFor succeeds" {
Expect.equal
(Query.Definition.ensureTableFor "my.table" "JSONB")
"CREATE TABLE IF NOT EXISTS my.table (data JSONB NOT NULL)"
"CREATE TABLE statement not constructed correctly"
}
testList "ensureKey" [
test "succeeds when a schema is present" {
Expect.equal
(Query.Definition.ensureKey "test.table")
"CREATE UNIQUE INDEX IF NOT EXISTS idx_table_key ON test.table ((data ->> 'Id'))"
"CREATE INDEX for key statement with schema not constructed correctly"
}
test "succeeds when a schema is not present" {
Expect.equal
(Query.Definition.ensureKey "table")
"CREATE UNIQUE INDEX IF NOT EXISTS idx_table_key ON table ((data ->> 'Id'))"
"CREATE INDEX for key statement without schema not constructed correctly"
}
]
test "ensureIndexOn succeeds for multiple fields and directions" {
Expect.equal
(Query.Definition.ensureIndexOn "test.table" "gibberish" [ "taco"; "guac DESC"; "salsa ASC" ])
([ "CREATE INDEX IF NOT EXISTS idx_table_gibberish ON test.table "
"((data ->> 'taco'), (data ->> 'guac') DESC, (data ->> 'salsa') ASC)" ]
|> String.concat "")
"CREATE INDEX for multiple field statement incorrect"
}
]
test "insert succeeds" {
Expect.equal (Query.insert tbl) $"INSERT INTO {tbl} VALUES (@data)" "INSERT statement not correct"
}
test "save succeeds" {
Expect.equal
(Query.save tbl)
$"INSERT INTO {tbl} VALUES (@data) ON CONFLICT ((data ->> 'Id')) DO UPDATE SET data = EXCLUDED.data"
"INSERT ON CONFLICT UPDATE statement not correct"
}
test "update succeeds" {
Expect.equal
(Query.update tbl)
$"UPDATE {tbl} SET data = @data WHERE data ->> 'Id' = @id"
"UPDATE full statement not correct"
}
testList "Count" [
test "all succeeds" {
Expect.equal (Query.Count.all tbl) $"SELECT COUNT(*) AS it FROM {tbl}" "Count query not correct"
}
test "byField succeeds" {
Expect.equal
(Query.Count.byField tbl "thatField" EQ)
$"SELECT COUNT(*) AS it FROM {tbl} WHERE data ->> 'thatField' = @field"
"JSON field text comparison count query not correct"
}
]
testList "Exists" [
test "byId succeeds" {
Expect.equal
(Query.Exists.byId tbl)
$"SELECT EXISTS (SELECT 1 FROM {tbl} WHERE data ->> 'Id' = @id) AS it"
"ID existence query not correct"
}
test "byField succeeds" {
Expect.equal
(Query.Exists.byField tbl "Test" LT)
$"SELECT EXISTS (SELECT 1 FROM {tbl} WHERE data ->> 'Test' < @field) AS it"
"JSON field text comparison exists query not correct"
}
]
testList "Find" [
test "byId succeeds" {
Expect.equal
(Query.Find.byId tbl)
$"SELECT data FROM {tbl} WHERE data ->> 'Id' = @id"
"SELECT by ID query not correct"
}
test "byField succeeds" {
Expect.equal
(Query.Find.byField tbl "Golf" GE)
$"SELECT data FROM {tbl} WHERE data ->> 'Golf' >= @field"
"SELECT by JSON comparison query not correct"
}
]
testList "Delete" [
test "byId succeeds" {
Expect.equal
(Query.Delete.byId tbl)
$"DELETE FROM {tbl} WHERE data ->> 'Id' = @id"
"DELETE by ID query not correct"
}
test "byField succeeds" {
Expect.equal
(Query.Delete.byField tbl "gone" NEX)
$"DELETE FROM {tbl} WHERE data ->> 'gone' IS NULL"
"DELETE by JSON comparison query not correct"
}
]
]
]

View File

@@ -0,0 +1,700 @@
module PostgresExtensionTests
open BitBadger.Documents
open BitBadger.Documents.Postgres
open BitBadger.Documents.Tests
open Expecto
open Npgsql
open Types
/// Open a connection to the throwaway database
let private mkConn (db: ThrowawayPostgresDb) =
let conn = new NpgsqlConnection(db.ConnectionString)
conn.Open()
conn
/// Integration tests for the F# extensions on the NpgsqlConnection data type
let integrationTests =
let loadDocs (conn: NpgsqlConnection) = backgroundTask {
for doc in testDocuments do do! conn.insert PostgresDb.TableName doc
}
testList "Postgres.Extensions" [
testList "customList" [
testTask "succeeds when data is found" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let! docs = conn.customList (Query.selectFromTable PostgresDb.TableName) [] fromData<JsonDocument>
Expect.equal (List.length docs) 5 "There should have been 5 documents returned"
}
testTask "succeeds when data is not found" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let! docs =
conn.customList
$"SELECT data FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath"
[ "@path", Sql.string "$.NumValue ? (@ > 100)" ]
fromData<JsonDocument>
Expect.isEmpty docs "There should have been no documents returned"
}
]
testList "customSingle" [
testTask "succeeds when a row is found" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let! doc =
conn.customSingle
$"SELECT data FROM {PostgresDb.TableName} WHERE data ->> 'Id' = @id"
[ "@id", Sql.string "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 = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let! doc =
conn.customSingle
$"SELECT data FROM {PostgresDb.TableName} WHERE data ->> 'Id' = @id"
[ "@id", Sql.string "eighty" ]
fromData<JsonDocument>
Expect.isNone doc "There should not have been a document returned"
}
]
testList "customNonQuery" [
testTask "succeeds when operating on data" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
do! conn.customNonQuery $"DELETE FROM {PostgresDb.TableName}" []
let! remaining = conn.countAll PostgresDb.TableName
Expect.equal remaining 0 "There should be no documents remaining in the table"
}
testTask "succeeds when no data matches where clause" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
do! conn.customNonQuery
$"DELETE FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath"
[ "@path", Sql.string "$.NumValue ? (@ > 100)" ]
let! remaining = conn.countAll PostgresDb.TableName
Expect.equal remaining 5 "There should be 5 documents remaining in the table"
}
]
testTask "scalar succeeds" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
let! nbr = conn.customScalar "SELECT 5 AS test_value" [] (fun row -> row.int "test_value")
Expect.equal nbr 5 "The query should have returned the number 5"
}
testTask "ensureTable succeeds" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
let tableExists () =
conn.customScalar "SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'ensured') AS it" [] toExists
let keyExists () =
conn.customScalar
"SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'idx_ensured_key') AS it" [] toExists
let! exists = tableExists ()
let! alsoExists = keyExists ()
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' = tableExists ()
let! alsoExists' = keyExists ()
Expect.isTrue exists' "The table should now exist"
Expect.isTrue alsoExists' "The key index should now exist"
}
testTask "ensureDocumentIndex succeeds" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
let indexExists () =
conn.customScalar
"SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'idx_ensured_document') AS it" [] toExists
let! exists = indexExists ()
Expect.isFalse exists "The index should not exist already"
do! conn.ensureTable "ensured"
do! conn.ensureDocumentIndex "ensured" Optimized
let! exists' = indexExists ()
Expect.isTrue exists' "The index should now exist"
}
testTask "ensureFieldIndex succeeds" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
let indexExists () =
conn.customScalar
"SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'idx_ensured_test') AS it" [] toExists
let! exists = indexExists ()
Expect.isFalse exists "The index should not exist already"
do! conn.ensureTable "ensured"
do! conn.ensureFieldIndex "ensured" "test" [ "Id"; "Category" ]
let! exists' = indexExists ()
Expect.isTrue exists' "The index should now exist"
}
testList "insert" [
testTask "succeeds" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
let! before = conn.countAll PostgresDb.TableName
Expect.equal before 0 "There should be no documents in the table"
let testDoc = { emptyDoc with Id = "turkey"; Sub = Some { Foo = "gobble"; Bar = "gobble" } }
do! conn.insert PostgresDb.TableName testDoc
let! after = conn.findAll<JsonDocument> PostgresDb.TableName
Expect.equal after [ testDoc ] "There should have been one document inserted"
}
testTask "fails for duplicate key" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! conn.insert PostgresDb.TableName { emptyDoc with Id = "test" }
Expect.throws
(fun () ->
conn.insert PostgresDb.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 = PostgresDb.BuildDb()
use conn = mkConn db
let! before = conn.countAll PostgresDb.TableName
Expect.equal before 0 "There should be no documents in the table"
let testDoc = { emptyDoc with Id = "test"; Sub = Some { Foo = "a"; Bar = "b" } }
do! conn.save PostgresDb.TableName testDoc
let! after = conn.findAll<JsonDocument> PostgresDb.TableName
Expect.equal after [ testDoc ] "There should have been one document inserted"
}
testTask "succeeds when a document is updated" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
let testDoc = { emptyDoc with Id = "test"; Sub = Some { Foo = "a"; Bar = "b" } }
do! conn.insert PostgresDb.TableName testDoc
let! before = conn.findById<string, JsonDocument> PostgresDb.TableName "test"
Expect.isSome before "There should have been a document returned"
Expect.equal before.Value testDoc "The document is not correct"
let upd8Doc = { testDoc with Sub = Some { Foo = "c"; Bar = "d" } }
do! conn.save PostgresDb.TableName upd8Doc
let! after = conn.findById<string, JsonDocument> PostgresDb.TableName "test"
Expect.isSome after "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 = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let! theCount = conn.countAll PostgresDb.TableName
Expect.equal theCount 5 "There should have been 5 matching documents"
}
testTask "countByField succeeds" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let! theCount = conn.countByField PostgresDb.TableName "Value" EQ "purple"
Expect.equal theCount 2 "There should have been 2 matching documents"
}
testTask "countByContains succeeds" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let! theCount = conn.countByContains PostgresDb.TableName {| Value = "purple" |}
Expect.equal theCount 2 "There should have been 2 matching documents"
}
testTask "countByJsonPath succeeds" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let! theCount = conn.countByJsonPath PostgresDb.TableName "$.NumValue ? (@ > 5)"
Expect.equal theCount 3 "There should have been 3 matching documents"
}
testList "existsById" [
testTask "succeeds when a document exists" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let! exists = conn.existsById PostgresDb.TableName "three"
Expect.isTrue exists "There should have been an existing document"
}
testTask "succeeds when a document does not exist" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let! exists = conn.existsById PostgresDb.TableName "seven"
Expect.isFalse exists "There should not have been an existing document"
}
]
testList "existsByField" [
testTask "succeeds when documents exist" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let! exists = conn.existsByField PostgresDb.TableName "Sub" EX ""
Expect.isTrue exists "There should have been existing documents"
}
testTask "succeeds when documents do not exist" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let! exists = conn.existsByField PostgresDb.TableName "NumValue" EQ "six"
Expect.isFalse exists "There should not have been existing documents"
}
]
testList "existsByContains" [
testTask "succeeds when documents exist" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let! exists = conn.existsByContains PostgresDb.TableName {| NumValue = 10 |}
Expect.isTrue exists "There should have been existing documents"
}
testTask "succeeds when no matching documents exist" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let! exists = conn.existsByContains PostgresDb.TableName {| Nothing = "none" |}
Expect.isFalse exists "There should not have been any existing documents"
}
]
testList "existsByJsonPath" [
testTask "succeeds when documents exist" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let! exists = conn.existsByJsonPath PostgresDb.TableName """$.Sub.Foo ? (@ == "green")"""
Expect.isTrue exists "There should have been existing documents"
}
testTask "succeeds when no matching documents exist" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let! exists = conn.existsByJsonPath PostgresDb.TableName "$.NumValue ? (@ > 1000)"
Expect.isFalse exists "There should not have been any existing documents"
}
]
testList "findAll" [
testTask "succeeds when there is data" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! conn.insert PostgresDb.TableName { Foo = "one"; Bar = "two" }
do! conn.insert PostgresDb.TableName { Foo = "three"; Bar = "four" }
do! conn.insert PostgresDb.TableName { Foo = "five"; Bar = "six" }
let! results = conn.findAll<SubDocument> PostgresDb.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 = PostgresDb.BuildDb()
use conn = mkConn db
let! results = conn.findAll<SubDocument> PostgresDb.TableName
Expect.equal results [] "There should have been no documents returned"
}
]
testList "findById" [
testTask "succeeds when a document is found" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let! doc = conn.findById<string, JsonDocument> PostgresDb.TableName "two"
Expect.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 = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let! doc = conn.findById<string, JsonDocument> PostgresDb.TableName "three hundred eighty-seven"
Expect.isNone doc "There should not have been a document returned"
}
]
testList "findByField" [
testTask "succeeds when documents are found" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let! docs = conn.findByField<JsonDocument> PostgresDb.TableName "Value" EQ "another"
Expect.equal (List.length docs) 1 "There should have been one document returned"
}
testTask "succeeds when documents are not found" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let! docs = conn.findByField<JsonDocument> PostgresDb.TableName "Value" EQ "mauve"
Expect.isEmpty docs "There should have been no documents returned"
}
]
testList "findByContains" [
testTask "succeeds when documents are found" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let! docs = conn.findByContains<JsonDocument> PostgresDb.TableName {| Sub = {| Foo = "green" |} |}
Expect.equal (List.length docs) 2 "There should have been two documents returned"
}
testTask "succeeds when documents are not found" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let! docs = conn.findByContains<JsonDocument> PostgresDb.TableName {| Value = "mauve" |}
Expect.isEmpty docs "There should have been no documents returned"
}
]
testList "findByJsonPath" [
testTask "succeeds when documents are found" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let! docs = conn.findByJsonPath<JsonDocument> PostgresDb.TableName "$.NumValue ? (@ < 15)"
Expect.equal (List.length docs) 3 "There should have been 3 documents returned"
}
testTask "succeeds when documents are not found" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let! docs = conn.findByJsonPath<JsonDocument> PostgresDb.TableName "$.NumValue ? (@ < 0)"
Expect.isEmpty docs "There should have been no documents returned"
}
]
testList "findFirstByField" [
testTask "succeeds when a document is found" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let! doc = conn.findFirstByField<JsonDocument> PostgresDb.TableName "Value" EQ "another"
Expect.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 = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let! doc = conn.findFirstByField<JsonDocument> PostgresDb.TableName "Value" EQ "purple"
Expect.isSome doc "There should have been a document returned"
Expect.contains [ "five"; "four" ] doc.Value.Id "An incorrect document was returned"
}
testTask "succeeds when a document is not found" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let! doc = conn.findFirstByField<JsonDocument> PostgresDb.TableName "Value" EQ "absent"
Expect.isNone doc "There should not have been a document returned"
}
]
testList "findFirstByContains" [
testTask "succeeds when a document is found" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let! doc = conn.findFirstByContains<JsonDocument> PostgresDb.TableName {| Value = "another" |}
Expect.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 = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let! doc = conn.findFirstByContains<JsonDocument> PostgresDb.TableName {| Sub = {| Foo = "green" |} |}
Expect.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 = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let! doc = conn.findFirstByContains<JsonDocument> PostgresDb.TableName {| Value = "absent" |}
Expect.isNone doc "There should not have been a document returned"
}
]
testList "findFirstByJsonPath" [
testTask "succeeds when a document is found" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let! doc = conn.findFirstByJsonPath<JsonDocument> PostgresDb.TableName """$.Value ? (@ == "FIRST!")"""
Expect.isSome doc "There should have been a document returned"
Expect.equal doc.Value.Id "one" "The incorrect document was returned"
}
testTask "succeeds when multiple documents are found" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let! doc = conn.findFirstByJsonPath<JsonDocument> PostgresDb.TableName """$.Sub.Foo ? (@ == "green")"""
Expect.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 = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let! doc = conn.findFirstByJsonPath<JsonDocument> PostgresDb.TableName """$.Id ? (@ == "nope")"""
Expect.isNone doc "There should not have been a document returned"
}
]
testList "updateById" [
testTask "succeeds when a document is updated" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
let testDoc = { emptyDoc with Id = "one"; Sub = Some { Foo = "blue"; Bar = "red" } }
do! conn.updateById PostgresDb.TableName "one" testDoc
let! after = conn.findById<string, JsonDocument> PostgresDb.TableName "one"
Expect.isSome after "There should have been a document returned post-update"
Expect.equal after.Value testDoc "The updated document is not correct"
}
testTask "succeeds when no document is updated" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
let! before = conn.countAll PostgresDb.TableName
Expect.equal before 0 "There should have been no documents returned"
// This not raising an exception is the test
do! conn.updateById
PostgresDb.TableName "test" { emptyDoc with Id = "x"; Sub = Some { Foo = "blue"; Bar = "red" } }
}
]
testList "updateByFunc" [
testTask "succeeds when a document is updated" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
do! conn.updateByFunc
PostgresDb.TableName (_.Id) { Id = "one"; Value = "le un"; NumValue = 1; Sub = None }
let! after = conn.findById<string, JsonDocument> PostgresDb.TableName "one"
Expect.isSome after "There should have been a document returned post-update"
Expect.equal
after.Value
{ Id = "one"; Value = "le un"; NumValue = 1; Sub = None }
"The updated document is not correct"
}
testTask "succeeds when no document is updated" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
let! before = conn.countAll PostgresDb.TableName
Expect.equal before 0 "There should have been no documents returned"
// This not raising an exception is the test
do! conn.updateByFunc
PostgresDb.TableName (_.Id) { Id = "one"; Value = "le un"; NumValue = 1; Sub = None }
}
]
testList "patchById" [
testTask "succeeds when a document is updated" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
do! conn.patchById PostgresDb.TableName "one" {| NumValue = 44 |}
let! after = conn.findById<string, JsonDocument> PostgresDb.TableName "one"
Expect.isSome after "There should have been a document returned post-update"
Expect.equal after.Value.NumValue 44 "The updated document is not correct"
}
testTask "succeeds when no document is updated" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
let! before = conn.countAll PostgresDb.TableName
Expect.equal before 0 "There should have been no documents returned"
// This not raising an exception is the test
do! conn.patchById PostgresDb.TableName "test" {| Foo = "green" |}
}
]
testList "patchByField" [
testTask "succeeds when a document is updated" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
do! conn.patchByField PostgresDb.TableName "Value" EQ "purple" {| NumValue = 77 |}
let! after = conn.countByField PostgresDb.TableName "NumValue" EQ "77"
Expect.equal after 2 "There should have been 2 documents returned"
}
testTask "succeeds when no document is updated" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
let! before = conn.countAll PostgresDb.TableName
Expect.equal before 0 "There should have been no documents returned"
// This not raising an exception is the test
do! conn.patchByField PostgresDb.TableName "Value" EQ "burgundy" {| Foo = "green" |}
}
]
testList "patchByContains" [
testTask "succeeds when a document is updated" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
do! conn.patchByContains PostgresDb.TableName {| Value = "purple" |} {| NumValue = 77 |}
let! after = conn.countByContains PostgresDb.TableName {| NumValue = 77 |}
Expect.equal after 2 "There should have been 2 documents returned"
}
testTask "succeeds when no document is updated" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
let! before = conn.countAll PostgresDb.TableName
Expect.equal before 0 "There should have been no documents returned"
// This not raising an exception is the test
do! conn.patchByContains PostgresDb.TableName {| Value = "burgundy" |} {| Foo = "green" |}
}
]
testList "patchByJsonPath" [
testTask "succeeds when a document is updated" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
do! conn.patchByJsonPath PostgresDb.TableName "$.NumValue ? (@ > 10)" {| NumValue = 1000 |}
let! after = conn.countByJsonPath PostgresDb.TableName "$.NumValue ? (@ > 999)"
Expect.equal after 2 "There should have been 2 documents returned"
}
testTask "succeeds when no document is updated" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
let! before = conn.countAll PostgresDb.TableName
Expect.equal before 0 "There should have been no documents returned"
// This not raising an exception is the test
do! conn.patchByJsonPath PostgresDb.TableName "$.NumValue ? (@ < 0)" {| Foo = "green" |}
}
]
testList "deleteById" [
testTask "succeeds when a document is deleted" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
do! conn.deleteById PostgresDb.TableName "four"
let! remaining = conn.countAll PostgresDb.TableName
Expect.equal remaining 4 "There should have been 4 documents remaining"
}
testTask "succeeds when a document is not deleted" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
do! conn.deleteById PostgresDb.TableName "thirty"
let! remaining = conn.countAll PostgresDb.TableName
Expect.equal remaining 5 "There should have been 5 documents remaining"
}
]
testList "deleteByField" [
testTask "succeeds when documents are deleted" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
do! conn.deleteByField PostgresDb.TableName "Value" EQ "purple"
let! remaining = conn.countAll PostgresDb.TableName
Expect.equal remaining 3 "There should have been 3 documents remaining"
}
testTask "succeeds when documents are not deleted" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
do! conn.deleteByField PostgresDb.TableName "Value" EQ "crimson"
let! remaining = conn.countAll PostgresDb.TableName
Expect.equal remaining 5 "There should have been 5 documents remaining"
}
]
testList "deleteByContains" [
testTask "succeeds when documents are deleted" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
do! conn.deleteByContains PostgresDb.TableName {| Value = "purple" |}
let! remaining = conn.countAll PostgresDb.TableName
Expect.equal remaining 3 "There should have been 3 documents remaining"
}
testTask "succeeds when documents are not deleted" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
do! conn.deleteByContains PostgresDb.TableName {| Value = "crimson" |}
let! remaining = conn.countAll PostgresDb.TableName
Expect.equal remaining 5 "There should have been 5 documents remaining"
}
]
testList "deleteByJsonPath" [
testTask "succeeds when documents are deleted" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
do! conn.deleteByJsonPath PostgresDb.TableName """$.Sub.Foo ? (@ == "green")"""
let! remaining = conn.countAll PostgresDb.TableName
Expect.equal remaining 3 "There should have been 3 documents remaining"
}
testTask "succeeds when documents are not deleted" {
use db = PostgresDb.BuildDb()
use conn = mkConn db
do! loadDocs conn
do! conn.deleteByJsonPath PostgresDb.TableName "$.NumValue ? (@ > 100)"
let! remaining = conn.countAll PostgresDb.TableName
Expect.equal remaining 5 "There should have been 5 documents remaining"
}
]
]
|> testSequenced

816
src/Tests/PostgresTests.fs Normal file
View File

@@ -0,0 +1,816 @@
module PostgresTests
open Expecto
open BitBadger.Documents
open BitBadger.Documents.Postgres
open BitBadger.Documents.Tests
/// Tests which do not hit the database
let unitTests =
testList "Unit" [
testList "Parameters" [
test "idParam succeeds" {
Expect.equal (idParam 88) ("@id", Sql.string "88") "ID parameter not constructed correctly"
}
test "jsonParam succeeds" {
Expect.equal
(jsonParam "@test" {| Something = "good" |})
("@test", Sql.jsonb """{"Something":"good"}""")
"JSON parameter not constructed correctly"
}
test "fieldParam succeeds" {
let it = fieldParam 242
Expect.equal (fst it) "@field" "Field parameter name not correct"
match snd it with
| SqlValue.Parameter value ->
Expect.equal value.ParameterName "@field" "Parameter name not correct"
Expect.equal value.Value 242 "Parameter value not correct"
| _ -> Expect.isTrue false "The parameter was not a Parameter type"
}
test "noParams succeeds" {
Expect.isEmpty noParams "The no-params sequence should be empty"
}
]
testList "Query" [
testList "Definition" [
test "ensureTable succeeds" {
Expect.equal
(Query.Definition.ensureTable PostgresDb.TableName)
$"CREATE TABLE IF NOT EXISTS {PostgresDb.TableName} (data JSONB NOT NULL)"
"CREATE TABLE statement not constructed correctly"
}
test "ensureDocumentIndex succeeds for full index" {
Expect.equal
(Query.Definition.ensureDocumentIndex "schema.tbl" Full)
"CREATE INDEX IF NOT EXISTS idx_tbl_document ON schema.tbl USING GIN (data)"
"CREATE INDEX statement not constructed correctly"
}
test "ensureDocumentIndex succeeds for JSONB Path Ops index" {
Expect.equal
(Query.Definition.ensureDocumentIndex PostgresDb.TableName Optimized)
(sprintf "CREATE INDEX IF NOT EXISTS idx_%s_document ON %s USING GIN (data jsonb_path_ops)"
PostgresDb.TableName PostgresDb.TableName)
"CREATE INDEX statement not constructed correctly"
}
]
test "whereDataContains succeeds" {
Expect.equal (Query.whereDataContains "@test") "data @> @test" "WHERE clause not correct"
}
test "whereJsonPathMatches succeeds" {
Expect.equal (Query.whereJsonPathMatches "@path") "data @? @path::jsonpath" "WHERE clause not correct"
}
testList "Count" [
test "byContains succeeds" {
Expect.equal
(Query.Count.byContains PostgresDb.TableName)
$"SELECT COUNT(*) AS it FROM {PostgresDb.TableName} WHERE data @> @criteria"
"JSON containment count query not correct"
}
test "byJsonPath succeeds" {
Expect.equal
(Query.Count.byJsonPath PostgresDb.TableName)
$"SELECT COUNT(*) AS it FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath"
"JSON Path match count query not correct"
}
]
testList "Exists" [
test "byContains succeeds" {
Expect.equal
(Query.Exists.byContains PostgresDb.TableName)
$"SELECT EXISTS (SELECT 1 FROM {PostgresDb.TableName} WHERE data @> @criteria) AS it"
"JSON containment exists query not correct"
}
test "byJsonPath succeeds" {
Expect.equal
(Query.Exists.byJsonPath PostgresDb.TableName)
$"SELECT EXISTS (SELECT 1 FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath) AS it"
"JSON Path match existence query not correct"
}
]
testList "Find" [
test "byContains succeeds" {
Expect.equal
(Query.Find.byContains PostgresDb.TableName)
$"SELECT data FROM {PostgresDb.TableName} WHERE data @> @criteria"
"SELECT by JSON containment query not correct"
}
test "byJsonPath succeeds" {
Expect.equal
(Query.Find.byJsonPath PostgresDb.TableName)
$"SELECT data FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath"
"SELECT by JSON Path match query not correct"
}
]
testList "Patch" [
test "byId succeeds" {
Expect.equal
(Query.Patch.byId PostgresDb.TableName)
$"UPDATE {PostgresDb.TableName} SET data = data || @data WHERE data ->> 'Id' = @id"
"UPDATE partial by ID statement not correct"
}
test "byField succeeds" {
Expect.equal
(Query.Patch.byField PostgresDb.TableName "Snail" LT)
$"UPDATE {PostgresDb.TableName} SET data = data || @data WHERE data ->> 'Snail' < @field"
"UPDATE partial by ID statement not correct"
}
test "byContains succeeds" {
Expect.equal
(Query.Patch.byContains PostgresDb.TableName)
$"UPDATE {PostgresDb.TableName} SET data = data || @data WHERE data @> @criteria"
"UPDATE partial by JSON containment statement not correct"
}
test "byJsonPath succeeds" {
Expect.equal
(Query.Patch.byJsonPath PostgresDb.TableName)
$"UPDATE {PostgresDb.TableName} SET data = data || @data WHERE data @? @path::jsonpath"
"UPDATE partial by JSON Path statement not correct"
}
]
testList "Delete" [
test "byContains succeeds" {
Expect.equal (Query.Delete.byContains PostgresDb.TableName)
$"DELETE FROM {PostgresDb.TableName} WHERE data @> @criteria"
"DELETE by JSON containment query not correct"
}
test "byJsonPath succeeds" {
Expect.equal (Query.Delete.byJsonPath PostgresDb.TableName)
$"DELETE FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath"
"DELETE by JSON Path match query not correct"
}
]
]
]
open ThrowawayDb.Postgres
open Types
let isTrue<'T> (_ : 'T) = true
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 PostgresDb.TableName doc
}
testList "Integration" [
testList "Configuration" [
test "useDataSource disposes existing source" {
use db1 = ThrowawayDatabase.Create PostgresDb.ConnStr.Value
let source = PostgresDb.MkDataSource db1.ConnectionString
Configuration.useDataSource source
use db2 = ThrowawayDatabase.Create PostgresDb.ConnStr.Value
Configuration.useDataSource (PostgresDb.MkDataSource db2.ConnectionString)
Expect.throws (fun () -> source.OpenConnection() |> ignore) "Data source should have been disposed"
}
test "dataSource returns configured data source" {
use db = ThrowawayDatabase.Create PostgresDb.ConnStr.Value
let source = PostgresDb.MkDataSource db.ConnectionString
Configuration.useDataSource source
Expect.isTrue (obj.ReferenceEquals(source, Configuration.dataSource ()))
"Data source should have been the same"
}
]
testList "Custom" [
testList "list" [
testTask "succeeds when data is found" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
let! docs = Custom.list (Query.selectFromTable PostgresDb.TableName) [] fromData<JsonDocument>
Expect.hasCountOf docs 5u isTrue "There should have been 5 documents returned"
}
testTask "succeeds when data is not found" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
let! docs =
Custom.list $"SELECT data FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath"
[ "@path", Sql.string "$.NumValue ? (@ > 100)" ] fromData<JsonDocument>
Expect.isEmpty docs "There should have been no documents returned"
}
]
testList "single" [
testTask "succeeds when a row is found" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
let! doc =
Custom.single $"SELECT data FROM {PostgresDb.TableName} WHERE data ->> 'Id' = @id"
[ "@id", Sql.string "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 = PostgresDb.BuildDb()
do! loadDocs ()
let! doc =
Custom.single $"SELECT data FROM {PostgresDb.TableName} WHERE data ->> 'Id' = @id"
[ "@id", Sql.string "eighty" ] fromData<JsonDocument>
Expect.isNone doc "There should not have been a document returned"
}
]
testList "nonQuery" [
testTask "succeeds when operating on data" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
do! Custom.nonQuery $"DELETE FROM {PostgresDb.TableName}" []
let! remaining = Count.all PostgresDb.TableName
Expect.equal remaining 0 "There should be no documents remaining in the table"
}
testTask "succeeds when no data matches where clause" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
do! Custom.nonQuery $"DELETE FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath"
[ "@path", Sql.string "$.NumValue ? (@ > 100)" ]
let! remaining = Count.all PostgresDb.TableName
Expect.equal remaining 5 "There should be 5 documents remaining in the table"
}
]
testTask "scalar succeeds" {
use db = PostgresDb.BuildDb()
let! nbr = Custom.scalar "SELECT 5 AS test_value" [] (fun row -> row.int "test_value")
Expect.equal nbr 5 "The query should have returned the number 5"
}
]
testList "Definition" [
testTask "ensureTable succeeds" {
use db = PostgresDb.BuildDb()
let tableExists () =
Custom.scalar "SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'ensured') AS it" [] toExists
let keyExists () =
Custom.scalar
"SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'idx_ensured_key') AS it" [] toExists
let! exists = tableExists ()
let! alsoExists = keyExists ()
Expect.isFalse exists "The table should not exist already"
Expect.isFalse alsoExists "The key index should not exist already"
do! Definition.ensureTable "ensured"
let! exists' = tableExists ()
let! alsoExists' = keyExists ()
Expect.isTrue exists' "The table should now exist"
Expect.isTrue alsoExists' "The key index should now exist"
}
testTask "ensureDocumentIndex succeeds" {
use db = PostgresDb.BuildDb()
let indexExists () =
Custom.scalar
"SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'idx_ensured_document') AS it"
[]
toExists
let! exists = indexExists ()
Expect.isFalse exists "The index should not exist already"
do! Definition.ensureTable "ensured"
do! Definition.ensureDocumentIndex "ensured" Optimized
let! exists' = indexExists ()
Expect.isTrue exists' "The index should now exist"
}
testTask "ensureFieldIndex succeeds" {
use db = PostgresDb.BuildDb()
let indexExists () =
Custom.scalar
"SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'idx_ensured_test') AS it" [] toExists
let! exists = indexExists ()
Expect.isFalse exists "The index should not exist already"
do! Definition.ensureTable "ensured"
do! Definition.ensureFieldIndex "ensured" "test" [ "Id"; "Category" ]
let! exists' = indexExists ()
Expect.isTrue exists' "The index should now exist"
}
]
testList "insert" [
testTask "succeeds" {
use db = PostgresDb.BuildDb()
let! before = Find.all<SubDocument> PostgresDb.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! insert PostgresDb.TableName testDoc
let! after = Find.all<JsonDocument> PostgresDb.TableName
Expect.equal after [ testDoc ] "There should have been one document inserted"
}
testTask "fails for duplicate key" {
use db = PostgresDb.BuildDb()
do! insert PostgresDb.TableName { emptyDoc with Id = "test" }
Expect.throws
(fun () ->
insert PostgresDb.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 = PostgresDb.BuildDb()
let! before = Find.all<JsonDocument> PostgresDb.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! save PostgresDb.TableName testDoc
let! after = Find.all<JsonDocument> PostgresDb.TableName
Expect.equal after [ testDoc ] "There should have been one document inserted"
}
testTask "succeeds when a document is updated" {
use db = PostgresDb.BuildDb()
let testDoc = { emptyDoc with Id = "test"; Sub = Some { Foo = "a"; Bar = "b" } }
do! insert PostgresDb.TableName testDoc
let! before = Find.byId<string, JsonDocument> PostgresDb.TableName "test"
Expect.isSome before "There should have been a document returned"
Expect.equal before.Value testDoc "The document is not correct"
let upd8Doc = { testDoc with Sub = Some { Foo = "c"; Bar = "d" } }
do! save PostgresDb.TableName upd8Doc
let! after = Find.byId<string, JsonDocument> PostgresDb.TableName "test"
Expect.isSome after "There should have been a document returned post-update"
Expect.equal after.Value upd8Doc "The updated document is not correct"
}
]
testList "Count" [
testTask "all succeeds" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
let! theCount = Count.all PostgresDb.TableName
Expect.equal theCount 5 "There should have been 5 matching documents"
}
testTask "byField succeeds" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
let! theCount = Count.byField PostgresDb.TableName "Value" EQ "purple"
Expect.equal theCount 2 "There should have been 2 matching documents"
}
testTask "byContains succeeds" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
let! theCount = Count.byContains PostgresDb.TableName {| Value = "purple" |}
Expect.equal theCount 2 "There should have been 2 matching documents"
}
testTask "byJsonPath succeeds" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
let! theCount = Count.byJsonPath PostgresDb.TableName "$.NumValue ? (@ > 5)"
Expect.equal theCount 3 "There should have been 3 matching documents"
}
]
testList "Exists" [
testList "byId" [
testTask "succeeds when a document exists" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
let! exists = Exists.byId PostgresDb.TableName "three"
Expect.isTrue exists "There should have been an existing document"
}
testTask "succeeds when a document does not exist" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
let! exists = Exists.byId PostgresDb.TableName "seven"
Expect.isFalse exists "There should not have been an existing document"
}
]
testList "byField" [
testTask "succeeds when documents exist" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
let! exists = Exists.byField PostgresDb.TableName "Sub" EX ""
Expect.isTrue exists "There should have been existing documents"
}
testTask "succeeds when documents do not exist" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
let! exists = Exists.byField PostgresDb.TableName "NumValue" EQ "six"
Expect.isFalse exists "There should not have been existing documents"
}
]
testList "byContains" [
testTask "succeeds when documents exist" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
let! exists = Exists.byContains PostgresDb.TableName {| NumValue = 10 |}
Expect.isTrue exists "There should have been existing documents"
}
testTask "succeeds when no matching documents exist" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
let! exists = Exists.byContains PostgresDb.TableName {| Nothing = "none" |}
Expect.isFalse exists "There should not have been any existing documents"
}
]
testList "byJsonPath" [
testTask "succeeds when documents exist" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
let! exists = Exists.byJsonPath PostgresDb.TableName """$.Sub.Foo ? (@ == "green")"""
Expect.isTrue exists "There should have been existing documents"
}
testTask "succeeds when no matching documents exist" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
let! exists = Exists.byJsonPath PostgresDb.TableName "$.NumValue ? (@ > 1000)"
Expect.isFalse exists "There should not have been any existing documents"
}
]
]
testList "Find" [
testList "all" [
testTask "succeeds when there is data" {
use db = PostgresDb.BuildDb()
do! insert PostgresDb.TableName { Foo = "one"; Bar = "two" }
do! insert PostgresDb.TableName { Foo = "three"; Bar = "four" }
do! insert PostgresDb.TableName { Foo = "five"; Bar = "six" }
let! results = Find.all<SubDocument> PostgresDb.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 = PostgresDb.BuildDb()
let! results = Find.all<SubDocument> PostgresDb.TableName
Expect.equal results [] "There should have been no documents returned"
}
]
testList "byId" [
testTask "succeeds when a document is found" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
let! doc = Find.byId<string, JsonDocument> PostgresDb.TableName "two"
Expect.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 = PostgresDb.BuildDb()
do! loadDocs ()
let! doc = Find.byId<string, JsonDocument> PostgresDb.TableName "three hundred eighty-seven"
Expect.isNone doc "There should not have been a document returned"
}
]
testList "byField" [
testTask "succeeds when documents are found" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
let! docs = Find.byField<JsonDocument> PostgresDb.TableName "Value" EQ "another"
Expect.equal (List.length docs) 1 "There should have been one document returned"
}
testTask "succeeds when documents are not found" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
let! docs = Find.byField<JsonDocument> PostgresDb.TableName "Value" EQ "mauve"
Expect.isEmpty docs "There should have been no documents returned"
}
]
testList "byContains" [
testTask "succeeds when documents are found" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
let! docs = Find.byContains<JsonDocument> PostgresDb.TableName {| Sub = {| Foo = "green" |} |}
Expect.equal (List.length docs) 2 "There should have been two documents returned"
}
testTask "succeeds when documents are not found" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
let! docs = Find.byContains<JsonDocument> PostgresDb.TableName {| Value = "mauve" |}
Expect.isEmpty docs "There should have been no documents returned"
}
]
testList "byJsonPath" [
testTask "succeeds when documents are found" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
let! docs = Find.byJsonPath<JsonDocument> PostgresDb.TableName "$.NumValue ? (@ < 15)"
Expect.equal (List.length docs) 3 "There should have been 3 documents returned"
}
testTask "succeeds when documents are not found" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
let! docs = Find.byJsonPath<JsonDocument> PostgresDb.TableName "$.NumValue ? (@ < 0)"
Expect.isEmpty docs "There should have been no documents returned"
}
]
testList "firstByField" [
testTask "succeeds when a document is found" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
let! doc = Find.firstByField<JsonDocument> PostgresDb.TableName "Value" EQ "another"
Expect.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 = PostgresDb.BuildDb()
do! loadDocs ()
let! doc = Find.firstByField<JsonDocument> PostgresDb.TableName "Value" EQ "purple"
Expect.isSome doc "There should have been a document returned"
Expect.contains [ "five"; "four" ] doc.Value.Id "An incorrect document was returned"
}
testTask "succeeds when a document is not found" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
let! doc = Find.firstByField<JsonDocument> PostgresDb.TableName "Value" EQ "absent"
Expect.isNone doc "There should not have been a document returned"
}
]
testList "firstByContains" [
testTask "succeeds when a document is found" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
let! doc = Find.firstByContains<JsonDocument> PostgresDb.TableName {| Value = "another" |}
Expect.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 = PostgresDb.BuildDb()
do! loadDocs ()
let! doc = Find.firstByContains<JsonDocument> PostgresDb.TableName {| Sub = {| Foo = "green" |} |}
Expect.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 = PostgresDb.BuildDb()
do! loadDocs ()
let! doc = Find.firstByContains<JsonDocument> PostgresDb.TableName {| Value = "absent" |}
Expect.isNone doc "There should not have been a document returned"
}
]
testList "firstByJsonPath" [
testTask "succeeds when a document is found" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
let! doc = Find.firstByJsonPath<JsonDocument> PostgresDb.TableName """$.Value ? (@ == "FIRST!")"""
Expect.isSome doc "There should have been a document returned"
Expect.equal doc.Value.Id "one" "The incorrect document was returned"
}
testTask "succeeds when multiple documents are found" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
let! doc = Find.firstByJsonPath<JsonDocument> PostgresDb.TableName """$.Sub.Foo ? (@ == "green")"""
Expect.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 = PostgresDb.BuildDb()
do! loadDocs ()
let! doc = Find.firstByJsonPath<JsonDocument> PostgresDb.TableName """$.Id ? (@ == "nope")"""
Expect.isNone doc "There should not have been a document returned"
}
]
]
testList "Update" [
testList "byId" [
testTask "succeeds when a document is updated" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
let testDoc = { emptyDoc with Id = "one"; Sub = Some { Foo = "blue"; Bar = "red" } }
do! Update.byId PostgresDb.TableName "one" testDoc
let! after = Find.byId<string, JsonDocument> PostgresDb.TableName "one"
Expect.isSome after "There should have been a document returned post-update"
Expect.equal after.Value testDoc "The updated document is not correct"
}
testTask "succeeds when no document is updated" {
use db = PostgresDb.BuildDb()
let! before = Count.all PostgresDb.TableName
Expect.equal before 0 "There should have been no documents returned"
// This not raising an exception is the test
do! Update.byId
PostgresDb.TableName
"test"
{ emptyDoc with Id = "x"; Sub = Some { Foo = "blue"; Bar = "red" } }
}
]
testList "byFunc" [
testTask "succeeds when a document is updated" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
do! Update.byFunc PostgresDb.TableName (_.Id)
{ Id = "one"; Value = "le un"; NumValue = 1; Sub = None }
let! after = Find.byId<string, JsonDocument> PostgresDb.TableName "one"
Expect.isSome after "There should have been a document returned post-update"
Expect.equal
after.Value
{ Id = "one"; Value = "le un"; NumValue = 1; Sub = None }
"The updated document is not correct"
}
testTask "succeeds when no document is updated" {
use db = PostgresDb.BuildDb()
let! before = Count.all PostgresDb.TableName
Expect.equal before 0 "There should have been no documents returned"
// This not raising an exception is the test
do! Update.byFunc
PostgresDb.TableName (_.Id) { Id = "one"; Value = "le un"; NumValue = 1; Sub = None }
}
]
]
testList "Patch" [
testList "byId" [
testTask "succeeds when a document is updated" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
do! Patch.byId PostgresDb.TableName "one" {| NumValue = 44 |}
let! after = Find.byId<string, JsonDocument> PostgresDb.TableName "one"
Expect.isSome after "There should have been a document returned post-update"
Expect.equal after.Value.NumValue 44 "The updated document is not correct"
}
testTask "succeeds when no document is updated" {
use db = PostgresDb.BuildDb()
let! before = Count.all PostgresDb.TableName
Expect.equal before 0 "There should have been no documents returned"
// This not raising an exception is the test
do! Patch.byId PostgresDb.TableName "test" {| Foo = "green" |}
}
]
testList "byField" [
testTask "succeeds when a document is updated" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
do! Patch.byField PostgresDb.TableName "Value" EQ "purple" {| NumValue = 77 |}
let! after = Count.byField PostgresDb.TableName "NumValue" EQ "77"
Expect.equal after 2 "There should have been 2 documents returned"
}
testTask "succeeds when no document is updated" {
use db = PostgresDb.BuildDb()
let! before = Count.all PostgresDb.TableName
Expect.equal before 0 "There should have been no documents returned"
// This not raising an exception is the test
do! Patch.byField PostgresDb.TableName "Value" EQ "burgundy" {| Foo = "green" |}
}
]
testList "byContains" [
testTask "succeeds when a document is updated" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
do! Patch.byContains PostgresDb.TableName {| Value = "purple" |} {| NumValue = 77 |}
let! after = Count.byContains PostgresDb.TableName {| NumValue = 77 |}
Expect.equal after 2 "There should have been 2 documents returned"
}
testTask "succeeds when no document is updated" {
use db = PostgresDb.BuildDb()
let! before = Count.all PostgresDb.TableName
Expect.equal before 0 "There should have been no documents returned"
// This not raising an exception is the test
do! Patch.byContains PostgresDb.TableName {| Value = "burgundy" |} {| Foo = "green" |}
}
]
testList "byJsonPath" [
testTask "succeeds when a document is updated" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
do! Patch.byJsonPath PostgresDb.TableName "$.NumValue ? (@ > 10)" {| NumValue = 1000 |}
let! after = Count.byJsonPath PostgresDb.TableName "$.NumValue ? (@ > 999)"
Expect.equal after 2 "There should have been 2 documents returned"
}
testTask "succeeds when no document is updated" {
use db = PostgresDb.BuildDb()
let! before = Count.all PostgresDb.TableName
Expect.equal before 0 "There should have been no documents returned"
// This not raising an exception is the test
do! Patch.byJsonPath PostgresDb.TableName "$.NumValue ? (@ < 0)" {| Foo = "green" |}
}
]
]
testList "Delete" [
testList "byId" [
testTask "succeeds when a document is deleted" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
do! Delete.byId PostgresDb.TableName "four"
let! remaining = Count.all PostgresDb.TableName
Expect.equal remaining 4 "There should have been 4 documents remaining"
}
testTask "succeeds when a document is not deleted" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
do! Delete.byId PostgresDb.TableName "thirty"
let! remaining = Count.all PostgresDb.TableName
Expect.equal remaining 5 "There should have been 5 documents remaining"
}
]
testList "byField" [
testTask "succeeds when documents are deleted" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
do! Delete.byField PostgresDb.TableName "Value" EQ "purple"
let! remaining = Count.all PostgresDb.TableName
Expect.equal remaining 3 "There should have been 3 documents remaining"
}
testTask "succeeds when documents are not deleted" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
do! Delete.byField PostgresDb.TableName "Value" EQ "crimson"
let! remaining = Count.all PostgresDb.TableName
Expect.equal remaining 5 "There should have been 5 documents remaining"
}
]
testList "byContains" [
testTask "succeeds when documents are deleted" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
do! Delete.byContains PostgresDb.TableName {| Value = "purple" |}
let! remaining = Count.all PostgresDb.TableName
Expect.equal remaining 3 "There should have been 3 documents remaining"
}
testTask "succeeds when documents are not deleted" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
do! Delete.byContains PostgresDb.TableName {| Value = "crimson" |}
let! remaining = Count.all PostgresDb.TableName
Expect.equal remaining 5 "There should have been 5 documents remaining"
}
]
testList "byJsonPath" [
testTask "succeeds when documents are deleted" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
do! Delete.byJsonPath PostgresDb.TableName """$.Sub.Foo ? (@ == "green")"""
let! remaining = Count.all PostgresDb.TableName
Expect.equal remaining 3 "There should have been 3 documents remaining"
}
testTask "succeeds when documents are not deleted" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
do! Delete.byJsonPath PostgresDb.TableName "$.NumValue ? (@ > 100)"
let! remaining = Count.all PostgresDb.TableName
Expect.equal remaining 5 "There should have been 5 documents remaining"
}
]
]
]
|> testSequenced
let all = testList "Postgres" [ unitTests; integrationTests ]

19
src/Tests/Program.fs Normal file
View File

@@ -0,0 +1,19 @@
open Expecto
open BitBadger.Documents.Tests.CSharp
let allTests =
testList
"BitBadger.Documents"
[ CommonTests.all
CommonCSharpTests.Unit
PostgresTests.all
PostgresCSharpTests.All
PostgresExtensionTests.integrationTests
testSequenced PostgresCSharpExtensionTests.Integration
SqliteTests.all
SqliteCSharpTests.All
SqliteExtensionTests.integrationTests
testSequenced SqliteCSharpExtensionTests.Integration ]
[<EntryPoint>]
let main args = runTestsWithCLIArgs [] args allTests

View File

@@ -0,0 +1,471 @@
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 loadDocs () = backgroundTask {
for doc in testDocuments do do! insert SqliteDb.TableName doc
}
testList "Sqlite.Extensions" [
testTask "ensureTable succeeds" {
use! db = SqliteDb.BuildDb()
use conn = Configuration.dbConn ()
let itExists (name: string) =
conn.customScalar
$"SELECT EXISTS (SELECT 1 FROM {SqliteDb.Catalog} WHERE name = @name) AS it"
[ SqliteParameter("@name", name) ]
toExists
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"
}
testTask "ensureFieldIndex succeeds" {
use! db = SqliteDb.BuildDb()
use conn = Configuration.dbConn ()
let indexExists () =
conn.customScalar
$"SELECT EXISTS (SELECT 1 FROM {SqliteDb.Catalog} WHERE name = 'idx_ensured_test') AS it"
[]
toExists
let! exists = indexExists ()
Expect.isFalse exists "The index should not exist already"
do! conn.ensureTable "ensured"
do! conn.ensureFieldIndex "ensured" "test" [ "Name"; "Age" ]
let! exists' = indexExists ()
Expect.isTrue exists' "The 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 "updateById" [
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.updateById 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.updateById
SqliteDb.TableName
"test"
{ emptyDoc with Id = "x"; Sub = Some { Foo = "blue"; Bar = "red" } }
}
]
testList "updateByFunc" [
testTask "succeeds when a document is updated" {
use! db = SqliteDb.BuildDb()
use conn = Configuration.dbConn ()
do! loadDocs ()
do! conn.updateByFunc
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.updateByFunc
SqliteDb.TableName (_.Id) { Id = "one"; Value = "le un"; NumValue = 1; Sub = None }
}
]
testList "patchById" [
testTask "succeeds when a document is updated" {
use! db = SqliteDb.BuildDb()
use conn = Configuration.dbConn ()
do! loadDocs ()
do! conn.patchById 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.patchById SqliteDb.TableName "test" {| Foo = "green" |}
}
]
testList "patchByField" [
testTask "succeeds when a document is updated" {
use! db = SqliteDb.BuildDb()
use conn = Configuration.dbConn ()
do! loadDocs ()
do! conn.patchByField 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.patchByField 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:"
}
]
|> testSequenced

536
src/Tests/SqliteTests.fs Normal file
View File

@@ -0,0 +1,536 @@
module SqliteTests
open BitBadger.Documents
open BitBadger.Documents.Sqlite
open BitBadger.Documents.Tests
open Expecto
open Microsoft.Data.Sqlite
open Types
/// Unit tests for the SQLite library
let unitTests =
testList "Unit" [
testList "Query" [
test "Definition.ensureTable succeeds" {
Expect.equal
(Query.Definition.ensureTable "tbl")
"CREATE TABLE IF NOT EXISTS tbl (data TEXT NOT NULL)"
"CREATE TABLE statement not correct"
}
testList "Patch" [
test "byId succeeds" {
Expect.equal
(Query.Patch.byId "tbl")
"UPDATE tbl SET data = json_patch(data, json(@data)) WHERE data ->> 'Id' = @id"
"UPDATE partial by ID statement not correct"
}
test "byField succeeds" {
Expect.equal
(Query.Patch.byField "tbl" "Part" NE)
"UPDATE tbl SET data = json_patch(data, json(@data)) WHERE data ->> 'Part' <> @field"
"UPDATE partial by JSON comparison query not correct"
}
]
]
testList "Parameters" [
test "idParam succeeds" {
let theParam = idParam 7
Expect.equal theParam.ParameterName "@id" "The parameter name is incorrect"
Expect.equal theParam.Value "7" "The parameter value is incorrect"
}
test "jsonParam succeeds" {
let theParam = jsonParam "@test" {| Nice = "job" |}
Expect.equal theParam.ParameterName "@test" "The parameter name is incorrect"
Expect.equal theParam.Value """{"Nice":"job"}""" "The parameter value is incorrect"
}
test "fieldParam succeeds" {
let theParam = fieldParam 99
Expect.equal theParam.ParameterName "@field" "The parameter name is incorrect"
Expect.equal theParam.Value 99 "The parameter value is incorrect"
}
test "noParams succeeds" {
Expect.isEmpty noParams "The parameter list should have been empty"
}
]
// Results are exhaustively executed in the context of other tests
]
/// These tests each use a fresh copy of a SQLite database
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 "Integration" [
testList "Configuration" [
test "useConnectionString / connectionString succeed" {
try
Configuration.useConnectionString "Data Source=test.db"
Expect.equal
Configuration.connectionString
(Some "Data Source=test.db;Foreign Keys=True")
"Connection string incorrect"
finally
Configuration.useConnectionString "Data Source=:memory:"
}
test "useSerializer succeeds" {
try
Configuration.useSerializer
{ new IDocumentSerializer with
member _.Serialize<'T>(it: 'T) : string = """{"Overridden":true}"""
member _.Deserialize<'T>(it: string) : 'T = Unchecked.defaultof<'T>
}
let serialized = Configuration.serializer().Serialize { Foo = "howdy"; Bar = "bye"}
Expect.equal serialized """{"Overridden":true}""" "Specified serializer was not used"
let deserialized = Configuration.serializer().Deserialize<obj> """{"Something":"here"}"""
Expect.isNull deserialized "Specified serializer should have returned null"
finally
Configuration.useSerializer DocumentSerializer.``default``
}
test "serializer returns configured serializer" {
Expect.isTrue (obj.ReferenceEquals(DocumentSerializer.``default``, Configuration.serializer ()))
"Serializer should have been the same"
}
test "useIdField / idField succeeds" {
Expect.equal (Configuration.idField ()) "Id" "The default configured ID field was incorrect"
Configuration.useIdField "id"
Expect.equal (Configuration.idField ()) "id" "useIdField did not set the ID field"
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" [
testTask "ensureTable succeeds" {
use! db = SqliteDb.BuildDb()
let itExists (name: string) =
Custom.scalar
$"SELECT EXISTS (SELECT 1 FROM {SqliteDb.Catalog} WHERE name = @name) AS it"
[ SqliteParameter("@name", name) ]
toExists
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! Definition.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"
}
testTask "ensureFieldIndex succeeds" {
use! db = SqliteDb.BuildDb()
let indexExists () =
Custom.scalar
$"SELECT EXISTS (SELECT 1 FROM {SqliteDb.Catalog} WHERE name = 'idx_ensured_test') AS it"
[]
toExists
let! exists = indexExists ()
Expect.isFalse exists "The index should not exist already"
do! Definition.ensureTable "ensured"
do! Definition.ensureFieldIndex "ensured" "test" [ "Name"; "Age" ]
let! exists' = indexExists ()
Expect.isTrue exists' "The index should now exist"
}
]
testList "insert" [
testTask "succeeds" {
use! db = SqliteDb.BuildDb()
let! before = Find.all<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! insert SqliteDb.TableName testDoc
let! after = Find.all<JsonDocument> SqliteDb.TableName
Expect.equal after [ testDoc ] "There should have been one document inserted"
}
testTask "fails for duplicate key" {
use! db = SqliteDb.BuildDb()
do! insert SqliteDb.TableName { emptyDoc with Id = "test" }
Expect.throws
(fun () ->
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()
let! before = Find.all<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! save SqliteDb.TableName testDoc
let! after = Find.all<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()
let testDoc = { emptyDoc with Id = "test"; Sub = Some { Foo = "a"; Bar = "b" } }
do! insert SqliteDb.TableName testDoc
let! before = Find.byId<string, JsonDocument> SqliteDb.TableName "test"
Expect.isSome before "There should have been a document returned"
Expect.equal before.Value testDoc "The document is not correct"
let upd8Doc = { testDoc with Sub = Some { Foo = "c"; Bar = "d" } }
do! save SqliteDb.TableName upd8Doc
let! after = Find.byId<string, JsonDocument> SqliteDb.TableName "test"
Expect.isSome after "There should have been a document returned post-update"
Expect.equal after.Value upd8Doc "The updated document is not correct"
}
]
testList "Count" [
testTask "all succeeds" {
use! db = SqliteDb.BuildDb()
do! loadDocs ()
let! theCount = Count.all SqliteDb.TableName
Expect.equal theCount 5L "There should have been 5 matching documents"
}
testTask "byField succeeds" {
use! db = SqliteDb.BuildDb()
do! loadDocs ()
let! theCount = Count.byField SqliteDb.TableName "Value" EQ "purple"
Expect.equal theCount 2L "There should have been 2 matching documents"
}
]
testList "Exists" [
testList "byId" [
testTask "succeeds when a document exists" {
use! db = SqliteDb.BuildDb()
do! loadDocs ()
let! exists = Exists.byId 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()
do! loadDocs ()
let! exists = Exists.byId SqliteDb.TableName "seven"
Expect.isFalse exists "There should not have been an existing document"
}
]
testList "byField" [
testTask "succeeds when documents exist" {
use! db = SqliteDb.BuildDb()
do! loadDocs ()
let! exists = Exists.byField 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()
do! loadDocs ()
let! exists = Exists.byField SqliteDb.TableName "Nothing" LT "none"
Expect.isFalse exists "There should not have been any existing documents"
}
]
]
testList "Find" [
testList "all" [
testTask "succeeds when there is data" {
use! db = SqliteDb.BuildDb()
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 = Find.all<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()
let! results = Find.all<SubDocument> SqliteDb.TableName
Expect.equal results [] "There should have been no documents returned"
}
]
testList "byId" [
testTask "succeeds when a document is found" {
use! db = SqliteDb.BuildDb()
do! loadDocs ()
let! doc = Find.byId<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()
do! loadDocs ()
let! doc = Find.byId<string, JsonDocument> SqliteDb.TableName "three hundred eighty-seven"
Expect.isFalse (Option.isSome doc) "There should not have been a document returned"
}
]
testList "byField" [
testTask "succeeds when documents are found" {
use! db = SqliteDb.BuildDb()
do! loadDocs ()
let! docs = Find.byField<JsonDocument> SqliteDb.TableName "NumValue" GT 15
Expect.equal (List.length docs) 2 "There should have been two documents returned"
}
testTask "succeeds when documents are not found" {
use! db = SqliteDb.BuildDb()
do! loadDocs ()
let! docs = Find.byField<JsonDocument> SqliteDb.TableName "NumValue" GT 100
Expect.isTrue (List.isEmpty docs) "There should have been no documents returned"
}
]
testList "firstByField" [
testTask "succeeds when a document is found" {
use! db = SqliteDb.BuildDb()
do! loadDocs ()
let! doc = Find.firstByField<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()
do! loadDocs ()
let! doc = Find.firstByField<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()
do! loadDocs ()
let! doc = Find.firstByField<JsonDocument> SqliteDb.TableName "Value" EQ "absent"
Expect.isFalse (Option.isSome doc) "There should not have been a document returned"
}
]
]
testList "Update" [
testList "byId" [
testTask "succeeds when a document is updated" {
use! db = SqliteDb.BuildDb()
do! loadDocs ()
let testDoc = { emptyDoc with Id = "one"; Sub = Some { Foo = "blue"; Bar = "red" } }
do! Update.byId SqliteDb.TableName "one" testDoc
let! after = Find.byId<string, JsonDocument> SqliteDb.TableName "one"
Expect.isSome after "There should have been a document returned post-update"
Expect.equal after.Value testDoc "The updated document is not correct"
}
testTask "succeeds when no document is updated" {
use! db = SqliteDb.BuildDb()
let! before = Find.all<JsonDocument> SqliteDb.TableName
Expect.isEmpty before "There should have been no documents returned"
// This not raising an exception is the test
do! Update.byId
SqliteDb.TableName
"test"
{ emptyDoc with Id = "x"; Sub = Some { Foo = "blue"; Bar = "red" } }
}
]
testList "byFunc" [
testTask "succeeds when a document is updated" {
use! db = SqliteDb.BuildDb()
do! loadDocs ()
do! Update.byFunc
SqliteDb.TableName (_.Id) { Id = "one"; Value = "le un"; NumValue = 1; Sub = None }
let! after = Find.byId<string, JsonDocument> SqliteDb.TableName "one"
Expect.isSome after "There should have been a document returned post-update"
Expect.equal
after.Value
{ Id = "one"; Value = "le un"; NumValue = 1; Sub = None }
"The updated document is not correct"
}
testTask "succeeds when no document is updated" {
use! db = SqliteDb.BuildDb()
let! before = Find.all<JsonDocument> SqliteDb.TableName
Expect.isEmpty before "There should have been no documents returned"
// This not raising an exception is the test
do! Update.byFunc
SqliteDb.TableName (_.Id) { Id = "one"; Value = "le un"; NumValue = 1; Sub = None }
}
]
]
testList "Patch" [
testList "byId" [
testTask "succeeds when a document is updated" {
use! db = SqliteDb.BuildDb()
do! loadDocs ()
do! Patch.byId SqliteDb.TableName "one" {| NumValue = 44 |}
let! after = Find.byId<string, JsonDocument> SqliteDb.TableName "one"
Expect.isSome after "There should have been a document returned post-update"
Expect.equal after.Value.NumValue 44 "The updated document is not correct"
}
testTask "succeeds when no document is updated" {
use! db = SqliteDb.BuildDb()
let! before = Find.all<SubDocument> SqliteDb.TableName
Expect.isEmpty before "There should have been no documents returned"
// This not raising an exception is the test
do! Patch.byId SqliteDb.TableName "test" {| Foo = "green" |}
}
]
testList "byField" [
testTask "succeeds when a document is updated" {
use! db = SqliteDb.BuildDb()
do! loadDocs ()
do! Patch.byField SqliteDb.TableName "Value" EQ "purple" {| NumValue = 77 |}
let! after = Count.byField 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()
let! before = Find.all<SubDocument> SqliteDb.TableName
Expect.isEmpty before "There should have been no documents returned"
// This not raising an exception is the test
do! Patch.byField SqliteDb.TableName "Value" EQ "burgundy" {| Foo = "green" |}
}
]
]
testList "Delete" [
testList "byId" [
testTask "succeeds when a document is deleted" {
use! db = SqliteDb.BuildDb()
do! loadDocs ()
do! Delete.byId SqliteDb.TableName "four"
let! remaining = Count.all 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()
do! loadDocs ()
do! Delete.byId SqliteDb.TableName "thirty"
let! remaining = Count.all SqliteDb.TableName
Expect.equal remaining 5L "There should have been 5 documents remaining"
}
]
testList "byField" [
testTask "succeeds when documents are deleted" {
use! db = SqliteDb.BuildDb()
do! loadDocs ()
do! Delete.byField SqliteDb.TableName "Value" NE "purple"
let! remaining = Count.all SqliteDb.TableName
Expect.equal remaining 2L "There should have been 2 documents remaining"
}
testTask "succeeds when documents are not deleted" {
use! db = SqliteDb.BuildDb()
do! loadDocs ()
do! Delete.byField SqliteDb.TableName "Value" EQ "crimson"
let! remaining = Count.all SqliteDb.TableName
Expect.equal remaining 5L "There should have been 5 documents remaining"
}
]
]
test "clean up database" {
Configuration.useConnectionString "data source=:memory:"
}
]
|> testSequenced
let all = testList "Sqlite" [ unitTests; integrationTests ]

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

@@ -0,0 +1,23 @@
module Types
type SubDocument =
{ Foo: string
Bar: string }
type JsonDocument =
{ Id: string
Value: string
NumValue: int
Sub: SubDocument option }
/// An empty JsonDocument
let emptyDoc = { Id = ""; Value = ""; NumValue = 0; Sub = None }
/// Documents to use for testing
let testDocuments = [
{ 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 }
]