From 2daa347e77f565fb7ea0acd602f9556a23cd82cc Mon Sep 17 00:00:00 2001 From: "Daniel J. Summers" Date: Tue, 23 Jan 2024 19:18:02 -0500 Subject: [PATCH] RemoveField -> RemoveFields Implemented for all --- src/Postgres/Extensions.fs | 36 ++++ src/Postgres/Library.fs | 175 ++++++++++++++-- src/Sqlite/Extensions.fs | 22 +- src/Sqlite/Library.fs | 141 ++++++++----- .../PostgresCSharpExtensionTests.cs | 177 ++++++++++++++++ src/Tests.CSharp/PostgresCSharpTests.cs | 198 +++++++++++++++++- .../SqliteCSharpExtensionTests.cs | 19 +- src/Tests.CSharp/SqliteCSharpTests.cs | 37 ++-- src/Tests/PostgresExtensionTests.fs | 156 ++++++++++++++ src/Tests/PostgresTests.fs | 172 ++++++++++++++- src/Tests/SqliteExtensionTests.fs | 16 +- src/Tests/SqliteTests.fs | 31 +-- 12 files changed, 1049 insertions(+), 131 deletions(-) diff --git a/src/Postgres/Extensions.fs b/src/Postgres/Extensions.fs index 9b89b84..c2ae2e5 100644 --- a/src/Postgres/Extensions.fs +++ b/src/Postgres/Extensions.fs @@ -133,6 +133,22 @@ module Extensions = member conn.patchByJsonPath tableName jsonPath (patch: 'TPatch) = WithProps.Patch.byJsonPath tableName jsonPath patch (Sql.existingConnection conn) + /// Remove fields from a document by the document's ID + member conn.removeFieldsById tableName (docId: 'TKey) fieldNames = + WithProps.RemoveFields.byId tableName docId fieldNames (Sql.existingConnection conn) + + /// Remove fields from documents via a comparison on a JSON field in the document + member conn.removeFieldsByField tableName field fieldNames = + WithProps.RemoveFields.byField tableName field fieldNames (Sql.existingConnection conn) + + /// Remove fields from documents via a JSON containment query (@>) + member conn.removeFieldsByContains tableName (criteria: 'TContains) fieldNames = + WithProps.RemoveFields.byContains tableName criteria fieldNames (Sql.existingConnection conn) + + /// Remove fields from documents via a JSON Path match query (@?) + member conn.removeFieldsByJsonPath tableName jsonPath fieldNames = + WithProps.RemoveFields.byJsonPath tableName jsonPath fieldNames (Sql.existingConnection conn) + /// Delete a document by its ID member conn.deleteById tableName (docId: 'TKey) = WithProps.Delete.byId tableName docId (Sql.existingConnection conn) @@ -312,6 +328,26 @@ type NpgsqlConnectionCSharpExtensions = static member inline PatchByJsonPath(conn, tableName, jsonPath, patch: 'TPatch) = WithProps.Patch.byJsonPath tableName jsonPath patch (Sql.existingConnection conn) + /// Remove fields from a document by the document's ID + [] + static member inline RemoveFieldsById(conn, tableName, docId: 'TKey, fieldNames) = + WithProps.RemoveFields.ById(tableName, docId, fieldNames, Sql.existingConnection conn) + + /// Remove fields from documents via a comparison on a JSON field in the document + [] + static member inline RemoveFieldsByField(conn, tableName, field, fieldNames) = + WithProps.RemoveFields.ByField(tableName, field, fieldNames, Sql.existingConnection conn) + + /// Remove fields from documents via a JSON containment query (@>) + [] + static member inline RemoveFieldsByContains(conn, tableName, criteria: 'TContains, fieldNames) = + WithProps.RemoveFields.ByContains(tableName, criteria, fieldNames, Sql.existingConnection conn) + + /// Remove fields from documents via a JSON Path match query (@?) + [] + static member inline RemoveFieldsByJsonPath(conn, tableName, jsonPath, fieldNames) = + WithProps.RemoveFields.ByJsonPath(tableName, jsonPath, fieldNames, Sql.existingConnection conn) + /// Delete a document by its ID [] static member inline DeleteById(conn, tableName, docId: 'TKey) = diff --git a/src/Postgres/Library.fs b/src/Postgres/Library.fs index bb496ee..1351af8 100644 --- a/src/Postgres/Library.fs +++ b/src/Postgres/Library.fs @@ -65,18 +65,28 @@ module Parameters = /// Create a JSON field parameter (name "@field") [] - let addFieldParam field parameters = + let addFieldParam name field parameters = match field.Op with | EX | NEX -> parameters - | _ -> ("@field", Sql.parameter (NpgsqlParameter("@field", field.Value))) :: parameters + | _ -> (name, Sql.parameter (NpgsqlParameter(name, field.Value))) :: parameters /// Create a JSON field parameter (name "@field") - let AddField field parameters = + let AddField name field parameters = match field.Op with | EX | NEX -> parameters - | _ -> - ("@field", Sql.parameter (NpgsqlParameter("@field", field.Value))) |> Seq.singleton |> Seq.append parameters + | _ -> (name, Sql.parameter (NpgsqlParameter(name, field.Value))) |> Seq.singleton |> Seq.append parameters + /// Append JSON field name parameters for the given field names to the given parameters + [] + let fieldNameParam (fieldNames: string list) = + if fieldNames.Length = 1 then "@name", Sql.string fieldNames[0] + else "@name", Sql.stringArray (Array.ofList fieldNames) + + /// Append JSON field name parameters for the given field names to the given parameters + let FieldName(fieldNames: string seq) = + if Seq.isEmpty fieldNames then "@name", Sql.string (Seq.head fieldNames) + else "@name", Sql.stringArray (Array.ofSeq fieldNames) + /// An empty parameter sequence [] let noParams = @@ -154,25 +164,56 @@ module Query = /// Queries to patch (partially update) documents module Patch = + /// Create an UPDATE statement to patch documents + let private update tableName whereClause = + $"UPDATE %s{tableName} SET data = data || @data WHERE {whereClause}" + /// Query to patch a document by its ID [] let byId tableName = - $"""UPDATE %s{tableName} SET data = data || @data WHERE {Query.whereById "@id"}""" + Query.whereById "@id" |> update tableName /// Query to patch documents match a JSON field comparison (->> =) [] let byField tableName field = - $"""UPDATE %s{tableName} SET data = data || @data WHERE {Query.whereByField field "@field"}""" + Query.whereByField field "@field" |> update tableName /// Query to patch documents matching a JSON containment query (@>) [] let byContains tableName = - $"""UPDATE %s{tableName} SET data = data || @data WHERE {whereDataContains "@criteria"}""" + whereDataContains "@criteria" |> update tableName /// Query to patch documents matching a JSON containment query (@>) [] let byJsonPath tableName = - $"""UPDATE %s{tableName} SET data = data || @data WHERE {whereJsonPathMatches "@path"}""" + whereJsonPathMatches "@path" |> update tableName + + /// Queries to remove fields from documents + module RemoveFields = + + /// Create an UPDATE statement to remove parameters + let private update tableName whereClause = + $"UPDATE %s{tableName} SET data = data - @name WHERE {whereClause}" + + /// Query to remove fields from a document by the document's ID + [] + let byId tableName = + Query.whereById "@id" |> update tableName + + /// Query to remove fields from documents via a comparison on a JSON field within the document + [] + let byField tableName field = + Query.whereByField field "@field" |> update tableName + + /// Query to patch documents matching a JSON containment query (@>) + [] + let byContains tableName = + whereDataContains "@criteria" |> update tableName + + /// Query to patch documents matching a JSON containment query (@>) + [] + let byJsonPath tableName = + whereJsonPathMatches "@path" |> update tableName /// Queries to delete documents module Delete = @@ -312,7 +353,7 @@ module WithProps = /// Count matching documents using a JSON field comparison (->> =) [] let byField tableName field sqlProps = - Custom.scalar (Query.Count.byField tableName field) (addFieldParam field []) toCount sqlProps + Custom.scalar (Query.Count.byField tableName field) (addFieldParam "@field" field []) toCount sqlProps /// Count matching documents using a JSON containment query (@>) [] @@ -336,7 +377,7 @@ module WithProps = /// Determine if a document exists using a JSON field comparison (->> =) [] let byField tableName field sqlProps = - Custom.scalar (Query.Exists.byField tableName field) (addFieldParam field []) toExists sqlProps + Custom.scalar (Query.Exists.byField tableName field) (addFieldParam "@field" field []) toExists sqlProps /// Determine if a document exists using a JSON containment query (@>) [] @@ -373,11 +414,13 @@ module WithProps = /// Retrieve documents matching a JSON field comparison (->> =) [] let byField<'TDoc> tableName field sqlProps = - Custom.list<'TDoc> (Query.Find.byField tableName field) (addFieldParam field []) fromData<'TDoc> sqlProps + Custom.list<'TDoc> + (Query.Find.byField tableName field) (addFieldParam "@field" field []) fromData<'TDoc> sqlProps /// Retrieve documents matching a JSON field comparison (->> =) let ByField<'TDoc>(tableName, field, sqlProps) = - Custom.List<'TDoc>(Query.Find.byField tableName field, addFieldParam field [], fromData<'TDoc>, sqlProps) + Custom.List<'TDoc>( + Query.Find.byField tableName field, addFieldParam "@field" field [], fromData<'TDoc>, sqlProps) /// Retrieve documents matching a JSON containment query (@>) [] @@ -405,12 +448,18 @@ module WithProps = [] let firstByField<'TDoc> tableName field sqlProps = Custom.single<'TDoc> - $"{Query.Find.byField tableName field} LIMIT 1" (addFieldParam field []) fromData<'TDoc> sqlProps + $"{Query.Find.byField tableName field} LIMIT 1" + (addFieldParam "@field" field []) + fromData<'TDoc> + sqlProps /// Retrieve the first document matching a JSON field comparison (->> =); returns null if not found let FirstByField<'TDoc when 'TDoc: null>(tableName, field, sqlProps) = Custom.Single<'TDoc>( - $"{Query.Find.byField tableName field} LIMIT 1", addFieldParam field [], fromData<'TDoc>, sqlProps) + $"{Query.Find.byField tableName field} LIMIT 1", + addFieldParam "@field" field [], + fromData<'TDoc>, + sqlProps) /// Retrieve the first document matching a JSON containment query (@>); returns None if not found [] @@ -471,7 +520,9 @@ module WithProps = [] let byField tableName field (patch: 'TPatch) sqlProps = Custom.nonQuery - (Query.Patch.byField tableName field) (addFieldParam field [ jsonParam "@data" patch ]) sqlProps + (Query.Patch.byField tableName field) + (addFieldParam "@field" field [ jsonParam "@data" patch ]) + sqlProps /// Patch documents using a JSON containment query in the WHERE clause (@>) [] @@ -485,6 +536,55 @@ module WithProps = Custom.nonQuery (Query.Patch.byJsonPath tableName) [ jsonParam "@data" patch; "@path", Sql.string jsonPath ] sqlProps + /// Commands to remove fields from documents + [] + module RemoveFields = + + /// Remove fields from a document by the document's ID + [] + let byId tableName (docId: 'TKey) fieldNames sqlProps = + Custom.nonQuery (Query.RemoveFields.byId tableName) [ idParam docId; fieldNameParam fieldNames ] sqlProps + + /// Remove fields from a document by the document's ID + let ById(tableName, docId: 'TKey, fieldNames, sqlProps) = + byId tableName docId (List.ofSeq fieldNames) sqlProps + + /// Remove fields from documents via a comparison on a JSON field in the document + [] + let byField tableName field fieldNames sqlProps = + Custom.nonQuery + (Query.RemoveFields.byField tableName field) + (addFieldParam "@field" field [ fieldNameParam fieldNames ]) + sqlProps + + /// Remove fields from documents via a comparison on a JSON field in the document + let ByField(tableName, field, fieldNames, sqlProps) = + byField tableName field (List.ofSeq fieldNames) sqlProps + + /// Remove fields from documents via a JSON containment query (@>) + [] + let byContains tableName (criteria: 'TContains) fieldNames sqlProps = + Custom.nonQuery + (Query.RemoveFields.byContains tableName) + [ jsonParam "@criteria" criteria; fieldNameParam fieldNames ] + sqlProps + + /// Remove fields from documents via a JSON containment query (@>) + let ByContains(tableName, criteria: 'TContains, fieldNames, sqlProps) = + byContains tableName criteria (List.ofSeq fieldNames) sqlProps + + /// Remove fields from documents via a JSON Path match query (@?) + [] + let byJsonPath tableName jsonPath fieldNames sqlProps = + Custom.nonQuery + (Query.RemoveFields.byJsonPath tableName) + [ "@path", Sql.string jsonPath; fieldNameParam fieldNames ] + sqlProps + + /// Remove fields from documents via a JSON Path match query (@?) + let ByJsonPath(tableName, jsonPath, fieldNames, sqlProps) = + byJsonPath tableName jsonPath (List.ofSeq fieldNames) sqlProps + /// Commands to delete documents [] module Delete = @@ -497,7 +597,7 @@ module WithProps = /// Delete documents by matching a JSON field comparison query (->> =) [] let byField tableName field sqlProps = - Custom.nonQuery (Query.Delete.byField tableName field) (addFieldParam field []) sqlProps + Custom.nonQuery (Query.Delete.byField tableName field) (addFieldParam "@field" field []) sqlProps /// Delete documents by matching a JSON contains query (@>) [] @@ -753,6 +853,47 @@ module Patch = WithProps.Patch.byJsonPath tableName jsonPath patch (fromDataSource ()) +/// Commands to remove fields from documents +[] +module RemoveFields = + + /// Remove fields from a document by the document's ID + [] + let byId tableName (docId: 'TKey) fieldNames = + WithProps.RemoveFields.byId tableName docId fieldNames (fromDataSource ()) + + /// Remove fields from a document by the document's ID + let ById(tableName, docId: 'TKey, fieldNames) = + WithProps.RemoveFields.ById(tableName, docId, fieldNames, fromDataSource ()) + + /// Remove fields from documents via a comparison on a JSON field in the document + [] + let byField tableName field fieldNames = + WithProps.RemoveFields.byField tableName field fieldNames (fromDataSource ()) + + /// Remove fields from documents via a comparison on a JSON field in the document + let ByField(tableName, field, fieldNames) = + WithProps.RemoveFields.ByField(tableName, field, fieldNames, fromDataSource ()) + + /// Remove fields from documents via a JSON containment query (@>) + [] + let byContains tableName (criteria: 'TContains) fieldNames = + WithProps.RemoveFields.byContains tableName criteria fieldNames (fromDataSource ()) + + /// Remove fields from documents via a JSON containment query (@>) + let ByContains(tableName, criteria: 'TContains, fieldNames) = + WithProps.RemoveFields.ByContains(tableName, criteria, fieldNames, fromDataSource ()) + + /// Remove fields from documents via a JSON Path match query (@?) + [] + let byJsonPath tableName jsonPath fieldNames = + WithProps.RemoveFields.byJsonPath tableName jsonPath fieldNames (fromDataSource ()) + + /// Remove fields from documents via a JSON Path match query (@?) + let ByJsonPath(tableName, jsonPath, fieldNames) = + WithProps.RemoveFields.ByJsonPath(tableName, jsonPath, fieldNames, fromDataSource ()) + + /// Commands to delete documents [] module Delete = diff --git a/src/Sqlite/Extensions.fs b/src/Sqlite/Extensions.fs index 3416614..7ad8888 100644 --- a/src/Sqlite/Extensions.fs +++ b/src/Sqlite/Extensions.fs @@ -88,13 +88,13 @@ module Extensions = member conn.patchByField tableName field (patch: 'TPatch) = WithConn.Patch.byField tableName field patch conn - /// Remove a field from a document by the document's ID - member conn.removeFieldById tableName (docId: 'TKey) fieldName = - WithConn.RemoveField.byId tableName docId fieldName conn + /// Remove fields from a document by the document's ID + member conn.removeFieldsById tableName (docId: 'TKey) fieldNames = + WithConn.RemoveFields.byId tableName docId fieldNames conn /// Remove a field from a document via a comparison on a JSON field in the document - member conn.removeFieldByField tableName field fieldName = - WithConn.RemoveField.byField tableName field fieldName conn + member conn.removeFieldsByField tableName field fieldNames = + WithConn.RemoveFields.byField tableName field fieldNames conn /// Delete a document by its ID member conn.deleteById tableName (docId: 'TKey) = @@ -212,15 +212,15 @@ type SqliteConnectionCSharpExtensions = static member inline PatchByField<'TPatch>(conn, tableName, field, patch: 'TPatch) = WithConn.Patch.byField tableName field patch conn - /// Remove a field from a document by the document's ID + /// Remove fields from a document by the document's ID [] - static member inline RemoveFieldById<'TKey>(conn, tableName, docId: 'TKey, fieldName) = - WithConn.RemoveField.byId tableName docId fieldName conn + static member inline RemoveFieldsById<'TKey>(conn, tableName, docId: 'TKey, fieldNames) = + WithConn.RemoveFields.ById(tableName, docId, fieldNames, conn) - /// Remove a field from a document via a comparison on a JSON field in the document + /// Remove fields from documents via a comparison on a JSON field in the document [] - static member inline RemoveFieldByField(conn, tableName, field, fieldName) = - WithConn.RemoveField.byField tableName field fieldName conn + static member inline RemoveFieldsByField(conn, tableName, field, fieldNames) = + WithConn.RemoveFields.ByField(tableName, field, fieldNames, conn) /// Delete a document by its ID [] diff --git a/src/Sqlite/Library.fs b/src/Sqlite/Library.fs index 12a72e8..8e7cdb7 100644 --- a/src/Sqlite/Library.fs +++ b/src/Sqlite/Library.fs @@ -42,30 +42,45 @@ module Query = /// Document patching (partial update) queries module Patch = + /// Create an UPDATE statement to patch documents + let internal update tableName whereClause = + $"UPDATE %s{tableName} SET data = json_patch(data, json(@data)) WHERE %s{whereClause}" + /// Query to patch (partially update) a document by its ID [] let byId tableName = - $"""UPDATE %s{tableName} SET data = json_patch(data, json(@data)) WHERE {Query.whereById "@id"}""" + Query.whereById "@id" |> update tableName /// Query to patch (partially update) a document via a comparison on a JSON field [] let byField tableName field = - sprintf - "UPDATE %s SET data = json_patch(data, json(@data)) WHERE %s" - tableName (Query.whereByField field "@field") + Query.whereByField field "@field" |> update tableName - /// Queries to remove a field from a document - module RemoveField = + /// Queries to remove fields from documents + module RemoveFields = - /// Query to remove a field from a document by the document's ID - [] - let byId tableName = - $"""UPDATE %s{tableName} SET data = json_remove(data, @name) WHERE {Query.whereById "@id"}""" + /// Create an UPDATE statement to remove parameters + let internal update tableName (parameters: SqliteParameter list) whereClause = + let paramNames = parameters |> List.map _.ParameterName |> String.concat ", " + $"UPDATE %s{tableName} SET data = json_remove(data, {paramNames}) WHERE {whereClause}" + + /// Query to remove fields from a document by the document's ID + [] + let byId tableName parameters = + Query.whereById "@id" |> update tableName parameters - /// Query to remove a field from a document via a comparison on a JSON field within the document - [] - let byField tableName field = - $"""UPDATE %s{tableName} SET data = json_remove(data, @name) WHERE {Query.whereByField field "@field"}""" + /// Query to remove fields from a document by the document's ID + let ById(tableName, parameters) = + byId tableName (List.ofSeq parameters) + + /// Query to remove fields from documents via a comparison on a JSON field within the document + [] + let byField tableName field parameters = + Query.whereByField field "@field" |> update tableName parameters + + /// Query to remove fields from documents via a comparison on a JSON field within the document + let ByField(tableName, field, parameters) = + byField tableName field (List.ofSeq parameters) /// Parameter handling helpers @@ -84,21 +99,23 @@ module Parameters = /// Create a JSON field parameter (name "@field") [] - let addFieldParam field parameters = - match field.Op with - | EX | NEX -> parameters - | _ -> SqliteParameter("@field", field.Value) :: parameters + let addFieldParam name field parameters = + match field.Op with EX | NEX -> parameters | _ -> SqliteParameter(name, field.Value) :: parameters /// Create a JSON field parameter (name "@field") - let AddField field parameters = + let AddField(name, field, parameters) = match field.Op with | EX | NEX -> parameters - | _ -> SqliteParameter("@field", field.Value) |> Seq.singleton |> Seq.append parameters + | _ -> SqliteParameter(name, field.Value) |> Seq.singleton |> Seq.append parameters - /// Create a JSON field name parameter (name "@name") - [] - let fieldNameParam name = - SqliteParameter("@name", $"$.%s{name}") + /// Append JSON field name parameters for the given field names to the given parameters + [] + let fieldNameParams paramName (fieldNames: string list) = + fieldNames |> List.mapi (fun idx name -> SqliteParameter($"%s{paramName}{idx}", $"$.{name}")) + + /// Append JSON field name parameters for the given field names to the given parameters + let FieldNames(paramName, fieldNames: string seq) = + fieldNames |> Seq.mapi (fun idx name -> SqliteParameter($"%s{paramName}{idx}", $"$.{name}")) /// An empty parameter sequence [] @@ -250,7 +267,7 @@ module WithConn = /// Count matching documents using a comparison on a JSON field [] let byField tableName field conn = - Custom.scalar (Query.Count.byField tableName field) (addFieldParam field []) toCount conn + Custom.scalar (Query.Count.byField tableName field) (addFieldParam "@field" field []) toCount conn /// Commands to determine if documents exist [] @@ -264,7 +281,7 @@ module WithConn = /// Determine if a document exists using a comparison on a JSON field [] let byField tableName field conn = - Custom.scalar (Query.Exists.byField tableName field) (addFieldParam field []) toExists conn + Custom.scalar (Query.Exists.byField tableName field) (addFieldParam "@field" field []) toExists conn /// Commands to retrieve documents [] @@ -291,21 +308,24 @@ module WithConn = /// Retrieve documents via a comparison on a JSON field [] let byField<'TDoc> tableName field conn = - Custom.list<'TDoc> (Query.Find.byField tableName field) (addFieldParam field []) fromData<'TDoc> conn + Custom.list<'TDoc> + (Query.Find.byField tableName field) (addFieldParam "@field" field []) fromData<'TDoc> conn /// Retrieve documents via a comparison on a JSON field let ByField<'TDoc>(tableName, field, conn) = - Custom.List<'TDoc>(Query.Find.byField tableName field, addFieldParam field [], fromData<'TDoc>, conn) + Custom.List<'TDoc>( + Query.Find.byField tableName field, addFieldParam "@field" field [], fromData<'TDoc>, conn) /// Retrieve documents via a comparison on a JSON field, returning only the first result [] let firstByField<'TDoc> tableName field conn = - Custom.single $"{Query.Find.byField tableName field} LIMIT 1" (addFieldParam field []) fromData<'TDoc> conn + Custom.single + $"{Query.Find.byField tableName field} LIMIT 1" (addFieldParam "@field" field []) fromData<'TDoc> conn /// Retrieve documents via a comparison on a JSON field, returning only the first result let FirstByField<'TDoc when 'TDoc: null>(tableName, field, conn) = Custom.Single( - $"{Query.Find.byField tableName field} LIMIT 1", addFieldParam field [], fromData<'TDoc>, conn) + $"{Query.Find.byField tableName field} LIMIT 1", addFieldParam "@field" field [], fromData<'TDoc>, conn) /// Commands to update documents [] @@ -337,23 +357,34 @@ module WithConn = /// Patch documents using a comparison on a JSON field [] let byField tableName field (patch: 'TPatch) (conn: SqliteConnection) = - Custom.nonQuery (Query.Patch.byField tableName field) (addFieldParam field [ jsonParam "@data" patch ]) conn + Custom.nonQuery + (Query.Patch.byField tableName field) (addFieldParam "@field" field [ jsonParam "@data" patch ]) conn /// Commands to remove fields from documents [] - module RemoveField = + module RemoveFields = - /// Remove a field from a document by the document's ID - [] - let byId tableName (docId: 'TKey) fieldName conn = - Custom.nonQuery (Query.RemoveField.byId tableName) [ idParam docId; fieldNameParam fieldName ] conn + /// Remove fields from a document by the document's ID + [] + let byId tableName (docId: 'TKey) fieldNames conn = + let nameParams = fieldNameParams "@name" fieldNames + Custom.nonQuery (Query.RemoveFields.byId tableName nameParams) (idParam docId :: nameParams) conn - /// Remove a field from a document via a comparison on a JSON field in the document - [] - let byField tableName field fieldName conn = + /// Remove fields from a document by the document's ID + let ById(tableName, docId: 'TKey, fieldNames, conn) = + byId tableName docId (List.ofSeq fieldNames) conn + + /// Remove fields from documents via a comparison on a JSON field in the document + [] + let byField tableName field fieldNames conn = + let nameParams = fieldNameParams "@name" fieldNames Custom.nonQuery - (Query.RemoveField.byField tableName field) (addFieldParam field [ fieldNameParam fieldName ]) conn + (Query.RemoveFields.byField tableName field nameParams) (addFieldParam "@field" field nameParams) conn + /// Remove fields from documents via a comparison on a JSON field in the document + let ByField(tableName, field, fieldNames, conn) = + byField tableName field (List.ofSeq fieldNames) conn + /// Commands to delete documents [] module Delete = @@ -366,7 +397,7 @@ module WithConn = /// Delete documents by matching a comparison on a JSON field [] let byField tableName field conn = - Custom.nonQuery (Query.Delete.byField tableName field) (addFieldParam field []) conn + Custom.nonQuery (Query.Delete.byField tableName field) (addFieldParam "@field" field []) conn /// Commands to execute custom SQL queries @@ -563,19 +594,29 @@ module Patch = /// Commands to remove fields from documents [] -module RemoveField = +module RemoveFields = - /// Remove a field from a document by the document's ID - [] - let byId tableName (docId: 'TKey) fieldName = + /// Remove fields from a document by the document's ID + [] + let byId tableName (docId: 'TKey) fieldNames = use conn = Configuration.dbConn () - WithConn.RemoveField.byId tableName docId fieldName conn + WithConn.RemoveFields.byId tableName docId fieldNames conn - /// Remove a field from a document via a comparison on a JSON field in the document - [] - let byField tableName field fieldName = + /// Remove fields from a document by the document's ID + let ById(tableName, docId: 'TKey, fieldNames) = use conn = Configuration.dbConn () - WithConn.RemoveField.byField tableName field fieldName conn + WithConn.RemoveFields.ById(tableName, docId, fieldNames, conn) + + /// Remove field from documents via a comparison on a JSON field in the document + [] + let byField tableName field fieldNames = + use conn = Configuration.dbConn () + WithConn.RemoveFields.byField tableName field fieldNames conn + + /// Remove field from documents via a comparison on a JSON field in the document + let ByField(tableName, field, fieldNames) = + use conn = Configuration.dbConn () + WithConn.RemoveFields.ByField(tableName, field, fieldNames, conn) /// Commands to delete documents [] diff --git a/src/Tests.CSharp/PostgresCSharpExtensionTests.cs b/src/Tests.CSharp/PostgresCSharpExtensionTests.cs index 7dede84..fdfe528 100644 --- a/src/Tests.CSharp/PostgresCSharpExtensionTests.cs +++ b/src/Tests.CSharp/PostgresCSharpExtensionTests.cs @@ -711,6 +711,183 @@ public class PostgresCSharpExtensionTests await conn.PatchByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ < 0)", new { Foo = "green" }); }) }), + TestList("RemoveFieldsById", new[] + { + 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", [ "Sub", "Value" ]); + var updated = await Find.ById(PostgresDb.TableName, "two"); + Expect.isNotNull(updated, "The updated document should have been retrieved"); + Expect.equal(updated.Value, "", "The string value should have been removed"); + Expect.isNull(updated.Sub, "The sub-document should have been removed"); + }), + TestCase("succeeds when a single field is removed", async () => + { + await using var db = PostgresDb.BuildDb(); + await using var conn = MkConn(db); + await LoadDocs(); + + await conn.RemoveFieldsById(PostgresDb.TableName, "two", [ "Sub" ]); + var updated = await Find.ById(PostgresDb.TableName, "two"); + Expect.isNotNull(updated, "The updated document should have been retrieved"); + Expect.notEqual(updated.Value, "", "The string value should not have been removed"); + Expect.isNull(updated.Sub, "The sub-document should have been removed"); + }), + TestCase("succeeds when a field is not removed", async () => + { + await using var db = PostgresDb.BuildDb(); + await using var conn = MkConn(db); + await LoadDocs(); + + // This not raising an exception is the test + await conn.RemoveFieldsById(PostgresDb.TableName, "two", [ "AFieldThatIsNotThere" ]); + }), + TestCase("succeeds when no document is matched", async () => + { + await using var db = PostgresDb.BuildDb(); + await using var conn = MkConn(db); + + // This not raising an exception is the test + await conn.RemoveFieldsById(PostgresDb.TableName, "two", [ "Value" ]); + }) + }), + TestList("RemoveFieldsByField", new[] + { + 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"), [ "Sub", "Value" ]); + var updated = await Find.ById(PostgresDb.TableName, "four"); + Expect.isNotNull(updated, "The updated document should have been retrieved"); + Expect.equal(updated.Value, "", "The string value should have been removed"); + Expect.isNull(updated.Sub, "The sub-document should have been removed"); + }), + TestCase("succeeds when a single field is removed", async () => + { + await using var db = PostgresDb.BuildDb(); + await using var conn = MkConn(db); + await LoadDocs(); + + await conn.RemoveFieldsByField(PostgresDb.TableName, Field.EQ("NumValue", "17"), [ "Sub" ]); + var updated = await Find.ById(PostgresDb.TableName, "four"); + Expect.isNotNull(updated, "The updated document should have been retrieved"); + Expect.notEqual(updated.Value, "", "The string value should not have been removed"); + Expect.isNull(updated.Sub, "The sub-document should have been removed"); + }), + TestCase("succeeds when a field is not removed", async () => + { + await using var db = PostgresDb.BuildDb(); + await using var conn = MkConn(db); + await LoadDocs(); + + // This not raising an exception is the test + await conn.RemoveFieldsByField(PostgresDb.TableName, Field.EQ("NumValue", "17"), [ "Nothing" ]); + }), + TestCase("succeeds when no document is matched", async () => + { + await using var db = PostgresDb.BuildDb(); + await using var conn = MkConn(db); + + // This not raising an exception is the test + await conn.RemoveFieldsByField(PostgresDb.TableName, Field.NE("Abracadabra", "apple"), [ "Value" ]); + }) + }), + TestList("RemoveFieldsByContains", new[] + { + 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 }, [ "Sub", "Value" ]); + var updated = await Find.ById(PostgresDb.TableName, "four"); + Expect.isNotNull(updated, "The updated document should have been retrieved"); + Expect.equal(updated.Value, "", "The string value should have been removed"); + Expect.isNull(updated.Sub, "The sub-document should have been removed"); + }), + TestCase("succeeds when a single field is removed", async () => + { + await using var db = PostgresDb.BuildDb(); + await using var conn = MkConn(db); + await LoadDocs(); + + await conn.RemoveFieldsByContains(PostgresDb.TableName, new { NumValue = 17 }, [ "Sub" ]); + var updated = await Find.ById(PostgresDb.TableName, "four"); + Expect.isNotNull(updated, "The updated document should have been retrieved"); + Expect.notEqual(updated.Value, "", "The string value should not have been removed"); + Expect.isNull(updated.Sub, "The sub-document should have been removed"); + }), + TestCase("succeeds when a field is not removed", async () => + { + await using var db = PostgresDb.BuildDb(); + await using var conn = MkConn(db); + await LoadDocs(); + + // This not raising an exception is the test + await conn.RemoveFieldsByContains(PostgresDb.TableName, new { NumValue = 17 }, [ "Nothing" ]); + }), + TestCase("succeeds when no document is matched", async () => + { + await using var db = PostgresDb.BuildDb(); + await using var conn = MkConn(db); + + // This not raising an exception is the test + await conn.RemoveFieldsByContains(PostgresDb.TableName, new { Abracadabra = "apple" }, [ "Value" ]); + }) + }), + TestList("RemoveFieldsByJsonPath", new[] + { + 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)", [ "Sub", "Value" ]); + var updated = await Find.ById(PostgresDb.TableName, "four"); + Expect.isNotNull(updated, "The updated document should have been retrieved"); + Expect.equal(updated.Value, "", "The string value should have been removed"); + Expect.isNull(updated.Sub, "The sub-document should have been removed"); + }), + TestCase("succeeds when a single field is removed", async () => + { + await using var db = PostgresDb.BuildDb(); + await using var conn = MkConn(db); + await LoadDocs(); + + await conn.RemoveFieldsByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ == 17)", [ "Sub" ]); + var updated = await Find.ById(PostgresDb.TableName, "four"); + Expect.isNotNull(updated, "The updated document should have been retrieved"); + Expect.notEqual(updated.Value, "", "The string value should not have been removed"); + Expect.isNull(updated.Sub, "The sub-document should have been removed"); + }), + TestCase("succeeds when a field is not removed", async () => + { + await using var db = PostgresDb.BuildDb(); + await using var conn = MkConn(db); + await LoadDocs(); + + // This not raising an exception is the test + await conn.RemoveFieldsByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ == 17)", [ "Nothing" ]); + }), + TestCase("succeeds when no document is matched", async () => + { + await using var db = PostgresDb.BuildDb(); + await using var conn = MkConn(db); + + // This not raising an exception is the test + await conn.RemoveFieldsByJsonPath(PostgresDb.TableName, "$.Abracadabra ? (@ == \"apple\")", + [ "Value" ]); + }) + }), TestList("DeleteById", new[] { TestCase("succeeds when a document is deleted", async () => diff --git a/src/Tests.CSharp/PostgresCSharpTests.cs b/src/Tests.CSharp/PostgresCSharpTests.cs index 84a0080..88b69a2 100644 --- a/src/Tests.CSharp/PostgresCSharpTests.cs +++ b/src/Tests.CSharp/PostgresCSharpTests.cs @@ -11,7 +11,7 @@ using static Runner; /// /// C# tests for the PostgreSQL implementation of BitBadger.Documents /// -public class PostgresCSharpTests +public static class PostgresCSharpTests { /// /// Tests which do not hit the database @@ -36,7 +36,8 @@ public class PostgresCSharpTests { TestCase("succeeds when a parameter is added", () => { - var it = Parameters.AddField(Field.EQ("it", "242"), Enumerable.Empty>()) + var it = Parameters + .AddField("@field", Field.EQ("it", "242"), Enumerable.Empty>()) .ToList(); Expect.hasLength(it, 1, "There should have been a parameter added"); Expect.equal(it[0].Item1, "@field", "Field parameter not constructed correctly"); @@ -44,10 +45,37 @@ public class PostgresCSharpTests }), TestCase("succeeds when a parameter is not added", () => { - var it = Parameters.AddField(Field.EX("It"), Enumerable.Empty>()); + var it = Parameters.AddField("@it", Field.EX("It"), Enumerable.Empty>()); Expect.isEmpty(it, "There should not have been any parameters added"); }) }), + TestList("RemoveFields", new[] + { + TestCase("ById succeeds", () => + { + Expect.equal(Postgres.Query.RemoveFields.ById("tbl"), + "UPDATE tbl SET data = data - @name WHERE data ->> 'Id' = @id", + "Remove field by ID query not correct"); + }), + TestCase("ByField succeeds", () => + { + Expect.equal(Postgres.Query.RemoveFields.ByField("tbl", Field.LT("Fly", 0)), + "UPDATE tbl SET data = data - @name WHERE data ->> 'Fly' < @field", + "Remove field by field query not correct"); + }), + TestCase("ByContains succeeds", () => + { + Expect.equal(Postgres.Query.RemoveFields.ByContains("tbl"), + "UPDATE tbl SET data = data - @name WHERE data @> @criteria", + "Remove field by contains query not correct"); + }), + TestCase("ByJsonPath succeeds", () => + { + Expect.equal(Postgres.Query.RemoveFields.ByJsonPath("tbl"), + "UPDATE tbl SET data = data - @name WHERE data @? @path::jsonpath", + "Remove field by JSON path query not correct"); + }) + }), TestCase("None succeeds", () => { Expect.isEmpty(Parameters.None, "The no-params sequence should be empty"); @@ -883,6 +911,170 @@ public class PostgresCSharpTests }) }) }), + TestList("RemoveFields", new[] + { + TestList("ById", new[] + { + TestCase("succeeds when multiple fields are removed", async () => + { + await using var db = PostgresDb.BuildDb(); + await LoadDocs(); + + await RemoveFields.ById(PostgresDb.TableName, "two", [ "Sub", "Value" ]); + var updated = await Find.ById(PostgresDb.TableName, "two"); + Expect.isNotNull(updated, "The updated document should have been retrieved"); + Expect.equal(updated.Value, "", "The string value should have been removed"); + Expect.isNull(updated.Sub, "The sub-document should have been removed"); + }), + TestCase("succeeds when a single field is removed", async () => + { + await using var db = PostgresDb.BuildDb(); + await LoadDocs(); + + await RemoveFields.ById(PostgresDb.TableName, "two", [ "Sub" ]); + var updated = await Find.ById(PostgresDb.TableName, "two"); + Expect.isNotNull(updated, "The updated document should have been retrieved"); + Expect.notEqual(updated.Value, "", "The string value should not have been removed"); + Expect.isNull(updated.Sub, "The sub-document should have been removed"); + }), + TestCase("succeeds when a field is not removed", async () => + { + await using var db = PostgresDb.BuildDb(); + await LoadDocs(); + + // This not raising an exception is the test + await RemoveFields.ById(PostgresDb.TableName, "two", [ "AFieldThatIsNotThere" ]); + }), + TestCase("succeeds when no document is matched", async () => + { + await using var db = PostgresDb.BuildDb(); + + // This not raising an exception is the test + await RemoveFields.ById(PostgresDb.TableName, "two", [ "Value" ]); + }) + }), + TestList("ByField", new[] + { + TestCase("succeeds when multiple fields are removed", async () => + { + await using var db = PostgresDb.BuildDb(); + await LoadDocs(); + + await RemoveFields.ByField(PostgresDb.TableName, Field.EQ("NumValue", "17"), [ "Sub", "Value" ]); + var updated = await Find.ById(PostgresDb.TableName, "four"); + Expect.isNotNull(updated, "The updated document should have been retrieved"); + Expect.equal(updated.Value, "", "The string value should have been removed"); + Expect.isNull(updated.Sub, "The sub-document should have been removed"); + }), + TestCase("succeeds when a single field is removed", async () => + { + await using var db = PostgresDb.BuildDb(); + await LoadDocs(); + + await RemoveFields.ByField(PostgresDb.TableName, Field.EQ("NumValue", "17"), [ "Sub" ]); + var updated = await Find.ById(PostgresDb.TableName, "four"); + Expect.isNotNull(updated, "The updated document should have been retrieved"); + Expect.notEqual(updated.Value, "", "The string value should not have been removed"); + Expect.isNull(updated.Sub, "The sub-document should have been removed"); + }), + TestCase("succeeds when a field is not removed", async () => + { + await using var db = PostgresDb.BuildDb(); + await LoadDocs(); + + // This not raising an exception is the test + await RemoveFields.ByField(PostgresDb.TableName, Field.EQ("NumValue", "17"), [ "Nothing" ]); + }), + TestCase("succeeds when no document is matched", async () => + { + await using var db = PostgresDb.BuildDb(); + + // This not raising an exception is the test + await RemoveFields.ByField(PostgresDb.TableName, Field.NE("Abracadabra", "apple"), [ "Value" ]); + }) + }), + TestList("ByContains", new[] + { + TestCase("succeeds when multiple fields are removed", async () => + { + await using var db = PostgresDb.BuildDb(); + await LoadDocs(); + + await RemoveFields.ByContains(PostgresDb.TableName, new { NumValue = 17 }, [ "Sub", "Value" ]); + var updated = await Find.ById(PostgresDb.TableName, "four"); + Expect.isNotNull(updated, "The updated document should have been retrieved"); + Expect.equal(updated.Value, "", "The string value should have been removed"); + Expect.isNull(updated.Sub, "The sub-document should have been removed"); + }), + TestCase("succeeds when a single field is removed", async () => + { + await using var db = PostgresDb.BuildDb(); + await LoadDocs(); + + await RemoveFields.ByContains(PostgresDb.TableName, new { NumValue = 17 }, [ "Sub" ]); + var updated = await Find.ById(PostgresDb.TableName, "four"); + Expect.isNotNull(updated, "The updated document should have been retrieved"); + Expect.notEqual(updated.Value, "", "The string value should not have been removed"); + Expect.isNull(updated.Sub, "The sub-document should have been removed"); + }), + TestCase("succeeds when a field is not removed", async () => + { + await using var db = PostgresDb.BuildDb(); + await LoadDocs(); + + // This not raising an exception is the test + await RemoveFields.ByContains(PostgresDb.TableName, new { NumValue = 17 }, [ "Nothing" ]); + }), + TestCase("succeeds when no document is matched", async () => + { + await using var db = PostgresDb.BuildDb(); + + // This not raising an exception is the test + await RemoveFields.ByContains(PostgresDb.TableName, new { Abracadabra = "apple" }, [ "Value" ]); + }) + }), + TestList("ByJsonPath", new[] + { + TestCase("succeeds when multiple fields are removed", async () => + { + await using var db = PostgresDb.BuildDb(); + await LoadDocs(); + + await RemoveFields.ByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ == 17)", [ "Sub", "Value" ]); + var updated = await Find.ById(PostgresDb.TableName, "four"); + Expect.isNotNull(updated, "The updated document should have been retrieved"); + Expect.equal(updated.Value, "", "The string value should have been removed"); + Expect.isNull(updated.Sub, "The sub-document should have been removed"); + }), + TestCase("succeeds when a single field is removed", async () => + { + await using var db = PostgresDb.BuildDb(); + await LoadDocs(); + + await RemoveFields.ByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ == 17)", [ "Sub" ]); + var updated = await Find.ById(PostgresDb.TableName, "four"); + Expect.isNotNull(updated, "The updated document should have been retrieved"); + Expect.notEqual(updated.Value, "", "The string value should not have been removed"); + Expect.isNull(updated.Sub, "The sub-document should have been removed"); + }), + TestCase("succeeds when a field is not removed", async () => + { + await using var db = PostgresDb.BuildDb(); + await LoadDocs(); + + // This not raising an exception is the test + await RemoveFields.ByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ == 17)", [ "Nothing" ]); + }), + TestCase("succeeds when no document is matched", async () => + { + await using var db = PostgresDb.BuildDb(); + + // This not raising an exception is the test + await RemoveFields.ByJsonPath(PostgresDb.TableName, "$.Abracadabra ? (@ == \"apple\")", + [ "Value" ]); + }) + }) + }), TestList("Delete", new[] { TestList("ById", new[] diff --git a/src/Tests.CSharp/SqliteCSharpExtensionTests.cs b/src/Tests.CSharp/SqliteCSharpExtensionTests.cs index cc5061d..7accd98 100644 --- a/src/Tests.CSharp/SqliteCSharpExtensionTests.cs +++ b/src/Tests.CSharp/SqliteCSharpExtensionTests.cs @@ -467,17 +467,18 @@ public static class SqliteCSharpExtensionTests await conn.PatchByField(SqliteDb.TableName, Field.EQ("Value", "burgundy"), new { Foo = "green" }); }) }), - TestList("RemoveFieldById", new[] + TestList("RemoveFieldsById", new[] { - TestCase("succeeds when a field is removed", async () => + 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.RemoveFieldById(SqliteDb.TableName, "two", "Sub"); + 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"); Expect.isNull(updated.Sub, "The sub-document should have been removed"); }), TestCase("succeeds when a field is not removed", async () => @@ -487,7 +488,7 @@ public static class SqliteCSharpExtensionTests await LoadDocs(); // This not raising an exception is the test - await conn.RemoveFieldById(SqliteDb.TableName, "two", "AFieldThatIsNotThere"); + await conn.RemoveFieldsById(SqliteDb.TableName, "two", [ "AFieldThatIsNotThere" ]); }), TestCase("succeeds when no document is matched", async () => { @@ -495,10 +496,10 @@ public static class SqliteCSharpExtensionTests await using var conn = Sqlite.Configuration.DbConn(); // This not raising an exception is the test - await conn.RemoveFieldById(SqliteDb.TableName, "two", "Value"); + await conn.RemoveFieldsById(SqliteDb.TableName, "two", [ "Value" ]); }) }), - TestList("RemoveFieldByField", new[] + TestList("RemoveFieldsByField", new[] { TestCase("succeeds when a field is removed", async () => { @@ -506,7 +507,7 @@ public static class SqliteCSharpExtensionTests await using var conn = Sqlite.Configuration.DbConn(); await LoadDocs(); - await conn.RemoveFieldByField(SqliteDb.TableName, Field.EQ("NumValue", 17), "Sub"); + await conn.RemoveFieldsByField(SqliteDb.TableName, 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"); @@ -518,7 +519,7 @@ public static class SqliteCSharpExtensionTests await LoadDocs(); // This not raising an exception is the test - await conn.RemoveFieldByField(SqliteDb.TableName, Field.EQ("NumValue", 17), "Nothing"); + await conn.RemoveFieldsByField(SqliteDb.TableName, Field.EQ("NumValue", 17), [ "Nothing" ]); }), TestCase("succeeds when no document is matched", async () => { @@ -526,7 +527,7 @@ public static class SqliteCSharpExtensionTests await using var conn = Sqlite.Configuration.DbConn(); // This not raising an exception is the test - await conn.RemoveFieldByField(SqliteDb.TableName, Field.NE("Abracadabra", "apple"), "Value"); + await conn.RemoveFieldsByField(SqliteDb.TableName, Field.NE("Abracadabra", "apple"), [ "Value" ]); }) }), TestList("DeleteById", new[] diff --git a/src/Tests.CSharp/SqliteCSharpTests.cs b/src/Tests.CSharp/SqliteCSharpTests.cs index 3c6559b..4e050e2 100644 --- a/src/Tests.CSharp/SqliteCSharpTests.cs +++ b/src/Tests.CSharp/SqliteCSharpTests.cs @@ -41,18 +41,19 @@ public static class SqliteCSharpTests "UPDATE partial by JSON comparison query not correct"); }) }), - TestList("RemoveField", new[] + TestList("RemoveFields", new[] { TestCase("ById succeeds", () => { - Expect.equal(Sqlite.Query.RemoveField.ById("tbl"), + Expect.equal(Sqlite.Query.RemoveFields.ById("tbl", [ new SqliteParameter("@name", "one") ]), "UPDATE tbl SET data = json_remove(data, @name) WHERE data ->> 'Id' = @id", "Remove field by ID query not correct"); }), TestCase("ByField succeeds", () => { - Expect.equal(Sqlite.Query.RemoveField.ByField("tbl", Field.LT("Fly", 0)), - "UPDATE tbl SET data = json_remove(data, @name) WHERE data ->> 'Fly' < @field", + Expect.equal(Sqlite.Query.RemoveFields.ByField("tbl", Field.LT("Fly", 0), + [ new SqliteParameter("@name0", "one"), new SqliteParameter("@name1", "two") ]), + "UPDATE tbl SET data = json_remove(data, @name0, @name1) WHERE data ->> 'Fly' < @field", "Remove field by field query not correct"); }) }) @@ -73,7 +74,8 @@ public static class SqliteCSharpTests }), TestCase("AddField succeeds when adding a parameter", () => { - var paramList = Parameters.AddField(Field.EQ("it", 99), Enumerable.Empty()).ToList(); + var paramList = Parameters.AddField("@field", Field.EQ("it", 99), Enumerable.Empty()) + .ToList(); Expect.hasLength(paramList, 1, "There should have been a parameter added"); var theParam = paramList[0]; Expect.equal(theParam.ParameterName, "@field", "The parameter name is incorrect"); @@ -81,7 +83,7 @@ public static class SqliteCSharpTests }), TestCase("AddField succeeds when not adding a parameter", () => { - var paramSeq = Parameters.AddField(Field.EX("Coffee"), Enumerable.Empty()); + var paramSeq = Parameters.AddField("@it", Field.EX("Coffee"), Enumerable.Empty()); Expect.isEmpty(paramSeq, "There should not have been any parameters added"); }), TestCase("None succeeds", () => @@ -92,14 +94,14 @@ public static class SqliteCSharpTests // Results are exhaustively executed in the context of other tests }); - private static readonly List TestDocuments = new() - { + private static readonly List TestDocuments = + [ new() { Id = "one", Value = "FIRST!", NumValue = 0 }, new() { Id = "two", Value = "another", NumValue = 10, Sub = new() { Foo = "green", Bar = "blue" } }, new() { Id = "three", Value = "", NumValue = 4 }, new() { Id = "four", Value = "purple", NumValue = 17, Sub = new() { Foo = "green", Bar = "red" } }, new() { Id = "five", Value = "purple", NumValue = 18 } - }; + ]; /// /// Add the test documents to the database @@ -563,18 +565,19 @@ public static class SqliteCSharpTests }) }) }), - TestList("RemoveField", new[] + TestList("RemoveFields", new[] { TestList("ById", new[] { - TestCase("succeeds when a field is removed", async () => + TestCase("succeeds when fields are removed", async () => { await using var db = await SqliteDb.BuildDb(); await LoadDocs(); - await RemoveField.ById(SqliteDb.TableName, "two", "Sub"); + await RemoveFields.ById(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"); Expect.isNull(updated.Sub, "The sub-document should have been removed"); }), TestCase("succeeds when a field is not removed", async () => @@ -583,14 +586,14 @@ public static class SqliteCSharpTests await LoadDocs(); // This not raising an exception is the test - await RemoveField.ById(SqliteDb.TableName, "two", "AFieldThatIsNotThere"); + await RemoveFields.ById(SqliteDb.TableName, "two", [ "AFieldThatIsNotThere" ]); }), TestCase("succeeds when no document is matched", async () => { await using var db = await SqliteDb.BuildDb(); // This not raising an exception is the test - await RemoveField.ById(SqliteDb.TableName, "two", "Value"); + await RemoveFields.ById(SqliteDb.TableName, "two", [ "Value" ]); }) }), TestList("ByField", new[] @@ -600,7 +603,7 @@ public static class SqliteCSharpTests await using var db = await SqliteDb.BuildDb(); await LoadDocs(); - await RemoveField.ByField(SqliteDb.TableName, Field.EQ("NumValue", 17), "Sub"); + await RemoveFields.ByField(SqliteDb.TableName, 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"); @@ -611,14 +614,14 @@ public static class SqliteCSharpTests await LoadDocs(); // This not raising an exception is the test - await RemoveField.ByField(SqliteDb.TableName, Field.EQ("NumValue", 17), "Nothing"); + await RemoveFields.ByField(SqliteDb.TableName, Field.EQ("NumValue", 17), [ "Nothing" ]); }), TestCase("succeeds when no document is matched", async () => { await using var db = await SqliteDb.BuildDb(); // This not raising an exception is the test - await RemoveField.ByField(SqliteDb.TableName, Field.NE("Abracadabra", "apple"), "Value"); + await RemoveFields.ByField(SqliteDb.TableName, Field.NE("Abracadabra", "apple"), [ "Value" ]); }) }) }), diff --git a/src/Tests/PostgresExtensionTests.fs b/src/Tests/PostgresExtensionTests.fs index cfc0135..41b1210 100644 --- a/src/Tests/PostgresExtensionTests.fs +++ b/src/Tests/PostgresExtensionTests.fs @@ -616,6 +616,162 @@ let integrationTests = do! conn.patchByJsonPath PostgresDb.TableName "$.NumValue ? (@ < 0)" {| Foo = "green" |} } ] + testList "removeFieldsById" [ + testTask "succeeds when multiple fields are removed" { + use db = PostgresDb.BuildDb() + use conn = mkConn db + do! loadDocs conn + + do! conn.removeFieldsById PostgresDb.TableName "two" [ "Sub"; "Value" ] + let! noSubs = conn.countByField PostgresDb.TableName (Field.NEX "Sub") + Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" + let! noValue = conn.countByField PostgresDb.TableName (Field.NEX "Value") + Expect.equal noValue 1 "There should be 1 document without Value fields" + } + testTask "succeeds when a single field is removed" { + use db = PostgresDb.BuildDb() + use conn = mkConn db + do! loadDocs conn + + do! conn.removeFieldsById PostgresDb.TableName "two" [ "Sub" ] + let! noSubs = conn.countByField PostgresDb.TableName (Field.NEX "Sub") + Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" + let! noValue = conn.countByField PostgresDb.TableName (Field.NEX "Value") + Expect.equal noValue 0 "There should be no documents without Value fields" + } + testTask "succeeds when a field is not removed" { + use db = PostgresDb.BuildDb() + use conn = mkConn db + do! loadDocs conn + + // This not raising an exception is the test + do! conn.removeFieldsById PostgresDb.TableName "two" [ "AFieldThatIsNotThere" ] + } + testTask "succeeds when no document is matched" { + use db = PostgresDb.BuildDb() + use conn = mkConn db + + // This not raising an exception is the test + do! conn.removeFieldsById PostgresDb.TableName "two" [ "Value" ] + } + ] + testList "removeFieldsByField" [ + testTask "succeeds when multiple fields are removed" { + use db = PostgresDb.BuildDb() + use conn = mkConn db + do! loadDocs conn + + do! conn.removeFieldsByField PostgresDb.TableName (Field.EQ "NumValue" "17") [ "Sub"; "Value" ] + let! noSubs = conn.countByField PostgresDb.TableName (Field.NEX "Sub") + Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" + let! noValue = conn.countByField PostgresDb.TableName (Field.NEX "Value") + Expect.equal noValue 1 "There should be 1 document without Value fields" + } + testTask "succeeds when a single field is removed" { + use db = PostgresDb.BuildDb() + use conn = mkConn db + do! loadDocs conn + + do! conn.removeFieldsByField PostgresDb.TableName (Field.EQ "NumValue" "17") [ "Sub" ] + let! noSubs = conn.countByField PostgresDb.TableName (Field.NEX "Sub") + Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" + let! noValue = conn.countByField PostgresDb.TableName (Field.NEX "Value") + Expect.equal noValue 0 "There should be no documents without Value fields" + } + testTask "succeeds when a field is not removed" { + use db = PostgresDb.BuildDb() + use conn = mkConn db + do! loadDocs conn + + // This not raising an exception is the test + do! conn.removeFieldsByField PostgresDb.TableName (Field.EQ "NumValue" "17") [ "Nothing" ] + } + testTask "succeeds when no document is matched" { + use db = PostgresDb.BuildDb() + use conn = mkConn db + + // This not raising an exception is the test + do! conn.removeFieldsByField PostgresDb.TableName (Field.NE "Abracadabra" "apple") [ "Value" ] + } + ] + testList "removeFieldsByContains" [ + testTask "succeeds when multiple fields are removed" { + use db = PostgresDb.BuildDb() + use conn = mkConn db + do! loadDocs conn + + do! conn.removeFieldsByContains PostgresDb.TableName {| NumValue = 17 |} [ "Sub"; "Value" ] + let! noSubs = conn.countByField PostgresDb.TableName (Field.NEX "Sub") + Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" + let! noValue = conn.countByField PostgresDb.TableName (Field.NEX "Value") + Expect.equal noValue 1 "There should be 1 document without Value fields" + } + testTask "succeeds when a single field is removed" { + use db = PostgresDb.BuildDb() + use conn = mkConn db + do! loadDocs conn + + do! conn.removeFieldsByContains PostgresDb.TableName {| NumValue = 17 |} [ "Sub" ] + let! noSubs = conn.countByField PostgresDb.TableName (Field.NEX "Sub") + Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" + let! noValue = conn.countByField PostgresDb.TableName (Field.NEX "Value") + Expect.equal noValue 0 "There should be no documents without Value fields" + } + testTask "succeeds when a field is not removed" { + use db = PostgresDb.BuildDb() + use conn = mkConn db + do! loadDocs conn + + // This not raising an exception is the test + do! conn.removeFieldsByContains PostgresDb.TableName {| NumValue = 17 |} [ "Nothing" ] + } + testTask "succeeds when no document is matched" { + use db = PostgresDb.BuildDb() + use conn = mkConn db + + // This not raising an exception is the test + do! conn.removeFieldsByContains PostgresDb.TableName {| Abracadabra = "apple" |} [ "Value" ] + } + ] + testList "removeFieldsByJsonPath" [ + testTask "succeeds when multiple fields are removed" { + use db = PostgresDb.BuildDb() + use conn = mkConn db + do! loadDocs conn + + do! conn.removeFieldsByJsonPath PostgresDb.TableName "$.NumValue ? (@ == 17)" [ "Sub"; "Value" ] + let! noSubs = conn.countByField PostgresDb.TableName (Field.NEX "Sub") + Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" + let! noValue = conn.countByField PostgresDb.TableName (Field.NEX "Value") + Expect.equal noValue 1 "There should be 1 document without Value fields" + } + testTask "succeeds when a single field is removed" { + use db = PostgresDb.BuildDb() + use conn = mkConn db + do! loadDocs conn + + do! conn.removeFieldsByJsonPath PostgresDb.TableName "$.NumValue ? (@ == 17)" [ "Sub" ] + let! noSubs = conn.countByField PostgresDb.TableName (Field.NEX "Sub") + Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" + let! noValue = conn.countByField PostgresDb.TableName (Field.NEX "Value") + Expect.equal noValue 0 "There should be no documents without Value fields" + } + testTask "succeeds when a field is not removed" { + use db = PostgresDb.BuildDb() + use conn = mkConn db + do! loadDocs conn + + // This not raising an exception is the test + do! conn.removeFieldsByJsonPath PostgresDb.TableName "$.NumValue ? (@ == 17)" [ "Nothing" ] + } + testTask "succeeds when no document is matched" { + use db = PostgresDb.BuildDb() + use conn = mkConn db + + // This not raising an exception is the test + do! conn.removeFieldsByJsonPath PostgresDb.TableName "$.Abracadabra ? (@ == \"apple\")" [ "Value" ] + } + ] testList "deleteById" [ testTask "succeeds when a document is deleted" { use db = PostgresDb.BuildDb() diff --git a/src/Tests/PostgresTests.fs b/src/Tests/PostgresTests.fs index b0ef091..29384ec 100644 --- a/src/Tests/PostgresTests.fs +++ b/src/Tests/PostgresTests.fs @@ -20,7 +20,7 @@ let unitTests = } testList "addFieldParam" [ test "succeeds when a parameter is added" { - let paramList = addFieldParam (Field.EQ "it" "242") [] + let paramList = addFieldParam "@field" (Field.EQ "it" "242") [] Expect.hasLength paramList 1 "There should have been a parameter added" let it = paramList[0] Expect.equal (fst it) "@field" "Field parameter name not correct" @@ -31,7 +31,7 @@ let unitTests = | _ -> Expect.isTrue false "The parameter was not a Parameter type" } test "succeeds when a parameter is not added" { - let paramList = addFieldParam (Field.EX "tacos") [] + let paramList = addFieldParam "@field" (Field.EX "tacos") [] Expect.isEmpty paramList "There should not have been any parameters added" } ] @@ -135,6 +135,32 @@ let unitTests = "UPDATE partial by JSON Path statement not correct" } ] + testList "RemoveFields" [ + test "byId succeeds" { + Expect.equal + (Query.RemoveFields.byId "tbl") + "UPDATE tbl SET data = data - @name WHERE data ->> 'Id' = @id" + "Remove field by ID query not correct" + } + test "byField succeeds" { + Expect.equal + (Query.RemoveFields.byField "tbl" (Field.LT "Fly" 0)) + "UPDATE tbl SET data = data - @name WHERE data ->> 'Fly' < @field" + "Remove field by field query not correct" + } + test "byContains succeeds" { + Expect.equal + (Query.RemoveFields.byContains "tbl") + "UPDATE tbl SET data = data - @name WHERE data @> @criteria" + "Remove field by contains query not correct" + } + test "byJsonPath succeeds" { + Expect.equal + (Query.RemoveFields.byJsonPath "tbl") + "UPDATE tbl SET data = data - @name WHERE data @? @path::jsonpath" + "Remove field by JSON path query not correct" + } + ] testList "Delete" [ test "byContains succeeds" { Expect.equal (Query.Delete.byContains PostgresDb.TableName) @@ -743,6 +769,148 @@ let integrationTests = } ] ] + testList "RemoveFields" [ + testList "byId" [ + testTask "succeeds when multiple fields are removed" { + use db = PostgresDb.BuildDb() + do! loadDocs () + + do! RemoveFields.byId PostgresDb.TableName "two" [ "Sub"; "Value" ] + let! noSubs = Count.byField PostgresDb.TableName (Field.NEX "Sub") + Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" + let! noValue = Count.byField PostgresDb.TableName (Field.NEX "Value") + Expect.equal noValue 1 "There should be 1 document without Value fields" + } + testTask "succeeds when a single field is removed" { + use db = PostgresDb.BuildDb() + do! loadDocs () + + do! RemoveFields.byId PostgresDb.TableName "two" [ "Sub" ] + let! noSubs = Count.byField PostgresDb.TableName (Field.NEX "Sub") + Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" + let! noValue = Count.byField PostgresDb.TableName (Field.NEX "Value") + Expect.equal noValue 0 "There should be no documents without Value fields" + } + testTask "succeeds when a field is not removed" { + use db = PostgresDb.BuildDb() + do! loadDocs () + + // This not raising an exception is the test + do! RemoveFields.byId PostgresDb.TableName "two" [ "AFieldThatIsNotThere" ] + } + testTask "succeeds when no document is matched" { + use db = PostgresDb.BuildDb() + + // This not raising an exception is the test + do! RemoveFields.byId PostgresDb.TableName "two" [ "Value" ] + } + ] + testList "byField" [ + testTask "succeeds when multiple fields are removed" { + use db = PostgresDb.BuildDb() + do! loadDocs () + + do! RemoveFields.byField PostgresDb.TableName (Field.EQ "NumValue" "17") [ "Sub"; "Value" ] + let! noSubs = Count.byField PostgresDb.TableName (Field.NEX "Sub") + Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" + let! noValue = Count.byField PostgresDb.TableName (Field.NEX "Value") + Expect.equal noValue 1 "There should be 1 document without Value fields" + } + testTask "succeeds when a single field is removed" { + use db = PostgresDb.BuildDb() + do! loadDocs () + + do! RemoveFields.byField PostgresDb.TableName (Field.EQ "NumValue" "17") [ "Sub" ] + let! noSubs = Count.byField PostgresDb.TableName (Field.NEX "Sub") + Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" + let! noValue = Count.byField PostgresDb.TableName (Field.NEX "Value") + Expect.equal noValue 0 "There should be no documents without Value fields" + } + testTask "succeeds when a field is not removed" { + use db = PostgresDb.BuildDb() + do! loadDocs () + + // This not raising an exception is the test + do! RemoveFields.byField PostgresDb.TableName (Field.EQ "NumValue" "17") [ "Nothing" ] + } + testTask "succeeds when no document is matched" { + use db = PostgresDb.BuildDb() + + // This not raising an exception is the test + do! RemoveFields.byField PostgresDb.TableName (Field.NE "Abracadabra" "apple") [ "Value" ] + } + ] + testList "byContains" [ + testTask "succeeds when multiple fields are removed" { + use db = PostgresDb.BuildDb() + do! loadDocs () + + do! RemoveFields.byContains PostgresDb.TableName {| NumValue = 17 |} [ "Sub"; "Value" ] + let! noSubs = Count.byField PostgresDb.TableName (Field.NEX "Sub") + Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" + let! noValue = Count.byField PostgresDb.TableName (Field.NEX "Value") + Expect.equal noValue 1 "There should be 1 document without Value fields" + } + testTask "succeeds when a single field is removed" { + use db = PostgresDb.BuildDb() + do! loadDocs () + + do! RemoveFields.byContains PostgresDb.TableName {| NumValue = 17 |} [ "Sub" ] + let! noSubs = Count.byField PostgresDb.TableName (Field.NEX "Sub") + Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" + let! noValue = Count.byField PostgresDb.TableName (Field.NEX "Value") + Expect.equal noValue 0 "There should be no documents without Value fields" + } + testTask "succeeds when a field is not removed" { + use db = PostgresDb.BuildDb() + do! loadDocs () + + // This not raising an exception is the test + do! RemoveFields.byContains PostgresDb.TableName {| NumValue = 17 |} [ "Nothing" ] + } + testTask "succeeds when no document is matched" { + use db = PostgresDb.BuildDb() + + // This not raising an exception is the test + do! RemoveFields.byContains PostgresDb.TableName {| Abracadabra = "apple" |} [ "Value" ] + } + ] + testList "byJsonPath" [ + testTask "succeeds when multiple fields are removed" { + use db = PostgresDb.BuildDb() + do! loadDocs () + + do! RemoveFields.byJsonPath PostgresDb.TableName "$.NumValue ? (@ == 17)" [ "Sub"; "Value" ] + let! noSubs = Count.byField PostgresDb.TableName (Field.NEX "Sub") + Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" + let! noValue = Count.byField PostgresDb.TableName (Field.NEX "Value") + Expect.equal noValue 1 "There should be 1 document without Value fields" + } + testTask "succeeds when a single field is removed" { + use db = PostgresDb.BuildDb() + do! loadDocs () + + do! RemoveFields.byJsonPath PostgresDb.TableName "$.NumValue ? (@ == 17)" [ "Sub" ] + let! noSubs = Count.byField PostgresDb.TableName (Field.NEX "Sub") + Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" + let! noValue = Count.byField PostgresDb.TableName (Field.NEX "Value") + Expect.equal noValue 0 "There should be no documents without Value fields" + } + testTask "succeeds when a field is not removed" { + use db = PostgresDb.BuildDb() + do! loadDocs () + + // This not raising an exception is the test + do! RemoveFields.byJsonPath PostgresDb.TableName "$.NumValue ? (@ == 17)" [ "Nothing" ] + } + testTask "succeeds when no document is matched" { + use db = PostgresDb.BuildDb() + + // This not raising an exception is the test + do! RemoveFields.byJsonPath PostgresDb.TableName "$.Abracadabra ? (@ == \"apple\")" [ "Value" ] + } + ] + ] testList "Delete" [ testList "byId" [ testTask "succeeds when a document is deleted" { diff --git a/src/Tests/SqliteExtensionTests.fs b/src/Tests/SqliteExtensionTests.fs index ee89a9b..d8a43ff 100644 --- a/src/Tests/SqliteExtensionTests.fs +++ b/src/Tests/SqliteExtensionTests.fs @@ -345,13 +345,13 @@ let integrationTests = do! conn.patchByField SqliteDb.TableName (Field.EQ "Value" "burgundy") {| Foo = "green" |} } ] - testList "removeFieldById" [ - testTask "succeeds when a field is removed" { + testList "removeFieldsById" [ + testTask "succeeds when fields are removed" { use! db = SqliteDb.BuildDb() use conn = Configuration.dbConn () do! loadDocs () - do! conn.removeFieldById SqliteDb.TableName "two" "Sub" + do! conn.removeFieldsById SqliteDb.TableName "two" [ "Sub"; "Value" ] try let! _ = conn.findById SqliteDb.TableName "two" Expect.isTrue false "The updated document should have failed to parse" @@ -365,14 +365,14 @@ let integrationTests = do! loadDocs () // This not raising an exception is the test - do! conn.removeFieldById SqliteDb.TableName "two" "AFieldThatIsNotThere" + do! conn.removeFieldsById SqliteDb.TableName "two" [ "AFieldThatIsNotThere" ] } 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.removeFieldById SqliteDb.TableName "two" "Value" + do! conn.removeFieldsById SqliteDb.TableName "two" [ "Value" ] } ] testList "removeFieldByField" [ @@ -381,7 +381,7 @@ let integrationTests = use conn = Configuration.dbConn () do! loadDocs () - do! conn.removeFieldByField SqliteDb.TableName (Field.EQ "NumValue" 17) "Sub" + do! conn.removeFieldsByField SqliteDb.TableName (Field.EQ "NumValue" 17) [ "Sub" ] try let! _ = conn.findById SqliteDb.TableName "four" Expect.isTrue false "The updated document should have failed to parse" @@ -395,14 +395,14 @@ let integrationTests = do! loadDocs () // This not raising an exception is the test - do! conn.removeFieldByField SqliteDb.TableName (Field.EQ "NumValue" 17) "Nothing" + do! conn.removeFieldsByField SqliteDb.TableName (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.removeFieldByField SqliteDb.TableName (Field.NE "Abracadabra" "apple") "Value" + do! conn.removeFieldsByField SqliteDb.TableName (Field.NE "Abracadabra" "apple") [ "Value" ] } ] testList "deleteById" [ diff --git a/src/Tests/SqliteTests.fs b/src/Tests/SqliteTests.fs index a16b37f..9063d2e 100644 --- a/src/Tests/SqliteTests.fs +++ b/src/Tests/SqliteTests.fs @@ -32,17 +32,20 @@ let unitTests = "UPDATE partial by JSON comparison query not correct" } ] - testList "RemoveField" [ + testList "RemoveFields" [ test "byId succeeds" { Expect.equal - (Query.RemoveField.byId "tbl") + (Query.RemoveFields.byId "tbl" [ SqliteParameter("@name", "one") ]) "UPDATE tbl SET data = json_remove(data, @name) WHERE data ->> 'Id' = @id" "Remove field by ID query not correct" } test "byField succeeds" { Expect.equal - (Query.RemoveField.byField "tbl" (Field.GT "Fly" 0)) - "UPDATE tbl SET data = json_remove(data, @name) WHERE data ->> 'Fly' > @field" + (Query.RemoveFields.byField + "tbl" + (Field.GT "Fly" 0) + [ SqliteParameter("@name0", "one"); SqliteParameter("@name1", "two") ]) + "UPDATE tbl SET data = json_remove(data, @name0, @name1) WHERE data ->> 'Fly' > @field" "Remove field by field query not correct" } ] @@ -60,14 +63,14 @@ let unitTests = } testList "addFieldParam" [ test "succeeds when adding a parameter" { - let paramList = addFieldParam (Field.EQ "it" 99) [] + let paramList = addFieldParam "@field" (Field.EQ "it" 99) [] Expect.hasLength paramList 1 "There should have been a parameter added" let theParam = paramList[0] Expect.equal theParam.ParameterName "@field" "The parameter name is incorrect" Expect.equal theParam.Value 99 "The parameter value is incorrect" } test "succeeds when not adding a parameter" { - let paramList = addFieldParam (Field.NEX "Coffee") [] + let paramList = addFieldParam "@it" (Field.NEX "Coffee") [] Expect.isEmpty paramList "There should not have been any parameters added" } ] @@ -512,13 +515,13 @@ let integrationTests = } ] ] - testList "RemoveField" [ + testList "RemoveFields" [ testList "byId" [ - testTask "succeeds when a field is removed" { + testTask "succeeds when fields is removed" { use! db = SqliteDb.BuildDb() do! loadDocs () - do! RemoveField.byId SqliteDb.TableName "two" "Sub" + do! RemoveFields.byId SqliteDb.TableName "two" [ "Sub"; "Value" ] try let! _ = Find.byId SqliteDb.TableName "two" Expect.isTrue false "The updated document should have failed to parse" @@ -531,13 +534,13 @@ let integrationTests = do! loadDocs () // This not raising an exception is the test - do! RemoveField.byId SqliteDb.TableName "two" "AFieldThatIsNotThere" + do! RemoveFields.byId SqliteDb.TableName "two" [ "AFieldThatIsNotThere" ] } testTask "succeeds when no document is matched" { use! db = SqliteDb.BuildDb() // This not raising an exception is the test - do! RemoveField.byId SqliteDb.TableName "two" "Value" + do! RemoveFields.byId SqliteDb.TableName "two" [ "Value" ] } ] testList "byField" [ @@ -545,7 +548,7 @@ let integrationTests = use! db = SqliteDb.BuildDb() do! loadDocs () - do! RemoveField.byField SqliteDb.TableName (Field.EQ "NumValue" 17) "Sub" + do! RemoveFields.byField SqliteDb.TableName (Field.EQ "NumValue" 17) [ "Sub" ] try let! _ = Find.byId SqliteDb.TableName "four" Expect.isTrue false "The updated document should have failed to parse" @@ -558,13 +561,13 @@ let integrationTests = do! loadDocs () // This not raising an exception is the test - do! RemoveField.byField SqliteDb.TableName (Field.EQ "NumValue" 17) "Nothing" + do! RemoveFields.byField SqliteDb.TableName (Field.EQ "NumValue" 17) [ "Nothing" ] } testTask "succeeds when no document is matched" { use! db = SqliteDb.BuildDb() // This not raising an exception is the test - do! RemoveField.byField SqliteDb.TableName (Field.NE "Abracadabra" "apple") "Value" + do! RemoveFields.byField SqliteDb.TableName (Field.NE "Abracadabra" "apple") [ "Value" ] } ] ]