Make Json calls and stream writes async

This commit is contained in:
Daniel J. Summers 2025-04-05 19:33:47 -04:00
parent 74961c4ba7
commit 120a59ff7f
4 changed files with 203 additions and 155 deletions

View File

@ -326,13 +326,14 @@ module Results =
/// <param name="sqlProps">The query from which JSON should be extracted</param> /// <param name="sqlProps">The query from which JSON should be extracted</param>
/// <returns>A JSON array as a string; no results will produce an empty array (<c>"[]"</c>)</returns> /// <returns>A JSON array as a string; no results will produce an empty array (<c>"[]"</c>)</returns>
[<CompiledName "FSharpToJsonArray">] [<CompiledName "FSharpToJsonArray">]
let toJsonArray (mapFunc: RowReader -> string) sqlProps = let toJsonArray (mapFunc: RowReader -> string) sqlProps = backgroundTask {
let output = StringBuilder("[") let output = StringBuilder("[")
sqlProps do! sqlProps
|> Sql.iter (fun it -> |> Sql.iterAsync (fun it ->
if output.Length > 2 then ignore (output.Append ",") if output.Length > 2 then ignore (output.Append ",")
mapFunc it |> output.Append |> ignore) mapFunc it |> output.Append |> ignore)
output.Append("]").ToString() return output.Append("]").ToString()
}
/// <summary>Create a JSON array of items for the results of a query</summary> /// <summary>Create a JSON array of items for the results of a query</summary>
/// <param name="mapFunc">The mapping function to extract JSON from the query's results</param> /// <param name="mapFunc">The mapping function to extract JSON from the query's results</param>
@ -346,14 +347,15 @@ module Results =
/// <param name="mapFunc">The mapping function to extract JSON from the query's results</param> /// <param name="mapFunc">The mapping function to extract JSON from the query's results</param>
/// <param name="sqlProps">The query from which JSON should be extracted</param> /// <param name="sqlProps">The query from which JSON should be extracted</param>
[<CompiledName "FSharpWriteJsonArray">] [<CompiledName "FSharpWriteJsonArray">]
let writeJsonArray (writer: StreamWriter) (mapFunc: RowReader -> string) sqlProps = let writeJsonArray (writer: StreamWriter) (mapFunc: RowReader -> string) sqlProps = backgroundTask {
writer.Write "[" do! writer.WriteAsync "["
let mutable isFirst = true let mutable isFirst = true
sqlProps do! sqlProps
|> Sql.iter (fun it -> |> Sql.iterAsync (fun it ->
if isFirst then isFirst <- false else writer.Write "," if isFirst then isFirst <- false else writer.Write ","
mapFunc it |> writer.Write) writer.WriteAsync(mapFunc it).ConfigureAwait(false).GetAwaiter().GetResult())
writer.Write "]" do! writer.WriteAsync "]"
}
/// <summary>Write a JSON array of items for the results of a query to the given <c>StreamWriter</c></summary> /// <summary>Write a JSON array of items for the results of a query to the given <c>StreamWriter</c></summary>
/// <param name="writer">The StreamWriter to which results should be written</param> /// <param name="writer">The StreamWriter to which results should be written</param>

View File

