RC4 changes #7

Merged
danieljsummers merged 7 commits from arr-cee-four into main 2024-09-17 02:33:57 +00:00
19 changed files with 883 additions and 569 deletions

View File

@ -2,39 +2,45 @@
open System.Security.Cryptography open System.Security.Cryptography
/// The types of logical operations available for JSON fields /// The types of comparisons available for JSON fields
[<Struct>] type Comparison =
type Op =
/// Equals (=) /// Equals (=)
| EQ | Equal of Value: obj
/// Greater Than (>) /// Greater Than (>)
| GT | Greater of Value: obj
/// Greater Than or Equal To (>=) /// Greater Than or Equal To (>=)
| GE | GreaterOrEqual of Value: obj
/// Less Than (<) /// Less Than (<)
| LT | Less of Value: obj
/// Less Than or Equal To (<=) /// Less Than or Equal To (<=)
| LE | LessOrEqual of Value: obj
/// Not Equal to (<>) /// Not Equal to (<>)
| NE | NotEqual of Value: obj
/// Between (BETWEEN) /// Between (BETWEEN)
| BT | Between of Min: obj * Max: obj
/// In (IN)
| In of Values: obj seq
/// In Array (PostgreSQL: |?, SQLite: EXISTS / json_each / IN)
| InArray of Table: string * Values: obj seq
/// Exists (IS NOT NULL) /// Exists (IS NOT NULL)
| EX | Exists
/// Does Not Exist (IS NULL) /// Does Not Exist (IS NULL)
| NEX | NotExists
override this.ToString() = /// Get the operator SQL for this comparison
member this.OpSql =
match this with match this with
| EQ -> "=" | Equal _ -> "="
| GT -> ">" | Greater _ -> ">"
| GE -> ">=" | GreaterOrEqual _ -> ">="
| LT -> "<" | Less _ -> "<"
| LE -> "<=" | LessOrEqual _ -> "<="
| NE -> "<>" | NotEqual _ -> "<>"
| BT -> "BETWEEN" | Between _ -> "BETWEEN"
| EX -> "IS NOT NULL" | In _ -> "IN"
| NEX -> "IS NULL" | InArray _ -> "?|" // PostgreSQL only; SQL needs a subquery for this
| Exists -> "IS NOT NULL"
| NotExists -> "IS NULL"
/// The dialect in which a command should be rendered /// The dialect in which a command should be rendered
@ -43,73 +49,129 @@ type Dialect =
| PostgreSQL | PostgreSQL
| SQLite | SQLite
/// The format in which an element of a JSON field should be extracted
[<Struct>]
type FieldFormat =
/// Use ->> or #>>; extracts a text (PostgreSQL) or SQL (SQLite) value
| AsSql
/// Use -> or #>; extracts a JSONB (PostgreSQL) or JSON (SQLite) value
| AsJson
/// Criteria for a field WHERE clause /// Criteria for a field WHERE clause
type Field = { type Field =
/// The name of the field { /// The name of the field
Name: string Name: string
/// The operation by which the field will be compared /// The comparison for the field
Op: Op Comparison: Comparison
/// The value of the field /// The name of the parameter for this field
Value: obj ParameterName: string option
/// The name of the parameter for this field /// The table qualifier for this field
ParameterName: string option Qualifier: string option }
with
/// The table qualifier for this field /// Create a comparison against a field
Qualifier: string option static member Where name comparison =
} with { Name = name; Comparison = comparison; ParameterName = None; Qualifier = None }
/// Create an equals (=) field criterion /// Create an equals (=) field criterion
static member EQ name (value: obj) = static member Equal name (value: obj) =
{ Name = name; Op = EQ; Value = value; ParameterName = None; Qualifier = None } Field.Where name (Equal value)
/// Create an equals (=) field criterion (alias)
static member EQ name (value: obj) = Field.Equal name value
/// Create a greater than (>) field criterion /// Create a greater than (>) field criterion
static member GT name (value: obj) = static member Greater name (value: obj) =
{ Name = name; Op = GT; Value = value; ParameterName = None; Qualifier = None } Field.Where name (Greater value)
/// Create a greater than (>) field criterion (alias)
static member GT name (value: obj) = Field.Greater name value
/// Create a greater than or equal to (>=) field criterion /// Create a greater than or equal to (>=) field criterion
static member GE name (value: obj) = static member GreaterOrEqual name (value: obj) =
{ Name = name; Op = GE; Value = value; ParameterName = None; Qualifier = None } Field.Where name (GreaterOrEqual value)
/// Create a greater than or equal to (>=) field criterion (alias)
static member GE name (value: obj) = Field.GreaterOrEqual name value
/// Create a less than (<) field criterion /// Create a less than (<) field criterion
static member LT name (value: obj) = static member Less name (value: obj) =
{ Name = name; Op = LT; Value = value; ParameterName = None; Qualifier = None } Field.Where name (Less value)
/// Create a less than (<) field criterion (alias)
static member LT name (value: obj) = Field.Less name value
/// Create a less than or equal to (<=) field criterion /// Create a less than or equal to (<=) field criterion
static member LE name (value: obj) = static member LessOrEqual name (value: obj) =
{ Name = name; Op = LE; Value = value; ParameterName = None; Qualifier = None } Field.Where name (LessOrEqual value)
/// Create a less than or equal to (<=) field criterion (alias)
static member LE name (value: obj) = Field.LessOrEqual name value
/// Create a not equals (<>) field criterion /// Create a not equals (<>) field criterion
static member NE name (value: obj) = static member NotEqual name (value: obj) =
{ Name = name; Op = NE; Value = value; ParameterName = None; Qualifier = None } Field.Where name (NotEqual value)
/// Create a BETWEEN field criterion /// Create a not equals (<>) field criterion (alias)
static member BT name (min: obj) (max: obj) = static member NE name (value: obj) = Field.NotEqual name value
{ Name = name; Op = BT; Value = [ min; max ]; ParameterName = None; Qualifier = None }
/// Create a Between field criterion
static member Between name (min: obj) (max: obj) =
Field.Where name (Between(min, max))
/// Create a Between field criterion (alias)
static member BT name (min: obj) (max: obj) = Field.Between name min max
/// Create an In field criterion
static member In name (values: obj seq) =
Field.Where name (In values)
/// Create an In field criterion (alias)
static member IN name (values: obj seq) = Field.In name values
/// Create an InArray field criterion
static member InArray name tableName (values: obj seq) =
Field.Where name (InArray(tableName, values))
/// Create an exists (IS NOT NULL) field criterion /// Create an exists (IS NOT NULL) field criterion
static member EX name = static member Exists name =
{ Name = name; Op = EX; Value = obj (); ParameterName = None; Qualifier = None } Field.Where name Exists
/// Create an exists (IS NOT NULL) field criterion (alias)
static member EX name = Field.Exists name
/// Create a not exists (IS NULL) field criterion /// Create a not exists (IS NULL) field criterion
static member NEX name = static member NotExists name =
{ Name = name; Op = NEX; Value = obj (); ParameterName = None; Qualifier = None } Field.Where name NotExists
/// Create a not exists (IS NULL) field criterion (alias)
static member NEX name = Field.NotExists name
/// Transform a field name (a.b.c) to a path for the given SQL dialect /// Transform a field name (a.b.c) to a path for the given SQL dialect
static member NameToPath (name: string) dialect = static member NameToPath (name: string) dialect format =
let path = let path =
if name.Contains '.' then if name.Contains '.' then
match dialect with match dialect with
| PostgreSQL -> "#>>'{" + String.concat "," (name.Split '.') + "}'" | PostgreSQL ->
| SQLite -> "->>'" + String.concat "'->>'" (name.Split '.') + "'" (match format with AsJson -> "#>" | AsSql -> "#>>")
else $"->>'{name}'" + "'{" + String.concat "," (name.Split '.') + "}'"
| SQLite ->
let parts = name.Split '.'
let last = Array.last parts
let final = (match format with AsJson -> "'->'" | AsSql -> "'->>'") + $"{last}'"
"->'" + String.concat "'->'" (Array.truncate (Array.length parts - 1) parts) + final
else
match format with AsJson -> $"->'{name}'" | AsSql -> $"->>'{name}'"
$"data{path}" $"data{path}"
/// Create a field with a given name, but no other properties filled (op will be EQ, value will be "") /// Create a field with a given name, but no other properties filled (op will be EQ, value will be "")
static member Named name = static member Named name =
{ Name = name; Op = EQ; Value = ""; ParameterName = None; Qualifier = None } Field.Where name (Equal "")
/// Specify the name of the parameter for this field /// Specify the name of the parameter for this field
member this.WithParameterName name = member this.WithParameterName name =
@ -120,8 +182,9 @@ type Field = {
{ this with Qualifier = Some alias } { this with Qualifier = Some alias }
/// Get the qualified path to the field /// Get the qualified path to the field
member this.Path dialect = member this.Path dialect format =
(this.Qualifier |> Option.map (fun q -> $"{q}.") |> Option.defaultValue "") + Field.NameToPath this.Name dialect (this.Qualifier |> Option.map (fun q -> $"{q}.") |> Option.defaultValue "")
+ Field.NameToPath this.Name dialect format
/// How fields should be matched /// How fields should be matched
@ -337,7 +400,7 @@ module Query =
let parts = it.Split ' ' let parts = it.Split ' '
let fieldName = if Array.length parts = 1 then it else parts[0] let fieldName = if Array.length parts = 1 then it else parts[0]
let direction = if Array.length parts < 2 then "" else $" {parts[1]}" let direction = if Array.length parts < 2 then "" else $" {parts[1]}"
$"({Field.NameToPath fieldName dialect}){direction}") $"({Field.NameToPath fieldName dialect AsSql}){direction}")
|> String.concat ", " |> String.concat ", "
$"CREATE INDEX IF NOT EXISTS idx_{tbl}_%s{indexName} ON {tableName} ({jsonFields})" $"CREATE INDEX IF NOT EXISTS idx_{tbl}_%s{indexName} ON {tableName} ({jsonFields})"
@ -403,11 +466,13 @@ module Query =
|> Seq.map (fun (field, direction) -> |> Seq.map (fun (field, direction) ->
if field.Name.StartsWith "n:" then if field.Name.StartsWith "n:" then
let f = { field with Name = field.Name[2..] } let f = { field with Name = field.Name[2..] }
match dialect with PostgreSQL -> $"({f.Path PostgreSQL})::numeric" | SQLite -> f.Path SQLite match dialect with
| PostgreSQL -> $"({f.Path PostgreSQL AsSql})::numeric"
| SQLite -> f.Path SQLite AsSql
elif field.Name.StartsWith "i:" then elif field.Name.StartsWith "i:" then
let p = { field with Name = field.Name[2..] }.Path dialect let p = { field with Name = field.Name[2..] }.Path dialect AsSql
match dialect with PostgreSQL -> $"LOWER({p})" | SQLite -> $"{p} COLLATE NOCASE" match dialect with PostgreSQL -> $"LOWER({p})" | SQLite -> $"{p} COLLATE NOCASE"
else field.Path dialect else field.Path dialect AsSql
|> function path -> path + defaultArg direction "") |> function path -> path + defaultArg direction "")
|> String.concat ", " |> String.concat ", "
|> function it -> $" ORDER BY {it}" |> function it -> $" ORDER BY {it}"

View File

@ -6,8 +6,8 @@
<AssemblyVersion>4.0.0.0</AssemblyVersion> <AssemblyVersion>4.0.0.0</AssemblyVersion>
<FileVersion>4.0.0.0</FileVersion> <FileVersion>4.0.0.0</FileVersion>
<VersionPrefix>4.0.0</VersionPrefix> <VersionPrefix>4.0.0</VersionPrefix>
<VersionSuffix>rc3</VersionSuffix> <VersionSuffix>rc4</VersionSuffix>
<PackageReleaseNotes>From rc2: preserve additional ORDER BY qualifiers. From rc1: add case-insensitive ordering. From v3.1: Change ByField to ByFields; support dot-access to nested document fields; add Find*Ordered functions/methods; see project site for breaking changes and compatibility</PackageReleaseNotes> <PackageReleaseNotes>From rc3: Add In/InArray field comparisons, revamp internal comparison handling. From rc2: preserve additional ORDER BY qualifiers. From rc1: add case-insensitive ordering. From v3.1: Change ByField to ByFields; support dot-access to nested document fields; add Find*Ordered functions/methods; see project site for breaking changes and compatibility</PackageReleaseNotes>
<Authors>danieljsummers</Authors> <Authors>danieljsummers</Authors>
<Company>Bit Badger Solutions</Company> <Company>Bit Badger Solutions</Company>
<PackageReadmeFile>README.md</PackageReadmeFile> <PackageReadmeFile>README.md</PackageReadmeFile>

View File

@ -87,18 +87,25 @@ module Parameters =
fields fields
|> Seq.map (fun it -> |> Seq.map (fun it ->
seq { seq {
match it.Op with match it.Comparison with
| EX | NEX -> () | Exists | NotExists -> ()
| BT -> | Between (min, max) ->
let p = name.Derive it.ParameterName
let values = it.Value :?> obj list
yield ($"{p}min",
parameterFor (List.head values) (fun v -> Sql.parameter (NpgsqlParameter($"{p}min", v))))
yield ($"{p}max",
parameterFor (List.last values) (fun v -> Sql.parameter (NpgsqlParameter($"{p}max", v))))
| _ ->
let p = name.Derive it.ParameterName let p = name.Derive it.ParameterName
yield (p, parameterFor it.Value (fun v -> Sql.parameter (NpgsqlParameter(p, v)))) }) yield ($"{p}min", parameterFor min (fun v -> Sql.parameter (NpgsqlParameter($"{p}min", v))))
yield ($"{p}max", parameterFor max (fun v -> Sql.parameter (NpgsqlParameter($"{p}max", v))))
| In values ->
let p = name.Derive it.ParameterName
yield!
values
|> Seq.mapi (fun idx v ->
let paramName = $"{p}_{idx}"
paramName, Sql.parameter (NpgsqlParameter(paramName, v)))
| InArray (_, values) ->
let p = name.Derive it.ParameterName
yield (p, Sql.stringArray (values |> Seq.map string |> Array.ofSeq))
| Equal v | Greater v | GreaterOrEqual v | Less v | LessOrEqual v | NotEqual v ->
let p = name.Derive it.ParameterName
yield (p, parameterFor v (fun l -> Sql.parameter (NpgsqlParameter(p, l)))) })
|> Seq.collect id |> Seq.collect id
|> Seq.append parameters |> Seq.append parameters
|> Seq.toList |> Seq.toList
@ -131,23 +138,28 @@ module Query =
| _ -> false | _ -> false
fields fields
|> Seq.map (fun it -> |> Seq.map (fun it ->
match it.Op with match it.Comparison with
| EX | NEX -> $"{it.Path PostgreSQL} {it.Op}" | Exists | NotExists -> $"{it.Path PostgreSQL AsSql} {it.Comparison.OpSql}"
| InArray _ -> $"{it.Path PostgreSQL AsJson} {it.Comparison.OpSql} {name.Derive it.ParameterName}"
| _ -> | _ ->
let p = name.Derive it.ParameterName let p = name.Derive it.ParameterName
let param, value = let param, value =
match it.Op with match it.Comparison with
| BT -> $"{p}min AND {p}max", (it.Value :?> obj list)[0] | Between (min, _) -> $"{p}min AND {p}max", min
| _ -> p, it.Value | In values ->
let paramNames = values |> Seq.mapi (fun idx _ -> $"{p}_{idx}") |> String.concat ", "
$"({paramNames})", defaultArg (Seq.tryHead values) (obj ())
| Equal v | Greater v | GreaterOrEqual v | Less v | LessOrEqual v | NotEqual v -> p, v
| _ -> p, ""
if isNumeric value then if isNumeric value then
$"({it.Path PostgreSQL})::numeric {it.Op} {param}" $"({it.Path PostgreSQL AsSql})::numeric {it.Comparison.OpSql} {param}"
else $"{it.Path PostgreSQL} {it.Op} {param}") else $"{it.Path PostgreSQL AsSql} {it.Comparison.OpSql} {param}")
|> String.concat $" {howMatched} " |> String.concat $" {howMatched} "
/// Create a WHERE clause fragment to implement an ID-based query /// Create a WHERE clause fragment to implement an ID-based query
[<CompiledName "WhereById">] [<CompiledName "WhereById">]
let whereById<'TKey> (docId: 'TKey) = let whereById<'TKey> (docId: 'TKey) =
whereByFields Any [ { Field.EQ (Configuration.idField ()) docId with ParameterName = Some "@id" } ] whereByFields Any [ { Field.Equal (Configuration.idField ()) docId with ParameterName = Some "@id" } ]
/// Table and index definition queries /// Table and index definition queries
module Definition = module Definition =

View File

@ -66,7 +66,7 @@ var customer = await Find.ById<string, Customer>("customer", "123");
// Find.byId type signature is string -> 'TKey -> Task<'TDoc option> // Find.byId type signature is string -> 'TKey -> Task<'TDoc option>
let! customer = Find.byId<string, Customer> "customer" "123" let! customer = Find.byId<string, Customer> "customer" "123"
``` ```
_(keys are treated as strings in the database)_ _(keys are treated as strings or numbers depending on their defintion; however, they are indexed as strings)_
Count customers in Atlanta (using JSON containment): Count customers in Atlanta (using JSON containment):

View File

@ -37,18 +37,26 @@ module Query =
let name = ParameterName() let name = ParameterName()
fields fields
|> Seq.map (fun it -> |> Seq.map (fun it ->
match it.Op with match it.Comparison with
| EX | NEX -> $"{it.Path SQLite} {it.Op}" | Exists | NotExists -> $"{it.Path SQLite AsSql} {it.Comparison.OpSql}"
| BT -> | Between _ ->
let p = name.Derive it.ParameterName let p = name.Derive it.ParameterName
$"{it.Path SQLite} {it.Op} {p}min AND {p}max" $"{it.Path SQLite AsSql} {it.Comparison.OpSql} {p}min AND {p}max"
| _ -> $"{it.Path SQLite} {it.Op} {name.Derive it.ParameterName}") | In values ->
let p = name.Derive it.ParameterName
let paramNames = values |> Seq.mapi (fun idx _ -> $"{p}_{idx}") |> String.concat ", "
$"{it.Path SQLite AsSql} {it.Comparison.OpSql} ({paramNames})"
| InArray (table, values) ->
let p = name.Derive it.ParameterName
let paramNames = values |> Seq.mapi (fun idx _ -> $"{p}_{idx}") |> String.concat ", "
$"EXISTS (SELECT 1 FROM json_each({table}.data, '$.{it.Name}') WHERE value IN ({paramNames}))"
| _ -> $"{it.Path SQLite AsSql} {it.Comparison.OpSql} {name.Derive it.ParameterName}")
|> String.concat $" {howMatched} " |> String.concat $" {howMatched} "
/// Create a WHERE clause fragment to implement an ID-based query /// Create a WHERE clause fragment to implement an ID-based query
[<CompiledName "WhereById">] [<CompiledName "WhereById">]
let whereById paramName = let whereById paramName =
whereByFields Any [ { Field.EQ (Configuration.idField ()) 0 with ParameterName = Some paramName } ] whereByFields Any [ { Field.Equal (Configuration.idField ()) 0 with ParameterName = Some paramName } ]
/// Create an UPDATE statement to patch documents /// Create an UPDATE statement to patch documents
[<CompiledName "Patch">] [<CompiledName "Patch">]
@ -66,7 +74,7 @@ module Query =
let byId<'TKey> statement (docId: 'TKey) = let byId<'TKey> statement (docId: 'TKey) =
Query.statementWhere Query.statementWhere
statement statement
(whereByFields Any [ { Field.EQ (Configuration.idField ()) docId with ParameterName = Some "@id" } ]) (whereByFields Any [ { Field.Equal (Configuration.idField ()) docId with ParameterName = Some "@id" } ])
/// Create a query on JSON fields /// Create a query on JSON fields
[<CompiledName "ByFields">] [<CompiledName "ByFields">]
@ -103,14 +111,16 @@ module Parameters =
fields fields
|> Seq.map (fun it -> |> Seq.map (fun it ->
seq { seq {
match it.Op with match it.Comparison with
| EX | NEX -> () | Exists | NotExists -> ()
| BT -> | Between (min, max) ->
let p = name.Derive it.ParameterName let p = name.Derive it.ParameterName
let values = it.Value :?> obj list yield! [ SqliteParameter($"{p}min", min); SqliteParameter($"{p}max", max) ]
yield SqliteParameter($"{p}min", List.head values) | In values | InArray (_, values) ->
yield SqliteParameter($"{p}max", List.last values) let p = name.Derive it.ParameterName
| _ -> yield SqliteParameter(name.Derive it.ParameterName, it.Value) }) yield! values |> Seq.mapi (fun idx v -> SqliteParameter($"{p}_{idx}", v))
| Equal v | Greater v | GreaterOrEqual v | Less v | LessOrEqual v | NotEqual v ->
yield SqliteParameter(name.Derive it.ParameterName, v) })
|> Seq.collect id |> Seq.collect id
|> Seq.append parameters |> Seq.append parameters
|> Seq.toList |> Seq.toList

View File

@ -73,13 +73,13 @@ Count customers in Atlanta:
```csharp ```csharp
// C#; parameters are table name, field, operator, and value // C#; parameters are table name, field, operator, and value
// Count.ByField type signature is Func<string, Field, Task<long>> // Count.ByField type signature is Func<string, Field, Task<long>>
var customerCount = await Count.ByField("customer", Field.EQ("City", "Atlanta")); var customerCount = await Count.ByField("customer", Field.Equal("City", "Atlanta"));
``` ```
```fsharp ```fsharp
// F# // F#
// Count.byField type signature is string -> Field -> Task<int64> // Count.byField type signature is string -> Field -> Task<int64>
let! customerCount = Count.byField "customer" (Field.EQ "City" "Atlanta") let! customerCount = Count.byField "customer" (Field.Equal "City" "Atlanta")
``` ```
Delete customers in Chicago: _(no offense, Second City; just an example...)_ Delete customers in Chicago: _(no offense, Second City; just an example...)_
@ -87,13 +87,13 @@ Delete customers in Chicago: _(no offense, Second City; just an example...)_
```csharp ```csharp
// C#; parameters are same as above, except return is void // C#; parameters are same as above, except return is void
// Delete.ByField type signature is Func<string, Field, Task> // Delete.ByField type signature is Func<string, Field, Task>
await Delete.ByField("customer", Field.EQ("City", "Chicago")); await Delete.ByField("customer", Field.Equal("City", "Chicago"));
``` ```
```fsharp ```fsharp
// F# // F#
// Delete.byField type signature is string -> string -> Op -> obj -> Task<unit> // Delete.byField type signature is string -> string -> Op -> obj -> Task<unit>
do! Delete.byField "customer" (Field.EQ "City" "Chicago") do! Delete.byField "customer" (Field.Equal "City" "Chicago")
``` ```
## More Information ## More Information

View File

