Version 4 #6

Merged
danieljsummers merged 30 commits from version-four into main 2024-08-19 23:30:39 +00:00
3 changed files with 270 additions and 154 deletions
Showing only changes of commit d9d37f110d - Show all commits

View File

@ -46,6 +46,23 @@ module private Helpers =
()
}
/// Create a numerically-typed parameter, or use the given parameter derivation function if non-(numeric or string)
let internal parameterFor<'T> (value: 'T) (catchAllFunc: 'T -> SqlValue) =
match box value with
| :? int8 as it -> Sql.int8 it
| :? uint8 as it -> Sql.int8 (int8 it)
| :? int16 as it -> Sql.int16 it
| :? uint16 as it -> Sql.int16 (int16 it)
| :? int as it -> Sql.int it
| :? uint32 as it -> Sql.int (int it)
| :? int64 as it -> Sql.int64 it
| :? uint64 as it -> Sql.int64 (int64 it)
| :? decimal as it -> Sql.decimal it
| :? single as it -> Sql.double (double it)
| :? double as it -> Sql.double it
| :? string as it -> Sql.string it
| _ -> catchAllFunc value
open BitBadger.Documents
@ -56,21 +73,7 @@ module Parameters =
/// Create an ID parameter (name "@id", key will be treated as a string)
[<CompiledName "Id">]
let idParam (key: 'TKey) =
match box key with
| :? int8 as it -> Sql.int8 it
| :? uint8 as it -> Sql.int8 (int8 it)
| :? int16 as it -> Sql.int16 it
| :? uint16 as it -> Sql.int16 (int16 it)
| :? int as it -> Sql.int it
| :? uint32 as it -> Sql.int (int it)
| :? int64 as it -> Sql.int64 it
| :? uint64 as it -> Sql.int64 (int64 it)
| :? decimal as it -> Sql.decimal it
| :? single as it -> Sql.double (double it)
| :? double as it -> Sql.double it
| :? string as it -> Sql.string it
| _ -> Sql.string (string key)
|> function it -> "@id", it
"@id", parameterFor key (fun it -> Sql.string (string it))
/// Create a parameter with a JSON value
[<CompiledName "Json">]
@ -89,11 +92,13 @@ module Parameters =
| BT ->
let p = name.Derive it.ParameterName
let values = it.Value :?> obj list
yield ($"{p}min", Sql.parameter (NpgsqlParameter($"{p}min", List.head values)))
yield ($"{p}max", Sql.parameter (NpgsqlParameter($"{p}max", List.last values)))
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
yield (p, Sql.parameter (NpgsqlParameter(p, it.Value))) })
yield (p, parameterFor it.Value (fun v -> Sql.parameter (NpgsqlParameter(p, v)))) })
|> Seq.collect id
|> Seq.append parameters
|> Seq.toList
@ -131,27 +136,30 @@ module Query =
[<CompiledName "WhereByFields">]
let whereByFields howMatched fields =
let name = ParameterName()
let isNumeric (it: obj) =
match it with
| :? int8 | :? uint8 | :? int16 | :? uint16 | :? int | :? uint32 | :? int64 | :? uint64
| :? decimal | :? single | :? double -> true
| _ -> false
fields
|> Seq.map (fun it ->
match it.Op with
| EX | NEX -> $"{it.Path PostgreSQL} {it.Op}"
| BT ->
let p = name.Derive it.ParameterName
let path, value =
| _ ->
let p = name.Derive it.ParameterName
let param, value =
match it.Op with
| BT -> $"{p}min AND {p}max", (it.Value :?> obj list)[0]
| _ -> p, it.Value
match value with
| :? int8 | :? uint8 | :? int16 | :? uint16 | :? int | :? uint32 | :? int64 | :? uint64
| :? decimal | :? single | :? double -> $"({it.Path PostgreSQL})::numeric {it.Op} {path}"
| _ -> $"{it.Path PostgreSQL} {it.Op} {path}"
| _ -> $"{it.Path PostgreSQL} {it.Op} {name.Derive it.ParameterName}")
if isNumeric value then
$"({it.Path PostgreSQL})::numeric {it.Op} {param}"
else $"{it.Path PostgreSQL} {it.Op} {param}")
|> String.concat (match howMatched with Any -> " OR " | All -> " AND ")
/// Create a WHERE clause fragment to implement an ID-based query
[<CompiledName "WhereById">]
let whereById paramName =
whereByFields Any [ { Field.EQ (Configuration.idField ()) 0 with ParameterName = Some paramName } ]
let whereById<'TKey> (docId: 'TKey) =
whereByFields Any [ { Field.EQ (Configuration.idField ()) docId with ParameterName = Some "@id" } ]
/// Table and index definition queries
module Definition =
@ -191,9 +199,7 @@ module Query =
/// Create a query by a document's ID
[<CompiledName "ById">]
let byId<'TKey> statement (docId: 'TKey) =
Query.statementWhere
statement
(whereByFields Any [ { Field.EQ (Configuration.idField ()) docId with ParameterName = Some "@id" } ])
Query.statementWhere statement (whereById docId)
/// Create a query on JSON fields
[<CompiledName "ByFields">]
@ -359,7 +365,7 @@ module WithProps =
/// Determine if a document exists for the given ID
[<CompiledName "ById">]
let byId tableName (docId: 'TKey) sqlProps =
Custom.scalar (Query.exists tableName (Query.whereById "@id")) [ idParam docId ] toExists sqlProps
Custom.scalar (Query.exists tableName (Query.whereById docId)) [ idParam docId ] toExists sqlProps
/// Determine if a document exists using JSON field comparisons (->> =)
[<CompiledName "ByFields">]
@ -537,9 +543,7 @@ module WithProps =
[<CompiledName "ById">]
let byId tableName (docId: 'TKey) (document: 'TDoc) sqlProps =
Custom.nonQuery
(Query.statementWhere (Query.update tableName) (Query.whereById "@id"))
[ idParam docId; jsonParam "@data" document ]
sqlProps
(Query.byId (Query.update tableName) docId) [ idParam docId; jsonParam "@data" document ] sqlProps
/// Update an entire document by its ID, using the provided function to obtain the ID from the document
[<CompiledName "FSharpByFunc">]

View File

@ -20,12 +20,93 @@ public static class PostgresCSharpTests
[
TestList("Parameters",
[
TestCase("Id succeeds", () =>
{
var it = Parameters.Id(88);
Expect.equal(it.Item1, "@id", "ID parameter not constructed correctly");
Expect.equal(it.Item2, Sql.@string("88"), "ID parameter value incorrect");
}),
TestList("Id",
[
// NOTE: these tests also exercise all branches of the internal parameterFor function
TestCase("succeeds for byte ID", () =>
{
var it = Parameters.Id((sbyte)7);
Expect.equal(it.Item1, "@id", "ID parameter not constructed correctly");
Expect.equal(it.Item2, Sql.int8(7), "Byte ID parameter not constructed correctly");
}),
TestCase("succeeds for unsigned byte ID", () =>
{
var it = Parameters.Id((byte)7);
Expect.equal(it.Item1, "@id", "ID parameter not constructed correctly");
Expect.equal(it.Item2, Sql.int8(7), "Unsigned byte ID parameter not constructed correctly");
}),
TestCase("succeeds for short ID", () =>
{
var it = Parameters.Id((short)44);
Expect.equal(it.Item1, "@id", "ID parameter not constructed correctly");
Expect.equal(it.Item2, Sql.int16(44), "Short ID parameter not constructed correctly");
}),
TestCase("succeeds for unsigned short ID", () =>
{
var it = Parameters.Id((ushort)64);
Expect.equal(it.Item1, "@id", "ID parameter not constructed correctly");
Expect.equal(it.Item2, Sql.int16(64), "Unsigned short ID parameter not constructed correctly");
}),
TestCase("succeeds for integer ID", () =>
{
var it = Parameters.Id(88);
Expect.equal(it.Item1, "@id", "ID parameter not constructed correctly");
Expect.equal(it.Item2, Sql.@int(88), "ID parameter value incorrect");
}),
TestCase("succeeds for unsigned integer ID", () =>
{
var it = Parameters.Id((uint)889);
Expect.equal(it.Item1, "@id", "ID parameter not constructed correctly");
Expect.equal(it.Item2, Sql.@int(889), "Unsigned int ID parameter not constructed correctly");
}),
TestCase("succeeds for long ID", () =>
{
var it = Parameters.Id((long)123);
Expect.equal(it.Item1, "@id", "ID parameter not constructed correctly");
Expect.equal(it.Item2, Sql.int64(123), "Long ID parameter not constructed correctly");
}),
TestCase("succeeds for unsigned long ID", () =>
{
var it = Parameters.Id((ulong)6464);
Expect.equal(it.Item1, "@id", "ID parameter not constructed correctly");
Expect.equal(it.Item2, Sql.int64(6464),
"Unsigned long ID parameter not constructed correctly");
}),
TestCase("succeeds for decimal ID", () =>
{
var it = Parameters.Id((decimal)4.56);
Expect.equal(it.Item1, "@id", "ID parameter not constructed correctly");
Expect.equal(it.Item2, Sql.@decimal((decimal)4.56),
"Decimal ID parameter not constructed correctly");
}),
TestCase("succeeds for single ID", () =>
{
var it = Parameters.Id((float)5.67);
Expect.equal(it.Item1, "@id", "ID parameter not constructed correctly");
Expect.equal(it.Item2, Sql.@double((float)5.67),
"Single ID parameter not constructed correctly");
}),
TestCase("succeeds for double ID", () =>
{
var it = Parameters.Id(6.78);
Expect.equal(it.Item1, "@id", "ID parameter not constructed correctly");
Expect.equal(it.Item2, Sql.@double(6.78),
"Double ID parameter not constructed correctly");
}),
TestCase("succeeds for string ID", () =>
{
var it = Parameters.Id("99");
Expect.equal(it.Item1, "@id", "ID parameter not constructed correctly");
Expect.equal(it.Item2, Sql.@string("99"), "ID parameter value incorrect");
}),
TestCase("succeeds for non-numeric non-string ID", () =>
{
var it = Parameters.Id(new Uri("https://example.com"));
Expect.equal(it.Item1, "@id", "ID parameter not constructed correctly");
Expect.equal(it.Item2, Sql.@string("https://example.com/"),
"Non-numeric, non-string parameter value incorrect");
})
]),
TestCase("Json succeeds", () =>
{
var it = Parameters.Json("@test", new { Something = "good" });
@ -40,10 +121,7 @@ public static class PostgresCSharpTests
Expect.hasLength(paramList, 1, "There should have been a parameter added");
var (name, value) = paramList[0];
Expect.equal(name, "@field0", "Field parameter name not correct");
if (!value.IsParameter)
{
Expect.isTrue(false, "The parameter was not a Parameter type");
}
Expect.equal(value, Sql.@string("242"), "Field parameter value not correct");
}),
TestCase("succeeds when multiple independent parameters are added", () =>
{
@ -52,22 +130,13 @@ public static class PostgresCSharpTests
Expect.hasLength(paramList, 3, "There should have been 2 parameters added");
var (name, value) = paramList[0];
Expect.equal(name, "@id", "First field parameter name not correct");
if (!value.IsString)
{
Expect.isTrue(false, "First parameter was not a String type");
}
Expect.equal(value, Sql.@int(14), "First field parameter value not correct");
(name, value) = paramList[1];
Expect.equal(name, "@field0", "Second field parameter name not correct");
if (!value.IsParameter)
{
Expect.isTrue(false, "Second parameter was not a Parameter type");
}
Expect.equal(value, Sql.@string("you"), "Second field parameter value not correct");
(name, value) = paramList[2];
Expect.equal(name, "@field1", "Third parameter name not correct");
if (!value.IsParameter)
{
Expect.isTrue(false, "Third parameter was not a Parameter type");
}
Expect.equal(value, Sql.@string("them"), "Third parameter value not correct");
}),
TestCase("succeeds when a parameter is not added", () =>
{
@ -81,16 +150,10 @@ public static class PostgresCSharpTests
Expect.hasLength(paramList, 2, "There should have been 2 parameters added");
var (name, value) = paramList[0];
Expect.equal(name, "@testmin", "Minimum field name not correct");
if (!value.IsParameter)
{
Expect.isTrue(false, "Minimum parameter was not a Parameter type");
}
Expect.equal(value, Sql.@string("eh"), "Minimum field value not correct");
(name, value) = paramList[1];
Expect.equal(name, "@testmax", "Maximum field name not correct");
if (!value.IsParameter)
{
Expect.isTrue(false, "Maximum parameter was not a Parameter type");
}
Expect.equal(value, Sql.@string("zed"), "Maximum field value not correct");
})
]),
#pragma warning disable CS0618
@ -101,7 +164,7 @@ public static class PostgresCSharpTests
var it = Parameters.AddField("@field", Field.EQ("it", "242"), []).ToList();
Expect.hasLength(it, 1, "There should have been a parameter added");
Expect.equal(it[0].Item1, "@field", "Field parameter not constructed correctly");
Expect.isTrue(it[0].Item2.IsParameter, "Field parameter value incorrect");
Expect.isTrue(it[0].Item2.IsString, "Field parameter value incorrect");
}),
TestCase("succeeds when a parameter is not added", () =>
{
@ -113,9 +176,9 @@ public static class PostgresCSharpTests
var it = Parameters.AddField("@field", Field.BT("that", "eh", "zed"), []).ToList();
Expect.hasLength(it, 2, "There should have been 2 parameters added");
Expect.equal(it[0].Item1, "@fieldmin", "Minimum field name not correct");
Expect.isTrue(it[0].Item2.IsParameter, "Minimum field parameter value incorrect");
Expect.isTrue(it[0].Item2.IsString, "Minimum field parameter value incorrect");
Expect.equal(it[1].Item1, "@fieldmax", "Maximum field name not correct");
Expect.isTrue(it[1].Item2.IsParameter, "Maximum field parameter value incorrect");
Expect.isTrue(it[1].Item2.IsString, "Maximum field parameter value incorrect");
})
]),
#pragma warning restore CS0618
@ -172,7 +235,7 @@ public static class PostgresCSharpTests
{
Expect.equal(
Postgres.Query.WhereByFields(FieldMatch.Any,
[Field.GT("theField", 0).WithParameterName("@test")]),
[Field.GT("theField", "0").WithParameterName("@test")]),
"data->>'theField' > @test", "WHERE clause not correct");
}),
TestCase("succeeds for a single field when an existence operator is passed", () =>
@ -206,7 +269,8 @@ public static class PostgresCSharpTests
Expect.equal(
Postgres.Query.WhereByFields(FieldMatch.Any,
[Field.NEX("thatField"), Field.GE("thisField", 18)]),
"data->>'thatField' IS NULL OR data->>'thisField' >= @field0", "WHERE clause not correct");
"data->>'thatField' IS NULL OR (data->>'thisField')::numeric >= @field0",
"WHERE clause not correct");
}),
TestCase("succeeds for all multiple fields with between operators", () =>
{
@ -217,10 +281,23 @@ public static class PostgresCSharpTests
"WHERE clause not correct");
})
]),
TestCase("WhereById succeeds", () =>
{
Expect.equal(Postgres.Query.WhereById("@id"), "data->>'Id' = @id", "WHERE clause not correct");
}),
TestList("WhereById",
[
TestCase("succeeds for numeric ID", () =>
{
Expect.equal(Postgres.Query.WhereById(18), "(data->>'Id')::numeric = @id",
"WHERE clause not correct");
}),
TestCase("succeeds for string ID", () =>
{
Expect.equal(Postgres.Query.WhereById("18"), "data->>'Id' = @id", "WHERE clause not correct");
}),
TestCase("succeeds for non-numeric non-string ID", () =>
{
Expect.equal(Postgres.Query.WhereById(new Uri("https://example.com")), "data->>'Id' = @id",
"WHERE clause not correct");
}),
]),
TestList("Definition",
[
TestCase("EnsureTable succeeds", () =>

View File

@ -11,9 +11,78 @@ open BitBadger.Documents.Tests
let unitTests =
testList "Unit" [
testList "Parameters" [
test "idParam succeeds" {
Expect.equal (idParam 88) ("@id", Sql.string "88") "ID parameter not constructed correctly"
}
testList "idParam" [
// NOTE: these tests also exercise all branches of the internal parameterFor function
test "succeeds for byte ID" {
Expect.equal
(idParam (sbyte 7)) ("@id", Sql.int8 (sbyte 7)) "Byte ID parameter not constructed correctly"
}
test "succeeds for unsigned byte ID" {
Expect.equal
(idParam (byte 7))
("@id", Sql.int8 (int8 (byte 7)))
"Unsigned byte ID parameter not constructed correctly"
}
test "succeeds for short ID" {
Expect.equal
(idParam (int16 44))
("@id", Sql.int16 (int16 44))
"Short ID parameter not constructed correctly"
}
test "succeeds for unsigned short ID" {
Expect.equal
(idParam (uint16 64))
("@id", Sql.int16 (int16 64))
"Unsigned short ID parameter not constructed correctly"
}
test "succeeds for integer ID" {
Expect.equal (idParam 88) ("@id", Sql.int 88) "Int ID parameter not constructed correctly"
}
test "succeeds for unsigned integer ID" {
Expect.equal
(idParam (uint 889)) ("@id", Sql.int 889) "Unsigned int ID parameter not constructed correctly"
}
test "succeeds for long ID" {
Expect.equal
(idParam (int64 123))
("@id", Sql.int64 (int64 123))
"Long ID parameter not constructed correctly"
}
test "succeeds for unsigned long ID" {
Expect.equal
(idParam (uint64 6464))
("@id", Sql.int64 (int64 6464))
"Unsigned long ID parameter not constructed correctly"
}
test "succeeds for decimal ID" {
Expect.equal
(idParam (decimal 4.56))
("@id", Sql.decimal (decimal 4.56))
"Decimal ID parameter not constructed correctly"
}
test "succeeds for single ID" {
Expect.equal
(idParam (single 5.67))
("@id", Sql.double (double (single 5.67)))
"Single ID parameter not constructed correctly"
}
test "succeeds for double ID" {
Expect.equal
(idParam (double 6.78))
("@id", Sql.double (double 6.78))
"Double ID parameter not constructed correctly"
}
test "succeeds for string ID" {
Expect.equal (idParam "99") ("@id", Sql.string "99") "String ID parameter not constructed correctly"
}
test "succeeds for non-numeric non-string ID" {
let target = { new obj() with override _.ToString() = "ToString was called" }
Expect.equal
(idParam target)
("@id", Sql.string "ToString was called")
"Non-numeric, non-string parameter not constructed correctly"
}
]
test "jsonParam succeeds" {
Expect.equal
(jsonParam "@test" {| Something = "good" |})
@ -24,35 +93,20 @@ let unitTests =
test "succeeds when a parameter is added" {
let paramList = addFieldParams [ Field.EQ "it" "242" ] []
Expect.hasLength paramList 1 "There should have been a parameter added"
let it = Seq.head paramList
Expect.equal (fst it) "@field0" "Field parameter name not correct"
match snd it with
| SqlValue.Parameter value ->
Expect.equal value.ParameterName "@field0" "Parameter name not correct"
Expect.equal value.Value "242" "Parameter value not correct"
| _ -> Expect.isTrue false "The parameter was not a Parameter type"
let name, value = Seq.head paramList
Expect.equal name "@field0" "Field parameter name not correct"
Expect.equal value (Sql.string "242") "Parameter value not correct"
}
test "succeeds when multiple independent parameters are added" {
let paramList = addFieldParams [ Field.EQ "me" "you"; Field.GT "us" "them" ] [ idParam 14 ]
Expect.hasLength paramList 3 "There should have been 2 parameters added"
let p = Array.ofSeq paramList
Expect.equal (fst p[0]) "@id" "First field parameter name not correct"
match snd p[0] with
| SqlValue.String value ->
Expect.equal value "14" "First parameter value not correct"
| _ -> Expect.isTrue false "First parameter was not a String type"
Expect.equal (snd p[0]) (Sql.int 14) "First parameter value not correct"
Expect.equal (fst p[1]) "@field0" "Second field parameter name not correct"
match snd p[1] with
| SqlValue.Parameter value ->
Expect.equal value.ParameterName "@field0" "Second parameter name not correct"
Expect.equal value.Value "you" "Second parameter value not correct"
| _ -> Expect.isTrue false "Second parameter was not a Parameter type"
Expect.equal (snd p[1]) (Sql.string "you") "Second parameter value not correct"
Expect.equal (fst p[2]) "@field1" "Third parameter name not correct"
match snd p[2] with
| SqlValue.Parameter value ->
Expect.equal value.ParameterName "@field1" "Third parameter name not correct"
Expect.equal value.Value "them" "Third parameter value not correct"
| _ -> Expect.isTrue false "Third parameter was not a Parameter type"
Expect.equal (snd p[2]) (Sql.string "them") "Third parameter value not correct"
}
test "succeeds when a parameter is not added" {
let paramList = addFieldParams [ Field.EX "tacos" ] []
@ -62,33 +116,21 @@ let unitTests =
let paramList =
addFieldParams [ { Field.BT "that" "eh" "zed" with ParameterName = Some "@test" } ] []
Expect.hasLength paramList 2 "There should have been 2 parameters added"
let min = Seq.head paramList
Expect.equal (fst min) "@testmin" "Minimum field name not correct"
match snd min with
| SqlValue.Parameter value ->
Expect.equal value.ParameterName "@testmin" "Minimum parameter name not correct"
Expect.equal value.Value "eh" "Minimum parameter value not correct"
| _ -> Expect.isTrue false "Minimum parameter was not a Parameter type"
let max = paramList |> Seq.skip 1 |> Seq.head
Expect.equal (fst max) "@testmax" "Maximum field name not correct"
match snd max with
| SqlValue.Parameter value ->
Expect.equal value.ParameterName "@testmax" "Maximum parameter name not correct"
Expect.equal value.Value "zed" "Maximum parameter value not correct"
| _ -> Expect.isTrue false "Maximum parameter was not a Parameter type"
let name, value = Seq.head paramList
Expect.equal name "@testmin" "Minimum field name not correct"
Expect.equal value (Sql.string "eh") "Minimum parameter value not correct"
let name, value = paramList |> Seq.skip 1 |> Seq.head
Expect.equal name "@testmax" "Maximum field name not correct"
Expect.equal value (Sql.string "zed") "Maximum parameter value not correct"
}
]
testList "addFieldParam" [
test "succeeds when a parameter is added" {
let paramList = addFieldParam "@field" (Field.EQ "it" "242") []
Expect.hasLength paramList 1 "There should have been a parameter added"
let it = Seq.head paramList
Expect.equal (fst it) "@field" "Field parameter name not correct"
match snd it with
| SqlValue.Parameter value ->
Expect.equal value.ParameterName "@field" "Parameter name not correct"
Expect.equal value.Value "242" "Parameter value not correct"
| _ -> Expect.isTrue false "The parameter was not a Parameter type"
let name, value = Seq.head paramList
Expect.equal name "@field" "Field parameter name not correct"
Expect.equal value (Sql.string "242") "Parameter value not correct"
}
test "succeeds when a parameter is not added" {
let paramList = addFieldParam "@field" (Field.EX "tacos") []
@ -97,54 +139,36 @@ let unitTests =
test "succeeds when two parameters are added" {
let paramList = addFieldParam "@field" (Field.BT "that" "eh" "zed") []
Expect.hasLength paramList 2 "There should have been 2 parameters added"
let min = Seq.head paramList
Expect.equal (fst min) "@fieldmin" "Minimum field name not correct"
match snd min with
| SqlValue.Parameter value ->
Expect.equal value.ParameterName "@fieldmin" "Minimum parameter name not correct"
Expect.equal value.Value "eh" "Minimum parameter value not correct"
| _ -> Expect.isTrue false "Minimum parameter was not a Parameter type"
let max = paramList |> Seq.skip 1 |> Seq.head
Expect.equal (fst max) "@fieldmax" "Maximum field name not correct"
match snd max with
| SqlValue.Parameter value ->
Expect.equal value.ParameterName "@fieldmax" "Maximum parameter name not correct"
Expect.equal value.Value "zed" "Maximum parameter value not correct"
| _ -> Expect.isTrue false "Maximum parameter was not a Parameter type"
let name, value = Seq.head paramList
Expect.equal name "@fieldmin" "Minimum field name not correct"
Expect.equal value (Sql.string "eh") "Minimum parameter value not correct"
let name, value = paramList |> Seq.skip 1 |> Seq.head
Expect.equal name "@fieldmax" "Maximum field name not correct"
Expect.equal value (Sql.string "zed") "Maximum parameter value not correct"
}
]
testList "fieldNameParams" [
test "succeeds for one name" {
let name, value = fieldNameParams [ "bob" ]
Expect.equal name "@name" "The parameter name was incorrect"
match value with
| SqlValue.String it -> Expect.equal it "bob" "The parameter value was incorrect"
| _ -> Expect.isTrue false "The parameter was not a String type"
Expect.equal value (Sql.string "bob") "The parameter value was incorrect"
}
test "succeeds for multiple names" {
let name, value = fieldNameParams [ "bob"; "tom"; "mike" ]
Expect.equal name "@name" "The parameter name was incorrect"
match value with
| SqlValue.StringArray it ->
Expect.equal it [| "bob"; "tom"; "mike" |] "The parameter value was incorrect"
| _ -> Expect.isTrue false "The parameter was not a StringArray type"
Expect.equal value (Sql.stringArray [| "bob"; "tom"; "mike" |]) "The parameter value was incorrect"
}
]
testList "fieldNameParam" [
test "succeeds for one name" {
let name, value = fieldNameParam [ "bob" ]
Expect.equal name "@name" "The parameter name was incorrect"
match value with
| SqlValue.String it -> Expect.equal it "bob" "The parameter value was incorrect"
| _ -> Expect.isTrue false "The parameter was not a String type"
Expect.equal value (Sql.string "bob") "The parameter value was incorrect"
}
test "succeeds for multiple names" {
let name, value = fieldNameParam [ "bob"; "tom"; "mike" ]
Expect.equal name "@name" "The parameter name was incorrect"
match value with
| SqlValue.StringArray it ->
Expect.equal it [| "bob"; "tom"; "mike" |] "The parameter value was incorrect"
| _ -> Expect.isTrue false "The parameter was not a StringArray type"
Expect.equal value (Sql.stringArray [| "bob"; "tom"; "mike" |]) "The parameter value was incorrect"
}
]
test "noParams succeeds" {
@ -155,7 +179,7 @@ let unitTests =
testList "whereByFields" [
test "succeeds for a single field when a logical operator is passed" {
Expect.equal
(Query.whereByFields Any [ { Field.GT "theField" 0 with ParameterName = Some "@test" } ])
(Query.whereByFields Any [ { Field.GT "theField" "0" with ParameterName = Some "@test" } ])
"data->>'theField' > @test"
"WHERE clause not correct"
}
@ -186,7 +210,7 @@ let unitTests =
test "succeeds for any multiple fields with an existence operator" {
Expect.equal
(Query.whereByFields Any [ Field.NEX "thatField"; Field.GE "thisField" 18 ])
"data->>'thatField' IS NULL OR data->>'thisField' >= @field0"
"data->>'thatField' IS NULL OR (data->>'thisField')::numeric >= @field0"
"WHERE clause not correct"
}
test "succeeds for all multiple fields with between operators" {
@ -196,9 +220,20 @@ let unitTests =
"WHERE clause not correct"
}
]
test "whereById succeeds" {
Expect.equal (Query.whereById "@id") "data->>'Id' = @id" "WHERE clause not correct"
}
testList "whereById" [
test "succeeds for numeric ID" {
Expect.equal (Query.whereById 18) "(data->>'Id')::numeric = @id" "WHERE clause not correct"
}
test "succeeds for string ID" {
Expect.equal (Query.whereById "18") "data->>'Id' = @id" "WHERE clause not correct"
}
test "succeeds for non-numeric non-string ID" {
Expect.equal
(Query.whereById (System.Uri "https://example.com"))
"data->>'Id' = @id"
"WHERE clause not correct"
}
]
testList "Definition" [
test "ensureTable succeeds" {
Expect.equal
@ -505,7 +540,7 @@ let integrationTests =
Expect.isFalse exists "There should not have been an existing document"
}
]
ftestList "byFields" [
testList "byFields" [
testTask "succeeds when documents exist" {
use db = PostgresDb.BuildDb()
do! loadDocs ()
@ -621,7 +656,7 @@ let integrationTests =
PostgresDb.TableName All [ Field.EQ "Value" "purple"; Field.EX "Sub" ]
Expect.equal (List.length docs) 1 "There should have been one document returned"
}
ftestTask "succeeds when documents are not found" {
testTask "succeeds when documents are not found" {
use db = PostgresDb.BuildDb()
do! loadDocs ()