@ -107,9 +107,10 @@ module Custom =
/// <param name="sqlProps">The <c>SqlProps</c> to use to execute the query</param> /// <param name="sqlProps">The <c>SqlProps</c> to use to execute the query</param>
/// <returns>The JSON document with the first matching result, or an empty document if not found</returns> /// <returns>The JSON document with the first matching result, or an empty document if not found</returns>
[<CompiledName "FSharpJsonSingle">] [<CompiledName "FSharpJsonSingle">]
let jsonSingle query parameters mapFunc sqlProps = let jsonSingle query parameters mapFunc sqlProps = backgroundTask {
let results = jsonArray $"%s{query} LIMIT 1" parameters mapFunc sqlProps let! results = jsonArray $"%s{query} LIMIT 1" parameters mapFunc sqlProps
if results = "[]" then "{}" else results[1..results.Length - 2] return if results = "[]" then "{}" else results[1..results.Length - 2]
}
/// <summary>Execute a query that returns one or no JSON documents</summary> /// <summary>Execute a query that returns one or no JSON documents</summary>
/// <param name="query">The query to retrieve the results</param> /// <param name="query">The query to retrieve the results</param>
@ -972,8 +973,10 @@ module Json =
/// <param name="fields">The field conditions to match</param> /// <param name="fields">The field conditions to match</param>
/// <param name="sqlProps">The <c>SqlProps</c> to use to execute the query</param> /// <param name="sqlProps">The <c>SqlProps</c> to use to execute the query</param>
[<CompiledName "WriteFirstByFields">] [<CompiledName "WriteFirstByFields">]
let writeFirstByFields tableName (writer: StreamWriter) howMatched fields sqlProps = let writeFirstByFields tableName (writer: StreamWriter) howMatched fields sqlProps = backgroundTask {
firstByFields tableName howMatched fields sqlProps |> writer.Write let! json = firstByFields tableName howMatched fields sqlProps
do! writer.WriteAsync json
}
/// <summary> /// <summary>
/// Retrieve the first JSON document matching JSON field comparisons (<c>-&gt;&gt; =</c>, etc.) ordered by the given /// Retrieve the first JSON document matching JSON field comparisons (<c>-&gt;&gt; =</c>, etc.) ordered by the given
@ -1005,7 +1008,10 @@ module Json =
/// <param name="sqlProps">The <c>SqlProps</c> to use to execute the query</param> /// <param name="sqlProps">The <c>SqlProps</c> to use to execute the query</param>
[<CompiledName "WriteFirstByFieldsOrdered">] [<CompiledName "WriteFirstByFieldsOrdered">]
let writeFirstByFieldsOrdered tableName (writer: StreamWriter) howMatched queryFields orderFields sqlProps = let writeFirstByFieldsOrdered tableName (writer: StreamWriter) howMatched queryFields orderFields sqlProps =
firstByFieldsOrdered tableName howMatched queryFields orderFields sqlProps |> writer.Write backgroundTask {
let! json = firstByFieldsOrdered tableName howMatched queryFields orderFields sqlProps
do! writer.WriteAsync json
}
/// <summary>Retrieve the first JSON document matching a JSON containment query (<c>@&gt;</c>)</summary> /// <summary>Retrieve the first JSON document matching a JSON containment query (<c>@&gt;</c>)</summary>
/// <param name="tableName">The table from which a document should be retrieved (may include schema)</param> /// <param name="tableName">The table from which a document should be retrieved (may include schema)</param>
@ -1025,8 +1031,10 @@ module Json =
/// <param name="criteria">The document to match with the containment query</param> /// <param name="criteria">The document to match with the containment query</param>
/// <param name="sqlProps">The <c>SqlProps</c> to use to execute the query</param> /// <param name="sqlProps">The <c>SqlProps</c> to use to execute the query</param>
[<CompiledName "WriteFirstByContains">] [<CompiledName "WriteFirstByContains">]
let writeFirstByContains tableName (writer: StreamWriter) (criteria: obj) sqlProps = let writeFirstByContains tableName (writer: StreamWriter) (criteria: obj) sqlProps = backgroundTask {
firstByContains tableName criteria sqlProps |> writer.Write let! json = firstByContains tableName criteria sqlProps
do! writer.WriteAsync json
}
/// <summary> /// <summary>
/// Retrieve the first JSON document matching a JSON containment query (<c>@&gt;</c>) ordered by the given fields in /// Retrieve the first JSON document matching a JSON containment query (<c>@&gt;</c>) ordered by the given fields in
@ -1056,7 +1064,10 @@ module Json =
/// <param name="sqlProps">The <c>SqlProps</c> to use to execute the query</param> /// <param name="sqlProps">The <c>SqlProps</c> to use to execute the query</param>
[<CompiledName "WriteFirstByContainsOrdered">] [<CompiledName "WriteFirstByContainsOrdered">]
let writeFirstByContainsOrdered tableName (writer: StreamWriter) (criteria: obj) orderFields sqlProps = let writeFirstByContainsOrdered tableName (writer: StreamWriter) (criteria: obj) orderFields sqlProps =
firstByContainsOrdered tableName criteria orderFields sqlProps |> writer.Write backgroundTask {
let! json = firstByContainsOrdered tableName criteria orderFields sqlProps
do! writer.WriteAsync json
}
/// <summary>Retrieve the first JSON document matching a JSON Path match query (<c>@?</c>)</summary> /// <summary>Retrieve the first JSON document matching a JSON Path match query (<c>@?</c>)</summary>
/// <param name="tableName">The table from which a document should be retrieved (may include schema)</param> /// <param name="tableName">The table from which a document should be retrieved (may include schema)</param>
@ -1076,8 +1087,10 @@ module Json =
/// <param name="jsonPath">The JSON Path expression to match</param> /// <param name="jsonPath">The JSON Path expression to match</param>
/// <param name="sqlProps">The <c>SqlProps</c> to use to execute the query</param> /// <param name="sqlProps">The <c>SqlProps</c> to use to execute the query</param>
[<CompiledName "WriteFirstByJsonPath">] [<CompiledName "WriteFirstByJsonPath">]
let writeFirstByJsonPath tableName (writer: StreamWriter) jsonPath sqlProps = let writeFirstByJsonPath tableName (writer: StreamWriter) jsonPath sqlProps = backgroundTask {
firstByJsonPath tableName jsonPath sqlProps |> writer.Write let! json = firstByJsonPath tableName jsonPath sqlProps
do! writer.WriteAsync json
}
/// <summary> /// <summary>
/// Retrieve the first JSON document matching a JSON Path match query (<c>@?</c>) ordered by the given fields in the /// Retrieve the first JSON document matching a JSON Path match query (<c>@?</c>) ordered by the given fields in the
@ -1106,8 +1119,10 @@ module Json =
/// <param name="orderFields">Fields by which the results should be ordered</param> /// <param name="orderFields">Fields by which the results should be ordered</param>
/// <param name="sqlProps">The <c>SqlProps</c> to use to execute the query</param> /// <param name="sqlProps">The <c>SqlProps</c> to use to execute the query</param>
[<CompiledName "WriteFirstByJsonPathOrdered">] [<CompiledName "WriteFirstByJsonPathOrdered">]
let writeFirstByJsonPathOrdered tableName (writer: StreamWriter) jsonPath orderFields sqlProps = let writeFirstByJsonPathOrdered tableName (writer: StreamWriter) jsonPath orderFields sqlProps = backgroundTask {
firstByJsonPathOrdered tableName jsonPath orderFields sqlProps |> writer.Write let! json = firstByJsonPathOrdered tableName jsonPath orderFields sqlProps
do! writer.WriteAsync json
}
/// <summary>Commands to update documents</summary> /// <summary>Commands to update documents</summary>
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]

View File

