RC4 changes #7

Merged
danieljsummers merged 7 commits from arr-cee-four into main 2024-09-17 02:33:57 +00:00
9 changed files with 197 additions and 39 deletions
Showing only changes of commit 1c5b8042de - Show all commits

View File

@ -38,7 +38,7 @@ type Comparison =
| NotEqual _ -> "<>" | NotEqual _ -> "<>"
| Between _ -> "BETWEEN" | Between _ -> "BETWEEN"
| In _ -> "IN" | In _ -> "IN"
| InArray _ -> "|?" // PostgreSQL only; SQL needs a subquery for this | InArray _ -> "?|" // PostgreSQL only; SQL needs a subquery for this
| Exists -> "IS NOT NULL" | Exists -> "IS NOT NULL"
| NotExists -> "IS NULL" | NotExists -> "IS NULL"
@ -120,20 +120,24 @@ with
/// Create a not equals (<>) field criterion (alias) /// Create a not equals (<>) field criterion (alias)
static member NE name (value: obj) = Field.NotEqual name value static member NE name (value: obj) = Field.NotEqual name value
/// Create a BETWEEN field criterion /// Create a Between field criterion
static member Between name (min: obj) (max: obj) = static member Between name (min: obj) (max: obj) =
Field.Where name (Between(min, max)) Field.Where name (Between(min, max))
/// Create a BETWEEN field criterion (alias) /// Create a Between field criterion (alias)
static member BT name (min: obj) (max: obj) = Field.Between name min max static member BT name (min: obj) (max: obj) = Field.Between name min max
/// Create an IN field criterion /// Create an In field criterion
static member In name (values: obj seq) = static member In name (values: obj seq) =
Field.Where name (In values) Field.Where name (In values)
/// Create an IN field criterion (alias) /// Create an In field criterion (alias)
static member IN name (values: obj seq) = Field.In name values 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 Exists name = static member Exists name =
Field.Where name Exists Field.Where name Exists

View File

