diff --git a/src/Common/Library.fs b/src/Common/Library.fs index fd2554b..4a9f171 100644 --- a/src/Common/Library.fs +++ b/src/Common/Library.fs @@ -309,10 +309,10 @@ module Query = { it with Name = parts[0] }, Some $" {parts[1]}" else it, None) |> Seq.map (fun (field, direction) -> - let path = - if dialect = PostgreSQL && field.Name.StartsWith "n:" then - $"({ { field with Name = field.Name[2..] }.Path dialect})::numeric" - else field.Path dialect - path + defaultArg direction "") + match dialect, field.Name.StartsWith "n:" with + | PostgreSQL, true -> $"({ { field with Name = field.Name[2..] }.Path PostgreSQL})::numeric" + | SQLite, true -> { field with Name = field.Name[2..] }.Path SQLite + | _, _ -> field.Path dialect + |> function path -> path + defaultArg direction "") |> String.concat ", " |> function it -> $" ORDER BY {it}" diff --git a/src/Sqlite/Extensions.fs b/src/Sqlite/Extensions.fs index c5e83e5..d8b5106 100644 --- a/src/Sqlite/Extensions.fs +++ b/src/Sqlite/Extensions.fs @@ -49,11 +49,6 @@ module Extensions = member conn.countByFields tableName howMatched fields = WithConn.Count.byFields tableName howMatched fields conn - /// Count matching documents using a comparison on a JSON field - [] - member conn.countByField tableName field = - conn.countByFields tableName Any [ field ] - /// Determine if a document exists for the given ID member conn.existsById tableName (docId: 'TKey) = WithConn.Exists.byId tableName docId conn @@ -62,11 +57,6 @@ module Extensions = member conn.existsByFields tableName howMatched fields = WithConn.Exists.byFields tableName howMatched fields conn - /// Determine if a document exists using a comparison on a JSON field - [] - member conn.existsByField tableName field = - conn.existsByFields tableName Any [ field ] - /// Retrieve all documents in the given table member conn.findAll<'TDoc> tableName = WithConn.Find.all<'TDoc> tableName conn @@ -87,11 +77,6 @@ module Extensions = member conn.findByFieldsOrdered<'TDoc> tableName howMatched queryFields orderFields = WithConn.Find.byFieldsOrdered<'TDoc> tableName howMatched queryFields orderFields conn - /// Retrieve documents via a comparison on a JSON field - [] - member conn.findByField<'TDoc> tableName field = - conn.findByFields<'TDoc> tableName Any [ field ] - /// Retrieve documents via a comparison on JSON fields, returning only the first result member conn.findFirstByFields<'TDoc> tableName howMatched fields = WithConn.Find.firstByFields<'TDoc> tableName howMatched fields conn @@ -101,11 +86,6 @@ module Extensions = member conn.findFirstByFieldsOrdered<'TDoc> tableName howMatched queryFields orderFields = WithConn.Find.firstByFieldsOrdered<'TDoc> tableName howMatched queryFields orderFields conn - /// Retrieve documents via a comparison on a JSON field, returning only the first result - [] - member conn.findFirstByField<'TDoc> tableName field = - conn.findFirstByFields<'TDoc> tableName Any [ field ] - /// Update an entire document by its ID member conn.updateById tableName (docId: 'TKey) (document: 'TDoc) = WithConn.Update.byId tableName docId document conn @@ -122,11 +102,6 @@ module Extensions = member conn.patchByFields tableName howMatched fields (patch: 'TPatch) = WithConn.Patch.byFields tableName howMatched fields patch conn - /// Patch documents using a comparison on a JSON field - [] - member conn.patchByField tableName field (patch: 'TPatch) = - conn.patchByFields tableName Any [ field ] patch - /// Remove fields from a document by the document's ID member conn.removeFieldsById tableName (docId: 'TKey) fieldNames = WithConn.RemoveFields.byId tableName docId fieldNames conn @@ -135,11 +110,6 @@ module Extensions = member conn.removeFieldsByFields tableName howMatched fields fieldNames = WithConn.RemoveFields.byFields tableName howMatched fields fieldNames conn - /// Remove a field from a document via a comparison on a JSON field in the document - [] - member conn.removeFieldsByField tableName field fieldNames = - conn.removeFieldsByFields tableName Any [ field ] fieldNames - /// Delete a document by its ID member conn.deleteById tableName (docId: 'TKey) = WithConn.Delete.byId tableName docId conn @@ -147,11 +117,6 @@ module Extensions = /// Delete documents by matching a comparison on JSON fields member conn.deleteByFields tableName howMatched fields = WithConn.Delete.byFields tableName howMatched fields conn - - /// Delete documents by matching a comparison on a JSON field - [] - member conn.deleteByField tableName field = - conn.deleteByFields tableName Any [ field ] open System.Runtime.CompilerServices @@ -211,12 +176,6 @@ type SqliteConnectionCSharpExtensions = static member inline CountByFields(conn, tableName, howMatched, fields) = WithConn.Count.byFields tableName howMatched fields conn - /// Count matching documents using a comparison on a JSON field - [] - [] - static member inline CountByField(conn, tableName, field) = - conn.CountByFields(tableName, Any, [ field ]) - /// Determine if a document exists for the given ID [] static member inline ExistsById<'TKey>(conn, tableName, docId: 'TKey) = @@ -227,12 +186,6 @@ type SqliteConnectionCSharpExtensions = static member inline ExistsByFields(conn, tableName, howMatched, fields) = WithConn.Exists.byFields tableName howMatched fields conn - /// Determine if a document exists using a comparison on a JSON field - [] - [] - static member inline ExistsByField(conn, tableName, field) = - conn.ExistsByFields(tableName, Any, [ field ]) - /// Retrieve all documents in the given table [] static member inline FindAll<'TDoc>(conn, tableName) = @@ -241,7 +194,7 @@ type SqliteConnectionCSharpExtensions = /// Retrieve all documents in the given table ordered by the given fields in the document [] static member inline FindAllOrdered<'TDoc>(conn, tableName, orderFields) = - WithConn.Find.AllOrdered<'TDoc>(tableName, conn, orderFields) + WithConn.Find.AllOrdered<'TDoc>(tableName, orderFields, conn) /// Retrieve a document by its ID [] @@ -258,12 +211,6 @@ type SqliteConnectionCSharpExtensions = static member inline FindByFieldsOrdered<'TDoc>(conn, tableName, howMatched, queryFields, orderFields) = WithConn.Find.ByFieldsOrdered<'TDoc>(tableName, howMatched, queryFields, orderFields, conn) - /// Retrieve documents via a comparison on a JSON field - [] - [] - static member inline FindByField<'TDoc>(conn, tableName, field) = - conn.FindByFields<'TDoc>(tableName, Any, [ field ]) - /// Retrieve documents via a comparison on JSON fields, returning only the first result [] static member inline FindFirstByFields<'TDoc when 'TDoc: null>(conn, tableName, howMatched, fields) = @@ -276,12 +223,6 @@ type SqliteConnectionCSharpExtensions = conn, tableName, howMatched, queryFields, orderFields) = WithConn.Find.FirstByFieldsOrdered<'TDoc>(tableName, howMatched, queryFields, orderFields, conn) - /// Retrieve documents via a comparison on a JSON field, returning only the first result - [] - [] - static member inline FindFirstByField<'TDoc when 'TDoc: null>(conn, tableName, field) = - conn.FindFirstByFields<'TDoc>(tableName, Any, [ field ]) - /// Update an entire document by its ID [] static member inline UpdateById<'TKey, 'TDoc>(conn, tableName, docId: 'TKey, document: 'TDoc) = @@ -302,12 +243,6 @@ type SqliteConnectionCSharpExtensions = static member inline PatchByFields<'TPatch>(conn, tableName, howMatched, fields, patch: 'TPatch) = WithConn.Patch.byFields tableName howMatched fields patch conn - /// Patch documents using a comparison on a JSON field - [] - [] - static member inline PatchByField<'TPatch>(conn, tableName, field, patch: 'TPatch) = - conn.PatchByFields(tableName, Any, [ field ], patch) - /// Remove fields from a document by the document's ID [] static member inline RemoveFieldsById<'TKey>(conn, tableName, docId: 'TKey, fieldNames) = @@ -318,12 +253,6 @@ type SqliteConnectionCSharpExtensions = static member inline RemoveFieldsByFields(conn, tableName, howMatched, fields, fieldNames) = WithConn.RemoveFields.byFields tableName howMatched fields fieldNames conn - /// Remove fields from documents via a comparison on a JSON field in the document - [] - [] - static member inline RemoveFieldsByField(conn, tableName, field, fieldNames) = - conn.RemoveFieldsByFields(tableName, Any, [ field ], fieldNames) - /// Delete a document by its ID [] static member inline DeleteById<'TKey>(conn, tableName, docId: 'TKey) = diff --git a/src/Sqlite/Library.fs b/src/Sqlite/Library.fs index 7fb3afd..accbdb8 100644 --- a/src/Sqlite/Library.fs +++ b/src/Sqlite/Library.fs @@ -321,7 +321,7 @@ module WithConn = /// Retrieve all documents in the given table ordered by the given fields in the document let AllOrdered<'TDoc>(tableName, orderFields, conn) = - Custom.List(Query.find tableName + Query.orderBy orderFields PostgreSQL, [], fromData<'TDoc>, conn) + Custom.List(Query.find tableName + Query.orderBy orderFields SQLite, [], fromData<'TDoc>, conn) /// Retrieve a document by its ID (returns None if not found) [] diff --git a/src/Tests.CSharp/CommonCSharpTests.cs b/src/Tests.CSharp/CommonCSharpTests.cs index 0dda978..f0d81f9 100644 --- a/src/Tests.CSharp/CommonCSharpTests.cs +++ b/src/Tests.CSharp/CommonCSharpTests.cs @@ -386,43 +386,53 @@ public static class CommonCSharpTests [ TestCase("succeeds for no fields", () => { - Expect.equal("", Query.OrderBy([], Dialect.PostgreSQL), + 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)"); + Expect.equal(Query.OrderBy([], Dialect.SQLite), "", "Order By should have been blank (SQLite)"); }), TestCase("succeeds for PostgreSQL with one field and no direction", () => { - Expect.equal(" ORDER BY data->>'TestField'", - Query.OrderBy([Field.Named("TestField")], Dialect.PostgreSQL), - "Order By not constructed correctly"); + 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(" ORDER BY data->>'TestField'", - Query.OrderBy([Field.Named("TestField")], Dialect.SQLite), - "Order By not constructed correctly"); + 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(" ORDER BY data#>>'{Nested,Test,Field}' DESC, data->>'AnotherField', data->>'It' DESC", + Expect.equal( Query.OrderBy( [ Field.Named("Nested.Test.Field DESC"), Field.Named("AnotherField"), Field.Named("It DESC") ], - Dialect.PostgreSQL), "Order By not constructed correctly"); + 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( - " ORDER BY data->>'Nested'->>'Test'->>'Field' DESC, data->>'AnotherField', data->>'It' DESC", 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"); }) ]) ]) diff --git a/src/Tests.CSharp/SqliteCSharpExtensionTests.cs b/src/Tests.CSharp/SqliteCSharpExtensionTests.cs index 70098ce..7290183 100644 --- a/src/Tests.CSharp/SqliteCSharpExtensionTests.cs +++ b/src/Tests.CSharp/SqliteCSharpExtensionTests.cs @@ -1,6 +1,5 @@ using Expecto.CSharp; using Expecto; -using Microsoft.Data.Sqlite; using BitBadger.Documents.Sqlite; namespace BitBadger.Documents.Tests.CSharp; @@ -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); + [Parameters.Id("one")], Results.FromData); Expect.isNotNull(doc, "There should have been a document returned"); Expect.equal(doc!.Id, "one", "The incorrect document was returned"); }), @@ -40,7 +39,7 @@ 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); + [Parameters.Id("eighty")], Results.FromData); Expect.isNull(doc, "There should not have been a document returned"); }) ]), @@ -63,8 +62,8 @@ 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); + $"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'NumValue' > @value", [new("@value", 100)], + Results.FromData); Expect.isEmpty(docs, "There should have been no documents returned"); }) ]), @@ -88,7 +87,7 @@ 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"); @@ -107,38 +106,41 @@ public static class SqliteCSharpExtensionTests await using var db = await SqliteDb.BuildDb(); await using var conn = Sqlite.Configuration.DbConn(); - Func> 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 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 IndexExists() => + conn.CustomScalar( + $"SELECT EXISTS (SELECT 1 FROM {SqliteDb.Catalog} WHERE name = 'idx_ensured_test') AS it", + Parameters.None, Results.ToExists); }), TestList("Insert", [ @@ -213,17 +215,15 @@ public static class SqliteCSharpExtensionTests var theCount = await conn.CountAll(SqliteDb.TableName); Expect.equal(theCount, 5L, "There should have been 5 matching documents"); }), -#pragma warning disable CS0618 TestCase("CountByField succeeds", async () => { await using var db = await SqliteDb.BuildDb(); 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"); }), -#pragma warning restore CS0618 TestList("ExistsById", [ TestCase("succeeds when a document exists", async () => @@ -245,8 +245,7 @@ public static class SqliteCSharpExtensionTests Expect.isFalse(exists, "There should not have been an existing document"); }) ]), -#pragma warning disable CS0618 - TestList("ExistsByField", + TestList("ExistsByFields", [ TestCase("succeeds when documents exist", async () => { @@ -254,7 +253,7 @@ public static class SqliteCSharpExtensionTests 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 () => @@ -263,11 +262,11 @@ 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"); }) ]), -#pragma warning restore CS0618 TestList("FindAll", [ TestCase("succeeds when there is data", async () => @@ -290,6 +289,43 @@ public static class SqliteCSharpExtensionTests Expect.isEmpty(results, "There should have been no documents returned"); }) ]), + 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(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(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(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 () => @@ -312,8 +348,7 @@ public static class SqliteCSharpExtensionTests Expect.isNull(doc, "There should not have been a document returned"); }) ]), -#pragma warning disable CS0618 - TestList("FindByField", + TestList("FindByFields", [ TestCase("succeeds when documents are found", async () => { @@ -321,7 +356,8 @@ public static class SqliteCSharpExtensionTests await using var conn = Sqlite.Configuration.DbConn(); await LoadDocs(); - var docs = await conn.FindByField(SqliteDb.TableName, Field.GT("NumValue", 15)); + var docs = await conn.FindByFields(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 () => @@ -330,11 +366,37 @@ public static class SqliteCSharpExtensionTests await using var conn = Sqlite.Configuration.DbConn(); await LoadDocs(); - var docs = await conn.FindByField(SqliteDb.TableName, Field.EQ("Value", "mauve")); + var docs = await conn.FindByFields(SqliteDb.TableName, FieldMatch.Any, + [Field.EQ("Value", "mauve")]); Expect.isEmpty(docs, "There should have been no documents returned"); }) ]), - TestList("FindFirstByField", + 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(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(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 () => { @@ -342,7 +404,8 @@ public static class SqliteCSharpExtensionTests await using var conn = Sqlite.Configuration.DbConn(); await LoadDocs(); - var doc = await conn.FindFirstByField(SqliteDb.TableName, Field.EQ("Value", "another")); + var doc = await conn.FindFirstByFields(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"); }), @@ -352,9 +415,10 @@ public static class SqliteCSharpExtensionTests await using var conn = Sqlite.Configuration.DbConn(); await LoadDocs(); - var doc = await conn.FindFirstByField(SqliteDb.TableName, Field.EQ("Sub.Foo", "green")); + var doc = await conn.FindFirstByFields(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 () => { @@ -362,11 +426,36 @@ public static class SqliteCSharpExtensionTests await using var conn = Sqlite.Configuration.DbConn(); await LoadDocs(); - var doc = await conn.FindFirstByField(SqliteDb.TableName, Field.EQ("Value", "absent")); + var doc = await conn.FindFirstByFields(SqliteDb.TableName, FieldMatch.Any, + [Field.EQ("Value", "absent")]); Expect.isNull(doc, "There should not have been a document returned"); }) ]), -#pragma warning restore CS0618 + 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(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(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 () => @@ -450,8 +539,7 @@ public static class SqliteCSharpExtensionTests await conn.PatchById(SqliteDb.TableName, "test", new { Foo = "green" }); }) ]), -#pragma warning disable CS0618 - TestList("PatchByField", + TestList("PatchByFields", [ TestCase("succeeds when a document is updated", async () => { @@ -459,8 +547,9 @@ public static class SqliteCSharpExtensionTests 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 () => @@ -471,10 +560,10 @@ 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" }); }) ]), -#pragma warning restore CS0618 TestList("RemoveFieldsById", [ TestCase("succeeds when fields are removed", async () => @@ -483,7 +572,7 @@ public static class SqliteCSharpExtensionTests 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(SqliteDb.TableName, "two"); Expect.isNotNull(updated, "The updated document should have been retrieved"); Expect.equal(updated.Value, "", "The string value should have been removed"); @@ -496,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 () => { @@ -504,11 +593,10 @@ 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"]); }) ]), -#pragma warning disable CS0618 - TestList("RemoveFieldsByField", + TestList("RemoveFieldsByFields", [ TestCase("succeeds when a field is removed", async () => { @@ -516,7 +604,8 @@ public static class SqliteCSharpExtensionTests 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(SqliteDb.TableName, "four"); Expect.isNotNull(updated, "The updated document should have been retrieved"); Expect.isNull(updated.Sub, "The sub-document should have been removed"); @@ -528,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 () => { @@ -536,10 +626,10 @@ 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"]); }) ]), -#pragma warning restore CS0618 TestList("DeleteById", [ TestCase("succeeds when a document is deleted", async () => @@ -563,8 +653,7 @@ public static class SqliteCSharpExtensionTests Expect.equal(remaining, 5L, "There should have been 5 documents remaining"); }) ]), -#pragma warning disable CS0618 - TestList("DeleteByField", + TestList("DeleteByFields", [ TestCase("succeeds when documents are deleted", async () => { @@ -572,7 +661,7 @@ public static class SqliteCSharpExtensionTests 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"); }), @@ -582,12 +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"); }) ]), -#pragma warning restore CS0618 TestCase("Clean up database", () => Sqlite.Configuration.UseConnectionString("data source=:memory:")) ]); } diff --git a/src/Tests.CSharp/SqliteCSharpTests.cs b/src/Tests.CSharp/SqliteCSharpTests.cs index 13cc1f3..b453ff8 100644 --- a/src/Tests.CSharp/SqliteCSharpTests.cs +++ b/src/Tests.CSharp/SqliteCSharpTests.cs @@ -467,6 +467,39 @@ public static class SqliteCSharpTests Expect.isEmpty(results, "There should have been no documents returned"); }) ]), + TestList("AllOrdered", + [ + TestCase("succeeds when ordering numerically", async () => + { + await using var db = await SqliteDb.BuildDb(); + await LoadDocs(); + + var results = await Find.AllOrdered(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 LoadDocs(); + + var results = await Find.AllOrdered(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 LoadDocs(); + + var results = await Find.AllOrdered(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("ById", [ TestCase("succeeds when a document is found", async () => @@ -508,6 +541,29 @@ public static class SqliteCSharpTests Expect.isEmpty(docs, "There should have been no documents returned"); }) ]), + TestList("ByFieldsOrdered", + [ + TestCase("succeeds when documents are found", async () => + { + await using var db = await SqliteDb.BuildDb(); + await LoadDocs(); + + var docs = await Find.ByFieldsOrdered(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 LoadDocs(); + + var docs = await Find.ByFieldsOrdered(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("FirstByFields", [ TestCase("succeeds when a document is found", async () => @@ -539,6 +595,29 @@ public static class SqliteCSharpTests [Field.EQ("Value", "absent")]); Expect.isNull(doc, "There should not have been a document returned"); }) + ]), + TestList("FirstByFieldsOrdered", + [ + TestCase("succeeds when sorting ascending", async () => + { + await using var db = await SqliteDb.BuildDb(); + await LoadDocs(); + + var doc = await Find.FirstByFieldsOrdered(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 LoadDocs(); + + var doc = await Find.FirstByFieldsOrdered(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"); + }) ]) ]); diff --git a/src/Tests/CommonTests.fs b/src/Tests/CommonTests.fs index 4b3b718..853f4b2 100644 --- a/src/Tests/CommonTests.fs +++ b/src/Tests/CommonTests.fs @@ -277,37 +277,49 @@ let all = } testList "orderBy" [ test "succeeds for no fields" { - Expect.equal "" (Query.orderBy [] PostgreSQL) "Order By should have been blank (PostgreSQL)" - Expect.equal "" (Query.orderBy [] SQLite) "Order By should have been blank (SQLite)" + Expect.equal (Query.orderBy [] PostgreSQL) "" "Order By should have been blank (PostgreSQL)" + Expect.equal (Query.orderBy [] SQLite) "" "Order By should have been blank (SQLite)" } test "succeeds for PostgreSQL with one field and no direction" { Expect.equal - " ORDER BY data->>'TestField'" (Query.orderBy [ Field.Named "TestField" ] PostgreSQL) + " ORDER BY data->>'TestField'" "Order By not constructed correctly" } test "succeeds for SQLite with one field and no direction" { Expect.equal - " ORDER BY data->>'TestField'" (Query.orderBy [ Field.Named "TestField" ] SQLite) + " ORDER BY data->>'TestField'" "Order By not constructed correctly" } test "succeeds for PostgreSQL with multiple fields and direction" { Expect.equal - " ORDER BY data#>>'{Nested,Test,Field}' DESC, data->>'AnotherField', data->>'It' DESC" (Query.orderBy [ Field.Named "Nested.Test.Field DESC"; Field.Named "AnotherField"; Field.Named "It DESC" ] PostgreSQL) + " ORDER BY data#>>'{Nested,Test,Field}' DESC, data->>'AnotherField', data->>'It' DESC" "Order By not constructed correctly" } test "succeeds for SQLite with multiple fields and direction" { Expect.equal - " ORDER BY data->>'Nested'->>'Test'->>'Field' DESC, data->>'AnotherField', data->>'It' DESC" (Query.orderBy [ Field.Named "Nested.Test.Field DESC"; Field.Named "AnotherField"; Field.Named "It DESC" ] SQLite) + " ORDER BY data->>'Nested'->>'Test'->>'Field' DESC, data->>'AnotherField', data->>'It' DESC" "Order By not constructed correctly" } + test "succeeds for PostgreSQL numeric fields" { + Expect.equal + (Query.orderBy [ Field.Named "n:Test" ] PostgreSQL) + " ORDER BY (data->>'Test')::numeric" + "Order By not constructed correctly for numeric field" + } + test "succeeds for SQLite numeric fields" { + Expect.equal + (Query.orderBy [ Field.Named "n:Test" ] SQLite) + " ORDER BY data->>'Test'" + "Order By not constructed correctly for numeric field" + } ] ] ] diff --git a/src/Tests/SqliteExtensionTests.fs b/src/Tests/SqliteExtensionTests.fs index 9fd5bad..51d4f39 100644 --- a/src/Tests/SqliteExtensionTests.fs +++ b/src/Tests/SqliteExtensionTests.fs @@ -8,8 +8,6 @@ open Expecto open Microsoft.Data.Sqlite open Types -#nowarn "0044" - /// Integration tests for the F# extensions on the SqliteConnection data type let integrationTests = let loadDocs () = backgroundTask { @@ -115,12 +113,12 @@ let integrationTests = let! theCount = conn.countAll SqliteDb.TableName Expect.equal theCount 5L "There should have been 5 matching documents" } - testTask "countByField succeeds" { + testTask "countByFields succeeds" { use! db = SqliteDb.BuildDb() use conn = Configuration.dbConn () do! loadDocs () - let! theCount = conn.countByField SqliteDb.TableName (Field.EQ "Value" "purple") + let! theCount = conn.countByFields SqliteDb.TableName Any [ Field.EQ "Value" "purple" ] Expect.equal theCount 2L "There should have been 2 matching documents" } testList "existsById" [ @@ -141,13 +139,13 @@ let integrationTests = Expect.isFalse exists "There should not have been an existing document" } ] - testList "existsByField" [ + testList "existsByFields" [ testTask "succeeds when documents exist" { use! db = SqliteDb.BuildDb() use conn = Configuration.dbConn () do! loadDocs () - let! exists = conn.existsByField SqliteDb.TableName (Field.EQ "NumValue" 10) + let! exists = conn.existsByFields SqliteDb.TableName Any [ Field.EQ "NumValue" 10 ] Expect.isTrue exists "There should have been existing documents" } testTask "succeeds when no matching documents exist" { @@ -155,7 +153,7 @@ let integrationTests = use conn = Configuration.dbConn () do! loadDocs () - let! exists = conn.existsByField SqliteDb.TableName (Field.EQ "Nothing" "none") + let! exists = conn.existsByFields SqliteDb.TableName Any [ Field.EQ "Nothing" "none" ] Expect.isFalse exists "There should not have been any existing documents" } ] @@ -183,6 +181,44 @@ let integrationTests = Expect.equal results [] "There should have been no documents returned" } ] + testList "findAllOrdered" [ + testTask "succeeds when ordering numerically" { + use! db = SqliteDb.BuildDb() + use conn = Configuration.dbConn () + do! loadDocs () + + let! results = conn.findAllOrdered SqliteDb.TableName [ Field.Named "n:NumValue" ] + Expect.hasLength results 5 "There should have been 5 documents returned" + Expect.equal + (results |> List.map _.Id |> String.concat "|") + "one|three|two|four|five" + "The documents were not ordered correctly" + } + testTask "succeeds when ordering numerically descending" { + use! db = SqliteDb.BuildDb() + use conn = Configuration.dbConn () + do! loadDocs () + + let! results = conn.findAllOrdered SqliteDb.TableName [ Field.Named "n:NumValue DESC" ] + Expect.hasLength results 5 "There should have been 5 documents returned" + Expect.equal + (results |> List.map _.Id |> String.concat "|") + "five|four|two|three|one" + "The documents were not ordered correctly" + } + testTask "succeeds when ordering alphabetically" { + use! db = SqliteDb.BuildDb() + use conn = Configuration.dbConn () + do! loadDocs () + + let! results = conn.findAllOrdered SqliteDb.TableName [ Field.Named "Id DESC" ] + Expect.hasLength results 5 "There should have been 5 documents returned" + Expect.equal + (results |> List.map _.Id |> String.concat "|") + "two|three|one|four|five" + "The documents were not ordered correctly" + } + ] testList "findById" [ testTask "succeeds when a document is found" { use! db = SqliteDb.BuildDb() @@ -190,7 +226,7 @@ let integrationTests = do! loadDocs () let! doc = conn.findById SqliteDb.TableName "two" - Expect.isTrue (Option.isSome doc) "There should have been a document returned" + Expect.isSome doc "There should have been a document returned" Expect.equal doc.Value.Id "two" "The incorrect document was returned" } testTask "succeeds when a document is not found" { @@ -199,35 +235,59 @@ let integrationTests = do! loadDocs () let! doc = conn.findById SqliteDb.TableName "three hundred eighty-seven" - Expect.isFalse (Option.isSome doc) "There should not have been a document returned" + Expect.isNone doc "There should not have been a document returned" } ] - testList "findByField" [ + testList "findByFields" [ testTask "succeeds when documents are found" { use! db = SqliteDb.BuildDb() use conn = Configuration.dbConn () do! loadDocs () - let! docs = conn.findByField SqliteDb.TableName (Field.EQ "Sub.Foo" "green") - Expect.equal (List.length docs) 2 "There should have been two documents returned" + let! docs = conn.findByFields SqliteDb.TableName Any [ Field.EQ "Sub.Foo" "green" ] + Expect.hasLength docs 2 "There should have been two documents returned" } testTask "succeeds when documents are not found" { use! db = SqliteDb.BuildDb() use conn = Configuration.dbConn () do! loadDocs () - let! docs = conn.findByField SqliteDb.TableName (Field.EQ "Value" "mauve") - Expect.isTrue (List.isEmpty docs) "There should have been no documents returned" + let! docs = conn.findByFields SqliteDb.TableName Any [ Field.EQ "Value" "mauve" ] + Expect.isEmpty docs "There should have been no documents returned" } ] - testList "findFirstByField" [ + testList "findByFieldsOrdered" [ + testTask "succeeds when sorting ascending" { + use! db = SqliteDb.BuildDb() + use conn = Configuration.dbConn () + do! loadDocs () + + let! docs = + conn.findByFieldsOrdered + SqliteDb.TableName Any [ Field.GT "NumValue" 15 ] [ Field.Named "Id" ] + Expect.equal + (docs |> List.map _.Id |> String.concat "|") "five|four" "The documents were not ordered correctly" + } + testTask "succeeds when sorting descending" { + use! db = SqliteDb.BuildDb() + use conn = Configuration.dbConn () + do! loadDocs () + + let! docs = + conn.findByFieldsOrdered + SqliteDb.TableName Any [ Field.GT "NumValue" 15 ] [ Field.Named "Id DESC" ] + Expect.equal + (docs |> List.map _.Id |> String.concat "|") "four|five" "The documents were not ordered correctly" + } + ] + testList "findFirstByFields" [ testTask "succeeds when a document is found" { use! db = SqliteDb.BuildDb() use conn = Configuration.dbConn () do! loadDocs () - let! doc = conn.findFirstByField SqliteDb.TableName (Field.EQ "Value" "another") - Expect.isTrue (Option.isSome doc) "There should have been a document returned" + let! doc = conn.findFirstByFields SqliteDb.TableName Any [ Field.EQ "Value" "another" ] + Expect.isSome doc "There should have been a document returned" Expect.equal doc.Value.Id "two" "The incorrect document was returned" } testTask "succeeds when multiple documents are found" { @@ -235,8 +295,8 @@ let integrationTests = use conn = Configuration.dbConn () do! loadDocs () - let! doc = conn.findFirstByField SqliteDb.TableName (Field.EQ "Sub.Foo" "green") - Expect.isTrue (Option.isSome doc) "There should have been a document returned" + let! doc = conn.findFirstByFields SqliteDb.TableName Any [ Field.EQ "Sub.Foo" "green" ] + Expect.isSome doc "There should have been a document returned" Expect.contains [ "two"; "four" ] doc.Value.Id "An incorrect document was returned" } testTask "succeeds when a document is not found" { @@ -244,8 +304,32 @@ let integrationTests = use conn = Configuration.dbConn () do! loadDocs () - let! doc = conn.findFirstByField SqliteDb.TableName (Field.EQ "Value" "absent") - Expect.isFalse (Option.isSome doc) "There should not have been a document returned" + let! doc = conn.findFirstByFields SqliteDb.TableName Any [ Field.EQ "Value" "absent" ] + Expect.isNone doc "There should not have been a document returned" + } + ] + testList "findFirstByFieldsOrdered" [ + testTask "succeeds when sorting ascending" { + use! db = SqliteDb.BuildDb() + use conn = Configuration.dbConn () + do! loadDocs () + + let! doc = + conn.findFirstByFieldsOrdered + SqliteDb.TableName Any [ Field.EQ "Sub.Foo" "green" ] [ Field.Named "Sub.Bar" ] + Expect.isSome doc "There should have been a document returned" + Expect.equal "two" doc.Value.Id "An incorrect document was returned" + } + testTask "succeeds when sorting descending" { + use! db = SqliteDb.BuildDb() + use conn = Configuration.dbConn () + do! loadDocs () + + let! doc = + conn.findFirstByFieldsOrdered + SqliteDb.TableName Any [ Field.EQ "Sub.Foo" "green" ] [ Field.Named "Sub.Bar DESC" ] + Expect.isSome doc "There should have been a document returned" + Expect.equal "four" doc.Value.Id "An incorrect document was returned" } ] testList "updateById" [ @@ -326,14 +410,14 @@ let integrationTests = do! conn.patchById SqliteDb.TableName "test" {| Foo = "green" |} } ] - testList "patchByField" [ + testList "patchByFields" [ testTask "succeeds when a document is updated" { use! db = SqliteDb.BuildDb() use conn = Configuration.dbConn () do! loadDocs () - do! conn.patchByField SqliteDb.TableName (Field.EQ "Value" "purple") {| NumValue = 77 |} - let! after = conn.countByField SqliteDb.TableName (Field.EQ "NumValue" 77) + do! conn.patchByFields SqliteDb.TableName Any [ Field.EQ "Value" "purple" ] {| NumValue = 77 |} + let! after = conn.countByFields SqliteDb.TableName Any [ Field.EQ "NumValue" 77 ] Expect.equal after 2L "There should have been 2 documents returned" } testTask "succeeds when no document is updated" { @@ -344,7 +428,7 @@ let integrationTests = Expect.isEmpty before "There should have been no documents returned" // This not raising an exception is the test - do! conn.patchByField SqliteDb.TableName (Field.EQ "Value" "burgundy") {| Foo = "green" |} + do! conn.patchByFields SqliteDb.TableName Any [ Field.EQ "Value" "burgundy" ] {| Foo = "green" |} } ] testList "removeFieldsById" [ @@ -377,13 +461,13 @@ let integrationTests = do! conn.removeFieldsById SqliteDb.TableName "two" [ "Value" ] } ] - testList "removeFieldByField" [ + testList "removeFieldByFields" [ testTask "succeeds when a field is removed" { use! db = SqliteDb.BuildDb() use conn = Configuration.dbConn () do! loadDocs () - do! conn.removeFieldsByField SqliteDb.TableName (Field.EQ "NumValue" 17) [ "Sub" ] + do! conn.removeFieldsByFields SqliteDb.TableName Any [ Field.EQ "NumValue" 17 ] [ "Sub" ] try let! _ = conn.findById SqliteDb.TableName "four" Expect.isTrue false "The updated document should have failed to parse" @@ -397,14 +481,14 @@ let integrationTests = do! loadDocs () // This not raising an exception is the test - do! conn.removeFieldsByField SqliteDb.TableName (Field.EQ "NumValue" 17) [ "Nothing" ] + do! conn.removeFieldsByFields SqliteDb.TableName Any [ Field.EQ "NumValue" 17 ] [ "Nothing" ] } testTask "succeeds when no document is matched" { use! db = SqliteDb.BuildDb() use conn = Configuration.dbConn () // This not raising an exception is the test - do! conn.removeFieldsByField SqliteDb.TableName (Field.NE "Abracadabra" "apple") [ "Value" ] + do! conn.removeFieldsByFields SqliteDb.TableName Any [ Field.NE "Abracadabra" "apple" ] [ "Value" ] } ] testList "deleteById" [ @@ -427,13 +511,13 @@ let integrationTests = Expect.equal remaining 5L "There should have been 5 documents remaining" } ] - testList "deleteByField" [ + testList "deleteByFields" [ testTask "succeeds when documents are deleted" { use! db = SqliteDb.BuildDb() use conn = Configuration.dbConn () do! loadDocs () - do! conn.deleteByField SqliteDb.TableName (Field.NE "Value" "purple") + do! conn.deleteByFields SqliteDb.TableName Any [ Field.NE "Value" "purple" ] let! remaining = conn.countAll SqliteDb.TableName Expect.equal remaining 2L "There should have been 2 documents remaining" } @@ -442,7 +526,7 @@ let integrationTests = use conn = Configuration.dbConn () do! loadDocs () - do! conn.deleteByField SqliteDb.TableName (Field.EQ "Value" "crimson") + do! conn.deleteByFields SqliteDb.TableName Any [ Field.EQ "Value" "crimson" ] let! remaining = conn.countAll SqliteDb.TableName Expect.equal remaining 5L "There should have been 5 documents remaining" } @@ -480,8 +564,8 @@ let integrationTests = use conn = Configuration.dbConn () do! loadDocs () - let! docs = conn.customList (Query.selectFromTable SqliteDb.TableName) [] fromData - Expect.hasCountOf docs 5u (fun _ -> true) "There should have been 5 documents returned" + let! docs = conn.customList (Query.find SqliteDb.TableName) [] fromData + Expect.hasLength docs 5 "There should have been 5 documents returned" } testTask "succeeds when data is not found" { use! db = SqliteDb.BuildDb() diff --git a/src/Tests/SqliteTests.fs b/src/Tests/SqliteTests.fs index 1006e25..1754e72 100644 --- a/src/Tests/SqliteTests.fs +++ b/src/Tests/SqliteTests.fs @@ -424,13 +424,48 @@ let findTests = testList "Find" [ Expect.equal results [] "There should have been no documents returned" } ] + testList "allOrdered" [ + testTask "succeeds when ordering numerically" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + let! results = Find.allOrdered SqliteDb.TableName [ Field.Named "n:NumValue" ] + Expect.hasLength results 5 "There should have been 5 documents returned" + Expect.equal + (results |> List.map _.Id |> String.concat "|") + "one|three|two|four|five" + "The documents were not ordered correctly" + } + testTask "succeeds when ordering numerically descending" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + let! results = Find.allOrdered SqliteDb.TableName [ Field.Named "n:NumValue DESC" ] + Expect.hasLength results 5 "There should have been 5 documents returned" + Expect.equal + (results |> List.map _.Id |> String.concat "|") + "five|four|two|three|one" + "The documents were not ordered correctly" + } + testTask "succeeds when ordering alphabetically" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + let! results = Find.allOrdered SqliteDb.TableName [ Field.Named "Id DESC" ] + Expect.hasLength results 5 "There should have been 5 documents returned" + Expect.equal + (results |> List.map _.Id |> String.concat "|") + "two|three|one|four|five" + "The documents were not ordered correctly" + } + ] testList "byId" [ testTask "succeeds when a document is found" { use! db = SqliteDb.BuildDb() do! loadDocs () let! doc = Find.byId SqliteDb.TableName "two" - Expect.isTrue (Option.isSome doc) "There should have been a document returned" + Expect.isSome doc "There should have been a document returned" Expect.equal doc.Value.Id "two" "The incorrect document was returned" } testTask "succeeds when a document is not found" { @@ -438,7 +473,7 @@ let findTests = testList "Find" [ do! loadDocs () let! doc = Find.byId SqliteDb.TableName "three hundred eighty-seven" - Expect.isFalse (Option.isSome doc) "There should not have been a document returned" + Expect.isNone doc "There should not have been a document returned" } ] testList "byFields" [ @@ -457,13 +492,35 @@ let findTests = testList "Find" [ Expect.isTrue (List.isEmpty docs) "There should have been no documents returned" } ] + testList "byFieldsOrdered" [ + testTask "succeeds when sorting ascending" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + let! docs = + Find.byFieldsOrdered + SqliteDb.TableName Any [ Field.GT "NumValue" 15 ] [ Field.Named "Id" ] + Expect.equal + (docs |> List.map _.Id |> String.concat "|") "five|four" "The documents were not ordered correctly" + } + testTask "succeeds when sorting descending" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + let! docs = + Find.byFieldsOrdered + SqliteDb.TableName Any [ Field.GT "NumValue" 15 ] [ Field.Named "Id DESC" ] + Expect.equal + (docs |> List.map _.Id |> String.concat "|") "four|five" "The documents were not ordered correctly" + } + ] testList "firstByFields" [ testTask "succeeds when a document is found" { use! db = SqliteDb.BuildDb() do! loadDocs () let! doc = Find.firstByFields SqliteDb.TableName Any [ Field.EQ "Value" "another" ] - Expect.isTrue (Option.isSome doc) "There should have been a document returned" + Expect.isSome doc "There should have been a document returned" Expect.equal doc.Value.Id "two" "The incorrect document was returned" } testTask "succeeds when multiple documents are found" { @@ -471,7 +528,7 @@ let findTests = testList "Find" [ do! loadDocs () let! doc = Find.firstByFields SqliteDb.TableName Any [ Field.EQ "Sub.Foo" "green" ] - Expect.isTrue (Option.isSome doc) "There should have been a document returned" + Expect.isSome doc "There should have been a document returned" Expect.contains [ "two"; "four" ] doc.Value.Id "An incorrect document was returned" } testTask "succeeds when a document is not found" { @@ -479,7 +536,29 @@ let findTests = testList "Find" [ do! loadDocs () let! doc = Find.firstByFields SqliteDb.TableName Any [ Field.EQ "Value" "absent" ] - Expect.isFalse (Option.isSome doc) "There should not have been a document returned" + Expect.isNone doc "There should not have been a document returned" + } + ] + testList "firstByFieldsOrdered" [ + testTask "succeeds when sorting ascending" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + let! doc = + Find.firstByFieldsOrdered + SqliteDb.TableName Any [ Field.EQ "Sub.Foo" "green" ] [ Field.Named "Sub.Bar" ] + Expect.isSome doc "There should have been a document returned" + Expect.equal "two" doc.Value.Id "An incorrect document was returned" + } + testTask "succeeds when sorting descending" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + let! doc = + Find.firstByFieldsOrdered + SqliteDb.TableName Any [ Field.EQ "Sub.Foo" "green" ] [ Field.Named "Sub.Bar DESC" ] + Expect.isSome doc "There should have been a document returned" + Expect.equal "four" doc.Value.Id "An incorrect document was returned" } ] ]