@ -412,7 +412,8 @@ public static class PostgresCSharpTests
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
var docs = Custom.JsonArray(Query.Find(PostgresDb.TableName), Parameters.None, Results.JsonFromData); var docs = await Custom.JsonArray(Query.Find(PostgresDb.TableName), Parameters.None,
Results.JsonFromData);
Expect.stringStarts(docs, "[", "The JSON array should have started with `[`"); Expect.stringStarts(docs, "[", "The JSON array should have started with `[`");
Expect.hasLength(docs.Split("{\"Id\":"), 6, "There should have been 5 documents returned"); Expect.hasLength(docs.Split("{\"Id\":"), 6, "There should have been 5 documents returned");
Expect.stringEnds(docs, "]", "The JSON array should have ended with `[`"); Expect.stringEnds(docs, "]", "The JSON array should have ended with `[`");
@ -422,7 +423,8 @@ public static class PostgresCSharpTests
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
var docs = Custom.JsonArray($"SELECT data FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath", var docs = await Custom.JsonArray(
$"SELECT data FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath",
[Tuple.Create("@path", Sql.@string("$.NumValue ? (@ > 100)"))], Results.JsonFromData); [Tuple.Create("@path", Sql.@string("$.NumValue ? (@ > 100)"))], Results.JsonFromData);
Expect.equal(docs, "[]", "There should have been no documents returned"); Expect.equal(docs, "[]", "There should have been no documents returned");
}) })
@ -436,7 +438,8 @@ public static class PostgresCSharpTests
await using MemoryStream stream = new(); await using MemoryStream stream = new();
await using var writer = WriteStream(stream); await using var writer = WriteStream(stream);
Custom.WriteJsonArray(Query.Find(PostgresDb.TableName), Parameters.None, writer, Results.JsonFromData); await Custom.WriteJsonArray(Query.Find(PostgresDb.TableName), Parameters.None, writer,
Results.JsonFromData);
var docs = StreamText(stream); var docs = StreamText(stream);
Expect.stringStarts(docs, "[", "The JSON array should have started with `[`"); Expect.stringStarts(docs, "[", "The JSON array should have started with `[`");
@ -450,7 +453,7 @@ public static class PostgresCSharpTests
await using MemoryStream stream = new(); await using MemoryStream stream = new();
await using var writer = WriteStream(stream); await using var writer = WriteStream(stream);
Custom.WriteJsonArray($"SELECT data FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath", await Custom.WriteJsonArray($"SELECT data FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath",
[Tuple.Create("@path", Sql.@string("$.NumValue ? (@ > 100)"))], writer, Results.JsonFromData); [Tuple.Create("@path", Sql.@string("$.NumValue ? (@ > 100)"))], writer, Results.JsonFromData);
Expect.equal(StreamText(stream), "[]", "There should have been no documents returned"); Expect.equal(StreamText(stream), "[]", "There should have been no documents returned");
@ -485,7 +488,7 @@ public static class PostgresCSharpTests
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
var doc = Custom.JsonSingle($"SELECT data FROM {PostgresDb.TableName} WHERE data ->> 'Id' = @id", var doc = await Custom.JsonSingle($"SELECT data FROM {PostgresDb.TableName} WHERE data ->> 'Id' = @id",
[Tuple.Create("@id", Sql.@string("one"))], Results.JsonFromData); [Tuple.Create("@id", Sql.@string("one"))], Results.JsonFromData);
Expect.stringStarts(doc, "{", "The document should have started with an open brace"); Expect.stringStarts(doc, "{", "The document should have started with an open brace");
Expect.stringContains(doc, "\"Id\": \"one\"", "An incorrect document was returned"); Expect.stringContains(doc, "\"Id\": \"one\"", "An incorrect document was returned");
@ -496,7 +499,7 @@ public static class PostgresCSharpTests
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
var doc = Custom.JsonSingle($"SELECT data FROM {PostgresDb.TableName} WHERE data ->> 'Id' = @id", var doc = await Custom.JsonSingle($"SELECT data FROM {PostgresDb.TableName} WHERE data ->> 'Id' = @id",
[Tuple.Create("@id", Sql.@string("eighty"))], Results.JsonFromData); [Tuple.Create("@id", Sql.@string("eighty"))], Results.JsonFromData);
Expect.equal(doc, "{}", "There should not have been a document returned"); Expect.equal(doc, "{}", "There should not have been a document returned");
}) })
@ -1370,12 +1373,12 @@ public static class PostgresCSharpTests
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
VerifyAllData(Json.All(PostgresDb.TableName)); VerifyAllData(await Json.All(PostgresDb.TableName));
}), }),
TestCase("succeeds when there is no data", async () => TestCase("succeeds when there is no data", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
VerifyEmpty(Json.All(PostgresDb.TableName)); VerifyEmpty(await Json.All(PostgresDb.TableName));
}) })
]), ]),
TestList("AllOrdered", TestList("AllOrdered",
@ -1384,21 +1387,21 @@ public static class PostgresCSharpTests
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
VerifyExpectedOrder(Json.AllOrdered(PostgresDb.TableName, [Field.Named("n:NumValue")]), VerifyExpectedOrder(await Json.AllOrdered(PostgresDb.TableName, [Field.Named("n:NumValue")]),
"one", "three", "two", "four", "five"); "one", "three", "two", "four", "five");
}), }),
TestCase("succeeds when ordering numerically descending", async () => TestCase("succeeds when ordering numerically descending", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
VerifyExpectedOrder(Json.AllOrdered(PostgresDb.TableName, [Field.Named("n:NumValue DESC")]), VerifyExpectedOrder(await Json.AllOrdered(PostgresDb.TableName, [Field.Named("n:NumValue DESC")]),
"five", "four", "two", "three", "one"); "five", "four", "two", "three", "one");
}), }),
TestCase("succeeds when ordering alphabetically", async () => TestCase("succeeds when ordering alphabetically", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
VerifyExpectedOrder(Json.AllOrdered(PostgresDb.TableName, [Field.Named("Id DESC")]), VerifyExpectedOrder(await Json.AllOrdered(PostgresDb.TableName, [Field.Named("Id DESC")]),
"two", "three", "one", "four", "five"); "two", "three", "one", "four", "five");
}) })
]), ]),
@ -1409,7 +1412,7 @@ public static class PostgresCSharpTests
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
var json = Json.ById(PostgresDb.TableName, "two"); var json = await Json.ById(PostgresDb.TableName, "two");
Expect.stringStarts(json, """{"Id": "two",""", "An incorrect document was returned"); Expect.stringStarts(json, """{"Id": "two",""", "An incorrect document was returned");
Expect.stringEnds(json, "}", "JSON should have ended with this document"); Expect.stringEnds(json, "}", "JSON should have ended with this document");
}), }),
@ -1417,7 +1420,7 @@ public static class PostgresCSharpTests
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
VerifyNoDoc(Json.ById(PostgresDb.TableName, "three hundred eighty-seven")); VerifyNoDoc(await Json.ById(PostgresDb.TableName, "three hundred eighty-seven"));
}) })
]), ]),
TestList("ByFields", TestList("ByFields",
@ -1427,7 +1430,7 @@ public static class PostgresCSharpTests
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
VerifySingleById( VerifySingleById(
Json.ByFields(PostgresDb.TableName, FieldMatch.All, await Json.ByFields(PostgresDb.TableName, FieldMatch.All,
[Field.In("Value", ["purple", "blue"]), Field.Exists("Sub")]), [Field.In("Value", ["purple", "blue"]), Field.Exists("Sub")]),
"four"); "four");
}), }),
@ -1436,14 +1439,14 @@ public static class PostgresCSharpTests
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
VerifySingleById( VerifySingleById(
Json.ByFields(PostgresDb.TableName, FieldMatch.All, [Field.In("NumValue", [2, 4, 6, 8])]), await Json.ByFields(PostgresDb.TableName, FieldMatch.All, [Field.In("NumValue", [2, 4, 6, 8])]),
"three"); "three");
}), }),
TestCase("succeeds when documents are not found", async () => TestCase("succeeds when documents are not found", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
VerifyEmpty(Json.ByFields(PostgresDb.TableName, FieldMatch.All, VerifyEmpty(await Json.ByFields(PostgresDb.TableName, FieldMatch.All,
[Field.Equal("Value", "mauve"), Field.NotEqual("NumValue", 40)])); [Field.Equal("Value", "mauve"), Field.NotEqual("NumValue", 40)]));
}), }),
TestCase("succeeds for InArray when matching documents exist", async () => TestCase("succeeds for InArray when matching documents exist", async () =>
@ -1452,7 +1455,7 @@ public static class PostgresCSharpTests
await Definition.EnsureTable(PostgresDb.TableName); await Definition.EnsureTable(PostgresDb.TableName);
foreach (var doc in ArrayDocument.TestDocuments) await Document.Insert(PostgresDb.TableName, doc); foreach (var doc in ArrayDocument.TestDocuments) await Document.Insert(PostgresDb.TableName, doc);
var json = Json.ByFields(PostgresDb.TableName, FieldMatch.All, var json = await Json.ByFields(PostgresDb.TableName, FieldMatch.All,
[Field.InArray("Values", PostgresDb.TableName, ["c"])]); [Field.InArray("Values", PostgresDb.TableName, ["c"])]);
VerifyBeginEnd(json); VerifyBeginEnd(json);
VerifyDocById(json, "first"); VerifyDocById(json, "first");
@ -1463,7 +1466,7 @@ public static class PostgresCSharpTests
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await Definition.EnsureTable(PostgresDb.TableName); await Definition.EnsureTable(PostgresDb.TableName);
foreach (var doc in ArrayDocument.TestDocuments) await Document.Insert(PostgresDb.TableName, doc); foreach (var doc in ArrayDocument.TestDocuments) await Document.Insert(PostgresDb.TableName, doc);
VerifyEmpty(Json.ByFields(PostgresDb.TableName, FieldMatch.All, VerifyEmpty(await Json.ByFields(PostgresDb.TableName, FieldMatch.All,
[Field.InArray("Values", PostgresDb.TableName, ["j"])])); [Field.InArray("Values", PostgresDb.TableName, ["j"])]));
}) })
]), ]),
@ -1474,7 +1477,7 @@ public static class PostgresCSharpTests
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
VerifyExpectedOrder( VerifyExpectedOrder(
Json.ByFieldsOrdered(PostgresDb.TableName, FieldMatch.All, [Field.Equal("Value", "purple")], await Json.ByFieldsOrdered(PostgresDb.TableName, FieldMatch.All, [Field.Equal("Value", "purple")],
[Field.Named("Id")]), [Field.Named("Id")]),
"five", "four"); "five", "four");
}), }),
@ -1483,7 +1486,7 @@ public static class PostgresCSharpTests
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
VerifyExpectedOrder( VerifyExpectedOrder(
Json.ByFieldsOrdered(PostgresDb.TableName, FieldMatch.All, [Field.Equal("Value", "purple")], await Json.ByFieldsOrdered(PostgresDb.TableName, FieldMatch.All, [Field.Equal("Value", "purple")],
[Field.Named("Id DESC")]), [Field.Named("Id DESC")]),
"four", "five"); "four", "five");
}) })
@ -1495,7 +1498,7 @@ public static class PostgresCSharpTests
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
var json = Json.ByContains(PostgresDb.TableName, new { Sub = new { Foo = "green" } }); var json = await Json.ByContains(PostgresDb.TableName, new { Sub = new { Foo = "green" } });
VerifyBeginEnd(json); VerifyBeginEnd(json);
VerifyDocById(json, "two"); VerifyDocById(json, "two");
VerifyDocById(json, "four"); VerifyDocById(json, "four");
@ -1504,7 +1507,7 @@ public static class PostgresCSharpTests
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
VerifyEmpty(Json.ByContains(PostgresDb.TableName, new { Value = "mauve" })); VerifyEmpty(await Json.ByContains(PostgresDb.TableName, new { Value = "mauve" }));
}) })
]), ]),
TestList("ByContainsOrdered", TestList("ByContainsOrdered",
@ -1515,7 +1518,7 @@ public static class PostgresCSharpTests
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
VerifyExpectedOrder( VerifyExpectedOrder(
Json.ByContainsOrdered(PostgresDb.TableName, new { Sub = new { Foo = "green" } }, await Json.ByContainsOrdered(PostgresDb.TableName, new { Sub = new { Foo = "green" } },
[Field.Named("Sub.Bar")]), [Field.Named("Sub.Bar")]),
"two", "four"); "two", "four");
}), }),
@ -1524,7 +1527,7 @@ public static class PostgresCSharpTests
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
VerifyExpectedOrder( VerifyExpectedOrder(
Json.ByContainsOrdered(PostgresDb.TableName, new { Sub = new { Foo = "green" } }, await Json.ByContainsOrdered(PostgresDb.TableName, new { Sub = new { Foo = "green" } },
[Field.Named("Sub.Bar DESC")]), [Field.Named("Sub.Bar DESC")]),
"four", "two"); "four", "two");
}) })
@ -1536,7 +1539,7 @@ public static class PostgresCSharpTests
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
var json = Json.ByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ < 15)"); var json = await Json.ByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ < 15)");
VerifyBeginEnd(json); VerifyBeginEnd(json);
VerifyDocById(json, "one"); VerifyDocById(json, "one");
VerifyDocById(json, "two"); VerifyDocById(json, "two");
@ -1546,7 +1549,7 @@ public static class PostgresCSharpTests
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
VerifyEmpty(Json.ByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ < 0)")); VerifyEmpty(await Json.ByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ < 0)"));
}) })
]), ]),
TestList("ByJsonPathOrdered", TestList("ByJsonPathOrdered",
@ -1557,7 +1560,7 @@ public static class PostgresCSharpTests
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
VerifyExpectedOrder( VerifyExpectedOrder(
Json.ByJsonPathOrdered(PostgresDb.TableName, "$.NumValue ? (@ < 15)", await Json.ByJsonPathOrdered(PostgresDb.TableName, "$.NumValue ? (@ < 15)",
[Field.Named("n:NumValue")]), [Field.Named("n:NumValue")]),
"one", "three", "two"); "one", "three", "two");
}), }),
@ -1566,7 +1569,7 @@ public static class PostgresCSharpTests
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
VerifyExpectedOrder( VerifyExpectedOrder(
Json.ByJsonPathOrdered(PostgresDb.TableName, "$.NumValue ? (@ < 15)", await Json.ByJsonPathOrdered(PostgresDb.TableName, "$.NumValue ? (@ < 15)",
[Field.Named("n:NumValue DESC")]), [Field.Named("n:NumValue DESC")]),
"two", "three", "one"); "two", "three", "one");
}) })
@ -1578,7 +1581,7 @@ public static class PostgresCSharpTests
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
VerifyDocById( VerifyDocById(
Json.FirstByFields(PostgresDb.TableName, FieldMatch.Any, [Field.Equal("Value", "another")]), await Json.FirstByFields(PostgresDb.TableName, FieldMatch.Any, [Field.Equal("Value", "another")]),
"two"); "two");
}), }),
TestCase("succeeds when multiple documents are found", async () => TestCase("succeeds when multiple documents are found", async () =>
@ -1586,14 +1589,15 @@ public static class PostgresCSharpTests
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
VerifyAnyById( VerifyAnyById(
Json.FirstByFields(PostgresDb.TableName, FieldMatch.Any, [Field.Equal("Value", "purple")]), await Json.FirstByFields(PostgresDb.TableName, FieldMatch.Any, [Field.Equal("Value", "purple")]),
["five", "four"]); ["five", "four"]);
}), }),
TestCase("succeeds when a document is not found", async () => TestCase("succeeds when a document is not found", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
VerifyNoDoc(Json.FirstByFields(PostgresDb.TableName, FieldMatch.Any, [Field.Equal("Value", "absent")])); VerifyNoDoc(await Json.FirstByFields(PostgresDb.TableName, FieldMatch.Any,
[Field.Equal("Value", "absent")]));
}) })
]), ]),
TestList("FirstByFieldsOrdered", TestList("FirstByFieldsOrdered",
@ -1603,8 +1607,8 @@ public static class PostgresCSharpTests
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
VerifyDocById( VerifyDocById(
Json.FirstByFieldsOrdered(PostgresDb.TableName, FieldMatch.Any, [Field.Equal("Value", "purple")], await Json.FirstByFieldsOrdered(PostgresDb.TableName, FieldMatch.Any,
[Field.Named("Id")]), [Field.Equal("Value", "purple")], [Field.Named("Id")]),
"five"); "five");
}), }),
TestCase("succeeds when sorting descending", async () => TestCase("succeeds when sorting descending", async () =>
@ -1612,8 +1616,8 @@ public static class PostgresCSharpTests
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
VerifyDocById( VerifyDocById(
Json.FirstByFieldsOrdered(PostgresDb.TableName, FieldMatch.Any, [Field.Equal("Value", "purple")], await Json.FirstByFieldsOrdered(PostgresDb.TableName, FieldMatch.Any,
[Field.Named("Id DESC")]), [Field.Equal("Value", "purple")], [Field.Named("Id DESC")]),
"four"); "four");
}) })
]), ]),
@ -1623,20 +1627,20 @@ public static class PostgresCSharpTests
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
VerifyDocById(Json.FirstByContains(PostgresDb.TableName, new { Value = "another" }), "two"); VerifyDocById(await Json.FirstByContains(PostgresDb.TableName, new { Value = "another" }), "two");
}), }),
TestCase("succeeds when multiple documents are found", async () => TestCase("succeeds when multiple documents are found", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
VerifyAnyById(Json.FirstByContains(PostgresDb.TableName, new { Sub = new { Foo = "green" } }), VerifyAnyById(await Json.FirstByContains(PostgresDb.TableName, new { Sub = new { Foo = "green" } }),
["two", "four"]); ["two", "four"]);
}), }),
TestCase("succeeds when a document is not found", async () => TestCase("succeeds when a document is not found", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
VerifyNoDoc(Json.FirstByContains(PostgresDb.TableName, new { Value = "absent" })); VerifyNoDoc(await Json.FirstByContains(PostgresDb.TableName, new { Value = "absent" }));
}) })
]), ]),
TestList("FirstByContainsOrdered", TestList("FirstByContainsOrdered",
@ -1646,7 +1650,7 @@ public static class PostgresCSharpTests
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
VerifyDocById( VerifyDocById(
Json.FirstByContainsOrdered(PostgresDb.TableName, new { Sub = new { Foo = "green" } }, await Json.FirstByContainsOrdered(PostgresDb.TableName, new { Sub = new { Foo = "green" } },
[Field.Named("Value")]), [Field.Named("Value")]),
"two"); "two");
}), }),
@ -1655,7 +1659,7 @@ public static class PostgresCSharpTests
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
VerifyDocById( VerifyDocById(
Json.FirstByContainsOrdered(PostgresDb.TableName, new { Sub = new { Foo = "green" } }, await Json.FirstByContainsOrdered(PostgresDb.TableName, new { Sub = new { Foo = "green" } },
[Field.Named("Value DESC")]), [Field.Named("Value DESC")]),
"four"); "four");
}) })
@ -1666,20 +1670,20 @@ public static class PostgresCSharpTests
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
VerifyDocById(Json.FirstByJsonPath(PostgresDb.TableName, """$.Value ? (@ == "FIRST!")"""), "one"); VerifyDocById(await Json.FirstByJsonPath(PostgresDb.TableName, """$.Value ? (@ == "FIRST!")"""), "one");
}), }),
TestCase("succeeds when multiple documents are found", async () => TestCase("succeeds when multiple documents are found", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
VerifyAnyById(Json.FirstByJsonPath(PostgresDb.TableName, """$.Sub.Foo ? (@ == "green")"""), VerifyAnyById(await Json.FirstByJsonPath(PostgresDb.TableName, """$.Sub.Foo ? (@ == "green")"""),
["two", "four"]); ["two", "four"]);
}), }),
TestCase("succeeds when a document is not found", async () => TestCase("succeeds when a document is not found", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
VerifyNoDoc(Json.FirstByJsonPath(PostgresDb.TableName, """$.Id ? (@ == "nope")""")); VerifyNoDoc(await Json.FirstByJsonPath(PostgresDb.TableName, """$.Id ? (@ == "nope")"""));
}) })
]), ]),
TestList("FirstByJsonPathOrdered", TestList("FirstByJsonPathOrdered",
@ -1689,7 +1693,7 @@ public static class PostgresCSharpTests
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
VerifyDocById( VerifyDocById(
Json.FirstByJsonPathOrdered(PostgresDb.TableName, """$.Sub.Foo ? (@ == "green")""", await Json.FirstByJsonPathOrdered(PostgresDb.TableName, """$.Sub.Foo ? (@ == "green")""",
[Field.Named("Sub.Bar")]), [Field.Named("Sub.Bar")]),
"two"); "two");
}), }),
@ -1698,7 +1702,7 @@ public static class PostgresCSharpTests
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
await LoadDocs(); await LoadDocs();
VerifyDocById( VerifyDocById(
Json.FirstByJsonPathOrdered(PostgresDb.TableName, """$.Sub.Foo ? (@ == "green")""", await Json.FirstByJsonPathOrdered(PostgresDb.TableName, """$.Sub.Foo ? (@ == "green")""",
[Field.Named("Sub.Bar DESC")]), [Field.Named("Sub.Bar DESC")]),
"four"); "four");
}) })