@ -1,6 +1,5 @@
using Expecto.CSharp; using Expecto.CSharp;
using Expecto; using Expecto;
using Microsoft.FSharp.Collections;
using Microsoft.FSharp.Core; using Microsoft.FSharp.Core;
namespace BitBadger.Documents.Tests.CSharp; namespace BitBadger.Documents.Tests.CSharp;
@ -22,45 +21,53 @@ internal class TestSerializer : IDocumentSerializer
public static class CommonCSharpTests public static class CommonCSharpTests
{ {
/// <summary> /// <summary>
/// Unit tests for the Op enum /// Unit tests for the OpSql property of the Comparison discriminated union
/// </summary> /// </summary>
private static readonly Test OpTests = TestList("Op", private static readonly Test OpTests = TestList("Comparison.OpSql",
[ [
TestCase("EQ succeeds", () => TestCase("Equal succeeds", () =>
{ {
Expect.equal(Op.EQ.ToString(), "=", "The equals operator was not correct"); Expect.equal(Comparison.NewEqual("").OpSql, "=", "The Equals SQL was not correct");
}), }),
TestCase("GT succeeds", () => TestCase("Greater succeeds", () =>
{ {
Expect.equal(Op.GT.ToString(), ">", "The greater than operator was not correct"); Expect.equal(Comparison.NewGreater("").OpSql, ">", "The Greater SQL was not correct");
}), }),
TestCase("GE succeeds", () => TestCase("GreaterOrEqual succeeds", () =>
{ {
Expect.equal(Op.GE.ToString(), ">=", "The greater than or equal to operator was not correct"); Expect.equal(Comparison.NewGreaterOrEqual("").OpSql, ">=", "The GreaterOrEqual SQL was not correct");
}), }),
TestCase("LT succeeds", () => TestCase("Less succeeds", () =>
{ {
Expect.equal(Op.LT.ToString(), "<", "The less than operator was not correct"); Expect.equal(Comparison.NewLess("").OpSql, "<", "The Less SQL was not correct");
}), }),
TestCase("LE succeeds", () => TestCase("LessOrEqual succeeds", () =>
{ {
Expect.equal(Op.LE.ToString(), "<=", "The less than or equal to operator was not correct"); Expect.equal(Comparison.NewLessOrEqual("").OpSql, "<=", "The LessOrEqual SQL was not correct");
}), }),
TestCase("NE succeeds", () => TestCase("NotEqual succeeds", () =>
{ {
Expect.equal(Op.NE.ToString(), "<>", "The not equal to operator was not correct"); Expect.equal(Comparison.NewNotEqual("").OpSql, "<>", "The NotEqual SQL was not correct");
}), }),
TestCase("BT succeeds", () => TestCase("Between succeeds", () =>
{ {
Expect.equal(Op.BT.ToString(), "BETWEEN", "The \"between\" operator was not correct"); Expect.equal(Comparison.NewBetween("", "").OpSql, "BETWEEN", "The Between SQL was not correct");
}), }),
TestCase("EX succeeds", () => TestCase("In succeeds", () =>
{ {
Expect.equal(Op.EX.ToString(), "IS NOT NULL", "The \"exists\" operator was not correct"); Expect.equal(Comparison.NewIn([]).OpSql, "IN", "The In SQL was not correct");
}), }),
TestCase("NEX succeeds", () => TestCase("InArray succeeds", () =>
{ {
Expect.equal(Op.NEX.ToString(), "IS NULL", "The \"not exists\" operator was not correct"); Expect.equal(Comparison.NewInArray("", []).OpSql, "?|", "The InArray SQL was not correct");
}),
TestCase("Exists succeeds", () =>
{
Expect.equal(Comparison.Exists.OpSql, "IS NOT NULL", "The Exists SQL was not correct");
}),
TestCase("NotExists succeeds", () =>
{
Expect.equal(Comparison.NotExists.OpSql, "IS NULL", "The NotExists SQL was not correct");
}) })
]); ]);
@ -69,101 +76,110 @@ public static class CommonCSharpTests
/// </summary> /// </summary>
private static readonly Test FieldTests = TestList("Field", private static readonly Test FieldTests = TestList("Field",
[ [
TestCase("EQ succeeds", () => TestCase("Equal succeeds", () =>
{ {
var field = Field.EQ("Test", 14); var field = Field.Equal("Test", 14);
Expect.equal(field.Name, "Test", "Field name incorrect"); Expect.equal(field.Name, "Test", "Field name incorrect");
Expect.equal(field.Op, Op.EQ, "Operator incorrect"); Expect.equal(field.Comparison, Comparison.NewEqual(14), "Comparison incorrect");
Expect.equal(field.Value, 14, "Value incorrect");
}), }),
TestCase("GT succeeds", () => TestCase("Greater succeeds", () =>
{ {
var field = Field.GT("Great", "night"); var field = Field.Greater("Great", "night");
Expect.equal(field.Name, "Great", "Field name incorrect"); Expect.equal(field.Name, "Great", "Field name incorrect");
Expect.equal(field.Op, Op.GT, "Operator incorrect"); Expect.equal(field.Comparison, Comparison.NewGreater("night"), "Comparison incorrect");
Expect.equal(field.Value, "night", "Value incorrect");
}), }),
TestCase("GE succeeds", () => TestCase("GreaterOrEqual succeeds", () =>
{ {
var field = Field.GE("Nice", 88L); var field = Field.GreaterOrEqual("Nice", 88L);
Expect.equal(field.Name, "Nice", "Field name incorrect"); Expect.equal(field.Name, "Nice", "Field name incorrect");
Expect.equal(field.Op, Op.GE, "Operator incorrect"); Expect.equal(field.Comparison, Comparison.NewGreaterOrEqual(88L), "Comparison incorrect");
Expect.equal(field.Value, 88L, "Value incorrect");
}), }),
TestCase("LT succeeds", () => TestCase("Less succeeds", () =>
{ {
var field = Field.LT("Lesser", "seven"); var field = Field.Less("Lesser", "seven");
Expect.equal(field.Name, "Lesser", "Field name incorrect"); Expect.equal(field.Name, "Lesser", "Field name incorrect");
Expect.equal(field.Op, Op.LT, "Operator incorrect"); Expect.equal(field.Comparison, Comparison.NewLess("seven"), "Comparison incorrect");
Expect.equal(field.Value, "seven", "Value incorrect");
}), }),
TestCase("LE succeeds", () => TestCase("LessOrEqual succeeds", () =>
{ {
var field = Field.LE("Nobody", "KNOWS"); var field = Field.LessOrEqual("Nobody", "KNOWS");
Expect.equal(field.Name, "Nobody", "Field name incorrect"); Expect.equal(field.Name, "Nobody", "Field name incorrect");
Expect.equal(field.Op, Op.LE, "Operator incorrect"); Expect.equal(field.Comparison, Comparison.NewLessOrEqual("KNOWS"), "Comparison incorrect");
Expect.equal(field.Value, "KNOWS", "Value incorrect");
}), }),
TestCase("NE succeeds", () => TestCase("NotEqual succeeds", () =>
{ {
var field = Field.NE("Park", "here"); var field = Field.NotEqual("Park", "here");
Expect.equal(field.Name, "Park", "Field name incorrect"); Expect.equal(field.Name, "Park", "Field name incorrect");
Expect.equal(field.Op, Op.NE, "Operator incorrect"); Expect.equal(field.Comparison, Comparison.NewNotEqual("here"), "Comparison incorrect");
Expect.equal(field.Value, "here", "Value incorrect");
}), }),
TestCase("BT succeeds", () => TestCase("Between succeeds", () =>
{ {
var field = Field.BT("Age", 18, 49); var field = Field.Between("Age", 18, 49);
Expect.equal(field.Name, "Age", "Field name incorrect"); Expect.equal(field.Name, "Age", "Field name incorrect");
Expect.equal(field.Op, Op.BT, "Operator incorrect"); Expect.equal(field.Comparison, Comparison.NewBetween(18, 49), "Comparison incorrect");
Expect.equal(((FSharpList<object>)field.Value).ToArray(), [18, 49], "Value incorrect");
}), }),
TestCase("EX succeeds", () => TestCase("In succeeds", () =>
{ {
var field = Field.EX("Groovy"); var field = Field.In("Here", [8, 16, 32]);
Expect.equal(field.Name, "Here", "Field name incorrect");
Expect.isTrue(field.Comparison.IsIn, "Comparison incorrect");
Expect.sequenceEqual(((Comparison.In)field.Comparison).Values, [8, 16, 32], "Value incorrect");
}),
TestCase("InArray succeeds", () =>
{
var field = Field.InArray("ArrayField", "table", ["x", "y", "z"]);
Expect.equal(field.Name, "ArrayField", "Field name incorrect");
Expect.isTrue(field.Comparison.IsInArray, "Comparison incorrect");
var it = (Comparison.InArray)field.Comparison;
Expect.equal(it.Table, "table", "Table name incorrect");
Expect.sequenceEqual(it.Values, ["x", "y", "z"], "Value incorrect");
}),
TestCase("Exists succeeds", () =>
{
var field = Field.Exists("Groovy");
Expect.equal(field.Name, "Groovy", "Field name incorrect"); Expect.equal(field.Name, "Groovy", "Field name incorrect");
Expect.equal(field.Op, Op.EX, "Operator incorrect"); Expect.isTrue(field.Comparison.IsExists, "Comparison incorrect");
}), }),
TestCase("NEX succeeds", () => TestCase("NotExists succeeds", () =>
{ {
var field = Field.NEX("Rad"); var field = Field.NotExists("Rad");
Expect.equal(field.Name, "Rad", "Field name incorrect"); Expect.equal(field.Name, "Rad", "Field name incorrect");
Expect.equal(field.Op, Op.NEX, "Operator incorrect"); Expect.isTrue(field.Comparison.IsNotExists, "Comparison incorrect");
}), }),
TestList("NameToPath", TestList("NameToPath",
[ [
TestCase("succeeds for PostgreSQL and a simple name", () => TestCase("succeeds for PostgreSQL and a simple name", () =>
{ {
Expect.equal("data->>'Simple'", Field.NameToPath("Simple", Dialect.PostgreSQL), Expect.equal("data->>'Simple'", Field.NameToPath("Simple", Dialect.PostgreSQL, FieldFormat.AsSql),
"Path not constructed correctly"); "Path not constructed correctly");
}), }),
TestCase("succeeds for SQLite and a simple name", () => TestCase("succeeds for SQLite and a simple name", () =>
{ {
Expect.equal("data->>'Simple'", Field.NameToPath("Simple", Dialect.SQLite), Expect.equal("data->>'Simple'", Field.NameToPath("Simple", Dialect.SQLite, FieldFormat.AsSql),
"Path not constructed correctly"); "Path not constructed correctly");
}), }),
TestCase("succeeds for PostgreSQL and a nested name", () => TestCase("succeeds for PostgreSQL and a nested name", () =>
{ {
Expect.equal("data#>>'{A,Long,Path,to,the,Property}'", Expect.equal("data#>>'{A,Long,Path,to,the,Property}'",
Field.NameToPath("A.Long.Path.to.the.Property", Dialect.PostgreSQL), Field.NameToPath("A.Long.Path.to.the.Property", Dialect.PostgreSQL, FieldFormat.AsSql),
"Path not constructed correctly"); "Path not constructed correctly");
}), }),
TestCase("succeeds for SQLite and a nested name", () => TestCase("succeeds for SQLite and a nested name", () =>
{ {
Expect.equal("data->>'A'->>'Long'->>'Path'->>'to'->>'the'->>'Property'", Expect.equal("data->'A'->'Long'->'Path'->'to'->'the'->>'Property'",
Field.NameToPath("A.Long.Path.to.the.Property", Dialect.SQLite), Field.NameToPath("A.Long.Path.to.the.Property", Dialect.SQLite, FieldFormat.AsSql),
"Path not constructed correctly"); "Path not constructed correctly");
}) })
]), ]),
TestCase("WithParameterName succeeds", () => TestCase("WithParameterName succeeds", () =>
{ {
var field = Field.EQ("Bob", "Tom").WithParameterName("@name"); var field = Field.Equal("Bob", "Tom").WithParameterName("@name");
Expect.isSome(field.ParameterName, "The parameter name should have been filled"); Expect.isSome(field.ParameterName, "The parameter name should have been filled");
Expect.equal("@name", field.ParameterName.Value, "The parameter name is incorrect"); Expect.equal("@name", field.ParameterName.Value, "The parameter name is incorrect");
}), }),
TestCase("WithQualifier succeeds", () => TestCase("WithQualifier succeeds", () =>
{ {
var field = Field.EQ("Bill", "Matt").WithQualifier("joe"); var field = Field.Equal("Bill", "Matt").WithQualifier("joe");
Expect.isSome(field.Qualifier, "The table qualifier should have been filled"); Expect.isSome(field.Qualifier, "The table qualifier should have been filled");
Expect.equal("joe", field.Qualifier.Value, "The table qualifier is incorrect"); Expect.equal("joe", field.Qualifier.Value, "The table qualifier is incorrect");
}), }),
@ -171,48 +187,51 @@ public static class CommonCSharpTests
[ [
TestCase("succeeds for a PostgreSQL single field with no qualifier", () => TestCase("succeeds for a PostgreSQL single field with no qualifier", () =>
{ {
var field = Field.GE("SomethingCool", 18); var field = Field.GreaterOrEqual("SomethingCool", 18);
Expect.equal("data->>'SomethingCool'", field.Path(Dialect.PostgreSQL), Expect.equal("data->>'SomethingCool'", field.Path(Dialect.PostgreSQL, FieldFormat.AsSql),
"The PostgreSQL path is incorrect"); "The PostgreSQL path is incorrect");
}), }),
TestCase("succeeds for a PostgreSQL single field with a qualifier", () => TestCase("succeeds for a PostgreSQL single field with a qualifier", () =>
{ {
var field = Field.LT("SomethingElse", 9).WithQualifier("this"); var field = Field.Less("SomethingElse", 9).WithQualifier("this");
Expect.equal("this.data->>'SomethingElse'", field.Path(Dialect.PostgreSQL), Expect.equal("this.data->>'SomethingElse'", field.Path(Dialect.PostgreSQL, FieldFormat.AsSql),
"The PostgreSQL path is incorrect"); "The PostgreSQL path is incorrect");
}), }),
TestCase("succeeds for a PostgreSQL nested field with no qualifier", () => TestCase("succeeds for a PostgreSQL nested field with no qualifier", () =>
{ {
var field = Field.EQ("My.Nested.Field", "howdy"); var field = Field.Equal("My.Nested.Field", "howdy");
Expect.equal("data#>>'{My,Nested,Field}'", field.Path(Dialect.PostgreSQL), Expect.equal("data#>>'{My,Nested,Field}'", field.Path(Dialect.PostgreSQL, FieldFormat.AsSql),
"The PostgreSQL path is incorrect"); "The PostgreSQL path is incorrect");
}), }),
TestCase("succeeds for a PostgreSQL nested field with a qualifier", () => TestCase("succeeds for a PostgreSQL nested field with a qualifier", () =>
{ {
var field = Field.EQ("Nest.Away", "doc").WithQualifier("bird"); var field = Field.Equal("Nest.Away", "doc").WithQualifier("bird");
Expect.equal("bird.data#>>'{Nest,Away}'", field.Path(Dialect.PostgreSQL), Expect.equal("bird.data#>>'{Nest,Away}'", field.Path(Dialect.PostgreSQL, FieldFormat.AsSql),
"The PostgreSQL path is incorrect"); "The PostgreSQL path is incorrect");
}), }),
TestCase("succeeds for a SQLite single field with no qualifier", () => TestCase("succeeds for a SQLite single field with no qualifier", () =>
{ {
var field = Field.GE("SomethingCool", 18); var field = Field.GreaterOrEqual("SomethingCool", 18);
Expect.equal("data->>'SomethingCool'", field.Path(Dialect.SQLite), "The SQLite path is incorrect"); Expect.equal("data->>'SomethingCool'", field.Path(Dialect.SQLite, FieldFormat.AsSql),
"The SQLite path is incorrect");
}), }),
TestCase("succeeds for a SQLite single field with a qualifier", () => TestCase("succeeds for a SQLite single field with a qualifier", () =>
{ {
var field = Field.LT("SomethingElse", 9).WithQualifier("this"); var field = Field.Less("SomethingElse", 9).WithQualifier("this");
Expect.equal("this.data->>'SomethingElse'", field.Path(Dialect.SQLite), "The SQLite path is incorrect"); Expect.equal("this.data->>'SomethingElse'", field.Path(Dialect.SQLite, FieldFormat.AsSql),
"The SQLite path is incorrect");
}), }),
TestCase("succeeds for a SQLite nested field with no qualifier", () => TestCase("succeeds for a SQLite nested field with no qualifier", () =>
{ {
var field = Field.EQ("My.Nested.Field", "howdy"); var field = Field.Equal("My.Nested.Field", "howdy");
Expect.equal("data->>'My'->>'Nested'->>'Field'", field.Path(Dialect.SQLite), Expect.equal("data->'My'->'Nested'->>'Field'", field.Path(Dialect.SQLite, FieldFormat.AsSql),
"The SQLite path is incorrect"); "The SQLite path is incorrect");
}), }),
TestCase("succeeds for a SQLite nested field with a qualifier", () => TestCase("succeeds for a SQLite nested field with a qualifier", () =>
{ {
var field = Field.EQ("Nest.Away", "doc").WithQualifier("bird"); var field = Field.Equal("Nest.Away", "doc").WithQualifier("bird");
Expect.equal("bird.data->>'Nest'->>'Away'", field.Path(Dialect.SQLite), "The SQLite path is incorrect"); Expect.equal("bird.data->'Nest'->>'Away'", field.Path(Dialect.SQLite, FieldFormat.AsSql),
"The SQLite path is incorrect");
}) })
]) ])
]); ]);
@ -529,7 +548,7 @@ public static class CommonCSharpTests
{ {
Expect.equal( Expect.equal(
Query.Definition.EnsureIndexOn("tbl", "nest", ["a.b.c"], Dialect.SQLite), Query.Definition.EnsureIndexOn("tbl", "nest", ["a.b.c"], Dialect.SQLite),
"CREATE INDEX IF NOT EXISTS idx_tbl_nest ON tbl ((data->>'a'->>'b'->>'c'))", "CREATE INDEX IF NOT EXISTS idx_tbl_nest ON tbl ((data->'a'->'b'->>'c'))",
"CREATE INDEX for nested SQLite field incorrect"); "CREATE INDEX for nested SQLite field incorrect");
}) })
]) ])
@ -601,7 +620,7 @@ public static class CommonCSharpTests
Field.Named("Nested.Test.Field DESC"), Field.Named("AnotherField"), Field.Named("Nested.Test.Field DESC"), Field.Named("AnotherField"),
Field.Named("It DESC") Field.Named("It DESC")
], Dialect.SQLite), ], Dialect.SQLite),
" ORDER BY data->>'Nested'->>'Test'->>'Field' DESC, data->>'AnotherField', data->>'It' DESC", " ORDER BY data->'Nested'->'Test'->>'Field' DESC, data->>'AnotherField', data->>'It' DESC",
"Order By not constructed correctly"); "Order By not constructed correctly");
}), }),
TestCase("succeeds for PostgreSQL numeric fields", () => TestCase("succeeds for PostgreSQL numeric fields", () =>
@ -623,7 +642,7 @@ public static class CommonCSharpTests
TestCase("succeeds for SQLite case-insensitive ordering", () => TestCase("succeeds for SQLite case-insensitive ordering", () =>
{ {
Expect.equal(Query.OrderBy([Field.Named("i:Test.Field ASC NULLS LAST")], Dialect.SQLite), Expect.equal(Query.OrderBy([Field.Named("i:Test.Field ASC NULLS LAST")], Dialect.SQLite),
" ORDER BY data->>'Test'->>'Field' COLLATE NOCASE ASC NULLS LAST", " ORDER BY data->'Test'->>'Field' COLLATE NOCASE ASC NULLS LAST",
"Order By not constructed correctly for case-insensitive field"); "Order By not constructed correctly for case-insensitive field");
}) })
]) ])

View File

@ -205,7 +205,7 @@ public class PostgresCSharpExtensionTests
} }
}) })
]), ]),
TestList("save", TestList("Save",
[ [
TestCase("succeeds when a document is inserted", async () => TestCase("succeeds when a document is inserted", async () =>
{ {
@ -253,7 +253,7 @@ public class PostgresCSharpExtensionTests
await LoadDocs(); await LoadDocs();
var theCount = await conn.CountByFields(PostgresDb.TableName, FieldMatch.Any, var theCount = await conn.CountByFields(PostgresDb.TableName, FieldMatch.Any,
[Field.EQ("Value", "purple")]); [Field.Equal("Value", "purple")]);
Expect.equal(theCount, 2, "There should have been 2 matching documents"); Expect.equal(theCount, 2, "There should have been 2 matching documents");
}), }),
TestCase("CountByContains succeeds", async () => TestCase("CountByContains succeeds", async () =>
@ -303,7 +303,7 @@ public class PostgresCSharpExtensionTests
await using var conn = MkConn(db); await using var conn = MkConn(db);
await LoadDocs(); await LoadDocs();
var exists = await conn.ExistsByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EX("Sub")]); var exists = await conn.ExistsByFields(PostgresDb.TableName, FieldMatch.Any, [Field.Exists("Sub")]);
Expect.isTrue(exists, "There should have been existing documents"); Expect.isTrue(exists, "There should have been existing documents");
}), }),
TestCase("succeeds when documents do not exist", async () => TestCase("succeeds when documents do not exist", async () =>
@ -313,7 +313,7 @@ public class PostgresCSharpExtensionTests
await LoadDocs(); await LoadDocs();
var exists = var exists =
await conn.ExistsByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", "six")]); await conn.ExistsByFields(PostgresDb.TableName, FieldMatch.Any, [Field.Equal("NumValue", "six")]);
Expect.isFalse(exists, "There should not have been existing documents"); Expect.isFalse(exists, "There should not have been existing documents");
}) })
]), ]),
@ -450,7 +450,7 @@ public class PostgresCSharpExtensionTests
await LoadDocs(); await LoadDocs();
var docs = await conn.FindByFields<JsonDocument>(PostgresDb.TableName, FieldMatch.Any, var docs = await conn.FindByFields<JsonDocument>(PostgresDb.TableName, FieldMatch.Any,
[Field.EQ("Value", "another")]); [Field.Equal("Value", "another")]);
Expect.equal(docs.Count, 1, "There should have been one document returned"); Expect.equal(docs.Count, 1, "There should have been one document returned");
}), }),
TestCase("succeeds when documents are not found", async () => TestCase("succeeds when documents are not found", async () =>
@ -460,7 +460,7 @@ public class PostgresCSharpExtensionTests
await LoadDocs(); await LoadDocs();
var docs = await conn.FindByFields<JsonDocument>(PostgresDb.TableName, FieldMatch.Any, var docs = await conn.FindByFields<JsonDocument>(PostgresDb.TableName, FieldMatch.Any,
[Field.EQ("Value", "mauve")]); [Field.Equal("Value", "mauve")]);
Expect.isEmpty(docs, "There should have been no documents returned"); Expect.isEmpty(docs, "There should have been no documents returned");
}) })
]), ]),
@ -473,7 +473,7 @@ public class PostgresCSharpExtensionTests
await LoadDocs(); await LoadDocs();
var docs = await conn.FindByFieldsOrdered<JsonDocument>(PostgresDb.TableName, FieldMatch.Any, var docs = await conn.FindByFieldsOrdered<JsonDocument>(PostgresDb.TableName, FieldMatch.Any,
[Field.EQ("Value", "purple")], [Field.Named("Id")]); [Field.Equal("Value", "purple")], [Field.Named("Id")]);
Expect.hasLength(docs, 2, "There should have been two document returned"); Expect.hasLength(docs, 2, "There should have been two document returned");
Expect.equal(string.Join('|', docs.Select(x => x.Id)), "five|four", Expect.equal(string.Join('|', docs.Select(x => x.Id)), "five|four",
"The documents were not ordered correctly"); "The documents were not ordered correctly");
@ -485,7 +485,7 @@ public class PostgresCSharpExtensionTests
await LoadDocs(); await LoadDocs();
var docs = await conn.FindByFieldsOrdered<JsonDocument>(PostgresDb.TableName, FieldMatch.Any, var docs = await conn.FindByFieldsOrdered<JsonDocument>(PostgresDb.TableName, FieldMatch.Any,
[Field.EQ("Value", "purple")], [Field.Named("Id DESC")]); [Field.Equal("Value", "purple")], [Field.Named("Id DESC")]);
Expect.hasLength(docs, 2, "There should have been two document returned"); Expect.hasLength(docs, 2, "There should have been two document returned");
Expect.equal(string.Join('|', docs.Select(x => x.Id)), "four|five", Expect.equal(string.Join('|', docs.Select(x => x.Id)), "four|five",
"The documents were not ordered correctly"); "The documents were not ordered correctly");
@ -599,7 +599,7 @@ public class PostgresCSharpExtensionTests
await LoadDocs(); await LoadDocs();
var doc = await conn.FindFirstByFields<JsonDocument>(PostgresDb.TableName, FieldMatch.Any, var doc = await conn.FindFirstByFields<JsonDocument>(PostgresDb.TableName, FieldMatch.Any,
[Field.EQ("Value", "another")]); [Field.Equal("Value", "another")]);
Expect.isNotNull(doc, "There should have been a document returned"); Expect.isNotNull(doc, "There should have been a document returned");
Expect.equal(doc.Id, "two", "The incorrect document was returned"); Expect.equal(doc.Id, "two", "The incorrect document was returned");
}), }),
@ -610,7 +610,7 @@ public class PostgresCSharpExtensionTests
await LoadDocs(); await LoadDocs();
var doc = await conn.FindFirstByFields<JsonDocument>(PostgresDb.TableName, FieldMatch.Any, var doc = await conn.FindFirstByFields<JsonDocument>(PostgresDb.TableName, FieldMatch.Any,
[Field.EQ("Value", "purple")]); [Field.Equal("Value", "purple")]);
Expect.isNotNull(doc, "There should have been a document returned"); Expect.isNotNull(doc, "There should have been a document returned");
Expect.contains(["five", "four"], doc.Id, "An incorrect document was returned"); Expect.contains(["five", "four"], doc.Id, "An incorrect document was returned");
}), }),
@ -621,7 +621,7 @@ public class PostgresCSharpExtensionTests
await LoadDocs(); await LoadDocs();
var doc = await conn.FindFirstByFields<JsonDocument>(PostgresDb.TableName, FieldMatch.Any, var doc = await conn.FindFirstByFields<JsonDocument>(PostgresDb.TableName, FieldMatch.Any,
[Field.EQ("Value", "absent")]); [Field.Equal("Value", "absent")]);
Expect.isNull(doc, "There should not have been a document returned"); Expect.isNull(doc, "There should not have been a document returned");
}) })
]), ]),
@ -634,7 +634,7 @@ public class PostgresCSharpExtensionTests
await LoadDocs(); await LoadDocs();
var doc = await conn.FindFirstByFieldsOrdered<JsonDocument>(PostgresDb.TableName, FieldMatch.Any, var doc = await conn.FindFirstByFieldsOrdered<JsonDocument>(PostgresDb.TableName, FieldMatch.Any,
[Field.EQ("Value", "purple")], [Field.Named("Id")]); [Field.Equal("Value", "purple")], [Field.Named("Id")]);
Expect.isNotNull(doc, "There should have been a document returned"); Expect.isNotNull(doc, "There should have been a document returned");
Expect.equal("five", doc.Id, "An incorrect document was returned"); Expect.equal("five", doc.Id, "An incorrect document was returned");
}), }),
@ -645,7 +645,7 @@ public class PostgresCSharpExtensionTests
await LoadDocs(); await LoadDocs();
var doc = await conn.FindFirstByFieldsOrdered<JsonDocument>(PostgresDb.TableName, FieldMatch.Any, var doc = await conn.FindFirstByFieldsOrdered<JsonDocument>(PostgresDb.TableName, FieldMatch.Any,
[Field.EQ("Value", "purple")], [Field.Named("Id DESC")]); [Field.Equal("Value", "purple")], [Field.Named("Id DESC")]);
Expect.isNotNull(doc, "There should have been a document returned"); Expect.isNotNull(doc, "There should have been a document returned");
Expect.equal("four", doc.Id, "An incorrect document was returned"); Expect.equal("four", doc.Id, "An incorrect document was returned");
}) })
@ -859,10 +859,10 @@ public class PostgresCSharpExtensionTests
await using var conn = MkConn(db); await using var conn = MkConn(db);
await LoadDocs(); await LoadDocs();
await conn.PatchByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("Value", "purple")], await conn.PatchByFields(PostgresDb.TableName, FieldMatch.Any, [Field.Equal("Value", "purple")],
new { NumValue = 77 }); new { NumValue = 77 });
var after = await conn.CountByFields(PostgresDb.TableName, FieldMatch.Any, var after = await conn.CountByFields(PostgresDb.TableName, FieldMatch.Any,
[Field.EQ("NumValue", "77")]); [Field.Equal("NumValue", 77)]);
Expect.equal(after, 2, "There should have been 2 documents returned"); Expect.equal(after, 2, "There should have been 2 documents returned");
}), }),
TestCase("succeeds when no document is updated", async () => TestCase("succeeds when no document is updated", async () =>
@ -873,7 +873,7 @@ public class PostgresCSharpExtensionTests
Expect.equal(before, 0, "There should have been no documents returned"); Expect.equal(before, 0, "There should have been no documents returned");
// This not raising an exception is the test // This not raising an exception is the test
await conn.PatchByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("Value", "burgundy")], await conn.PatchByFields(PostgresDb.TableName, FieldMatch.Any, [Field.Equal("Value", "burgundy")],
new { Foo = "green" }); new { Foo = "green" });
}) })
]), ]),
@ -975,7 +975,7 @@ public class PostgresCSharpExtensionTests
await using var conn = MkConn(db); await using var conn = MkConn(db);
await LoadDocs(); await LoadDocs();
await conn.RemoveFieldsByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", "17")], await conn.RemoveFieldsByFields(PostgresDb.TableName, FieldMatch.Any, [Field.Equal("NumValue", "17")],
["Sub", "Value"]); ["Sub", "Value"]);
var updated = await Find.ById<string, JsonDocument>(PostgresDb.TableName, "four"); var updated = await Find.ById<string, JsonDocument>(PostgresDb.TableName, "four");
Expect.isNotNull(updated, "The updated document should have been retrieved"); Expect.isNotNull(updated, "The updated document should have been retrieved");
@ -988,7 +988,7 @@ public class PostgresCSharpExtensionTests
await using var conn = MkConn(db); await using var conn = MkConn(db);
await LoadDocs(); await LoadDocs();
await conn.RemoveFieldsByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", "17")], await conn.RemoveFieldsByFields(PostgresDb.TableName, FieldMatch.Any, [Field.Equal("NumValue", "17")],
["Sub"]); ["Sub"]);
var updated = await Find.ById<string, JsonDocument>(PostgresDb.TableName, "four"); var updated = await Find.ById<string, JsonDocument>(PostgresDb.TableName, "four");
Expect.isNotNull(updated, "The updated document should have been retrieved"); Expect.isNotNull(updated, "The updated document should have been retrieved");
@ -1002,7 +1002,7 @@ public class PostgresCSharpExtensionTests
await LoadDocs(); await LoadDocs();
// This not raising an exception is the test // This not raising an exception is the test
await conn.RemoveFieldsByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", "17")], await conn.RemoveFieldsByFields(PostgresDb.TableName, FieldMatch.Any, [Field.Equal("NumValue", "17")],
["Nothing"]); ["Nothing"]);
}), }),
TestCase("succeeds when no document is matched", async () => TestCase("succeeds when no document is matched", async () =>
@ -1012,7 +1012,7 @@ public class PostgresCSharpExtensionTests
// This not raising an exception is the test // This not raising an exception is the test
await conn.RemoveFieldsByFields(PostgresDb.TableName, FieldMatch.Any, await conn.RemoveFieldsByFields(PostgresDb.TableName, FieldMatch.Any,
[Field.NE("Abracadabra", "apple")], ["Value"]); [Field.NotEqual("Abracadabra", "apple")], ["Value"]);
}) })
]), ]),
TestList("RemoveFieldsByContains", TestList("RemoveFieldsByContains",
@ -1134,7 +1134,7 @@ public class PostgresCSharpExtensionTests
await using var conn = MkConn(db); await using var conn = MkConn(db);
await LoadDocs(); await LoadDocs();
await conn.DeleteByFields(PostgresDb.TableName, FieldMatch.Any, [Field.NE("Value", "purple")]); await conn.DeleteByFields(PostgresDb.TableName, FieldMatch.Any, [Field.NotEqual("Value", "purple")]);
var remaining = await conn.CountAll(PostgresDb.TableName); var remaining = await conn.CountAll(PostgresDb.TableName);
Expect.equal(remaining, 2, "There should have been 2 documents remaining"); Expect.equal(remaining, 2, "There should have been 2 documents remaining");
}), }),
@ -1144,7 +1144,7 @@ public class PostgresCSharpExtensionTests
await using var conn = MkConn(db); await using var conn = MkConn(db);
await LoadDocs(); await LoadDocs();
await conn.DeleteByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("Value", "crimson")]); await conn.DeleteByFields(PostgresDb.TableName, FieldMatch.Any, [Field.Equal("Value", "crimson")]);
var remaining = await conn.CountAll(PostgresDb.TableName); var remaining = await conn.CountAll(PostgresDb.TableName);
Expect.equal(remaining, 5, "There should have been 5 documents remaining"); Expect.equal(remaining, 5, "There should have been 5 documents remaining");
}) })

