diff --git a/src/Tests.CSharp/PostgresCSharpTests.cs b/src/Tests.CSharp/PostgresCSharpTests.cs
index 1f53ba7..75335ae 100644
--- a/src/Tests.CSharp/PostgresCSharpTests.cs
+++ b/src/Tests.CSharp/PostgresCSharpTests.cs
@@ -13,330 +13,333 @@ using static Runner;
///
public static class PostgresCSharpTests
{
+ ///
+ /// Unit tests for the Parameters module of the PostgreSQL library
+ ///
+ private static readonly Test ParametersTests = TestList("Parameters",
+ [
+ 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" });
+ Expect.equal(it.Item1, "@test", "JSON parameter not constructed correctly");
+ Expect.equal(it.Item2, Sql.jsonb("{\"Something\":\"good\"}"), "JSON parameter value incorrect");
+ }),
+ TestList("AddFields",
+ [
+ TestCase("succeeds when a parameter is added", () =>
+ {
+ var paramList = Parameters.AddFields([Field.EQ("it", "242")], []).ToList();
+ 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");
+ Expect.equal(value, Sql.@string("242"), "Field parameter value not correct");
+ }),
+ TestCase("succeeds when multiple independent parameters are added", () =>
+ {
+ var paramList = Parameters.AddFields([Field.EQ("me", "you"), Field.GT("us", "them")],
+ [Parameters.Id(14)]).ToList();
+ 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");
+ 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");
+ 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");
+ Expect.equal(value, Sql.@string("them"), "Third parameter value not correct");
+ }),
+ TestCase("succeeds when a parameter is not added", () =>
+ {
+ var paramList = Parameters.AddFields([Field.EX("tacos")], []).ToList();
+ Expect.isEmpty(paramList, "There should not have been any parameters added");
+ }),
+ TestCase("succeeds when two parameters are added for one field", () =>
+ {
+ var paramList =
+ Parameters.AddFields([Field.BT("that", "eh", "zed").WithParameterName("@test")], []).ToList();
+ 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");
+ Expect.equal(value, Sql.@string("eh"), "Minimum field value not correct");
+ (name, value) = paramList[1];
+ Expect.equal(name, "@testmax", "Maximum field name not correct");
+ Expect.equal(value, Sql.@string("zed"), "Maximum field value not correct");
+ })
+ ]),
+ TestList("FieldNames",
+ [
+ TestCase("succeeds for one name", () =>
+ {
+ var (name, value) = Parameters.FieldNames(["bob"]);
+ Expect.equal(name, "@name", "The parameter name was incorrect");
+ if (!value.IsString)
+ {
+ Expect.isTrue(false, "The parameter was not a String type");
+ }
+ }),
+ TestCase("succeeds for multiple names", () =>
+ {
+ var (name, value) = Parameters.FieldNames(["bob", "tom", "mike"]);
+ Expect.equal(name, "@name", "The parameter name was incorrect");
+ if (!value.IsStringArray)
+ {
+ Expect.isTrue(false, "The parameter was not a StringArray type");
+ }
+ })
+ ]),
+#pragma warning disable CS0618
+ TestList("FieldName",
+ [
+ TestCase("succeeds for one name", () =>
+ {
+ var (name, value) = Parameters.FieldName(["bob"]);
+ Expect.equal(name, "@name", "The parameter name was incorrect");
+ if (!value.IsString)
+ {
+ Expect.isTrue(false, "The parameter was not a String type");
+ }
+ }),
+ TestCase("succeeds for multiple names", () =>
+ {
+ var (name, value) = Parameters.FieldName(["bob", "tom", "mike"]);
+ Expect.equal(name, "@name", "The parameter name was incorrect");
+ if (!value.IsStringArray)
+ {
+ Expect.isTrue(false, "The parameter was not a StringArray type");
+ }
+ })
+ ])
+#pragma warning restore CS0618
+ ]);
+
+ ///
+ /// Unit tests for the Query module of the PostgreSQL library
+ ///
+ private static readonly Test QueryTests = TestList("Query",
+ [
+ TestList("WhereByFields",
+ [
+ TestCase("succeeds for a single field when a logical operator is passed", () =>
+ {
+ Expect.equal(
+ Postgres.Query.WhereByFields(FieldMatch.Any,
+ [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", () =>
+ {
+ Expect.equal(Postgres.Query.WhereByFields(FieldMatch.Any, [Field.NEX("thatField")]),
+ "data->>'thatField' IS NULL", "WHERE clause not correct");
+ }),
+ TestCase("succeeds for a single field when a between operator is passed with numeric values", () =>
+ {
+ Expect.equal(
+ Postgres.Query.WhereByFields(FieldMatch.All,
+ [Field.BT("aField", 50, 99).WithParameterName("@range")]),
+ "(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", () =>
+ {
+ Expect.equal(
+ Postgres.Query.WhereByFields(FieldMatch.Any,
+ [Field.BT("field0", "a", "b").WithParameterName("@alpha")]),
+ "data->>'field0' BETWEEN @alphamin AND @alphamax", "WHERE clause not correct");
+ }),
+ TestCase("succeeds for all multiple fields with logical operators", () =>
+ {
+ Expect.equal(
+ Postgres.Query.WhereByFields(FieldMatch.All,
+ [Field.EQ("theFirst", "1"), Field.EQ("numberTwo", "2")]),
+ "data->>'theFirst' = @field0 AND data->>'numberTwo' = @field1", "WHERE clause not correct");
+ }),
+ TestCase("succeeds for any multiple fields with an existence operator", () =>
+ {
+ Expect.equal(
+ Postgres.Query.WhereByFields(FieldMatch.Any,
+ [Field.NEX("thatField"), Field.GE("thisField", 18)]),
+ "data->>'thatField' IS NULL OR (data->>'thisField')::numeric >= @field0",
+ "WHERE clause not correct");
+ }),
+ TestCase("succeeds for all multiple fields with between operators", () =>
+ {
+ Expect.equal(
+ Postgres.Query.WhereByFields(FieldMatch.All,
+ [Field.BT("aField", 50, 99), Field.BT("anotherField", "a", "b")]),
+ "(data->>'aField')::numeric BETWEEN @field0min AND @field0max AND data->>'anotherField' BETWEEN @field1min AND @field1max",
+ "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", () =>
+ {
+ Expect.equal(Postgres.Query.Definition.EnsureTable(PostgresDb.TableName),
+ $"CREATE TABLE IF NOT EXISTS {PostgresDb.TableName} (data JSONB NOT NULL)",
+ "CREATE TABLE statement not constructed correctly");
+ }),
+ TestCase("EnsureDocumentIndex succeeds for full index", () =>
+ {
+ Expect.equal(Postgres.Query.Definition.EnsureDocumentIndex("schema.tbl", DocumentIndex.Full),
+ "CREATE INDEX IF NOT EXISTS idx_tbl_document ON schema.tbl USING GIN (data)",
+ "CREATE INDEX statement not constructed correctly");
+ }),
+ TestCase("EnsureDocumentIndex succeeds for JSONB Path Ops index", () =>
+ {
+ Expect.equal(
+ Postgres.Query.Definition.EnsureDocumentIndex(PostgresDb.TableName, DocumentIndex.Optimized),
+ string.Format(
+ "CREATE INDEX IF NOT EXISTS idx_{0}_document ON {0} USING GIN (data jsonb_path_ops)",
+ PostgresDb.TableName),
+ "CREATE INDEX statement not constructed correctly");
+ })
+ ]),
+ TestCase("WhereDataContains succeeds", () =>
+ {
+ Expect.equal(Postgres.Query.WhereDataContains("@test"), "data @> @test", "WHERE clause not correct");
+ }),
+ TestCase("WhereJsonPathMatches succeeds", () =>
+ {
+ Expect.equal(Postgres.Query.WhereJsonPathMatches("@path"), "data @? @path::jsonpath",
+ "WHERE clause not correct");
+ }),
+ TestCase("Patch succeeds", () =>
+ {
+ Expect.equal(Postgres.Query.Patch(PostgresDb.TableName),
+ $"UPDATE {PostgresDb.TableName} SET data = data || @data", "Patch query not correct");
+ }),
+ TestCase("RemoveFields succeeds", () =>
+ {
+ Expect.equal(Postgres.Query.RemoveFields(PostgresDb.TableName),
+ $"UPDATE {PostgresDb.TableName} SET data = data - @name", "Field removal query not correct");
+ }),
+ TestCase("ById succeeds", () =>
+ {
+ Expect.equal(Postgres.Query.ById("test", "14"), "test WHERE data->>'Id' = @id", "By-ID query not correct");
+ }),
+ TestCase("ByFields succeeds", () =>
+ {
+ Expect.equal(Postgres.Query.ByFields("unit", FieldMatch.Any, [Field.GT("That", 14)]),
+ "unit WHERE (data->>'That')::numeric > @field0", "By-Field query not correct");
+ }),
+ TestCase("ByContains succeeds", () =>
+ {
+ Expect.equal(Postgres.Query.ByContains("exam"), "exam WHERE data @> @criteria",
+ "By-Contains query not correct");
+ }),
+ TestCase("ByPathMach succeeds", () =>
+ {
+ Expect.equal(Postgres.Query.ByPathMatch("verify"), "verify WHERE data @? @path::jsonpath",
+ "By-JSON Path query not correct");
+ })
+ ]);
+
///
/// Tests which do not hit the database
///
private static readonly Test Unit = TestList("Unit",
[
- TestList("Parameters",
- [
- 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" });
- Expect.equal(it.Item1, "@test", "JSON parameter not constructed correctly");
- Expect.equal(it.Item2, Sql.jsonb("{\"Something\":\"good\"}"), "JSON parameter value incorrect");
- }),
- TestList("AddFields",
- [
- TestCase("succeeds when a parameter is added", () =>
- {
- var paramList = Parameters.AddFields([Field.EQ("it", "242")], []).ToList();
- 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");
- Expect.equal(value, Sql.@string("242"), "Field parameter value not correct");
- }),
- TestCase("succeeds when multiple independent parameters are added", () =>
- {
- var paramList = Parameters.AddFields([Field.EQ("me", "you"), Field.GT("us", "them")],
- [Parameters.Id(14)]).ToList();
- 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");
- 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");
- 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");
- Expect.equal(value, Sql.@string("them"), "Third parameter value not correct");
- }),
- TestCase("succeeds when a parameter is not added", () =>
- {
- var paramList = Parameters.AddFields([Field.EX("tacos")], []).ToList();
- Expect.isEmpty(paramList, "There should not have been any parameters added");
- }),
- TestCase("succeeds when two parameters are added for one field", () =>
- {
- var paramList =
- Parameters.AddFields([Field.BT("that", "eh", "zed").WithParameterName("@test")], []).ToList();
- 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");
- Expect.equal(value, Sql.@string("eh"), "Minimum field value not correct");
- (name, value) = paramList[1];
- Expect.equal(name, "@testmax", "Maximum field name not correct");
- Expect.equal(value, Sql.@string("zed"), "Maximum field value not correct");
- })
- ]),
- TestList("FieldNames",
- [
- TestCase("succeeds for one name", () =>
- {
- var (name, value) = Parameters.FieldNames(["bob"]);
- Expect.equal(name, "@name", "The parameter name was incorrect");
- if (!value.IsString)
- {
- Expect.isTrue(false, "The parameter was not a String type");
- }
- }),
- TestCase("succeeds for multiple names", () =>
- {
- var (name, value) = Parameters.FieldNames(["bob", "tom", "mike"]);
- Expect.equal(name, "@name", "The parameter name was incorrect");
- if (!value.IsStringArray)
- {
- Expect.isTrue(false, "The parameter was not a StringArray type");
- }
- })
- ]),
-#pragma warning disable CS0618
- TestList("FieldName",
- [
- TestCase("succeeds for one name", () =>
- {
- var (name, value) = Parameters.FieldName(["bob"]);
- Expect.equal(name, "@name", "The parameter name was incorrect");
- if (!value.IsString)
- {
- Expect.isTrue(false, "The parameter was not a String type");
- }
- }),
- TestCase("succeeds for multiple names", () =>
- {
- var (name, value) = Parameters.FieldName(["bob", "tom", "mike"]);
- Expect.equal(name, "@name", "The parameter name was incorrect");
- if (!value.IsStringArray)
- {
- Expect.isTrue(false, "The parameter was not a StringArray type");
- }
- })
- ])
-#pragma warning restore CS0618
- ]),
- TestList("Query",
- [
- TestList("WhereByFields",
- [
- TestCase("succeeds for a single field when a logical operator is passed", () =>
- {
- Expect.equal(
- Postgres.Query.WhereByFields(FieldMatch.Any,
- [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", () =>
- {
- Expect.equal(Postgres.Query.WhereByFields(FieldMatch.Any, [Field.NEX("thatField")]),
- "data->>'thatField' IS NULL", "WHERE clause not correct");
- }),
- TestCase("succeeds for a single field when a between operator is passed with numeric values", () =>
- {
- Expect.equal(
- Postgres.Query.WhereByFields(FieldMatch.All,
- [Field.BT("aField", 50, 99).WithParameterName("@range")]),
- "(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", () =>
- {
- Expect.equal(
- Postgres.Query.WhereByFields(FieldMatch.Any,
- [Field.BT("field0", "a", "b").WithParameterName("@alpha")]),
- "data->>'field0' BETWEEN @alphamin AND @alphamax", "WHERE clause not correct");
- }),
- TestCase("succeeds for all multiple fields with logical operators", () =>
- {
- Expect.equal(
- Postgres.Query.WhereByFields(FieldMatch.All,
- [Field.EQ("theFirst", "1"), Field.EQ("numberTwo", "2")]),
- "data->>'theFirst' = @field0 AND data->>'numberTwo' = @field1", "WHERE clause not correct");
- }),
- TestCase("succeeds for any multiple fields with an existence operator", () =>
- {
- Expect.equal(
- Postgres.Query.WhereByFields(FieldMatch.Any,
- [Field.NEX("thatField"), Field.GE("thisField", 18)]),
- "data->>'thatField' IS NULL OR (data->>'thisField')::numeric >= @field0",
- "WHERE clause not correct");
- }),
- TestCase("succeeds for all multiple fields with between operators", () =>
- {
- Expect.equal(
- Postgres.Query.WhereByFields(FieldMatch.All,
- [Field.BT("aField", 50, 99), Field.BT("anotherField", "a", "b")]),
- "(data->>'aField')::numeric BETWEEN @field0min AND @field0max AND data->>'anotherField' BETWEEN @field1min AND @field1max",
- "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", () =>
- {
- Expect.equal(Postgres.Query.Definition.EnsureTable(PostgresDb.TableName),
- $"CREATE TABLE IF NOT EXISTS {PostgresDb.TableName} (data JSONB NOT NULL)",
- "CREATE TABLE statement not constructed correctly");
- }),
- TestCase("EnsureDocumentIndex succeeds for full index", () =>
- {
- Expect.equal(Postgres.Query.Definition.EnsureDocumentIndex("schema.tbl", DocumentIndex.Full),
- "CREATE INDEX IF NOT EXISTS idx_tbl_document ON schema.tbl USING GIN (data)",
- "CREATE INDEX statement not constructed correctly");
- }),
- TestCase("EnsureDocumentIndex succeeds for JSONB Path Ops index", () =>
- {
- Expect.equal(
- Postgres.Query.Definition.EnsureDocumentIndex(PostgresDb.TableName, DocumentIndex.Optimized),
- string.Format(
- "CREATE INDEX IF NOT EXISTS idx_{0}_document ON {0} USING GIN (data jsonb_path_ops)",
- PostgresDb.TableName),
- "CREATE INDEX statement not constructed correctly");
- })
- ]),
- TestCase("WhereDataContains succeeds", () =>
- {
- Expect.equal(Postgres.Query.WhereDataContains("@test"), "data @> @test",
- "WHERE clause not correct");
- }),
- TestCase("WhereJsonPathMatches succeeds", () =>
- {
- Expect.equal(Postgres.Query.WhereJsonPathMatches("@path"), "data @? @path::jsonpath",
- "WHERE clause not correct");
- }),
- TestCase("Patch succeeds", () =>
- {
- Expect.equal(Postgres.Query.Patch(PostgresDb.TableName),
- $"UPDATE {PostgresDb.TableName} SET data = data || @data", "Patch query not correct");
- }),
- TestCase("RemoveFields succeeds", () =>
- {
- Expect.equal(Postgres.Query.RemoveFields(PostgresDb.TableName),
- $"UPDATE {PostgresDb.TableName} SET data = data - @name", "Field removal query not correct");
- }),
- TestCase("ById succeeds", () =>
- {
- Expect.equal(Postgres.Query.ById("test", "14"), "test WHERE data->>'Id' = @id",
- "By-ID query not correct");
- }),
- TestCase("ByFields succeeds", () =>
- {
- Expect.equal(Postgres.Query.ByFields("unit", FieldMatch.Any, [Field.GT("That", 14)]),
- "unit WHERE (data->>'That')::numeric > @field0", "By-Field query not correct");
- }),
- TestCase ("ByContains succeeds", () =>
- {
- Expect.equal(Postgres.Query.ByContains("exam"), "exam WHERE data @> @criteria",
- "By-Contains query not correct");
- }),
- TestCase("ByPathMach succeeds", () =>
- {
- Expect.equal(Postgres.Query.ByPathMatch("verify"), "verify WHERE data @? @path::jsonpath",
- "By-JSON Path query not correct");
- })
- ])
+ ParametersTests,
+ QueryTests
]);
private static readonly List TestDocuments =
@@ -357,984 +360,1171 @@ public static class PostgresCSharpTests
}
///
- /// Integration tests for the PostgreSQL library
+ /// Integration tests for the Configuration module of the PostgreSQL library
///
- private static readonly Test Integration = TestList("Integration",
+ private static readonly Test ConfigurationTests = TestList("Configuration",
[
- TestList("Configuration",
- [
- TestCase("UseDataSource disposes existing source", () =>
- {
- using var db1 = ThrowawayDatabase.Create(PostgresDb.ConnStr.Value);
- var source = PostgresDb.MkDataSource(db1.ConnectionString);
- Postgres.Configuration.UseDataSource(source);
+ TestCase("UseDataSource disposes existing source", () =>
+ {
+ using var db1 = ThrowawayDatabase.Create(PostgresDb.ConnStr.Value);
+ var source = PostgresDb.MkDataSource(db1.ConnectionString);
+ Postgres.Configuration.UseDataSource(source);
- using var db2 = ThrowawayDatabase.Create(PostgresDb.ConnStr.Value);
- Postgres.Configuration.UseDataSource(PostgresDb.MkDataSource(db2.ConnectionString));
+ using var db2 = ThrowawayDatabase.Create(PostgresDb.ConnStr.Value);
+ Postgres.Configuration.UseDataSource(PostgresDb.MkDataSource(db2.ConnectionString));
+ try
+ {
+ _ = source.OpenConnection();
+ Expect.isTrue(false, "Data source should have been disposed");
+ }
+ catch (Exception)
+ {
+ // This is what should have happened
+ }
+ }),
+ TestCase("DataSource returns configured data source", () =>
+ {
+ using var db = ThrowawayDatabase.Create(PostgresDb.ConnStr.Value);
+ var source = PostgresDb.MkDataSource(db.ConnectionString);
+ Postgres.Configuration.UseDataSource(source);
+
+ Expect.isTrue(ReferenceEquals(source, Postgres.Configuration.DataSource()),
+ "Data source should have been the same");
+ })
+ ]);
+
+ ///
+ /// Integration tests for the Custom module of the PostgreSQL library
+ ///
+ private static readonly Test CustomTests = TestList("Custom",
+ [
+ TestList("List",
+ [
+ TestCase("succeeds when data is found", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var docs = await Custom.List(Query.Find(PostgresDb.TableName), Parameters.None,
+ Results.FromData);
+ Expect.equal(docs.Count, 5, "There should have been 5 documents returned");
+ }),
+ TestCase("succeeds when data is not found", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var docs = await Custom.List(
+ $"SELECT data FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath",
+ [Tuple.Create("@path", Sql.@string("$.NumValue ? (@ > 100)"))], Results.FromData);
+ Expect.isEmpty(docs, "There should have been no documents returned");
+ })
+ ]),
+ TestList("Single",
+ [
+ TestCase("succeeds when a row is found", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var doc = await Custom.Single($"SELECT data FROM {PostgresDb.TableName} WHERE data ->> 'Id' = @id",
+ [Tuple.Create("@id", Sql.@string("one"))], Results.FromData);
+ Expect.isNotNull(doc, "There should have been a document returned");
+ Expect.equal(doc.Id, "one", "The incorrect document was returned");
+ }),
+ TestCase("succeeds when a row is not found", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var doc = await Custom.Single($"SELECT data FROM {PostgresDb.TableName} WHERE data ->> 'Id' = @id",
+ [Tuple.Create("@id", Sql.@string("eighty"))], Results.FromData);
+ Expect.isNull(doc, "There should not have been a document returned");
+ })
+ ]),
+ TestList("NonQuery",
+ [
+ TestCase("succeeds when operating on data", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ await Custom.NonQuery($"DELETE FROM {PostgresDb.TableName}", Parameters.None);
+
+ var remaining = await Count.All(PostgresDb.TableName);
+ Expect.equal(remaining, 0, "There should be no documents remaining in the table");
+ }),
+ TestCase("succeeds when no data matches where clause", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ await Custom.NonQuery($"DELETE FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath",
+ [Tuple.Create("@path", Sql.@string("$.NumValue ? (@ > 100)"))]);
+
+ var remaining = await Count.All(PostgresDb.TableName);
+ Expect.equal(remaining, 5, "There should be 5 documents remaining in the table");
+ })
+ ]),
+ TestCase("Scalar succeeds", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+
+ var nbr = await Custom.Scalar("SELECT 5 AS test_value", Parameters.None, row => row.@int("test_value"));
+ Expect.equal(nbr, 5, "The query should have returned the number 5");
+ })
+ ]);
+
+ ///
+ /// Integration tests for the Definition module of the PostgreSQL library
+ ///
+ private static readonly Test DefinitionTests = TestList("Definition",
+ [
+ TestCase("EnsureTable succeeds", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+
+ var exists = await TableExists();
+ var alsoExists = await KeyExists();
+ Expect.isFalse(exists, "The table should not exist already");
+ Expect.isFalse(alsoExists, "The key index should not exist already");
+
+ await Definition.EnsureTable("ensured");
+ exists = await TableExists();
+ alsoExists = await KeyExists();
+ Expect.isTrue(exists, "The table should now exist");
+ Expect.isTrue(alsoExists, "The key index should now exist");
+ return;
+
+ Task TableExists() => Custom.Scalar(
+ "SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'ensured') AS it", Parameters.None,
+ Results.ToExists);
+
+ Task KeyExists() => Custom.Scalar(
+ "SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'idx_ensured_key') AS it", Parameters.None,
+ Results.ToExists);
+ }),
+ TestCase("EnsureDocumentIndex succeeds", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+
+ var exists = await IndexExists();
+ Expect.isFalse(exists, "The index should not exist already");
+
+ await Definition.EnsureTable("ensured");
+ await Definition.EnsureDocumentIndex("ensured", DocumentIndex.Optimized);
+ exists = await IndexExists();
+ Expect.isTrue(exists, "The index should now exist");
+ return;
+
+ Task IndexExists() => Custom.Scalar(
+ "SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'idx_ensured_document') AS it",
+ Parameters.None, Results.ToExists);
+ }),
+ TestCase("EnsureFieldIndex succeeds", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+
+ var exists = await IndexExists();
+ Expect.isFalse(exists, "The index should not exist already");
+
+ await Definition.EnsureTable("ensured");
+ await Definition.EnsureFieldIndex("ensured", "test", new[] { "Id", "Category" });
+ exists = await IndexExists();
+ Expect.isTrue(exists, "The index should now exist");
+ return;
+
+ Task IndexExists() => Custom.Scalar(
+ "SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'idx_ensured_test') AS it", Parameters.None,
+ Results.ToExists);
+ })
+ ]);
+
+ ///
+ /// Integration tests for the Document module of the PostgreSQL library
+ ///
+ private static readonly Test DocumentTests = TestList("Document",
+ [
+ TestList("Insert",
+ [
+ TestCase("succeeds", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ var before = await Count.All(PostgresDb.TableName);
+ Expect.equal(before, 0, "There should be no documents in the table");
+
+ await Document.Insert(PostgresDb.TableName,
+ new JsonDocument { Id = "turkey", Sub = new() { Foo = "gobble", Bar = "gobble" } });
+ var after = await Count.All(PostgresDb.TableName);
+ Expect.equal(after, 1, "There should have been one document inserted");
+ }),
+ TestCase("fails for duplicate key", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await Document.Insert(PostgresDb.TableName, new JsonDocument { Id = "test" });
try
{
- _ = source.OpenConnection();
- Expect.isTrue(false, "Data source should have been disposed");
+ await Document.Insert(PostgresDb.TableName, new JsonDocument { Id = "test" });
+ Expect.isTrue(false, "An exception should have been raised for duplicate document ID insert");
}
catch (Exception)
{
// This is what should have happened
}
- }),
- TestCase("DataSource returns configured data source", () =>
- {
- using var db = ThrowawayDatabase.Create(PostgresDb.ConnStr.Value);
- var source = PostgresDb.MkDataSource(db.ConnectionString);
- Postgres.Configuration.UseDataSource(source);
-
- Expect.isTrue(ReferenceEquals(source, Postgres.Configuration.DataSource()),
- "Data source should have been the same");
})
]),
- TestList("Custom",
+ TestList("Save",
[
- TestList("List",
- [
- TestCase("succeeds when data is found", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var docs = await Custom.List(Query.Find(PostgresDb.TableName), Parameters.None,
- Results.FromData);
- Expect.equal(docs.Count, 5, "There should have been 5 documents returned");
- }),
- TestCase("succeeds when data is not found", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var docs = await Custom.List(
- $"SELECT data FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath",
- new[] { Tuple.Create("@path", Sql.@string("$.NumValue ? (@ > 100)")) },
- Results.FromData);
- Expect.isEmpty(docs, "There should have been no documents returned");
- })
- ]),
- TestList("Single",
- [
- TestCase("succeeds when a row is found", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var doc = await Custom.Single($"SELECT data FROM {PostgresDb.TableName} WHERE data ->> 'Id' = @id",
- new[] { Tuple.Create("@id", Sql.@string("one")) }, Results.FromData);
- Expect.isNotNull(doc, "There should have been a document returned");
- Expect.equal(doc.Id, "one", "The incorrect document was returned");
- }),
- TestCase("succeeds when a row is not found", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var doc = await Custom.Single($"SELECT data FROM {PostgresDb.TableName} WHERE data ->> 'Id' = @id",
- new[] { Tuple.Create("@id", Sql.@string("eighty")) }, Results.FromData);
- Expect.isNull(doc, "There should not have been a document returned");
- })
- ]),
- TestList("NonQuery",
- [
- TestCase("succeeds when operating on data", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- await Custom.NonQuery($"DELETE FROM {PostgresDb.TableName}", Parameters.None);
-
- var remaining = await Count.All(PostgresDb.TableName);
- Expect.equal(remaining, 0, "There should be no documents remaining in the table");
- }),
- TestCase("succeeds when no data matches where clause", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- await Custom.NonQuery($"DELETE FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath",
- new[] { Tuple.Create("@path", Sql.@string("$.NumValue ? (@ > 100)")) });
-
- var remaining = await Count.All(PostgresDb.TableName);
- Expect.equal(remaining, 5, "There should be 5 documents remaining in the table");
- })
- ]),
- TestCase("Scalar succeeds", async () =>
+ TestCase("succeeds when a document is inserted", async () =>
{
await using var db = PostgresDb.BuildDb();
+ var before = await Count.All(PostgresDb.TableName);
+ Expect.equal(before, 0, "There should be no documents in the table");
- var nbr = await Custom.Scalar("SELECT 5 AS test_value", Parameters.None, row => row.@int("test_value"));
- Expect.equal(nbr, 5, "The query should have returned the number 5");
+ await Document.Save(PostgresDb.TableName,
+ new JsonDocument { Id = "test", Sub = new() { Foo = "a", Bar = "b" } });
+ var after = await Count.All(PostgresDb.TableName);
+ Expect.equal(after, 1, "There should have been one document inserted");
+ }),
+ TestCase("succeeds when a document is updated", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await Document.Insert(PostgresDb.TableName,
+ new JsonDocument { Id = "test", Sub = new() { Foo = "a", Bar = "b" } });
+
+ var before = await Find.ById(PostgresDb.TableName, "test");
+ Expect.isNotNull(before, "There should have been a document returned");
+ Expect.equal(before.Id, "test", "The document is not correct");
+
+ before.Sub = new() { Foo = "c", Bar = "d" };
+ await Document.Save(PostgresDb.TableName, before);
+ var after = await Find.ById(PostgresDb.TableName, "test");
+ Expect.isNotNull(after, "There should have been a document returned post-update");
+ Expect.equal(after.Id, "test", "The document is not correct");
+ Expect.equal(after.Sub!.Foo, "c", "The updated document is not correct");
})
- ]),
- TestList("Definition",
- [
- TestCase("EnsureTable succeeds", async () =>
- {
- await using var db = PostgresDb.BuildDb();
-
- var exists = await TableExists();
- var alsoExists = await KeyExists();
- Expect.isFalse(exists, "The table should not exist already");
- Expect.isFalse(alsoExists, "The key index should not exist already");
-
- await Definition.EnsureTable("ensured");
- exists = await TableExists();
- alsoExists = await KeyExists();
- Expect.isTrue(exists, "The table should now exist");
- Expect.isTrue(alsoExists, "The key index should now exist");
- return;
-
- Task TableExists() => Custom.Scalar(
- "SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'ensured') AS it", Parameters.None,
- Results.ToExists);
- Task KeyExists() => Custom.Scalar(
- "SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'idx_ensured_key') AS it", Parameters.None,
- Results.ToExists);
- }),
- TestCase("EnsureDocumentIndex succeeds", async () =>
- {
- await using var db = PostgresDb.BuildDb();
-
- var exists = await IndexExists();
- Expect.isFalse(exists, "The index should not exist already");
-
- await Definition.EnsureTable("ensured");
- await Definition.EnsureDocumentIndex("ensured", DocumentIndex.Optimized);
- exists = await IndexExists();
- Expect.isTrue(exists, "The index should now exist");
- return;
-
- Task IndexExists() => Custom.Scalar(
- "SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'idx_ensured_document') AS it",
- Parameters.None, Results.ToExists);
- }),
- TestCase("EnsureFieldIndex succeeds", async () =>
- {
- await using var db = PostgresDb.BuildDb();
-
- var exists = await IndexExists();
- Expect.isFalse(exists, "The index should not exist already");
-
- await Definition.EnsureTable("ensured");
- await Definition.EnsureFieldIndex("ensured", "test", new[] { "Id", "Category" });
- exists = await IndexExists();
- Expect.isTrue(exists, "The index should now exist");
- return;
-
- Task IndexExists() => Custom.Scalar(
- "SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'idx_ensured_test') AS it", Parameters.None,
- Results.ToExists);
- })
- ]),
- TestList("Document",
- [
- TestList("Insert",
- [
- TestCase("succeeds", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- var before = await Count.All(PostgresDb.TableName);
- Expect.equal(before, 0, "There should be no documents in the table");
-
- await Document.Insert(PostgresDb.TableName,
- new JsonDocument { Id = "turkey", Sub = new() { Foo = "gobble", Bar = "gobble" } });
- var after = await Count.All(PostgresDb.TableName);
- Expect.equal(after, 1, "There should have been one document inserted");
- }),
- TestCase("fails for duplicate key", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await Document.Insert(PostgresDb.TableName, new JsonDocument { Id = "test" });
- try
- {
- await Document.Insert(PostgresDb.TableName, new JsonDocument { Id = "test" });
- Expect.isTrue(false, "An exception should have been raised for duplicate document ID insert");
- }
- catch (Exception)
- {
- // This is what should have happened
- }
- })
- ]),
- TestList("Save",
- [
- TestCase("succeeds when a document is inserted", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- var before = await Count.All(PostgresDb.TableName);
- Expect.equal(before, 0, "There should be no documents in the table");
-
- await Document.Save(PostgresDb.TableName,
- new JsonDocument { Id = "test", Sub = new() { Foo = "a", Bar = "b" } });
- var after = await Count.All(PostgresDb.TableName);
- Expect.equal(after, 1, "There should have been one document inserted");
- }),
- TestCase("succeeds when a document is updated", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await Document.Insert(PostgresDb.TableName,
- new JsonDocument { Id = "test", Sub = new() { Foo = "a", Bar = "b" } });
-
- var before = await Find.ById(PostgresDb.TableName, "test");
- Expect.isNotNull(before, "There should have been a document returned");
- Expect.equal(before.Id, "test", "The document is not correct");
-
- before.Sub = new() { Foo = "c", Bar = "d" };
- await Document.Save(PostgresDb.TableName, before);
- var after = await Find.ById(PostgresDb.TableName, "test");
- Expect.isNotNull(after, "There should have been a document returned post-update");
- Expect.equal(after.Id, "test", "The document is not correct");
- Expect.equal(after.Sub!.Foo, "c", "The updated document is not correct");
- })
- ])
- ]),
- TestList("Count",
- [
- TestCase("All succeeds", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var theCount = await Count.All(PostgresDb.TableName);
- Expect.equal(theCount, 5, "There should have been 5 matching documents");
- }),
- TestList("ByFields",
- [
- TestCase("succeeds for numeric range", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var theCount = await Count.ByFields(PostgresDb.TableName, FieldMatch.Any,
- [Field.BT("NumValue", 10, 20)]);
- Expect.equal(theCount, 3, "There should have been 3 matching documents");
- }),
- TestCase("succeeds for non-numeric range", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var theCount = await Count.ByFields(PostgresDb.TableName, FieldMatch.All,
- [Field.BT("Value", "aardvark", "apple")]);
- Expect.equal(theCount, 1, "There should have been 1 matching document");
- })
- ]),
- TestCase("ByContains succeeds", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var theCount = await Count.ByContains(PostgresDb.TableName, new { Value = "purple" });
- Expect.equal(theCount, 2, "There should have been 2 matching documents");
- }),
- TestCase("ByJsonPath succeeds", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var theCount = await Count.ByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ > 5)");
- Expect.equal(theCount, 3, "There should have been 3 matching documents");
- })
- ]),
- TestList("Exists",
- [
- TestList("ById",
- [
- TestCase("succeeds when a document exists", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var exists = await Exists.ById(PostgresDb.TableName, "three");
- Expect.isTrue(exists, "There should have been an existing document");
- }),
- TestCase("succeeds when a document does not exist", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var exists = await Exists.ById(PostgresDb.TableName, "seven");
- Expect.isFalse(exists, "There should not have been an existing document");
- })
- ]),
- TestList("ByFields",
- [
- TestCase("succeeds when documents exist", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var exists = await Exists.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.NEX("Sub")]);
- Expect.isTrue(exists, "There should have been existing documents");
- }),
- TestCase("succeeds when documents do not exist", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var exists = await Exists.ByFields(PostgresDb.TableName, FieldMatch.Any,
- [Field.EQ("NumValue", "six")]);
- Expect.isFalse(exists, "There should not have been existing documents");
- })
- ]),
- TestList("ByContains",
- [
- TestCase("succeeds when documents exist", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var exists = await Exists.ByContains(PostgresDb.TableName, new { NumValue = 10 });
- Expect.isTrue(exists, "There should have been existing documents");
- }),
- TestCase("succeeds when no matching documents exist", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var exists = await Exists.ByContains(PostgresDb.TableName, new { Nothing = "none" });
- Expect.isFalse(exists, "There should not have been any existing documents");
- })
- ]),
- TestList("ByJsonPath",
- [
- TestCase("succeeds when documents exist", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var exists = await Exists.ByJsonPath(PostgresDb.TableName, "$.Sub.Foo ? (@ == \"green\")");
- Expect.isTrue(exists, "There should have been existing documents");
- }),
- TestCase("succeeds when no matching documents exist", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var exists = await Exists.ByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ > 1000)");
- Expect.isFalse(exists, "There should not have been any existing documents");
- })
- ])
- ]),
- TestList("Find",
- [
- TestList("All",
- [
- TestCase("succeeds when there is data", async () =>
- {
- await using var db = PostgresDb.BuildDb();
-
- await Document.Insert(PostgresDb.TableName, new SubDocument { Foo = "one", Bar = "two" });
- await Document.Insert(PostgresDb.TableName, new SubDocument { Foo = "three", Bar = "four" });
- await Document.Insert(PostgresDb.TableName, new SubDocument { Foo = "five", Bar = "six" });
-
- var results = await Find.All(PostgresDb.TableName);
- Expect.equal(results.Count, 3, "There should have been 3 documents returned");
- }),
- TestCase("succeeds when there is no data", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- var results = await Find.All(PostgresDb.TableName);
- Expect.isEmpty(results, "There should have been no documents returned");
- })
- ]),
- TestList("ById",
- [
- TestCase("succeeds when a document is found", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var doc = await Find.ById(PostgresDb.TableName, "two");
- Expect.isNotNull(doc, "There should have been a document returned");
- Expect.equal(doc.Id, "two", "The incorrect document was returned");
- }),
- TestCase("succeeds when a document is not found", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var doc = await Find.ById(PostgresDb.TableName, "three hundred eighty-seven");
- Expect.isNull(doc, "There should not have been a document returned");
- })
- ]),
- TestList("ByFields",
- [
- TestCase("succeeds when documents are found", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var docs = await Find.ByFields(PostgresDb.TableName, FieldMatch.Any,
- [Field.EQ("Value", "another")]);
- Expect.equal(docs.Count, 1, "There should have been one document returned");
- }),
- TestCase("succeeds when documents are not found", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var docs = await Find.ByFields(PostgresDb.TableName, FieldMatch.Any,
- [Field.EQ("Value", "mauve")]);
- Expect.isEmpty(docs, "There should have been no documents returned");
- })
- ]),
- TestList("ByContains",
- [
- TestCase("succeeds when documents are found", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var docs = await Find.ByContains(PostgresDb.TableName,
- new { Sub = new { Foo = "green" } });
- Expect.equal(docs.Count, 2, "There should have been two documents returned");
- }),
- TestCase("succeeds when documents are not found", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var docs = await Find.ByContains(PostgresDb.TableName, new { Value = "mauve" });
- Expect.isEmpty(docs, "There should have been no documents returned");
- })
- ]),
- TestList("ByJsonPath",
- [
- TestCase("succeeds when documents are found", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var docs = await Find.ByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ < 15)");
- Expect.equal(docs.Count, 3, "There should have been 3 documents returned");
- }),
- TestCase("succeeds when documents are not found", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var docs = await Find.ByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ < 0)");
- Expect.isEmpty(docs, "There should have been no documents returned");
- })
- ]),
- TestList("FirstByFields",
- [
- TestCase("succeeds when a document is found", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var doc = await Find.FirstByFields(PostgresDb.TableName, FieldMatch.Any,
- [Field.EQ("Value", "another")]);
- Expect.isNotNull(doc, "There should have been a document returned");
- Expect.equal(doc.Id, "two", "The incorrect document was returned");
- }),
- TestCase("succeeds when multiple documents are found", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var doc = await Find.FirstByFields(PostgresDb.TableName, FieldMatch.Any,
- [Field.EQ("Value", "purple")]);
- Expect.isNotNull(doc, "There should have been a document returned");
- Expect.contains(new[] { "five", "four" }, doc.Id, "An incorrect document was returned");
- }),
- TestCase("succeeds when a document is not found", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var doc = await Find.FirstByFields(PostgresDb.TableName, FieldMatch.Any,
- [Field.EQ("Value", "absent")]);
- Expect.isNull(doc, "There should not have been a document returned");
- })
- ]),
- TestList("FirstByContains",
- [
- TestCase("succeeds when a document is found", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var doc = await Find.FirstByContains(PostgresDb.TableName, new { Value = "another" });
- Expect.isNotNull(doc, "There should have been a document returned");
- Expect.equal(doc.Id, "two", "The incorrect document was returned");
- }),
- TestCase("succeeds when multiple documents are found", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var doc = await Find.FirstByContains(PostgresDb.TableName,
- new { Sub = new { Foo = "green" } });
- Expect.isNotNull(doc, "There should have been a document returned");
- Expect.contains(new[] { "two", "four" }, doc.Id, "An incorrect document was returned");
- }),
- TestCase("succeeds when a document is not found", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var doc = await Find.FirstByContains(PostgresDb.TableName, new { Value = "absent" });
- Expect.isNull(doc, "There should not have been a document returned");
- })
- ]),
- TestList("FirstByJsonPath",
- [
- TestCase("succeeds when a document is found", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var doc = await Find.FirstByJsonPath(PostgresDb.TableName,
- "$.Value ? (@ == \"FIRST!\")");
- Expect.isNotNull(doc, "There should have been a document returned");
- Expect.equal(doc.Id, "one", "The incorrect document was returned");
- }),
- TestCase("succeeds when multiple documents are found", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var doc = await Find.FirstByJsonPath(PostgresDb.TableName,
- "$.Sub.Foo ? (@ == \"green\")");
- Expect.isNotNull(doc, "There should have been a document returned");
- Expect.contains(new[] { "two", "four" }, doc.Id, "An incorrect document was returned");
- }),
- TestCase("succeeds when a document is not found", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- var doc = await Find.FirstByJsonPath(PostgresDb.TableName, "$.Id ? (@ == \"nope\")");
- Expect.isNull(doc, "There should not have been a document returned");
- })
- ])
- ]),
- TestList("Update",
- [
- TestList("ById",
- [
- TestCase("succeeds when a document is updated", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- await Update.ById(PostgresDb.TableName, "one",
- new JsonDocument { Id = "one", Sub = new() { Foo = "blue", Bar = "red" } });
- var after = await Find.ById(PostgresDb.TableName, "one");
- Expect.isNotNull(after, "There should have been a document returned post-update");
- Expect.equal(after.Id, "one", "The updated document is not correct (ID)");
- Expect.equal(after.Value, "", "The updated document is not correct (Value)");
- Expect.equal(after.NumValue, 0, "The updated document is not correct (NumValue)");
- Expect.isNotNull(after.Sub, "The updated document should have had a sub-document");
- Expect.equal(after.Sub!.Foo, "blue", "The updated document is not correct (Sub.Foo)");
- Expect.equal(after.Sub.Bar, "red", "The updated document is not correct (Sub.Bar)");
- }),
- TestCase("succeeds when no document is updated", async () =>
- {
- await using var db = PostgresDb.BuildDb();
-
- var before = await Count.All(PostgresDb.TableName);
- Expect.equal(before, 0, "There should have been no documents returned");
-
- // This not raising an exception is the test
- await Update.ById(PostgresDb.TableName, "test",
- new JsonDocument { Id = "x", Sub = new() { Foo = "blue", Bar = "red" } });
- })
- ]),
- TestList("ByFunc",
- [
- TestCase("succeeds when a document is updated", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- await Update.ByFunc(PostgresDb.TableName, doc => doc.Id,
- new JsonDocument { Id = "one", Value = "le un", NumValue = 1 });
- var after = await Find.ById(PostgresDb.TableName, "one");
- Expect.isNotNull(after, "There should have been a document returned post-update");
- Expect.equal(after.Id, "one", "The updated document is not correct (ID)");
- Expect.equal(after.Value, "le un", "The updated document is not correct (Value)");
- Expect.equal(after.NumValue, 1, "The updated document is not correct (NumValue)");
- Expect.isNull(after.Sub, "The updated document should not have had a sub-document");
- }),
- TestCase("succeeds when no document is updated", async () =>
- {
- await using var db = PostgresDb.BuildDb();
-
- var before = await Count.All(PostgresDb.TableName);
- Expect.equal(before, 0, "There should have been no documents returned");
-
- // This not raising an exception is the test
- await Update.ByFunc(PostgresDb.TableName, doc => doc.Id,
- new JsonDocument { Id = "one", Value = "le un", NumValue = 1 });
- })
- ])
- ]),
- TestList("Patch",
- [
- TestList("ById",
- [
- TestCase("succeeds when a document is updated", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- await Patch.ById(PostgresDb.TableName, "one", new { NumValue = 44 });
- var after = await Find.ById(PostgresDb.TableName, "one");
- Expect.isNotNull(after, "There should have been a document returned post-update");
- Expect.equal(after.NumValue, 44, "The updated document is not correct");
- }),
- TestCase("succeeds when no document is updated", async () =>
- {
- await using var db = PostgresDb.BuildDb();
-
- var before = await Count.All(PostgresDb.TableName);
- Expect.equal(before, 0, "There should have been no documents returned");
-
- // This not raising an exception is the test
- await Patch.ById(PostgresDb.TableName, "test", new { Foo = "green" });
- })
- ]),
- TestList("ByFields",
- [
- TestCase("succeeds when a document is updated", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- await Patch.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("Value", "purple")],
- new { NumValue = 77 });
- var after = await Count.ByFields(PostgresDb.TableName, FieldMatch.Any,
- [Field.EQ("NumValue", "77")]);
- Expect.equal(after, 2, "There should have been 2 documents returned");
- }),
- TestCase("succeeds when no document is updated", async () =>
- {
- await using var db = PostgresDb.BuildDb();
-
- var before = await Count.All(PostgresDb.TableName);
- Expect.equal(before, 0, "There should have been no documents returned");
-
- // This not raising an exception is the test
- await Patch.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("Value", "burgundy")],
- new { Foo = "green" });
- })
- ]),
- TestList("ByContains",
- [
- TestCase("succeeds when a document is updated", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- await Patch.ByContains(PostgresDb.TableName, new { Value = "purple" }, new { NumValue = 77 });
- var after = await Count.ByContains(PostgresDb.TableName, new { NumValue = 77 });
- Expect.equal(after, 2, "There should have been 2 documents returned");
- }),
- TestCase("succeeds when no document is updated", async () =>
- {
- await using var db = PostgresDb.BuildDb();
-
- var before = await Count.All(PostgresDb.TableName);
- Expect.equal(before, 0, "There should have been no documents returned");
-
- // This not raising an exception is the test
- await Patch.ByContains(PostgresDb.TableName, new { Value = "burgundy" }, new { Foo = "green" });
- })
- ]),
- TestList("ByJsonPath",
- [
- TestCase("succeeds when a document is updated", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- await Patch.ByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ > 10)", new { NumValue = 1000 });
- var after = await Count.ByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ > 999)");
- Expect.equal(after, 2, "There should have been 2 documents returned");
- }),
- TestCase("succeeds when no document is updated", async () =>
- {
- await using var db = PostgresDb.BuildDb();
-
- var before = await Count.All(PostgresDb.TableName);
- Expect.equal(before, 0, "There should have been no documents returned");
-
- // This not raising an exception is the test
- await Patch.ByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ < 0)", new { Foo = "green" });
- })
- ])
- ]),
- TestList("RemoveFields",
- [
- TestList("ById",
- [
- TestCase("succeeds when multiple fields are removed", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- await RemoveFields.ById(PostgresDb.TableName, "two", new[] { "Sub", "Value" });
- var updated = await Find.ById(PostgresDb.TableName, "two");
- Expect.isNotNull(updated, "The updated document should have been retrieved");
- Expect.equal(updated.Value, "", "The string value should have been removed");
- Expect.isNull(updated.Sub, "The sub-document should have been removed");
- }),
- TestCase("succeeds when a single field is removed", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- await RemoveFields.ById(PostgresDb.TableName, "two", new[] { "Sub" });
- var updated = await Find.ById(PostgresDb.TableName, "two");
- Expect.isNotNull(updated, "The updated document should have been retrieved");
- Expect.notEqual(updated.Value, "", "The string value should not have been removed");
- Expect.isNull(updated.Sub, "The sub-document should have been removed");
- }),
- TestCase("succeeds when a field is not removed", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- // This not raising an exception is the test
- await RemoveFields.ById(PostgresDb.TableName, "two", new[] { "AFieldThatIsNotThere" });
- }),
- TestCase("succeeds when no document is matched", async () =>
- {
- await using var db = PostgresDb.BuildDb();
-
- // This not raising an exception is the test
- await RemoveFields.ById(PostgresDb.TableName, "two", new[] { "Value" });
- })
- ]),
- TestList("ByFields",
- [
- TestCase("succeeds when multiple fields are removed", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- await RemoveFields.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", "17")],
- new[] { "Sub", "Value" });
- var updated = await Find.ById(PostgresDb.TableName, "four");
- Expect.isNotNull(updated, "The updated document should have been retrieved");
- Expect.equal(updated.Value, "", "The string value should have been removed");
- Expect.isNull(updated.Sub, "The sub-document should have been removed");
- }),
- TestCase("succeeds when a single field is removed", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- await RemoveFields.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", "17")],
- new[] { "Sub" });
- var updated = await Find.ById(PostgresDb.TableName, "four");
- Expect.isNotNull(updated, "The updated document should have been retrieved");
- Expect.notEqual(updated.Value, "", "The string value should not have been removed");
- Expect.isNull(updated.Sub, "The sub-document should have been removed");
- }),
- TestCase("succeeds when a field is not removed", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- // This not raising an exception is the test
- await RemoveFields.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", "17")],
- new[] { "Nothing" });
- }),
- TestCase("succeeds when no document is matched", async () =>
- {
- await using var db = PostgresDb.BuildDb();
-
- // This not raising an exception is the test
- await RemoveFields.ByFields(PostgresDb.TableName, FieldMatch.Any,
- [Field.NE("Abracadabra", "apple")], new[] { "Value" });
- })
- ]),
- TestList("ByContains",
- [
- TestCase("succeeds when multiple fields are removed", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- await RemoveFields.ByContains(PostgresDb.TableName, new { NumValue = 17 },
- new[] { "Sub", "Value" });
- var updated = await Find.ById(PostgresDb.TableName, "four");
- Expect.isNotNull(updated, "The updated document should have been retrieved");
- Expect.equal(updated.Value, "", "The string value should have been removed");
- Expect.isNull(updated.Sub, "The sub-document should have been removed");
- }),
- TestCase("succeeds when a single field is removed", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- await RemoveFields.ByContains(PostgresDb.TableName, new { NumValue = 17 }, new[] { "Sub" });
- var updated = await Find.ById(PostgresDb.TableName, "four");
- Expect.isNotNull(updated, "The updated document should have been retrieved");
- Expect.notEqual(updated.Value, "", "The string value should not have been removed");
- Expect.isNull(updated.Sub, "The sub-document should have been removed");
- }),
- TestCase("succeeds when a field is not removed", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- // This not raising an exception is the test
- await RemoveFields.ByContains(PostgresDb.TableName, new { NumValue = 17 }, new[] { "Nothing" });
- }),
- TestCase("succeeds when no document is matched", async () =>
- {
- await using var db = PostgresDb.BuildDb();
-
- // This not raising an exception is the test
- await RemoveFields.ByContains(PostgresDb.TableName, new { Abracadabra = "apple" },
- new[] { "Value" });
- })
- ]),
- TestList("ByJsonPath",
- [
- TestCase("succeeds when multiple fields are removed", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- await RemoveFields.ByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ == 17)",
- new[] { "Sub", "Value" });
- var updated = await Find.ById(PostgresDb.TableName, "four");
- Expect.isNotNull(updated, "The updated document should have been retrieved");
- Expect.equal(updated.Value, "", "The string value should have been removed");
- Expect.isNull(updated.Sub, "The sub-document should have been removed");
- }),
- TestCase("succeeds when a single field is removed", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- await RemoveFields.ByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ == 17)", new[] { "Sub" });
- var updated = await Find.ById(PostgresDb.TableName, "four");
- Expect.isNotNull(updated, "The updated document should have been retrieved");
- Expect.notEqual(updated.Value, "", "The string value should not have been removed");
- Expect.isNull(updated.Sub, "The sub-document should have been removed");
- }),
- TestCase("succeeds when a field is not removed", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- // This not raising an exception is the test
- await RemoveFields.ByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ == 17)", new[] { "Nothing" });
- }),
- TestCase("succeeds when no document is matched", async () =>
- {
- await using var db = PostgresDb.BuildDb();
-
- // This not raising an exception is the test
- await RemoveFields.ByJsonPath(PostgresDb.TableName, "$.Abracadabra ? (@ == \"apple\")",
- new[] { "Value" });
- })
- ])
- ]),
- TestList("Delete",
- [
- TestList("ById",
- [
- TestCase("succeeds when a document is deleted", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- await Delete.ById(PostgresDb.TableName, "four");
- var remaining = await Count.All(PostgresDb.TableName);
- Expect.equal(remaining, 4, "There should have been 4 documents remaining");
- }),
- TestCase("succeeds when a document is not deleted", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- await Delete.ById(PostgresDb.TableName, "thirty");
- var remaining = await Count.All(PostgresDb.TableName);
- Expect.equal(remaining, 5, "There should have been 5 documents remaining");
- })
- ]),
- TestList("ByFields",
- [
- TestCase("succeeds when documents are deleted", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- await Delete.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("Value", "purple")]);
- var remaining = await Count.All(PostgresDb.TableName);
- Expect.equal(remaining, 3, "There should have been 3 documents remaining");
- }),
- TestCase("succeeds when documents are not deleted", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- await Delete.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("Value", "crimson")]);
- var remaining = await Count.All(PostgresDb.TableName);
- Expect.equal(remaining, 5, "There should have been 5 documents remaining");
- })
- ]),
- TestList("ByContains",
- [
- TestCase("succeeds when documents are deleted", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- await Delete.ByContains(PostgresDb.TableName, new { Value = "purple" });
- var remaining = await Count.All(PostgresDb.TableName);
- Expect.equal(remaining, 3, "There should have been 3 documents remaining");
- }),
- TestCase("succeeds when documents are not deleted", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- await Delete.ByContains(PostgresDb.TableName, new { Value = "crimson" });
- var remaining = await Count.All(PostgresDb.TableName);
- Expect.equal(remaining, 5, "There should have been 5 documents remaining");
- })
- ]),
- TestList("ByJsonPath",
- [
- TestCase("succeeds when documents are deleted", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- await Delete.ByJsonPath(PostgresDb.TableName, "$.Sub.Foo ? (@ == \"green\")");
- var remaining = await Count.All(PostgresDb.TableName);
- Expect.equal(remaining, 3, "There should have been 3 documents remaining");
- }),
- TestCase("succeeds when documents are not deleted", async () =>
- {
- await using var db = PostgresDb.BuildDb();
- await LoadDocs();
-
- await Delete.ByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ > 100)");
- var remaining = await Count.All(PostgresDb.TableName);
- Expect.equal(remaining, 5, "There should have been 5 documents remaining");
- })
- ])
])
]);
-
+
+ ///
+ /// Integration tests for the Count module of the PostgreSQL library
+ ///
+ private static readonly Test CountTests = TestList("Count",
+ [
+ TestCase("All succeeds", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var theCount = await Count.All(PostgresDb.TableName);
+ Expect.equal(theCount, 5, "There should have been 5 matching documents");
+ }),
+ TestList("ByFields",
+ [
+ TestCase("succeeds for numeric range", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var theCount = await Count.ByFields(PostgresDb.TableName, FieldMatch.Any,
+ [Field.BT("NumValue", 10, 20)]);
+ Expect.equal(theCount, 3, "There should have been 3 matching documents");
+ }),
+ TestCase("succeeds for non-numeric range", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var theCount = await Count.ByFields(PostgresDb.TableName, FieldMatch.All,
+ [Field.BT("Value", "aardvark", "apple")]);
+ Expect.equal(theCount, 1, "There should have been 1 matching document");
+ })
+ ]),
+ TestCase("ByContains succeeds", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var theCount = await Count.ByContains(PostgresDb.TableName, new { Value = "purple" });
+ Expect.equal(theCount, 2, "There should have been 2 matching documents");
+ }),
+ TestCase("ByJsonPath succeeds", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var theCount = await Count.ByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ > 5)");
+ Expect.equal(theCount, 3, "There should have been 3 matching documents");
+ })
+ ]);
+
+ ///
+ /// Integration tests for the Exists module of the PostgreSQL library
+ ///
+ private static readonly Test ExistsTests = TestList("Exists",
+ [
+ TestList("ById",
+ [
+ TestCase("succeeds when a document exists", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var exists = await Exists.ById(PostgresDb.TableName, "three");
+ Expect.isTrue(exists, "There should have been an existing document");
+ }),
+ TestCase("succeeds when a document does not exist", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var exists = await Exists.ById(PostgresDb.TableName, "seven");
+ Expect.isFalse(exists, "There should not have been an existing document");
+ })
+ ]),
+ TestList("ByFields",
+ [
+ TestCase("succeeds when documents exist", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var exists = await Exists.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.NEX("Sub")]);
+ Expect.isTrue(exists, "There should have been existing documents");
+ }),
+ TestCase("succeeds when documents do not exist", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var exists = await Exists.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", "six")]);
+ Expect.isFalse(exists, "There should not have been existing documents");
+ })
+ ]),
+ TestList("ByContains",
+ [
+ TestCase("succeeds when documents exist", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var exists = await Exists.ByContains(PostgresDb.TableName, new { NumValue = 10 });
+ Expect.isTrue(exists, "There should have been existing documents");
+ }),
+ TestCase("succeeds when no matching documents exist", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var exists = await Exists.ByContains(PostgresDb.TableName, new { Nothing = "none" });
+ Expect.isFalse(exists, "There should not have been any existing documents");
+ })
+ ]),
+ TestList("ByJsonPath",
+ [
+ TestCase("succeeds when documents exist", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var exists = await Exists.ByJsonPath(PostgresDb.TableName, "$.Sub.Foo ? (@ == \"green\")");
+ Expect.isTrue(exists, "There should have been existing documents");
+ }),
+ TestCase("succeeds when no matching documents exist", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var exists = await Exists.ByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ > 1000)");
+ Expect.isFalse(exists, "There should not have been any existing documents");
+ })
+ ])
+ ]);
+
+ ///
+ /// Integration tests for the Find module of the PostgreSQL library
+ ///
+ private static readonly Test FindTests = TestList("Find",
+ [
+ TestList("All",
+ [
+ TestCase("succeeds when there is data", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+
+ await Document.Insert(PostgresDb.TableName, new SubDocument { Foo = "one", Bar = "two" });
+ await Document.Insert(PostgresDb.TableName, new SubDocument { Foo = "three", Bar = "four" });
+ await Document.Insert(PostgresDb.TableName, new SubDocument { Foo = "five", Bar = "six" });
+
+ var results = await Find.All(PostgresDb.TableName);
+ Expect.hasLength(results, 3, "There should have been 3 documents returned");
+ }),
+ TestCase("succeeds when there is no data", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ var results = await Find.All(PostgresDb.TableName);
+ Expect.isEmpty(results, "There should have been no documents returned");
+ })
+ ]),
+ TestList("AllOrdered",
+ [
+ TestCase("succeeds when ordering numerically", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var results =
+ await Find.AllOrdered(PostgresDb.TableName, [Field.Named("n:NumValue")]);
+ Expect.hasLength(results, 5, "There should have been 5 documents returned");
+ Expect.equal(string.Join('|', results.Select(x => x.Id)), "one|three|two|four|five",
+ "The documents were not ordered correctly");
+ }),
+ TestCase("succeeds when ordering numerically descending", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var results =
+ await Find.AllOrdered(PostgresDb.TableName, [Field.Named("n:NumValue DESC")]);
+ Expect.hasLength(results, 5, "There should have been 5 documents returned");
+ Expect.equal(string.Join('|', results.Select(x => x.Id)), "five|four|two|three|one",
+ "The documents were not ordered correctly");
+ }),
+ TestCase("succeeds when ordering alphabetically", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var results = await Find.AllOrdered(PostgresDb.TableName, [Field.Named("Id DESC")]);
+ Expect.hasLength(results, 5, "There should have been 5 documents returned");
+ Expect.equal(string.Join('|', results.Select(x => x.Id)), "two|three|one|four|five",
+ "The documents were not ordered correctly");
+ })
+ ]),
+ TestList("ById",
+ [
+ TestCase("succeeds when a document is found", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var doc = await Find.ById(PostgresDb.TableName, "two");
+ Expect.isNotNull(doc, "There should have been a document returned");
+ Expect.equal(doc.Id, "two", "The incorrect document was returned");
+ }),
+ TestCase("succeeds when a document is not found", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var doc = await Find.ById(PostgresDb.TableName, "three hundred eighty-seven");
+ Expect.isNull(doc, "There should not have been a document returned");
+ })
+ ]),
+ TestList("ByFields",
+ [
+ TestCase("succeeds when documents are found", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var docs = await Find.ByFields(PostgresDb.TableName, FieldMatch.Any,
+ [Field.EQ("Value", "another")]);
+ Expect.hasLength(docs, 1, "There should have been one document returned");
+ }),
+ TestCase("succeeds when documents are not found", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var docs = await Find.ByFields(PostgresDb.TableName, FieldMatch.Any,
+ [Field.EQ("Value", "mauve")]);
+ Expect.isEmpty(docs, "There should have been no documents returned");
+ })
+ ]),
+ TestList("ByFieldsOrdered",
+ [
+ TestCase("succeeds when documents are found", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var docs = await Find.ByFieldsOrdered(PostgresDb.TableName, FieldMatch.Any,
+ [Field.EQ("Value", "purple")], [Field.Named("Id")]);
+ Expect.hasLength(docs, 2, "There should have been two document returned");
+ Expect.equal(string.Join('|', docs.Select(x => x.Id)), "five|four",
+ "The documents were not ordered correctly");
+ }),
+ TestCase("succeeds when documents are not found", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var docs = await Find.ByFieldsOrdered(PostgresDb.TableName, FieldMatch.Any,
+ [Field.EQ("Value", "purple")], [Field.Named("Id DESC")]);
+ Expect.hasLength(docs, 2, "There should have been two document returned");
+ Expect.equal(string.Join('|', docs.Select(x => x.Id)), "four|five",
+ "The documents were not ordered correctly");
+ })
+ ]),
+ TestList("ByContains",
+ [
+ TestCase("succeeds when documents are found", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var docs = await Find.ByContains(PostgresDb.TableName,
+ new { Sub = new { Foo = "green" } });
+ Expect.hasLength(docs, 2, "There should have been two documents returned");
+ }),
+ TestCase("succeeds when documents are not found", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var docs = await Find.ByContains(PostgresDb.TableName, new { Value = "mauve" });
+ Expect.isEmpty(docs, "There should have been no documents returned");
+ })
+ ]),
+ TestList("ByContainsOrdered",
+ [
+ // Id = two, Sub.Bar = blue; Id = four, Sub.Bar = red
+ TestCase("succeeds when sorting ascending", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var docs = await Find.ByContainsOrdered(PostgresDb.TableName,
+ new { Sub = new { Foo = "green" } }, [Field.Named("Sub.Bar")]);
+ Expect.hasLength(docs, 2, "There should have been two documents returned");
+ Expect.equal(string.Join('|', docs.Select(x => x.Id)), "two|four",
+ "Documents not ordered correctly");
+ }),
+ TestCase("succeeds when sorting descending", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var docs = await Find.ByContainsOrdered(PostgresDb.TableName,
+ new { Sub = new { Foo = "green" } }, [Field.Named("Sub.Bar DESC")]);
+ Expect.hasLength(docs, 2, "There should have been two documents returned");
+ Expect.equal(string.Join('|', docs.Select(x => x.Id)), "four|two",
+ "Documents not ordered correctly");
+ })
+ ]),
+ TestList("ByJsonPath",
+ [
+ TestCase("succeeds when documents are found", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var docs = await Find.ByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ < 15)");
+ Expect.hasLength(docs, 3, "There should have been 3 documents returned");
+ }),
+ TestCase("succeeds when documents are not found", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var docs = await Find.ByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ < 0)");
+ Expect.isEmpty(docs, "There should have been no documents returned");
+ })
+ ]),
+ TestList("ByJsonPathOrdered",
+ [
+ // Id = one, NumValue = 0; Id = two, NumValue = 10; Id = three, NumValue = 4
+ TestCase("succeeds when sorting ascending", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var docs = await Find.ByJsonPathOrdered(PostgresDb.TableName, "$.NumValue ? (@ < 15)",
+ [Field.Named("n:NumValue")]);
+ Expect.hasLength(docs, 3, "There should have been 3 documents returned");
+ Expect.equal(string.Join('|', docs.Select(x => x.Id)), "one|three|two",
+ "Documents not ordered correctly");
+ }),
+ TestCase("succeeds when sorting descending", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var docs = await Find.ByJsonPathOrdered(PostgresDb.TableName, "$.NumValue ? (@ < 15)",
+ [Field.Named("n:NumValue DESC")]);
+ Expect.hasLength(docs, 3, "There should have been 3 documents returned");
+ Expect.equal(string.Join('|', docs.Select(x => x.Id)), "two|three|one",
+ "Documents not ordered correctly");
+ })
+ ]),
+ TestList("FirstByFields",
+ [
+ TestCase("succeeds when a document is found", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var doc = await Find.FirstByFields(PostgresDb.TableName, FieldMatch.Any,
+ [Field.EQ("Value", "another")]);
+ Expect.isNotNull(doc, "There should have been a document returned");
+ Expect.equal(doc.Id, "two", "The incorrect document was returned");
+ }),
+ TestCase("succeeds when multiple documents are found", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var doc = await Find.FirstByFields(PostgresDb.TableName, FieldMatch.Any,
+ [Field.EQ("Value", "purple")]);
+ Expect.isNotNull(doc, "There should have been a document returned");
+ Expect.contains(["five", "four"], doc.Id, "An incorrect document was returned");
+ }),
+ TestCase("succeeds when a document is not found", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var doc = await Find.FirstByFields(PostgresDb.TableName, FieldMatch.Any,
+ [Field.EQ("Value", "absent")]);
+ Expect.isNull(doc, "There should not have been a document returned");
+ })
+ ]),
+ TestList("FirstByFieldsOrdered",
+ [
+ TestCase("succeeds when sorting ascending", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var doc = await Find.FirstByFieldsOrdered(PostgresDb.TableName, FieldMatch.Any,
+ [Field.EQ("Value", "purple")], [Field.Named("Id")]);
+ Expect.isNotNull(doc, "There should have been a document returned");
+ Expect.equal("five", doc.Id, "An incorrect document was returned");
+ }),
+ TestCase("succeeds when a document is not found", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var doc = await Find.FirstByFieldsOrdered(PostgresDb.TableName, FieldMatch.Any,
+ [Field.EQ("Value", "purple")], [Field.Named("Id DESC")]);
+ Expect.isNotNull(doc, "There should have been a document returned");
+ Expect.equal("four", doc.Id, "An incorrect document was returned");
+ })
+ ]),
+ TestList("FirstByContains",
+ [
+ TestCase("succeeds when a document is found", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var doc = await Find.FirstByContains(PostgresDb.TableName, new { Value = "another" });
+ Expect.isNotNull(doc, "There should have been a document returned");
+ Expect.equal(doc.Id, "two", "The incorrect document was returned");
+ }),
+ TestCase("succeeds when multiple documents are found", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var doc = await Find.FirstByContains(PostgresDb.TableName,
+ new { Sub = new { Foo = "green" } });
+ Expect.isNotNull(doc, "There should have been a document returned");
+ Expect.contains(["two", "four"], doc.Id, "An incorrect document was returned");
+ }),
+ TestCase("succeeds when a document is not found", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var doc = await Find.FirstByContains(PostgresDb.TableName, new { Value = "absent" });
+ Expect.isNull(doc, "There should not have been a document returned");
+ })
+ ]),
+ TestList("FirstByJsonPath",
+ [
+ TestCase("succeeds when a document is found", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var doc = await Find.FirstByJsonPath(PostgresDb.TableName,
+ "$.Value ? (@ == \"FIRST!\")");
+ Expect.isNotNull(doc, "There should have been a document returned");
+ Expect.equal(doc.Id, "one", "The incorrect document was returned");
+ }),
+ TestCase("succeeds when multiple documents are found", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var doc = await Find.FirstByJsonPath(PostgresDb.TableName,
+ "$.Sub.Foo ? (@ == \"green\")");
+ Expect.isNotNull(doc, "There should have been a document returned");
+ Expect.contains(["two", "four"], doc.Id, "An incorrect document was returned");
+ }),
+ TestCase("succeeds when a document is not found", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ var doc = await Find.FirstByJsonPath(PostgresDb.TableName, "$.Id ? (@ == \"nope\")");
+ Expect.isNull(doc, "There should not have been a document returned");
+ })
+ ])
+ ]);
+
+ ///
+ /// Integration tests for the Update module of the PostgreSQL library
+ ///
+ private static readonly Test UpdateTests = TestList("Update",
+ [
+ TestList("ById",
+ [
+ TestCase("succeeds when a document is updated", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ await Update.ById(PostgresDb.TableName, "one",
+ new JsonDocument { Id = "one", Sub = new() { Foo = "blue", Bar = "red" } });
+ var after = await Find.ById(PostgresDb.TableName, "one");
+ Expect.isNotNull(after, "There should have been a document returned post-update");
+ Expect.equal(after.Id, "one", "The updated document is not correct (ID)");
+ Expect.equal(after.Value, "", "The updated document is not correct (Value)");
+ Expect.equal(after.NumValue, 0, "The updated document is not correct (NumValue)");
+ Expect.isNotNull(after.Sub, "The updated document should have had a sub-document");
+ Expect.equal(after.Sub!.Foo, "blue", "The updated document is not correct (Sub.Foo)");
+ Expect.equal(after.Sub.Bar, "red", "The updated document is not correct (Sub.Bar)");
+ }),
+ TestCase("succeeds when no document is updated", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+
+ var before = await Count.All(PostgresDb.TableName);
+ Expect.equal(before, 0, "There should have been no documents returned");
+
+ // This not raising an exception is the test
+ await Update.ById(PostgresDb.TableName, "test",
+ new JsonDocument { Id = "x", Sub = new() { Foo = "blue", Bar = "red" } });
+ })
+ ]),
+ TestList("ByFunc",
+ [
+ TestCase("succeeds when a document is updated", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ await Update.ByFunc(PostgresDb.TableName, doc => doc.Id,
+ new JsonDocument { Id = "one", Value = "le un", NumValue = 1 });
+ var after = await Find.ById(PostgresDb.TableName, "one");
+ Expect.isNotNull(after, "There should have been a document returned post-update");
+ Expect.equal(after.Id, "one", "The updated document is not correct (ID)");
+ Expect.equal(after.Value, "le un", "The updated document is not correct (Value)");
+ Expect.equal(after.NumValue, 1, "The updated document is not correct (NumValue)");
+ Expect.isNull(after.Sub, "The updated document should not have had a sub-document");
+ }),
+ TestCase("succeeds when no document is updated", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+
+ var before = await Count.All(PostgresDb.TableName);
+ Expect.equal(before, 0, "There should have been no documents returned");
+
+ // This not raising an exception is the test
+ await Update.ByFunc(PostgresDb.TableName, doc => doc.Id,
+ new JsonDocument { Id = "one", Value = "le un", NumValue = 1 });
+ })
+ ])
+ ]);
+
+ ///
+ /// Integration tests for the Patch module of the PostgreSQL library
+ ///
+ private static readonly Test PatchTests = TestList("Patch",
+ [
+ TestList("ById",
+ [
+ TestCase("succeeds when a document is updated", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ await Patch.ById(PostgresDb.TableName, "one", new { NumValue = 44 });
+ var after = await Find.ById(PostgresDb.TableName, "one");
+ Expect.isNotNull(after, "There should have been a document returned post-update");
+ Expect.equal(after.NumValue, 44, "The updated document is not correct");
+ }),
+ TestCase("succeeds when no document is updated", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+
+ var before = await Count.All(PostgresDb.TableName);
+ Expect.equal(before, 0, "There should have been no documents returned");
+
+ // This not raising an exception is the test
+ await Patch.ById(PostgresDb.TableName, "test", new { Foo = "green" });
+ })
+ ]),
+ TestList("ByFields",
+ [
+ TestCase("succeeds when a document is updated", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ await Patch.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("Value", "purple")],
+ new { NumValue = 77 });
+ var after = await Count.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", "77")]);
+ Expect.equal(after, 2, "There should have been 2 documents returned");
+ }),
+ TestCase("succeeds when no document is updated", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+
+ var before = await Count.All(PostgresDb.TableName);
+ Expect.equal(before, 0, "There should have been no documents returned");
+
+ // This not raising an exception is the test
+ await Patch.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("Value", "burgundy")],
+ new { Foo = "green" });
+ })
+ ]),
+ TestList("ByContains",
+ [
+ TestCase("succeeds when a document is updated", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ await Patch.ByContains(PostgresDb.TableName, new { Value = "purple" }, new { NumValue = 77 });
+ var after = await Count.ByContains(PostgresDb.TableName, new { NumValue = 77 });
+ Expect.equal(after, 2, "There should have been 2 documents returned");
+ }),
+ TestCase("succeeds when no document is updated", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+
+ var before = await Count.All(PostgresDb.TableName);
+ Expect.equal(before, 0, "There should have been no documents returned");
+
+ // This not raising an exception is the test
+ await Patch.ByContains(PostgresDb.TableName, new { Value = "burgundy" }, new { Foo = "green" });
+ })
+ ]),
+ TestList("ByJsonPath",
+ [
+ TestCase("succeeds when a document is updated", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ await Patch.ByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ > 10)", new { NumValue = 1000 });
+ var after = await Count.ByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ > 999)");
+ Expect.equal(after, 2, "There should have been 2 documents returned");
+ }),
+ TestCase("succeeds when no document is updated", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+
+ var before = await Count.All(PostgresDb.TableName);
+ Expect.equal(before, 0, "There should have been no documents returned");
+
+ // This not raising an exception is the test
+ await Patch.ByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ < 0)", new { Foo = "green" });
+ })
+ ])
+ ]);
+
+ ///
+ /// Integration tests for the RemoveFields module of the PostgreSQL library
+ ///
+ private static readonly Test RemoveFieldsTests = TestList("RemoveFields",
+ [
+ TestList("ById",
+ [
+ TestCase("succeeds when multiple fields are removed", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ await RemoveFields.ById(PostgresDb.TableName, "two", ["Sub", "Value"]);
+ var updated = await Find.ById(PostgresDb.TableName, "two");
+ Expect.isNotNull(updated, "The updated document should have been retrieved");
+ Expect.equal(updated.Value, "", "The string value should have been removed");
+ Expect.isNull(updated.Sub, "The sub-document should have been removed");
+ }),
+ TestCase("succeeds when a single field is removed", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ await RemoveFields.ById(PostgresDb.TableName, "two", ["Sub"]);
+ var updated = await Find.ById(PostgresDb.TableName, "two");
+ Expect.isNotNull(updated, "The updated document should have been retrieved");
+ Expect.notEqual(updated.Value, "", "The string value should not have been removed");
+ Expect.isNull(updated.Sub, "The sub-document should have been removed");
+ }),
+ TestCase("succeeds when a field is not removed", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ // This not raising an exception is the test
+ await RemoveFields.ById(PostgresDb.TableName, "two", ["AFieldThatIsNotThere"]);
+ }),
+ TestCase("succeeds when no document is matched", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+
+ // This not raising an exception is the test
+ await RemoveFields.ById(PostgresDb.TableName, "two", ["Value"]);
+ })
+ ]),
+ TestList("ByFields",
+ [
+ TestCase("succeeds when multiple fields are removed", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ await RemoveFields.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", "17")],
+ ["Sub", "Value"]);
+ var updated = await Find.ById(PostgresDb.TableName, "four");
+ Expect.isNotNull(updated, "The updated document should have been retrieved");
+ Expect.equal(updated.Value, "", "The string value should have been removed");
+ Expect.isNull(updated.Sub, "The sub-document should have been removed");
+ }),
+ TestCase("succeeds when a single field is removed", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ await RemoveFields.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", "17")],
+ ["Sub"]);
+ var updated = await Find.ById(PostgresDb.TableName, "four");
+ Expect.isNotNull(updated, "The updated document should have been retrieved");
+ Expect.notEqual(updated.Value, "", "The string value should not have been removed");
+ Expect.isNull(updated.Sub, "The sub-document should have been removed");
+ }),
+ TestCase("succeeds when a field is not removed", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ // This not raising an exception is the test
+ await RemoveFields.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", "17")],
+ ["Nothing"]);
+ }),
+ TestCase("succeeds when no document is matched", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+
+ // This not raising an exception is the test
+ await RemoveFields.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.NE("Abracadabra", "apple")],
+ ["Value"]);
+ })
+ ]),
+ TestList("ByContains",
+ [
+ TestCase("succeeds when multiple fields are removed", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ await RemoveFields.ByContains(PostgresDb.TableName, new { NumValue = 17 }, ["Sub", "Value"]);
+ var updated = await Find.ById(PostgresDb.TableName, "four");
+ Expect.isNotNull(updated, "The updated document should have been retrieved");
+ Expect.equal(updated.Value, "", "The string value should have been removed");
+ Expect.isNull(updated.Sub, "The sub-document should have been removed");
+ }),
+ TestCase("succeeds when a single field is removed", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ await RemoveFields.ByContains(PostgresDb.TableName, new { NumValue = 17 }, ["Sub"]);
+ var updated = await Find.ById(PostgresDb.TableName, "four");
+ Expect.isNotNull(updated, "The updated document should have been retrieved");
+ Expect.notEqual(updated.Value, "", "The string value should not have been removed");
+ Expect.isNull(updated.Sub, "The sub-document should have been removed");
+ }),
+ TestCase("succeeds when a field is not removed", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ // This not raising an exception is the test
+ await RemoveFields.ByContains(PostgresDb.TableName, new { NumValue = 17 }, ["Nothing"]);
+ }),
+ TestCase("succeeds when no document is matched", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+
+ // This not raising an exception is the test
+ await RemoveFields.ByContains(PostgresDb.TableName, new { Abracadabra = "apple" }, ["Value"]);
+ })
+ ]),
+ TestList("ByJsonPath",
+ [
+ TestCase("succeeds when multiple fields are removed", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ await RemoveFields.ByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ == 17)", ["Sub", "Value"]);
+ var updated = await Find.ById(PostgresDb.TableName, "four");
+ Expect.isNotNull(updated, "The updated document should have been retrieved");
+ Expect.equal(updated.Value, "", "The string value should have been removed");
+ Expect.isNull(updated.Sub, "The sub-document should have been removed");
+ }),
+ TestCase("succeeds when a single field is removed", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ await RemoveFields.ByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ == 17)", ["Sub"]);
+ var updated = await Find.ById(PostgresDb.TableName, "four");
+ Expect.isNotNull(updated, "The updated document should have been retrieved");
+ Expect.notEqual(updated.Value, "", "The string value should not have been removed");
+ Expect.isNull(updated.Sub, "The sub-document should have been removed");
+ }),
+ TestCase("succeeds when a field is not removed", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ // This not raising an exception is the test
+ await RemoveFields.ByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ == 17)", ["Nothing"]);
+ }),
+ TestCase("succeeds when no document is matched", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+
+ // This not raising an exception is the test
+ await RemoveFields.ByJsonPath(PostgresDb.TableName, "$.Abracadabra ? (@ == \"apple\")", ["Value"]);
+ })
+ ])
+ ]);
+
+ ///
+ /// Integration tests for the Delete module of the PostgreSQL library
+ ///
+ private static readonly Test DeleteTests = TestList("Delete",
+ [
+ TestList("ById",
+ [
+ TestCase("succeeds when a document is deleted", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ await Delete.ById(PostgresDb.TableName, "four");
+ var remaining = await Count.All(PostgresDb.TableName);
+ Expect.equal(remaining, 4, "There should have been 4 documents remaining");
+ }),
+ TestCase("succeeds when a document is not deleted", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ await Delete.ById(PostgresDb.TableName, "thirty");
+ var remaining = await Count.All(PostgresDb.TableName);
+ Expect.equal(remaining, 5, "There should have been 5 documents remaining");
+ })
+ ]),
+ TestList("ByFields",
+ [
+ TestCase("succeeds when documents are deleted", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ await Delete.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("Value", "purple")]);
+ var remaining = await Count.All(PostgresDb.TableName);
+ Expect.equal(remaining, 3, "There should have been 3 documents remaining");
+ }),
+ TestCase("succeeds when documents are not deleted", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ await Delete.ByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("Value", "crimson")]);
+ var remaining = await Count.All(PostgresDb.TableName);
+ Expect.equal(remaining, 5, "There should have been 5 documents remaining");
+ })
+ ]),
+ TestList("ByContains",
+ [
+ TestCase("succeeds when documents are deleted", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ await Delete.ByContains(PostgresDb.TableName, new { Value = "purple" });
+ var remaining = await Count.All(PostgresDb.TableName);
+ Expect.equal(remaining, 3, "There should have been 3 documents remaining");
+ }),
+ TestCase("succeeds when documents are not deleted", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ await Delete.ByContains(PostgresDb.TableName, new { Value = "crimson" });
+ var remaining = await Count.All(PostgresDb.TableName);
+ Expect.equal(remaining, 5, "There should have been 5 documents remaining");
+ })
+ ]),
+ TestList("ByJsonPath",
+ [
+ TestCase("succeeds when documents are deleted", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ await Delete.ByJsonPath(PostgresDb.TableName, "$.Sub.Foo ? (@ == \"green\")");
+ var remaining = await Count.All(PostgresDb.TableName);
+ Expect.equal(remaining, 3, "There should have been 3 documents remaining");
+ }),
+ TestCase("succeeds when documents are not deleted", async () =>
+ {
+ await using var db = PostgresDb.BuildDb();
+ await LoadDocs();
+
+ await Delete.ByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ > 100)");
+ var remaining = await Count.All(PostgresDb.TableName);
+ Expect.equal(remaining, 5, "There should have been 5 documents remaining");
+ })
+ ])
+ ]);
+
///
/// All Postgres C# tests
///
[Tests]
- public static readonly Test All = TestList("Postgres.C#", [Unit, TestSequenced(Integration)]);
+ public static readonly Test All = TestList("Postgres.C#",
+ [
+ TestList("Unit",
+ [
+ ParametersTests,
+ QueryTests
+ ]),
+ TestSequenced(TestList("Integration",
+ [
+ ConfigurationTests,
+ CustomTests,
+ DefinitionTests,
+ DocumentTests,
+ CountTests,
+ ExistsTests,
+ FindTests,
+ UpdateTests,
+ PatchTests,
+ RemoveFieldsTests,
+ DeleteTests
+ ]))
+ ]);
}
diff --git a/src/Tests/PostgresTests.fs b/src/Tests/PostgresTests.fs
index 0a2e3ba..1c04aaa 100644
--- a/src/Tests/PostgresTests.fs
+++ b/src/Tests/PostgresTests.fs
@@ -7,1118 +7,1249 @@ open BitBadger.Documents.Tests
#nowarn "0044"
-/// Tests which do not hit the database
-let unitTests =
- testList "Unit" [
- testList "Parameters" [
- 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" |})
- ("@test", Sql.jsonb """{"Something":"good"}""")
- "JSON parameter not constructed correctly"
- }
- testList "addFieldParams" [
- 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 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"
- 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"
- Expect.equal (snd p[1]) (Sql.string "you") "Second parameter value not correct"
- Expect.equal (fst p[2]) "@field1" "Third parameter name not correct"
- 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" ] []
- Expect.isEmpty paramList "There should not have been any parameters added"
- }
- test "succeeds when two parameters are added for one field" {
- let paramList =
- addFieldParams [ { Field.BT "that" "eh" "zed" with ParameterName = Some "@test" } ] []
- Expect.hasLength paramList 2 "There should have been 2 parameters added"
- 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 "fieldNameParams" [
- test "succeeds for one name" {
- let name, value = fieldNameParams [ "bob" ]
- Expect.equal name "@name" "The parameter name was incorrect"
- 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"
- 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"
- 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"
- Expect.equal value (Sql.stringArray [| "bob"; "tom"; "mike" |]) "The parameter value was incorrect"
- }
- ]
- test "noParams succeeds" {
- Expect.isEmpty noParams "The no-params sequence should be empty"
- }
- ]
- testList "Query" [
- 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" } ])
- "data->>'theField' > @test"
- "WHERE clause not correct"
- }
- test "succeeds for a single field when an existence operator is passed" {
- Expect.equal
- (Query.whereByFields Any [ Field.NEX "thatField" ])
- "data->>'thatField' IS NULL"
- "WHERE clause not correct"
- }
- test "succeeds for a single field when a between operator is passed with numeric values" {
- Expect.equal
- (Query.whereByFields All [ { Field.BT "aField" 50 99 with ParameterName = Some "@range" } ])
- "(data->>'aField')::numeric BETWEEN @rangemin AND @rangemax"
- "WHERE clause not correct"
- }
- test "succeeds for a single field when a between operator is passed with non-numeric values" {
- Expect.equal
- (Query.whereByFields Any [ { Field.BT "field0" "a" "b" with ParameterName = Some "@alpha" } ])
- "data->>'field0' BETWEEN @alphamin AND @alphamax"
- "WHERE clause not correct"
- }
- test "succeeds for all multiple fields with logical operators" {
- Expect.equal
- (Query.whereByFields All [ Field.EQ "theFirst" "1"; Field.EQ "numberTwo" "2" ])
- "data->>'theFirst' = @field0 AND data->>'numberTwo' = @field1"
- "WHERE clause not correct"
- }
- 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')::numeric >= @field0"
- "WHERE clause not correct"
- }
- test "succeeds for all multiple fields with between operators" {
- Expect.equal
- (Query.whereByFields All [ Field.BT "aField" 50 99; Field.BT "anotherField" "a" "b" ])
- "(data->>'aField')::numeric BETWEEN @field0min AND @field0max AND data->>'anotherField' BETWEEN @field1min AND @field1max"
- "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
- (Query.Definition.ensureTable PostgresDb.TableName)
- $"CREATE TABLE IF NOT EXISTS {PostgresDb.TableName} (data JSONB NOT NULL)"
- "CREATE TABLE statement not constructed correctly"
- }
- test "ensureDocumentIndex succeeds for full index" {
- Expect.equal
- (Query.Definition.ensureDocumentIndex "schema.tbl" Full)
- "CREATE INDEX IF NOT EXISTS idx_tbl_document ON schema.tbl USING GIN (data)"
- "CREATE INDEX statement not constructed correctly"
- }
- test "ensureDocumentIndex succeeds for JSONB Path Ops index" {
- Expect.equal
- (Query.Definition.ensureDocumentIndex PostgresDb.TableName Optimized)
- (sprintf "CREATE INDEX IF NOT EXISTS idx_%s_document ON %s USING GIN (data jsonb_path_ops)"
- PostgresDb.TableName PostgresDb.TableName)
- "CREATE INDEX statement not constructed correctly"
- }
- ]
- test "whereDataContains succeeds" {
- Expect.equal (Query.whereDataContains "@test") "data @> @test" "WHERE clause not correct"
- }
- test "whereJsonPathMatches succeeds" {
- Expect.equal (Query.whereJsonPathMatches "@path") "data @? @path::jsonpath" "WHERE clause not correct"
- }
- test "patch succeeds" {
- Expect.equal
- (Query.patch PostgresDb.TableName)
- $"UPDATE {PostgresDb.TableName} SET data = data || @data"
- "Patch query not correct"
- }
- test "removeFields succeeds" {
- Expect.equal
- (Query.removeFields PostgresDb.TableName)
- $"UPDATE {PostgresDb.TableName} SET data = data - @name"
- "Field removal query not correct"
- }
- test "byId succeeds" {
- Expect.equal (Query.byId "test" "14") "test WHERE data->>'Id' = @id" "By-ID query not correct"
- }
- test "byFields succeeds" {
- Expect.equal
- (Query.byFields "unit" Any [ Field.GT "That" 14 ])
- "unit WHERE (data->>'That')::numeric > @field0"
- "By-Field query not correct"
- }
- test "byContains succeeds" {
- Expect.equal (Query.byContains "exam") "exam WHERE data @> @criteria" "By-Contains query not correct"
- }
- test "byPathMach succeeds" {
- Expect.equal
- (Query.byPathMatch "verify") "verify WHERE data @? @path::jsonpath" "By-JSON Path query not correct"
- }
- ]
+(** UNIT TESTS **)
+
+/// Unit tests for the Parameters module of the PostgreSQL library
+let parametersTests = testList "Parameters" [
+ 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" |})
+ ("@test", Sql.jsonb """{"Something":"good"}""")
+ "JSON parameter not constructed correctly"
+ }
+ testList "addFieldParams" [
+ 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 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"
+ 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"
+ Expect.equal (snd p[1]) (Sql.string "you") "Second parameter value not correct"
+ Expect.equal (fst p[2]) "@field1" "Third parameter name not correct"
+ 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" ] []
+ Expect.isEmpty paramList "There should not have been any parameters added"
+ }
+ test "succeeds when two parameters are added for one field" {
+ let paramList = addFieldParams [ { Field.BT "that" "eh" "zed" with ParameterName = Some "@test" } ] []
+ Expect.hasLength paramList 2 "There should have been 2 parameters added"
+ 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 "fieldNameParams" [
+ test "succeeds for one name" {
+ let name, value = fieldNameParams [ "bob" ]
+ Expect.equal name "@name" "The parameter name was incorrect"
+ 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"
+ 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"
+ 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"
+ Expect.equal value (Sql.stringArray [| "bob"; "tom"; "mike" |]) "The parameter value was incorrect"
+ }
+ ]
+ test "noParams succeeds" {
+ Expect.isEmpty noParams "The no-params sequence should be empty"
+ }
+]
+
+/// Unit tests for the Query module of the PostgreSQL library
+let queryTests = testList "Query" [
+ 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" } ])
+ "data->>'theField' > @test"
+ "WHERE clause not correct"
+ }
+ test "succeeds for a single field when an existence operator is passed" {
+ Expect.equal
+ (Query.whereByFields Any [ Field.NEX "thatField" ])
+ "data->>'thatField' IS NULL"
+ "WHERE clause not correct"
+ }
+ test "succeeds for a single field when a between operator is passed with numeric values" {
+ Expect.equal
+ (Query.whereByFields All [ { Field.BT "aField" 50 99 with ParameterName = Some "@range" } ])
+ "(data->>'aField')::numeric BETWEEN @rangemin AND @rangemax"
+ "WHERE clause not correct"
+ }
+ test "succeeds for a single field when a between operator is passed with non-numeric values" {
+ Expect.equal
+ (Query.whereByFields Any [ { Field.BT "field0" "a" "b" with ParameterName = Some "@alpha" } ])
+ "data->>'field0' BETWEEN @alphamin AND @alphamax"
+ "WHERE clause not correct"
+ }
+ test "succeeds for all multiple fields with logical operators" {
+ Expect.equal
+ (Query.whereByFields All [ Field.EQ "theFirst" "1"; Field.EQ "numberTwo" "2" ])
+ "data->>'theFirst' = @field0 AND data->>'numberTwo' = @field1"
+ "WHERE clause not correct"
+ }
+ 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')::numeric >= @field0"
+ "WHERE clause not correct"
+ }
+ test "succeeds for all multiple fields with between operators" {
+ Expect.equal
+ (Query.whereByFields All [ Field.BT "aField" 50 99; Field.BT "anotherField" "a" "b" ])
+ "(data->>'aField')::numeric BETWEEN @field0min AND @field0max AND data->>'anotherField' BETWEEN @field1min AND @field1max"
+ "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
+ (Query.Definition.ensureTable PostgresDb.TableName)
+ $"CREATE TABLE IF NOT EXISTS {PostgresDb.TableName} (data JSONB NOT NULL)"
+ "CREATE TABLE statement not constructed correctly"
+ }
+ test "ensureDocumentIndex succeeds for full index" {
+ Expect.equal
+ (Query.Definition.ensureDocumentIndex "schema.tbl" Full)
+ "CREATE INDEX IF NOT EXISTS idx_tbl_document ON schema.tbl USING GIN (data)"
+ "CREATE INDEX statement not constructed correctly"
+ }
+ test "ensureDocumentIndex succeeds for JSONB Path Ops index" {
+ Expect.equal
+ (Query.Definition.ensureDocumentIndex PostgresDb.TableName Optimized)
+ (sprintf "CREATE INDEX IF NOT EXISTS idx_%s_document ON %s USING GIN (data jsonb_path_ops)"
+ PostgresDb.TableName PostgresDb.TableName)
+ "CREATE INDEX statement not constructed correctly"
+ }
+ ]
+ test "whereDataContains succeeds" {
+ Expect.equal (Query.whereDataContains "@test") "data @> @test" "WHERE clause not correct"
+ }
+ test "whereJsonPathMatches succeeds" {
+ Expect.equal (Query.whereJsonPathMatches "@path") "data @? @path::jsonpath" "WHERE clause not correct"
+ }
+ test "patch succeeds" {
+ Expect.equal
+ (Query.patch PostgresDb.TableName)
+ $"UPDATE {PostgresDb.TableName} SET data = data || @data"
+ "Patch query not correct"
+ }
+ test "removeFields succeeds" {
+ Expect.equal
+ (Query.removeFields PostgresDb.TableName)
+ $"UPDATE {PostgresDb.TableName} SET data = data - @name"
+ "Field removal query not correct"
+ }
+ test "byId succeeds" {
+ Expect.equal (Query.byId "test" "14") "test WHERE data->>'Id' = @id" "By-ID query not correct"
+ }
+ test "byFields succeeds" {
+ Expect.equal
+ (Query.byFields "unit" Any [ Field.GT "That" 14 ])
+ "unit WHERE (data->>'That')::numeric > @field0"
+ "By-Field query not correct"
+ }
+ test "byContains succeeds" {
+ Expect.equal (Query.byContains "exam") "exam WHERE data @> @criteria" "By-Contains query not correct"
+ }
+ test "byPathMach succeeds" {
+ Expect.equal
+ (Query.byPathMatch "verify") "verify WHERE data @? @path::jsonpath" "By-JSON Path query not correct"
+ }
+]
+
+(** INTEGRATION TESTS **)
open ThrowawayDb.Postgres
open Types
-let isTrue<'T> (_ : 'T) = true
+/// Documents to use for integration tests
+let documents = [
+ { Id = "one"; Value = "FIRST!"; NumValue = 0; Sub = None }
+ { Id = "two"; Value = "another"; NumValue = 10; Sub = Some { Foo = "green"; Bar = "blue" } }
+ { Id = "three"; Value = ""; NumValue = 4; Sub = None }
+ { Id = "four"; Value = "purple"; NumValue = 17; Sub = Some { Foo = "green"; Bar = "red" } }
+ { Id = "five"; Value = "purple"; NumValue = 18; Sub = None }
+]
-let integrationTests =
- let documents = [
- { Id = "one"; Value = "FIRST!"; NumValue = 0; Sub = None }
- { Id = "two"; Value = "another"; NumValue = 10; Sub = Some { Foo = "green"; Bar = "blue" } }
- { Id = "three"; Value = ""; NumValue = 4; Sub = None }
- { Id = "four"; Value = "purple"; NumValue = 17; Sub = Some { Foo = "green"; Bar = "red" } }
- { Id = "five"; Value = "purple"; NumValue = 18; Sub = None }
- ]
- let loadDocs () = backgroundTask {
- for doc in documents do do! insert PostgresDb.TableName doc
+/// Load the test documents into the database
+let loadDocs () = backgroundTask {
+ for doc in documents do do! insert PostgresDb.TableName doc
+}
+
+/// Integration tests for the Configuration module of the PostgreSQL library
+let configurationTests = testList "Configuration" [
+ test "useDataSource disposes existing source" {
+ use db1 = ThrowawayDatabase.Create PostgresDb.ConnStr.Value
+ let source = PostgresDb.MkDataSource db1.ConnectionString
+ Configuration.useDataSource source
+
+ use db2 = ThrowawayDatabase.Create PostgresDb.ConnStr.Value
+ Configuration.useDataSource (PostgresDb.MkDataSource db2.ConnectionString)
+ Expect.throws (fun () -> source.OpenConnection() |> ignore) "Data source should have been disposed"
}
- testList "Integration" [
- testList "Configuration" [
- test "useDataSource disposes existing source" {
- use db1 = ThrowawayDatabase.Create PostgresDb.ConnStr.Value
- let source = PostgresDb.MkDataSource db1.ConnectionString
- Configuration.useDataSource source
-
- use db2 = ThrowawayDatabase.Create PostgresDb.ConnStr.Value
- Configuration.useDataSource (PostgresDb.MkDataSource db2.ConnectionString)
- Expect.throws (fun () -> source.OpenConnection() |> ignore) "Data source should have been disposed"
- }
- test "dataSource returns configured data source" {
- use db = ThrowawayDatabase.Create PostgresDb.ConnStr.Value
- let source = PostgresDb.MkDataSource db.ConnectionString
- Configuration.useDataSource source
-
- Expect.isTrue (obj.ReferenceEquals(source, Configuration.dataSource ()))
- "Data source should have been the same"
- }
- ]
- testList "Custom" [
- testList "list" [
- testTask "succeeds when data is found" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! docs = Custom.list (Query.selectFromTable PostgresDb.TableName) [] fromData
- Expect.hasCountOf docs 5u isTrue "There should have been 5 documents returned"
- }
- testTask "succeeds when data is not found" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! docs =
- Custom.list $"SELECT data FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath"
- [ "@path", Sql.string "$.NumValue ? (@ > 100)" ] fromData
- Expect.isEmpty docs "There should have been no documents returned"
- }
- ]
- testList "single" [
- testTask "succeeds when a row is found" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! doc =
- Custom.single $"SELECT data FROM {PostgresDb.TableName} WHERE data ->> 'Id' = @id"
- [ "@id", Sql.string "one"] fromData
- Expect.isSome doc "There should have been a document returned"
- Expect.equal doc.Value.Id "one" "The incorrect document was returned"
- }
- testTask "succeeds when a row is not found" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! doc =
- Custom.single $"SELECT data FROM {PostgresDb.TableName} WHERE data ->> 'Id' = @id"
- [ "@id", Sql.string "eighty" ] fromData
- Expect.isNone doc "There should not have been a document returned"
- }
- ]
- testList "nonQuery" [
- testTask "succeeds when operating on data" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- do! Custom.nonQuery $"DELETE FROM {PostgresDb.TableName}" []
-
- let! remaining = Count.all PostgresDb.TableName
- Expect.equal remaining 0 "There should be no documents remaining in the table"
- }
- testTask "succeeds when no data matches where clause" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- do! Custom.nonQuery $"DELETE FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath"
- [ "@path", Sql.string "$.NumValue ? (@ > 100)" ]
-
- let! remaining = Count.all PostgresDb.TableName
- Expect.equal remaining 5 "There should be 5 documents remaining in the table"
- }
- ]
- testTask "scalar succeeds" {
- use db = PostgresDb.BuildDb()
- let! nbr = Custom.scalar "SELECT 5 AS test_value" [] (fun row -> row.int "test_value")
- Expect.equal nbr 5 "The query should have returned the number 5"
- }
- ]
- testList "Definition" [
- testTask "ensureTable succeeds" {
- use db = PostgresDb.BuildDb()
- let tableExists () =
- Custom.scalar "SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'ensured') AS it" [] toExists
- let keyExists () =
- Custom.scalar
- "SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'idx_ensured_key') AS it" [] toExists
-
- let! exists = tableExists ()
- let! alsoExists = keyExists ()
- Expect.isFalse exists "The table should not exist already"
- Expect.isFalse alsoExists "The key index should not exist already"
-
- do! Definition.ensureTable "ensured"
- let! exists' = tableExists ()
- let! alsoExists' = keyExists ()
- Expect.isTrue exists' "The table should now exist"
- Expect.isTrue alsoExists' "The key index should now exist"
- }
- testTask "ensureDocumentIndex succeeds" {
- use db = PostgresDb.BuildDb()
- let indexExists () =
- Custom.scalar
- "SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'idx_ensured_document') AS it"
- []
- toExists
-
- let! exists = indexExists ()
- Expect.isFalse exists "The index should not exist already"
-
- do! Definition.ensureTable "ensured"
- do! Definition.ensureDocumentIndex "ensured" Optimized
- let! exists' = indexExists ()
- Expect.isTrue exists' "The index should now exist"
- }
- testTask "ensureFieldIndex succeeds" {
- use db = PostgresDb.BuildDb()
- let indexExists () =
- Custom.scalar
- "SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'idx_ensured_test') AS it" [] toExists
-
- let! exists = indexExists ()
- Expect.isFalse exists "The index should not exist already"
-
- do! Definition.ensureTable "ensured"
- do! Definition.ensureFieldIndex "ensured" "test" [ "Id"; "Category" ]
- let! exists' = indexExists ()
- Expect.isTrue exists' "The index should now exist"
- }
- ]
- testList "insert" [
- testTask "succeeds" {
- use db = PostgresDb.BuildDb()
- let! before = Find.all PostgresDb.TableName
- Expect.equal before [] "There should be no documents in the table"
-
- let testDoc = { emptyDoc with Id = "turkey"; Sub = Some { Foo = "gobble"; Bar = "gobble" } }
- do! insert PostgresDb.TableName testDoc
- let! after = Find.all PostgresDb.TableName
- Expect.equal after [ testDoc ] "There should have been one document inserted"
- }
- testTask "fails for duplicate key" {
- use db = PostgresDb.BuildDb()
- do! insert PostgresDb.TableName { emptyDoc with Id = "test" }
- Expect.throws
- (fun () ->
- insert PostgresDb.TableName {emptyDoc with Id = "test" }
- |> Async.AwaitTask
- |> Async.RunSynchronously)
- "An exception should have been raised for duplicate document ID insert"
- }
- ]
- testList "save" [
- testTask "succeeds when a document is inserted" {
- use db = PostgresDb.BuildDb()
- let! before = Find.all PostgresDb.TableName
- Expect.equal before [] "There should be no documents in the table"
-
- let testDoc = { emptyDoc with Id = "test"; Sub = Some { Foo = "a"; Bar = "b" } }
- do! save PostgresDb.TableName testDoc
- let! after = Find.all PostgresDb.TableName
- Expect.equal after [ testDoc ] "There should have been one document inserted"
- }
- testTask "succeeds when a document is updated" {
- use db = PostgresDb.BuildDb()
- let testDoc = { emptyDoc with Id = "test"; Sub = Some { Foo = "a"; Bar = "b" } }
- do! insert PostgresDb.TableName testDoc
-
- let! before = Find.byId PostgresDb.TableName "test"
- Expect.isSome before "There should have been a document returned"
- Expect.equal before.Value testDoc "The document is not correct"
-
- let upd8Doc = { testDoc with Sub = Some { Foo = "c"; Bar = "d" } }
- do! save PostgresDb.TableName upd8Doc
- let! after = Find.byId PostgresDb.TableName "test"
- Expect.isSome after "There should have been a document returned post-update"
- Expect.equal after.Value upd8Doc "The updated document is not correct"
- }
- ]
- testList "Count" [
- testTask "all succeeds" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! theCount = Count.all PostgresDb.TableName
- Expect.equal theCount 5 "There should have been 5 matching documents"
- }
- testList "byFields" [
- testTask "succeeds when items are found" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! theCount =
- Count.byFields PostgresDb.TableName Any [ Field.BT "NumValue" 15 20; Field.EQ "NumValue" 0 ]
- Expect.equal theCount 3 "There should have been 3 matching documents"
- }
- testTask "succeeds when items are not found" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! theCount = Count.byFields PostgresDb.TableName All [ Field.EX "Sub"; Field.GT "NumValue" 100 ]
- Expect.equal theCount 0 "There should have been no matching documents"
- }
- ]
- testTask "byContains succeeds" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! theCount = Count.byContains PostgresDb.TableName {| Value = "purple" |}
- Expect.equal theCount 2 "There should have been 2 matching documents"
- }
- testTask "byJsonPath succeeds" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! theCount = Count.byJsonPath PostgresDb.TableName "$.NumValue ? (@ > 5)"
- Expect.equal theCount 3 "There should have been 3 matching documents"
- }
- ]
- testList "Exists" [
- testList "byId" [
- testTask "succeeds when a document exists" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! exists = Exists.byId PostgresDb.TableName "three"
- Expect.isTrue exists "There should have been an existing document"
- }
- testTask "succeeds when a document does not exist" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! exists = Exists.byId PostgresDb.TableName "seven"
- Expect.isFalse exists "There should not have been an existing document"
- }
- ]
- testList "byFields" [
- testTask "succeeds when documents exist" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! exists = Exists.byFields PostgresDb.TableName Any [ Field.EX "Sub"; Field.EX "Boo" ]
- Expect.isTrue exists "There should have been existing documents"
- }
- testTask "succeeds when documents do not exist" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! exists =
- Exists.byFields PostgresDb.TableName All [ Field.EQ "NumValue" "six"; Field.EX "Nope" ]
- Expect.isFalse exists "There should not have been existing documents"
- }
- ]
- testList "byContains" [
- testTask "succeeds when documents exist" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! exists = Exists.byContains PostgresDb.TableName {| NumValue = 10 |}
- Expect.isTrue exists "There should have been existing documents"
- }
- testTask "succeeds when no matching documents exist" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! exists = Exists.byContains PostgresDb.TableName {| Nothing = "none" |}
- Expect.isFalse exists "There should not have been any existing documents"
- }
- ]
- testList "byJsonPath" [
- testTask "succeeds when documents exist" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! exists = Exists.byJsonPath PostgresDb.TableName """$.Sub.Foo ? (@ == "green")"""
- Expect.isTrue exists "There should have been existing documents"
- }
- testTask "succeeds when no matching documents exist" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! exists = Exists.byJsonPath PostgresDb.TableName "$.NumValue ? (@ > 1000)"
- Expect.isFalse exists "There should not have been any existing documents"
- }
- ]
- ]
- testList "Find" [
- testList "all" [
- testTask "succeeds when there is data" {
- use db = PostgresDb.BuildDb()
-
- do! insert PostgresDb.TableName { Foo = "one"; Bar = "two" }
- do! insert PostgresDb.TableName { Foo = "three"; Bar = "four" }
- do! insert PostgresDb.TableName { Foo = "five"; Bar = "six" }
-
- let! results = Find.all PostgresDb.TableName
- let expected = [
- { Foo = "one"; Bar = "two" }
- { Foo = "three"; Bar = "four" }
- { Foo = "five"; Bar = "six" }
- ]
- Expect.equal results expected "There should have been 3 documents returned"
- }
- testTask "succeeds when there is no data" {
- use db = PostgresDb.BuildDb()
- let! results = Find.all PostgresDb.TableName
- Expect.equal results [] "There should have been no documents returned"
- }
- ]
- ftestList "allOrdered" [
- testTask "succeeds when ordering numerically" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! results = Find.allOrdered PostgresDb.TableName [ Field.Named "n:NumValue" ]
- Expect.hasLength results 5 "There should have been 5 documents returned"
- Expect.equal
- (results |> List.map _.Id |> String.concat "|")
- "one|three|two|four|five"
- "The documents were not ordered correctly"
- }
- testTask "succeeds when ordering alphabetically" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! results = Find.allOrdered PostgresDb.TableName [ Field.Named "Id DESC" ]
- Expect.hasLength results 5 "There should have been 5 documents returned"
- Expect.equal
- (results |> List.map _.Id |> String.concat "|")
- "two|three|one|four|five"
- "The documents were not ordered correctly"
- }
- ]
- testList "byId" [
- testTask "succeeds when a document is found" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! doc = Find.byId PostgresDb.TableName "two"
- Expect.isSome doc "There should have been a document returned"
- Expect.equal doc.Value.Id "two" "The incorrect document was returned"
- }
- testTask "succeeds when a document is not found" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! doc = Find.byId PostgresDb.TableName "three hundred eighty-seven"
- Expect.isNone doc "There should not have been a document returned"
- }
- ]
- testList "byFields" [
- testTask "succeeds when documents are found" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! docs =
- Find.byFields
- PostgresDb.TableName All [ Field.EQ "Value" "purple"; Field.EX "Sub" ]
- Expect.equal (List.length docs) 1 "There should have been one document returned"
- }
- testTask "succeeds when documents are not found" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! docs =
- Find.byFields
- PostgresDb.TableName All [ Field.EQ "Value" "mauve"; Field.NE "NumValue" 40 ]
- Expect.isEmpty docs "There should have been no documents returned"
- }
- ]
- testList "byContains" [
- testTask "succeeds when documents are found" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! docs = Find.byContains PostgresDb.TableName {| Sub = {| Foo = "green" |} |}
- Expect.equal (List.length docs) 2 "There should have been two documents returned"
- }
- testTask "succeeds when documents are not found" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! docs = Find.byContains PostgresDb.TableName {| Value = "mauve" |}
- Expect.isEmpty docs "There should have been no documents returned"
- }
- ]
- testList "byJsonPath" [
- testTask "succeeds when documents are found" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! docs = Find.byJsonPath PostgresDb.TableName "$.NumValue ? (@ < 15)"
- Expect.equal (List.length docs) 3 "There should have been 3 documents returned"
- }
- testTask "succeeds when documents are not found" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! docs = Find.byJsonPath PostgresDb.TableName "$.NumValue ? (@ < 0)"
- Expect.isEmpty docs "There should have been no documents returned"
- }
- ]
- testList "firstByFields" [
- testTask "succeeds when a document is found" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! doc = Find.firstByFields PostgresDb.TableName Any [ Field.EQ "Value" "another" ]
- Expect.isSome doc "There should have been a document returned"
- Expect.equal doc.Value.Id "two" "The incorrect document was returned"
- }
- testTask "succeeds when multiple documents are found" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! doc = Find.firstByFields PostgresDb.TableName Any [ Field.EQ "Value" "purple" ]
- Expect.isSome doc "There should have been a document returned"
- Expect.contains [ "five"; "four" ] doc.Value.Id "An incorrect document was returned"
- }
- testTask "succeeds when a document is not found" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! doc = Find.firstByFields PostgresDb.TableName Any [ Field.EQ "Value" "absent" ]
- Expect.isNone doc "There should not have been a document returned"
- }
- ]
- testList "firstByContains" [
- testTask "succeeds when a document is found" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! doc = Find.firstByContains PostgresDb.TableName {| Value = "another" |}
- Expect.isSome doc "There should have been a document returned"
- Expect.equal doc.Value.Id "two" "The incorrect document was returned"
- }
- testTask "succeeds when multiple documents are found" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! doc = Find.firstByContains PostgresDb.TableName {| Sub = {| Foo = "green" |} |}
- Expect.isSome doc "There should have been a document returned"
- Expect.contains [ "two"; "four" ] doc.Value.Id "An incorrect document was returned"
- }
- testTask "succeeds when a document is not found" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! doc = Find.firstByContains PostgresDb.TableName {| Value = "absent" |}
- Expect.isNone doc "There should not have been a document returned"
- }
- ]
- testList "firstByJsonPath" [
- testTask "succeeds when a document is found" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! doc = Find.firstByJsonPath PostgresDb.TableName """$.Value ? (@ == "FIRST!")"""
- Expect.isSome doc "There should have been a document returned"
- Expect.equal doc.Value.Id "one" "The incorrect document was returned"
- }
- testTask "succeeds when multiple documents are found" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! doc = Find.firstByJsonPath PostgresDb.TableName """$.Sub.Foo ? (@ == "green")"""
- Expect.isSome doc "There should have been a document returned"
- Expect.contains [ "two"; "four" ] doc.Value.Id "An incorrect document was returned"
- }
- testTask "succeeds when a document is not found" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let! doc = Find.firstByJsonPath PostgresDb.TableName """$.Id ? (@ == "nope")"""
- Expect.isNone doc "There should not have been a document returned"
- }
- ]
- ]
- testList "Update" [
- testList "byId" [
- testTask "succeeds when a document is updated" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- let testDoc = { emptyDoc with Id = "one"; Sub = Some { Foo = "blue"; Bar = "red" } }
- do! Update.byId PostgresDb.TableName "one" testDoc
- let! after = Find.byId PostgresDb.TableName "one"
- Expect.isSome after "There should have been a document returned post-update"
- Expect.equal after.Value testDoc "The updated document is not correct"
- }
- testTask "succeeds when no document is updated" {
- use db = PostgresDb.BuildDb()
-
- let! before = Count.all PostgresDb.TableName
- Expect.equal before 0 "There should have been no documents returned"
-
- // This not raising an exception is the test
- do! Update.byId
- PostgresDb.TableName
- "test"
- { emptyDoc with Id = "x"; Sub = Some { Foo = "blue"; Bar = "red" } }
- }
- ]
- testList "byFunc" [
- testTask "succeeds when a document is updated" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- do! Update.byFunc PostgresDb.TableName (_.Id)
- { Id = "one"; Value = "le un"; NumValue = 1; Sub = None }
- let! after = Find.byId PostgresDb.TableName "one"
- Expect.isSome after "There should have been a document returned post-update"
- Expect.equal
- after.Value
- { Id = "one"; Value = "le un"; NumValue = 1; Sub = None }
- "The updated document is not correct"
- }
- testTask "succeeds when no document is updated" {
- use db = PostgresDb.BuildDb()
-
- let! before = Count.all PostgresDb.TableName
- Expect.equal before 0 "There should have been no documents returned"
-
- // This not raising an exception is the test
- do! Update.byFunc
- PostgresDb.TableName (_.Id) { Id = "one"; Value = "le un"; NumValue = 1; Sub = None }
- }
- ]
- ]
- testList "Patch" [
- testList "byId" [
- testTask "succeeds when a document is updated" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- do! Patch.byId PostgresDb.TableName "one" {| NumValue = 44 |}
- let! after = Find.byId PostgresDb.TableName "one"
- Expect.isSome after "There should have been a document returned post-update"
- Expect.equal after.Value.NumValue 44 "The updated document is not correct"
- }
- testTask "succeeds when no document is updated" {
- use db = PostgresDb.BuildDb()
-
- let! before = Count.all PostgresDb.TableName
- Expect.equal before 0 "There should have been no documents returned"
-
- // This not raising an exception is the test
- do! Patch.byId PostgresDb.TableName "test" {| Foo = "green" |}
- }
- ]
- testList "byFields" [
- testTask "succeeds when a document is updated" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- do! Patch.byFields PostgresDb.TableName Any [ Field.EQ "Value" "purple" ] {| NumValue = 77 |}
- let! after = Count.byFields PostgresDb.TableName Any [ Field.EQ "NumValue" 77 ]
- Expect.equal after 2 "There should have been 2 documents returned"
- }
- testTask "succeeds when no document is updated" {
- use db = PostgresDb.BuildDb()
-
- let! before = Count.all PostgresDb.TableName
- Expect.equal before 0 "There should have been no documents returned"
-
- // This not raising an exception is the test
- do! Patch.byFields PostgresDb.TableName Any [ Field.EQ "Value" "burgundy" ] {| Foo = "green" |}
- }
- ]
- testList "byContains" [
- testTask "succeeds when a document is updated" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- do! Patch.byContains PostgresDb.TableName {| Value = "purple" |} {| NumValue = 77 |}
- let! after = Count.byContains PostgresDb.TableName {| NumValue = 77 |}
- Expect.equal after 2 "There should have been 2 documents returned"
- }
- testTask "succeeds when no document is updated" {
- use db = PostgresDb.BuildDb()
-
- let! before = Count.all PostgresDb.TableName
- Expect.equal before 0 "There should have been no documents returned"
-
- // This not raising an exception is the test
- do! Patch.byContains PostgresDb.TableName {| Value = "burgundy" |} {| Foo = "green" |}
- }
- ]
- testList "byJsonPath" [
- testTask "succeeds when a document is updated" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- do! Patch.byJsonPath PostgresDb.TableName "$.NumValue ? (@ > 10)" {| NumValue = 1000 |}
- let! after = Count.byJsonPath PostgresDb.TableName "$.NumValue ? (@ > 999)"
- Expect.equal after 2 "There should have been 2 documents returned"
- }
- testTask "succeeds when no document is updated" {
- use db = PostgresDb.BuildDb()
-
- let! before = Count.all PostgresDb.TableName
- Expect.equal before 0 "There should have been no documents returned"
-
- // This not raising an exception is the test
- do! Patch.byJsonPath PostgresDb.TableName "$.NumValue ? (@ < 0)" {| Foo = "green" |}
- }
- ]
- ]
- testList "RemoveFields" [
- testList "byId" [
- testTask "succeeds when multiple fields are removed" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- do! RemoveFields.byId PostgresDb.TableName "two" [ "Sub"; "Value" ]
- let! noSubs = Count.byFields PostgresDb.TableName Any [ Field.NEX "Sub" ]
- Expect.equal noSubs 4 "There should now be 4 documents without Sub fields"
- let! noValue = Count.byFields PostgresDb.TableName Any [ Field.NEX "Value" ]
- Expect.equal noValue 1 "There should be 1 document without Value fields"
- }
- testTask "succeeds when a single field is removed" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- do! RemoveFields.byId PostgresDb.TableName "two" [ "Sub" ]
- let! noSubs = Count.byFields PostgresDb.TableName Any [ Field.NEX "Sub" ]
- Expect.equal noSubs 4 "There should now be 4 documents without Sub fields"
- let! noValue = Count.byFields PostgresDb.TableName Any [ Field.NEX "Value" ]
- Expect.equal noValue 0 "There should be no documents without Value fields"
- }
- testTask "succeeds when a field is not removed" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- // This not raising an exception is the test
- do! RemoveFields.byId PostgresDb.TableName "two" [ "AFieldThatIsNotThere" ]
- }
- testTask "succeeds when no document is matched" {
- use db = PostgresDb.BuildDb()
-
- // This not raising an exception is the test
- do! RemoveFields.byId PostgresDb.TableName "two" [ "Value" ]
- }
- ]
- testList "byFields" [
- testTask "succeeds when multiple fields are removed" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- do! RemoveFields.byFields PostgresDb.TableName Any [ Field.EQ "NumValue" "17" ] [ "Sub"; "Value" ]
- let! noSubs = Count.byFields PostgresDb.TableName Any [ Field.NEX "Sub" ]
- Expect.equal noSubs 4 "There should now be 4 documents without Sub fields"
- let! noValue = Count.byFields PostgresDb.TableName Any [ Field.NEX "Value" ]
- Expect.equal noValue 1 "There should be 1 document without Value fields"
- }
- testTask "succeeds when a single field is removed" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- do! RemoveFields.byFields PostgresDb.TableName Any [ Field.EQ "NumValue" "17" ] [ "Sub" ]
- let! noSubs = Count.byFields PostgresDb.TableName Any [ Field.NEX "Sub" ]
- Expect.equal noSubs 4 "There should now be 4 documents without Sub fields"
- let! noValue = Count.byFields PostgresDb.TableName Any [ Field.NEX "Value" ]
- Expect.equal noValue 0 "There should be no documents without Value fields"
- }
- testTask "succeeds when a field is not removed" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- // This not raising an exception is the test
- do! RemoveFields.byFields PostgresDb.TableName Any [ Field.EQ "NumValue" "17" ] [ "Nothing" ]
- }
- testTask "succeeds when no document is matched" {
- use db = PostgresDb.BuildDb()
-
- // This not raising an exception is the test
- do! RemoveFields.byFields PostgresDb.TableName Any [ Field.NE "Abracadabra" "apple" ] [ "Value" ]
- }
- ]
- testList "byContains" [
- testTask "succeeds when multiple fields are removed" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- do! RemoveFields.byContains PostgresDb.TableName {| NumValue = 17 |} [ "Sub"; "Value" ]
- let! noSubs = Count.byFields PostgresDb.TableName Any [ Field.NEX "Sub" ]
- Expect.equal noSubs 4 "There should now be 4 documents without Sub fields"
- let! noValue = Count.byFields PostgresDb.TableName Any [ Field.NEX "Value" ]
- Expect.equal noValue 1 "There should be 1 document without Value fields"
- }
- testTask "succeeds when a single field is removed" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- do! RemoveFields.byContains PostgresDb.TableName {| NumValue = 17 |} [ "Sub" ]
- let! noSubs = Count.byFields PostgresDb.TableName Any [ Field.NEX "Sub" ]
- Expect.equal noSubs 4 "There should now be 4 documents without Sub fields"
- let! noValue = Count.byFields PostgresDb.TableName Any [ Field.NEX "Value" ]
- Expect.equal noValue 0 "There should be no documents without Value fields"
- }
- testTask "succeeds when a field is not removed" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- // This not raising an exception is the test
- do! RemoveFields.byContains PostgresDb.TableName {| NumValue = 17 |} [ "Nothing" ]
- }
- testTask "succeeds when no document is matched" {
- use db = PostgresDb.BuildDb()
-
- // This not raising an exception is the test
- do! RemoveFields.byContains PostgresDb.TableName {| Abracadabra = "apple" |} [ "Value" ]
- }
- ]
- testList "byJsonPath" [
- testTask "succeeds when multiple fields are removed" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- do! RemoveFields.byJsonPath PostgresDb.TableName "$.NumValue ? (@ == 17)" [ "Sub"; "Value" ]
- let! noSubs = Count.byFields PostgresDb.TableName Any [ Field.NEX "Sub" ]
- Expect.equal noSubs 4 "There should now be 4 documents without Sub fields"
- let! noValue = Count.byFields PostgresDb.TableName Any [ Field.NEX "Value" ]
- Expect.equal noValue 1 "There should be 1 document without Value fields"
- }
- testTask "succeeds when a single field is removed" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- do! RemoveFields.byJsonPath PostgresDb.TableName "$.NumValue ? (@ == 17)" [ "Sub" ]
- let! noSubs = Count.byFields PostgresDb.TableName Any [ Field.NEX "Sub" ]
- Expect.equal noSubs 4 "There should now be 4 documents without Sub fields"
- let! noValue = Count.byFields PostgresDb.TableName Any [ Field.NEX "Value" ]
- Expect.equal noValue 0 "There should be no documents without Value fields"
- }
- testTask "succeeds when a field is not removed" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- // This not raising an exception is the test
- do! RemoveFields.byJsonPath PostgresDb.TableName "$.NumValue ? (@ == 17)" [ "Nothing" ]
- }
- testTask "succeeds when no document is matched" {
- use db = PostgresDb.BuildDb()
-
- // This not raising an exception is the test
- do! RemoveFields.byJsonPath PostgresDb.TableName "$.Abracadabra ? (@ == \"apple\")" [ "Value" ]
- }
- ]
- ]
- testList "Delete" [
- testList "byId" [
- testTask "succeeds when a document is deleted" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- do! Delete.byId PostgresDb.TableName "four"
- let! remaining = Count.all PostgresDb.TableName
- Expect.equal remaining 4 "There should have been 4 documents remaining"
- }
- testTask "succeeds when a document is not deleted" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- do! Delete.byId PostgresDb.TableName "thirty"
- let! remaining = Count.all PostgresDb.TableName
- Expect.equal remaining 5 "There should have been 5 documents remaining"
- }
- ]
- testList "byFields" [
- testTask "succeeds when documents are deleted" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- do! Delete.byFields PostgresDb.TableName Any [ Field.EQ "Value" "purple" ]
- let! remaining = Count.all PostgresDb.TableName
- Expect.equal remaining 3 "There should have been 3 documents remaining"
- }
- testTask "succeeds when documents are not deleted" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- do! Delete.byFields PostgresDb.TableName Any [ Field.EQ "Value" "crimson" ]
- let! remaining = Count.all PostgresDb.TableName
- Expect.equal remaining 5 "There should have been 5 documents remaining"
- }
- ]
- testList "byContains" [
- testTask "succeeds when documents are deleted" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- do! Delete.byContains PostgresDb.TableName {| Value = "purple" |}
- let! remaining = Count.all PostgresDb.TableName
- Expect.equal remaining 3 "There should have been 3 documents remaining"
- }
- testTask "succeeds when documents are not deleted" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- do! Delete.byContains PostgresDb.TableName {| Value = "crimson" |}
- let! remaining = Count.all PostgresDb.TableName
- Expect.equal remaining 5 "There should have been 5 documents remaining"
- }
- ]
- testList "byJsonPath" [
- testTask "succeeds when documents are deleted" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- do! Delete.byJsonPath PostgresDb.TableName """$.Sub.Foo ? (@ == "green")"""
- let! remaining = Count.all PostgresDb.TableName
- Expect.equal remaining 3 "There should have been 3 documents remaining"
- }
- testTask "succeeds when documents are not deleted" {
- use db = PostgresDb.BuildDb()
- do! loadDocs ()
-
- do! Delete.byJsonPath PostgresDb.TableName "$.NumValue ? (@ > 100)"
- let! remaining = Count.all PostgresDb.TableName
- Expect.equal remaining 5 "There should have been 5 documents remaining"
- }
- ]
- ]
+ test "dataSource returns configured data source" {
+ use db = ThrowawayDatabase.Create PostgresDb.ConnStr.Value
+ let source = PostgresDb.MkDataSource db.ConnectionString
+ Configuration.useDataSource source
+
+ Expect.isTrue (obj.ReferenceEquals(source, Configuration.dataSource ())) "Data source should have been the same"
+ }
+]
+
+/// Integration tests for the Custom module of the PostgreSQL library
+let customTests = testList "Custom" [
+ testList "list" [
+ testTask "succeeds when data is found" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! docs = Custom.list (Query.selectFromTable PostgresDb.TableName) [] fromData
+ Expect.hasLength docs 5 "There should have been 5 documents returned"
+ }
+ testTask "succeeds when data is not found" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! docs =
+ Custom.list
+ $"SELECT data FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath"
+ [ "@path", Sql.string "$.NumValue ? (@ > 100)" ]
+ fromData
+ Expect.isEmpty docs "There should have been no documents returned"
+ }
]
- |> testSequenced
+ testList "single" [
+ testTask "succeeds when a row is found" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+ let! doc =
+ Custom.single
+ $"SELECT data FROM {PostgresDb.TableName} WHERE data ->> 'Id' = @id"
+ [ "@id", Sql.string "one"]
+ fromData
+ Expect.isSome doc "There should have been a document returned"
+ Expect.equal doc.Value.Id "one" "The incorrect document was returned"
+ }
+ testTask "succeeds when a row is not found" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
-let all = testList "Postgres" [ unitTests; integrationTests ]
+ let! doc =
+ Custom.single
+ $"SELECT data FROM {PostgresDb.TableName} WHERE data ->> 'Id' = @id"
+ [ "@id", Sql.string "eighty" ]
+ fromData
+ Expect.isNone doc "There should not have been a document returned"
+ }
+ ]
+ testList "nonQuery" [
+ testTask "succeeds when operating on data" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ do! Custom.nonQuery $"DELETE FROM {PostgresDb.TableName}" []
+
+ let! remaining = Count.all PostgresDb.TableName
+ Expect.equal remaining 0 "There should be no documents remaining in the table"
+ }
+ testTask "succeeds when no data matches where clause" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ do! Custom.nonQuery
+ $"DELETE FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath"
+ [ "@path", Sql.string "$.NumValue ? (@ > 100)" ]
+
+ let! remaining = Count.all PostgresDb.TableName
+ Expect.equal remaining 5 "There should be 5 documents remaining in the table"
+ }
+ ]
+ testTask "scalar succeeds" {
+ use db = PostgresDb.BuildDb()
+ let! nbr = Custom.scalar "SELECT 5 AS test_value" [] (fun row -> row.int "test_value")
+ Expect.equal nbr 5 "The query should have returned the number 5"
+ }
+]
+
+/// Integration tests for the Definition module of the PostgreSQL library
+let definitionTests = testList "Definition" [
+ testTask "ensureTable succeeds" {
+ use db = PostgresDb.BuildDb()
+ let tableExists () =
+ Custom.scalar "SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'ensured') AS it" [] toExists
+ let keyExists () =
+ Custom.scalar
+ "SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'idx_ensured_key') AS it" [] toExists
+
+ let! exists = tableExists ()
+ let! alsoExists = keyExists ()
+ Expect.isFalse exists "The table should not exist already"
+ Expect.isFalse alsoExists "The key index should not exist already"
+
+ do! Definition.ensureTable "ensured"
+ let! exists' = tableExists ()
+ let! alsoExists' = keyExists ()
+ Expect.isTrue exists' "The table should now exist"
+ Expect.isTrue alsoExists' "The key index should now exist"
+ }
+ testTask "ensureDocumentIndex succeeds" {
+ use db = PostgresDb.BuildDb()
+ let indexExists () =
+ Custom.scalar
+ "SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'idx_ensured_document') AS it" [] toExists
+
+ let! exists = indexExists ()
+ Expect.isFalse exists "The index should not exist already"
+
+ do! Definition.ensureTable "ensured"
+ do! Definition.ensureDocumentIndex "ensured" Optimized
+ let! exists' = indexExists ()
+ Expect.isTrue exists' "The index should now exist"
+ }
+ testTask "ensureFieldIndex succeeds" {
+ use db = PostgresDb.BuildDb()
+ let indexExists () =
+ Custom.scalar "SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'idx_ensured_test') AS it" [] toExists
+
+ let! exists = indexExists ()
+ Expect.isFalse exists "The index should not exist already"
+
+ do! Definition.ensureTable "ensured"
+ do! Definition.ensureFieldIndex "ensured" "test" [ "Id"; "Category" ]
+ let! exists' = indexExists ()
+ Expect.isTrue exists' "The index should now exist"
+ }
+]
+
+/// Integration tests for the (auto-opened) Document module of the PostgreSQL library
+let documentTests = testList "Document" [
+ testList "insert" [
+ testTask "succeeds" {
+ use db = PostgresDb.BuildDb()
+ let! before = Find.all PostgresDb.TableName
+ Expect.equal before [] "There should be no documents in the table"
+
+ let testDoc = { emptyDoc with Id = "turkey"; Sub = Some { Foo = "gobble"; Bar = "gobble" } }
+ do! insert PostgresDb.TableName testDoc
+ let! after = Find.all PostgresDb.TableName
+ Expect.equal after [ testDoc ] "There should have been one document inserted"
+ }
+ testTask "fails for duplicate key" {
+ use db = PostgresDb.BuildDb()
+ do! insert PostgresDb.TableName { emptyDoc with Id = "test" }
+ Expect.throws
+ (fun () ->
+ insert PostgresDb.TableName {emptyDoc with Id = "test" }
+ |> Async.AwaitTask
+ |> Async.RunSynchronously)
+ "An exception should have been raised for duplicate document ID insert"
+ }
+ ]
+ testList "save" [
+ testTask "succeeds when a document is inserted" {
+ use db = PostgresDb.BuildDb()
+ let! before = Find.all PostgresDb.TableName
+ Expect.equal before [] "There should be no documents in the table"
+
+ let testDoc = { emptyDoc with Id = "test"; Sub = Some { Foo = "a"; Bar = "b" } }
+ do! save PostgresDb.TableName testDoc
+ let! after = Find.all PostgresDb.TableName
+ Expect.equal after [ testDoc ] "There should have been one document inserted"
+ }
+ testTask "succeeds when a document is updated" {
+ use db = PostgresDb.BuildDb()
+ let testDoc = { emptyDoc with Id = "test"; Sub = Some { Foo = "a"; Bar = "b" } }
+ do! insert PostgresDb.TableName testDoc
+
+ let! before = Find.byId PostgresDb.TableName "test"
+ Expect.isSome before "There should have been a document returned"
+ Expect.equal before.Value testDoc "The document is not correct"
+
+ let upd8Doc = { testDoc with Sub = Some { Foo = "c"; Bar = "d" } }
+ do! save PostgresDb.TableName upd8Doc
+ let! after = Find.byId PostgresDb.TableName "test"
+ Expect.isSome after "There should have been a document returned post-update"
+ Expect.equal after.Value upd8Doc "The updated document is not correct"
+ }
+ ]
+]
+
+/// Integration tests for the Count module of the PostgreSQL library
+let countTests = testList "Count" [
+ testTask "all succeeds" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! theCount = Count.all PostgresDb.TableName
+ Expect.equal theCount 5 "There should have been 5 matching documents"
+ }
+ testList "byFields" [
+ testTask "succeeds when items are found" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! theCount = Count.byFields PostgresDb.TableName Any [ Field.BT "NumValue" 15 20; Field.EQ "NumValue" 0 ]
+ Expect.equal theCount 3 "There should have been 3 matching documents"
+ }
+ testTask "succeeds when items are not found" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! theCount = Count.byFields PostgresDb.TableName All [ Field.EX "Sub"; Field.GT "NumValue" 100 ]
+ Expect.equal theCount 0 "There should have been no matching documents"
+ }
+ ]
+ testTask "byContains succeeds" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! theCount = Count.byContains PostgresDb.TableName {| Value = "purple" |}
+ Expect.equal theCount 2 "There should have been 2 matching documents"
+ }
+ testTask "byJsonPath succeeds" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! theCount = Count.byJsonPath PostgresDb.TableName "$.NumValue ? (@ > 5)"
+ Expect.equal theCount 3 "There should have been 3 matching documents"
+ }
+]
+
+/// Integration tests for the Exists module of the PostgreSQL library
+let existsTests = testList "Exists" [
+ testList "byId" [
+ testTask "succeeds when a document exists" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! exists = Exists.byId PostgresDb.TableName "three"
+ Expect.isTrue exists "There should have been an existing document"
+ }
+ testTask "succeeds when a document does not exist" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! exists = Exists.byId PostgresDb.TableName "seven"
+ Expect.isFalse exists "There should not have been an existing document"
+ }
+ ]
+ testList "byFields" [
+ testTask "succeeds when documents exist" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! exists = Exists.byFields PostgresDb.TableName Any [ Field.EX "Sub"; Field.EX "Boo" ]
+ Expect.isTrue exists "There should have been existing documents"
+ }
+ testTask "succeeds when documents do not exist" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! exists = Exists.byFields PostgresDb.TableName All [ Field.EQ "NumValue" "six"; Field.EX "Nope" ]
+ Expect.isFalse exists "There should not have been existing documents"
+ }
+ ]
+ testList "byContains" [
+ testTask "succeeds when documents exist" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! exists = Exists.byContains PostgresDb.TableName {| NumValue = 10 |}
+ Expect.isTrue exists "There should have been existing documents"
+ }
+ testTask "succeeds when no matching documents exist" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! exists = Exists.byContains PostgresDb.TableName {| Nothing = "none" |}
+ Expect.isFalse exists "There should not have been any existing documents"
+ }
+ ]
+ testList "byJsonPath" [
+ testTask "succeeds when documents exist" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! exists = Exists.byJsonPath PostgresDb.TableName """$.Sub.Foo ? (@ == "green")"""
+ Expect.isTrue exists "There should have been existing documents"
+ }
+ testTask "succeeds when no matching documents exist" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! exists = Exists.byJsonPath PostgresDb.TableName "$.NumValue ? (@ > 1000)"
+ Expect.isFalse exists "There should not have been any existing documents"
+ }
+ ]
+]
+
+/// Integration tests for the Find module of the PostgreSQL library
+let findTests = testList "Find" [
+ testList "all" [
+ testTask "succeeds when there is data" {
+ use db = PostgresDb.BuildDb()
+
+ do! insert PostgresDb.TableName { Foo = "one"; Bar = "two" }
+ do! insert PostgresDb.TableName { Foo = "three"; Bar = "four" }
+ do! insert PostgresDb.TableName { Foo = "five"; Bar = "six" }
+
+ let! results = Find.all PostgresDb.TableName
+ Expect.equal
+ results
+ [ { Foo = "one"; Bar = "two" }; { Foo = "three"; Bar = "four" }; { Foo = "five"; Bar = "six" } ]
+ "There should have been 3 documents returned"
+ }
+ testTask "succeeds when there is no data" {
+ use db = PostgresDb.BuildDb()
+ let! results = Find.all PostgresDb.TableName
+ Expect.equal results [] "There should have been no documents returned"
+ }
+ ]
+ testList "allOrdered" [
+ testTask "succeeds when ordering numerically" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! results = Find.allOrdered PostgresDb.TableName [ Field.Named "n:NumValue" ]
+ Expect.hasLength results 5 "There should have been 5 documents returned"
+ Expect.equal
+ (results |> List.map _.Id |> String.concat "|")
+ "one|three|two|four|five"
+ "The documents were not ordered correctly"
+ }
+ testTask "succeeds when ordering numerically descending" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! results = Find.allOrdered PostgresDb.TableName [ Field.Named "n:NumValue DESC" ]
+ Expect.hasLength results 5 "There should have been 5 documents returned"
+ Expect.equal
+ (results |> List.map _.Id |> String.concat "|")
+ "five|four|two|three|one"
+ "The documents were not ordered correctly"
+ }
+ testTask "succeeds when ordering alphabetically" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! results = Find.allOrdered PostgresDb.TableName [ Field.Named "Id DESC" ]
+ Expect.hasLength results 5 "There should have been 5 documents returned"
+ Expect.equal
+ (results |> List.map _.Id |> String.concat "|")
+ "two|three|one|four|five"
+ "The documents were not ordered correctly"
+ }
+ ]
+ testList "byId" [
+ testTask "succeeds when a document is found" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! doc = Find.byId PostgresDb.TableName "two"
+ Expect.isSome doc "There should have been a document returned"
+ Expect.equal doc.Value.Id "two" "The incorrect document was returned"
+ }
+ testTask "succeeds when a document is not found" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! doc = Find.byId PostgresDb.TableName "three hundred eighty-seven"
+ Expect.isNone doc "There should not have been a document returned"
+ }
+ ]
+ testList "byFields" [
+ testTask "succeeds when documents are found" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! docs =
+ Find.byFields PostgresDb.TableName All [ Field.EQ "Value" "purple"; Field.EX "Sub" ]
+ Expect.equal (List.length docs) 1 "There should have been one document returned"
+ }
+ testTask "succeeds when documents are not found" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! docs =
+ Find.byFields
+ PostgresDb.TableName All [ Field.EQ "Value" "mauve"; Field.NE "NumValue" 40 ]
+ Expect.isEmpty docs "There should have been no documents returned"
+ }
+ ]
+ testList "byFieldsOrdered" [
+ testTask "succeeds when sorting ascending" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! docs =
+ Find.byFieldsOrdered
+ PostgresDb.TableName All [ Field.EQ "Value" "purple" ] [ Field.Named "Id" ]
+ Expect.hasLength docs 2 "There should have been two documents returned"
+ Expect.equal
+ (docs |> List.map _.Id |> String.concat "|") "five|four" "Documents not ordered correctly"
+ }
+ testTask "succeeds when sorting descending" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! docs =
+ Find.byFieldsOrdered
+ PostgresDb.TableName All [ Field.EQ "Value" "purple" ] [ Field.Named "Id DESC" ]
+ Expect.hasLength docs 2 "There should have been two documents returned"
+ Expect.equal
+ (docs |> List.map _.Id |> String.concat "|") "four|five" "Documents not ordered correctly"
+ }
+ ]
+ testList "byContains" [
+ testTask "succeeds when documents are found" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! docs = Find.byContains PostgresDb.TableName {| Sub = {| Foo = "green" |} |}
+ Expect.equal (List.length docs) 2 "There should have been two documents returned"
+ }
+ testTask "succeeds when documents are not found" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! docs = Find.byContains PostgresDb.TableName {| Value = "mauve" |}
+ Expect.isEmpty docs "There should have been no documents returned"
+ }
+ ]
+ testList "byContainsOrdered" [
+ // Id = two, Sub.Bar = blue; Id = four, Sub.Bar = red
+ testTask "succeeds when sorting ascending" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! docs =
+ Find.byContainsOrdered
+ PostgresDb.TableName {| Sub = {| Foo = "green" |} |} [ Field.Named "Sub.Bar" ]
+ Expect.hasLength docs 2 "There should have been two documents returned"
+ Expect.equal
+ (docs |> List.map _.Id |> String.concat "|") "two|four" "Documents not ordered correctly"
+ }
+ testTask "succeeds when sorting descending" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! docs =
+ Find.byContainsOrdered
+ PostgresDb.TableName {| Sub = {| Foo = "green" |} |} [ Field.Named "Sub.Bar DESC" ]
+ Expect.hasLength docs 2 "There should have been two documents returned"
+ Expect.equal
+ (docs |> List.map _.Id |> String.concat "|") "four|two" "Documents not ordered correctly"
+ }
+ ]
+ testList "byJsonPath" [
+ testTask "succeeds when documents are found" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! docs = Find.byJsonPath PostgresDb.TableName "$.NumValue ? (@ < 15)"
+ Expect.equal (List.length docs) 3 "There should have been 3 documents returned"
+ }
+ testTask "succeeds when documents are not found" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! docs = Find.byJsonPath PostgresDb.TableName "$.NumValue ? (@ < 0)"
+ Expect.isEmpty docs "There should have been no documents returned"
+ }
+ ]
+ testList "byJsonPathOrdered" [
+ // Id = one, NumValue = 0; Id = two, NumValue = 10; Id = three, NumValue = 4
+ testTask "succeeds when sorting ascending" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! docs =
+ Find.byJsonPathOrdered
+ PostgresDb.TableName "$.NumValue ? (@ < 15)" [ Field.Named "n:NumValue" ]
+ Expect.hasLength docs 3 "There should have been 3 documents returned"
+ Expect.equal
+ (docs |> List.map _.Id |> String.concat "|") "one|three|two" "Documents not ordered correctly"
+ }
+ testTask "succeeds when sorting descending" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! docs =
+ Find.byJsonPathOrdered
+ PostgresDb.TableName "$.NumValue ? (@ < 15)" [ Field.Named "n:NumValue DESC" ]
+ Expect.hasLength docs 3 "There should have been 3 documents returned"
+ Expect.equal
+ (docs |> List.map _.Id |> String.concat "|") "two|three|one" "Documents not ordered correctly"
+ }
+ ]
+ testList "firstByFields" [
+ testTask "succeeds when a document is found" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! doc = Find.firstByFields PostgresDb.TableName Any [ Field.EQ "Value" "another" ]
+ Expect.isSome doc "There should have been a document returned"
+ Expect.equal doc.Value.Id "two" "The incorrect document was returned"
+ }
+ testTask "succeeds when multiple documents are found" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! doc = Find.firstByFields PostgresDb.TableName Any [ Field.EQ "Value" "purple" ]
+ Expect.isSome doc "There should have been a document returned"
+ Expect.contains [ "five"; "four" ] doc.Value.Id "An incorrect document was returned"
+ }
+ testTask "succeeds when a document is not found" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! doc = Find.firstByFields PostgresDb.TableName Any [ Field.EQ "Value" "absent" ]
+ Expect.isNone doc "There should not have been a document returned"
+ }
+ ]
+ testList "firstByFieldsOrdered" [
+ testTask "succeeds when sorting ascending" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! doc =
+ Find.firstByFieldsOrdered
+ PostgresDb.TableName Any [ Field.EQ "Value" "purple" ] [ Field.Named "Id" ]
+ Expect.isSome doc "There should have been a document returned"
+ Expect.equal "five" doc.Value.Id "An incorrect document was returned"
+ }
+ testTask "succeeds when sorting descending" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! doc =
+ Find.firstByFieldsOrdered
+ PostgresDb.TableName Any [ Field.EQ "Value" "purple" ] [ Field.Named "Id DESC" ]
+ Expect.isSome doc "There should have been a document returned"
+ Expect.equal "four" doc.Value.Id "An incorrect document was returned"
+ }
+ ]
+ testList "firstByContains" [
+ testTask "succeeds when a document is found" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! doc = Find.firstByContains PostgresDb.TableName {| Value = "another" |}
+ Expect.isSome doc "There should have been a document returned"
+ Expect.equal doc.Value.Id "two" "The incorrect document was returned"
+ }
+ testTask "succeeds when multiple documents are found" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! doc = Find.firstByContains PostgresDb.TableName {| Sub = {| Foo = "green" |} |}
+ Expect.isSome doc "There should have been a document returned"
+ Expect.contains [ "two"; "four" ] doc.Value.Id "An incorrect document was returned"
+ }
+ testTask "succeeds when a document is not found" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! doc = Find.firstByContains PostgresDb.TableName {| Value = "absent" |}
+ Expect.isNone doc "There should not have been a document returned"
+ }
+ ]
+ testList "firstByJsonPath" [
+ testTask "succeeds when a document is found" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! doc = Find.firstByJsonPath PostgresDb.TableName """$.Value ? (@ == "FIRST!")"""
+ Expect.isSome doc "There should have been a document returned"
+ Expect.equal doc.Value.Id "one" "The incorrect document was returned"
+ }
+ testTask "succeeds when multiple documents are found" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! doc = Find.firstByJsonPath PostgresDb.TableName """$.Sub.Foo ? (@ == "green")"""
+ Expect.isSome doc "There should have been a document returned"
+ Expect.contains [ "two"; "four" ] doc.Value.Id "An incorrect document was returned"
+ }
+ testTask "succeeds when a document is not found" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let! doc = Find.firstByJsonPath PostgresDb.TableName """$.Id ? (@ == "nope")"""
+ Expect.isNone doc "There should not have been a document returned"
+ }
+ ]
+]
+
+/// Integration tests for the Update module of the PostegreSQL library
+let updateTests = testList "Update" [
+ testList "byId" [
+ testTask "succeeds when a document is updated" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ let testDoc = { emptyDoc with Id = "one"; Sub = Some { Foo = "blue"; Bar = "red" } }
+ do! Update.byId PostgresDb.TableName "one" testDoc
+ let! after = Find.byId PostgresDb.TableName "one"
+ Expect.isSome after "There should have been a document returned post-update"
+ Expect.equal after.Value testDoc "The updated document is not correct"
+ }
+ testTask "succeeds when no document is updated" {
+ use db = PostgresDb.BuildDb()
+
+ let! before = Count.all PostgresDb.TableName
+ Expect.equal before 0 "There should have been no documents returned"
+
+ // This not raising an exception is the test
+ do! Update.byId
+ PostgresDb.TableName "test" { emptyDoc with Id = "x"; Sub = Some { Foo = "blue"; Bar = "red" } }
+ }
+ ]
+ testList "byFunc" [
+ testTask "succeeds when a document is updated" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ do! Update.byFunc PostgresDb.TableName (_.Id) { Id = "one"; Value = "le un"; NumValue = 1; Sub = None }
+ let! after = Find.byId PostgresDb.TableName "one"
+ Expect.isSome after "There should have been a document returned post-update"
+ Expect.equal
+ after.Value
+ { Id = "one"; Value = "le un"; NumValue = 1; Sub = None }
+ "The updated document is not correct"
+ }
+ testTask "succeeds when no document is updated" {
+ use db = PostgresDb.BuildDb()
+
+ let! before = Count.all PostgresDb.TableName
+ Expect.equal before 0 "There should have been no documents returned"
+
+ // This not raising an exception is the test
+ do! Update.byFunc PostgresDb.TableName (_.Id) { Id = "one"; Value = "le un"; NumValue = 1; Sub = None }
+ }
+ ]
+]
+
+/// Integration tests for the Patch module of the PostgreSQL library
+let patchTests = testList "Patch" [
+ testList "byId" [
+ testTask "succeeds when a document is updated" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ do! Patch.byId PostgresDb.TableName "one" {| NumValue = 44 |}
+ let! after = Find.byId PostgresDb.TableName "one"
+ Expect.isSome after "There should have been a document returned post-update"
+ Expect.equal after.Value.NumValue 44 "The updated document is not correct"
+ }
+ testTask "succeeds when no document is updated" {
+ use db = PostgresDb.BuildDb()
+
+ let! before = Count.all PostgresDb.TableName
+ Expect.equal before 0 "There should have been no documents returned"
+
+ // This not raising an exception is the test
+ do! Patch.byId PostgresDb.TableName "test" {| Foo = "green" |}
+ }
+ ]
+ testList "byFields" [
+ testTask "succeeds when a document is updated" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ do! Patch.byFields PostgresDb.TableName Any [ Field.EQ "Value" "purple" ] {| NumValue = 77 |}
+ let! after = Count.byFields PostgresDb.TableName Any [ Field.EQ "NumValue" 77 ]
+ Expect.equal after 2 "There should have been 2 documents returned"
+ }
+ testTask "succeeds when no document is updated" {
+ use db = PostgresDb.BuildDb()
+
+ let! before = Count.all PostgresDb.TableName
+ Expect.equal before 0 "There should have been no documents returned"
+
+ // This not raising an exception is the test
+ do! Patch.byFields PostgresDb.TableName Any [ Field.EQ "Value" "burgundy" ] {| Foo = "green" |}
+ }
+ ]
+ testList "byContains" [
+ testTask "succeeds when a document is updated" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ do! Patch.byContains PostgresDb.TableName {| Value = "purple" |} {| NumValue = 77 |}
+ let! after = Count.byContains PostgresDb.TableName {| NumValue = 77 |}
+ Expect.equal after 2 "There should have been 2 documents returned"
+ }
+ testTask "succeeds when no document is updated" {
+ use db = PostgresDb.BuildDb()
+
+ let! before = Count.all PostgresDb.TableName
+ Expect.equal before 0 "There should have been no documents returned"
+
+ // This not raising an exception is the test
+ do! Patch.byContains PostgresDb.TableName {| Value = "burgundy" |} {| Foo = "green" |}
+ }
+ ]
+ testList "byJsonPath" [
+ testTask "succeeds when a document is updated" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ do! Patch.byJsonPath PostgresDb.TableName "$.NumValue ? (@ > 10)" {| NumValue = 1000 |}
+ let! after = Count.byJsonPath PostgresDb.TableName "$.NumValue ? (@ > 999)"
+ Expect.equal after 2 "There should have been 2 documents returned"
+ }
+ testTask "succeeds when no document is updated" {
+ use db = PostgresDb.BuildDb()
+
+ let! before = Count.all PostgresDb.TableName
+ Expect.equal before 0 "There should have been no documents returned"
+
+ // This not raising an exception is the test
+ do! Patch.byJsonPath PostgresDb.TableName "$.NumValue ? (@ < 0)" {| Foo = "green" |}
+ }
+ ]
+]
+
+/// Integration tests for the RemoveFields module of the PostgreSQL library
+let removeFieldsTests = testList "RemoveFields" [
+ testList "byId" [
+ testTask "succeeds when multiple fields are removed" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ do! RemoveFields.byId PostgresDb.TableName "two" [ "Sub"; "Value" ]
+ let! noSubs = Count.byFields PostgresDb.TableName Any [ Field.NEX "Sub" ]
+ Expect.equal noSubs 4 "There should now be 4 documents without Sub fields"
+ let! noValue = Count.byFields PostgresDb.TableName Any [ Field.NEX "Value" ]
+ Expect.equal noValue 1 "There should be 1 document without Value fields"
+ }
+ testTask "succeeds when a single field is removed" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ do! RemoveFields.byId PostgresDb.TableName "two" [ "Sub" ]
+ let! noSubs = Count.byFields PostgresDb.TableName Any [ Field.NEX "Sub" ]
+ Expect.equal noSubs 4 "There should now be 4 documents without Sub fields"
+ let! noValue = Count.byFields PostgresDb.TableName Any [ Field.NEX "Value" ]
+ Expect.equal noValue 0 "There should be no documents without Value fields"
+ }
+ testTask "succeeds when a field is not removed" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ // This not raising an exception is the test
+ do! RemoveFields.byId PostgresDb.TableName "two" [ "AFieldThatIsNotThere" ]
+ }
+ testTask "succeeds when no document is matched" {
+ use db = PostgresDb.BuildDb()
+
+ // This not raising an exception is the test
+ do! RemoveFields.byId PostgresDb.TableName "two" [ "Value" ]
+ }
+ ]
+ testList "byFields" [
+ testTask "succeeds when multiple fields are removed" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ do! RemoveFields.byFields PostgresDb.TableName Any [ Field.EQ "NumValue" "17" ] [ "Sub"; "Value" ]
+ let! noSubs = Count.byFields PostgresDb.TableName Any [ Field.NEX "Sub" ]
+ Expect.equal noSubs 4 "There should now be 4 documents without Sub fields"
+ let! noValue = Count.byFields PostgresDb.TableName Any [ Field.NEX "Value" ]
+ Expect.equal noValue 1 "There should be 1 document without Value fields"
+ }
+ testTask "succeeds when a single field is removed" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ do! RemoveFields.byFields PostgresDb.TableName Any [ Field.EQ "NumValue" "17" ] [ "Sub" ]
+ let! noSubs = Count.byFields PostgresDb.TableName Any [ Field.NEX "Sub" ]
+ Expect.equal noSubs 4 "There should now be 4 documents without Sub fields"
+ let! noValue = Count.byFields PostgresDb.TableName Any [ Field.NEX "Value" ]
+ Expect.equal noValue 0 "There should be no documents without Value fields"
+ }
+ testTask "succeeds when a field is not removed" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ // This not raising an exception is the test
+ do! RemoveFields.byFields PostgresDb.TableName Any [ Field.EQ "NumValue" "17" ] [ "Nothing" ]
+ }
+ testTask "succeeds when no document is matched" {
+ use db = PostgresDb.BuildDb()
+
+ // This not raising an exception is the test
+ do! RemoveFields.byFields PostgresDb.TableName Any [ Field.NE "Abracadabra" "apple" ] [ "Value" ]
+ }
+ ]
+ testList "byContains" [
+ testTask "succeeds when multiple fields are removed" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ do! RemoveFields.byContains PostgresDb.TableName {| NumValue = 17 |} [ "Sub"; "Value" ]
+ let! noSubs = Count.byFields PostgresDb.TableName Any [ Field.NEX "Sub" ]
+ Expect.equal noSubs 4 "There should now be 4 documents without Sub fields"
+ let! noValue = Count.byFields PostgresDb.TableName Any [ Field.NEX "Value" ]
+ Expect.equal noValue 1 "There should be 1 document without Value fields"
+ }
+ testTask "succeeds when a single field is removed" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ do! RemoveFields.byContains PostgresDb.TableName {| NumValue = 17 |} [ "Sub" ]
+ let! noSubs = Count.byFields PostgresDb.TableName Any [ Field.NEX "Sub" ]
+ Expect.equal noSubs 4 "There should now be 4 documents without Sub fields"
+ let! noValue = Count.byFields PostgresDb.TableName Any [ Field.NEX "Value" ]
+ Expect.equal noValue 0 "There should be no documents without Value fields"
+ }
+ testTask "succeeds when a field is not removed" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ // This not raising an exception is the test
+ do! RemoveFields.byContains PostgresDb.TableName {| NumValue = 17 |} [ "Nothing" ]
+ }
+ testTask "succeeds when no document is matched" {
+ use db = PostgresDb.BuildDb()
+
+ // This not raising an exception is the test
+ do! RemoveFields.byContains PostgresDb.TableName {| Abracadabra = "apple" |} [ "Value" ]
+ }
+ ]
+ testList "byJsonPath" [
+ testTask "succeeds when multiple fields are removed" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ do! RemoveFields.byJsonPath PostgresDb.TableName "$.NumValue ? (@ == 17)" [ "Sub"; "Value" ]
+ let! noSubs = Count.byFields PostgresDb.TableName Any [ Field.NEX "Sub" ]
+ Expect.equal noSubs 4 "There should now be 4 documents without Sub fields"
+ let! noValue = Count.byFields PostgresDb.TableName Any [ Field.NEX "Value" ]
+ Expect.equal noValue 1 "There should be 1 document without Value fields"
+ }
+ testTask "succeeds when a single field is removed" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ do! RemoveFields.byJsonPath PostgresDb.TableName "$.NumValue ? (@ == 17)" [ "Sub" ]
+ let! noSubs = Count.byFields PostgresDb.TableName Any [ Field.NEX "Sub" ]
+ Expect.equal noSubs 4 "There should now be 4 documents without Sub fields"
+ let! noValue = Count.byFields PostgresDb.TableName Any [ Field.NEX "Value" ]
+ Expect.equal noValue 0 "There should be no documents without Value fields"
+ }
+ testTask "succeeds when a field is not removed" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ // This not raising an exception is the test
+ do! RemoveFields.byJsonPath PostgresDb.TableName "$.NumValue ? (@ == 17)" [ "Nothing" ]
+ }
+ testTask "succeeds when no document is matched" {
+ use db = PostgresDb.BuildDb()
+
+ // This not raising an exception is the test
+ do! RemoveFields.byJsonPath PostgresDb.TableName "$.Abracadabra ? (@ == \"apple\")" [ "Value" ]
+ }
+ ]
+]
+
+/// Integration tests for the Delete module of the PostgreSQL library
+let deleteTests = testList "Delete" [
+ testList "byId" [
+ testTask "succeeds when a document is deleted" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ do! Delete.byId PostgresDb.TableName "four"
+ let! remaining = Count.all PostgresDb.TableName
+ Expect.equal remaining 4 "There should have been 4 documents remaining"
+ }
+ testTask "succeeds when a document is not deleted" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ do! Delete.byId PostgresDb.TableName "thirty"
+ let! remaining = Count.all PostgresDb.TableName
+ Expect.equal remaining 5 "There should have been 5 documents remaining"
+ }
+ ]
+ testList "byFields" [
+ testTask "succeeds when documents are deleted" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ do! Delete.byFields PostgresDb.TableName Any [ Field.EQ "Value" "purple" ]
+ let! remaining = Count.all PostgresDb.TableName
+ Expect.equal remaining 3 "There should have been 3 documents remaining"
+ }
+ testTask "succeeds when documents are not deleted" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ do! Delete.byFields PostgresDb.TableName Any [ Field.EQ "Value" "crimson" ]
+ let! remaining = Count.all PostgresDb.TableName
+ Expect.equal remaining 5 "There should have been 5 documents remaining"
+ }
+ ]
+ testList "byContains" [
+ testTask "succeeds when documents are deleted" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ do! Delete.byContains PostgresDb.TableName {| Value = "purple" |}
+ let! remaining = Count.all PostgresDb.TableName
+ Expect.equal remaining 3 "There should have been 3 documents remaining"
+ }
+ testTask "succeeds when documents are not deleted" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ do! Delete.byContains PostgresDb.TableName {| Value = "crimson" |}
+ let! remaining = Count.all PostgresDb.TableName
+ Expect.equal remaining 5 "There should have been 5 documents remaining"
+ }
+ ]
+ testList "byJsonPath" [
+ testTask "succeeds when documents are deleted" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ do! Delete.byJsonPath PostgresDb.TableName """$.Sub.Foo ? (@ == "green")"""
+ let! remaining = Count.all PostgresDb.TableName
+ Expect.equal remaining 3 "There should have been 3 documents remaining"
+ }
+ testTask "succeeds when documents are not deleted" {
+ use db = PostgresDb.BuildDb()
+ do! loadDocs ()
+
+ do! Delete.byJsonPath PostgresDb.TableName "$.NumValue ? (@ > 100)"
+ let! remaining = Count.all PostgresDb.TableName
+ Expect.equal remaining 5 "There should have been 5 documents remaining"
+ }
+ ]
+]
+
+/// All tests for the PostgreSQL library
+let all = testList "Postgres" [
+ testList "Unit" [ parametersTests; queryTests ]
+ testSequenced <| testList "Integration" [
+ configurationTests
+ customTests
+ definitionTests
+ documentTests
+ countTests
+ existsTests
+ findTests
+ updateTests
+ patchTests
+ removeFieldsTests
+ deleteTests
+ ]
+]