View File

@ -336,16 +336,16 @@ let customTests = testList "Custom" [
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
let docs = Custom.jsonArray (Query.find PostgresDb.TableName) [] jsonFromData let! docs = Custom.jsonArray (Query.find PostgresDb.TableName) [] jsonFromData
Expect.stringStarts docs "[" "The JSON array should have started with `[`" Expect.stringStarts docs "[" "The JSON array should have started with `[`"
Expect.hasLength (docs.Split "{\"Id\":") 6 "There should have been 5 documents returned" Expect.hasLength ((string docs).Split "{\"Id\":") 6 "There should have been 5 documents returned"
Expect.stringEnds docs "]" "The JSON array should have ended with `[`" Expect.stringEnds docs "]" "The JSON array should have ended with `[`"
} }
testTask "succeeds when data is not found" { testTask "succeeds when data is not found" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
let docs = let! docs =
Custom.jsonArray Custom.jsonArray
$"SELECT data FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath" $"SELECT data FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath"
[ "@path", Sql.string "$.NumValue ? (@ > 100)" ] [ "@path", Sql.string "$.NumValue ? (@ > 100)" ]
@ -360,7 +360,7 @@ let customTests = testList "Custom" [
use stream = new MemoryStream() use stream = new MemoryStream()
use writer = writeStream stream use writer = writeStream stream
Custom.writeJsonArray (Query.find PostgresDb.TableName) [] writer jsonFromData do! Custom.writeJsonArray (Query.find PostgresDb.TableName) [] writer jsonFromData
let docs = streamText stream let docs = streamText stream
Expect.stringStarts docs "[" "The JSON array should have started with `[`" Expect.stringStarts docs "[" "The JSON array should have started with `[`"
@ -373,7 +373,7 @@ let customTests = testList "Custom" [
use stream = new MemoryStream() use stream = new MemoryStream()
use writer = writeStream stream use writer = writeStream stream
Custom.writeJsonArray do! Custom.writeJsonArray
$"SELECT data FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath" $"SELECT data FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath"
[ "@path", Sql.string "$.NumValue ? (@ > 100)" ] [ "@path", Sql.string "$.NumValue ? (@ > 100)" ]
writer writer
@ -412,7 +412,7 @@ let customTests = testList "Custom" [
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
let doc = let! doc =
Custom.jsonSingle Custom.jsonSingle
$"SELECT data FROM {PostgresDb.TableName} WHERE data ->> 'Id' = @id" $"SELECT data FROM {PostgresDb.TableName} WHERE data ->> 'Id' = @id"
[ "@id", Sql.string "one"] [ "@id", Sql.string "one"]
@ -425,7 +425,7 @@ let customTests = testList "Custom" [
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
let doc = let! doc =
Custom.jsonSingle Custom.jsonSingle
$"SELECT data FROM {PostgresDb.TableName} WHERE data ->> 'Id' = @id" $"SELECT data FROM {PostgresDb.TableName} WHERE data ->> 'Id' = @id"
[ "@id", Sql.string "eighty" ] [ "@id", Sql.string "eighty" ]
@ -1113,16 +1113,16 @@ let private verifyBeginEnd json =
Expect.stringEnds json "]" "The array should have ended with `]`" Expect.stringEnds json "]" "The array should have ended with `]`"
/// Verify the presence of a document by its ID /// Verify the presence of a document by its ID
let private verifyDocById docId json = let private verifyDocById json docId =
Expect.stringContains json $"{{\"Id\": \"%s{docId}\"," $"Document `{docId}` not present" Expect.stringContains json $"{{\"Id\": \"%s{docId}\"," $"Document `{docId}` not present"
/// Verify the presence of a document by its ID /// Verify the presence of a document by its ID
let private verifySingleById docId json = let private verifySingleById json docId =
verifyBeginEnd json verifyBeginEnd json
Expect.stringContains json $"{{\"Id\": \"%s{docId}\"," $"Document `{docId}` not present" Expect.stringContains json $"{{\"Id\": \"%s{docId}\"," $"Document `{docId}` not present"
/// Verify the presence of any of the given document IDs in the given JSON /// Verify the presence of any of the given document IDs in the given JSON
let private verifyAnyById (docIds: string list) (json: string) = let private verifyAnyById (json: string) (docIds: string list) =
match docIds |> List.tryFind (fun it -> json.Contains $"{{\"Id\": \"{it}\"") with match docIds |> List.tryFind (fun it -> json.Contains $"{{\"Id\": \"{it}\"") with
| Some _ -> () | Some _ -> ()
| None -> | None ->
@ -1132,7 +1132,7 @@ let private verifyAnyById (docIds: string list) (json: string) =
/// Verify the JSON for `all` returning data /// Verify the JSON for `all` returning data
let private verifyAllData json = let private verifyAllData json =
verifyBeginEnd json verifyBeginEnd json
for docId in [ "one"; "two"; "three"; "four"; "five" ] do verifyDocById docId json [ "one"; "two"; "three"; "four"; "five" ] |> List.iter (verifyDocById json)
/// Verify an empty JSON array /// Verify an empty JSON array
let private verifyEmpty json = let private verifyEmpty json =
@ -1143,7 +1143,7 @@ let private verifyNoDoc json =
Expect.equal json "{}" "There should be no document returned" Expect.equal json "{}" "There should be no document returned"
/// Verify the JSON for an ordered query /// Verify the JSON for an ordered query
let private verifyExpectedOrder idFirst idSecond idThird idFourth idFifth (json: string) = let private verifyExpectedOrder (json: string) idFirst idSecond idThird idFourth idFifth =
let firstIdx = json.IndexOf $"{{\"Id\": \"%s{idFirst}\"," let firstIdx = json.IndexOf $"{{\"Id\": \"%s{idFirst}\","
let secondIdx = json.IndexOf $"{{\"Id\": \"%s{idSecond}\"," let secondIdx = json.IndexOf $"{{\"Id\": \"%s{idSecond}\","
verifyBeginEnd json verifyBeginEnd json
@ -1170,31 +1170,33 @@ let jsonTests = testList "Json" [
testTask "succeeds when there is data" { testTask "succeeds when there is data" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
Json.all PostgresDb.TableName |> verifyAllData let! json = Json.all PostgresDb.TableName
verifyAllData json
} }
testTask "succeeds when there is no data" { testTask "succeeds when there is no data" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
Json.all PostgresDb.TableName |> verifyEmpty let! json = Json.all PostgresDb.TableName
verifyEmpty json
} }
] ]
testList "allOrdered" [ testList "allOrdered" [
testTask "succeeds when ordering numerically" { testTask "succeeds when ordering numerically" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
Json.allOrdered PostgresDb.TableName [ Field.Named "n:NumValue" ] let! json = Json.allOrdered PostgresDb.TableName [ Field.Named "n:NumValue" ]
|> verifyExpectedOrder "one" "three" (Some "two") (Some "four") (Some "five") verifyExpectedOrder json "one" "three" (Some "two") (Some "four") (Some "five")
} }
testTask "succeeds when ordering numerically descending" { testTask "succeeds when ordering numerically descending" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
Json.allOrdered PostgresDb.TableName [ Field.Named "n:NumValue DESC" ] let! json = Json.allOrdered PostgresDb.TableName [ Field.Named "n:NumValue DESC" ]
|> verifyExpectedOrder "five" "four" (Some "two") (Some "three") (Some "one") verifyExpectedOrder json "five" "four" (Some "two") (Some "three") (Some "one")
} }
testTask "succeeds when ordering alphabetically" { testTask "succeeds when ordering alphabetically" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
Json.allOrdered PostgresDb.TableName [ Field.Named "Id DESC" ] let! json = Json.allOrdered PostgresDb.TableName [ Field.Named "Id DESC" ]
|> verifyExpectedOrder "two" "three" (Some "one") (Some "four") (Some "five") verifyExpectedOrder json "two" "three" (Some "one") (Some "four") (Some "five")
} }
] ]
testList "byId" [ testList "byId" [
@ -1202,64 +1204,70 @@ let jsonTests = testList "Json" [
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
let json = Json.byId PostgresDb.TableName "two" let! json = Json.byId PostgresDb.TableName "two"
Expect.stringStarts json """{"Id": "two",""" "An incorrect document was returned" Expect.stringStarts json """{"Id": "two",""" "An incorrect document was returned"
Expect.stringEnds json "}" "JSON should have ended with this document" Expect.stringEnds json "}" "JSON should have ended with this document"
} }
testTask "succeeds when a document is not found" { testTask "succeeds when a document is not found" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
Json.byId PostgresDb.TableName "three hundred eighty-seven" |> verifyNoDoc let! json = Json.byId PostgresDb.TableName "three hundred eighty-seven"
verifyNoDoc json
} }
] ]
testList "byFields" [ testList "byFields" [
testTask "succeeds when documents are found" { testTask "succeeds when documents are found" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
let! json =
Json.byFields PostgresDb.TableName All [ Field.In "Value" [ "purple"; "blue" ]; Field.Exists "Sub" ] Json.byFields PostgresDb.TableName All [ Field.In "Value" [ "purple"; "blue" ]; Field.Exists "Sub" ]
|> verifySingleById "four" verifySingleById json "four"
} }
testTask "succeeds when documents are found using IN with numeric field" { testTask "succeeds when documents are found using IN with numeric field" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
Json.byFields PostgresDb.TableName All [ Field.In "NumValue" [ 2; 4; 6; 8 ] ] |> verifySingleById "three" let! json = Json.byFields PostgresDb.TableName All [ Field.In "NumValue" [ 2; 4; 6; 8 ] ]
verifySingleById json "three"
} }
testTask "succeeds when documents are not found" { testTask "succeeds when documents are not found" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
let! json =
Json.byFields PostgresDb.TableName All [ Field.Equal "Value" "mauve"; Field.NotEqual "NumValue" 40 ] Json.byFields PostgresDb.TableName All [ Field.Equal "Value" "mauve"; Field.NotEqual "NumValue" 40 ]
|> verifyEmpty verifyEmpty json
} }
testTask "succeeds for InArray when matching documents exist" { testTask "succeeds for InArray when matching documents exist" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! Definition.ensureTable PostgresDb.TableName do! Definition.ensureTable PostgresDb.TableName
for doc in ArrayDocument.TestDocuments do do! insert PostgresDb.TableName doc for doc in ArrayDocument.TestDocuments do do! insert PostgresDb.TableName doc
let json = Json.byFields PostgresDb.TableName All [ Field.InArray "Values" PostgresDb.TableName [ "c" ] ] let! json = Json.byFields PostgresDb.TableName All [ Field.InArray "Values" PostgresDb.TableName [ "c" ] ]
verifyBeginEnd json verifyBeginEnd json
verifyDocById "first" json verifyDocById json "first"
verifyDocById "second" json verifyDocById json "second"
} }
testTask "succeeds for InArray when no matching documents exist" { testTask "succeeds for InArray when no matching documents exist" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! Definition.ensureTable PostgresDb.TableName do! Definition.ensureTable PostgresDb.TableName
for doc in ArrayDocument.TestDocuments do do! insert PostgresDb.TableName doc for doc in ArrayDocument.TestDocuments do do! insert PostgresDb.TableName doc
Json.byFields PostgresDb.TableName All [ Field.InArray "Values" PostgresDb.TableName [ "j" ] ] let! json = Json.byFields PostgresDb.TableName All [ Field.InArray "Values" PostgresDb.TableName [ "j" ] ]
|> verifyEmpty verifyEmpty json
} }
] ]
testList "byFieldsOrdered" [ testList "byFieldsOrdered" [
testTask "succeeds when sorting ascending" { testTask "succeeds when sorting ascending" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
let! json =
Json.byFieldsOrdered PostgresDb.TableName All [ Field.Equal "Value" "purple" ] [ Field.Named "Id" ] Json.byFieldsOrdered PostgresDb.TableName All [ Field.Equal "Value" "purple" ] [ Field.Named "Id" ]
|> verifyExpectedOrder "five" "four" None None None verifyExpectedOrder json "five" "four" None None None
} }
testTask "succeeds when sorting descending" { testTask "succeeds when sorting descending" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
let! json =
Json.byFieldsOrdered PostgresDb.TableName All [ Field.Equal "Value" "purple" ] [ Field.Named "Id DESC" ] Json.byFieldsOrdered PostgresDb.TableName All [ Field.Equal "Value" "purple" ] [ Field.Named "Id DESC" ]
|> verifyExpectedOrder "four" "five" None None None verifyExpectedOrder json "four" "five" None None None
} }
] ]
testList "byContains" [ testList "byContains" [
@ -1267,15 +1275,16 @@ let jsonTests = testList "Json" [
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
let json = Json.byContains PostgresDb.TableName {| Sub = {| Foo = "green" |} |} let! json = Json.byContains PostgresDb.TableName {| Sub = {| Foo = "green" |} |}
verifyBeginEnd json verifyBeginEnd json
verifyDocById "two" json verifyDocById json "two"
verifyDocById "four" json verifyDocById json "four"
} }
testTask "succeeds when documents are not found" { testTask "succeeds when documents are not found" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
Json.byContains PostgresDb.TableName {| Value = "mauve" |} |> verifyEmpty let! json = Json.byContains PostgresDb.TableName {| Value = "mauve" |}
verifyEmpty json
} }
] ]
testList "byContainsOrdered" [ testList "byContainsOrdered" [
@ -1283,14 +1292,17 @@ let jsonTests = testList "Json" [
testTask "succeeds when sorting ascending" { testTask "succeeds when sorting ascending" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
let! json =
Json.byContainsOrdered PostgresDb.TableName {| Sub = {| Foo = "green" |} |} [ Field.Named "Sub.Bar" ] Json.byContainsOrdered PostgresDb.TableName {| Sub = {| Foo = "green" |} |} [ Field.Named "Sub.Bar" ]
|> verifyExpectedOrder "two" "four" None None None verifyExpectedOrder json "two" "four" None None None
} }
testTask "succeeds when sorting descending" { testTask "succeeds when sorting descending" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
Json.byContainsOrdered PostgresDb.TableName {| Sub = {| Foo = "green" |} |} [ Field.Named "Sub.Bar DESC" ] let! json =
|> verifyExpectedOrder "four" "two" None None None Json.byContainsOrdered
PostgresDb.TableName {| Sub = {| Foo = "green" |} |} [ Field.Named "Sub.Bar DESC" ]
verifyExpectedOrder json "four" "two" None None None
} }
] ]
testList "byJsonPath" [ testList "byJsonPath" [
@ -1298,16 +1310,17 @@ let jsonTests = testList "Json" [
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
let json = Json.byJsonPath PostgresDb.TableName "$.NumValue ? (@ < 15)" let! json = Json.byJsonPath PostgresDb.TableName "$.NumValue ? (@ < 15)"
verifyBeginEnd json verifyBeginEnd json
verifyDocById "one" json verifyDocById json "one"
verifyDocById "two" json verifyDocById json "two"
verifyDocById "three" json verifyDocById json "three"
} }
testTask "succeeds when documents are not found" { testTask "succeeds when documents are not found" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
Json.byJsonPath PostgresDb.TableName "$.NumValue ? (@ < 0)" |> verifyEmpty let! json = Json.byJsonPath PostgresDb.TableName "$.NumValue ? (@ < 0)"
verifyEmpty json
} }
] ]
testList "byJsonPathOrdered" [ testList "byJsonPathOrdered" [
@ -1315,113 +1328,127 @@ let jsonTests = testList "Json" [
testTask "succeeds when sorting ascending" { testTask "succeeds when sorting ascending" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
Json.byJsonPathOrdered PostgresDb.TableName "$.NumValue ? (@ < 15)" [ Field.Named "n:NumValue" ] let! json = Json.byJsonPathOrdered PostgresDb.TableName "$.NumValue ? (@ < 15)" [ Field.Named "n:NumValue" ]
|> verifyExpectedOrder "one" "three" (Some "two") None None verifyExpectedOrder json "one" "three" (Some "two") None None
} }
testTask "succeeds when sorting descending" { testTask "succeeds when sorting descending" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
let! json =
Json.byJsonPathOrdered PostgresDb.TableName "$.NumValue ? (@ < 15)" [ Field.Named "n:NumValue DESC" ] Json.byJsonPathOrdered PostgresDb.TableName "$.NumValue ? (@ < 15)" [ Field.Named "n:NumValue DESC" ]
|> verifyExpectedOrder "two" "three" (Some "one") None None verifyExpectedOrder json "two" "three" (Some "one") None None
} }
] ]
testList "firstByFields" [ testList "firstByFields" [
testTask "succeeds when a document is found" { testTask "succeeds when a document is found" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
Json.firstByFields PostgresDb.TableName Any [ Field.Equal "Value" "another" ] let! json = Json.firstByFields PostgresDb.TableName Any [ Field.Equal "Value" "another" ]
|> verifyDocById "two" verifyDocById json "two"
} }
testTask "succeeds when multiple documents are found" { testTask "succeeds when multiple documents are found" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
Json.firstByFields PostgresDb.TableName Any [ Field.Equal "Value" "purple" ] let! json = Json.firstByFields PostgresDb.TableName Any [ Field.Equal "Value" "purple" ]
|> verifyAnyById [ "five"; "four" ] verifyAnyById json [ "five"; "four" ]
} }
testTask "succeeds when a document is not found" { testTask "succeeds when a document is not found" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
Json.firstByFields PostgresDb.TableName Any [ Field.Equal "Value" "absent" ] |> verifyNoDoc let! json = Json.firstByFields PostgresDb.TableName Any [ Field.Equal "Value" "absent" ]
verifyNoDoc json
} }
] ]
testList "firstByFieldsOrdered" [ testList "firstByFieldsOrdered" [
testTask "succeeds when sorting ascending" { testTask "succeeds when sorting ascending" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
let! json =
Json.firstByFieldsOrdered PostgresDb.TableName Any [ Field.Equal "Value" "purple" ] [ Field.Named "Id" ] Json.firstByFieldsOrdered PostgresDb.TableName Any [ Field.Equal "Value" "purple" ] [ Field.Named "Id" ]
|> verifyDocById "five" verifyDocById json "five"
} }
testTask "succeeds when sorting descending" { testTask "succeeds when sorting descending" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
let! json =
Json.firstByFieldsOrdered Json.firstByFieldsOrdered
PostgresDb.TableName Any [ Field.Equal "Value" "purple" ] [ Field.Named "Id DESC" ] PostgresDb.TableName Any [ Field.Equal "Value" "purple" ] [ Field.Named "Id DESC" ]
|> verifyDocById "four" verifyDocById json "four"
} }
] ]
testList "firstByContains" [ testList "firstByContains" [
testTask "succeeds when a document is found" { testTask "succeeds when a document is found" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
Json.firstByContains PostgresDb.TableName {| Value = "another" |} |> verifyDocById "two" let! json = Json.firstByContains PostgresDb.TableName {| Value = "another" |}
verifyDocById json "two"
} }
testTask "succeeds when multiple documents are found" { testTask "succeeds when multiple documents are found" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
Json.firstByContains PostgresDb.TableName {| Sub = {| Foo = "green" |} |} |> verifyAnyById [ "two"; "four" ] let! json = Json.firstByContains PostgresDb.TableName {| Sub = {| Foo = "green" |} |}
verifyAnyById json [ "two"; "four" ]
} }
testTask "succeeds when a document is not found" { testTask "succeeds when a document is not found" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
Json.firstByContains PostgresDb.TableName {| Value = "absent" |} |> verifyNoDoc let! json = Json.firstByContains PostgresDb.TableName {| Value = "absent" |}
verifyNoDoc json
} }
] ]
testList "firstByContainsOrdered" [ testList "firstByContainsOrdered" [
testTask "succeeds when sorting ascending" { testTask "succeeds when sorting ascending" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
let! json =
Json.firstByContainsOrdered PostgresDb.TableName {| Sub = {| Foo = "green" |} |} [ Field.Named "Value" ] Json.firstByContainsOrdered PostgresDb.TableName {| Sub = {| Foo = "green" |} |} [ Field.Named "Value" ]
|> verifyDocById "two" verifyDocById json "two"
} }
testTask "succeeds when sorting descending" { testTask "succeeds when sorting descending" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
let! json =
Json.firstByContainsOrdered Json.firstByContainsOrdered
PostgresDb.TableName {| Sub = {| Foo = "green" |} |} [ Field.Named "Value DESC" ] PostgresDb.TableName {| Sub = {| Foo = "green" |} |} [ Field.Named "Value DESC" ]
|> verifyDocById "four" verifyDocById json "four"
} }
] ]
testList "firstByJsonPath" [ testList "firstByJsonPath" [
testTask "succeeds when a document is found" { testTask "succeeds when a document is found" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
Json.firstByJsonPath PostgresDb.TableName """$.Value ? (@ == "FIRST!")""" |> verifyDocById "one" let! json = Json.firstByJsonPath PostgresDb.TableName """$.Value ? (@ == "FIRST!")"""
verifyDocById json "one"
} }
testTask "succeeds when multiple documents are found" { testTask "succeeds when multiple documents are found" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
Json.firstByJsonPath PostgresDb.TableName """$.Sub.Foo ? (@ == "green")""" let! json = Json.firstByJsonPath PostgresDb.TableName """$.Sub.Foo ? (@ == "green")"""
|> verifyAnyById [ "two"; "four" ] verifyAnyById json [ "two"; "four" ]
} }
testTask "succeeds when a document is not found" { testTask "succeeds when a document is not found" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
Json.firstByJsonPath PostgresDb.TableName """$.Id ? (@ == "nope")""" |> verifyNoDoc let! json = Json.firstByJsonPath PostgresDb.TableName """$.Id ? (@ == "nope")"""
verifyNoDoc json
} }
] ]
testList "firstByJsonPathOrdered" [ testList "firstByJsonPathOrdered" [
testTask "succeeds when sorting ascending" { testTask "succeeds when sorting ascending" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
Json.firstByJsonPathOrdered PostgresDb.TableName """$.Sub.Foo ? (@ == "green")""" [ Field.Named "Sub.Bar" ] let! json =
|> verifyDocById "two" Json.firstByJsonPathOrdered
PostgresDb.TableName """$.Sub.Foo ? (@ == "green")""" [ Field.Named "Sub.Bar" ]
verifyDocById json "two"
} }
testTask "succeeds when sorting descending" { testTask "succeeds when sorting descending" {
use db = PostgresDb.BuildDb() use db = PostgresDb.BuildDb()
do! loadDocs () do! loadDocs ()
let! json =
Json.firstByJsonPathOrdered Json.firstByJsonPathOrdered
PostgresDb.TableName """$.Sub.Foo ? (@ == "green")""" [ Field.Named "Sub.Bar DESC" ] PostgresDb.TableName """$.Sub.Foo ? (@ == "green")""" [ Field.Named "Sub.Bar DESC" ]
|> verifyDocById "four" verifyDocById json "four"
} }
] ]
] ]