View File

@ -111,7 +111,7 @@ public static class PostgresCSharpTests
[ [
TestCase("succeeds when a parameter is added", () => TestCase("succeeds when a parameter is added", () =>
{ {
var paramList = Parameters.AddFields([Field.EQ("it", "242")], []).ToList(); var paramList = Parameters.AddFields([Field.Equal("it", "242")], []).ToList();
Expect.hasLength(paramList, 1, "There should have been a parameter added"); Expect.hasLength(paramList, 1, "There should have been a parameter added");
var (name, value) = paramList[0]; var (name, value) = paramList[0];
Expect.equal(name, "@field0", "Field parameter name not correct"); Expect.equal(name, "@field0", "Field parameter name not correct");
@ -119,7 +119,7 @@ public static class PostgresCSharpTests
}), }),
TestCase("succeeds when multiple independent parameters are added", () => TestCase("succeeds when multiple independent parameters are added", () =>
{ {
var paramList = Parameters.AddFields([Field.EQ("me", "you"), Field.GT("us", "them")], var paramList = Parameters.AddFields([Field.Equal("me", "you"), Field.Greater("us", "them")],
[Parameters.Id(14)]).ToList(); [Parameters.Id(14)]).ToList();
Expect.hasLength(paramList, 3, "There should have been 2 parameters added"); Expect.hasLength(paramList, 3, "There should have been 2 parameters added");
var (name, value) = paramList[0]; var (name, value) = paramList[0];
@ -134,13 +134,13 @@ public static class PostgresCSharpTests
}), }),
TestCase("succeeds when a parameter is not added", () => TestCase("succeeds when a parameter is not added", () =>
{ {
var paramList = Parameters.AddFields([Field.EX("tacos")], []).ToList(); var paramList = Parameters.AddFields([Field.Exists("tacos")], []).ToList();
Expect.isEmpty(paramList, "There should not have been any parameters added"); Expect.isEmpty(paramList, "There should not have been any parameters added");
}), }),
TestCase("succeeds when two parameters are added for one field", () => TestCase("succeeds when two parameters are added for one field", () =>
{ {
var paramList = var paramList =
Parameters.AddFields([Field.BT("that", "eh", "zed").WithParameterName("@test")], []).ToList(); Parameters.AddFields([Field.Between("that", "eh", "zed").WithParameterName("@test")], []).ToList();
Expect.hasLength(paramList, 2, "There should have been 2 parameters added"); Expect.hasLength(paramList, 2, "There should have been 2 parameters added");
var (name, value) = paramList[0]; var (name, value) = paramList[0];
Expect.equal(name, "@testmin", "Minimum field name not correct"); Expect.equal(name, "@testmin", "Minimum field name not correct");
@ -184,54 +184,60 @@ public static class PostgresCSharpTests
[ [
TestList("WhereByFields", TestList("WhereByFields",
[ [
TestCase("succeeds for a single field when a logical operator is passed", () => TestCase("succeeds for a single field when a logical comparison is passed", () =>
{ {
Expect.equal( Expect.equal(
Postgres.Query.WhereByFields(FieldMatch.Any, Postgres.Query.WhereByFields(FieldMatch.Any,
[Field.GT("theField", "0").WithParameterName("@test")]), [Field.Greater("theField", "0").WithParameterName("@test")]),
"data->>'theField' > @test", "WHERE clause not correct"); "data->>'theField' > @test", "WHERE clause not correct");
}), }),
TestCase("succeeds for a single field when an existence operator is passed", () => TestCase("succeeds for a single field when an existence comparison is passed", () =>
{ {
Expect.equal(Postgres.Query.WhereByFields(FieldMatch.Any, [Field.NEX("thatField")]), Expect.equal(Postgres.Query.WhereByFields(FieldMatch.Any, [Field.NotExists("thatField")]),
"data->>'thatField' IS NULL", "WHERE clause not correct"); "data->>'thatField' IS NULL", "WHERE clause not correct");
}), }),
TestCase("succeeds for a single field when a between operator is passed with numeric values", () => TestCase("succeeds for a single field when a between comparison is passed with numeric values", () =>
{ {
Expect.equal( Expect.equal(
Postgres.Query.WhereByFields(FieldMatch.All, Postgres.Query.WhereByFields(FieldMatch.All,
[Field.BT("aField", 50, 99).WithParameterName("@range")]), [Field.Between("aField", 50, 99).WithParameterName("@range")]),
"(data->>'aField')::numeric BETWEEN @rangemin AND @rangemax", "WHERE clause not correct"); "(data->>'aField')::numeric BETWEEN @rangemin AND @rangemax", "WHERE clause not correct");
}), }),
TestCase("succeeds for a single field when a between operator is passed with non-numeric values", () => TestCase("succeeds for a single field when a between comparison is passed with non-numeric values", () =>
{ {
Expect.equal( Expect.equal(
Postgres.Query.WhereByFields(FieldMatch.Any, Postgres.Query.WhereByFields(FieldMatch.Any,
[Field.BT("field0", "a", "b").WithParameterName("@alpha")]), [Field.Between("field0", "a", "b").WithParameterName("@alpha")]),
"data->>'field0' BETWEEN @alphamin AND @alphamax", "WHERE clause not correct"); "data->>'field0' BETWEEN @alphamin AND @alphamax", "WHERE clause not correct");
}), }),
TestCase("succeeds for all multiple fields with logical operators", () => TestCase("succeeds for all multiple fields with logical comparisons", () =>
{ {
Expect.equal( Expect.equal(
Postgres.Query.WhereByFields(FieldMatch.All, Postgres.Query.WhereByFields(FieldMatch.All,
[Field.EQ("theFirst", "1"), Field.EQ("numberTwo", "2")]), [Field.Equal("theFirst", "1"), Field.Equal("numberTwo", "2")]),
"data->>'theFirst' = @field0 AND data->>'numberTwo' = @field1", "WHERE clause not correct"); "data->>'theFirst' = @field0 AND data->>'numberTwo' = @field1", "WHERE clause not correct");
}), }),
TestCase("succeeds for any multiple fields with an existence operator", () => TestCase("succeeds for any multiple fields with an existence comparison", () =>
{ {
Expect.equal( Expect.equal(
Postgres.Query.WhereByFields(FieldMatch.Any, Postgres.Query.WhereByFields(FieldMatch.Any,
[Field.NEX("thatField"), Field.GE("thisField", 18)]), [Field.NotExists("thatField"), Field.GreaterOrEqual("thisField", 18)]),
"data->>'thatField' IS NULL OR (data->>'thisField')::numeric >= @field0", "data->>'thatField' IS NULL OR (data->>'thisField')::numeric >= @field0",
"WHERE clause not correct"); "WHERE clause not correct");
}), }),
TestCase("succeeds for all multiple fields with between operators", () => TestCase("succeeds for all multiple fields with between comparisons", () =>
{ {
Expect.equal( Expect.equal(
Postgres.Query.WhereByFields(FieldMatch.All, Postgres.Query.WhereByFields(FieldMatch.All,
[Field.BT("aField", 50, 99), Field.BT("anotherField", "a", "b")]), [Field.Between("aField", 50, 99), Field.Between("anotherField", "a", "b")]),
"(data->>'aField')::numeric BETWEEN @field0min AND @field0max AND data->>'anotherField' BETWEEN @field1min AND @field1max", "(data->>'aField')::numeric BETWEEN @field0min AND @field0max AND data->>'anotherField' BETWEEN @field1min AND @field1max",
"WHERE clause not correct"); "WHERE clause not correct");
}),
TestCase("succeeds for a field with an InArray comparison", () =>
{
Expect.equal(
Postgres.Query.WhereByFields(FieldMatch.All, [Field.InArray("theField", "the_table", ["q", "r"])]),
"data->'theField' ?| @field0", "WHERE clause not correct");
}) })
]), ]),
TestList("WhereById", TestList("WhereById",
@ -299,7 +305,7 @@ public static class PostgresCSharpTests
}), }),
TestCase("ByFields succeeds", () => TestCase("ByFields succeeds", () =>
{ {
Expect.equal(Postgres.Query.ByFields("unit", FieldMatch.Any, [Field.GT("That", 14)]), Expect.equal(Postgres.Query.ByFields("unit", FieldMatch.Any, [Field.Greater("That", 14)]),
"unit WHERE (data->>'That')::numeric > @field0", "By-Field query not correct"); "unit WHERE (data->>'That')::numeric > @field0", "By-Field query not correct");
}), }),
TestCase("ByContains succeeds", () => TestCase("ByContains succeeds", () =>
@ -314,21 +320,12 @@ public static class PostgresCSharpTests
}) })
]); ]);
private static readonly List<JsonDocument> TestDocuments =
[
new() { Id = "one", Value = "FIRST!", NumValue = 0 },
new() { Id = "two", Value = "another", NumValue = 10, Sub = new() { Foo = "green", Bar = "blue" } },
new() { Id = "three", Value = "", NumValue = 4 },
new() { Id = "four", Value = "purple", NumValue = 17, Sub = new() { Foo = "green", Bar = "red" } },
new() { Id = "five", Value = "purple", NumValue = 18 }
];
/// <summary> /// <summary>
/// Add the test documents to the database /// Add the test documents to the database
/// </summary> /// </summary>
internal static async Task LoadDocs() internal static async Task LoadDocs()
{ {
foreach (var doc in TestDocuments) await Document.Insert(SqliteDb.TableName, doc); foreach (var doc in JsonDocument.TestDocuments) await Document.Insert(SqliteDb.TableName, doc);
} }
/// <summary> /// <summary>
@ -676,7 +673,7 @@ public static class PostgresCSharpTests
await LoadDocs(); await LoadDocs();
var theCount = await Count.ByFields(PostgresDb.TableName, FieldMatch.Any, var theCount = await Count.ByFields(PostgresDb.TableName, FieldMatch.Any,
[Field.BT("NumValue", 10, 20)]); [Field.Between("NumValue", 10, 20)]);
Expect.equal(theCount, 3, "There should have been 3 matching documents"); Expect.equal(theCount, 3, "There should have been 3 matching documents");
}), }),
TestCase("succeeds for non-numeric range", async () => TestCase("succeeds for non-numeric range", async () =>
@ -685,7 +682,7 @@ public static class PostgresCSharpTests
await LoadDocs(); await LoadDocs();
var theCount = await Count.ByFields(PostgresDb.TableName, FieldMatch.All, var theCount = await Count.ByFields(PostgresDb.TableName, FieldMatch.All,
[Field.BT("Value", "aardvark", "apple")]); [Field.Between("Value", "aardvark", "apple")]);
Expect.equal(theCount, 1, "There should have been 1 matching document"); Expect.equal(theCount, 1, "There should have been 1 matching document");
}) })
]), ]),
@ -738,7 +735,7 @@ public static class PostgresCSharpTests
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
var exists = await Exists.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.NEX("Sub")]); var exists = await Exists.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.NotExists("Sub")]);
Expect.isTrue(exists, "There should have been existing documents"); Expect.isTrue(exists, "There should have been existing documents");
}), }),
TestCase("succeeds when documents do not exist", async () => TestCase("succeeds when documents do not exist", async () =>
@ -746,7 +743,8 @@ public static class PostgresCSharpTests
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
var exists = await Exists.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", "six")]); var exists = await Exists.ByFields(PostgresDb.TableName, FieldMatch.Any,
[Field.Equal("NumValue", "six")]);
Expect.isFalse(exists, "There should not have been existing documents"); Expect.isFalse(exists, "There should not have been existing documents");
}) })
]), ]),
@ -878,7 +876,16 @@ public static class PostgresCSharpTests
await LoadDocs(); await LoadDocs();
var docs = await Find.ByFields<JsonDocument>(PostgresDb.TableName, FieldMatch.Any, var docs = await Find.ByFields<JsonDocument>(PostgresDb.TableName, FieldMatch.Any,
[Field.EQ("Value", "another")]); [Field.Equal("Value", "another")]);
Expect.hasLength(docs, 1, "There should have been one document returned");
}),
TestCase("succeeds when documents are found using IN with numeric field", async () =>
{
await using var db = PostgresDb.BuildDb();
await LoadDocs();
var docs = await Find.ByFields<JsonDocument>(PostgresDb.TableName, FieldMatch.All,
[Field.In("NumValue", [2, 4, 6, 8])]);
Expect.hasLength(docs, 1, "There should have been one document returned"); Expect.hasLength(docs, 1, "There should have been one document returned");
}), }),
TestCase("succeeds when documents are not found", async () => TestCase("succeeds when documents are not found", async () =>
@ -887,7 +894,27 @@ public static class PostgresCSharpTests
await LoadDocs(); await LoadDocs();
var docs = await Find.ByFields<JsonDocument>(PostgresDb.TableName, FieldMatch.Any, var docs = await Find.ByFields<JsonDocument>(PostgresDb.TableName, FieldMatch.Any,
[Field.EQ("Value", "mauve")]); [Field.Equal("Value", "mauve")]);
Expect.isEmpty(docs, "There should have been no documents returned");
}),
TestCase("succeeds for InArray when matching documents exist", async () =>
{
await using var db = PostgresDb.BuildDb();
await Definition.EnsureTable(PostgresDb.TableName);
foreach (var doc in ArrayDocument.TestDocuments) await Document.Insert(PostgresDb.TableName, doc);
var docs = await Find.ByFields<ArrayDocument>(PostgresDb.TableName, FieldMatch.All,
[Field.InArray("Values", PostgresDb.TableName, ["c"])]);
Expect.hasLength(docs, 2, "There should have been two document returned");
}),
TestCase("succeeds for InArray when no matching documents exist", async () =>
{
await using var db = PostgresDb.BuildDb();
await Definition.EnsureTable(PostgresDb.TableName);
foreach (var doc in ArrayDocument.TestDocuments) await Document.Insert(PostgresDb.TableName, doc);
var docs = await Find.ByFields<ArrayDocument>(PostgresDb.TableName, FieldMatch.All,
[Field.InArray("Values", PostgresDb.TableName, ["j"])]);
Expect.isEmpty(docs, "There should have been no documents returned"); Expect.isEmpty(docs, "There should have been no documents returned");
}) })
]), ]),
@ -899,7 +926,7 @@ public static class PostgresCSharpTests
await LoadDocs(); await LoadDocs();
var docs = await Find.ByFieldsOrdered<JsonDocument>(PostgresDb.TableName, FieldMatch.Any, var docs = await Find.ByFieldsOrdered<JsonDocument>(PostgresDb.TableName, FieldMatch.Any,
[Field.EQ("Value", "purple")], [Field.Named("Id")]); [Field.Equal("Value", "purple")], [Field.Named("Id")]);
Expect.hasLength(docs, 2, "There should have been two document returned"); Expect.hasLength(docs, 2, "There should have been two document returned");
Expect.equal(string.Join('|', docs.Select(x => x.Id)), "five|four", Expect.equal(string.Join('|', docs.Select(x => x.Id)), "five|four",
"The documents were not ordered correctly"); "The documents were not ordered correctly");
@ -910,7 +937,7 @@ public static class PostgresCSharpTests
await LoadDocs(); await LoadDocs();
var docs = await Find.ByFieldsOrdered<JsonDocument>(PostgresDb.TableName, FieldMatch.Any, var docs = await Find.ByFieldsOrdered<JsonDocument>(PostgresDb.TableName, FieldMatch.Any,
[Field.EQ("Value", "purple")], [Field.Named("Id DESC")]); [Field.Equal("Value", "purple")], [Field.Named("Id DESC")]);
Expect.hasLength(docs, 2, "There should have been two document returned"); Expect.hasLength(docs, 2, "There should have been two document returned");
Expect.equal(string.Join('|', docs.Select(x => x.Id)), "four|five", Expect.equal(string.Join('|', docs.Select(x => x.Id)), "four|five",
"The documents were not ordered correctly"); "The documents were not ordered correctly");
@ -1015,7 +1042,7 @@ public static class PostgresCSharpTests
await LoadDocs(); await LoadDocs();
var doc = await Find.FirstByFields<JsonDocument>(PostgresDb.TableName, FieldMatch.Any, var doc = await Find.FirstByFields<JsonDocument>(PostgresDb.TableName, FieldMatch.Any,
[Field.EQ("Value", "another")]); [Field.Equal("Value", "another")]);
Expect.isNotNull(doc, "There should have been a document returned"); Expect.isNotNull(doc, "There should have been a document returned");
Expect.equal(doc.Id, "two", "The incorrect document was returned"); Expect.equal(doc.Id, "two", "The incorrect document was returned");
}), }),
@ -1025,7 +1052,7 @@ public static class PostgresCSharpTests
await LoadDocs(); await LoadDocs();
var doc = await Find.FirstByFields<JsonDocument>(PostgresDb.TableName, FieldMatch.Any, var doc = await Find.FirstByFields<JsonDocument>(PostgresDb.TableName, FieldMatch.Any,
[Field.EQ("Value", "purple")]); [Field.Equal("Value", "purple")]);
Expect.isNotNull(doc, "There should have been a document returned"); Expect.isNotNull(doc, "There should have been a document returned");
Expect.contains(["five", "four"], doc.Id, "An incorrect document was returned"); Expect.contains(["five", "four"], doc.Id, "An incorrect document was returned");
}), }),
@ -1035,7 +1062,7 @@ public static class PostgresCSharpTests
await LoadDocs(); await LoadDocs();
var doc = await Find.FirstByFields<JsonDocument>(PostgresDb.TableName, FieldMatch.Any, var doc = await Find.FirstByFields<JsonDocument>(PostgresDb.TableName, FieldMatch.Any,
[Field.EQ("Value", "absent")]); [Field.Equal("Value", "absent")]);
Expect.isNull(doc, "There should not have been a document returned"); Expect.isNull(doc, "There should not have been a document returned");
}) })
]), ]),
@ -1047,7 +1074,7 @@ public static class PostgresCSharpTests
await LoadDocs(); await LoadDocs();
var doc = await Find.FirstByFieldsOrdered<JsonDocument>(PostgresDb.TableName, FieldMatch.Any, var doc = await Find.FirstByFieldsOrdered<JsonDocument>(PostgresDb.TableName, FieldMatch.Any,
[Field.EQ("Value", "purple")], [Field.Named("Id")]); [Field.Equal("Value", "purple")], [Field.Named("Id")]);
Expect.isNotNull(doc, "There should have been a document returned"); Expect.isNotNull(doc, "There should have been a document returned");
Expect.equal("five", doc.Id, "An incorrect document was returned"); Expect.equal("five", doc.Id, "An incorrect document was returned");
}), }),
@ -1057,7 +1084,7 @@ public static class PostgresCSharpTests
await LoadDocs(); await LoadDocs();
var doc = await Find.FirstByFieldsOrdered<JsonDocument>(PostgresDb.TableName, FieldMatch.Any, var doc = await Find.FirstByFieldsOrdered<JsonDocument>(PostgresDb.TableName, FieldMatch.Any,
[Field.EQ("Value", "purple")], [Field.Named("Id DESC")]); [Field.Equal("Value", "purple")], [Field.Named("Id DESC")]);
Expect.isNotNull(doc, "There should have been a document returned"); Expect.isNotNull(doc, "There should have been a document returned");
Expect.equal("four", doc.Id, "An incorrect document was returned"); Expect.equal("four", doc.Id, "An incorrect document was returned");
}) })
@ -1271,9 +1298,9 @@ public static class PostgresCSharpTests
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
await Patch.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("Value", "purple")], await Patch.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.Equal("Value", "purple")],
new { NumValue = 77 }); new { NumValue = 77 });
var after = await Count.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", "77")]); var after = await Count.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.Equal("NumValue", "77")]);
Expect.equal(after, 2, "There should have been 2 documents returned"); Expect.equal(after, 2, "There should have been 2 documents returned");
}), }),
TestCase("succeeds when no document is updated", async () => TestCase("succeeds when no document is updated", async () =>
@ -1284,7 +1311,7 @@ public static class PostgresCSharpTests
Expect.equal(before, 0, "There should have been no documents returned"); Expect.equal(before, 0, "There should have been no documents returned");
// This not raising an exception is the test // This not raising an exception is the test
await Patch.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("Value", "burgundy")], await Patch.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.Equal("Value", "burgundy")],
new { Foo = "green" }); new { Foo = "green" });
}) })
]), ]),
@ -1386,7 +1413,7 @@ public static class PostgresCSharpTests
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
await RemoveFields.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", "17")], await RemoveFields.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.Equal("NumValue", "17")],
["Sub", "Value"]); ["Sub", "Value"]);
var updated = await Find.ById<string, JsonDocument>(PostgresDb.TableName, "four"); var updated = await Find.ById<string, JsonDocument>(PostgresDb.TableName, "four");
Expect.isNotNull(updated, "The updated document should have been retrieved"); Expect.isNotNull(updated, "The updated document should have been retrieved");
@ -1398,7 +1425,7 @@ public static class PostgresCSharpTests
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
await RemoveFields.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", "17")], await RemoveFields.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.Equal("NumValue", "17")],
["Sub"]); ["Sub"]);
var updated = await Find.ById<string, JsonDocument>(PostgresDb.TableName, "four"); var updated = await Find.ById<string, JsonDocument>(PostgresDb.TableName, "four");
Expect.isNotNull(updated, "The updated document should have been retrieved"); Expect.isNotNull(updated, "The updated document should have been retrieved");
@ -1411,7 +1438,7 @@ public static class PostgresCSharpTests
await LoadDocs(); await LoadDocs();
// This not raising an exception is the test // This not raising an exception is the test
await RemoveFields.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", "17")], await RemoveFields.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.Equal("NumValue", "17")],
["Nothing"]); ["Nothing"]);
}), }),
TestCase("succeeds when no document is matched", async () => TestCase("succeeds when no document is matched", async () =>
@ -1419,8 +1446,8 @@ public static class PostgresCSharpTests
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
// This not raising an exception is the test // This not raising an exception is the test
await RemoveFields.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.NE("Abracadabra", "apple")], await RemoveFields.ByFields(PostgresDb.TableName, FieldMatch.Any,
["Value"]); [Field.NotEqual("Abracadabra", "apple")], ["Value"]);
}) })
]), ]),
TestList("ByContains", TestList("ByContains",
@ -1538,7 +1565,7 @@ public static class PostgresCSharpTests
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
await Delete.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("Value", "purple")]); await Delete.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.Equal("Value", "purple")]);
var remaining = await Count.All(PostgresDb.TableName); var remaining = await Count.All(PostgresDb.TableName);
Expect.equal(remaining, 3, "There should have been 3 documents remaining"); Expect.equal(remaining, 3, "There should have been 3 documents remaining");
}), }),
@ -1547,7 +1574,7 @@ public static class PostgresCSharpTests
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
await Delete.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("Value", "crimson")]); await Delete.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.Equal("Value", "crimson")]);
var remaining = await Count.All(PostgresDb.TableName); var remaining = await Count.All(PostgresDb.TableName);
Expect.equal(remaining, 5, "There should have been 5 documents remaining"); Expect.equal(remaining, 5, "There should have been 5 documents remaining");
}) })

View File

@ -1,4 +1,3 @@
using BitBadger.Documents.Postgres;
using Npgsql; using Npgsql;
using Npgsql.FSharp; using Npgsql.FSharp;
using ThrowawayDb.Postgres; using ThrowawayDb.Postgres;

View File