@ -59,7 +59,7 @@ public static class CommonCSharpTests
}), }),
TestCase("InArray succeeds", () => TestCase("InArray succeeds", () =>
{ {
Expect.equal(Comparison.NewInArray("", []).OpSql, "|?", "The InArray SQL was not correct"); Expect.equal(Comparison.NewInArray("", []).OpSql, "?|", "The InArray SQL was not correct");
}), }),
TestCase("Exists succeeds", () => TestCase("Exists succeeds", () =>
{ {
@ -125,6 +125,15 @@ public static class CommonCSharpTests
Expect.isTrue(field.Comparison.IsIn, "Comparison incorrect"); Expect.isTrue(field.Comparison.IsIn, "Comparison incorrect");
Expect.sequenceEqual(((Comparison.In)field.Comparison).Values, [8, 16, 32], "Value 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", () => TestCase("Exists succeeds", () =>
{ {
var field = Field.Exists("Groovy"); var field = Field.Exists("Groovy");

View File

@ -184,40 +184,40 @@ 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.Greater("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.NotExists("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.Between("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.Between("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.Equal("theFirst", "1"), Field.Equal("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,
@ -225,13 +225,19 @@ public static class PostgresCSharpTests
"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.Between("aField", 50, 99), Field.Between("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",
@ -890,6 +896,26 @@ public static class PostgresCSharpTests
var docs = await Find.ByFields<JsonDocument>(PostgresDb.TableName, FieldMatch.Any, var docs = await Find.ByFields<JsonDocument>(PostgresDb.TableName, FieldMatch.Any,
[Field.Equal("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");
}),
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");
}) })
]), ]),
TestList("ByFieldsOrdered", TestList("ByFieldsOrdered",

View File

@ -59,6 +59,18 @@ public static class SqliteCSharpTests
[Field.Between("aField", 50, 99), Field.Between("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", () =>
@ -619,6 +631,26 @@ public static class SqliteCSharpTests
var docs = await Find.ByFields<JsonDocument>(SqliteDb.TableName, FieldMatch.Any, var docs = await Find.ByFields<JsonDocument>(SqliteDb.TableName, FieldMatch.Any,
[Field.Equal("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");
}),
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");
}) })
]), ]),
TestList("ByFieldsOrdered", TestList("ByFieldsOrdered",

View File

@ -31,3 +31,19 @@ public class JsonDocument
new() { Id = "five", Value = "purple", NumValue = 18 } 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

@ -33,7 +33,7 @@ let comparisonTests = testList "Comparison.OpSql" [
Expect.equal (In []).OpSql "IN" "The In SQL was not correct" Expect.equal (In []).OpSql "IN" "The In SQL was not correct"
} }
test "InArray succeeds" { test "InArray succeeds" {
Expect.equal (InArray("", [])).OpSql "|?" "The InArray SQL was not correct" Expect.equal (InArray("", [])).OpSql "?|" "The InArray SQL was not correct"
} }
test "Exists succeeds" { test "Exists succeeds" {
Expect.equal Exists.OpSql "IS NOT NULL" "The Exists SQL was not correct" Expect.equal Exists.OpSql "IS NOT NULL" "The Exists SQL was not correct"
@ -101,6 +101,13 @@ let fieldTests = testList "Field" [
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 "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" { test "Exists succeeds" {
let field = Field.Exists "Groovy" let field = Field.Exists "Groovy"
Expect.equal field.Name "Groovy" "Field name incorrect" Expect.equal field.Name "Groovy" "Field name incorrect"

View File

@ -135,60 +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.Greater "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.NotExists "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.Between "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.Between "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.Equal "theFirst" "1"; Field.Equal "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.NotExists "thatField"; Field.GreaterOrEqual "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.Between "aField" 50 99; Field.Between "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 operator with alphanumeric values" { test "succeeds for a field with an In comparison with alphanumeric values" {
Expect.equal Expect.equal
(Query.whereByFields All [ Field.In "this" [ "a"; "b"; "c" ] ]) (Query.whereByFields All [ Field.In "this" [ "a"; "b"; "c" ] ])
"data->>'this' IN (@field0_0, @field0_1, @field0_2)" "data->>'this' IN (@field0_0, @field0_1, @field0_2)"
"WHERE clause not correct" "WHERE clause not correct"
} }
test "succeeds for a field with an IN operator with numeric values" { test "succeeds for a field with an In comparison with numeric values" {
Expect.equal Expect.equal
(Query.whereByFields All [ Field.In "this" [ 7; 14; 21 ] ]) (Query.whereByFields All [ Field.In "this" [ 7; 14; 21 ] ])
"(data->>'this')::numeric IN (@field0_0, @field0_1, @field0_2)" "(data->>'this')::numeric IN (@field0_0, @field0_1, @field0_2)"
"WHERE clause not correct" "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" {
@ -740,6 +746,26 @@ let findTests = testList "Find" [
PostgresDb.TableName All [ Field.Equal "Value" "mauve"; Field.NotEqual "NumValue" 40 ] PostgresDb.TableName All [ Field.Equal "Value" "mauve"; Field.NotEqual "NumValue" 40 ]
Expect.isEmpty docs "There should have been no documents returned" 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"
}
] ]
testList "byFieldsOrdered" [ testList "byFieldsOrdered" [
testTask "succeeds when sorting ascending" { testTask "succeeds when sorting ascending" {

View File

@ -15,48 +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.Greater "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.NotExists "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.Between "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.Equal "theFirst" "1"; Field.Equal "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.NotExists "thatField"; Field.GreaterOrEqual "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.Between "aField" 50 99; Field.Between "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 operator" { test "succeeds for a field with an In comparison" {
Expect.equal Expect.equal
(Query.whereByFields All [ Field.In "this" [ "a"; "b"; "c" ] ]) (Query.whereByFields All [ Field.In "this" [ "a"; "b"; "c" ] ])
"data->>'this' IN (@field0_0, @field0_1, @field0_2)" "data->>'this' IN (@field0_0, @field0_1, @field0_2)"
"WHERE clause not correct" "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"
@ -531,6 +537,26 @@ let findTests = testList "Find" [
let! docs = Find.byFields<JsonDocument> SqliteDb.TableName Any [ Field.Greater "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" {

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