RC4 changes (#7)

- Add `In` and `InArray` comparisons
- Replace `Op` with `Comparison` (internal API, but was public)
- Spell out comparisons in `Field` constructor functions

Reviewed-on: #7
This commit was merged in pull request #7.
This commit is contained in:
2024-09-17 02:33:57 +00:00
parent 3bc662c984
commit 168bf0cd14
19 changed files with 883 additions and 569 deletions

View File

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