@ -221,7 +221,8 @@ public static class SqliteCSharpExtensionTests
await using var conn = Sqlite.Configuration.DbConn(); await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs(); await LoadDocs();
var theCount = await conn.CountByFields(SqliteDb.TableName, FieldMatch.Any, [Field.EQ("Value", "purple")]); var theCount = await conn.CountByFields(SqliteDb.TableName, FieldMatch.Any,
[Field.Equal("Value", "purple")]);
Expect.equal(theCount, 2L, "There should have been 2 matching documents"); Expect.equal(theCount, 2L, "There should have been 2 matching documents");
}), }),
TestList("ExistsById", TestList("ExistsById",
@ -253,7 +254,8 @@ public static class SqliteCSharpExtensionTests
await using var conn = Sqlite.Configuration.DbConn(); await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs(); await LoadDocs();
var exists = await conn.ExistsByFields(SqliteDb.TableName, FieldMatch.Any, [Field.GE("NumValue", 10)]); var exists = await conn.ExistsByFields(SqliteDb.TableName, FieldMatch.Any,
[Field.GreaterOrEqual("NumValue", 10)]);
Expect.isTrue(exists, "There should have been existing documents"); Expect.isTrue(exists, "There should have been existing documents");
}), }),
TestCase("succeeds when no matching documents exist", async () => TestCase("succeeds when no matching documents exist", async () =>
@ -263,7 +265,7 @@ public static class SqliteCSharpExtensionTests
await LoadDocs(); await LoadDocs();
var exists = var exists =
await conn.ExistsByFields(SqliteDb.TableName, FieldMatch.Any, [Field.EQ("Nothing", "none")]); await conn.ExistsByFields(SqliteDb.TableName, FieldMatch.Any, [Field.Equal("Nothing", "none")]);
Expect.isFalse(exists, "There should not have been any existing documents"); Expect.isFalse(exists, "There should not have been any existing documents");
}) })
]), ]),
@ -357,7 +359,7 @@ public static class SqliteCSharpExtensionTests
await LoadDocs(); await LoadDocs();
var docs = await conn.FindByFields<JsonDocument>(SqliteDb.TableName, FieldMatch.Any, var docs = await conn.FindByFields<JsonDocument>(SqliteDb.TableName, FieldMatch.Any,
[Field.GT("NumValue", 15)]); [Field.Greater("NumValue", 15)]);
Expect.equal(docs.Count, 2, "There should have been two documents returned"); Expect.equal(docs.Count, 2, "There should have been two documents returned");
}), }),
TestCase("succeeds when documents are not found", async () => TestCase("succeeds when documents are not found", async () =>
@ -367,7 +369,7 @@ public static class SqliteCSharpExtensionTests
await LoadDocs(); await LoadDocs();
var docs = await conn.FindByFields<JsonDocument>(SqliteDb.TableName, FieldMatch.Any, var docs = await conn.FindByFields<JsonDocument>(SqliteDb.TableName, FieldMatch.Any,
[Field.EQ("Value", "mauve")]); [Field.Equal("Value", "mauve")]);
Expect.isEmpty(docs, "There should have been no documents returned"); Expect.isEmpty(docs, "There should have been no documents returned");
}) })
]), ]),
@ -380,7 +382,7 @@ public static class SqliteCSharpExtensionTests
await LoadDocs(); await LoadDocs();
var docs = await conn.FindByFieldsOrdered<JsonDocument>(SqliteDb.TableName, FieldMatch.Any, var docs = await conn.FindByFieldsOrdered<JsonDocument>(SqliteDb.TableName, FieldMatch.Any,
[Field.GT("NumValue", 15)], [Field.Named("Id")]); [Field.Greater("NumValue", 15)], [Field.Named("Id")]);
Expect.equal(string.Join('|', docs.Select(x => x.Id)), "five|four", Expect.equal(string.Join('|', docs.Select(x => x.Id)), "five|four",
"There should have been two documents returned"); "There should have been two documents returned");
}), }),
@ -391,7 +393,7 @@ public static class SqliteCSharpExtensionTests
await LoadDocs(); await LoadDocs();
var docs = await conn.FindByFieldsOrdered<JsonDocument>(SqliteDb.TableName, FieldMatch.Any, var docs = await conn.FindByFieldsOrdered<JsonDocument>(SqliteDb.TableName, FieldMatch.Any,
[Field.GT("NumValue", 15)], [Field.Named("Id DESC")]); [Field.Greater("NumValue", 15)], [Field.Named("Id DESC")]);
Expect.equal(string.Join('|', docs.Select(x => x.Id)), "four|five", Expect.equal(string.Join('|', docs.Select(x => x.Id)), "four|five",
"There should have been two documents returned"); "There should have been two documents returned");
}) })
@ -405,7 +407,7 @@ public static class SqliteCSharpExtensionTests
await LoadDocs(); await LoadDocs();
var doc = await conn.FindFirstByFields<JsonDocument>(SqliteDb.TableName, FieldMatch.Any, var doc = await conn.FindFirstByFields<JsonDocument>(SqliteDb.TableName, FieldMatch.Any,
[Field.EQ("Value", "another")]); [Field.Equal("Value", "another")]);
Expect.isNotNull(doc, "There should have been a document returned"); Expect.isNotNull(doc, "There should have been a document returned");
Expect.equal(doc!.Id, "two", "The incorrect document was returned"); Expect.equal(doc!.Id, "two", "The incorrect document was returned");
}), }),
@ -416,7 +418,7 @@ public static class SqliteCSharpExtensionTests
await LoadDocs(); await LoadDocs();
var doc = await conn.FindFirstByFields<JsonDocument>(SqliteDb.TableName, FieldMatch.Any, var doc = await conn.FindFirstByFields<JsonDocument>(SqliteDb.TableName, FieldMatch.Any,
[Field.EQ("Sub.Foo", "green")]); [Field.Equal("Sub.Foo", "green")]);
Expect.isNotNull(doc, "There should have been a document returned"); Expect.isNotNull(doc, "There should have been a document returned");
Expect.contains(["two", "four"], doc!.Id, "An incorrect document was returned"); Expect.contains(["two", "four"], doc!.Id, "An incorrect document was returned");
}), }),
@ -427,7 +429,7 @@ public static class SqliteCSharpExtensionTests
await LoadDocs(); await LoadDocs();
var doc = await conn.FindFirstByFields<JsonDocument>(SqliteDb.TableName, FieldMatch.Any, var doc = await conn.FindFirstByFields<JsonDocument>(SqliteDb.TableName, FieldMatch.Any,
[Field.EQ("Value", "absent")]); [Field.Equal("Value", "absent")]);
Expect.isNull(doc, "There should not have been a document returned"); Expect.isNull(doc, "There should not have been a document returned");
}) })
]), ]),
@ -440,7 +442,7 @@ public static class SqliteCSharpExtensionTests
await LoadDocs(); await LoadDocs();
var doc = await conn.FindFirstByFieldsOrdered<JsonDocument>(SqliteDb.TableName, FieldMatch.Any, var doc = await conn.FindFirstByFieldsOrdered<JsonDocument>(SqliteDb.TableName, FieldMatch.Any,
[Field.EQ("Sub.Foo", "green")], [Field.Named("Sub.Bar")]); [Field.Equal("Sub.Foo", "green")], [Field.Named("Sub.Bar")]);
Expect.isNotNull(doc, "There should have been a document returned"); Expect.isNotNull(doc, "There should have been a document returned");
Expect.equal("two", doc!.Id, "An incorrect document was returned"); Expect.equal("two", doc!.Id, "An incorrect document was returned");
}), }),
@ -451,7 +453,7 @@ public static class SqliteCSharpExtensionTests
await LoadDocs(); await LoadDocs();
var doc = await conn.FindFirstByFieldsOrdered<JsonDocument>(SqliteDb.TableName, FieldMatch.Any, var doc = await conn.FindFirstByFieldsOrdered<JsonDocument>(SqliteDb.TableName, FieldMatch.Any,
[Field.EQ("Sub.Foo", "green")], [Field.Named("Sub.Bar DESC")]); [Field.Equal("Sub.Foo", "green")], [Field.Named("Sub.Bar DESC")]);
Expect.isNotNull(doc, "There should have been a document returned"); Expect.isNotNull(doc, "There should have been a document returned");
Expect.equal("four", doc!.Id, "An incorrect document was returned"); Expect.equal("four", doc!.Id, "An incorrect document was returned");
}) })
@ -547,9 +549,9 @@ public static class SqliteCSharpExtensionTests
await using var conn = Sqlite.Configuration.DbConn(); await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs(); await LoadDocs();
await conn.PatchByFields(SqliteDb.TableName, FieldMatch.Any, [Field.EQ("Value", "purple")], await conn.PatchByFields(SqliteDb.TableName, FieldMatch.Any, [Field.Equal("Value", "purple")],
new { NumValue = 77 }); new { NumValue = 77 });
var after = await conn.CountByFields(SqliteDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", 77)]); var after = await conn.CountByFields(SqliteDb.TableName, FieldMatch.Any, [Field.Equal("NumValue", 77)]);
Expect.equal(after, 2L, "There should have been 2 documents returned"); Expect.equal(after, 2L, "There should have been 2 documents returned");
}), }),
TestCase("succeeds when no document is updated", async () => TestCase("succeeds when no document is updated", async () =>
@ -560,7 +562,7 @@ public static class SqliteCSharpExtensionTests
Expect.isEmpty(before, "There should have been no documents returned"); Expect.isEmpty(before, "There should have been no documents returned");
// This not raising an exception is the test // This not raising an exception is the test
await conn.PatchByFields(SqliteDb.TableName, FieldMatch.Any, [Field.EQ("Value", "burgundy")], await conn.PatchByFields(SqliteDb.TableName, FieldMatch.Any, [Field.Equal("Value", "burgundy")],
new { Foo = "green" }); new { Foo = "green" });
}) })
]), ]),
@ -604,7 +606,7 @@ public static class SqliteCSharpExtensionTests
await using var conn = Sqlite.Configuration.DbConn(); await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs(); await LoadDocs();
await conn.RemoveFieldsByFields(SqliteDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", 17)], await conn.RemoveFieldsByFields(SqliteDb.TableName, FieldMatch.Any, [Field.Equal("NumValue", 17)],
["Sub"]); ["Sub"]);
var updated = await Find.ById<string, JsonDocument>(SqliteDb.TableName, "four"); var updated = await Find.ById<string, JsonDocument>(SqliteDb.TableName, "four");
Expect.isNotNull(updated, "The updated document should have been retrieved"); Expect.isNotNull(updated, "The updated document should have been retrieved");
@ -617,7 +619,7 @@ public static class SqliteCSharpExtensionTests
await LoadDocs(); await LoadDocs();
// This not raising an exception is the test // This not raising an exception is the test
await conn.RemoveFieldsByFields(SqliteDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", 17)], await conn.RemoveFieldsByFields(SqliteDb.TableName, FieldMatch.Any, [Field.Equal("NumValue", 17)],
["Nothing"]); ["Nothing"]);
}), }),
TestCase("succeeds when no document is matched", async () => TestCase("succeeds when no document is matched", async () =>
@ -626,8 +628,8 @@ public static class SqliteCSharpExtensionTests
await using var conn = Sqlite.Configuration.DbConn(); await using var conn = Sqlite.Configuration.DbConn();
// This not raising an exception is the test // This not raising an exception is the test
await conn.RemoveFieldsByFields(SqliteDb.TableName, FieldMatch.Any, [Field.NE("Abracadabra", "apple")], await conn.RemoveFieldsByFields(SqliteDb.TableName, FieldMatch.Any,
["Value"]); [Field.NotEqual("Abracadabra", "apple")], ["Value"]);
}) })
]), ]),
TestList("DeleteById", TestList("DeleteById",
@ -661,7 +663,7 @@ public static class SqliteCSharpExtensionTests
await using var conn = Sqlite.Configuration.DbConn(); await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs(); await LoadDocs();
await conn.DeleteByFields(SqliteDb.TableName, FieldMatch.Any, [Field.NE("Value", "purple")]); await conn.DeleteByFields(SqliteDb.TableName, FieldMatch.Any, [Field.NotEqual("Value", "purple")]);
var remaining = await conn.CountAll(SqliteDb.TableName); var remaining = await conn.CountAll(SqliteDb.TableName);
Expect.equal(remaining, 2L, "There should have been 2 documents remaining"); Expect.equal(remaining, 2L, "There should have been 2 documents remaining");
}), }),
@ -671,7 +673,7 @@ public static class SqliteCSharpExtensionTests
await using var conn = Sqlite.Configuration.DbConn(); await using var conn = Sqlite.Configuration.DbConn();
await LoadDocs(); await LoadDocs();
await conn.DeleteByFields(SqliteDb.TableName, FieldMatch.Any, [Field.EQ("Value", "crimson")]); await conn.DeleteByFields(SqliteDb.TableName, FieldMatch.Any, [Field.Equal("Value", "crimson")]);
var remaining = await conn.CountAll(SqliteDb.TableName); var remaining = await conn.CountAll(SqliteDb.TableName);
Expect.equal(remaining, 5L, "There should have been 5 documents remaining"); Expect.equal(remaining, 5L, "There should have been 5 documents remaining");
}) })

View File

@ -22,40 +22,55 @@ public static class SqliteCSharpTests
TestCase("succeeds for a single field when a logical operator is passed", () => TestCase("succeeds for a single field when a logical operator is passed", () =>
{ {
Expect.equal( Expect.equal(
Sqlite.Query.WhereByFields(FieldMatch.Any, [Field.GT("theField", 0).WithParameterName("@test")]), Sqlite.Query.WhereByFields(FieldMatch.Any,
[Field.Greater("theField", 0).WithParameterName("@test")]),
"data->>'theField' > @test", "WHERE clause not correct"); "data->>'theField' > @test", "WHERE clause not correct");
}), }),
TestCase("succeeds for a single field when an existence operator is passed", () => TestCase("succeeds for a single field when an existence operator is passed", () =>
{ {
Expect.equal(Sqlite.Query.WhereByFields(FieldMatch.Any, [Field.NEX("thatField")]), Expect.equal(Sqlite.Query.WhereByFields(FieldMatch.Any, [Field.NotExists("thatField")]),
"data->>'thatField' IS NULL", "WHERE clause not correct"); "data->>'thatField' IS NULL", "WHERE clause not correct");
}), }),
TestCase("succeeds for a single field when a between operator is passed", () => TestCase("succeeds for a single field when a between operator is passed", () =>
{ {
Expect.equal( Expect.equal(
Sqlite.Query.WhereByFields(FieldMatch.All, Sqlite.Query.WhereByFields(FieldMatch.All,
[Field.BT("aField", 50, 99).WithParameterName("@range")]), [Field.Between("aField", 50, 99).WithParameterName("@range")]),
"data->>'aField' BETWEEN @rangemin AND @rangemax", "WHERE clause not correct"); "data->>'aField' BETWEEN @rangemin AND @rangemax", "WHERE clause not correct");
}), }),
TestCase("succeeds for all multiple fields with logical operators", () => TestCase("succeeds for all multiple fields with logical operators", () =>
{ {
Expect.equal( Expect.equal(
Sqlite.Query.WhereByFields(FieldMatch.All, [Field.EQ("theFirst", "1"), Field.EQ("numberTwo", "2")]), Sqlite.Query.WhereByFields(FieldMatch.All,
[Field.Equal("theFirst", "1"), Field.Equal("numberTwo", "2")]),
"data->>'theFirst' = @field0 AND data->>'numberTwo' = @field1", "WHERE clause not correct"); "data->>'theFirst' = @field0 AND data->>'numberTwo' = @field1", "WHERE clause not correct");
}), }),
TestCase("succeeds for any multiple fields with an existence operator", () => TestCase("succeeds for any multiple fields with an existence operator", () =>
{ {
Expect.equal( Expect.equal(
Sqlite.Query.WhereByFields(FieldMatch.Any, [Field.NEX("thatField"), Field.GE("thisField", 18)]), Sqlite.Query.WhereByFields(FieldMatch.Any,
[Field.NotExists("thatField"), Field.GreaterOrEqual("thisField", 18)]),
"data->>'thatField' IS NULL OR data->>'thisField' >= @field0", "WHERE clause not correct"); "data->>'thatField' IS NULL OR data->>'thisField' >= @field0", "WHERE clause not correct");
}), }),
TestCase("succeeds for all multiple fields with between operators", () => TestCase("succeeds for all multiple fields with between operators", () =>
{ {
Expect.equal( Expect.equal(
Sqlite.Query.WhereByFields(FieldMatch.All, Sqlite.Query.WhereByFields(FieldMatch.All,
[Field.BT("aField", 50, 99), Field.BT("anotherField", "a", "b")]), [Field.Between("aField", 50, 99), Field.Between("anotherField", "a", "b")]),
"data->>'aField' BETWEEN @field0min AND @field0max AND data->>'anotherField' BETWEEN @field1min AND @field1max", "data->>'aField' BETWEEN @field0min AND @field0max AND data->>'anotherField' BETWEEN @field1min AND @field1max",
"WHERE clause not correct"); "WHERE clause not correct");
}),
TestCase("succeeds for a field with an In comparison", () =>
{
Expect.equal(Sqlite.Query.WhereByFields(FieldMatch.All, [Field.In("this", ["a", "b", "c"])]),
"data->>'this' IN (@field0_0, @field0_1, @field0_2)", "WHERE clause not correct");
}),
TestCase("succeeds for a field with an InArray comparison", () =>
{
Expect.equal(
Sqlite.Query.WhereByFields(FieldMatch.All, [Field.InArray("this", "the_table", ["a", "b"])]),
"EXISTS (SELECT 1 FROM json_each(the_table.data, '$.this') WHERE value IN (@field0_0, @field0_1))",
"WHERE clause not correct");
}) })
]), ]),
TestCase("WhereById succeeds", () => TestCase("WhereById succeeds", () =>
@ -79,7 +94,7 @@ public static class SqliteCSharpTests
}), }),
TestCase("ByFields succeeds", () => TestCase("ByFields succeeds", () =>
{ {
Expect.equal(Sqlite.Query.ByFields("unit", FieldMatch.Any, [Field.GT("That", 14)]), Expect.equal(Sqlite.Query.ByFields("unit", FieldMatch.Any, [Field.Greater("That", 14)]),
"unit WHERE data->>'That' > @field0", "By-Field query not correct"); "unit WHERE data->>'That' > @field0", "By-Field query not correct");
}), }),
TestCase("Definition.EnsureTable succeeds", () => TestCase("Definition.EnsureTable succeeds", () =>
@ -109,7 +124,7 @@ public static class SqliteCSharpTests
#pragma warning disable CS0618 #pragma warning disable CS0618
TestCase("AddField succeeds when adding a parameter", () => TestCase("AddField succeeds when adding a parameter", () =>
{ {
var paramList = Parameters.AddField("@field", Field.EQ("it", 99), []).ToList(); var paramList = Parameters.AddField("@field", Field.Equal("it", 99), []).ToList();
Expect.hasLength(paramList, 1, "There should have been a parameter added"); Expect.hasLength(paramList, 1, "There should have been a parameter added");
var theParam = paramList[0]; var theParam = paramList[0];
Expect.equal(theParam.ParameterName, "@field", "The parameter name is incorrect"); Expect.equal(theParam.ParameterName, "@field", "The parameter name is incorrect");
@ -117,7 +132,7 @@ public static class SqliteCSharpTests
}), }),
TestCase("AddField succeeds when not adding a parameter", () => TestCase("AddField succeeds when not adding a parameter", () =>
{ {
var paramSeq = Parameters.AddField("@it", Field.EX("Coffee"), []); var paramSeq = Parameters.AddField("@it", Field.Exists("Coffee"), []);
Expect.isEmpty(paramSeq, "There should not have been any parameters added"); Expect.isEmpty(paramSeq, "There should not have been any parameters added");
}), }),
#pragma warning restore CS0618 #pragma warning restore CS0618
@ -129,24 +144,12 @@ public static class SqliteCSharpTests
// Results are exhaustively executed in the context of other tests // Results are exhaustively executed in the context of other tests
/// <summary>
/// Documents used for integration tests
/// </summary>
private static readonly List<JsonDocument> TestDocuments =
[
new() { Id = "one", Value = "FIRST!", NumValue = 0 },
new() { Id = "two", Value = "another", NumValue = 10, Sub = new() { Foo = "green", Bar = "blue" } },
new() { Id = "three", Value = "", NumValue = 4 },
new() { Id = "four", Value = "purple", NumValue = 17, Sub = new() { Foo = "green", Bar = "red" } },
new() { Id = "five", Value = "purple", NumValue = 18 }
];
/// <summary> /// <summary>
/// Add the test documents to the database /// Add the test documents to the database
/// </summary> /// </summary>
internal static async Task LoadDocs() internal static async Task LoadDocs()
{ {
foreach (var doc in TestDocuments) await Document.Insert(SqliteDb.TableName, doc); foreach (var doc in JsonDocument.TestDocuments) await Document.Insert(SqliteDb.TableName, doc);
} }
/// <summary> /// <summary>
@ -459,7 +462,8 @@ public static class SqliteCSharpTests
await using var db = await SqliteDb.BuildDb(); await using var db = await SqliteDb.BuildDb();
await LoadDocs(); await LoadDocs();
var theCount = await Count.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.BT("NumValue", 10, 20)]); var theCount = await Count.ByFields(SqliteDb.TableName, FieldMatch.Any,
[Field.Between("NumValue", 10, 20)]);
Expect.equal(theCount, 3L, "There should have been 3 matching documents"); Expect.equal(theCount, 3L, "There should have been 3 matching documents");
}), }),
TestCase("succeeds for non-numeric range", async () => TestCase("succeeds for non-numeric range", async () =>
@ -468,7 +472,7 @@ public static class SqliteCSharpTests
await LoadDocs(); await LoadDocs();
var theCount = await Count.ByFields(SqliteDb.TableName, FieldMatch.Any, var theCount = await Count.ByFields(SqliteDb.TableName, FieldMatch.Any,
[Field.BT("Value", "aardvark", "apple")]); [Field.Between("Value", "aardvark", "apple")]);
Expect.equal(theCount, 1L, "There should have been 1 matching document"); Expect.equal(theCount, 1L, "There should have been 1 matching document");
}) })
]) ])
@ -505,7 +509,8 @@ public static class SqliteCSharpTests
await using var db = await SqliteDb.BuildDb(); await using var db = await SqliteDb.BuildDb();
await LoadDocs(); await LoadDocs();
var exists = await Exists.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.GE("NumValue", 10)]); var exists = await Exists.ByFields(SqliteDb.TableName, FieldMatch.Any,
[Field.GreaterOrEqual("NumValue", 10)]);
Expect.isTrue(exists, "There should have been existing documents"); Expect.isTrue(exists, "There should have been existing documents");
}), }),
TestCase("succeeds when no matching documents exist", async () => TestCase("succeeds when no matching documents exist", async () =>
@ -513,7 +518,8 @@ public static class SqliteCSharpTests
await using var db = await SqliteDb.BuildDb(); await using var db = await SqliteDb.BuildDb();
await LoadDocs(); await LoadDocs();
var exists = await Exists.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.EQ("Nothing", "none")]); var exists = await Exists.ByFields(SqliteDb.TableName, FieldMatch.Any,
[Field.Equal("Nothing", "none")]);
Expect.isFalse(exists, "There should not have been any existing documents"); Expect.isFalse(exists, "There should not have been any existing documents");
}) })
]) ])
@ -605,16 +611,45 @@ public static class SqliteCSharpTests
await LoadDocs(); await LoadDocs();
var docs = await Find.ByFields<JsonDocument>(SqliteDb.TableName, FieldMatch.Any, var docs = await Find.ByFields<JsonDocument>(SqliteDb.TableName, FieldMatch.Any,
[Field.GT("NumValue", 15)]); [Field.Greater("NumValue", 15)]);
Expect.equal(docs.Count, 2, "There should have been two documents returned"); Expect.equal(docs.Count, 2, "There should have been two documents returned");
}), }),
TestCase("succeeds when documents are found using IN with numeric field", async () =>
{
await using var db = await SqliteDb.BuildDb();
await LoadDocs();
var docs = await Find.ByFields<JsonDocument>(SqliteDb.TableName, FieldMatch.All,
[Field.In("NumValue", [2, 4, 6, 8])]);
Expect.hasLength(docs, 1, "There should have been one document returned");
}),
TestCase("succeeds when documents are not found", async () => TestCase("succeeds when documents are not found", async () =>
{ {
await using var db = await SqliteDb.BuildDb(); await using var db = await SqliteDb.BuildDb();
await LoadDocs(); await LoadDocs();
var docs = await Find.ByFields<JsonDocument>(SqliteDb.TableName, FieldMatch.Any, var docs = await Find.ByFields<JsonDocument>(SqliteDb.TableName, FieldMatch.Any,
[Field.EQ("Value", "mauve")]); [Field.Equal("Value", "mauve")]);
Expect.isEmpty(docs, "There should have been no documents returned");
}),
TestCase("succeeds for InArray when matching documents exist", async () =>
{
await using var db = await SqliteDb.BuildDb();
await Definition.EnsureTable(SqliteDb.TableName);
foreach (var doc in ArrayDocument.TestDocuments) await Document.Insert(SqliteDb.TableName, doc);
var docs = await Find.ByFields<ArrayDocument>(SqliteDb.TableName, FieldMatch.All,
[Field.InArray("Values", SqliteDb.TableName, ["c"])]);
Expect.hasLength(docs, 2, "There should have been two document returned");
}),
TestCase("succeeds for InArray when no matching documents exist", async () =>
{
await using var db = await SqliteDb.BuildDb();
await Definition.EnsureTable(SqliteDb.TableName);
foreach (var doc in ArrayDocument.TestDocuments) await Document.Insert(SqliteDb.TableName, doc);
var docs = await Find.ByFields<ArrayDocument>(SqliteDb.TableName, FieldMatch.All,
[Field.InArray("Values", SqliteDb.TableName, ["j"])]);
Expect.isEmpty(docs, "There should have been no documents returned"); Expect.isEmpty(docs, "There should have been no documents returned");
}) })
]), ]),
@ -626,7 +661,7 @@ public static class SqliteCSharpTests
await LoadDocs(); await LoadDocs();
var docs = await Find.ByFieldsOrdered<JsonDocument>(SqliteDb.TableName, FieldMatch.Any, var docs = await Find.ByFieldsOrdered<JsonDocument>(SqliteDb.TableName, FieldMatch.Any,
[Field.GT("NumValue", 15)], [Field.Named("Id")]); [Field.Greater("NumValue", 15)], [Field.Named("Id")]);
Expect.hasLength(docs, 2, "There should have been two documents returned"); Expect.hasLength(docs, 2, "There should have been two documents returned");
Expect.equal(string.Join('|', docs.Select(x => x.Id)), "five|four", Expect.equal(string.Join('|', docs.Select(x => x.Id)), "five|four",
"The documents were not sorted correctly"); "The documents were not sorted correctly");
@ -637,7 +672,7 @@ public static class SqliteCSharpTests
await LoadDocs(); await LoadDocs();
var docs = await Find.ByFieldsOrdered<JsonDocument>(SqliteDb.TableName, FieldMatch.Any, var docs = await Find.ByFieldsOrdered<JsonDocument>(SqliteDb.TableName, FieldMatch.Any,
[Field.GT("NumValue", 15)], [Field.Named("Id DESC")]); [Field.Greater("NumValue", 15)], [Field.Named("Id DESC")]);
Expect.hasLength(docs, 2, "There should have been two documents returned"); Expect.hasLength(docs, 2, "There should have been two documents returned");
Expect.equal(string.Join('|', docs.Select(x => x.Id)), "four|five", Expect.equal(string.Join('|', docs.Select(x => x.Id)), "four|five",
"The documents were not sorted correctly"); "The documents were not sorted correctly");
@ -648,7 +683,7 @@ public static class SqliteCSharpTests
await LoadDocs(); await LoadDocs();
var docs = await Find.ByFieldsOrdered<JsonDocument>(SqliteDb.TableName, FieldMatch.Any, var docs = await Find.ByFieldsOrdered<JsonDocument>(SqliteDb.TableName, FieldMatch.Any,
[Field.LE("NumValue", 10)], [Field.Named("Value")]); [Field.LessOrEqual("NumValue", 10)], [Field.Named("Value")]);
Expect.hasLength(docs, 3, "There should have been three documents returned"); Expect.hasLength(docs, 3, "There should have been three documents returned");
Expect.equal(string.Join('|', docs.Select(x => x.Id)), "three|one|two", Expect.equal(string.Join('|', docs.Select(x => x.Id)), "three|one|two",
"The documents were not sorted correctly"); "The documents were not sorted correctly");
@ -659,7 +694,7 @@ public static class SqliteCSharpTests
await LoadDocs(); await LoadDocs();
var docs = await Find.ByFieldsOrdered<JsonDocument>(SqliteDb.TableName, FieldMatch.Any, var docs = await Find.ByFieldsOrdered<JsonDocument>(SqliteDb.TableName, FieldMatch.Any,
[Field.LE("NumValue", 10)], [Field.Named("i:Value")]); [Field.LessOrEqual("NumValue", 10)], [Field.Named("i:Value")]);
Expect.hasLength(docs, 3, "There should have been three documents returned"); Expect.hasLength(docs, 3, "There should have been three documents returned");
Expect.equal(string.Join('|', docs.Select(x => x.Id)), "three|two|one", Expect.equal(string.Join('|', docs.Select(x => x.Id)), "three|two|one",
"The documents were not sorted correctly"); "The documents were not sorted correctly");
@ -673,7 +708,7 @@ public static class SqliteCSharpTests
await LoadDocs(); await LoadDocs();
var doc = await Find.FirstByFields<JsonDocument>(SqliteDb.TableName, FieldMatch.Any, var doc = await Find.FirstByFields<JsonDocument>(SqliteDb.TableName, FieldMatch.Any,
[Field.EQ("Value", "another")]); [Field.Equal("Value", "another")]);
Expect.isNotNull(doc, "There should have been a document returned"); Expect.isNotNull(doc, "There should have been a document returned");
Expect.equal(doc!.Id, "two", "The incorrect document was returned"); Expect.equal(doc!.Id, "two", "The incorrect document was returned");
}), }),
@ -683,7 +718,7 @@ public static class SqliteCSharpTests
await LoadDocs(); await LoadDocs();
var doc = await Find.FirstByFields<JsonDocument>(SqliteDb.TableName, FieldMatch.Any, var doc = await Find.FirstByFields<JsonDocument>(SqliteDb.TableName, FieldMatch.Any,
[Field.EQ("Sub.Foo", "green")]); [Field.Equal("Sub.Foo", "green")]);
Expect.isNotNull(doc, "There should have been a document returned"); Expect.isNotNull(doc, "There should have been a document returned");
Expect.contains(["two", "four"], doc!.Id, "An incorrect document was returned"); Expect.contains(["two", "four"], doc!.Id, "An incorrect document was returned");
}), }),
@ -693,7 +728,7 @@ public static class SqliteCSharpTests
await LoadDocs(); await LoadDocs();
var doc = await Find.FirstByFields<JsonDocument>(SqliteDb.TableName, FieldMatch.Any, var doc = await Find.FirstByFields<JsonDocument>(SqliteDb.TableName, FieldMatch.Any,
[Field.EQ("Value", "absent")]); [Field.Equal("Value", "absent")]);
Expect.isNull(doc, "There should not have been a document returned"); Expect.isNull(doc, "There should not have been a document returned");
}) })
]), ]),
@ -705,7 +740,7 @@ public static class SqliteCSharpTests
await LoadDocs(); await LoadDocs();
var doc = await Find.FirstByFieldsOrdered<JsonDocument>(SqliteDb.TableName, FieldMatch.Any, var doc = await Find.FirstByFieldsOrdered<JsonDocument>(SqliteDb.TableName, FieldMatch.Any,
[Field.EQ("Sub.Foo", "green")], [Field.Named("Sub.Bar")]); [Field.Equal("Sub.Foo", "green")], [Field.Named("Sub.Bar")]);
Expect.isNotNull(doc, "There should have been a document returned"); Expect.isNotNull(doc, "There should have been a document returned");
Expect.equal("two", doc!.Id, "An incorrect document was returned"); Expect.equal("two", doc!.Id, "An incorrect document was returned");
}), }),
@ -715,7 +750,7 @@ public static class SqliteCSharpTests
await LoadDocs(); await LoadDocs();
var doc = await Find.FirstByFieldsOrdered<JsonDocument>(SqliteDb.TableName, FieldMatch.Any, var doc = await Find.FirstByFieldsOrdered<JsonDocument>(SqliteDb.TableName, FieldMatch.Any,
[Field.EQ("Sub.Foo", "green")], [Field.Named("Sub.Bar DESC")]); [Field.Equal("Sub.Foo", "green")], [Field.Named("Sub.Bar DESC")]);
Expect.isNotNull(doc, "There should have been a document returned"); Expect.isNotNull(doc, "There should have been a document returned");
Expect.equal("four", doc!.Id, "An incorrect document was returned"); Expect.equal("four", doc!.Id, "An incorrect document was returned");
}) })
@ -821,9 +856,9 @@ public static class SqliteCSharpTests
await using var db = await SqliteDb.BuildDb(); await using var db = await SqliteDb.BuildDb();
await LoadDocs(); await LoadDocs();
await Patch.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.EQ("Value", "purple")], await Patch.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.Equal("Value", "purple")],
new { NumValue = 77 }); new { NumValue = 77 });
var after = await Count.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", 77)]); var after = await Count.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.Equal("NumValue", 77)]);
Expect.equal(after, 2L, "There should have been 2 documents returned"); Expect.equal(after, 2L, "There should have been 2 documents returned");
}), }),
TestCase("succeeds when no document is updated", async () => TestCase("succeeds when no document is updated", async () =>
@ -834,7 +869,7 @@ public static class SqliteCSharpTests
Expect.isEmpty(before, "There should have been no documents returned"); Expect.isEmpty(before, "There should have been no documents returned");
// This not raising an exception is the test // This not raising an exception is the test
await Patch.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.EQ("Value", "burgundy")], await Patch.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.Equal("Value", "burgundy")],
new { Foo = "green" }); new { Foo = "green" });
}) })
]) ])
@ -881,7 +916,7 @@ public static class SqliteCSharpTests
await using var db = await SqliteDb.BuildDb(); await using var db = await SqliteDb.BuildDb();
await LoadDocs(); await LoadDocs();
await RemoveFields.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", 17)], ["Sub"]); await RemoveFields.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.Equal("NumValue", 17)], ["Sub"]);
var updated = await Find.ById<string, JsonDocument>(SqliteDb.TableName, "four"); var updated = await Find.ById<string, JsonDocument>(SqliteDb.TableName, "four");
Expect.isNotNull(updated, "The updated document should have been retrieved"); Expect.isNotNull(updated, "The updated document should have been retrieved");
Expect.isNull(updated.Sub, "The sub-document should have been removed"); Expect.isNull(updated.Sub, "The sub-document should have been removed");
@ -892,7 +927,7 @@ public static class SqliteCSharpTests
await LoadDocs(); await LoadDocs();
// This not raising an exception is the test // This not raising an exception is the test
await RemoveFields.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", 17)], await RemoveFields.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.Equal("NumValue", 17)],
["Nothing"]); ["Nothing"]);
}), }),
TestCase("succeeds when no document is matched", async () => TestCase("succeeds when no document is matched", async () =>
@ -900,8 +935,8 @@ public static class SqliteCSharpTests
await using var db = await SqliteDb.BuildDb(); await using var db = await SqliteDb.BuildDb();
// This not raising an exception is the test // This not raising an exception is the test
await RemoveFields.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.NE("Abracadabra", "apple")], await RemoveFields.ByFields(SqliteDb.TableName, FieldMatch.Any,
["Value"]); [Field.NotEqual("Abracadabra", "apple")], ["Value"]);
}) })
]) ])
]); ]);
@ -939,7 +974,7 @@ public static class SqliteCSharpTests
await using var db = await SqliteDb.BuildDb(); await using var db = await SqliteDb.BuildDb();
await LoadDocs(); await LoadDocs();
await Delete.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.NE("Value", "purple")]); await Delete.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.NotEqual("Value", "purple")]);
var remaining = await Count.All(SqliteDb.TableName); var remaining = await Count.All(SqliteDb.TableName);
Expect.equal(remaining, 2L, "There should have been 2 documents remaining"); Expect.equal(remaining, 2L, "There should have been 2 documents remaining");
}), }),
@ -948,7 +983,7 @@ public static class SqliteCSharpTests
await using var db = await SqliteDb.BuildDb(); await using var db = await SqliteDb.BuildDb();
await LoadDocs(); await LoadDocs();
await Delete.ByFields(SqliteDb.TableName, FieldMatch.All, [Field.EQ("Value", "crimson")]); await Delete.ByFields(SqliteDb.TableName, FieldMatch.All, [Field.Equal("Value", "crimson")]);
var remaining = await Count.All(SqliteDb.TableName); var remaining = await Count.All(SqliteDb.TableName);
Expect.equal(remaining, 5L, "There should have been 5 documents remaining"); Expect.equal(remaining, 5L, "There should have been 5 documents remaining");
}) })

