Version 4 rc1 (#6)
Changes in this version: - **BREAKING CHANGE**: All `*byField`/`*ByField` functions are now `*byFields`/`*ByFields`, and take a `FieldMatch` case before the list of fields. The `Compat` namespace in both libraries will assist in this transition. In support of this change, the `Field` parameter name is optional; the library will generate parameter names for it if they are not specified. - **BREAKING CHANGE**: The `Query` namespaces have had some significant work, particularly from the full-query perspective. Most have been broken up into the base query and modifiers `by*` that will combine the base query with the `WHERE` clause needed to satisfy the criteria. - **FEATURE / BREAKING CHANGE**: PostgreSQL document fields will now be cast to numeric if the parameter value passed to the query is numeric. This drove the `Query` breaking changes, as the fields need to have their intended value for the library to generate the appropriate SQL. Additionally, if code assumes the library can be given something like `8` and transform it to `"8"`, this is no longer the case. - **FEATURE**: All `Find` queries (except `byId`/`ById`) now have a version with the `Ordered` suffix. These take a list of fields by which the query should be ordered. A new `Field` method called `Named` can assist with creating these fields. Prefixing the field name with `n:` will cast the field to numeric in PostgreSQL (and will be ignored by SQLite); adding " DESC" to the field name will sort it descending (Z-A, high to low) instead of ascending (A-Z, low to high). - **BREAKING CHANGE** (PostgreSQL only): `fieldNameParam`/`Parameters.FieldName` are now plural. The function still only generates one parameter, but the name is now the same between PostgreSQL and SQLite. The goal of this library is to abstract the differences away as much as practical, and this furthers that end. There are functions with these names in the `Compat` namespace. - **FEATURE**: In the F# v3 library, lists of parameters were expected to be F#'s `List` type, and the C# version took either `List<T>` or `IEnumerable<T>`. In this version, these all expect `seq`/`IEnumerable<T>`. F#'s `List` satisfies the `seq` constraints, so this should not be a breaking change. - **FEATURE**: `Field`s now may have qualifiers; this allows tables to be aliased when joining multiple tables (as all have the same `data` column). F# users can use `with` to specify this at creation, and both F# and C# can use the `WithQualifier` method to create a field with the qualifier specified. Parameter names for fields may be specified in a similar way, substituting `ParameterName` for `Qualifier`. Reviewed-on: #6
This commit was merged in pull request #6.
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Expecto.CSharp;
|
||||
using Expecto;
|
||||
using Microsoft.FSharp.Collections;
|
||||
using Microsoft.FSharp.Core;
|
||||
|
||||
namespace BitBadger.Documents.Tests.CSharp;
|
||||
|
||||
@@ -21,209 +22,613 @@ internal class TestSerializer : IDocumentSerializer
|
||||
public static class CommonCSharpTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Unit tests
|
||||
/// Unit tests for the Op enum
|
||||
/// </summary>
|
||||
[Tests]
|
||||
public static readonly Test Unit = TestList("Common.C# Unit", new[]
|
||||
{
|
||||
TestSequenced(
|
||||
TestList("Configuration", new[]
|
||||
private static readonly Test OpTests = TestList("Op",
|
||||
[
|
||||
TestCase("EQ succeeds", () =>
|
||||
{
|
||||
Expect.equal(Op.EQ.ToString(), "=", "The equals operator was not correct");
|
||||
}),
|
||||
TestCase("GT succeeds", () =>
|
||||
{
|
||||
Expect.equal(Op.GT.ToString(), ">", "The greater than operator was not correct");
|
||||
}),
|
||||
TestCase("GE succeeds", () =>
|
||||
{
|
||||
Expect.equal(Op.GE.ToString(), ">=", "The greater than or equal to operator was not correct");
|
||||
}),
|
||||
TestCase("LT succeeds", () =>
|
||||
{
|
||||
Expect.equal(Op.LT.ToString(), "<", "The less than operator was not correct");
|
||||
}),
|
||||
TestCase("LE succeeds", () =>
|
||||
{
|
||||
Expect.equal(Op.LE.ToString(), "<=", "The less than or equal to operator was not correct");
|
||||
}),
|
||||
TestCase("NE succeeds", () =>
|
||||
{
|
||||
Expect.equal(Op.NE.ToString(), "<>", "The not equal to operator was not correct");
|
||||
}),
|
||||
TestCase("BT succeeds", () =>
|
||||
{
|
||||
Expect.equal(Op.BT.ToString(), "BETWEEN", "The \"between\" operator was not correct");
|
||||
}),
|
||||
TestCase("EX succeeds", () =>
|
||||
{
|
||||
Expect.equal(Op.EX.ToString(), "IS NOT NULL", "The \"exists\" operator was not correct");
|
||||
}),
|
||||
TestCase("NEX succeeds", () =>
|
||||
{
|
||||
Expect.equal(Op.NEX.ToString(), "IS NULL", "The \"not exists\" operator was not correct");
|
||||
})
|
||||
]);
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests for the Field class
|
||||
/// </summary>
|
||||
private static readonly Test FieldTests = TestList("Field",
|
||||
[
|
||||
TestCase("EQ succeeds", () =>
|
||||
{
|
||||
var field = Field.EQ("Test", 14);
|
||||
Expect.equal(field.Name, "Test", "Field name incorrect");
|
||||
Expect.equal(field.Op, Op.EQ, "Operator incorrect");
|
||||
Expect.equal(field.Value, 14, "Value incorrect");
|
||||
}),
|
||||
TestCase("GT succeeds", () =>
|
||||
{
|
||||
var field = Field.GT("Great", "night");
|
||||
Expect.equal(field.Name, "Great", "Field name incorrect");
|
||||
Expect.equal(field.Op, Op.GT, "Operator incorrect");
|
||||
Expect.equal(field.Value, "night", "Value incorrect");
|
||||
}),
|
||||
TestCase("GE succeeds", () =>
|
||||
{
|
||||
var field = Field.GE("Nice", 88L);
|
||||
Expect.equal(field.Name, "Nice", "Field name incorrect");
|
||||
Expect.equal(field.Op, Op.GE, "Operator incorrect");
|
||||
Expect.equal(field.Value, 88L, "Value incorrect");
|
||||
}),
|
||||
TestCase("LT succeeds", () =>
|
||||
{
|
||||
var field = Field.LT("Lesser", "seven");
|
||||
Expect.equal(field.Name, "Lesser", "Field name incorrect");
|
||||
Expect.equal(field.Op, Op.LT, "Operator incorrect");
|
||||
Expect.equal(field.Value, "seven", "Value incorrect");
|
||||
}),
|
||||
TestCase("LE succeeds", () =>
|
||||
{
|
||||
var field = Field.LE("Nobody", "KNOWS");
|
||||
Expect.equal(field.Name, "Nobody", "Field name incorrect");
|
||||
Expect.equal(field.Op, Op.LE, "Operator incorrect");
|
||||
Expect.equal(field.Value, "KNOWS", "Value incorrect");
|
||||
}),
|
||||
TestCase("NE succeeds", () =>
|
||||
{
|
||||
var field = Field.NE("Park", "here");
|
||||
Expect.equal(field.Name, "Park", "Field name incorrect");
|
||||
Expect.equal(field.Op, Op.NE, "Operator incorrect");
|
||||
Expect.equal(field.Value, "here", "Value incorrect");
|
||||
}),
|
||||
TestCase("BT succeeds", () =>
|
||||
{
|
||||
var field = Field.BT("Age", 18, 49);
|
||||
Expect.equal(field.Name, "Age", "Field name incorrect");
|
||||
Expect.equal(field.Op, Op.BT, "Operator incorrect");
|
||||
Expect.equal(((FSharpList<object>)field.Value).ToArray(), [18, 49], "Value incorrect");
|
||||
}),
|
||||
TestCase("EX succeeds", () =>
|
||||
{
|
||||
var field = Field.EX("Groovy");
|
||||
Expect.equal(field.Name, "Groovy", "Field name incorrect");
|
||||
Expect.equal(field.Op, Op.EX, "Operator incorrect");
|
||||
}),
|
||||
TestCase("NEX succeeds", () =>
|
||||
{
|
||||
var field = Field.NEX("Rad");
|
||||
Expect.equal(field.Name, "Rad", "Field name incorrect");
|
||||
Expect.equal(field.Op, Op.NEX, "Operator incorrect");
|
||||
}),
|
||||
TestList("NameToPath",
|
||||
[
|
||||
TestCase("succeeds for PostgreSQL and a simple name", () =>
|
||||
{
|
||||
TestCase("UseSerializer succeeds", () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Configuration.UseSerializer(new TestSerializer());
|
||||
Expect.equal("data->>'Simple'", Field.NameToPath("Simple", Dialect.PostgreSQL),
|
||||
"Path not constructed correctly");
|
||||
}),
|
||||
TestCase("succeeds for SQLite and a simple name", () =>
|
||||
{
|
||||
Expect.equal("data->>'Simple'", Field.NameToPath("Simple", Dialect.SQLite),
|
||||
"Path not constructed correctly");
|
||||
}),
|
||||
TestCase("succeeds for PostgreSQL and a nested name", () =>
|
||||
{
|
||||
Expect.equal("data#>>'{A,Long,Path,to,the,Property}'",
|
||||
Field.NameToPath("A.Long.Path.to.the.Property", Dialect.PostgreSQL),
|
||||
"Path not constructed correctly");
|
||||
}),
|
||||
TestCase("succeeds for SQLite and a nested name", () =>
|
||||
{
|
||||
Expect.equal("data->>'A'->>'Long'->>'Path'->>'to'->>'the'->>'Property'",
|
||||
Field.NameToPath("A.Long.Path.to.the.Property", Dialect.SQLite),
|
||||
"Path not constructed correctly");
|
||||
})
|
||||
]),
|
||||
TestCase("WithParameterName succeeds", () =>
|
||||
{
|
||||
var field = Field.EQ("Bob", "Tom").WithParameterName("@name");
|
||||
Expect.isSome(field.ParameterName, "The parameter name should have been filled");
|
||||
Expect.equal("@name", field.ParameterName.Value, "The parameter name is incorrect");
|
||||
}),
|
||||
TestCase("WithQualifier succeeds", () =>
|
||||
{
|
||||
var field = Field.EQ("Bill", "Matt").WithQualifier("joe");
|
||||
Expect.isSome(field.Qualifier, "The table qualifier should have been filled");
|
||||
Expect.equal("joe", field.Qualifier.Value, "The table qualifier is incorrect");
|
||||
}),
|
||||
TestList("Path",
|
||||
[
|
||||
TestCase("succeeds for a PostgreSQL single field with no qualifier", () =>
|
||||
{
|
||||
var field = Field.GE("SomethingCool", 18);
|
||||
Expect.equal("data->>'SomethingCool'", field.Path(Dialect.PostgreSQL),
|
||||
"The PostgreSQL path is incorrect");
|
||||
}),
|
||||
TestCase("succeeds for a PostgreSQL single field with a qualifier", () =>
|
||||
{
|
||||
var field = Field.LT("SomethingElse", 9).WithQualifier("this");
|
||||
Expect.equal("this.data->>'SomethingElse'", field.Path(Dialect.PostgreSQL),
|
||||
"The PostgreSQL path is incorrect");
|
||||
}),
|
||||
TestCase("succeeds for a PostgreSQL nested field with no qualifier", () =>
|
||||
{
|
||||
var field = Field.EQ("My.Nested.Field", "howdy");
|
||||
Expect.equal("data#>>'{My,Nested,Field}'", field.Path(Dialect.PostgreSQL),
|
||||
"The PostgreSQL path is incorrect");
|
||||
}),
|
||||
TestCase("succeeds for a PostgreSQL nested field with a qualifier", () =>
|
||||
{
|
||||
var field = Field.EQ("Nest.Away", "doc").WithQualifier("bird");
|
||||
Expect.equal("bird.data#>>'{Nest,Away}'", field.Path(Dialect.PostgreSQL),
|
||||
"The PostgreSQL path is incorrect");
|
||||
}),
|
||||
TestCase("succeeds for a SQLite single field with no qualifier", () =>
|
||||
{
|
||||
var field = Field.GE("SomethingCool", 18);
|
||||
Expect.equal("data->>'SomethingCool'", field.Path(Dialect.SQLite), "The SQLite path is incorrect");
|
||||
}),
|
||||
TestCase("succeeds for a SQLite single field with a qualifier", () =>
|
||||
{
|
||||
var field = Field.LT("SomethingElse", 9).WithQualifier("this");
|
||||
Expect.equal("this.data->>'SomethingElse'", field.Path(Dialect.SQLite), "The SQLite path is incorrect");
|
||||
}),
|
||||
TestCase("succeeds for a SQLite nested field with no qualifier", () =>
|
||||
{
|
||||
var field = Field.EQ("My.Nested.Field", "howdy");
|
||||
Expect.equal("data->>'My'->>'Nested'->>'Field'", field.Path(Dialect.SQLite),
|
||||
"The SQLite path is incorrect");
|
||||
}),
|
||||
TestCase("succeeds for a SQLite nested field with a qualifier", () =>
|
||||
{
|
||||
var field = Field.EQ("Nest.Away", "doc").WithQualifier("bird");
|
||||
Expect.equal("bird.data->>'Nest'->>'Away'", field.Path(Dialect.SQLite), "The SQLite path is incorrect");
|
||||
})
|
||||
])
|
||||
]);
|
||||
|
||||
var serialized = Configuration.Serializer().Serialize(new SubDocument
|
||||
{
|
||||
Foo = "howdy",
|
||||
Bar = "bye"
|
||||
});
|
||||
Expect.equal(serialized, "{\"Overridden\":true}", "Specified serializer was not used");
|
||||
/// <summary>
|
||||
/// Unit tests for the FieldMatch enum
|
||||
/// </summary>
|
||||
private static readonly Test FieldMatchTests = TestList("FieldMatch.ToString",
|
||||
[
|
||||
TestCase("succeeds for Any", () =>
|
||||
{
|
||||
Expect.equal(FieldMatch.Any.ToString(), "OR", "SQL for Any is incorrect");
|
||||
}),
|
||||
TestCase("succeeds for All", () =>
|
||||
{
|
||||
Expect.equal(FieldMatch.All.ToString(), "AND", "SQL for All is incorrect");
|
||||
})
|
||||
]);
|
||||
|
||||
var deserialized = Configuration.Serializer()
|
||||
.Deserialize<object>("{\"Something\":\"here\"}");
|
||||
Expect.isNull(deserialized, "Specified serializer should have returned null");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Configuration.UseSerializer(DocumentSerializer.Default);
|
||||
}
|
||||
}),
|
||||
TestCase("Serializer returns configured serializer", () =>
|
||||
/// <summary>
|
||||
/// Unit tests for the ParameterName class
|
||||
/// </summary>
|
||||
private static readonly Test ParameterNameTests = TestList("ParameterName.Derive",
|
||||
[
|
||||
TestCase("succeeds with existing name", () =>
|
||||
{
|
||||
ParameterName name = new();
|
||||
Expect.equal(name.Derive(FSharpOption<string>.Some("@taco")), "@taco", "Name should have been @taco");
|
||||
Expect.equal(name.Derive(FSharpOption<string>.None), "@field0",
|
||||
"Counter should not have advanced for named field");
|
||||
}),
|
||||
TestCase("Derive succeeds with non-existent name", () =>
|
||||
{
|
||||
ParameterName name = new();
|
||||
Expect.equal(name.Derive(FSharpOption<string>.None), "@field0",
|
||||
"Anonymous field name should have been returned");
|
||||
Expect.equal(name.Derive(FSharpOption<string>.None), "@field1",
|
||||
"Counter should have advanced from previous call");
|
||||
Expect.equal(name.Derive(FSharpOption<string>.None), "@field2",
|
||||
"Counter should have advanced from previous call");
|
||||
Expect.equal(name.Derive(FSharpOption<string>.None), "@field3",
|
||||
"Counter should have advanced from previous call");
|
||||
})
|
||||
]);
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests for the AutoId enum
|
||||
/// </summary>
|
||||
private static readonly Test AutoIdTests = TestList("AutoId",
|
||||
[
|
||||
TestCase("GenerateGuid succeeds", () =>
|
||||
{
|
||||
var autoId = AutoId.GenerateGuid();
|
||||
Expect.isNotNull(autoId, "The GUID auto-ID should not have been null");
|
||||
Expect.stringHasLength(autoId, 32, "The GUID auto-ID should have been 32 characters long");
|
||||
Expect.equal(autoId, autoId.ToLowerInvariant(), "The GUID auto-ID should have been lowercase");
|
||||
}),
|
||||
TestCase("GenerateRandomString succeeds", () =>
|
||||
{
|
||||
foreach (var length in (int[]) [6, 8, 12, 20, 32, 57, 64])
|
||||
{
|
||||
var autoId = AutoId.GenerateRandomString(length);
|
||||
Expect.isNotNull(autoId, $"Random string ({length}) should not have been null");
|
||||
Expect.stringHasLength(autoId, length, $"Random string should have been {length} characters long");
|
||||
Expect.equal(autoId, autoId.ToLowerInvariant(),
|
||||
$"Random string ({length}) should have been lowercase");
|
||||
}
|
||||
}),
|
||||
TestList("NeedsAutoId",
|
||||
[
|
||||
TestCase("succeeds when no auto ID is configured", () =>
|
||||
{
|
||||
Expect.isFalse(AutoId.NeedsAutoId(AutoId.Disabled, new object(), "id"),
|
||||
"Disabled auto-ID never needs an automatic ID");
|
||||
}),
|
||||
TestCase("fails for any when the ID property is not found", () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Expect.isTrue(ReferenceEquals(DocumentSerializer.Default, Configuration.Serializer()),
|
||||
"Serializer should have been the same");
|
||||
}),
|
||||
TestCase("UseIdField / IdField succeeds", () =>
|
||||
_ = AutoId.NeedsAutoId(AutoId.Number, new { Key = "" }, "Id");
|
||||
Expect.isTrue(false, "Non-existent ID property should have thrown an exception");
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
try
|
||||
{
|
||||
Expect.equal(Configuration.IdField(), "Id",
|
||||
"The default configured ID field was incorrect");
|
||||
Configuration.UseIdField("id");
|
||||
Expect.equal(Configuration.IdField(), "id", "UseIdField did not set the ID field");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Configuration.UseIdField("Id");
|
||||
}
|
||||
// pass
|
||||
}
|
||||
}),
|
||||
TestCase("succeeds for byte when the ID is zero", () =>
|
||||
{
|
||||
Expect.isTrue(AutoId.NeedsAutoId(AutoId.Number, new { Id = (sbyte)0 }, "Id"),
|
||||
"Zero ID should have returned true");
|
||||
}),
|
||||
TestCase("succeeds for byte when the ID is non-zero", () =>
|
||||
{
|
||||
Expect.isFalse(AutoId.NeedsAutoId(AutoId.Number, new { Id = (sbyte)4 }, "Id"),
|
||||
"Non-zero ID should have returned false");
|
||||
}),
|
||||
TestCase("succeeds for short when the ID is zero", () =>
|
||||
{
|
||||
Expect.isTrue(AutoId.NeedsAutoId(AutoId.Number, new { Id = (short)0 }, "Id"),
|
||||
"Zero ID should have returned true");
|
||||
}),
|
||||
TestCase("succeeds for short when the ID is non-zero", () =>
|
||||
{
|
||||
Expect.isFalse(AutoId.NeedsAutoId(AutoId.Number, new { Id = (short)7 }, "Id"),
|
||||
"Non-zero ID should have returned false");
|
||||
}),
|
||||
TestCase("succeeds for int when the ID is zero", () =>
|
||||
{
|
||||
Expect.isTrue(AutoId.NeedsAutoId(AutoId.Number, new { Id = 0 }, "Id"),
|
||||
"Zero ID should have returned true");
|
||||
}),
|
||||
TestCase("succeeds for int when the ID is non-zero", () =>
|
||||
{
|
||||
Expect.isFalse(AutoId.NeedsAutoId(AutoId.Number, new { Id = 32 }, "Id"),
|
||||
"Non-zero ID should have returned false");
|
||||
}),
|
||||
TestCase("succeeds for long when the ID is zero", () =>
|
||||
{
|
||||
Expect.isTrue(AutoId.NeedsAutoId(AutoId.Number, new { Id = 0L }, "Id"),
|
||||
"Zero ID should have returned true");
|
||||
}),
|
||||
TestCase("succeeds for long when the ID is non-zero", () =>
|
||||
{
|
||||
Expect.isFalse(AutoId.NeedsAutoId(AutoId.Number, new { Id = 80L }, "Id"),
|
||||
"Non-zero ID should have returned false");
|
||||
}),
|
||||
TestCase("fails for number when the ID is not a number", () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
_ = AutoId.NeedsAutoId(AutoId.Number, new { Id = "" }, "Id");
|
||||
Expect.isTrue(false, "Numeric ID against a string should have thrown an exception");
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
// pass
|
||||
}
|
||||
}),
|
||||
TestCase("succeeds for GUID when the ID is blank", () =>
|
||||
{
|
||||
Expect.isTrue(AutoId.NeedsAutoId(AutoId.Guid, new { Id = "" }, "Id"),
|
||||
"Blank ID should have returned true");
|
||||
}),
|
||||
TestCase("succeeds for GUID when the ID is filled", () =>
|
||||
{
|
||||
Expect.isFalse(AutoId.NeedsAutoId(AutoId.Guid, new { Id = "abc" }, "Id"),
|
||||
"Filled ID should have returned false");
|
||||
}),
|
||||
TestCase("fails for GUID when the ID is not a string", () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
_ = AutoId.NeedsAutoId(AutoId.Guid, new { Id = 8 }, "Id");
|
||||
Expect.isTrue(false, "String ID against a number should have thrown an exception");
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
// pass
|
||||
}
|
||||
}),
|
||||
TestCase("succeeds for RandomString when the ID is blank", () =>
|
||||
{
|
||||
Expect.isTrue(AutoId.NeedsAutoId(AutoId.RandomString, new { Id = "" }, "Id"),
|
||||
"Blank ID should have returned true");
|
||||
}),
|
||||
TestCase("succeeds for RandomString when the ID is filled", () =>
|
||||
{
|
||||
Expect.isFalse(AutoId.NeedsAutoId(AutoId.RandomString, new { Id = "x" }, "Id"),
|
||||
"Filled ID should have returned false");
|
||||
}),
|
||||
TestCase("fails for RandomString when the ID is not a string", () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
_ = AutoId.NeedsAutoId(AutoId.RandomString, new { Id = 33 }, "Id");
|
||||
Expect.isTrue(false, "String ID against a number should have thrown an exception");
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
// pass
|
||||
}
|
||||
})
|
||||
])
|
||||
]);
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests for the Configuration static class
|
||||
/// </summary>
|
||||
private static readonly Test ConfigurationTests = TestList("Configuration",
|
||||
[
|
||||
TestCase("UseSerializer succeeds", () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Configuration.UseSerializer(new TestSerializer());
|
||||
|
||||
var serialized = Configuration.Serializer().Serialize(new SubDocument
|
||||
{
|
||||
Foo = "howdy",
|
||||
Bar = "bye"
|
||||
});
|
||||
Expect.equal(serialized, "{\"Overridden\":true}", "Specified serializer was not used");
|
||||
|
||||
var deserialized = Configuration.Serializer()
|
||||
.Deserialize<object>("{\"Something\":\"here\"}");
|
||||
Expect.isNull(deserialized, "Specified serializer should have returned null");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Configuration.UseSerializer(DocumentSerializer.Default);
|
||||
}
|
||||
}),
|
||||
TestCase("Serializer returns configured serializer", () =>
|
||||
{
|
||||
Expect.isTrue(ReferenceEquals(DocumentSerializer.Default, Configuration.Serializer()),
|
||||
"Serializer should have been the same");
|
||||
}),
|
||||
TestCase("UseIdField / IdField succeeds", () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Expect.equal(Configuration.IdField(), "Id",
|
||||
"The default configured ID field was incorrect");
|
||||
Configuration.UseIdField("id");
|
||||
Expect.equal(Configuration.IdField(), "id", "UseIdField did not set the ID field");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Configuration.UseIdField("Id");
|
||||
}
|
||||
}),
|
||||
TestCase("UseAutoIdStrategy / AutoIdStrategy succeeds", () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Expect.equal(Configuration.AutoIdStrategy(), AutoId.Disabled,
|
||||
"The default auto-ID strategy was incorrect");
|
||||
Configuration.UseAutoIdStrategy(AutoId.Guid);
|
||||
Expect.equal(Configuration.AutoIdStrategy(), AutoId.Guid,
|
||||
"The auto-ID strategy was not set correctly");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Configuration.UseAutoIdStrategy(AutoId.Disabled);
|
||||
}
|
||||
}),
|
||||
TestCase("UseIdStringLength / IdStringLength succeeds", () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Expect.equal(Configuration.IdStringLength(), 16, "The default ID string length was incorrect");
|
||||
Configuration.UseIdStringLength(33);
|
||||
Expect.equal(Configuration.IdStringLength(), 33, "The ID string length was not set correctly");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Configuration.UseIdStringLength(16);
|
||||
}
|
||||
})
|
||||
]);
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests for the Query static class
|
||||
/// </summary>
|
||||
private static readonly Test QueryTests = TestList("Query",
|
||||
[
|
||||
TestCase("StatementWhere succeeds", () =>
|
||||
{
|
||||
Expect.equal(Query.StatementWhere("q", "r"), "q WHERE r", "Statements not combined correctly");
|
||||
}),
|
||||
TestList("Definition",
|
||||
[
|
||||
TestCase("EnsureTableFor succeeds", () =>
|
||||
{
|
||||
Expect.equal(Query.Definition.EnsureTableFor("my.table", "JSONB"),
|
||||
"CREATE TABLE IF NOT EXISTS my.table (data JSONB NOT NULL)",
|
||||
"CREATE TABLE statement not constructed correctly");
|
||||
}),
|
||||
TestList("EnsureKey",
|
||||
[
|
||||
TestCase("succeeds when a schema is present", () =>
|
||||
{
|
||||
Expect.equal(Query.Definition.EnsureKey("test.table", Dialect.SQLite),
|
||||
"CREATE UNIQUE INDEX IF NOT EXISTS idx_table_key ON test.table ((data->>'Id'))",
|
||||
"CREATE INDEX for key statement with schema not constructed correctly");
|
||||
}),
|
||||
TestCase("succeeds when a schema is not present", () =>
|
||||
{
|
||||
Expect.equal(Query.Definition.EnsureKey("table", Dialect.PostgreSQL),
|
||||
"CREATE UNIQUE INDEX IF NOT EXISTS idx_table_key ON table ((data->>'Id'))",
|
||||
"CREATE INDEX for key statement without schema not constructed correctly");
|
||||
})
|
||||
})),
|
||||
TestList("Op", new[]
|
||||
{
|
||||
TestCase("EQ succeeds", () =>
|
||||
{
|
||||
Expect.equal(Op.EQ.ToString(), "=", "The equals operator was not correct");
|
||||
}),
|
||||
TestCase("GT succeeds", () =>
|
||||
{
|
||||
Expect.equal(Op.GT.ToString(), ">", "The greater than operator was not correct");
|
||||
}),
|
||||
TestCase("GE succeeds", () =>
|
||||
{
|
||||
Expect.equal(Op.GE.ToString(), ">=", "The greater than or equal to operator was not correct");
|
||||
}),
|
||||
TestCase("LT succeeds", () =>
|
||||
{
|
||||
Expect.equal(Op.LT.ToString(), "<", "The less than operator was not correct");
|
||||
}),
|
||||
TestCase("LE succeeds", () =>
|
||||
{
|
||||
Expect.equal(Op.LE.ToString(), "<=", "The less than or equal to operator was not correct");
|
||||
}),
|
||||
TestCase("NE succeeds", () =>
|
||||
{
|
||||
Expect.equal(Op.NE.ToString(), "<>", "The not equal to operator was not correct");
|
||||
}),
|
||||
TestCase("BT succeeds", () =>
|
||||
{
|
||||
Expect.equal(Op.BT.ToString(), "BETWEEN", "The \"between\" operator was not correct");
|
||||
}),
|
||||
TestCase("EX succeeds", () =>
|
||||
{
|
||||
Expect.equal(Op.EX.ToString(), "IS NOT NULL", "The \"exists\" operator was not correct");
|
||||
}),
|
||||
TestCase("NEX succeeds", () =>
|
||||
{
|
||||
Expect.equal(Op.NEX.ToString(), "IS NULL", "The \"not exists\" operator was not correct");
|
||||
})
|
||||
}),
|
||||
TestList("Field", new[]
|
||||
{
|
||||
TestCase("EQ succeeds", () =>
|
||||
{
|
||||
var field = Field.EQ("Test", 14);
|
||||
Expect.equal(field.Name, "Test", "Field name incorrect");
|
||||
Expect.equal(field.Op, Op.EQ, "Operator incorrect");
|
||||
Expect.equal(field.Value, 14, "Value incorrect");
|
||||
}),
|
||||
TestCase("GT succeeds", () =>
|
||||
{
|
||||
var field = Field.GT("Great", "night");
|
||||
Expect.equal(field.Name, "Great", "Field name incorrect");
|
||||
Expect.equal(field.Op, Op.GT, "Operator incorrect");
|
||||
Expect.equal(field.Value, "night", "Value incorrect");
|
||||
}),
|
||||
TestCase("GE succeeds", () =>
|
||||
{
|
||||
var field = Field.GE("Nice", 88L);
|
||||
Expect.equal(field.Name, "Nice", "Field name incorrect");
|
||||
Expect.equal(field.Op, Op.GE, "Operator incorrect");
|
||||
Expect.equal(field.Value, 88L, "Value incorrect");
|
||||
}),
|
||||
TestCase("LT succeeds", () =>
|
||||
{
|
||||
var field = Field.LT("Lesser", "seven");
|
||||
Expect.equal(field.Name, "Lesser", "Field name incorrect");
|
||||
Expect.equal(field.Op, Op.LT, "Operator incorrect");
|
||||
Expect.equal(field.Value, "seven", "Value incorrect");
|
||||
}),
|
||||
TestCase("LE succeeds", () =>
|
||||
{
|
||||
var field = Field.LE("Nobody", "KNOWS");
|
||||
Expect.equal(field.Name, "Nobody", "Field name incorrect");
|
||||
Expect.equal(field.Op, Op.LE, "Operator incorrect");
|
||||
Expect.equal(field.Value, "KNOWS", "Value incorrect");
|
||||
}),
|
||||
TestCase("NE succeeds", () =>
|
||||
{
|
||||
var field = Field.NE("Park", "here");
|
||||
Expect.equal(field.Name, "Park", "Field name incorrect");
|
||||
Expect.equal(field.Op, Op.NE, "Operator incorrect");
|
||||
Expect.equal(field.Value, "here", "Value incorrect");
|
||||
}),
|
||||
TestCase("BT succeeds", () =>
|
||||
{
|
||||
var field = Field.BT("Age", 18, 49);
|
||||
Expect.equal(field.Name, "Age", "Field name incorrect");
|
||||
Expect.equal(field.Op, Op.BT, "Operator incorrect");
|
||||
Expect.equal(((FSharpList<object>)field.Value).ToArray(), new object[] { 18, 49 }, "Value incorrect");
|
||||
}),
|
||||
TestCase("EX succeeds", () =>
|
||||
{
|
||||
var field = Field.EX("Groovy");
|
||||
Expect.equal(field.Name, "Groovy", "Field name incorrect");
|
||||
Expect.equal(field.Op, Op.EX, "Operator incorrect");
|
||||
}),
|
||||
TestCase("NEX succeeds", () =>
|
||||
{
|
||||
var field = Field.NEX("Rad");
|
||||
Expect.equal(field.Name, "Rad", "Field name incorrect");
|
||||
Expect.equal(field.Op, Op.NEX, "Operator incorrect");
|
||||
})
|
||||
}),
|
||||
TestList("Query", new[]
|
||||
{
|
||||
TestCase("SelectFromTable succeeds", () =>
|
||||
{
|
||||
Expect.equal(Query.SelectFromTable("test.table"), "SELECT data FROM test.table",
|
||||
"SELECT statement not correct");
|
||||
}),
|
||||
TestList("Definition", new[]
|
||||
{
|
||||
TestCase("EnsureTableFor succeeds", () =>
|
||||
{
|
||||
Expect.equal(Query.Definition.EnsureTableFor("my.table", "JSONB"),
|
||||
"CREATE TABLE IF NOT EXISTS my.table (data JSONB NOT NULL)",
|
||||
"CREATE TABLE statement not constructed correctly");
|
||||
}),
|
||||
TestList("EnsureKey", new[]
|
||||
{
|
||||
TestCase("succeeds when a schema is present", () =>
|
||||
{
|
||||
Expect.equal(Query.Definition.EnsureKey("test.table"),
|
||||
"CREATE UNIQUE INDEX IF NOT EXISTS idx_table_key ON test.table ((data ->> 'Id'))",
|
||||
"CREATE INDEX for key statement with schema not constructed correctly");
|
||||
}),
|
||||
TestCase("succeeds when a schema is not present", () =>
|
||||
{
|
||||
Expect.equal(Query.Definition.EnsureKey("table"),
|
||||
"CREATE UNIQUE INDEX IF NOT EXISTS idx_table_key ON table ((data ->> 'Id'))",
|
||||
"CREATE INDEX for key statement without schema not constructed correctly");
|
||||
})
|
||||
}),
|
||||
TestCase("EnsureIndexOn succeeds for multiple fields and directions", () =>
|
||||
]),
|
||||
TestList("EnsureIndexOn",
|
||||
[
|
||||
TestCase("succeeds for multiple fields and directions", () =>
|
||||
{
|
||||
Expect.equal(
|
||||
Query.Definition.EnsureIndexOn("test.table", "gibberish",
|
||||
new[] { "taco", "guac DESC", "salsa ASC" }),
|
||||
["taco", "guac DESC", "salsa ASC"], Dialect.SQLite),
|
||||
"CREATE INDEX IF NOT EXISTS idx_table_gibberish ON test.table "
|
||||
+ "((data ->> 'taco'), (data ->> 'guac') DESC, (data ->> 'salsa') ASC)",
|
||||
+ "((data->>'taco'), (data->>'guac') DESC, (data->>'salsa') ASC)",
|
||||
"CREATE INDEX for multiple field statement incorrect");
|
||||
}),
|
||||
TestCase("succeeds for nested PostgreSQL field", () =>
|
||||
{
|
||||
Expect.equal(
|
||||
Query.Definition.EnsureIndexOn("tbl", "nest", ["a.b.c"], Dialect.PostgreSQL),
|
||||
"CREATE INDEX IF NOT EXISTS idx_tbl_nest ON tbl ((data#>>'{a,b,c}'))",
|
||||
"CREATE INDEX for nested PostgreSQL field incorrect");
|
||||
}),
|
||||
TestCase("succeeds for nested SQLite field", () =>
|
||||
{
|
||||
Expect.equal(
|
||||
Query.Definition.EnsureIndexOn("tbl", "nest", ["a.b.c"], Dialect.SQLite),
|
||||
"CREATE INDEX IF NOT EXISTS idx_tbl_nest ON tbl ((data->>'a'->>'b'->>'c'))",
|
||||
"CREATE INDEX for nested SQLite field incorrect");
|
||||
})
|
||||
}),
|
||||
TestCase("Insert succeeds", () =>
|
||||
])
|
||||
]),
|
||||
TestCase("Insert succeeds", () =>
|
||||
{
|
||||
Expect.equal(Query.Insert("tbl"), "INSERT INTO tbl VALUES (@data)", "INSERT statement not correct");
|
||||
}),
|
||||
TestCase("Save succeeds", () =>
|
||||
{
|
||||
Expect.equal(Query.Save("tbl"),
|
||||
"INSERT INTO tbl VALUES (@data) ON CONFLICT ((data->>'Id')) DO UPDATE SET data = EXCLUDED.data",
|
||||
"INSERT ON CONFLICT UPDATE statement not correct");
|
||||
}),
|
||||
TestCase("Count succeeds", () =>
|
||||
{
|
||||
Expect.equal(Query.Count("tbl"), "SELECT COUNT(*) AS it FROM tbl", "Count query not correct");
|
||||
}),
|
||||
TestCase("Exists succeeds", () =>
|
||||
{
|
||||
Expect.equal(Query.Exists("tbl", "chicken"), "SELECT EXISTS (SELECT 1 FROM tbl WHERE chicken) AS it",
|
||||
"Exists query not correct");
|
||||
}),
|
||||
TestCase("Find succeeds", () =>
|
||||
{
|
||||
Expect.equal(Query.Find("test.table"), "SELECT data FROM test.table", "Find query not correct");
|
||||
}),
|
||||
TestCase("Update succeeds", () =>
|
||||
{
|
||||
Expect.equal(Query.Update("tbl"), "UPDATE tbl SET data = @data", "Update query not correct");
|
||||
}),
|
||||
TestCase("Delete succeeds", () =>
|
||||
{
|
||||
Expect.equal(Query.Delete("tbl"), "DELETE FROM tbl", "Delete query not correct");
|
||||
}),
|
||||
TestList("OrderBy",
|
||||
[
|
||||
TestCase("succeeds for no fields", () =>
|
||||
{
|
||||
Expect.equal(Query.Insert("tbl"), "INSERT INTO tbl VALUES (@data)", "INSERT statement not correct");
|
||||
Expect.equal(Query.OrderBy([], Dialect.PostgreSQL), "", "Order By should have been blank (PostgreSQL)");
|
||||
Expect.equal(Query.OrderBy([], Dialect.SQLite), "", "Order By should have been blank (SQLite)");
|
||||
}),
|
||||
TestCase("Save succeeds", () =>
|
||||
TestCase("succeeds for PostgreSQL with one field and no direction", () =>
|
||||
{
|
||||
Expect.equal(Query.Save("tbl"),
|
||||
"INSERT INTO tbl VALUES (@data) ON CONFLICT ((data->>'Id')) DO UPDATE SET data = EXCLUDED.data",
|
||||
"INSERT ON CONFLICT UPDATE statement not correct");
|
||||
Expect.equal(Query.OrderBy([Field.Named("TestField")], Dialect.PostgreSQL),
|
||||
" ORDER BY data->>'TestField'", "Order By not constructed correctly");
|
||||
}),
|
||||
TestCase("succeeds for SQLite with one field and no direction", () =>
|
||||
{
|
||||
Expect.equal(Query.OrderBy([Field.Named("TestField")], Dialect.SQLite),
|
||||
" ORDER BY data->>'TestField'", "Order By not constructed correctly");
|
||||
}),
|
||||
TestCase("succeeds for PostgreSQL with multiple fields and direction", () =>
|
||||
{
|
||||
Expect.equal(
|
||||
Query.OrderBy(
|
||||
[
|
||||
Field.Named("Nested.Test.Field DESC"), Field.Named("AnotherField"),
|
||||
Field.Named("It DESC")
|
||||
], Dialect.PostgreSQL),
|
||||
" ORDER BY data#>>'{Nested,Test,Field}' DESC, data->>'AnotherField', data->>'It' DESC",
|
||||
"Order By not constructed correctly");
|
||||
}),
|
||||
TestCase("succeeds for SQLite with multiple fields and direction", () =>
|
||||
{
|
||||
Expect.equal(
|
||||
Query.OrderBy(
|
||||
[
|
||||
Field.Named("Nested.Test.Field DESC"), Field.Named("AnotherField"),
|
||||
Field.Named("It DESC")
|
||||
], Dialect.SQLite),
|
||||
" ORDER BY data->>'Nested'->>'Test'->>'Field' DESC, data->>'AnotherField', data->>'It' DESC",
|
||||
"Order By not constructed correctly");
|
||||
}),
|
||||
TestCase("succeeds for PostgreSQL numeric fields", () =>
|
||||
{
|
||||
Expect.equal(Query.OrderBy([Field.Named("n:Test")], Dialect.PostgreSQL),
|
||||
" ORDER BY (data->>'Test')::numeric", "Order By not constructed correctly for numeric field");
|
||||
}),
|
||||
TestCase("succeeds for SQLite numeric fields", () =>
|
||||
{
|
||||
Expect.equal(Query.OrderBy([Field.Named("n:Test")], Dialect.SQLite), " ORDER BY data->>'Test'",
|
||||
"Order By not constructed correctly for numeric field");
|
||||
})
|
||||
})
|
||||
});
|
||||
])
|
||||
]);
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests
|
||||
/// </summary>
|
||||
[Tests]
|
||||
public static readonly Test Unit = TestList("Common.C# Unit",
|
||||
[
|
||||
OpTests,
|
||||
FieldTests,
|
||||
FieldMatchTests,
|
||||
ParameterNameTests,
|
||||
AutoIdTests,
|
||||
QueryTests,
|
||||
TestSequenced(ConfigurationTests)
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -31,17 +31,17 @@ public class PostgresCSharpExtensionTests
|
||||
/// Integration tests for the SQLite extension methods
|
||||
/// </summary>
|
||||
[Tests]
|
||||
public static readonly Test Integration = TestList("Postgres.C#.Extensions", new[]
|
||||
{
|
||||
TestList("CustomList", new[]
|
||||
{
|
||||
public static readonly Test Integration = TestList("Postgres.C#.Extensions",
|
||||
[
|
||||
TestList("CustomList",
|
||||
[
|
||||
TestCase("succeeds when data is found", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
await using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
var docs = await conn.CustomList(Query.SelectFromTable(PostgresDb.TableName), Parameters.None,
|
||||
var docs = await conn.CustomList(Query.Find(PostgresDb.TableName), Parameters.None,
|
||||
Results.FromData<JsonDocument>);
|
||||
Expect.equal(docs.Count, 5, "There should have been 5 documents returned");
|
||||
}),
|
||||
@@ -53,13 +53,13 @@ public class PostgresCSharpExtensionTests
|
||||
|
||||
var docs = await conn.CustomList(
|
||||
$"SELECT data FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath",
|
||||
new[] { Tuple.Create("@path", Sql.@string("$.NumValue ? (@ > 100)")) },
|
||||
[Tuple.Create("@path", Sql.@string("$.NumValue ? (@ > 100)"))],
|
||||
Results.FromData<JsonDocument>);
|
||||
Expect.isEmpty(docs, "There should have been no documents returned");
|
||||
})
|
||||
}),
|
||||
TestList("CustomSingle", new[]
|
||||
{
|
||||
]),
|
||||
TestList("CustomSingle",
|
||||
[
|
||||
TestCase("succeeds when a row is found", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
@@ -67,7 +67,7 @@ public class PostgresCSharpExtensionTests
|
||||
await LoadDocs();
|
||||
|
||||
var doc = await conn.CustomSingle($"SELECT data FROM {PostgresDb.TableName} WHERE data ->> 'Id' = @id",
|
||||
new[] { Tuple.Create("@id", Sql.@string("one")) }, Results.FromData<JsonDocument>);
|
||||
[Tuple.Create("@id", Sql.@string("one"))], Results.FromData<JsonDocument>);
|
||||
Expect.isNotNull(doc, "There should have been a document returned");
|
||||
Expect.equal(doc.Id, "one", "The incorrect document was returned");
|
||||
}),
|
||||
@@ -78,12 +78,12 @@ public class PostgresCSharpExtensionTests
|
||||
await LoadDocs();
|
||||
|
||||
var doc = await conn.CustomSingle($"SELECT data FROM {PostgresDb.TableName} WHERE data ->> 'Id' = @id",
|
||||
new[] { Tuple.Create("@id", Sql.@string("eighty")) }, Results.FromData<JsonDocument>);
|
||||
[Tuple.Create("@id", Sql.@string("eighty"))], Results.FromData<JsonDocument>);
|
||||
Expect.isNull(doc, "There should not have been a document returned");
|
||||
})
|
||||
}),
|
||||
TestList("CustomNonQuery", new[]
|
||||
{
|
||||
]),
|
||||
TestList("CustomNonQuery",
|
||||
[
|
||||
TestCase("succeeds when operating on data", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
@@ -102,12 +102,12 @@ public class PostgresCSharpExtensionTests
|
||||
await LoadDocs();
|
||||
|
||||
await conn.CustomNonQuery($"DELETE FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath",
|
||||
new[] { Tuple.Create("@path", Sql.@string("$.NumValue ? (@ > 100)")) });
|
||||
[Tuple.Create("@path", Sql.@string("$.NumValue ? (@ > 100)"))]);
|
||||
|
||||
var remaining = await conn.CountAll(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();
|
||||
@@ -119,58 +119,64 @@ public class PostgresCSharpExtensionTests
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
await using var conn = MkConn(db);
|
||||
var tableExists = () => conn.CustomScalar(
|
||||
"SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'ensured') AS it", Parameters.None,
|
||||
Results.ToExists);
|
||||
var keyExists = () => conn.CustomScalar(
|
||||
"SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'idx_ensured_key') AS it", Parameters.None,
|
||||
Results.ToExists);
|
||||
|
||||
var exists = await tableExists();
|
||||
var alsoExists = await keyExists();
|
||||
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 conn.EnsureTable("ensured");
|
||||
exists = await tableExists();
|
||||
alsoExists = await keyExists();
|
||||
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<bool> KeyExists() =>
|
||||
conn.CustomScalar("SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'idx_ensured_key') AS it",
|
||||
Parameters.None, Results.ToExists);
|
||||
Task<bool> TableExists() =>
|
||||
conn.CustomScalar("SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'ensured') AS it",
|
||||
Parameters.None, Results.ToExists);
|
||||
}),
|
||||
TestCase("EnsureDocumentIndex succeeds", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
await using var conn = MkConn(db);
|
||||
var indexExists = () => conn.CustomScalar(
|
||||
"SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'idx_ensured_document') AS it", Parameters.None,
|
||||
Results.ToExists);
|
||||
|
||||
var exists = await indexExists();
|
||||
var exists = await IndexExists();
|
||||
Expect.isFalse(exists, "The index should not exist already");
|
||||
|
||||
await conn.EnsureTable("ensured");
|
||||
await conn.EnsureDocumentIndex("ensured", DocumentIndex.Optimized);
|
||||
exists = await indexExists();
|
||||
exists = await IndexExists();
|
||||
Expect.isTrue(exists, "The index should now exist");
|
||||
return;
|
||||
|
||||
Task<bool> IndexExists() =>
|
||||
conn.CustomScalar("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();
|
||||
await using var conn = MkConn(db);
|
||||
var indexExists = () => conn.CustomScalar(
|
||||
"SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'idx_ensured_test') AS it", Parameters.None,
|
||||
Results.ToExists);
|
||||
|
||||
var exists = await indexExists();
|
||||
var exists = await IndexExists();
|
||||
Expect.isFalse(exists, "The index should not exist already");
|
||||
|
||||
await conn.EnsureTable("ensured");
|
||||
await conn.EnsureFieldIndex("ensured", "test", new[] { "Id", "Category" });
|
||||
exists = await indexExists();
|
||||
await conn.EnsureFieldIndex("ensured", "test", ["Id", "Category"]);
|
||||
exists = await IndexExists();
|
||||
Expect.isTrue(exists, "The index should now exist");
|
||||
return;
|
||||
|
||||
Task<bool> IndexExists() =>
|
||||
conn.CustomScalar("SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'idx_ensured_test') AS it",
|
||||
Parameters.None, Results.ToExists);
|
||||
}),
|
||||
TestList("Insert", new[]
|
||||
{
|
||||
TestList("Insert",
|
||||
[
|
||||
TestCase("succeeds", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
@@ -198,9 +204,9 @@ public class PostgresCSharpExtensionTests
|
||||
// This is what should have happened
|
||||
}
|
||||
})
|
||||
}),
|
||||
TestList("save", new[]
|
||||
{
|
||||
]),
|
||||
TestList("save",
|
||||
[
|
||||
TestCase("succeeds when a document is inserted", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
@@ -230,7 +236,7 @@ public class PostgresCSharpExtensionTests
|
||||
Expect.isNotNull(after, "There should have been a document returned post-update");
|
||||
Expect.equal(after.Sub!.Foo, "c", "The updated document is not correct");
|
||||
})
|
||||
}),
|
||||
]),
|
||||
TestCase("CountAll succeeds", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
@@ -240,13 +246,14 @@ public class PostgresCSharpExtensionTests
|
||||
var theCount = await conn.CountAll(PostgresDb.TableName);
|
||||
Expect.equal(theCount, 5, "There should have been 5 matching documents");
|
||||
}),
|
||||
TestCase("CountByField succeeds", async () =>
|
||||
TestCase("CountByFields succeeds", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
await using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
var theCount = await conn.CountByField(PostgresDb.TableName, Field.EQ("Value", "purple"));
|
||||
var theCount = await conn.CountByFields(PostgresDb.TableName, FieldMatch.Any,
|
||||
[Field.EQ("Value", "purple")]);
|
||||
Expect.equal(theCount, 2, "There should have been 2 matching documents");
|
||||
}),
|
||||
TestCase("CountByContains succeeds", async () =>
|
||||
@@ -267,8 +274,8 @@ public class PostgresCSharpExtensionTests
|
||||
var theCount = await conn.CountByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ > 5)");
|
||||
Expect.equal(theCount, 3, "There should have been 3 matching documents");
|
||||
}),
|
||||
TestList("ExistsById", new[]
|
||||
{
|
||||
TestList("ExistsById",
|
||||
[
|
||||
TestCase("succeeds when a document exists", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
@@ -287,16 +294,16 @@ public class PostgresCSharpExtensionTests
|
||||
var exists = await conn.ExistsById(PostgresDb.TableName, "seven");
|
||||
Expect.isFalse(exists, "There should not have been an existing document");
|
||||
})
|
||||
}),
|
||||
TestList("ExistsByField", new[]
|
||||
{
|
||||
]),
|
||||
TestList("ExistsByField",
|
||||
[
|
||||
TestCase("succeeds when documents exist", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
await using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
var exists = await conn.ExistsByField(PostgresDb.TableName, Field.EX("Sub"));
|
||||
var exists = await conn.ExistsByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EX("Sub")]);
|
||||
Expect.isTrue(exists, "There should have been existing documents");
|
||||
}),
|
||||
TestCase("succeeds when documents do not exist", async () =>
|
||||
@@ -305,12 +312,13 @@ public class PostgresCSharpExtensionTests
|
||||
await using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
var exists = await conn.ExistsByField(PostgresDb.TableName, Field.EQ("NumValue", "six"));
|
||||
var exists =
|
||||
await conn.ExistsByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", "six")]);
|
||||
Expect.isFalse(exists, "There should not have been existing documents");
|
||||
})
|
||||
}),
|
||||
TestList("ExistsByContains", new[]
|
||||
{
|
||||
]),
|
||||
TestList("ExistsByContains",
|
||||
[
|
||||
TestCase("succeeds when documents exist", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
@@ -329,9 +337,9 @@ public class PostgresCSharpExtensionTests
|
||||
var exists = await conn.ExistsByContains(PostgresDb.TableName, new { Nothing = "none" });
|
||||
Expect.isFalse(exists, "There should not have been any existing documents");
|
||||
})
|
||||
}),
|
||||
TestList("ExistsByJsonPath", new[]
|
||||
{
|
||||
]),
|
||||
TestList("ExistsByJsonPath",
|
||||
[
|
||||
TestCase("succeeds when documents exist", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
@@ -350,9 +358,9 @@ public class PostgresCSharpExtensionTests
|
||||
var exists = await conn.ExistsByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ > 1000)");
|
||||
Expect.isFalse(exists, "There should not have been any existing documents");
|
||||
})
|
||||
}),
|
||||
TestList("FindAll", new[]
|
||||
{
|
||||
]),
|
||||
TestList("FindAll",
|
||||
[
|
||||
TestCase("succeeds when there is data", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
@@ -372,9 +380,47 @@ public class PostgresCSharpExtensionTests
|
||||
var results = await conn.FindAll<JsonDocument>(PostgresDb.TableName);
|
||||
Expect.isEmpty(results, "There should have been no documents returned");
|
||||
})
|
||||
}),
|
||||
TestList("FindById", new[]
|
||||
{
|
||||
]),
|
||||
TestList("FindAllOrdered",
|
||||
[
|
||||
TestCase("succeeds when ordering numerically", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
await using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
var results =
|
||||
await conn.FindAllOrdered<JsonDocument>(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 using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
var results =
|
||||
await conn.FindAllOrdered<JsonDocument>(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 using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
var results = await conn.FindAllOrdered<JsonDocument>(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("FindById",
|
||||
[
|
||||
TestCase("succeeds when a document is found", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
@@ -394,16 +440,17 @@ public class PostgresCSharpExtensionTests
|
||||
var doc = await conn.FindById<string, JsonDocument>(PostgresDb.TableName, "three hundred eighty-seven");
|
||||
Expect.isNull(doc, "There should not have been a document returned");
|
||||
})
|
||||
}),
|
||||
TestList("FindByField", new[]
|
||||
{
|
||||
]),
|
||||
TestList("FindByFields",
|
||||
[
|
||||
TestCase("succeeds when documents are found", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
await using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
var docs = await conn.FindByField<JsonDocument>(PostgresDb.TableName, Field.EQ("Value", "another"));
|
||||
var docs = await conn.FindByFields<JsonDocument>(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 () =>
|
||||
@@ -412,12 +459,40 @@ public class PostgresCSharpExtensionTests
|
||||
await using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
var docs = await conn.FindByField<JsonDocument>(PostgresDb.TableName, Field.EQ("Value", "mauve"));
|
||||
var docs = await conn.FindByFields<JsonDocument>(PostgresDb.TableName, FieldMatch.Any,
|
||||
[Field.EQ("Value", "mauve")]);
|
||||
Expect.isEmpty(docs, "There should have been no documents returned");
|
||||
})
|
||||
}),
|
||||
TestList("FindByContains", new[]
|
||||
{
|
||||
]),
|
||||
TestList("FindByFieldsOrdered",
|
||||
[
|
||||
TestCase("succeeds when documents are found", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
await using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
var docs = await conn.FindByFieldsOrdered<JsonDocument>(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 using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
var docs = await conn.FindByFieldsOrdered<JsonDocument>(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("FindByContains",
|
||||
[
|
||||
TestCase("succeeds when documents are found", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
@@ -437,9 +512,37 @@ public class PostgresCSharpExtensionTests
|
||||
var docs = await conn.FindByContains<JsonDocument>(PostgresDb.TableName, new { Value = "mauve" });
|
||||
Expect.isEmpty(docs, "There should have been no documents returned");
|
||||
})
|
||||
}),
|
||||
TestList("FindByJsonPath", new[]
|
||||
{
|
||||
]),
|
||||
TestList("FindByContainsOrdered",
|
||||
[
|
||||
// Id = two, Sub.Bar = blue; Id = four, Sub.Bar = red
|
||||
TestCase("succeeds when sorting ascending", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
await using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
var docs = await conn.FindByContainsOrdered<JsonDocument>(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 using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
var docs = await conn.FindByContainsOrdered<JsonDocument>(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("FindByJsonPath",
|
||||
[
|
||||
TestCase("succeeds when documents are found", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
@@ -458,16 +561,45 @@ public class PostgresCSharpExtensionTests
|
||||
var docs = await conn.FindByJsonPath<JsonDocument>(PostgresDb.TableName, "$.NumValue ? (@ < 0)");
|
||||
Expect.isEmpty(docs, "There should have been no documents returned");
|
||||
})
|
||||
}),
|
||||
TestList("FindFirstByField", new[]
|
||||
{
|
||||
]),
|
||||
TestList("FindByJsonPathOrdered",
|
||||
[
|
||||
// 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 using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
var docs = await conn.FindByJsonPathOrdered<JsonDocument>(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 using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
var docs = await conn.FindByJsonPathOrdered<JsonDocument>(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("FindFirstByFields",
|
||||
[
|
||||
TestCase("succeeds when a document is found", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
await using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
var doc = await conn.FindFirstByField<JsonDocument>(PostgresDb.TableName, Field.EQ("Value", "another"));
|
||||
var doc = await conn.FindFirstByFields<JsonDocument>(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");
|
||||
}),
|
||||
@@ -477,9 +609,10 @@ public class PostgresCSharpExtensionTests
|
||||
await using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
var doc = await conn.FindFirstByField<JsonDocument>(PostgresDb.TableName, Field.EQ("Value", "purple"));
|
||||
var doc = await conn.FindFirstByFields<JsonDocument>(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");
|
||||
Expect.contains(["five", "four"], doc.Id, "An incorrect document was returned");
|
||||
}),
|
||||
TestCase("succeeds when a document is not found", async () =>
|
||||
{
|
||||
@@ -487,12 +620,38 @@ public class PostgresCSharpExtensionTests
|
||||
await using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
var doc = await conn.FindFirstByField<JsonDocument>(PostgresDb.TableName, Field.EQ("Value", "absent"));
|
||||
var doc = await conn.FindFirstByFields<JsonDocument>(PostgresDb.TableName, FieldMatch.Any,
|
||||
[Field.EQ("Value", "absent")]);
|
||||
Expect.isNull(doc, "There should not have been a document returned");
|
||||
})
|
||||
}),
|
||||
TestList("FindFirstByContains", new[]
|
||||
{
|
||||
]),
|
||||
TestList("FindFirstByFieldsOrdered",
|
||||
[
|
||||
TestCase("succeeds when sorting ascending", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
await using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
var doc = await conn.FindFirstByFieldsOrdered<JsonDocument>(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 using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
var doc = await conn.FindFirstByFieldsOrdered<JsonDocument>(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("FindFirstByContains",
|
||||
[
|
||||
TestCase("succeeds when a document is found", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
@@ -512,7 +671,7 @@ public class PostgresCSharpExtensionTests
|
||||
var doc = await conn.FindFirstByContains<JsonDocument>(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");
|
||||
Expect.contains(["two", "four"], doc.Id, "An incorrect document was returned");
|
||||
}),
|
||||
TestCase("succeeds when a document is not found", async () =>
|
||||
{
|
||||
@@ -523,9 +682,34 @@ public class PostgresCSharpExtensionTests
|
||||
var doc = await conn.FindFirstByContains<JsonDocument>(PostgresDb.TableName, new { Value = "absent" });
|
||||
Expect.isNull(doc, "There should not have been a document returned");
|
||||
})
|
||||
}),
|
||||
TestList("FindFirstByJsonPath", new[]
|
||||
{
|
||||
]),
|
||||
TestList("FindFirstByContainsOrdered",
|
||||
[
|
||||
TestCase("succeeds when sorting ascending", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
await using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
var doc = await conn.FindFirstByContainsOrdered<JsonDocument>(PostgresDb.TableName,
|
||||
new { Sub = new { Foo = "green" } }, [Field.Named("Value")]);
|
||||
Expect.isNotNull(doc, "There should have been a document returned");
|
||||
Expect.equal("two", doc.Id, "An incorrect document was returned");
|
||||
}),
|
||||
TestCase("succeeds when sorting descending", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
await using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
var doc = await conn.FindFirstByContainsOrdered<JsonDocument>(PostgresDb.TableName,
|
||||
new { Sub = new { Foo = "green" } }, [Field.Named("Value DESC")]);
|
||||
Expect.isNotNull(doc, "There should have been a document returned");
|
||||
Expect.equal("four", doc.Id, "An incorrect document was returned");
|
||||
})
|
||||
]),
|
||||
TestList("FindFirstByJsonPath",
|
||||
[
|
||||
TestCase("succeeds when a document is found", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
@@ -546,7 +730,7 @@ public class PostgresCSharpExtensionTests
|
||||
var doc = await conn.FindFirstByJsonPath<JsonDocument>(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");
|
||||
Expect.contains(["two", "four"], doc.Id, "An incorrect document was returned");
|
||||
}),
|
||||
TestCase("succeeds when a document is not found", async () =>
|
||||
{
|
||||
@@ -557,9 +741,34 @@ public class PostgresCSharpExtensionTests
|
||||
var doc = await conn.FindFirstByJsonPath<JsonDocument>(PostgresDb.TableName, "$.Id ? (@ == \"nope\")");
|
||||
Expect.isNull(doc, "There should not have been a document returned");
|
||||
})
|
||||
}),
|
||||
TestList("UpdateById", new[]
|
||||
{
|
||||
]),
|
||||
TestList("FindFirstByJsonPathOrdered",
|
||||
[
|
||||
TestCase("succeeds when sorting ascending", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
await using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
var doc = await conn.FindFirstByJsonPathOrdered<JsonDocument>(PostgresDb.TableName,
|
||||
"$.Sub.Foo ? (@ == \"green\")", [Field.Named("Sub.Bar")]);
|
||||
Expect.isNotNull(doc, "There should have been a document returned");
|
||||
Expect.equal("two", doc.Id, "An incorrect document was returned");
|
||||
}),
|
||||
TestCase("succeeds when sorting descending", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
await using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
var doc = await conn.FindFirstByJsonPathOrdered<JsonDocument>(PostgresDb.TableName,
|
||||
"$.Sub.Foo ? (@ == \"green\")", [Field.Named("Sub.Bar DESC")]);
|
||||
Expect.isNotNull(doc, "There should have been a document returned");
|
||||
Expect.equal("four", doc.Id, "An incorrect document was returned");
|
||||
})
|
||||
]),
|
||||
TestList("UpdateById",
|
||||
[
|
||||
TestCase("succeeds when a document is updated", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
@@ -588,9 +797,9 @@ public class PostgresCSharpExtensionTests
|
||||
await conn.UpdateById(PostgresDb.TableName, "test",
|
||||
new JsonDocument { Id = "x", Sub = new() { Foo = "blue", Bar = "red" } });
|
||||
})
|
||||
}),
|
||||
TestList("UpdateByFunc", new[]
|
||||
{
|
||||
]),
|
||||
TestList("UpdateByFunc",
|
||||
[
|
||||
TestCase("succeeds when a document is updated", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
@@ -617,9 +826,9 @@ public class PostgresCSharpExtensionTests
|
||||
await conn.UpdateByFunc(PostgresDb.TableName, doc => doc.Id,
|
||||
new JsonDocument { Id = "one", Value = "le un", NumValue = 1 });
|
||||
})
|
||||
}),
|
||||
TestList("PatchById", new[]
|
||||
{
|
||||
]),
|
||||
TestList("PatchById",
|
||||
[
|
||||
TestCase("succeeds when a document is updated", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
@@ -641,17 +850,19 @@ public class PostgresCSharpExtensionTests
|
||||
// This not raising an exception is the test
|
||||
await conn.PatchById(PostgresDb.TableName, "test", new { Foo = "green" });
|
||||
})
|
||||
}),
|
||||
TestList("PatchByField", new[]
|
||||
{
|
||||
]),
|
||||
TestList("PatchByFields",
|
||||
[
|
||||
TestCase("succeeds when a document is updated", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
await using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
await conn.PatchByField(PostgresDb.TableName, Field.EQ("Value", "purple"), new { NumValue = 77 });
|
||||
var after = await conn.CountByField(PostgresDb.TableName, Field.EQ("NumValue", "77"));
|
||||
await conn.PatchByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("Value", "purple")],
|
||||
new { NumValue = 77 });
|
||||
var after = await conn.CountByFields(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 () =>
|
||||
@@ -662,11 +873,12 @@ public class PostgresCSharpExtensionTests
|
||||
Expect.equal(before, 0, "There should have been no documents returned");
|
||||
|
||||
// This not raising an exception is the test
|
||||
await conn.PatchByField(PostgresDb.TableName, Field.EQ("Value", "burgundy"), new { Foo = "green" });
|
||||
await conn.PatchByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("Value", "burgundy")],
|
||||
new { Foo = "green" });
|
||||
})
|
||||
}),
|
||||
TestList("PatchByContains", new[]
|
||||
{
|
||||
]),
|
||||
TestList("PatchByContains",
|
||||
[
|
||||
TestCase("succeeds when a document is updated", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
@@ -687,9 +899,9 @@ public class PostgresCSharpExtensionTests
|
||||
// This not raising an exception is the test
|
||||
await conn.PatchByContains(PostgresDb.TableName, new { Value = "burgundy" }, new { Foo = "green" });
|
||||
})
|
||||
}),
|
||||
TestList("PatchByJsonPath", new[]
|
||||
{
|
||||
]),
|
||||
TestList("PatchByJsonPath",
|
||||
[
|
||||
TestCase("succeeds when a document is updated", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
@@ -710,16 +922,16 @@ public class PostgresCSharpExtensionTests
|
||||
// This not raising an exception is the test
|
||||
await conn.PatchByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ < 0)", new { Foo = "green" });
|
||||
})
|
||||
}),
|
||||
TestList("RemoveFieldsById", new[]
|
||||
{
|
||||
]),
|
||||
TestList("RemoveFieldsById",
|
||||
[
|
||||
TestCase("succeeds when multiple fields are removed", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
await using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
await conn.RemoveFieldsById(PostgresDb.TableName, "two", new[] { "Sub", "Value" });
|
||||
await conn.RemoveFieldsById(PostgresDb.TableName, "two", ["Sub", "Value"]);
|
||||
var updated = await Find.ById<string, JsonDocument>(PostgresDb.TableName, "two");
|
||||
Expect.isNotNull(updated, "The updated document should have been retrieved");
|
||||
Expect.equal(updated.Value, "", "The string value should have been removed");
|
||||
@@ -731,7 +943,7 @@ public class PostgresCSharpExtensionTests
|
||||
await using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
await conn.RemoveFieldsById(PostgresDb.TableName, "two", new[] { "Sub" });
|
||||
await conn.RemoveFieldsById(PostgresDb.TableName, "two", ["Sub"]);
|
||||
var updated = await Find.ById<string, JsonDocument>(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");
|
||||
@@ -744,7 +956,7 @@ public class PostgresCSharpExtensionTests
|
||||
await LoadDocs();
|
||||
|
||||
// This not raising an exception is the test
|
||||
await conn.RemoveFieldsById(PostgresDb.TableName, "two", new[] { "AFieldThatIsNotThere" });
|
||||
await conn.RemoveFieldsById(PostgresDb.TableName, "two", ["AFieldThatIsNotThere"]);
|
||||
}),
|
||||
TestCase("succeeds when no document is matched", async () =>
|
||||
{
|
||||
@@ -752,19 +964,19 @@ public class PostgresCSharpExtensionTests
|
||||
await using var conn = MkConn(db);
|
||||
|
||||
// This not raising an exception is the test
|
||||
await conn.RemoveFieldsById(PostgresDb.TableName, "two", new[] { "Value" });
|
||||
await conn.RemoveFieldsById(PostgresDb.TableName, "two", ["Value"]);
|
||||
})
|
||||
}),
|
||||
TestList("RemoveFieldsByField", new[]
|
||||
{
|
||||
]),
|
||||
TestList("RemoveFieldsByFields",
|
||||
[
|
||||
TestCase("succeeds when multiple fields are removed", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
await using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
await conn.RemoveFieldsByField(PostgresDb.TableName, Field.EQ("NumValue", "17"),
|
||||
new[] { "Sub", "Value" });
|
||||
await conn.RemoveFieldsByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", "17")],
|
||||
["Sub", "Value"]);
|
||||
var updated = await Find.ById<string, JsonDocument>(PostgresDb.TableName, "four");
|
||||
Expect.isNotNull(updated, "The updated document should have been retrieved");
|
||||
Expect.equal(updated.Value, "", "The string value should have been removed");
|
||||
@@ -776,7 +988,8 @@ public class PostgresCSharpExtensionTests
|
||||
await using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
await conn.RemoveFieldsByField(PostgresDb.TableName, Field.EQ("NumValue", "17"), new[] { "Sub" });
|
||||
await conn.RemoveFieldsByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", "17")],
|
||||
["Sub"]);
|
||||
var updated = await Find.ById<string, JsonDocument>(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");
|
||||
@@ -789,7 +1002,8 @@ public class PostgresCSharpExtensionTests
|
||||
await LoadDocs();
|
||||
|
||||
// This not raising an exception is the test
|
||||
await conn.RemoveFieldsByField(PostgresDb.TableName, Field.EQ("NumValue", "17"), new[] { "Nothing" });
|
||||
await conn.RemoveFieldsByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", "17")],
|
||||
["Nothing"]);
|
||||
}),
|
||||
TestCase("succeeds when no document is matched", async () =>
|
||||
{
|
||||
@@ -797,20 +1011,19 @@ public class PostgresCSharpExtensionTests
|
||||
await using var conn = MkConn(db);
|
||||
|
||||
// This not raising an exception is the test
|
||||
await conn.RemoveFieldsByField(PostgresDb.TableName, Field.NE("Abracadabra", "apple"),
|
||||
new[] { "Value" });
|
||||
await conn.RemoveFieldsByFields(PostgresDb.TableName, FieldMatch.Any,
|
||||
[Field.NE("Abracadabra", "apple")], ["Value"]);
|
||||
})
|
||||
}),
|
||||
TestList("RemoveFieldsByContains", new[]
|
||||
{
|
||||
]),
|
||||
TestList("RemoveFieldsByContains",
|
||||
[
|
||||
TestCase("succeeds when multiple fields are removed", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
await using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
await conn.RemoveFieldsByContains(PostgresDb.TableName, new { NumValue = 17 },
|
||||
new[] { "Sub", "Value" });
|
||||
await conn.RemoveFieldsByContains(PostgresDb.TableName, new { NumValue = 17 }, ["Sub", "Value"]);
|
||||
var updated = await Find.ById<string, JsonDocument>(PostgresDb.TableName, "four");
|
||||
Expect.isNotNull(updated, "The updated document should have been retrieved");
|
||||
Expect.equal(updated.Value, "", "The string value should have been removed");
|
||||
@@ -822,7 +1035,7 @@ public class PostgresCSharpExtensionTests
|
||||
await using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
await conn.RemoveFieldsByContains(PostgresDb.TableName, new { NumValue = 17 }, new[] { "Sub" });
|
||||
await conn.RemoveFieldsByContains(PostgresDb.TableName, new { NumValue = 17 }, ["Sub"]);
|
||||
var updated = await Find.ById<string, JsonDocument>(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");
|
||||
@@ -835,7 +1048,7 @@ public class PostgresCSharpExtensionTests
|
||||
await LoadDocs();
|
||||
|
||||
// This not raising an exception is the test
|
||||
await conn.RemoveFieldsByContains(PostgresDb.TableName, new { NumValue = 17 }, new[] { "Nothing" });
|
||||
await conn.RemoveFieldsByContains(PostgresDb.TableName, new { NumValue = 17 }, ["Nothing"]);
|
||||
}),
|
||||
TestCase("succeeds when no document is matched", async () =>
|
||||
{
|
||||
@@ -843,20 +1056,18 @@ public class PostgresCSharpExtensionTests
|
||||
await using var conn = MkConn(db);
|
||||
|
||||
// This not raising an exception is the test
|
||||
await conn.RemoveFieldsByContains(PostgresDb.TableName, new { Abracadabra = "apple" },
|
||||
new[] { "Value" });
|
||||
await conn.RemoveFieldsByContains(PostgresDb.TableName, new { Abracadabra = "apple" }, ["Value"]);
|
||||
})
|
||||
}),
|
||||
TestList("RemoveFieldsByJsonPath", new[]
|
||||
{
|
||||
]),
|
||||
TestList("RemoveFieldsByJsonPath",
|
||||
[
|
||||
TestCase("succeeds when multiple fields are removed", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
await using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
await conn.RemoveFieldsByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ == 17)",
|
||||
new[] { "Sub", "Value" });
|
||||
await conn.RemoveFieldsByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ == 17)", ["Sub", "Value"]);
|
||||
var updated = await Find.ById<string, JsonDocument>(PostgresDb.TableName, "four");
|
||||
Expect.isNotNull(updated, "The updated document should have been retrieved");
|
||||
Expect.equal(updated.Value, "", "The string value should have been removed");
|
||||
@@ -868,7 +1079,7 @@ public class PostgresCSharpExtensionTests
|
||||
await using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
await conn.RemoveFieldsByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ == 17)", new[] { "Sub" });
|
||||
await conn.RemoveFieldsByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ == 17)", ["Sub"]);
|
||||
var updated = await Find.ById<string, JsonDocument>(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");
|
||||
@@ -881,7 +1092,7 @@ public class PostgresCSharpExtensionTests
|
||||
await LoadDocs();
|
||||
|
||||
// This not raising an exception is the test
|
||||
await conn.RemoveFieldsByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ == 17)", new[] { "Nothing" });
|
||||
await conn.RemoveFieldsByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ == 17)", ["Nothing"]);
|
||||
}),
|
||||
TestCase("succeeds when no document is matched", async () =>
|
||||
{
|
||||
@@ -889,12 +1100,11 @@ public class PostgresCSharpExtensionTests
|
||||
await using var conn = MkConn(db);
|
||||
|
||||
// This not raising an exception is the test
|
||||
await conn.RemoveFieldsByJsonPath(PostgresDb.TableName, "$.Abracadabra ? (@ == \"apple\")",
|
||||
new[] { "Value" });
|
||||
await conn.RemoveFieldsByJsonPath(PostgresDb.TableName, "$.Abracadabra ? (@ == \"apple\")", ["Value"]);
|
||||
})
|
||||
}),
|
||||
TestList("DeleteById", new[]
|
||||
{
|
||||
]),
|
||||
TestList("DeleteById",
|
||||
[
|
||||
TestCase("succeeds when a document is deleted", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
@@ -915,16 +1125,16 @@ public class PostgresCSharpExtensionTests
|
||||
var remaining = await conn.CountAll(PostgresDb.TableName);
|
||||
Expect.equal(remaining, 5, "There should have been 5 documents remaining");
|
||||
})
|
||||
}),
|
||||
TestList("DeleteByField", new[]
|
||||
{
|
||||
]),
|
||||
TestList("DeleteByFields",
|
||||
[
|
||||
TestCase("succeeds when documents are deleted", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
await using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
await conn.DeleteByField(PostgresDb.TableName, Field.NE("Value", "purple"));
|
||||
await conn.DeleteByFields(PostgresDb.TableName, FieldMatch.Any, [Field.NE("Value", "purple")]);
|
||||
var remaining = await conn.CountAll(PostgresDb.TableName);
|
||||
Expect.equal(remaining, 2, "There should have been 2 documents remaining");
|
||||
}),
|
||||
@@ -934,13 +1144,13 @@ public class PostgresCSharpExtensionTests
|
||||
await using var conn = MkConn(db);
|
||||
await LoadDocs();
|
||||
|
||||
await conn.DeleteByField(PostgresDb.TableName, Field.EQ("Value", "crimson"));
|
||||
await conn.DeleteByFields(PostgresDb.TableName, FieldMatch.Any, [Field.EQ("Value", "crimson")]);
|
||||
var remaining = await conn.CountAll(PostgresDb.TableName);
|
||||
Expect.equal(remaining, 5, "There should have been 5 documents remaining");
|
||||
})
|
||||
}),
|
||||
TestList("DeleteByContains", new[]
|
||||
{
|
||||
]),
|
||||
TestList("DeleteByContains",
|
||||
[
|
||||
TestCase("succeeds when documents are deleted", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
@@ -961,9 +1171,9 @@ public class PostgresCSharpExtensionTests
|
||||
var remaining = await conn.CountAll(PostgresDb.TableName);
|
||||
Expect.equal(remaining, 5, "There should have been 5 documents remaining");
|
||||
})
|
||||
}),
|
||||
TestList("DeleteByJsonPath", new[]
|
||||
{
|
||||
]),
|
||||
TestList("DeleteByJsonPath",
|
||||
[
|
||||
TestCase("succeeds when documents are deleted", async () =>
|
||||
{
|
||||
await using var db = PostgresDb.BuildDb();
|
||||
@@ -984,6 +1194,6 @@ public class PostgresCSharpExtensionTests
|
||||
var remaining = await conn.CountAll(PostgresDb.TableName);
|
||||
Expect.equal(remaining, 5, "There should have been 5 documents remaining");
|
||||
})
|
||||
}),
|
||||
});
|
||||
]),
|
||||
]);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,4 @@
|
||||
using BitBadger.Documents.Postgres;
|
||||
using Npgsql;
|
||||
using Npgsql.FSharp;
|
||||
using ThrowawayDb.Postgres;
|
||||
@@ -131,7 +132,7 @@ public static class PostgresDb
|
||||
var sqlProps = Sql.connect(database.ConnectionString);
|
||||
|
||||
Sql.executeNonQuery(Sql.query(Postgres.Query.Definition.EnsureTable(TableName), sqlProps));
|
||||
Sql.executeNonQuery(Sql.query(Query.Definition.EnsureKey(TableName), sqlProps));
|
||||
Sql.executeNonQuery(Sql.query(Query.Definition.EnsureKey(TableName, Dialect.PostgreSQL), sqlProps));
|
||||
|
||||
Postgres.Configuration.UseDataSource(MkDataSource(database.ConnectionString));
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using Expecto.CSharp;
|
||||
using Expecto;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using BitBadger.Documents.Sqlite;
|
||||
|
||||
namespace BitBadger.Documents.Tests.CSharp;
|
||||
@@ -18,10 +17,10 @@ public static class SqliteCSharpExtensionTests
|
||||
/// Integration tests for the SQLite extension methods
|
||||
/// </summary>
|
||||
[Tests]
|
||||
public static readonly Test Integration = TestList("Sqlite.C#.Extensions", new[]
|
||||
{
|
||||
TestList("CustomSingle", new[]
|
||||
{
|
||||
public static readonly Test Integration = TestList("Sqlite.C#.Extensions",
|
||||
[
|
||||
TestList("CustomSingle",
|
||||
[
|
||||
TestCase("succeeds when a row is found", async () =>
|
||||
{
|
||||
await using var db = await SqliteDb.BuildDb();
|
||||
@@ -29,7 +28,7 @@ public static class SqliteCSharpExtensionTests
|
||||
await LoadDocs();
|
||||
|
||||
var doc = await conn.CustomSingle($"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'Id' = @id",
|
||||
new[] { Parameters.Id("one") }, Results.FromData<JsonDocument>);
|
||||
[Parameters.Id("one")], Results.FromData<JsonDocument>);
|
||||
Expect.isNotNull(doc, "There should have been a document returned");
|
||||
Expect.equal(doc!.Id, "one", "The incorrect document was returned");
|
||||
}),
|
||||
@@ -40,19 +39,19 @@ public static class SqliteCSharpExtensionTests
|
||||
await LoadDocs();
|
||||
|
||||
var doc = await conn.CustomSingle($"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'Id' = @id",
|
||||
new[] { Parameters.Id("eighty") }, Results.FromData<JsonDocument>);
|
||||
[Parameters.Id("eighty")], Results.FromData<JsonDocument>);
|
||||
Expect.isNull(doc, "There should not have been a document returned");
|
||||
})
|
||||
}),
|
||||
TestList("CustomList", new[]
|
||||
{
|
||||
]),
|
||||
TestList("CustomList",
|
||||
[
|
||||
TestCase("succeeds when data is found", async () =>
|
||||
{
|
||||
await using var db = await SqliteDb.BuildDb();
|
||||
await using var conn = Sqlite.Configuration.DbConn();
|
||||
await LoadDocs();
|
||||
|
||||
var docs = await conn.CustomList(Query.SelectFromTable(SqliteDb.TableName), Parameters.None,
|
||||
var docs = await conn.CustomList(Query.Find(SqliteDb.TableName), Parameters.None,
|
||||
Results.FromData<JsonDocument>);
|
||||
Expect.equal(docs.Count, 5, "There should have been 5 documents returned");
|
||||
}),
|
||||
@@ -63,13 +62,13 @@ public static class SqliteCSharpExtensionTests
|
||||
await LoadDocs();
|
||||
|
||||
var docs = await conn.CustomList(
|
||||
$"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'NumValue' > @value",
|
||||
new[] { new SqliteParameter("@value", 100) }, Results.FromData<JsonDocument>);
|
||||
$"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'NumValue' > @value", [new("@value", 100)],
|
||||
Results.FromData<JsonDocument>);
|
||||
Expect.isEmpty(docs, "There should have been no documents returned");
|
||||
})
|
||||
}),
|
||||
TestList("CustomNonQuery", new[]
|
||||
{
|
||||
]),
|
||||
TestList("CustomNonQuery",
|
||||
[
|
||||
TestCase("succeeds when operating on data", async () =>
|
||||
{
|
||||
await using var db = await SqliteDb.BuildDb();
|
||||
@@ -88,12 +87,12 @@ public static class SqliteCSharpExtensionTests
|
||||
await LoadDocs();
|
||||
|
||||
await conn.CustomNonQuery($"DELETE FROM {SqliteDb.TableName} WHERE data ->> 'NumValue' > @value",
|
||||
new[] { new SqliteParameter("@value", 100) });
|
||||
[new("@value", 100)]);
|
||||
|
||||
var remaining = await conn.CountAll(SqliteDb.TableName);
|
||||
Expect.equal(remaining, 5L, "There should be 5 documents remaining in the table");
|
||||
})
|
||||
}),
|
||||
]),
|
||||
TestCase("CustomScalar succeeds", async () =>
|
||||
{
|
||||
await using var db = await SqliteDb.BuildDb();
|
||||
@@ -107,41 +106,44 @@ public static class SqliteCSharpExtensionTests
|
||||
await using var db = await SqliteDb.BuildDb();
|
||||
await using var conn = Sqlite.Configuration.DbConn();
|
||||
|
||||
Func<string, ValueTask<bool>> itExists = async name =>
|
||||
await conn.CustomScalar(
|
||||
$"SELECT EXISTS (SELECT 1 FROM {SqliteDb.Catalog} WHERE name = @name) AS it",
|
||||
new SqliteParameter[] { new("@name", name) }, Results.ToExists);
|
||||
|
||||
var exists = await itExists("ensured");
|
||||
var alsoExists = await itExists("idx_ensured_key");
|
||||
var exists = await ItExists("ensured");
|
||||
var alsoExists = await ItExists("idx_ensured_key");
|
||||
Expect.isFalse(exists, "The table should not exist already");
|
||||
Expect.isFalse(alsoExists, "The key index should not exist already");
|
||||
|
||||
await conn.EnsureTable("ensured");
|
||||
|
||||
exists = await itExists("ensured");
|
||||
alsoExists = await itExists("idx_ensured_key");
|
||||
exists = await ItExists("ensured");
|
||||
alsoExists = await ItExists("idx_ensured_key");
|
||||
Expect.isTrue(exists, "The table should now exist");
|
||||
Expect.isTrue(alsoExists, "The key index should now exist");
|
||||
return;
|
||||
|
||||
Task<bool> ItExists(string name) =>
|
||||
conn.CustomScalar($"SELECT EXISTS (SELECT 1 FROM {SqliteDb.Catalog} WHERE name = @name) AS it",
|
||||
[new("@name", name)], Results.ToExists);
|
||||
}),
|
||||
TestCase("EnsureFieldIndex succeeds", async () =>
|
||||
{
|
||||
await using var db = await SqliteDb.BuildDb();
|
||||
await using var conn = Sqlite.Configuration.DbConn();
|
||||
var indexExists = () => conn.CustomScalar(
|
||||
$"SELECT EXISTS (SELECT 1 FROM {SqliteDb.Catalog} WHERE name = 'idx_ensured_test') AS it",
|
||||
Parameters.None, Results.ToExists);
|
||||
|
||||
var exists = await indexExists();
|
||||
var exists = await IndexExists();
|
||||
Expect.isFalse(exists, "The index should not exist already");
|
||||
|
||||
await conn.EnsureTable("ensured");
|
||||
await conn.EnsureFieldIndex("ensured", "test", new[] { "Id", "Category" });
|
||||
exists = await indexExists();
|
||||
await conn.EnsureFieldIndex("ensured", "test", ["Id", "Category"]);
|
||||
exists = await IndexExists();
|
||||
Expect.isTrue(exists, "The index should now exist");
|
||||
return;
|
||||
|
||||
Task<bool> IndexExists() =>
|
||||
conn.CustomScalar(
|
||||
$"SELECT EXISTS (SELECT 1 FROM {SqliteDb.Catalog} WHERE name = 'idx_ensured_test') AS it",
|
||||
Parameters.None, Results.ToExists);
|
||||
}),
|
||||
TestList("Insert", new[]
|
||||
{
|
||||
TestList("Insert",
|
||||
[
|
||||
TestCase("succeeds", async () =>
|
||||
{
|
||||
await using var db = await SqliteDb.BuildDb();
|
||||
@@ -168,9 +170,9 @@ public static class SqliteCSharpExtensionTests
|
||||
// This is what is supposed to happen
|
||||
}
|
||||
})
|
||||
}),
|
||||
TestList("Save", new[]
|
||||
{
|
||||
]),
|
||||
TestList("Save",
|
||||
[
|
||||
TestCase("succeeds when a document is inserted", async () =>
|
||||
{
|
||||
await using var db = await SqliteDb.BuildDb();
|
||||
@@ -203,7 +205,7 @@ public static class SqliteCSharpExtensionTests
|
||||
Expect.equal(after!.Id, "test", "The updated document is not correct");
|
||||
Expect.isNull(after.Sub, "There should not have been a sub-document in the updated document");
|
||||
})
|
||||
}),
|
||||
]),
|
||||
TestCase("CountAll succeeds", async () =>
|
||||
{
|
||||
await using var db = await SqliteDb.BuildDb();
|
||||
@@ -219,11 +221,11 @@ public static class SqliteCSharpExtensionTests
|
||||
await using var conn = Sqlite.Configuration.DbConn();
|
||||
await LoadDocs();
|
||||
|
||||
var theCount = await conn.CountByField(SqliteDb.TableName, Field.EQ("Value", "purple"));
|
||||
var theCount = await conn.CountByFields(SqliteDb.TableName, FieldMatch.Any, [Field.EQ("Value", "purple")]);
|
||||
Expect.equal(theCount, 2L, "There should have been 2 matching documents");
|
||||
}),
|
||||
TestList("ExistsById", new[]
|
||||
{
|
||||
TestList("ExistsById",
|
||||
[
|
||||
TestCase("succeeds when a document exists", async () =>
|
||||
{
|
||||
await using var db = await SqliteDb.BuildDb();
|
||||
@@ -242,16 +244,16 @@ public static class SqliteCSharpExtensionTests
|
||||
var exists = await conn.ExistsById(SqliteDb.TableName, "seven");
|
||||
Expect.isFalse(exists, "There should not have been an existing document");
|
||||
})
|
||||
}),
|
||||
TestList("ExistsByField", new[]
|
||||
{
|
||||
]),
|
||||
TestList("ExistsByFields",
|
||||
[
|
||||
TestCase("succeeds when documents exist", async () =>
|
||||
{
|
||||
await using var db = await SqliteDb.BuildDb();
|
||||
await using var conn = Sqlite.Configuration.DbConn();
|
||||
await LoadDocs();
|
||||
|
||||
var exists = await conn.ExistsByField(SqliteDb.TableName, Field.GE("NumValue", 10));
|
||||
var exists = await conn.ExistsByFields(SqliteDb.TableName, FieldMatch.Any, [Field.GE("NumValue", 10)]);
|
||||
Expect.isTrue(exists, "There should have been existing documents");
|
||||
}),
|
||||
TestCase("succeeds when no matching documents exist", async () =>
|
||||
@@ -260,12 +262,13 @@ public static class SqliteCSharpExtensionTests
|
||||
await using var conn = Sqlite.Configuration.DbConn();
|
||||
await LoadDocs();
|
||||
|
||||
var exists = await conn.ExistsByField(SqliteDb.TableName, Field.EQ("Nothing", "none"));
|
||||
var exists =
|
||||
await conn.ExistsByFields(SqliteDb.TableName, FieldMatch.Any, [Field.EQ("Nothing", "none")]);
|
||||
Expect.isFalse(exists, "There should not have been any existing documents");
|
||||
})
|
||||
}),
|
||||
TestList("FindAll", new[]
|
||||
{
|
||||
]),
|
||||
TestList("FindAll",
|
||||
[
|
||||
TestCase("succeeds when there is data", async () =>
|
||||
{
|
||||
await using var db = await SqliteDb.BuildDb();
|
||||
@@ -285,9 +288,46 @@ public static class SqliteCSharpExtensionTests
|
||||
var results = await conn.FindAll<JsonDocument>(SqliteDb.TableName);
|
||||
Expect.isEmpty(results, "There should have been no documents returned");
|
||||
})
|
||||
}),
|
||||
TestList("FindById", new[]
|
||||
{
|
||||
]),
|
||||
TestList("FindAllOrdered",
|
||||
[
|
||||
TestCase("succeeds when ordering numerically", async () =>
|
||||
{
|
||||
await using var db = await SqliteDb.BuildDb();
|
||||
await using var conn = Sqlite.Configuration.DbConn();
|
||||
await LoadDocs();
|
||||
|
||||
var results = await conn.FindAllOrdered<JsonDocument>(SqliteDb.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 = await SqliteDb.BuildDb();
|
||||
await using var conn = Sqlite.Configuration.DbConn();
|
||||
await LoadDocs();
|
||||
|
||||
var results =
|
||||
await conn.FindAllOrdered<JsonDocument>(SqliteDb.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 = await SqliteDb.BuildDb();
|
||||
await using var conn = Sqlite.Configuration.DbConn();
|
||||
await LoadDocs();
|
||||
|
||||
var results = await conn.FindAllOrdered<JsonDocument>(SqliteDb.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("FindById",
|
||||
[
|
||||
TestCase("succeeds when a document is found", async () =>
|
||||
{
|
||||
await using var db = await SqliteDb.BuildDb();
|
||||
@@ -307,16 +347,17 @@ public static class SqliteCSharpExtensionTests
|
||||
var doc = await conn.FindById<string, JsonDocument>(SqliteDb.TableName, "eighty-seven");
|
||||
Expect.isNull(doc, "There should not have been a document returned");
|
||||
})
|
||||
}),
|
||||
TestList("FindByField", new[]
|
||||
{
|
||||
]),
|
||||
TestList("FindByFields",
|
||||
[
|
||||
TestCase("succeeds when documents are found", async () =>
|
||||
{
|
||||
await using var db = await SqliteDb.BuildDb();
|
||||
await using var conn = Sqlite.Configuration.DbConn();
|
||||
await LoadDocs();
|
||||
|
||||
var docs = await conn.FindByField<JsonDocument>(SqliteDb.TableName, Field.GT("NumValue", 15));
|
||||
var docs = await conn.FindByFields<JsonDocument>(SqliteDb.TableName, FieldMatch.Any,
|
||||
[Field.GT("NumValue", 15)]);
|
||||
Expect.equal(docs.Count, 2, "There should have been two documents returned");
|
||||
}),
|
||||
TestCase("succeeds when documents are not found", async () =>
|
||||
@@ -325,19 +366,46 @@ public static class SqliteCSharpExtensionTests
|
||||
await using var conn = Sqlite.Configuration.DbConn();
|
||||
await LoadDocs();
|
||||
|
||||
var docs = await conn.FindByField<JsonDocument>(SqliteDb.TableName, Field.EQ("Value", "mauve"));
|
||||
var docs = await conn.FindByFields<JsonDocument>(SqliteDb.TableName, FieldMatch.Any,
|
||||
[Field.EQ("Value", "mauve")]);
|
||||
Expect.isEmpty(docs, "There should have been no documents returned");
|
||||
})
|
||||
}),
|
||||
TestList("FindFirstByField", new[]
|
||||
{
|
||||
]),
|
||||
TestList("ByFieldsOrdered",
|
||||
[
|
||||
TestCase("succeeds when documents are found", async () =>
|
||||
{
|
||||
await using var db = await SqliteDb.BuildDb();
|
||||
await using var conn = Sqlite.Configuration.DbConn();
|
||||
await LoadDocs();
|
||||
|
||||
var docs = await conn.FindByFieldsOrdered<JsonDocument>(SqliteDb.TableName, FieldMatch.Any,
|
||||
[Field.GT("NumValue", 15)], [Field.Named("Id")]);
|
||||
Expect.equal(string.Join('|', docs.Select(x => x.Id)), "five|four",
|
||||
"There should have been two documents returned");
|
||||
}),
|
||||
TestCase("succeeds when documents are not found", async () =>
|
||||
{
|
||||
await using var db = await SqliteDb.BuildDb();
|
||||
await using var conn = Sqlite.Configuration.DbConn();
|
||||
await LoadDocs();
|
||||
|
||||
var docs = await conn.FindByFieldsOrdered<JsonDocument>(SqliteDb.TableName, FieldMatch.Any,
|
||||
[Field.GT("NumValue", 15)], [Field.Named("Id DESC")]);
|
||||
Expect.equal(string.Join('|', docs.Select(x => x.Id)), "four|five",
|
||||
"There should have been two documents returned");
|
||||
})
|
||||
]),
|
||||
TestList("FindFirstByFields",
|
||||
[
|
||||
TestCase("succeeds when a document is found", async () =>
|
||||
{
|
||||
await using var db = await SqliteDb.BuildDb();
|
||||
await using var conn = Sqlite.Configuration.DbConn();
|
||||
await LoadDocs();
|
||||
|
||||
var doc = await conn.FindFirstByField<JsonDocument>(SqliteDb.TableName, Field.EQ("Value", "another"));
|
||||
var doc = await conn.FindFirstByFields<JsonDocument>(SqliteDb.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");
|
||||
}),
|
||||
@@ -347,9 +415,10 @@ public static class SqliteCSharpExtensionTests
|
||||
await using var conn = Sqlite.Configuration.DbConn();
|
||||
await LoadDocs();
|
||||
|
||||
var doc = await conn.FindFirstByField<JsonDocument>(SqliteDb.TableName, Field.EQ("Sub.Foo", "green"));
|
||||
var doc = await conn.FindFirstByFields<JsonDocument>(SqliteDb.TableName, FieldMatch.Any,
|
||||
[Field.EQ("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");
|
||||
Expect.contains(["two", "four"], doc!.Id, "An incorrect document was returned");
|
||||
}),
|
||||
TestCase("succeeds when a document is not found", async () =>
|
||||
{
|
||||
@@ -357,12 +426,38 @@ public static class SqliteCSharpExtensionTests
|
||||
await using var conn = Sqlite.Configuration.DbConn();
|
||||
await LoadDocs();
|
||||
|
||||
var doc = await conn.FindFirstByField<JsonDocument>(SqliteDb.TableName, Field.EQ("Value", "absent"));
|
||||
var doc = await conn.FindFirstByFields<JsonDocument>(SqliteDb.TableName, FieldMatch.Any,
|
||||
[Field.EQ("Value", "absent")]);
|
||||
Expect.isNull(doc, "There should not have been a document returned");
|
||||
})
|
||||
}),
|
||||
TestList("UpdateById", new[]
|
||||
{
|
||||
]),
|
||||
TestList("FindFirstByFieldsOrdered",
|
||||
[
|
||||
TestCase("succeeds when sorting ascending", async () =>
|
||||
{
|
||||
await using var db = await SqliteDb.BuildDb();
|
||||
await using var conn = Sqlite.Configuration.DbConn();
|
||||
await LoadDocs();
|
||||
|
||||
var doc = await conn.FindFirstByFieldsOrdered<JsonDocument>(SqliteDb.TableName, FieldMatch.Any,
|
||||
[Field.EQ("Sub.Foo", "green")], [Field.Named("Sub.Bar")]);
|
||||
Expect.isNotNull(doc, "There should have been a document returned");
|
||||
Expect.equal("two", doc!.Id, "An incorrect document was returned");
|
||||
}),
|
||||
TestCase("succeeds when sorting descending", async () =>
|
||||
{
|
||||
await using var db = await SqliteDb.BuildDb();
|
||||
await using var conn = Sqlite.Configuration.DbConn();
|
||||
await LoadDocs();
|
||||
|
||||
var doc = await conn.FindFirstByFieldsOrdered<JsonDocument>(SqliteDb.TableName, FieldMatch.Any,
|
||||
[Field.EQ("Sub.Foo", "green")], [Field.Named("Sub.Bar DESC")]);
|
||||
Expect.isNotNull(doc, "There should have been a document returned");
|
||||
Expect.equal("four", doc!.Id, "An incorrect document was returned");
|
||||
})
|
||||
]),
|
||||
TestList("UpdateById",
|
||||
[
|
||||
TestCase("succeeds when a document is updated", async () =>
|
||||
{
|
||||
await using var db = await SqliteDb.BuildDb();
|
||||
@@ -389,9 +484,9 @@ public static class SqliteCSharpExtensionTests
|
||||
await conn.UpdateById(SqliteDb.TableName, "test",
|
||||
new JsonDocument { Id = "x", Sub = new() { Foo = "blue", Bar = "red" } });
|
||||
})
|
||||
}),
|
||||
TestList("UpdateByFunc", new[]
|
||||
{
|
||||
]),
|
||||
TestList("UpdateByFunc",
|
||||
[
|
||||
TestCase("succeeds when a document is updated", async () =>
|
||||
{
|
||||
await using var db = await SqliteDb.BuildDb();
|
||||
@@ -418,9 +513,9 @@ public static class SqliteCSharpExtensionTests
|
||||
await conn.UpdateByFunc(SqliteDb.TableName, doc => doc.Id,
|
||||
new JsonDocument { Id = "one", Value = "le un", NumValue = 1 });
|
||||
})
|
||||
}),
|
||||
TestList("PatchById", new[]
|
||||
{
|
||||
]),
|
||||
TestList("PatchById",
|
||||
[
|
||||
TestCase("succeeds when a document is updated", async () =>
|
||||
{
|
||||
await using var db = await SqliteDb.BuildDb();
|
||||
@@ -443,17 +538,18 @@ public static class SqliteCSharpExtensionTests
|
||||
// This not raising an exception is the test
|
||||
await conn.PatchById(SqliteDb.TableName, "test", new { Foo = "green" });
|
||||
})
|
||||
}),
|
||||
TestList("PatchByField", new[]
|
||||
{
|
||||
]),
|
||||
TestList("PatchByFields",
|
||||
[
|
||||
TestCase("succeeds when a document is updated", async () =>
|
||||
{
|
||||
await using var db = await SqliteDb.BuildDb();
|
||||
await using var conn = Sqlite.Configuration.DbConn();
|
||||
await LoadDocs();
|
||||
|
||||
await conn.PatchByField(SqliteDb.TableName, Field.EQ("Value", "purple"), new { NumValue = 77 });
|
||||
var after = await conn.CountByField(SqliteDb.TableName, Field.EQ("NumValue", 77));
|
||||
await conn.PatchByFields(SqliteDb.TableName, FieldMatch.Any, [Field.EQ("Value", "purple")],
|
||||
new { NumValue = 77 });
|
||||
var after = await conn.CountByFields(SqliteDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", 77)]);
|
||||
Expect.equal(after, 2L, "There should have been 2 documents returned");
|
||||
}),
|
||||
TestCase("succeeds when no document is updated", async () =>
|
||||
@@ -464,18 +560,19 @@ public static class SqliteCSharpExtensionTests
|
||||
Expect.isEmpty(before, "There should have been no documents returned");
|
||||
|
||||
// This not raising an exception is the test
|
||||
await conn.PatchByField(SqliteDb.TableName, Field.EQ("Value", "burgundy"), new { Foo = "green" });
|
||||
await conn.PatchByFields(SqliteDb.TableName, FieldMatch.Any, [Field.EQ("Value", "burgundy")],
|
||||
new { Foo = "green" });
|
||||
})
|
||||
}),
|
||||
TestList("RemoveFieldsById", new[]
|
||||
{
|
||||
]),
|
||||
TestList("RemoveFieldsById",
|
||||
[
|
||||
TestCase("succeeds when fields are removed", async () =>
|
||||
{
|
||||
await using var db = await SqliteDb.BuildDb();
|
||||
await using var conn = Sqlite.Configuration.DbConn();
|
||||
await LoadDocs();
|
||||
|
||||
await conn.RemoveFieldsById(SqliteDb.TableName, "two", new[] { "Sub", "Value" });
|
||||
await conn.RemoveFieldsById(SqliteDb.TableName, "two", ["Sub", "Value"]);
|
||||
var updated = await Find.ById<string, JsonDocument>(SqliteDb.TableName, "two");
|
||||
Expect.isNotNull(updated, "The updated document should have been retrieved");
|
||||
Expect.equal(updated.Value, "", "The string value should have been removed");
|
||||
@@ -488,7 +585,7 @@ public static class SqliteCSharpExtensionTests
|
||||
await LoadDocs();
|
||||
|
||||
// This not raising an exception is the test
|
||||
await conn.RemoveFieldsById(SqliteDb.TableName, "two", new[] { "AFieldThatIsNotThere" });
|
||||
await conn.RemoveFieldsById(SqliteDb.TableName, "two", ["AFieldThatIsNotThere"]);
|
||||
}),
|
||||
TestCase("succeeds when no document is matched", async () =>
|
||||
{
|
||||
@@ -496,18 +593,19 @@ public static class SqliteCSharpExtensionTests
|
||||
await using var conn = Sqlite.Configuration.DbConn();
|
||||
|
||||
// This not raising an exception is the test
|
||||
await conn.RemoveFieldsById(SqliteDb.TableName, "two", new[] { "Value" });
|
||||
await conn.RemoveFieldsById(SqliteDb.TableName, "two", ["Value"]);
|
||||
})
|
||||
}),
|
||||
TestList("RemoveFieldsByField", new[]
|
||||
{
|
||||
]),
|
||||
TestList("RemoveFieldsByFields",
|
||||
[
|
||||
TestCase("succeeds when a field is removed", async () =>
|
||||
{
|
||||
await using var db = await SqliteDb.BuildDb();
|
||||
await using var conn = Sqlite.Configuration.DbConn();
|
||||
await LoadDocs();
|
||||
|
||||
await conn.RemoveFieldsByField(SqliteDb.TableName, Field.EQ("NumValue", 17), new[] { "Sub" });
|
||||
await conn.RemoveFieldsByFields(SqliteDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", 17)],
|
||||
["Sub"]);
|
||||
var updated = await Find.ById<string, JsonDocument>(SqliteDb.TableName, "four");
|
||||
Expect.isNotNull(updated, "The updated document should have been retrieved");
|
||||
Expect.isNull(updated.Sub, "The sub-document should have been removed");
|
||||
@@ -519,7 +617,8 @@ public static class SqliteCSharpExtensionTests
|
||||
await LoadDocs();
|
||||
|
||||
// This not raising an exception is the test
|
||||
await conn.RemoveFieldsByField(SqliteDb.TableName, Field.EQ("NumValue", 17), new[] { "Nothing" });
|
||||
await conn.RemoveFieldsByFields(SqliteDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", 17)],
|
||||
["Nothing"]);
|
||||
}),
|
||||
TestCase("succeeds when no document is matched", async () =>
|
||||
{
|
||||
@@ -527,11 +626,12 @@ public static class SqliteCSharpExtensionTests
|
||||
await using var conn = Sqlite.Configuration.DbConn();
|
||||
|
||||
// This not raising an exception is the test
|
||||
await conn.RemoveFieldsByField(SqliteDb.TableName, Field.NE("Abracadabra", "apple"), new[] { "Value" });
|
||||
await conn.RemoveFieldsByFields(SqliteDb.TableName, FieldMatch.Any, [Field.NE("Abracadabra", "apple")],
|
||||
["Value"]);
|
||||
})
|
||||
}),
|
||||
TestList("DeleteById", new[]
|
||||
{
|
||||
]),
|
||||
TestList("DeleteById",
|
||||
[
|
||||
TestCase("succeeds when a document is deleted", async () =>
|
||||
{
|
||||
await using var db = await SqliteDb.BuildDb();
|
||||
@@ -552,16 +652,16 @@ public static class SqliteCSharpExtensionTests
|
||||
var remaining = await conn.CountAll(SqliteDb.TableName);
|
||||
Expect.equal(remaining, 5L, "There should have been 5 documents remaining");
|
||||
})
|
||||
}),
|
||||
TestList("DeleteByField", new[]
|
||||
{
|
||||
]),
|
||||
TestList("DeleteByFields",
|
||||
[
|
||||
TestCase("succeeds when documents are deleted", async () =>
|
||||
{
|
||||
await using var db = await SqliteDb.BuildDb();
|
||||
await using var conn = Sqlite.Configuration.DbConn();
|
||||
await LoadDocs();
|
||||
|
||||
await conn.DeleteByField(SqliteDb.TableName, Field.NE("Value", "purple"));
|
||||
await conn.DeleteByFields(SqliteDb.TableName, FieldMatch.Any, [Field.NE("Value", "purple")]);
|
||||
var remaining = await conn.CountAll(SqliteDb.TableName);
|
||||
Expect.equal(remaining, 2L, "There should have been 2 documents remaining");
|
||||
}),
|
||||
@@ -571,11 +671,11 @@ public static class SqliteCSharpExtensionTests
|
||||
await using var conn = Sqlite.Configuration.DbConn();
|
||||
await LoadDocs();
|
||||
|
||||
await conn.DeleteByField(SqliteDb.TableName, Field.EQ("Value", "crimson"));
|
||||
await conn.DeleteByFields(SqliteDb.TableName, FieldMatch.Any, [Field.EQ("Value", "crimson")]);
|
||||
var remaining = await conn.CountAll(SqliteDb.TableName);
|
||||
Expect.equal(remaining, 5L, "There should have been 5 documents remaining");
|
||||
})
|
||||
}),
|
||||
]),
|
||||
TestCase("Clean up database", () => Sqlite.Configuration.UseConnectionString("data source=:memory:"))
|
||||
});
|
||||
]);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,11 @@
|
||||
namespace BitBadger.Documents.Tests.CSharp;
|
||||
|
||||
public class NumIdDocument
|
||||
{
|
||||
public int Key { get; set; } = 0;
|
||||
public string Text { get; set; } = "";
|
||||
}
|
||||
|
||||
public class SubDocument
|
||||
{
|
||||
public string Foo { get; set; } = "";
|
||||
|
||||
Reference in New Issue
Block a user