View File

@ -18,4 +18,32 @@ public class JsonDocument
public string Value { get; set; } = ""; public string Value { get; set; } = "";
public int NumValue { get; set; } = 0; public int NumValue { get; set; } = 0;
public SubDocument? Sub { get; set; } = null; public SubDocument? Sub { get; set; } = null;
/// <summary>
/// A set of documents used for integration tests
/// </summary>
public static readonly List<JsonDocument> TestDocuments =
[
new() { Id = "one", Value = "FIRST!", NumValue = 0 },
new() { Id = "two", Value = "another", NumValue = 10, Sub = new() { Foo = "green", Bar = "blue" } },
new() { Id = "three", Value = "", NumValue = 4 },
new() { Id = "four", Value = "purple", NumValue = 17, Sub = new() { Foo = "green", Bar = "red" } },
new() { Id = "five", Value = "purple", NumValue = 18 }
];
}
public class ArrayDocument
{
public string Id { get; set; } = "";
public string[] Values { get; set; } = [];
/// <summary>
/// A set of documents used for integration tests
/// </summary>
public static readonly List<ArrayDocument> TestDocuments =
[
new() { Id = "first", Values = ["a", "b", "c"] },
new() { Id = "second", Values = ["c", "d", "e"] },
new() { Id = "third", Values = ["x", "y", "z"] }
];
} }

View File

@ -7,170 +7,183 @@ open Expecto
let tbl = "test_table" let tbl = "test_table"
/// Unit tests for the Op DU /// Unit tests for the Op DU
let opTests = testList "Op" [ let comparisonTests = testList "Comparison.OpSql" [
test "EQ succeeds" { test "Equal succeeds" {
Expect.equal (string EQ) "=" "The equals operator was not correct" Expect.equal (Equal "").OpSql "=" "The Equals SQL was not correct"
} }
test "GT succeeds" { test "Greater succeeds" {
Expect.equal (string GT) ">" "The greater than operator was not correct" Expect.equal (Greater "").OpSql ">" "The Greater SQL was not correct"
} }
test "GE succeeds" { test "GreaterOrEqual succeeds" {
Expect.equal (string GE) ">=" "The greater than or equal to operator was not correct" Expect.equal (GreaterOrEqual "").OpSql ">=" "The GreaterOrEqual SQL was not correct"
} }
test "LT succeeds" { test "Less succeeds" {
Expect.equal (string LT) "<" "The less than operator was not correct" Expect.equal (Less "").OpSql "<" "The Less SQL was not correct"
} }
test "LE succeeds" { test "LessOrEqual succeeds" {
Expect.equal (string LE) "<=" "The less than or equal to operator was not correct" Expect.equal (LessOrEqual "").OpSql "<=" "The LessOrEqual SQL was not correct"
} }
test "NE succeeds" { test "NotEqual succeeds" {
Expect.equal (string NE) "<>" "The not equal to operator was not correct" Expect.equal (NotEqual "").OpSql "<>" "The NotEqual SQL was not correct"
} }
test "BT succeeds" { test "Between succeeds" {
Expect.equal (string BT) "BETWEEN" """The "between" operator was not correct""" Expect.equal (Between("", "")).OpSql "BETWEEN" "The Between SQL was not correct"
} }
test "EX succeeds" { test "In succeeds" {
Expect.equal (string EX) "IS NOT NULL" """The "exists" operator was not correct""" Expect.equal (In []).OpSql "IN" "The In SQL was not correct"
} }
test "NEX succeeds" { test "InArray succeeds" {
Expect.equal (string NEX) "IS NULL" """The "not exists" operator was not correct""" Expect.equal (InArray("", [])).OpSql "?|" "The InArray SQL was not correct"
}
test "Exists succeeds" {
Expect.equal Exists.OpSql "IS NOT NULL" "The Exists SQL was not correct"
}
test "NotExists succeeds" {
Expect.equal NotExists.OpSql "IS NULL" "The NotExists SQL was not correct"
} }
] ]
/// Unit tests for the Field class /// Unit tests for the Field class
let fieldTests = testList "Field" [ let fieldTests = testList "Field" [
test "EQ succeeds" { test "Equal succeeds" {
let field = Field.EQ "Test" 14 let field = Field.Equal "Test" 14
Expect.equal field.Name "Test" "Field name incorrect" Expect.equal field.Name "Test" "Field name incorrect"
Expect.equal field.Op EQ "Operator incorrect" Expect.equal field.Comparison (Equal 14) "Comparison incorrect"
Expect.equal field.Value 14 "Value incorrect"
Expect.isNone field.ParameterName "The default parameter name should be None" Expect.isNone field.ParameterName "The default parameter name should be None"
Expect.isNone field.Qualifier "The default table qualifier should be None" Expect.isNone field.Qualifier "The default table qualifier should be None"
} }
test "GT succeeds" { test "Greater succeeds" {
let field = Field.GT "Great" "night" let field = Field.Greater "Great" "night"
Expect.equal field.Name "Great" "Field name incorrect" Expect.equal field.Name "Great" "Field name incorrect"
Expect.equal field.Op GT "Operator incorrect" Expect.equal field.Comparison (Greater "night") "Comparison incorrect"
Expect.equal field.Value "night" "Value incorrect"
Expect.isNone field.ParameterName "The default parameter name should be None" Expect.isNone field.ParameterName "The default parameter name should be None"
Expect.isNone field.Qualifier "The default table qualifier should be None" Expect.isNone field.Qualifier "The default table qualifier should be None"
} }
test "GE succeeds" { test "GreaterOrEqual succeeds" {
let field = Field.GE "Nice" 88L let field = Field.GreaterOrEqual "Nice" 88L
Expect.equal field.Name "Nice" "Field name incorrect" Expect.equal field.Name "Nice" "Field name incorrect"
Expect.equal field.Op GE "Operator incorrect" Expect.equal field.Comparison (GreaterOrEqual 88L) "Comparison incorrect"
Expect.equal field.Value 88L "Value incorrect"
Expect.isNone field.ParameterName "The default parameter name should be None" Expect.isNone field.ParameterName "The default parameter name should be None"
Expect.isNone field.Qualifier "The default table qualifier should be None" Expect.isNone field.Qualifier "The default table qualifier should be None"
} }
test "LT succeeds" { test "Less succeeds" {
let field = Field.LT "Lesser" "seven" let field = Field.Less "Lesser" "seven"
Expect.equal field.Name "Lesser" "Field name incorrect" Expect.equal field.Name "Lesser" "Field name incorrect"
Expect.equal field.Op LT "Operator incorrect" Expect.equal field.Comparison (Less "seven") "Comparison incorrect"
Expect.equal field.Value "seven" "Value incorrect"
Expect.isNone field.ParameterName "The default parameter name should be None" Expect.isNone field.ParameterName "The default parameter name should be None"
Expect.isNone field.Qualifier "The default table qualifier should be None" Expect.isNone field.Qualifier "The default table qualifier should be None"
} }
test "LE succeeds" { test "LessOrEqual succeeds" {
let field = Field.LE "Nobody" "KNOWS"; let field = Field.LessOrEqual "Nobody" "KNOWS";
Expect.equal field.Name "Nobody" "Field name incorrect" Expect.equal field.Name "Nobody" "Field name incorrect"
Expect.equal field.Op LE "Operator incorrect" Expect.equal field.Comparison (LessOrEqual "KNOWS") "Comparison incorrect"
Expect.equal field.Value "KNOWS" "Value incorrect"
Expect.isNone field.ParameterName "The default parameter name should be None" Expect.isNone field.ParameterName "The default parameter name should be None"
Expect.isNone field.Qualifier "The default table qualifier should be None" Expect.isNone field.Qualifier "The default table qualifier should be None"
} }
test "NE succeeds" { test "NotEqual succeeds" {
let field = Field.NE "Park" "here" let field = Field.NotEqual "Park" "here"
Expect.equal field.Name "Park" "Field name incorrect" Expect.equal field.Name "Park" "Field name incorrect"
Expect.equal field.Op NE "Operator incorrect" Expect.equal field.Comparison (NotEqual "here") "Comparison incorrect"
Expect.equal field.Value "here" "Value incorrect"
Expect.isNone field.ParameterName "The default parameter name should be None" Expect.isNone field.ParameterName "The default parameter name should be None"
Expect.isNone field.Qualifier "The default table qualifier should be None" Expect.isNone field.Qualifier "The default table qualifier should be None"
} }
test "BT succeeds" { test "Between succeeds" {
let field = Field.BT "Age" 18 49 let field = Field.Between "Age" 18 49
Expect.equal field.Name "Age" "Field name incorrect" Expect.equal field.Name "Age" "Field name incorrect"
Expect.equal field.Op BT "Operator incorrect" Expect.equal field.Comparison (Between(18, 49)) "Comparison incorrect"
Expect.sequenceEqual (field.Value :?> obj list) [ 18; 49 ] "Value incorrect"
Expect.isNone field.ParameterName "The default parameter name should be None" Expect.isNone field.ParameterName "The default parameter name should be None"
Expect.isNone field.Qualifier "The default table qualifier should be None" Expect.isNone field.Qualifier "The default table qualifier should be None"
} }
test "EX succeeds" { test "In succeeds" {
let field = Field.EX "Groovy" let field = Field.In "Here" [| 8; 16; 32 |]
Expect.equal field.Name "Here" "Field name incorrect"
Expect.equal field.Comparison (In [| 8; 16; 32 |]) "Comparison incorrect"
Expect.isNone field.ParameterName "The default parameter name should be None"
Expect.isNone field.Qualifier "The default table qualifier should be None"
}
test "InArray succeeds" {
let field = Field.InArray "ArrayField" "table" [| "z" |]
Expect.equal field.Name "ArrayField" "Field name incorrect"
Expect.equal field.Comparison (InArray("table", [| "z" |])) "Comparison incorrect"
Expect.isNone field.ParameterName "The default parameter name should be None"
Expect.isNone field.Qualifier "The default table qualifier should be None"
}
test "Exists succeeds" {
let field = Field.Exists "Groovy"
Expect.equal field.Name "Groovy" "Field name incorrect" Expect.equal field.Name "Groovy" "Field name incorrect"
Expect.equal field.Op EX "Operator incorrect" Expect.equal field.Comparison Exists "Comparison incorrect"
Expect.isNone field.ParameterName "The default parameter name should be None" Expect.isNone field.ParameterName "The default parameter name should be None"
Expect.isNone field.Qualifier "The default table qualifier should be None" Expect.isNone field.Qualifier "The default table qualifier should be None"
} }
test "NEX succeeds" { test "NotExists succeeds" {
let field = Field.NEX "Rad" let field = Field.NotExists "Rad"
Expect.equal field.Name "Rad" "Field name incorrect" Expect.equal field.Name "Rad" "Field name incorrect"
Expect.equal field.Op NEX "Operator incorrect" Expect.equal field.Comparison NotExists "Comparison incorrect"
Expect.isNone field.ParameterName "The default parameter name should be None" Expect.isNone field.ParameterName "The default parameter name should be None"
Expect.isNone field.Qualifier "The default table qualifier should be None" Expect.isNone field.Qualifier "The default table qualifier should be None"
} }
testList "NameToPath" [ testList "NameToPath" [
test "succeeds for PostgreSQL and a simple name" { test "succeeds for PostgreSQL and a simple name" {
Expect.equal "data->>'Simple'" (Field.NameToPath "Simple" PostgreSQL) "Path not constructed correctly" Expect.equal "data->>'Simple'" (Field.NameToPath "Simple" PostgreSQL AsSql) "Path not constructed correctly"
} }
test "succeeds for SQLite and a simple name" { test "succeeds for SQLite and a simple name" {
Expect.equal "data->>'Simple'" (Field.NameToPath "Simple" SQLite) "Path not constructed correctly" Expect.equal "data->>'Simple'" (Field.NameToPath "Simple" SQLite AsSql) "Path not constructed correctly"
} }
test "succeeds for PostgreSQL and a nested name" { test "succeeds for PostgreSQL and a nested name" {
Expect.equal Expect.equal
"data#>>'{A,Long,Path,to,the,Property}'" "data#>>'{A,Long,Path,to,the,Property}'"
(Field.NameToPath "A.Long.Path.to.the.Property" PostgreSQL) (Field.NameToPath "A.Long.Path.to.the.Property" PostgreSQL AsSql)
"Path not constructed correctly" "Path not constructed correctly"
} }
test "succeeds for SQLite and a nested name" { test "succeeds for SQLite and a nested name" {
Expect.equal Expect.equal
"data->>'A'->>'Long'->>'Path'->>'to'->>'the'->>'Property'" "data->'A'->'Long'->'Path'->'to'->'the'->>'Property'"
(Field.NameToPath "A.Long.Path.to.the.Property" SQLite) (Field.NameToPath "A.Long.Path.to.the.Property" SQLite AsSql)
"Path not constructed correctly" "Path not constructed correctly"
} }
] ]
test "WithParameterName succeeds" { test "WithParameterName succeeds" {
let field = (Field.EQ "Bob" "Tom").WithParameterName "@name" let field = (Field.Equal "Bob" "Tom").WithParameterName "@name"
Expect.isSome field.ParameterName "The parameter name should have been filled" Expect.isSome field.ParameterName "The parameter name should have been filled"
Expect.equal "@name" field.ParameterName.Value "The parameter name is incorrect" Expect.equal "@name" field.ParameterName.Value "The parameter name is incorrect"
} }
test "WithQualifier succeeds" { test "WithQualifier succeeds" {
let field = (Field.EQ "Bill" "Matt").WithQualifier "joe" let field = (Field.Equal "Bill" "Matt").WithQualifier "joe"
Expect.isSome field.Qualifier "The table qualifier should have been filled" Expect.isSome field.Qualifier "The table qualifier should have been filled"
Expect.equal "joe" field.Qualifier.Value "The table qualifier is incorrect" Expect.equal "joe" field.Qualifier.Value "The table qualifier is incorrect"
} }
testList "Path" [ testList "Path" [
test "succeeds for a PostgreSQL single field with no qualifier" { test "succeeds for a PostgreSQL single field with no qualifier" {
let field = Field.GE "SomethingCool" 18 let field = Field.GreaterOrEqual "SomethingCool" 18
Expect.equal "data->>'SomethingCool'" (field.Path PostgreSQL) "The PostgreSQL path is incorrect" Expect.equal "data->>'SomethingCool'" (field.Path PostgreSQL AsSql) "The PostgreSQL path is incorrect"
} }
test "succeeds for a PostgreSQL single field with a qualifier" { test "succeeds for a PostgreSQL single field with a qualifier" {
let field = { Field.LT "SomethingElse" 9 with Qualifier = Some "this" } let field = { Field.Less "SomethingElse" 9 with Qualifier = Some "this" }
Expect.equal "this.data->>'SomethingElse'" (field.Path PostgreSQL) "The PostgreSQL path is incorrect" Expect.equal "this.data->>'SomethingElse'" (field.Path PostgreSQL AsSql) "The PostgreSQL path is incorrect"
} }
test "succeeds for a PostgreSQL nested field with no qualifier" { test "succeeds for a PostgreSQL nested field with no qualifier" {
let field = Field.EQ "My.Nested.Field" "howdy" let field = Field.Equal "My.Nested.Field" "howdy"
Expect.equal "data#>>'{My,Nested,Field}'" (field.Path PostgreSQL) "The PostgreSQL path is incorrect" Expect.equal "data#>>'{My,Nested,Field}'" (field.Path PostgreSQL AsSql) "The PostgreSQL path is incorrect"
} }
test "succeeds for a PostgreSQL nested field with a qualifier" { test "succeeds for a PostgreSQL nested field with a qualifier" {
let field = { Field.EQ "Nest.Away" "doc" with Qualifier = Some "bird" } let field = { Field.Equal "Nest.Away" "doc" with Qualifier = Some "bird" }
Expect.equal "bird.data#>>'{Nest,Away}'" (field.Path PostgreSQL) "The PostgreSQL path is incorrect" Expect.equal "bird.data#>>'{Nest,Away}'" (field.Path PostgreSQL AsSql) "The PostgreSQL path is incorrect"
} }
test "succeeds for a SQLite single field with no qualifier" { test "succeeds for a SQLite single field with no qualifier" {
let field = Field.GE "SomethingCool" 18 let field = Field.GreaterOrEqual "SomethingCool" 18
Expect.equal "data->>'SomethingCool'" (field.Path SQLite) "The SQLite path is incorrect" Expect.equal "data->>'SomethingCool'" (field.Path SQLite AsSql) "The SQLite path is incorrect"
} }
test "succeeds for a SQLite single field with a qualifier" { test "succeeds for a SQLite single field with a qualifier" {
let field = { Field.LT "SomethingElse" 9 with Qualifier = Some "this" } let field = { Field.Less "SomethingElse" 9 with Qualifier = Some "this" }
Expect.equal "this.data->>'SomethingElse'" (field.Path SQLite) "The SQLite path is incorrect" Expect.equal "this.data->>'SomethingElse'" (field.Path SQLite AsSql) "The SQLite path is incorrect"
} }
test "succeeds for a SQLite nested field with no qualifier" { test "succeeds for a SQLite nested field with no qualifier" {
let field = Field.EQ "My.Nested.Field" "howdy" let field = Field.Equal "My.Nested.Field" "howdy"
Expect.equal "data->>'My'->>'Nested'->>'Field'" (field.Path SQLite) "The SQLite path is incorrect" Expect.equal "data->'My'->'Nested'->>'Field'" (field.Path SQLite AsSql) "The SQLite path is incorrect"
} }
test "succeeds for a SQLite nested field with a qualifier" { test "succeeds for a SQLite nested field with a qualifier" {
let field = { Field.EQ "Nest.Away" "doc" with Qualifier = Some "bird" } let field = { Field.Equal "Nest.Away" "doc" with Qualifier = Some "bird" }
Expect.equal "bird.data->>'Nest'->>'Away'" (field.Path SQLite) "The SQLite path is incorrect" Expect.equal "bird.data->'Nest'->>'Away'" (field.Path SQLite AsSql) "The SQLite path is incorrect"
} }
] ]
] ]
@ -373,7 +386,7 @@ let queryTests = testList "Query" [
test "succeeds for nested SQLite field" { test "succeeds for nested SQLite field" {
Expect.equal Expect.equal
(Query.Definition.ensureIndexOn tbl "nest" [ "a.b.c" ] SQLite) (Query.Definition.ensureIndexOn tbl "nest" [ "a.b.c" ] SQLite)
$"CREATE INDEX IF NOT EXISTS idx_{tbl}_nest ON {tbl} ((data->>'a'->>'b'->>'c'))" $"CREATE INDEX IF NOT EXISTS idx_{tbl}_nest ON {tbl} ((data->'a'->'b'->>'c'))"
"CREATE INDEX for nested SQLite field incorrect" "CREATE INDEX for nested SQLite field incorrect"
} }
] ]
@ -435,7 +448,7 @@ let queryTests = testList "Query" [
(Query.orderBy (Query.orderBy
[ Field.Named "Nested.Test.Field DESC"; Field.Named "AnotherField"; Field.Named "It DESC" ] [ Field.Named "Nested.Test.Field DESC"; Field.Named "AnotherField"; Field.Named "It DESC" ]
SQLite) SQLite)
" ORDER BY data->>'Nested'->>'Test'->>'Field' DESC, data->>'AnotherField', data->>'It' DESC" " ORDER BY data->'Nested'->'Test'->>'Field' DESC, data->>'AnotherField', data->>'It' DESC"
"Order By not constructed correctly" "Order By not constructed correctly"
} }
test "succeeds for PostgreSQL numeric fields" { test "succeeds for PostgreSQL numeric fields" {
@ -459,7 +472,7 @@ let queryTests = testList "Query" [
test "succeeds for SQLite case-insensitive ordering" { test "succeeds for SQLite case-insensitive ordering" {
Expect.equal Expect.equal
(Query.orderBy [ Field.Named "i:Test.Field ASC NULLS LAST" ] SQLite) (Query.orderBy [ Field.Named "i:Test.Field ASC NULLS LAST" ] SQLite)
" ORDER BY data->>'Test'->>'Field' COLLATE NOCASE ASC NULLS LAST" " ORDER BY data->'Test'->>'Field' COLLATE NOCASE ASC NULLS LAST"
"Order By not constructed correctly for case-insensitive field" "Order By not constructed correctly for case-insensitive field"
} }
] ]
@ -467,7 +480,7 @@ let queryTests = testList "Query" [
/// Tests which do not hit the database /// Tests which do not hit the database
let all = testList "Common" [ let all = testList "Common" [
opTests comparisonTests
fieldTests fieldTests
fieldMatchTests fieldMatchTests
parameterNameTests parameterNameTests

View File

@ -214,7 +214,7 @@ let integrationTests =
use conn = mkConn db use conn = mkConn db
do! loadDocs conn do! loadDocs conn
let! theCount = conn.countByFields PostgresDb.TableName Any [ Field.EQ "Value" "purple" ] let! theCount = conn.countByFields PostgresDb.TableName Any [ Field.Equal "Value" "purple" ]
Expect.equal theCount 2 "There should have been 2 matching documents" Expect.equal theCount 2 "There should have been 2 matching documents"
} }
testTask "countByContains succeeds" { testTask "countByContains succeeds" {
@ -257,7 +257,7 @@ let integrationTests =
use conn = mkConn db use conn = mkConn db
do! loadDocs conn do! loadDocs conn
let! exists = conn.existsByFields PostgresDb.TableName Any [ Field.EX "Sub" ] let! exists = conn.existsByFields PostgresDb.TableName Any [ Field.Exists "Sub" ]
Expect.isTrue exists "There should have been existing documents" Expect.isTrue exists "There should have been existing documents"
} }
testTask "succeeds when documents do not exist" { testTask "succeeds when documents do not exist" {
@ -265,7 +265,7 @@ let integrationTests =
use conn = mkConn db use conn = mkConn db
do! loadDocs conn do! loadDocs conn
let! exists = conn.existsByFields PostgresDb.TableName Any [ Field.EQ "NumValue" "six" ] let! exists = conn.existsByFields PostgresDb.TableName Any [ Field.Equal "NumValue" "six" ]
Expect.isFalse exists "There should not have been existing documents" Expect.isFalse exists "There should not have been existing documents"
} }
] ]
@ -390,7 +390,7 @@ let integrationTests =
use conn = mkConn db use conn = mkConn db
do! loadDocs conn do! loadDocs conn
let! docs = conn.findByFields<JsonDocument> PostgresDb.TableName Any [ Field.EQ "Value" "another" ] let! docs = conn.findByFields<JsonDocument> PostgresDb.TableName Any [ Field.Equal "Value" "another" ]
Expect.equal (List.length docs) 1 "There should have been one document returned" Expect.equal (List.length docs) 1 "There should have been one document returned"
} }
testTask "succeeds when documents are not found" { testTask "succeeds when documents are not found" {
@ -398,7 +398,7 @@ let integrationTests =
use conn = mkConn db use conn = mkConn db
do! loadDocs conn do! loadDocs conn
let! docs = conn.findByFields<JsonDocument> PostgresDb.TableName Any [ Field.EQ "Value" "mauve" ] let! docs = conn.findByFields<JsonDocument> PostgresDb.TableName Any [ Field.Equal "Value" "mauve" ]
Expect.isEmpty docs "There should have been no documents returned" Expect.isEmpty docs "There should have been no documents returned"
} }
] ]
@ -410,7 +410,7 @@ let integrationTests =
let! docs = let! docs =
conn.findByFieldsOrdered<JsonDocument> conn.findByFieldsOrdered<JsonDocument>
PostgresDb.TableName All [ Field.EQ "Value" "purple" ] [ Field.Named "Id" ] PostgresDb.TableName All [ Field.Equal "Value" "purple" ] [ Field.Named "Id" ]
Expect.hasLength docs 2 "There should have been two documents returned" Expect.hasLength docs 2 "There should have been two documents returned"
Expect.equal Expect.equal
(docs |> List.map _.Id |> String.concat "|") "five|four" "Documents not ordered correctly" (docs |> List.map _.Id |> String.concat "|") "five|four" "Documents not ordered correctly"
@ -422,7 +422,7 @@ let integrationTests =
let! docs = let! docs =
conn.findByFieldsOrdered<JsonDocument> conn.findByFieldsOrdered<JsonDocument>
PostgresDb.TableName All [ Field.EQ "Value" "purple" ] [ Field.Named "Id DESC" ] PostgresDb.TableName All [ Field.Equal "Value" "purple" ] [ Field.Named "Id DESC" ]
Expect.hasLength docs 2 "There should have been two documents returned" Expect.hasLength docs 2 "There should have been two documents returned"
Expect.equal Expect.equal
(docs |> List.map _.Id |> String.concat "|") "four|five" "Documents not ordered correctly" (docs |> List.map _.Id |> String.concat "|") "four|five" "Documents not ordered correctly"
@ -524,7 +524,8 @@ let integrationTests =
use conn = mkConn db use conn = mkConn db
do! loadDocs conn do! loadDocs conn
let! doc = conn.findFirstByFields<JsonDocument> PostgresDb.TableName Any [ Field.EQ "Value" "another" ] let! doc =
conn.findFirstByFields<JsonDocument> PostgresDb.TableName Any [ Field.Equal "Value" "another" ]
Expect.isSome doc "There should have been a document returned" Expect.isSome doc "There should have been a document returned"
Expect.equal doc.Value.Id "two" "The incorrect document was returned" Expect.equal doc.Value.Id "two" "The incorrect document was returned"
} }
@ -533,7 +534,8 @@ let integrationTests =
use conn = mkConn db use conn = mkConn db
do! loadDocs conn do! loadDocs conn
let! doc = conn.findFirstByFields<JsonDocument> PostgresDb.TableName Any [ Field.EQ "Value" "purple" ] let! doc =
conn.findFirstByFields<JsonDocument> PostgresDb.TableName Any [ Field.Equal "Value" "purple" ]
Expect.isSome doc "There should have been a document returned" Expect.isSome doc "There should have been a document returned"
Expect.contains [ "five"; "four" ] doc.Value.Id "An incorrect document was returned" Expect.contains [ "five"; "four" ] doc.Value.Id "An incorrect document was returned"
} }
@ -542,7 +544,8 @@ let integrationTests =
use conn = mkConn db use conn = mkConn db
do! loadDocs conn do! loadDocs conn
let! doc = conn.findFirstByFields<JsonDocument> PostgresDb.TableName Any [ Field.EQ "Value" "absent" ] let! doc =
conn.findFirstByFields<JsonDocument> PostgresDb.TableName Any [ Field.Equal "Value" "absent" ]
Expect.isNone doc "There should not have been a document returned" Expect.isNone doc "There should not have been a document returned"
} }
] ]
@ -554,7 +557,7 @@ let integrationTests =
let! doc = let! doc =
conn.findFirstByFieldsOrdered<JsonDocument> conn.findFirstByFieldsOrdered<JsonDocument>
PostgresDb.TableName Any [ Field.EQ "Value" "purple" ] [ Field.Named "Id" ] PostgresDb.TableName Any [ Field.Equal "Value" "purple" ] [ Field.Named "Id" ]
Expect.isSome doc "There should have been a document returned" Expect.isSome doc "There should have been a document returned"
Expect.equal "five" doc.Value.Id "An incorrect document was returned" Expect.equal "five" doc.Value.Id "An incorrect document was returned"
} }
@ -565,7 +568,7 @@ let integrationTests =
let! doc = let! doc =
conn.findFirstByFieldsOrdered<JsonDocument> conn.findFirstByFieldsOrdered<JsonDocument>
PostgresDb.TableName Any [ Field.EQ "Value" "purple" ] [ Field.Named "Id DESC" ] PostgresDb.TableName Any [ Field.Equal "Value" "purple" ] [ Field.Named "Id DESC" ]
Expect.isSome doc "There should have been a document returned" Expect.isSome doc "There should have been a document returned"
Expect.equal "four" doc.Value.Id "An incorrect document was returned" Expect.equal "four" doc.Value.Id "An incorrect document was returned"
} }
@ -750,8 +753,8 @@ let integrationTests =
use conn = mkConn db use conn = mkConn db
do! loadDocs conn do! loadDocs conn
do! conn.patchByFields PostgresDb.TableName Any [ Field.EQ "Value" "purple" ] {| NumValue = 77 |} do! conn.patchByFields PostgresDb.TableName Any [ Field.Equal "Value" "purple" ] {| NumValue = 77 |}
let! after = conn.countByFields PostgresDb.TableName Any [ Field.EQ "NumValue" "77" ] let! after = conn.countByFields PostgresDb.TableName Any [ Field.Equal "NumValue" "77" ]
Expect.equal after 2 "There should have been 2 documents returned" Expect.equal after 2 "There should have been 2 documents returned"
} }
testTask "succeeds when no document is updated" { testTask "succeeds when no document is updated" {
@ -761,7 +764,7 @@ let integrationTests =
Expect.equal before 0 "There should have been no documents returned" Expect.equal before 0 "There should have been no documents returned"
// This not raising an exception is the test // This not raising an exception is the test
do! conn.patchByFields PostgresDb.TableName Any [ Field.EQ "Value" "burgundy" ] {| Foo = "green" |} do! conn.patchByFields PostgresDb.TableName Any [ Field.Equal "Value" "burgundy" ] {| Foo = "green" |}
} }
] ]
testList "patchByContains" [ testList "patchByContains" [
@ -811,9 +814,9 @@ let integrationTests =
do! loadDocs conn do! loadDocs conn
do! conn.removeFieldsById PostgresDb.TableName "two" [ "Sub"; "Value" ] do! conn.removeFieldsById PostgresDb.TableName "two" [ "Sub"; "Value" ]
let! noSubs = conn.countByFields PostgresDb.TableName Any [ Field.NEX "Sub" ] let! noSubs = conn.countByFields PostgresDb.TableName Any [ Field.NotExists "Sub" ]
Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" Expect.equal noSubs 4 "There should now be 4 documents without Sub fields"
let! noValue = conn.countByFields PostgresDb.TableName Any [ Field.NEX "Value" ] let! noValue = conn.countByFields PostgresDb.TableName Any [ Field.NotExists "Value" ]
Expect.equal noValue 1 "There should be 1 document without Value fields" Expect.equal noValue 1 "There should be 1 document without Value fields"
} }
testTask "succeeds when a single field is removed" { testTask "succeeds when a single field is removed" {
@ -822,9 +825,9 @@ let integrationTests =
do! loadDocs conn do! loadDocs conn
do! conn.removeFieldsById PostgresDb.TableName "two" [ "Sub" ] do! conn.removeFieldsById PostgresDb.TableName "two" [ "Sub" ]
let! noSubs = conn.countByFields PostgresDb.TableName Any [ Field.NEX "Sub" ] let! noSubs = conn.countByFields PostgresDb.TableName Any [ Field.NotExists "Sub" ]
Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" Expect.equal noSubs 4 "There should now be 4 documents without Sub fields"
let! noValue = conn.countByFields PostgresDb.TableName Any [ Field.NEX "Value" ] let! noValue = conn.countByFields PostgresDb.TableName Any [ Field.NotExists "Value" ]
Expect.equal noValue 0 "There should be no documents without Value fields" Expect.equal noValue 0 "There should be no documents without Value fields"
} }
testTask "succeeds when a field is not removed" { testTask "succeeds when a field is not removed" {
@ -849,10 +852,11 @@ let integrationTests =
use conn = mkConn db use conn = mkConn db
do! loadDocs conn do! loadDocs conn
do! conn.removeFieldsByFields PostgresDb.TableName Any [ Field.EQ "NumValue" "17" ] [ "Sub"; "Value" ] do! conn.removeFieldsByFields
let! noSubs = conn.countByFields PostgresDb.TableName Any [ Field.NEX "Sub" ] PostgresDb.TableName Any [ Field.Equal "NumValue" "17" ] [ "Sub"; "Value" ]
let! noSubs = conn.countByFields PostgresDb.TableName Any [ Field.NotExists "Sub" ]
Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" Expect.equal noSubs 4 "There should now be 4 documents without Sub fields"
let! noValue = conn.countByFields PostgresDb.TableName Any [ Field.NEX "Value" ] let! noValue = conn.countByFields PostgresDb.TableName Any [ Field.NotExists "Value" ]
Expect.equal noValue 1 "There should be 1 document without Value fields" Expect.equal noValue 1 "There should be 1 document without Value fields"
} }
testTask "succeeds when a single field is removed" { testTask "succeeds when a single field is removed" {
@ -860,10 +864,10 @@ let integrationTests =
use conn = mkConn db use conn = mkConn db
do! loadDocs conn do! loadDocs conn
do! conn.removeFieldsByFields PostgresDb.TableName Any [ Field.EQ "NumValue" "17" ] [ "Sub" ] do! conn.removeFieldsByFields PostgresDb.TableName Any [ Field.Equal "NumValue" "17" ] [ "Sub" ]
let! noSubs = conn.countByFields PostgresDb.TableName Any [ Field.NEX "Sub" ] let! noSubs = conn.countByFields PostgresDb.TableName Any [ Field.NotExists "Sub" ]
Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" Expect.equal noSubs 4 "There should now be 4 documents without Sub fields"
let! noValue = conn.countByFields PostgresDb.TableName Any [ Field.NEX "Value" ] let! noValue = conn.countByFields PostgresDb.TableName Any [ Field.NotExists "Value" ]
Expect.equal noValue 0 "There should be no documents without Value fields" Expect.equal noValue 0 "There should be no documents without Value fields"
} }
testTask "succeeds when a field is not removed" { testTask "succeeds when a field is not removed" {
@ -872,14 +876,15 @@ let integrationTests =
do! loadDocs conn do! loadDocs conn
// This not raising an exception is the test // This not raising an exception is the test
do! conn.removeFieldsByFields PostgresDb.TableName Any [ Field.EQ "NumValue" "17" ] [ "Nothing" ] do! conn.removeFieldsByFields PostgresDb.TableName Any [ Field.Equal "NumValue" "17" ] [ "Nothing" ]
} }
testTask "succeeds when no document is matched" { testTask "succeeds when no document is matched" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
use conn = mkConn db use conn = mkConn db
// This not raising an exception is the test // This not raising an exception is the test
do! conn.removeFieldsByFields PostgresDb.TableName Any [ Field.NE "Abracadabra" "apple" ] [ "Value" ] do! conn.removeFieldsByFields
PostgresDb.TableName Any [ Field.NotEqual "Abracadabra" "apple" ] [ "Value" ]
} }
] ]
testList "removeFieldsByContains" [ testList "removeFieldsByContains" [
@ -889,9 +894,9 @@ let integrationTests =
do! loadDocs conn do! loadDocs conn
do! conn.removeFieldsByContains PostgresDb.TableName {| NumValue = 17 |} [ "Sub"; "Value" ] do! conn.removeFieldsByContains PostgresDb.TableName {| NumValue = 17 |} [ "Sub"; "Value" ]
let! noSubs = conn.countByFields PostgresDb.TableName Any [ Field.NEX "Sub" ] let! noSubs = conn.countByFields PostgresDb.TableName Any [ Field.NotExists "Sub" ]
Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" Expect.equal noSubs 4 "There should now be 4 documents without Sub fields"
let! noValue = conn.countByFields PostgresDb.TableName Any [ Field.NEX "Value" ] let! noValue = conn.countByFields PostgresDb.TableName Any [ Field.NotExists "Value" ]
Expect.equal noValue 1 "There should be 1 document without Value fields" Expect.equal noValue 1 "There should be 1 document without Value fields"
} }
testTask "succeeds when a single field is removed" { testTask "succeeds when a single field is removed" {
@ -900,9 +905,9 @@ let integrationTests =
do! loadDocs conn do! loadDocs conn
do! conn.removeFieldsByContains PostgresDb.TableName {| NumValue = 17 |} [ "Sub" ] do! conn.removeFieldsByContains PostgresDb.TableName {| NumValue = 17 |} [ "Sub" ]
let! noSubs = conn.countByFields PostgresDb.TableName Any [ Field.NEX "Sub" ] let! noSubs = conn.countByFields PostgresDb.TableName Any [ Field.NotExists "Sub" ]
Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" Expect.equal noSubs 4 "There should now be 4 documents without Sub fields"
let! noValue = conn.countByFields PostgresDb.TableName Any [ Field.NEX "Value" ] let! noValue = conn.countByFields PostgresDb.TableName Any [ Field.NotExists "Value" ]
Expect.equal noValue 0 "There should be no documents without Value fields" Expect.equal noValue 0 "There should be no documents without Value fields"
} }
testTask "succeeds when a field is not removed" { testTask "succeeds when a field is not removed" {
@ -928,9 +933,9 @@ let integrationTests =
do! loadDocs conn do! loadDocs conn
do! conn.removeFieldsByJsonPath PostgresDb.TableName "$.NumValue ? (@ == 17)" [ "Sub"; "Value" ] do! conn.removeFieldsByJsonPath PostgresDb.TableName "$.NumValue ? (@ == 17)" [ "Sub"; "Value" ]
let! noSubs = conn.countByFields PostgresDb.TableName Any [ Field.NEX "Sub" ] let! noSubs = conn.countByFields PostgresDb.TableName Any [ Field.NotExists "Sub" ]
Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" Expect.equal noSubs 4 "There should now be 4 documents without Sub fields"
let! noValue = conn.countByFields PostgresDb.TableName Any [ Field.NEX "Value" ] let! noValue = conn.countByFields PostgresDb.TableName Any [ Field.NotExists "Value" ]
Expect.equal noValue 1 "There should be 1 document without Value fields" Expect.equal noValue 1 "There should be 1 document without Value fields"
} }
testTask "succeeds when a single field is removed" { testTask "succeeds when a single field is removed" {
@ -939,9 +944,9 @@ let integrationTests =
do! loadDocs conn do! loadDocs conn
do! conn.removeFieldsByJsonPath PostgresDb.TableName "$.NumValue ? (@ == 17)" [ "Sub" ] do! conn.removeFieldsByJsonPath PostgresDb.TableName "$.NumValue ? (@ == 17)" [ "Sub" ]
let! noSubs = conn.countByFields PostgresDb.TableName Any [ Field.NEX "Sub" ] let! noSubs = conn.countByFields PostgresDb.TableName Any [ Field.NotExists "Sub" ]
Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" Expect.equal noSubs 4 "There should now be 4 documents without Sub fields"
let! noValue = conn.countByFields PostgresDb.TableName Any [ Field.NEX "Value" ] let! noValue = conn.countByFields PostgresDb.TableName Any [ Field.NotExists "Value" ]
Expect.equal noValue 0 "There should be no documents without Value fields" Expect.equal noValue 0 "There should be no documents without Value fields"
} }
testTask "succeeds when a field is not removed" { testTask "succeeds when a field is not removed" {
@ -986,7 +991,7 @@ let integrationTests =
use conn = mkConn db use conn = mkConn db
do! loadDocs conn do! loadDocs conn
do! conn.deleteByFields PostgresDb.TableName Any [ Field.EQ "Value" "purple" ] do! conn.deleteByFields PostgresDb.TableName Any [ Field.Equal "Value" "purple" ]
let! remaining = conn.countAll PostgresDb.TableName let! remaining = conn.countAll PostgresDb.TableName
Expect.equal remaining 3 "There should have been 3 documents remaining" Expect.equal remaining 3 "There should have been 3 documents remaining"
} }
@ -995,7 +1000,7 @@ let integrationTests =
use conn = mkConn db use conn = mkConn db
do! loadDocs conn do! loadDocs conn
do! conn.deleteByFields PostgresDb.TableName Any [ Field.EQ "Value" "crimson" ] do! conn.deleteByFields PostgresDb.TableName Any [ Field.Equal "Value" "crimson" ]
let! remaining = conn.countAll PostgresDb.TableName let! remaining = conn.countAll PostgresDb.TableName
Expect.equal remaining 5 "There should have been 5 documents remaining" Expect.equal remaining 5 "There should have been 5 documents remaining"
} }

View File

@ -83,14 +83,14 @@ let parametersTests = testList "Parameters" [
} }
testList "addFieldParams" [ testList "addFieldParams" [
test "succeeds when a parameter is added" { test "succeeds when a parameter is added" {
let paramList = addFieldParams [ Field.EQ "it" "242" ] [] let paramList = addFieldParams [ Field.Where "it" (Equal "242") ] []
Expect.hasLength paramList 1 "There should have been a parameter added" Expect.hasLength paramList 1 "There should have been a parameter added"
let name, value = Seq.head paramList let name, value = Seq.head paramList
Expect.equal name "@field0" "Field parameter name not correct" Expect.equal name "@field0" "Field parameter name not correct"
Expect.equal value (Sql.string "242") "Parameter value not correct" Expect.equal value (Sql.string "242") "Parameter value not correct"
} }
test "succeeds when multiple independent parameters are added" { test "succeeds when multiple independent parameters are added" {
let paramList = addFieldParams [ Field.EQ "me" "you"; Field.GT "us" "them" ] [ idParam 14 ] let paramList = addFieldParams [ Field.Equal "me" "you"; Field.Greater "us" "them" ] [ idParam 14 ]
Expect.hasLength paramList 3 "There should have been 2 parameters added" Expect.hasLength paramList 3 "There should have been 2 parameters added"
let p = Array.ofSeq paramList let p = Array.ofSeq paramList
Expect.equal (fst p[0]) "@id" "First field parameter name not correct" Expect.equal (fst p[0]) "@id" "First field parameter name not correct"
@ -101,11 +101,11 @@ let parametersTests = testList "Parameters" [
Expect.equal (snd p[2]) (Sql.string "them") "Third parameter value not correct" Expect.equal (snd p[2]) (Sql.string "them") "Third parameter value not correct"
} }
test "succeeds when a parameter is not added" { test "succeeds when a parameter is not added" {
let paramList = addFieldParams [ Field.EX "tacos" ] [] let paramList = addFieldParams [ Field.Exists "tacos" ] []
Expect.isEmpty paramList "There should not have been any parameters added" Expect.isEmpty paramList "There should not have been any parameters added"
} }
test "succeeds when two parameters are added for one field" { test "succeeds when two parameters are added for one field" {
let paramList = addFieldParams [ { Field.BT "that" "eh" "zed" with ParameterName = Some "@test" } ] [] let paramList = addFieldParams [ { Field.Between "that" "eh" "zed" with ParameterName = Some "@test" } ] []
Expect.hasLength paramList 2 "There should have been 2 parameters added" Expect.hasLength paramList 2 "There should have been 2 parameters added"
let name, value = Seq.head paramList let name, value = Seq.head paramList
Expect.equal name "@testmin" "Minimum field name not correct" Expect.equal name "@testmin" "Minimum field name not correct"
@ -135,48 +135,66 @@ let parametersTests = testList "Parameters" [
/// Unit tests for the Query module of the PostgreSQL library /// Unit tests for the Query module of the PostgreSQL library
let queryTests = testList "Query" [ let queryTests = testList "Query" [
testList "whereByFields" [ testList "whereByFields" [
test "succeeds for a single field when a logical operator is passed" { test "succeeds for a single field when a logical comparison is passed" {
Expect.equal Expect.equal
(Query.whereByFields Any [ { Field.GT "theField" "0" with ParameterName = Some "@test" } ]) (Query.whereByFields Any [ { Field.Greater "theField" "0" with ParameterName = Some "@test" } ])
"data->>'theField' > @test" "data->>'theField' > @test"
"WHERE clause not correct" "WHERE clause not correct"
} }
test "succeeds for a single field when an existence operator is passed" { test "succeeds for a single field when an existence comparison is passed" {
Expect.equal Expect.equal
(Query.whereByFields Any [ Field.NEX "thatField" ]) (Query.whereByFields Any [ Field.NotExists "thatField" ])
"data->>'thatField' IS NULL" "data->>'thatField' IS NULL"
"WHERE clause not correct" "WHERE clause not correct"
} }
test "succeeds for a single field when a between operator is passed with numeric values" { test "succeeds for a single field when a between comparison is passed with numeric values" {
Expect.equal Expect.equal
(Query.whereByFields All [ { Field.BT "aField" 50 99 with ParameterName = Some "@range" } ]) (Query.whereByFields All [ { Field.Between "aField" 50 99 with ParameterName = Some "@range" } ])
"(data->>'aField')::numeric BETWEEN @rangemin AND @rangemax" "(data->>'aField')::numeric BETWEEN @rangemin AND @rangemax"
"WHERE clause not correct" "WHERE clause not correct"
} }
test "succeeds for a single field when a between operator is passed with non-numeric values" { test "succeeds for a single field when a between comparison is passed with non-numeric values" {
Expect.equal Expect.equal
(Query.whereByFields Any [ { Field.BT "field0" "a" "b" with ParameterName = Some "@alpha" } ]) (Query.whereByFields Any [ { Field.Between "field0" "a" "b" with ParameterName = Some "@alpha" } ])
"data->>'field0' BETWEEN @alphamin AND @alphamax" "data->>'field0' BETWEEN @alphamin AND @alphamax"
"WHERE clause not correct" "WHERE clause not correct"
} }
test "succeeds for all multiple fields with logical operators" { test "succeeds for all multiple fields with logical comparisons" {
Expect.equal Expect.equal
(Query.whereByFields All [ Field.EQ "theFirst" "1"; Field.EQ "numberTwo" "2" ]) (Query.whereByFields All [ Field.Equal "theFirst" "1"; Field.Equal "numberTwo" "2" ])
"data->>'theFirst' = @field0 AND data->>'numberTwo' = @field1" "data->>'theFirst' = @field0 AND data->>'numberTwo' = @field1"
"WHERE clause not correct" "WHERE clause not correct"
} }
test "succeeds for any multiple fields with an existence operator" { test "succeeds for any multiple fields with an existence comparisons" {
Expect.equal Expect.equal
(Query.whereByFields Any [ Field.NEX "thatField"; Field.GE "thisField" 18 ]) (Query.whereByFields Any [ Field.NotExists "thatField"; Field.GreaterOrEqual "thisField" 18 ])
"data->>'thatField' IS NULL OR (data->>'thisField')::numeric >= @field0" "data->>'thatField' IS NULL OR (data->>'thisField')::numeric >= @field0"
"WHERE clause not correct" "WHERE clause not correct"
} }
test "succeeds for all multiple fields with between operators" { test "succeeds for all multiple fields with between comparisons" {
Expect.equal Expect.equal
(Query.whereByFields All [ Field.BT "aField" 50 99; Field.BT "anotherField" "a" "b" ]) (Query.whereByFields All [ Field.Between "aField" 50 99; Field.Between "anotherField" "a" "b" ])
"(data->>'aField')::numeric BETWEEN @field0min AND @field0max AND data->>'anotherField' BETWEEN @field1min AND @field1max" "(data->>'aField')::numeric BETWEEN @field0min AND @field0max AND data->>'anotherField' BETWEEN @field1min AND @field1max"
"WHERE clause not correct" "WHERE clause not correct"
} }
test "succeeds for a field with an In comparison with alphanumeric values" {
Expect.equal
(Query.whereByFields All [ Field.In "this" [ "a"; "b"; "c" ] ])
"data->>'this' IN (@field0_0, @field0_1, @field0_2)"
"WHERE clause not correct"
}
test "succeeds for a field with an In comparison with numeric values" {
Expect.equal
(Query.whereByFields All [ Field.In "this" [ 7; 14; 21 ] ])
"(data->>'this')::numeric IN (@field0_0, @field0_1, @field0_2)"
"WHERE clause not correct"
}
test "succeeds for a field with an InArray comparison" {
Expect.equal
(Query.whereByFields All [ Field.InArray "theField" "the_table" [ "q", "r" ] ])
"data->'theField' ?| @field0"
"WHERE clause not correct"
}
] ]
testList "whereById" [ testList "whereById" [
test "succeeds for numeric ID" { test "succeeds for numeric ID" {
@ -234,7 +252,7 @@ let queryTests = testList "Query" [
} }
test "byFields succeeds" { test "byFields succeeds" {
Expect.equal Expect.equal
(Query.byFields "unit" Any [ Field.GT "That" 14 ]) (Query.byFields "unit" Any [ Field.Greater "That" 14 ])
"unit WHERE (data->>'That')::numeric > @field0" "unit WHERE (data->>'That')::numeric > @field0"
"By-Field query not correct" "By-Field query not correct"
} }
@ -532,14 +550,15 @@ let countTests = testList "Count" [
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
let! theCount = Count.byFields PostgresDb.TableName Any [ Field.BT "NumValue" 15 20; Field.EQ "NumValue" 0 ] let! theCount =
Count.byFields PostgresDb.TableName Any [ Field.Between "NumValue" 15 20; Field.Equal "NumValue" 0 ]
Expect.equal theCount 3 "There should have been 3 matching documents" Expect.equal theCount 3 "There should have been 3 matching documents"
} }
testTask "succeeds when items are not found" { testTask "succeeds when items are not found" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
let! theCount = Count.byFields PostgresDb.TableName All [ Field.EX "Sub"; Field.GT "NumValue" 100 ] let! theCount = Count.byFields PostgresDb.TableName All [ Field.Exists "Sub"; Field.Greater "NumValue" 100 ]
Expect.equal theCount 0 "There should have been no matching documents" Expect.equal theCount 0 "There should have been no matching documents"
} }
] ]
@ -582,14 +601,14 @@ let existsTests = testList "Exists" [
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
let! exists = Exists.byFields PostgresDb.TableName Any [ Field.EX "Sub"; Field.EX "Boo" ] let! exists = Exists.byFields PostgresDb.TableName Any [ Field.Exists "Sub"; Field.Exists "Boo" ]
Expect.isTrue exists "There should have been existing documents" Expect.isTrue exists "There should have been existing documents"
} }
testTask "succeeds when documents do not exist" { testTask "succeeds when documents do not exist" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
let! exists = Exists.byFields PostgresDb.TableName All [ Field.EQ "NumValue" "six"; Field.EX "Nope" ] let! exists = Exists.byFields PostgresDb.TableName All [ Field.Equal "NumValue" "six"; Field.Exists "Nope" ]
Expect.isFalse exists "There should not have been existing documents" Expect.isFalse exists "There should not have been existing documents"
} }
] ]
@ -707,8 +726,16 @@ let findTests = testList "Find" [
do! loadDocs () do! loadDocs ()
let! docs = let! docs =
Find.byFields<JsonDocument> PostgresDb.TableName All [ Field.EQ "Value" "purple"; Field.EX "Sub" ] Find.byFields<JsonDocument>
Expect.equal (List.length docs) 1 "There should have been one document returned" PostgresDb.TableName All [ Field.In "Value" [ "purple"; "blue" ]; Field.Exists "Sub" ]
Expect.hasLength docs 1 "There should have been one document returned"
}
testTask "succeeds when documents are found using IN with numeric field" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
let! docs = Find.byFields<JsonDocument> PostgresDb.TableName All [ Field.In "NumValue" [ 2; 4; 6; 8 ] ]
Expect.hasLength docs 1 "There should have been one document returned"
} }
testTask "succeeds when documents are not found" { testTask "succeeds when documents are not found" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
@ -716,7 +743,27 @@ let findTests = testList "Find" [
let! docs = let! docs =
Find.byFields<JsonDocument> Find.byFields<JsonDocument>
PostgresDb.TableName All [ Field.EQ "Value" "mauve"; Field.NE "NumValue" 40 ] PostgresDb.TableName All [ Field.Equal "Value" "mauve"; Field.NotEqual "NumValue" 40 ]
Expect.isEmpty docs "There should have been no documents returned"
}
testTask "succeeds for InArray when matching documents exist" {
use db = PostgresDb.BuildDb()
do! Definition.ensureTable PostgresDb.TableName
for doc in ArrayDocument.TestDocuments do do! insert PostgresDb.TableName doc
let! docs =
Find.byFields<ArrayDocument>
PostgresDb.TableName All [ Field.InArray "Values" PostgresDb.TableName [ "c" ] ]
Expect.hasLength docs 2 "There should have been two documents returned"
}
testTask "succeeds for InArray when no matching documents exist" {
use db = PostgresDb.BuildDb()
do! Definition.ensureTable PostgresDb.TableName
for doc in ArrayDocument.TestDocuments do do! insert PostgresDb.TableName doc
let! docs =
Find.byFields<ArrayDocument>
PostgresDb.TableName All [ Field.InArray "Values" PostgresDb.TableName [ "j" ] ]
Expect.isEmpty docs "There should have been no documents returned" Expect.isEmpty docs "There should have been no documents returned"
} }
] ]
@ -727,7 +774,7 @@ let findTests = testList "Find" [
let! docs = let! docs =
Find.byFieldsOrdered<JsonDocument> Find.byFieldsOrdered<JsonDocument>
PostgresDb.TableName All [ Field.EQ "Value" "purple" ] [ Field.Named "Id" ] PostgresDb.TableName All [ Field.Equal "Value" "purple" ] [ Field.Named "Id" ]
Expect.hasLength docs 2 "There should have been two documents returned" Expect.hasLength docs 2 "There should have been two documents returned"
Expect.equal Expect.equal
(docs |> List.map _.Id |> String.concat "|") "five|four" "Documents not ordered correctly" (docs |> List.map _.Id |> String.concat "|") "five|four" "Documents not ordered correctly"
@ -738,7 +785,7 @@ let findTests = testList "Find" [
let! docs = let! docs =
Find.byFieldsOrdered<JsonDocument> Find.byFieldsOrdered<JsonDocument>
PostgresDb.TableName All [ Field.EQ "Value" "purple" ] [ Field.Named "Id DESC" ] PostgresDb.TableName All [ Field.Equal "Value" "purple" ] [ Field.Named "Id DESC" ]
Expect.hasLength docs 2 "There should have been two documents returned" Expect.hasLength docs 2 "There should have been two documents returned"
Expect.equal Expect.equal
(docs |> List.map _.Id |> String.concat "|") "four|five" "Documents not ordered correctly" (docs |> List.map _.Id |> String.concat "|") "four|five" "Documents not ordered correctly"
@ -831,7 +878,7 @@ let findTests = testList "Find" [
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
let! doc = Find.firstByFields<JsonDocument> PostgresDb.TableName Any [ Field.EQ "Value" "another" ] let! doc = Find.firstByFields<JsonDocument> PostgresDb.TableName Any [ Field.Equal "Value" "another" ]
Expect.isSome doc "There should have been a document returned" Expect.isSome doc "There should have been a document returned"
Expect.equal doc.Value.Id "two" "The incorrect document was returned" Expect.equal doc.Value.Id "two" "The incorrect document was returned"
} }
@ -839,7 +886,7 @@ let findTests = testList "Find" [
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
let! doc = Find.firstByFields<JsonDocument> PostgresDb.TableName Any [ Field.EQ "Value" "purple" ] let! doc = Find.firstByFields<JsonDocument> PostgresDb.TableName Any [ Field.Equal "Value" "purple" ]
Expect.isSome doc "There should have been a document returned" Expect.isSome doc "There should have been a document returned"
Expect.contains [ "five"; "four" ] doc.Value.Id "An incorrect document was returned" Expect.contains [ "five"; "four" ] doc.Value.Id "An incorrect document was returned"
} }
@ -847,7 +894,7 @@ let findTests = testList "Find" [
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
let! doc = Find.firstByFields<JsonDocument> PostgresDb.TableName Any [ Field.EQ "Value" "absent" ] let! doc = Find.firstByFields<JsonDocument> PostgresDb.TableName Any [ Field.Equal "Value" "absent" ]
Expect.isNone doc "There should not have been a document returned" Expect.isNone doc "There should not have been a document returned"
} }
] ]
@ -858,7 +905,7 @@ let findTests = testList "Find" [
let! doc = let! doc =
Find.firstByFieldsOrdered<JsonDocument> Find.firstByFieldsOrdered<JsonDocument>
PostgresDb.TableName Any [ Field.EQ "Value" "purple" ] [ Field.Named "Id" ] PostgresDb.TableName Any [ Field.Equal "Value" "purple" ] [ Field.Named "Id" ]
Expect.isSome doc "There should have been a document returned" Expect.isSome doc "There should have been a document returned"
Expect.equal "five" doc.Value.Id "An incorrect document was returned" Expect.equal "five" doc.Value.Id "An incorrect document was returned"
} }
@ -868,7 +915,7 @@ let findTests = testList "Find" [
let! doc = let! doc =
Find.firstByFieldsOrdered<JsonDocument> Find.firstByFieldsOrdered<JsonDocument>
PostgresDb.TableName Any [ Field.EQ "Value" "purple" ] [ Field.Named "Id DESC" ] PostgresDb.TableName Any [ Field.Equal "Value" "purple" ] [ Field.Named "Id DESC" ]
Expect.isSome doc "There should have been a document returned" Expect.isSome doc "There should have been a document returned"
Expect.equal "four" doc.Value.Id "An incorrect document was returned" Expect.equal "four" doc.Value.Id "An incorrect document was returned"
} }
@ -1045,8 +1092,8 @@ let patchTests = testList "Patch" [
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
do! Patch.byFields PostgresDb.TableName Any [ Field.EQ "Value" "purple" ] {| NumValue = 77 |} do! Patch.byFields PostgresDb.TableName Any [ Field.Equal "Value" "purple" ] {| NumValue = 77 |}
let! after = Count.byFields PostgresDb.TableName Any [ Field.EQ "NumValue" 77 ] let! after = Count.byFields PostgresDb.TableName Any [ Field.Equal "NumValue" 77 ]
Expect.equal after 2 "There should have been 2 documents returned" Expect.equal after 2 "There should have been 2 documents returned"
} }
testTask "succeeds when no document is updated" { testTask "succeeds when no document is updated" {
@ -1056,7 +1103,7 @@ let patchTests = testList "Patch" [
Expect.equal before 0 "There should have been no documents returned" Expect.equal before 0 "There should have been no documents returned"
// This not raising an exception is the test // This not raising an exception is the test
do! Patch.byFields PostgresDb.TableName Any [ Field.EQ "Value" "burgundy" ] {| Foo = "green" |} do! Patch.byFields PostgresDb.TableName Any [ Field.Equal "Value" "burgundy" ] {| Foo = "green" |}
} }
] ]
testList "byContains" [ testList "byContains" [
@ -1107,9 +1154,9 @@ let removeFieldsTests = testList "RemoveFields" [
do! loadDocs () do! loadDocs ()
do! RemoveFields.byId PostgresDb.TableName "two" [ "Sub"; "Value" ] do! RemoveFields.byId PostgresDb.TableName "two" [ "Sub"; "Value" ]
let! noSubs = Count.byFields PostgresDb.TableName Any [ Field.NEX "Sub" ] let! noSubs = Count.byFields PostgresDb.TableName Any [ Field.NotExists "Sub" ]
Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" Expect.equal noSubs 4 "There should now be 4 documents without Sub fields"
let! noValue = Count.byFields PostgresDb.TableName Any [ Field.NEX "Value" ] let! noValue = Count.byFields PostgresDb.TableName Any [ Field.NotExists "Value" ]
Expect.equal noValue 1 "There should be 1 document without Value fields" Expect.equal noValue 1 "There should be 1 document without Value fields"
} }
testTask "succeeds when a single field is removed" { testTask "succeeds when a single field is removed" {
@ -1117,9 +1164,9 @@ let removeFieldsTests = testList "RemoveFields" [
do! loadDocs () do! loadDocs ()
do! RemoveFields.byId PostgresDb.TableName "two" [ "Sub" ] do! RemoveFields.byId PostgresDb.TableName "two" [ "Sub" ]
let! noSubs = Count.byFields PostgresDb.TableName Any [ Field.NEX "Sub" ] let! noSubs = Count.byFields PostgresDb.TableName Any [ Field.NotExists "Sub" ]
Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" Expect.equal noSubs 4 "There should now be 4 documents without Sub fields"
let! noValue = Count.byFields PostgresDb.TableName Any [ Field.NEX "Value" ] let! noValue = Count.byFields PostgresDb.TableName Any [ Field.NotExists "Value" ]
Expect.equal noValue 0 "There should be no documents without Value fields" Expect.equal noValue 0 "There should be no documents without Value fields"
} }
testTask "succeeds when a field is not removed" { testTask "succeeds when a field is not removed" {
@ -1141,20 +1188,20 @@ let removeFieldsTests = testList "RemoveFields" [
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
do! RemoveFields.byFields PostgresDb.TableName Any [ Field.EQ "NumValue" "17" ] [ "Sub"; "Value" ] do! RemoveFields.byFields PostgresDb.TableName Any [ Field.Equal "NumValue" 17 ] [ "Sub"; "Value" ]
let! noSubs = Count.byFields PostgresDb.TableName Any [ Field.NEX "Sub" ] let! noSubs = Count.byFields PostgresDb.TableName Any [ Field.NotExists "Sub" ]
Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" Expect.equal noSubs 4 "There should now be 4 documents without Sub fields"
let! noValue = Count.byFields PostgresDb.TableName Any [ Field.NEX "Value" ] let! noValue = Count.byFields PostgresDb.TableName Any [ Field.NotExists "Value" ]
Expect.equal noValue 1 "There should be 1 document without Value fields" Expect.equal noValue 1 "There should be 1 document without Value fields"
} }
testTask "succeeds when a single field is removed" { testTask "succeeds when a single field is removed" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
do! RemoveFields.byFields PostgresDb.TableName Any [ Field.EQ "NumValue" "17" ] [ "Sub" ] do! RemoveFields.byFields PostgresDb.TableName Any [ Field.Equal "NumValue" 17 ] [ "Sub" ]
let! noSubs = Count.byFields PostgresDb.TableName Any [ Field.NEX "Sub" ] let! noSubs = Count.byFields PostgresDb.TableName Any [ Field.NotExists "Sub" ]
Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" Expect.equal noSubs 4 "There should now be 4 documents without Sub fields"
let! noValue = Count.byFields PostgresDb.TableName Any [ Field.NEX "Value" ] let! noValue = Count.byFields PostgresDb.TableName Any [ Field.NotExists "Value" ]
Expect.equal noValue 0 "There should be no documents without Value fields" Expect.equal noValue 0 "There should be no documents without Value fields"
} }
testTask "succeeds when a field is not removed" { testTask "succeeds when a field is not removed" {
@ -1162,13 +1209,13 @@ let removeFieldsTests = testList "RemoveFields" [
do! loadDocs () do! loadDocs ()
// This not raising an exception is the test // This not raising an exception is the test
do! RemoveFields.byFields PostgresDb.TableName Any [ Field.EQ "NumValue" "17" ] [ "Nothing" ] do! RemoveFields.byFields PostgresDb.TableName Any [ Field.Equal "NumValue" 17 ] [ "Nothing" ]
} }
testTask "succeeds when no document is matched" { testTask "succeeds when no document is matched" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
// This not raising an exception is the test // This not raising an exception is the test
do! RemoveFields.byFields PostgresDb.TableName Any [ Field.NE "Abracadabra" "apple" ] [ "Value" ] do! RemoveFields.byFields PostgresDb.TableName Any [ Field.NotEqual "Abracadabra" "apple" ] [ "Value" ]
} }
] ]
testList "byContains" [ testList "byContains" [
@ -1177,9 +1224,9 @@ let removeFieldsTests = testList "RemoveFields" [
do! loadDocs () do! loadDocs ()
do! RemoveFields.byContains PostgresDb.TableName {| NumValue = 17 |} [ "Sub"; "Value" ] do! RemoveFields.byContains PostgresDb.TableName {| NumValue = 17 |} [ "Sub"; "Value" ]
let! noSubs = Count.byFields PostgresDb.TableName Any [ Field.NEX "Sub" ] let! noSubs = Count.byFields PostgresDb.TableName Any [ Field.NotExists "Sub" ]
Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" Expect.equal noSubs 4 "There should now be 4 documents without Sub fields"
let! noValue = Count.byFields PostgresDb.TableName Any [ Field.NEX "Value" ] let! noValue = Count.byFields PostgresDb.TableName Any [ Field.NotExists "Value" ]
Expect.equal noValue 1 "There should be 1 document without Value fields" Expect.equal noValue 1 "There should be 1 document without Value fields"
} }
testTask "succeeds when a single field is removed" { testTask "succeeds when a single field is removed" {
@ -1187,9 +1234,9 @@ let removeFieldsTests = testList "RemoveFields" [
do! loadDocs () do! loadDocs ()
do! RemoveFields.byContains PostgresDb.TableName {| NumValue = 17 |} [ "Sub" ] do! RemoveFields.byContains PostgresDb.TableName {| NumValue = 17 |} [ "Sub" ]
let! noSubs = Count.byFields PostgresDb.TableName Any [ Field.NEX "Sub" ] let! noSubs = Count.byFields PostgresDb.TableName Any [ Field.NotExists "Sub" ]
Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" Expect.equal noSubs 4 "There should now be 4 documents without Sub fields"
let! noValue = Count.byFields PostgresDb.TableName Any [ Field.NEX "Value" ] let! noValue = Count.byFields PostgresDb.TableName Any [ Field.NotExists "Value" ]
Expect.equal noValue 0 "There should be no documents without Value fields" Expect.equal noValue 0 "There should be no documents without Value fields"
} }
testTask "succeeds when a field is not removed" { testTask "succeeds when a field is not removed" {
@ -1212,9 +1259,9 @@ let removeFieldsTests = testList "RemoveFields" [
do! loadDocs () do! loadDocs ()
do! RemoveFields.byJsonPath PostgresDb.TableName "$.NumValue ? (@ == 17)" [ "Sub"; "Value" ] do! RemoveFields.byJsonPath PostgresDb.TableName "$.NumValue ? (@ == 17)" [ "Sub"; "Value" ]
let! noSubs = Count.byFields PostgresDb.TableName Any [ Field.NEX "Sub" ] let! noSubs = Count.byFields PostgresDb.TableName Any [ Field.NotExists "Sub" ]
Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" Expect.equal noSubs 4 "There should now be 4 documents without Sub fields"
let! noValue = Count.byFields PostgresDb.TableName Any [ Field.NEX "Value" ] let! noValue = Count.byFields PostgresDb.TableName Any [ Field.NotExists "Value" ]
Expect.equal noValue 1 "There should be 1 document without Value fields" Expect.equal noValue 1 "There should be 1 document without Value fields"
} }
testTask "succeeds when a single field is removed" { testTask "succeeds when a single field is removed" {
@ -1222,9 +1269,9 @@ let removeFieldsTests = testList "RemoveFields" [
do! loadDocs () do! loadDocs ()
do! RemoveFields.byJsonPath PostgresDb.TableName "$.NumValue ? (@ == 17)" [ "Sub" ] do! RemoveFields.byJsonPath PostgresDb.TableName "$.NumValue ? (@ == 17)" [ "Sub" ]
let! noSubs = Count.byFields PostgresDb.TableName Any [ Field.NEX "Sub" ] let! noSubs = Count.byFields PostgresDb.TableName Any [ Field.NotExists "Sub" ]
Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" Expect.equal noSubs 4 "There should now be 4 documents without Sub fields"
let! noValue = Count.byFields PostgresDb.TableName Any [ Field.NEX "Value" ] let! noValue = Count.byFields PostgresDb.TableName Any [ Field.NotExists "Value" ]
Expect.equal noValue 0 "There should be no documents without Value fields" Expect.equal noValue 0 "There should be no documents without Value fields"
} }
testTask "succeeds when a field is not removed" { testTask "succeeds when a field is not removed" {
@ -1268,7 +1315,7 @@ let deleteTests = testList "Delete" [
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
do! Delete.byFields PostgresDb.TableName Any [ Field.EQ "Value" "purple" ] do! Delete.byFields PostgresDb.TableName Any [ Field.Equal "Value" "purple" ]
let! remaining = Count.all PostgresDb.TableName let! remaining = Count.all PostgresDb.TableName
Expect.equal remaining 3 "There should have been 3 documents remaining" Expect.equal remaining 3 "There should have been 3 documents remaining"
} }
@ -1276,7 +1323,7 @@ let deleteTests = testList "Delete" [
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
do! Delete.byFields PostgresDb.TableName Any [ Field.EQ "Value" "crimson" ] do! Delete.byFields PostgresDb.TableName Any [ Field.Equal "Value" "crimson" ]
let! remaining = Count.all PostgresDb.TableName let! remaining = Count.all PostgresDb.TableName
Expect.equal remaining 5 "There should have been 5 documents remaining" Expect.equal remaining 5 "There should have been 5 documents remaining"
} }

View File

@ -118,7 +118,7 @@ let integrationTests =
use conn = Configuration.dbConn () use conn = Configuration.dbConn ()
do! loadDocs () do! loadDocs ()
let! theCount = conn.countByFields SqliteDb.TableName Any [ Field.EQ "Value" "purple" ] let! theCount = conn.countByFields SqliteDb.TableName Any [ Field.Equal "Value" "purple" ]
Expect.equal theCount 2L "There should have been 2 matching documents" Expect.equal theCount 2L "There should have been 2 matching documents"
} }
testList "existsById" [ testList "existsById" [
@ -145,7 +145,7 @@ let integrationTests =
use conn = Configuration.dbConn () use conn = Configuration.dbConn ()
do! loadDocs () do! loadDocs ()
let! exists = conn.existsByFields SqliteDb.TableName Any [ Field.EQ "NumValue" 10 ] let! exists = conn.existsByFields SqliteDb.TableName Any [ Field.Equal "NumValue" 10 ]
Expect.isTrue exists "There should have been existing documents" Expect.isTrue exists "There should have been existing documents"
} }
testTask "succeeds when no matching documents exist" { testTask "succeeds when no matching documents exist" {
@ -153,7 +153,7 @@ let integrationTests =
use conn = Configuration.dbConn () use conn = Configuration.dbConn ()
do! loadDocs () do! loadDocs ()
let! exists = conn.existsByFields SqliteDb.TableName Any [ Field.EQ "Nothing" "none" ] let! exists = conn.existsByFields SqliteDb.TableName Any [ Field.Equal "Nothing" "none" ]
Expect.isFalse exists "There should not have been any existing documents" Expect.isFalse exists "There should not have been any existing documents"
} }
] ]
@ -244,7 +244,7 @@ let integrationTests =
use conn = Configuration.dbConn () use conn = Configuration.dbConn ()
do! loadDocs () do! loadDocs ()
let! docs = conn.findByFields<JsonDocument> SqliteDb.TableName Any [ Field.EQ "Sub.Foo" "green" ] let! docs = conn.findByFields<JsonDocument> SqliteDb.TableName Any [ Field.Equal "Sub.Foo" "green" ]
Expect.hasLength docs 2 "There should have been two documents returned" Expect.hasLength docs 2 "There should have been two documents returned"
} }
testTask "succeeds when documents are not found" { testTask "succeeds when documents are not found" {
@ -252,7 +252,7 @@ let integrationTests =
use conn = Configuration.dbConn () use conn = Configuration.dbConn ()
do! loadDocs () do! loadDocs ()
let! docs = conn.findByFields<JsonDocument> SqliteDb.TableName Any [ Field.EQ "Value" "mauve" ] let! docs = conn.findByFields<JsonDocument> SqliteDb.TableName Any [ Field.Equal "Value" "mauve" ]
Expect.isEmpty docs "There should have been no documents returned" Expect.isEmpty docs "There should have been no documents returned"
} }
] ]
@ -264,7 +264,7 @@ let integrationTests =
let! docs = let! docs =
conn.findByFieldsOrdered<JsonDocument> conn.findByFieldsOrdered<JsonDocument>
SqliteDb.TableName Any [ Field.GT "NumValue" 15 ] [ Field.Named "Id" ] SqliteDb.TableName Any [ Field.Greater "NumValue" 15 ] [ Field.Named "Id" ]
Expect.equal Expect.equal
(docs |> List.map _.Id |> String.concat "|") "five|four" "The documents were not ordered correctly" (docs |> List.map _.Id |> String.concat "|") "five|four" "The documents were not ordered correctly"
} }
@ -275,7 +275,7 @@ let integrationTests =
let! docs = let! docs =
conn.findByFieldsOrdered<JsonDocument> conn.findByFieldsOrdered<JsonDocument>
SqliteDb.TableName Any [ Field.GT "NumValue" 15 ] [ Field.Named "Id DESC" ] SqliteDb.TableName Any [ Field.Greater "NumValue" 15 ] [ Field.Named "Id DESC" ]
Expect.equal Expect.equal
(docs |> List.map _.Id |> String.concat "|") "four|five" "The documents were not ordered correctly" (docs |> List.map _.Id |> String.concat "|") "four|five" "The documents were not ordered correctly"
} }
@ -286,7 +286,7 @@ let integrationTests =
use conn = Configuration.dbConn () use conn = Configuration.dbConn ()
do! loadDocs () do! loadDocs ()
let! doc = conn.findFirstByFields<JsonDocument> SqliteDb.TableName Any [ Field.EQ "Value" "another" ] let! doc = conn.findFirstByFields<JsonDocument> SqliteDb.TableName Any [ Field.Equal "Value" "another" ]
Expect.isSome doc "There should have been a document returned" Expect.isSome doc "There should have been a document returned"
Expect.equal doc.Value.Id "two" "The incorrect document was returned" Expect.equal doc.Value.Id "two" "The incorrect document was returned"
} }
@ -295,7 +295,7 @@ let integrationTests =
use conn = Configuration.dbConn () use conn = Configuration.dbConn ()
do! loadDocs () do! loadDocs ()
let! doc = conn.findFirstByFields<JsonDocument> SqliteDb.TableName Any [ Field.EQ "Sub.Foo" "green" ] let! doc = conn.findFirstByFields<JsonDocument> SqliteDb.TableName Any [ Field.Equal "Sub.Foo" "green" ]
Expect.isSome doc "There should have been a document returned" Expect.isSome doc "There should have been a document returned"
Expect.contains [ "two"; "four" ] doc.Value.Id "An incorrect document was returned" Expect.contains [ "two"; "four" ] doc.Value.Id "An incorrect document was returned"
} }
@ -304,7 +304,7 @@ let integrationTests =
use conn = Configuration.dbConn () use conn = Configuration.dbConn ()
do! loadDocs () do! loadDocs ()
let! doc = conn.findFirstByFields<JsonDocument> SqliteDb.TableName Any [ Field.EQ "Value" "absent" ] let! doc = conn.findFirstByFields<JsonDocument> SqliteDb.TableName Any [ Field.Equal "Value" "absent" ]
Expect.isNone doc "There should not have been a document returned" Expect.isNone doc "There should not have been a document returned"
} }
] ]
@ -316,7 +316,7 @@ let integrationTests =
let! doc = let! doc =
conn.findFirstByFieldsOrdered<JsonDocument> conn.findFirstByFieldsOrdered<JsonDocument>
SqliteDb.TableName Any [ Field.EQ "Sub.Foo" "green" ] [ Field.Named "Sub.Bar" ] SqliteDb.TableName Any [ Field.Equal "Sub.Foo" "green" ] [ Field.Named "Sub.Bar" ]
Expect.isSome doc "There should have been a document returned" Expect.isSome doc "There should have been a document returned"
Expect.equal "two" doc.Value.Id "An incorrect document was returned" Expect.equal "two" doc.Value.Id "An incorrect document was returned"
} }
@ -327,7 +327,7 @@ let integrationTests =
let! doc = let! doc =
conn.findFirstByFieldsOrdered<JsonDocument> conn.findFirstByFieldsOrdered<JsonDocument>
SqliteDb.TableName Any [ Field.EQ "Sub.Foo" "green" ] [ Field.Named "Sub.Bar DESC" ] SqliteDb.TableName Any [ Field.Equal "Sub.Foo" "green" ] [ Field.Named "Sub.Bar DESC" ]
Expect.isSome doc "There should have been a document returned" Expect.isSome doc "There should have been a document returned"
Expect.equal "four" doc.Value.Id "An incorrect document was returned" Expect.equal "four" doc.Value.Id "An incorrect document was returned"
} }
@ -416,8 +416,8 @@ let integrationTests =
use conn = Configuration.dbConn () use conn = Configuration.dbConn ()
do! loadDocs () do! loadDocs ()
do! conn.patchByFields SqliteDb.TableName Any [ Field.EQ "Value" "purple" ] {| NumValue = 77 |} do! conn.patchByFields SqliteDb.TableName Any [ Field.Equal "Value" "purple" ] {| NumValue = 77 |}
let! after = conn.countByFields SqliteDb.TableName Any [ Field.EQ "NumValue" 77 ] let! after = conn.countByFields SqliteDb.TableName Any [ Field.Equal "NumValue" 77 ]
Expect.equal after 2L "There should have been 2 documents returned" Expect.equal after 2L "There should have been 2 documents returned"
} }
testTask "succeeds when no document is updated" { testTask "succeeds when no document is updated" {
@ -428,7 +428,7 @@ let integrationTests =
Expect.isEmpty before "There should have been no documents returned" Expect.isEmpty before "There should have been no documents returned"
// This not raising an exception is the test // This not raising an exception is the test
do! conn.patchByFields SqliteDb.TableName Any [ Field.EQ "Value" "burgundy" ] {| Foo = "green" |} do! conn.patchByFields SqliteDb.TableName Any [ Field.Equal "Value" "burgundy" ] {| Foo = "green" |}
} }
] ]
testList "removeFieldsById" [ testList "removeFieldsById" [
@ -467,7 +467,7 @@ let integrationTests =
use conn = Configuration.dbConn () use conn = Configuration.dbConn ()
do! loadDocs () do! loadDocs ()
do! conn.removeFieldsByFields SqliteDb.TableName Any [ Field.EQ "NumValue" 17 ] [ "Sub" ] do! conn.removeFieldsByFields SqliteDb.TableName Any [ Field.Equal "NumValue" 17 ] [ "Sub" ]
try try
let! _ = conn.findById<string, JsonDocument> SqliteDb.TableName "four" let! _ = conn.findById<string, JsonDocument> SqliteDb.TableName "four"
Expect.isTrue false "The updated document should have failed to parse" Expect.isTrue false "The updated document should have failed to parse"
@ -481,14 +481,15 @@ let integrationTests =
do! loadDocs () do! loadDocs ()
// This not raising an exception is the test // This not raising an exception is the test
do! conn.removeFieldsByFields SqliteDb.TableName Any [ Field.EQ "NumValue" 17 ] [ "Nothing" ] do! conn.removeFieldsByFields SqliteDb.TableName Any [ Field.Equal "NumValue" 17 ] [ "Nothing" ]
} }
testTask "succeeds when no document is matched" { testTask "succeeds when no document is matched" {
use! db = SqliteDb.BuildDb() use! db = SqliteDb.BuildDb()
use conn = Configuration.dbConn () use conn = Configuration.dbConn ()
// This not raising an exception is the test // This not raising an exception is the test
do! conn.removeFieldsByFields SqliteDb.TableName Any [ Field.NE "Abracadabra" "apple" ] [ "Value" ] do! conn.removeFieldsByFields
SqliteDb.TableName Any [ Field.NotEqual "Abracadabra" "apple" ] [ "Value" ]
} }
] ]
testList "deleteById" [ testList "deleteById" [
@ -517,7 +518,7 @@ let integrationTests =
use conn = Configuration.dbConn () use conn = Configuration.dbConn ()
do! loadDocs () do! loadDocs ()
do! conn.deleteByFields SqliteDb.TableName Any [ Field.NE "Value" "purple" ] do! conn.deleteByFields SqliteDb.TableName Any [ Field.NotEqual "Value" "purple" ]
let! remaining = conn.countAll SqliteDb.TableName let! remaining = conn.countAll SqliteDb.TableName
Expect.equal remaining 2L "There should have been 2 documents remaining" Expect.equal remaining 2L "There should have been 2 documents remaining"
} }
@ -526,7 +527,7 @@ let integrationTests =
use conn = Configuration.dbConn () use conn = Configuration.dbConn ()
do! loadDocs () do! loadDocs ()
do! conn.deleteByFields SqliteDb.TableName Any [ Field.EQ "Value" "crimson" ] do! conn.deleteByFields SqliteDb.TableName Any [ Field.Equal "Value" "crimson" ]
let! remaining = conn.countAll SqliteDb.TableName let! remaining = conn.countAll SqliteDb.TableName
Expect.equal remaining 5L "There should have been 5 documents remaining" Expect.equal remaining 5L "There should have been 5 documents remaining"
} }

View File

@ -15,42 +15,54 @@ open Types
/// Unit tests for the Query module of the SQLite library /// Unit tests for the Query module of the SQLite library
let queryTests = testList "Query" [ let queryTests = testList "Query" [
testList "whereByFields" [ testList "whereByFields" [
test "succeeds for a single field when a logical operator is passed" { test "succeeds for a single field when a logical comparison is passed" {
Expect.equal Expect.equal
(Query.whereByFields Any [ { Field.GT "theField" 0 with ParameterName = Some "@test" } ]) (Query.whereByFields Any [ { Field.Greater "theField" 0 with ParameterName = Some "@test" } ])
"data->>'theField' > @test" "data->>'theField' > @test"
"WHERE clause not correct" "WHERE clause not correct"
} }
test "succeeds for a single field when an existence operator is passed" { test "succeeds for a single field when an existence comparison is passed" {
Expect.equal Expect.equal
(Query.whereByFields Any [ Field.NEX "thatField" ]) (Query.whereByFields Any [ Field.NotExists "thatField" ])
"data->>'thatField' IS NULL" "data->>'thatField' IS NULL"
"WHERE clause not correct" "WHERE clause not correct"
} }
test "succeeds for a single field when a between operator is passed" { test "succeeds for a single field when a between comparison is passed" {
Expect.equal Expect.equal
(Query.whereByFields All [ { Field.BT "aField" 50 99 with ParameterName = Some "@range" } ]) (Query.whereByFields All [ { Field.Between "aField" 50 99 with ParameterName = Some "@range" } ])
"data->>'aField' BETWEEN @rangemin AND @rangemax" "data->>'aField' BETWEEN @rangemin AND @rangemax"
"WHERE clause not correct" "WHERE clause not correct"
} }
test "succeeds for all multiple fields with logical operators" { test "succeeds for all multiple fields with logical comparisons" {
Expect.equal Expect.equal
(Query.whereByFields All [ Field.EQ "theFirst" "1"; Field.EQ "numberTwo" "2" ]) (Query.whereByFields All [ Field.Equal "theFirst" "1"; Field.Equal "numberTwo" "2" ])
"data->>'theFirst' = @field0 AND data->>'numberTwo' = @field1" "data->>'theFirst' = @field0 AND data->>'numberTwo' = @field1"
"WHERE clause not correct" "WHERE clause not correct"
} }
test "succeeds for any multiple fields with an existence operator" { test "succeeds for any multiple fields with an existence comparison" {
Expect.equal Expect.equal
(Query.whereByFields Any [ Field.NEX "thatField"; Field.GE "thisField" 18 ]) (Query.whereByFields Any [ Field.NotExists "thatField"; Field.GreaterOrEqual "thisField" 18 ])
"data->>'thatField' IS NULL OR data->>'thisField' >= @field0" "data->>'thatField' IS NULL OR data->>'thisField' >= @field0"
"WHERE clause not correct" "WHERE clause not correct"
} }
test "succeeds for all multiple fields with between operators" { test "succeeds for all multiple fields with between comparisons" {
Expect.equal Expect.equal
(Query.whereByFields All [ Field.BT "aField" 50 99; Field.BT "anotherField" "a" "b" ]) (Query.whereByFields All [ Field.Between "aField" 50 99; Field.Between "anotherField" "a" "b" ])
"data->>'aField' BETWEEN @field0min AND @field0max AND data->>'anotherField' BETWEEN @field1min AND @field1max" "data->>'aField' BETWEEN @field0min AND @field0max AND data->>'anotherField' BETWEEN @field1min AND @field1max"
"WHERE clause not correct" "WHERE clause not correct"
} }
test "succeeds for a field with an In comparison" {
Expect.equal
(Query.whereByFields All [ Field.In "this" [ "a"; "b"; "c" ] ])
"data->>'this' IN (@field0_0, @field0_1, @field0_2)"
"WHERE clause not correct"
}
test "succeeds for a field with an InArray comparison" {
Expect.equal
(Query.whereByFields All [ Field.InArray "this" "the_table" [ "a"; "b" ] ])
"EXISTS (SELECT 1 FROM json_each(the_table.data, '$.this') WHERE value IN (@field0_0, @field0_1))"
"WHERE clause not correct"
}
] ]
test "whereById succeeds" { test "whereById succeeds" {
Expect.equal (Query.whereById "@id") "data->>'Id' = @id" "WHERE clause not correct" Expect.equal (Query.whereById "@id") "data->>'Id' = @id" "WHERE clause not correct"
@ -72,7 +84,7 @@ let queryTests = testList "Query" [
} }
test "byFields succeeds" { test "byFields succeeds" {
Expect.equal Expect.equal
(Query.byFields "unit" Any [ Field.GT "That" 14 ]) (Query.byFields "unit" Any [ Field.Greater "That" 14 ])
"unit WHERE data->>'That' > @field0" "unit WHERE data->>'That' > @field0"
"By-Field query not correct" "By-Field query not correct"
} }
@ -98,14 +110,14 @@ let parametersTests = testList "Parameters" [
} }
testList "addFieldParam" [ testList "addFieldParam" [
test "succeeds when adding a parameter" { test "succeeds when adding a parameter" {
let paramList = addFieldParam "@field" (Field.EQ "it" 99) [] let paramList = addFieldParam "@field" (Field.Equal "it" 99) []
Expect.hasLength paramList 1 "There should have been a parameter added" Expect.hasLength paramList 1 "There should have been a parameter added"
let theParam = Seq.head paramList let theParam = Seq.head paramList
Expect.equal theParam.ParameterName "@field" "The parameter name is incorrect" Expect.equal theParam.ParameterName "@field" "The parameter name is incorrect"
Expect.equal theParam.Value 99 "The parameter value is incorrect" Expect.equal theParam.Value 99 "The parameter value is incorrect"
} }
test "succeeds when not adding a parameter" { test "succeeds when not adding a parameter" {
let paramList = addFieldParam "@it" (Field.NEX "Coffee") [] let paramList = addFieldParam "@it" (Field.NotExists "Coffee") []
Expect.isEmpty paramList "There should not have been any parameters added" Expect.isEmpty paramList "There should not have been any parameters added"
} }
] ]
@ -380,14 +392,14 @@ let countTests = testList "Count" [
use! db = SqliteDb.BuildDb() use! db = SqliteDb.BuildDb()
do! loadDocs () do! loadDocs ()
let! theCount = Count.byFields SqliteDb.TableName Any [ Field.BT "NumValue" 10 20 ] let! theCount = Count.byFields SqliteDb.TableName Any [ Field.Between "NumValue" 10 20 ]
Expect.equal theCount 3L "There should have been 3 matching documents" Expect.equal theCount 3L "There should have been 3 matching documents"
} }
testTask "succeeds for a non-numeric range" { testTask "succeeds for a non-numeric range" {
use! db = SqliteDb.BuildDb() use! db = SqliteDb.BuildDb()
do! loadDocs () do! loadDocs ()
let! theCount = Count.byFields SqliteDb.TableName Any [ Field.BT "Value" "aardvark" "apple" ] let! theCount = Count.byFields SqliteDb.TableName Any [ Field.Between "Value" "aardvark" "apple" ]
Expect.equal theCount 1L "There should have been 1 matching document" Expect.equal theCount 1L "There should have been 1 matching document"
} }
] ]
@ -416,14 +428,14 @@ let existsTests = testList "Exists" [
use! db = SqliteDb.BuildDb() use! db = SqliteDb.BuildDb()
do! loadDocs () do! loadDocs ()
let! exists = Exists.byFields SqliteDb.TableName Any [ Field.EQ "NumValue" 10 ] let! exists = Exists.byFields SqliteDb.TableName Any [ Field.Equal "NumValue" 10 ]
Expect.isTrue exists "There should have been existing documents" Expect.isTrue exists "There should have been existing documents"
} }
testTask "succeeds when no matching documents exist" { testTask "succeeds when no matching documents exist" {
use! db = SqliteDb.BuildDb() use! db = SqliteDb.BuildDb()
do! loadDocs () do! loadDocs ()
let! exists = Exists.byFields SqliteDb.TableName Any [ Field.LT "Nothing" "none" ] let! exists = Exists.byFields SqliteDb.TableName Any [ Field.Less "Nothing" "none" ]
Expect.isFalse exists "There should not have been any existing documents" Expect.isFalse exists "There should not have been any existing documents"
} }
] ]
@ -508,16 +520,43 @@ let findTests = testList "Find" [
use! db = SqliteDb.BuildDb() use! db = SqliteDb.BuildDb()
do! loadDocs () do! loadDocs ()
let! docs = Find.byFields<JsonDocument> SqliteDb.TableName Any [ Field.GT "NumValue" 15 ] let! docs = Find.byFields<JsonDocument> SqliteDb.TableName Any [ Field.Greater "NumValue" 15 ]
Expect.equal (List.length docs) 2 "There should have been two documents returned" Expect.hasLength docs 2 "There should have been two documents returned"
}
testTask "succeeds when documents are found using IN with numeric field" {
use! db = SqliteDb.BuildDb()
do! loadDocs ()
let! docs = Find.byFields<JsonDocument> SqliteDb.TableName All [ Field.In "NumValue" [ 2; 4; 6; 8 ] ]
Expect.hasLength docs 1 "There should have been one document returned"
} }
testTask "succeeds when documents are not found" { testTask "succeeds when documents are not found" {
use! db = SqliteDb.BuildDb() use! db = SqliteDb.BuildDb()
do! loadDocs () do! loadDocs ()
let! docs = Find.byFields<JsonDocument> SqliteDb.TableName Any [ Field.GT "NumValue" 100 ] let! docs = Find.byFields<JsonDocument> SqliteDb.TableName Any [ Field.Greater "NumValue" 100 ]
Expect.isTrue (List.isEmpty docs) "There should have been no documents returned" Expect.isTrue (List.isEmpty docs) "There should have been no documents returned"
} }
testTask "succeeds for InArray when matching documents exist" {
use! db = SqliteDb.BuildDb()
do! Definition.ensureTable SqliteDb.TableName
for doc in ArrayDocument.TestDocuments do do! insert SqliteDb.TableName doc
let! docs =
Find.byFields<ArrayDocument>
SqliteDb.TableName All [ Field.InArray "Values" SqliteDb.TableName [ "c" ] ]
Expect.hasLength docs 2 "There should have been two documents returned"
}
testTask "succeeds for InArray when no matching documents exist" {
use! db = SqliteDb.BuildDb()
do! Definition.ensureTable SqliteDb.TableName
for doc in ArrayDocument.TestDocuments do do! insert SqliteDb.TableName doc
let! docs =
Find.byFields<ArrayDocument>
SqliteDb.TableName All [ Field.InArray "Values" SqliteDb.TableName [ "j" ] ]
Expect.isEmpty docs "There should have been no documents returned"
}
] ]
testList "byFieldsOrdered" [ testList "byFieldsOrdered" [
testTask "succeeds when sorting ascending" { testTask "succeeds when sorting ascending" {
@ -526,7 +565,7 @@ let findTests = testList "Find" [
let! docs = let! docs =
Find.byFieldsOrdered<JsonDocument> Find.byFieldsOrdered<JsonDocument>
SqliteDb.TableName Any [ Field.GT "NumValue" 15 ] [ Field.Named "Id" ] SqliteDb.TableName Any [ Field.Greater "NumValue" 15 ] [ Field.Named "Id" ]
Expect.hasLength docs 2 "There should have been two documents returned" Expect.hasLength docs 2 "There should have been two documents returned"
Expect.equal Expect.equal
(docs |> List.map _.Id |> String.concat "|") "five|four" "The documents were not ordered correctly" (docs |> List.map _.Id |> String.concat "|") "five|four" "The documents were not ordered correctly"
@ -537,7 +576,7 @@ let findTests = testList "Find" [
let! docs = let! docs =
Find.byFieldsOrdered<JsonDocument> Find.byFieldsOrdered<JsonDocument>
SqliteDb.TableName Any [ Field.GT "NumValue" 15 ] [ Field.Named "Id DESC" ] SqliteDb.TableName Any [ Field.Greater "NumValue" 15 ] [ Field.Named "Id DESC" ]
Expect.hasLength docs 2 "There should have been two documents returned" Expect.hasLength docs 2 "There should have been two documents returned"
Expect.equal Expect.equal
(docs |> List.map _.Id |> String.concat "|") "four|five" "The documents were not ordered correctly" (docs |> List.map _.Id |> String.concat "|") "four|five" "The documents were not ordered correctly"
@ -548,7 +587,7 @@ let findTests = testList "Find" [
let! docs = let! docs =
Find.byFieldsOrdered<JsonDocument> Find.byFieldsOrdered<JsonDocument>
SqliteDb.TableName All [ Field.LE "NumValue" 10 ] [ Field.Named "Value" ] SqliteDb.TableName All [ Field.LessOrEqual "NumValue" 10 ] [ Field.Named "Value" ]
Expect.hasLength docs 3 "There should have been three documents returned" Expect.hasLength docs 3 "There should have been three documents returned"
Expect.equal Expect.equal
(docs |> List.map _.Id |> String.concat "|") "three|one|two" "Documents not ordered correctly" (docs |> List.map _.Id |> String.concat "|") "three|one|two" "Documents not ordered correctly"
@ -559,7 +598,7 @@ let findTests = testList "Find" [
let! docs = let! docs =
Find.byFieldsOrdered<JsonDocument> Find.byFieldsOrdered<JsonDocument>
SqliteDb.TableName All [ Field.LE "NumValue" 10 ] [ Field.Named "i:Value" ] SqliteDb.TableName All [ Field.LessOrEqual "NumValue" 10 ] [ Field.Named "i:Value" ]
Expect.hasLength docs 3 "There should have been three documents returned" Expect.hasLength docs 3 "There should have been three documents returned"
Expect.equal Expect.equal
(docs |> List.map _.Id |> String.concat "|") "three|two|one" "Documents not ordered correctly" (docs |> List.map _.Id |> String.concat "|") "three|two|one" "Documents not ordered correctly"
@ -570,7 +609,7 @@ let findTests = testList "Find" [
use! db = SqliteDb.BuildDb() use! db = SqliteDb.BuildDb()
do! loadDocs () do! loadDocs ()
let! doc = Find.firstByFields<JsonDocument> SqliteDb.TableName Any [ Field.EQ "Value" "another" ] let! doc = Find.firstByFields<JsonDocument> SqliteDb.TableName Any [ Field.Equal "Value" "another" ]
Expect.isSome doc "There should have been a document returned" Expect.isSome doc "There should have been a document returned"
Expect.equal doc.Value.Id "two" "The incorrect document was returned" Expect.equal doc.Value.Id "two" "The incorrect document was returned"
} }
@ -578,7 +617,7 @@ let findTests = testList "Find" [
use! db = SqliteDb.BuildDb() use! db = SqliteDb.BuildDb()
do! loadDocs () do! loadDocs ()
let! doc = Find.firstByFields<JsonDocument> SqliteDb.TableName Any [ Field.EQ "Sub.Foo" "green" ] let! doc = Find.firstByFields<JsonDocument> SqliteDb.TableName Any [ Field.Equal "Sub.Foo" "green" ]
Expect.isSome doc "There should have been a document returned" Expect.isSome doc "There should have been a document returned"
Expect.contains [ "two"; "four" ] doc.Value.Id "An incorrect document was returned" Expect.contains [ "two"; "four" ] doc.Value.Id "An incorrect document was returned"
} }
@ -586,7 +625,7 @@ let findTests = testList "Find" [
use! db = SqliteDb.BuildDb() use! db = SqliteDb.BuildDb()
do! loadDocs () do! loadDocs ()
let! doc = Find.firstByFields<JsonDocument> SqliteDb.TableName Any [ Field.EQ "Value" "absent" ] let! doc = Find.firstByFields<JsonDocument> SqliteDb.TableName Any [ Field.Equal "Value" "absent" ]
Expect.isNone doc "There should not have been a document returned" Expect.isNone doc "There should not have been a document returned"
} }
] ]
@ -597,7 +636,7 @@ let findTests = testList "Find" [
let! doc = let! doc =
Find.firstByFieldsOrdered<JsonDocument> Find.firstByFieldsOrdered<JsonDocument>
SqliteDb.TableName Any [ Field.EQ "Sub.Foo" "green" ] [ Field.Named "Sub.Bar" ] SqliteDb.TableName Any [ Field.Equal "Sub.Foo" "green" ] [ Field.Named "Sub.Bar" ]
Expect.isSome doc "There should have been a document returned" Expect.isSome doc "There should have been a document returned"
Expect.equal "two" doc.Value.Id "An incorrect document was returned" Expect.equal "two" doc.Value.Id "An incorrect document was returned"
} }
@ -607,7 +646,7 @@ let findTests = testList "Find" [
let! doc = let! doc =
Find.firstByFieldsOrdered<JsonDocument> Find.firstByFieldsOrdered<JsonDocument>
SqliteDb.TableName Any [ Field.EQ "Sub.Foo" "green" ] [ Field.Named "Sub.Bar DESC" ] SqliteDb.TableName Any [ Field.Equal "Sub.Foo" "green" ] [ Field.Named "Sub.Bar DESC" ]
Expect.isSome doc "There should have been a document returned" Expect.isSome doc "There should have been a document returned"
Expect.equal "four" doc.Value.Id "An incorrect document was returned" Expect.equal "four" doc.Value.Id "An incorrect document was returned"
} }
@ -690,8 +729,8 @@ let patchTests = testList "Patch" [
use! db = SqliteDb.BuildDb() use! db = SqliteDb.BuildDb()
do! loadDocs () do! loadDocs ()
do! Patch.byFields SqliteDb.TableName Any [ Field.EQ "Value" "purple" ] {| NumValue = 77 |} do! Patch.byFields SqliteDb.TableName Any [ Field.Equal "Value" "purple" ] {| NumValue = 77 |}
let! after = Count.byFields SqliteDb.TableName Any [ Field.EQ "NumValue" 77 ] let! after = Count.byFields SqliteDb.TableName Any [ Field.Equal "NumValue" 77 ]
Expect.equal after 2L "There should have been 2 documents returned" Expect.equal after 2L "There should have been 2 documents returned"
} }
testTask "succeeds when no document is updated" { testTask "succeeds when no document is updated" {
@ -701,7 +740,7 @@ let patchTests = testList "Patch" [
Expect.isEmpty before "There should have been no documents returned" Expect.isEmpty before "There should have been no documents returned"
// This not raising an exception is the test // This not raising an exception is the test
do! Patch.byFields SqliteDb.TableName Any [ Field.EQ "Value" "burgundy" ] {| Foo = "green" |} do! Patch.byFields SqliteDb.TableName Any [ Field.Equal "Value" "burgundy" ] {| Foo = "green" |}
} }
] ]
] ]
@ -740,7 +779,7 @@ let removeFieldsTests = testList "RemoveFields" [
use! db = SqliteDb.BuildDb() use! db = SqliteDb.BuildDb()
do! loadDocs () do! loadDocs ()
do! RemoveFields.byFields SqliteDb.TableName Any [ Field.EQ "NumValue" 17 ] [ "Sub" ] do! RemoveFields.byFields SqliteDb.TableName Any [ Field.Equal "NumValue" 17 ] [ "Sub" ]
try try
let! _ = Find.byId<string, JsonDocument> SqliteDb.TableName "four" let! _ = Find.byId<string, JsonDocument> SqliteDb.TableName "four"
Expect.isTrue false "The updated document should have failed to parse" Expect.isTrue false "The updated document should have failed to parse"
@ -753,13 +792,13 @@ let removeFieldsTests = testList "RemoveFields" [
do! loadDocs () do! loadDocs ()
// This not raising an exception is the test // This not raising an exception is the test
do! RemoveFields.byFields SqliteDb.TableName Any [ Field.EQ "NumValue" 17 ] [ "Nothing" ] do! RemoveFields.byFields SqliteDb.TableName Any [ Field.Equal "NumValue" 17 ] [ "Nothing" ]
} }
testTask "succeeds when no document is matched" { testTask "succeeds when no document is matched" {
use! db = SqliteDb.BuildDb() use! db = SqliteDb.BuildDb()
// This not raising an exception is the test // This not raising an exception is the test
do! RemoveFields.byFields SqliteDb.TableName Any [ Field.NE "Abracadabra" "apple" ] [ "Value" ] do! RemoveFields.byFields SqliteDb.TableName Any [ Field.NotEqual "Abracadabra" "apple" ] [ "Value" ]
} }
] ]
] ]
@ -789,7 +828,7 @@ let deleteTests = testList "Delete" [
use! db = SqliteDb.BuildDb() use! db = SqliteDb.BuildDb()
do! loadDocs () do! loadDocs ()
do! Delete.byFields SqliteDb.TableName Any [ Field.NE "Value" "purple" ] do! Delete.byFields SqliteDb.TableName Any [ Field.NotEqual "Value" "purple" ]
let! remaining = Count.all SqliteDb.TableName let! remaining = Count.all SqliteDb.TableName
Expect.equal remaining 2L "There should have been 2 documents remaining" Expect.equal remaining 2L "There should have been 2 documents remaining"
} }
@ -797,7 +836,7 @@ let deleteTests = testList "Delete" [
use! db = SqliteDb.BuildDb() use! db = SqliteDb.BuildDb()
do! loadDocs () do! loadDocs ()
do! Delete.byFields SqliteDb.TableName Any [ Field.EQ "Value" "crimson" ] do! Delete.byFields SqliteDb.TableName Any [ Field.Equal "Value" "crimson" ]
let! remaining = Count.all SqliteDb.TableName let! remaining = Count.all SqliteDb.TableName
Expect.equal remaining 5L "There should have been 5 documents remaining" Expect.equal remaining 5L "There should have been 5 documents remaining"
} }

View File

@ -8,20 +8,32 @@ type SubDocument =
{ Foo: string { Foo: string
Bar: string } Bar: string }
type ArrayDocument =
{ Id: string
Values: string list }
with
/// <summary>
/// A set of documents used for integration tests
/// </summary>
static member TestDocuments =
[ { Id = "first"; Values = [ "a"; "b"; "c" ] }
{ Id = "second"; Values = [ "c"; "d"; "e" ] }
{ Id = "third"; Values = [ "x"; "y"; "z" ] } ]
type JsonDocument = type JsonDocument =
{ Id: string { Id: string
Value: string Value: string
NumValue: int NumValue: int
Sub: SubDocument option } Sub: SubDocument option }
/// An empty JsonDocument /// An empty JsonDocument
let emptyDoc = { Id = ""; Value = ""; NumValue = 0; Sub = None } let emptyDoc = { Id = ""; Value = ""; NumValue = 0; Sub = None }
/// Documents to use for testing /// Documents to use for testing
let testDocuments = [ let testDocuments =
{ Id = "one"; Value = "FIRST!"; NumValue = 0; Sub = None } [ { Id = "one"; Value = "FIRST!"; NumValue = 0; Sub = None }
{ Id = "two"; Value = "another"; NumValue = 10; Sub = Some { Foo = "green"; Bar = "blue" } } { Id = "two"; Value = "another"; NumValue = 10; Sub = Some { Foo = "green"; Bar = "blue" } }
{ Id = "three"; Value = ""; NumValue = 4; Sub = None } { Id = "three"; Value = ""; NumValue = 4; Sub = None }
{ Id = "four"; Value = "purple"; NumValue = 17; Sub = Some { Foo = "green"; Bar = "red" } } { Id = "four"; Value = "purple"; NumValue = 17; Sub = Some { Foo = "green"; Bar = "red" } }
{ Id = "five"; Value = "purple"; NumValue = 18; Sub = None } { Id = "five"; Value = "purple"; NumValue = 18; Sub = None } ]
]