From d8f64417e51d2da2e235f204d1d878aa589aad1d Mon Sep 17 00:00:00 2001 From: "Daniel J. Summers" Date: Thu, 8 Aug 2024 19:45:25 -0400 Subject: [PATCH] Add byFields to SQLite implementation - Add fieldNameParams/FieldNames to Postgres (syncs names between both implementations) --- src/Postgres/Extensions.fs | 29 +- src/Postgres/Library.fs | 20 +- src/Sqlite/Extensions.fs | 116 +++++- src/Sqlite/Library.fs | 370 +++++++++++------- src/Tests.CSharp/PostgresCSharpTests.cs | 2 +- .../SqliteCSharpExtensionTests.cs | 132 ++++--- src/Tests.CSharp/SqliteCSharpTests.cs | 38 +- src/Tests/SqliteTests.fs | 12 +- 8 files changed, 461 insertions(+), 258 deletions(-) diff --git a/src/Postgres/Extensions.fs b/src/Postgres/Extensions.fs index 8e1c7a3..b297eb9 100644 --- a/src/Postgres/Extensions.fs +++ b/src/Postgres/Extensions.fs @@ -1,5 +1,6 @@ namespace BitBadger.Documents.Postgres +open BitBadger.Documents open Npgsql open Npgsql.FSharp @@ -56,7 +57,7 @@ module Extensions = /// Count matching documents using a JSON field comparison query (->> =) [] member conn.countByField tableName field = - WithProps.Count.byField tableName field (Sql.existingConnection conn) + conn.countByFields tableName Any [ field ] /// Count matching documents using a JSON containment query (@>) member conn.countByContains tableName criteria = @@ -77,7 +78,7 @@ module Extensions = /// Determine if documents exist using a JSON field comparison query (->> =) [] member conn.existsByField tableName field = - WithProps.Exists.byField tableName field (Sql.existingConnection conn) + conn.existsByFields tableName Any [ field ] /// Determine if documents exist using a JSON containment query (@>) member conn.existsByContains tableName criteria = @@ -102,7 +103,7 @@ module Extensions = /// Retrieve documents matching a JSON field comparison query (->> =) [] member conn.findByField<'TDoc> tableName field = - WithProps.Find.byField<'TDoc> tableName field (Sql.existingConnection conn) + conn.findByFields<'TDoc> tableName Any [ field ] /// Retrieve documents matching a JSON containment query (@>) member conn.findByContains<'TDoc> tableName (criteria: obj) = @@ -119,7 +120,7 @@ module Extensions = /// Retrieve the first document matching a JSON field comparison query (->> =); returns None if not found [] member conn.findFirstByField<'TDoc> tableName field = - WithProps.Find.firstByField<'TDoc> tableName field (Sql.existingConnection conn) + conn.findFirstByFields<'TDoc> tableName Any [ field ] /// Retrieve the first document matching a JSON containment query (@>); returns None if not found member conn.findFirstByContains<'TDoc> tableName (criteria: obj) = @@ -148,7 +149,7 @@ module Extensions = /// Patch documents using a JSON field comparison query in the WHERE clause (->> =) [] member conn.patchByField tableName field (patch: 'TPatch) = - WithProps.Patch.byField tableName field patch (Sql.existingConnection conn) + conn.patchByFields tableName Any [ field ] patch /// Patch documents using a JSON containment query in the WHERE clause (@>) member conn.patchByContains tableName (criteria: 'TCriteria) (patch: 'TPatch) = @@ -169,7 +170,7 @@ module Extensions = /// 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) + conn.removeFieldsByFields tableName Any [ field ] fieldNames /// Remove fields from documents via a JSON containment query (@>) member conn.removeFieldsByContains tableName (criteria: 'TContains) fieldNames = @@ -189,7 +190,7 @@ module Extensions = /// Delete documents by matching a JSON field comparison query (->> =) [] member conn.deleteByField tableName field = - WithProps.Delete.byField tableName field (Sql.existingConnection conn) + conn.deleteByFields tableName Any [ field ] /// Delete documents by matching a JSON containment query (@>) member conn.deleteByContains tableName (criteria: 'TContains) = @@ -266,7 +267,7 @@ type NpgsqlConnectionCSharpExtensions = [] [] static member inline CountByField(conn, tableName, field) = - WithProps.Count.byField tableName field (Sql.existingConnection conn) + conn.CountByFields(tableName, Any, [ field ]) /// Count matching documents using a JSON containment query (@>) [] @@ -292,7 +293,7 @@ type NpgsqlConnectionCSharpExtensions = [] [] static member inline ExistsByField(conn, tableName, field) = - WithProps.Exists.byField tableName field (Sql.existingConnection conn) + conn.ExistsByFields(tableName, Any, [ field ]) /// Determine if documents exist using a JSON containment query (@>) [] @@ -323,7 +324,7 @@ type NpgsqlConnectionCSharpExtensions = [] [] static member inline FindByField<'TDoc>(conn, tableName, field) = - WithProps.Find.ByField<'TDoc>(tableName, field, Sql.existingConnection conn) + conn.FindByFields<'TDoc>(tableName, Any, [ field ]) /// Retrieve documents matching a JSON containment query (@>) [] @@ -344,7 +345,7 @@ type NpgsqlConnectionCSharpExtensions = [] [] static member inline FindFirstByField<'TDoc when 'TDoc: null>(conn, tableName, field) = - WithProps.Find.FirstByField<'TDoc>(tableName, field, Sql.existingConnection conn) + conn.FindFirstByFields<'TDoc>(tableName, Any, [ field ]) /// Retrieve the first document matching a JSON containment query (@>); returns None if not found [] @@ -380,7 +381,7 @@ type NpgsqlConnectionCSharpExtensions = [] [] static member inline PatchByField(conn, tableName, field, patch: 'TPatch) = - WithProps.Patch.byField tableName field patch (Sql.existingConnection conn) + conn.PatchByFields(tableName, Any, [ field ], patch) /// Patch documents using a JSON containment query in the WHERE clause (@>) [] @@ -406,7 +407,7 @@ type NpgsqlConnectionCSharpExtensions = [] [] static member inline RemoveFieldsByField(conn, tableName, field, fieldNames) = - WithProps.RemoveFields.byField tableName field fieldNames (Sql.existingConnection conn) + conn.RemoveFieldsByFields(tableName, Any, [ field ], fieldNames) /// Remove fields from documents via a JSON containment query (@>) [] @@ -432,7 +433,7 @@ type NpgsqlConnectionCSharpExtensions = [] [] static member inline DeleteByField(conn, tableName, field) = - WithProps.Delete.byField tableName field (Sql.existingConnection conn) + conn.DeleteByFields(tableName, Any, [ field ]) /// Delete documents by matching a JSON containment query (@>) [] diff --git a/src/Postgres/Library.fs b/src/Postgres/Library.fs index c4dfc2a..4be1a0c 100644 --- a/src/Postgres/Library.fs +++ b/src/Postgres/Library.fs @@ -90,12 +90,18 @@ module Parameters = [] let addFieldParam name field parameters = addFieldParams [ { field with ParameterName = Some name } ] parameters - + /// Append JSON field name parameters for the given field names to the given parameters - [] - let fieldNameParam (fieldNames: string seq) = + [] + let fieldNameParams (fieldNames: string seq) = if Seq.length fieldNames = 1 then "@name", Sql.string (Seq.head fieldNames) else "@name", Sql.stringArray (Array.ofSeq fieldNames) + + /// Append JSON field name parameters for the given field names to the given parameters + [] + [] + let fieldNameParam fieldNames = + fieldNameParams fieldNames /// An empty parameter sequence [] @@ -707,7 +713,7 @@ module WithProps = /// 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 + Custom.nonQuery (Query.RemoveFields.byId tableName) [ idParam docId; fieldNameParams fieldNames ] sqlProps /// Remove fields from a document by the document's ID let ById(tableName, docId: 'TKey, fieldNames, sqlProps) = @@ -718,7 +724,7 @@ module WithProps = let byFields tableName howMatched fields fieldNames sqlProps = Custom.nonQuery (Query.RemoveFields.byFields tableName howMatched fields) - (addFieldParams fields [ fieldNameParam fieldNames ]) + (addFieldParams fields [ fieldNameParams fieldNames ]) sqlProps /// Remove fields from documents via a comparison on a JSON field in the document @@ -732,7 +738,7 @@ module WithProps = let byContains tableName (criteria: 'TContains) fieldNames sqlProps = Custom.nonQuery (Query.RemoveFields.byContains tableName) - [ jsonParam "@criteria" criteria; fieldNameParam fieldNames ] + [ jsonParam "@criteria" criteria; fieldNameParams fieldNames ] sqlProps /// Remove fields from documents via a JSON containment query (@>) @@ -744,7 +750,7 @@ module WithProps = let byJsonPath tableName jsonPath fieldNames sqlProps = Custom.nonQuery (Query.RemoveFields.byJsonPath tableName) - [ "@path", Sql.string jsonPath; fieldNameParam fieldNames ] + [ "@path", Sql.string jsonPath; fieldNameParams fieldNames ] sqlProps /// Remove fields from documents via a JSON Path match query (@?) diff --git a/src/Sqlite/Extensions.fs b/src/Sqlite/Extensions.fs index 7ad8888..576b771 100644 --- a/src/Sqlite/Extensions.fs +++ b/src/Sqlite/Extensions.fs @@ -1,5 +1,6 @@ namespace BitBadger.Documents.Sqlite +open BitBadger.Documents open Microsoft.Data.Sqlite /// F# extensions for the SqliteConnection type @@ -44,17 +45,27 @@ module Extensions = member conn.countAll tableName = WithConn.Count.all tableName conn + /// Count matching documents using a comparison on JSON fields + 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 = - WithConn.Count.byField tableName field conn + 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 + /// Determine if a document exists using a comparison on JSON fields + 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 = - WithConn.Exists.byField tableName field conn + conn.existsByFields tableName Any [ field ] /// Retrieve all documents in the given table member conn.findAll<'TDoc> tableName = @@ -63,14 +74,24 @@ module Extensions = /// Retrieve a document by its ID member conn.findById<'TKey, 'TDoc> tableName (docId: 'TKey) = WithConn.Find.byId<'TKey, 'TDoc> tableName docId conn - + + /// Retrieve documents via a comparison on JSON fields + member conn.findByFields<'TDoc> tableName howMatched fields = + WithConn.Find.byFields<'TDoc> tableName howMatched fields conn + /// Retrieve documents via a comparison on a JSON field + [] member conn.findByField<'TDoc> tableName field = - WithConn.Find.byField<'TDoc> tableName field conn - + 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 + /// Retrieve documents via a comparison on a JSON field, returning only the first result + [] member conn.findFirstByField<'TDoc> tableName field = - WithConn.Find.firstByField<'TDoc> tableName field conn + conn.findFirstByFields<'TDoc> tableName Any [ field ] /// Update an entire document by its ID member conn.updateById tableName (docId: 'TKey) (document: 'TDoc) = @@ -84,25 +105,40 @@ module Extensions = member conn.patchById tableName (docId: 'TKey) (patch: 'TPatch) = WithConn.Patch.byId tableName docId patch conn + /// Patch documents using a comparison on JSON fields + 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) = - WithConn.Patch.byField tableName field patch conn + 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 + /// Remove a field from a document via a comparison on JSON fields in the document + 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 = - WithConn.RemoveFields.byField tableName field fieldNames conn + conn.removeFieldsByFields tableName Any [ field ] fieldNames /// Delete a document by its ID member conn.deleteById tableName (docId: 'TKey) = WithConn.Delete.byId tableName docId conn + /// 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 = - WithConn.Delete.byField tableName field conn + conn.deleteByFields tableName Any [ field ] open System.Runtime.CompilerServices @@ -157,20 +193,32 @@ type SqliteConnectionCSharpExtensions = static member inline CountAll(conn, tableName) = WithConn.Count.all tableName conn + /// Count matching documents using a comparison on JSON fields + [] + 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) = - WithConn.Count.byField tableName field conn + conn.CountByFields(tableName, Any, [ field ]) /// Determine if a document exists for the given ID [] static member inline ExistsById<'TKey>(conn, tableName, docId: 'TKey) = WithConn.Exists.byId tableName docId conn + /// Determine if a document exists using a comparison on JSON fields + [] + 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) = - WithConn.Exists.byField tableName field conn + conn.ExistsByFields(tableName, Any, [ field ]) /// Retrieve all documents in the given table [] @@ -182,15 +230,27 @@ type SqliteConnectionCSharpExtensions = static member inline FindById<'TKey, 'TDoc when 'TDoc: null>(conn, tableName, docId: 'TKey) = WithConn.Find.ById<'TKey, 'TDoc>(tableName, docId, conn) + /// Retrieve documents via a comparison on JSON fields + [] + static member inline FindByFields<'TDoc>(conn, tableName, howMatched, fields) = + WithConn.Find.ByFields<'TDoc>(tableName, howMatched, fields, conn) + /// Retrieve documents via a comparison on a JSON field [] + [] static member inline FindByField<'TDoc>(conn, tableName, field) = - WithConn.Find.ByField<'TDoc>(tableName, field, conn) + 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) = + WithConn.Find.FirstByFields<'TDoc>(tableName, howMatched, fields, 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) = - WithConn.Find.FirstByField<'TDoc>(tableName, field, conn) + conn.FindFirstByFields<'TDoc>(tableName, Any, [ field ]) /// Update an entire document by its ID [] @@ -207,27 +267,45 @@ type SqliteConnectionCSharpExtensions = static member inline PatchById<'TKey, 'TPatch>(conn, tableName, docId: 'TKey, patch: 'TPatch) = WithConn.Patch.byId tableName docId patch conn + /// Patch documents using a comparison on JSON fields + [] + 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) = - WithConn.Patch.byField tableName field patch conn + 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) = - WithConn.RemoveFields.ById(tableName, docId, fieldNames, conn) - + WithConn.RemoveFields.byId tableName docId fieldNames conn + + /// Remove fields from documents via a comparison on JSON fields in the document + [] + 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) = - WithConn.RemoveFields.ByField(tableName, field, fieldNames, conn) + conn.RemoveFieldsByFields(tableName, Any, [ field ], fieldNames) /// Delete a document by its ID [] static member inline DeleteById<'TKey>(conn, tableName, docId: 'TKey) = WithConn.Delete.byId tableName docId conn - + + /// Delete documents by matching a comparison on JSON fields + [] + static member inline DeleteByFields(conn, tableName, howMatched, fields) = + WithConn.Delete.byFields tableName howMatched fields conn + /// Delete documents by matching a comparison on a JSON field [] + [] static member inline DeleteByField(conn, tableName, field) = - WithConn.Delete.byField tableName field conn + conn.DeleteByFields(tableName, Any, [ field ]) diff --git a/src/Sqlite/Library.fs b/src/Sqlite/Library.fs index 3a52534..86df67b 100644 --- a/src/Sqlite/Library.fs +++ b/src/Sqlite/Library.fs @@ -32,11 +32,11 @@ module Configuration = module Query = /// Create a WHERE clause fragment to implement a comparison on fields in a JSON document - [] + [] let whereByFields howMatched fields = let name = ParameterName() fields - |> List.map (fun it -> + |> Seq.map (fun it -> match it.Op with | EX | NEX -> $"{it.SqlitePath} {it.Op}" | BT -> @@ -45,10 +45,6 @@ module Query = | _ -> $"{it.SqlitePath} {it.Op} {name.Derive it.ParameterName}") |> String.concat (match howMatched with Any -> " OR " | All -> " AND ") - /// Create a WHERE clause fragment to implement a comparison on fields in a JSON document - let WhereByFields(howMatched, fields: Field seq) = - whereByFields howMatched (List.ofSeq fields) - /// Create a WHERE clause fragment to implement a comparison on a field in a JSON document [] [] @@ -81,11 +77,16 @@ module Query = let all tableName = $"SELECT COUNT(*) AS it FROM %s{tableName}" + /// Query to count matching documents using a text comparison on JSON fields + [] + let byFields tableName howMatched fields = + $"SELECT COUNT(*) AS it FROM %s{tableName} WHERE {whereByFields howMatched fields}" + /// Query to count matching documents using a text comparison on a JSON field [] + [] let byField tableName field = - whereByFields Any [ { field with ParameterName = Some "@field" } ] - |> sprintf "SELECT COUNT(*) AS it FROM %s WHERE %s" tableName + byFields tableName Any [ field ] /// Queries for determining document existence module Exists = @@ -94,12 +95,17 @@ module Query = [] let byId tableName = $"""SELECT EXISTS (SELECT 1 FROM %s{tableName} WHERE {whereById "@id"}) AS it""" - + + /// Query to determine if documents exist using a comparison on JSON fields + [] + let byFields tableName howMatched fields = + $"SELECT EXISTS (SELECT 1 FROM %s{tableName} WHERE {whereByFields howMatched fields}) AS it" + /// Query to determine if documents exist using a comparison on a JSON field [] + [] let byField tableName field = - whereByFields Any [ { field with ParameterName = Some "@field" } ] - |> sprintf "SELECT EXISTS (SELECT 1 FROM %s WHERE %s) AS it" tableName + byFields tableName Any [ field ] /// Queries for retrieving documents module Find = @@ -109,12 +115,17 @@ module Query = let byId tableName = $"""{Query.selectFromTable tableName} WHERE {whereById "@id"}""" + /// Query to retrieve documents using a comparison on JSON fields + [] + let byFields tableName howMatched fields = + $"{Query.selectFromTable tableName} WHERE {whereByFields howMatched fields}" + /// Query to retrieve documents using a comparison on a JSON field [] + [] let byField tableName field = - whereByFields Any [ { field with ParameterName = Some "@field" } ] - |> sprintf "%s WHERE %s" (Query.selectFromTable tableName) - + byFields tableName Any [ field ] + /// Document patching (partial update) queries module Patch = @@ -126,37 +137,41 @@ module Query = [] let byId tableName = whereById "@id" |> update tableName - + + /// Query to patch (partially update) a document via a comparison on JSON fields + [] + let byFields tableName howMatched fields = + whereByFields howMatched fields |> update tableName + /// Query to patch (partially update) a document via a comparison on a JSON field [] + [] let byField tableName field = - whereByFields Any [ { field with ParameterName = Some "@field" } ] |> update tableName + byFields tableName Any [ field ] /// Queries to remove fields from documents module RemoveFields = /// 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}" + let internal update tableName (parameters: SqliteParameter seq) whereClause = + let paramNames = parameters |> Seq.map _.ParameterName |> String.concat ", " + $"UPDATE %s{tableName} SET data = json_remove(data, {paramNames}) WHERE %s{whereClause}" /// Query to remove fields from a document by the document's ID - [] + [] let byId tableName parameters = whereById "@id" |> update tableName parameters - /// 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 JSON fields within the document + [] + let byFields tableName howMatched fields parameters = + whereByFields howMatched fields |> update tableName parameters /// Query to remove fields from documents via a comparison on a JSON field within the document - [] + [] + [] let byField tableName field parameters = - whereByFields Any [ { field with ParameterName = Some "@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) + byFields tableName Any [ field ] parameters /// Queries to delete documents module Delete = @@ -165,12 +180,17 @@ module Query = [] let byId tableName = $"""DELETE FROM %s{tableName} WHERE {whereById "@id"}""" - + + /// Query to delete documents using a comparison on JSON fields + [] + let byFields tableName howMatched fields = + $"DELETE FROM %s{tableName} WHERE {whereByFields howMatched fields}" + /// Query to delete documents using a comparison on a JSON field [] + [] let byField tableName field = - whereByFields Any [ { field with ParameterName = Some "@field" } ] - |> sprintf "DELETE FROM %s WHERE %s" tableName + byFields tableName Any [ field ] /// Parameter handling helpers @@ -187,8 +207,9 @@ module Parameters = let jsonParam name (it: 'TJson) = SqliteParameter(name, Configuration.serializer().Serialize it) - /// Convert the fields to their parameters - let private convertFieldsToParameters fields = + /// Create JSON field parameters + [] + let addFieldParams fields parameters = let name = ParameterName() fields |> Seq.map (fun it -> @@ -202,38 +223,23 @@ module Parameters = yield SqliteParameter($"{p}max", List.last values) | _ -> yield SqliteParameter(name.Derive it.ParameterName, it.Value) }) |> Seq.collect id - - /// Create JSON field parameters - [] - let addFieldParams (fields: Field list) parameters = - convertFieldsToParameters fields - |> Seq.toList - |> List.append parameters - - /// Create JSON field parameters - let AddFields fields parameters = - convertFieldsToParameters fields |> Seq.append parameters + |> Seq.toList + |> Seq.ofList /// Create a JSON field parameter (name "@field") - [] + [] [] let addFieldParam name field parameters = addFieldParams [ { field with ParameterName = Some name } ] parameters - /// Create a JSON field parameter (name "@field") - [] - let AddField(name, field, parameters) = - AddFields [ { field with ParameterName = Some name } ] parameters - /// 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}")) + [] + let fieldNameParams paramName fieldNames = + fieldNames + |> Seq.mapi (fun idx name -> SqliteParameter($"%s{paramName}{idx}", $"$.%s{name}")) + |> Seq.toList + |> Seq.ofList /// An empty parameter sequence [] @@ -382,14 +388,16 @@ module WithConn = let all tableName conn = Custom.scalar (Query.Count.all tableName) [] toCount conn + /// Count matching documents using a comparison on JSON fields + [] + let byFields tableName howMatched fields conn = + Custom.scalar (Query.Count.byFields tableName howMatched fields) (addFieldParams fields []) toCount conn + /// Count matching documents using a comparison on a JSON field [] + [] let byField tableName field conn = - Custom.scalar - (Query.Count.byField tableName field) - (addFieldParams [ { field with ParameterName = Some "@field" } ] []) - toCount - conn + byFields tableName Any [ field ] conn /// Commands to determine if documents exist [] @@ -399,15 +407,17 @@ module WithConn = [] let byId tableName (docId: 'TKey) conn = Custom.scalar (Query.Exists.byId tableName) [ idParam docId ] toExists conn - + + /// Determine if a document exists using a comparison on JSON fields + [] + let byFields tableName howMatched fields conn = + Custom.scalar (Query.Exists.byFields tableName howMatched fields) (addFieldParams fields []) toExists conn + /// Determine if a document exists using a comparison on a JSON field [] + [] let byField tableName field conn = - Custom.scalar - (Query.Exists.byField tableName field) - (addFieldParams [ { field with ParameterName = Some "@field" } ] []) - toExists - conn + byFields tableName Any [ field ] conn /// Commands to retrieve documents [] @@ -430,40 +440,56 @@ module WithConn = /// Retrieve a document by its ID (returns null if not found) let ById<'TKey, 'TDoc when 'TDoc: null>(tableName, docId: 'TKey, conn) = Custom.Single<'TDoc>(Query.Find.byId tableName, [ idParam docId ], fromData<'TDoc>, conn) - + + /// Retrieve documents via a comparison on JSON fields + [] + let byFields<'TDoc> tableName howMatched fields conn = + Custom.list<'TDoc> + (Query.Find.byFields tableName howMatched fields) (addFieldParams fields []) 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) - (addFieldParams [ { field with ParameterName = Some "@field" } ] []) - fromData<'TDoc> - conn + byFields<'TDoc> tableName Any [ field ] conn - /// Retrieve documents via a comparison on a JSON field - let ByField<'TDoc>(tableName, field, conn) = + /// Retrieve documents via a comparison on JSON fields + let ByFields<'TDoc>(tableName, howMatched, fields, conn) = Custom.List<'TDoc>( - Query.Find.byField tableName field, - addFieldParams [ { field with ParameterName = Some "@field" } ] [], - fromData<'TDoc>, - conn) + Query.Find.byFields tableName howMatched fields, addFieldParams fields [], fromData<'TDoc>, conn) + + /// Retrieve documents via a comparison on a JSON field + [] + let ByField<'TDoc>(tableName, field, conn) = + ByFields<'TDoc>(tableName, Any, [ field ], conn) - /// Retrieve documents via a comparison on a JSON field, returning only the first result - [] - let firstByField<'TDoc> tableName field conn = + /// Retrieve documents via a comparison on JSON fields, returning only the first result + [] + let firstByFields<'TDoc> tableName howMatched fields conn = Custom.single - $"{Query.Find.byField tableName field} LIMIT 1" - (addFieldParams [ { field with ParameterName = Some "@field" } ] []) + $"{Query.Find.byFields tableName howMatched fields} LIMIT 1" + (addFieldParams fields []) 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) = + [] + [] + let firstByField<'TDoc> tableName field conn = + firstByFields<'TDoc> tableName Any [ field ] conn + + /// Retrieve documents via a comparison on JSON fields, returning only the first result + let FirstByFields<'TDoc when 'TDoc: null>(tableName, howMatched, fields, conn) = Custom.Single( - $"{Query.Find.byField tableName field} LIMIT 1", - addFieldParams [ { field with ParameterName = Some "@field" } ] [], + $"{Query.Find.byFields tableName howMatched fields} LIMIT 1", + addFieldParams fields [], 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) = + FirstByFields(tableName, Any, [ field ], conn) /// Commands to update documents [] @@ -492,40 +518,47 @@ module WithConn = let byId tableName (docId: 'TKey) (patch: 'TPatch) conn = Custom.nonQuery (Query.Patch.byId tableName) [ idParam docId; jsonParam "@data" patch ] conn + /// Patch documents using a comparison on JSON fields + [] + let byFields tableName howMatched fields (patch: 'TPatch) conn = + Custom.nonQuery + (Query.Patch.byFields tableName howMatched fields) + (addFieldParams fields [ jsonParam "@data" patch ]) + conn + /// Patch documents using a comparison on a JSON field [] - let byField tableName field (patch: 'TPatch) (conn: SqliteConnection) = - Custom.nonQuery - (Query.Patch.byField tableName field) - (addFieldParams [ { field with ParameterName = Some "@field" } ] [ jsonParam "@data" patch ]) - conn + [] + let byField tableName field (patch: 'TPatch) conn = + byFields tableName Any [ field ] patch conn /// Commands to remove fields from documents [] module RemoveFields = /// 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 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.RemoveFields.byField tableName field nameParams) - (addFieldParams [ { field with ParameterName = Some "@field" } ] nameParams) + (Query.RemoveFields.byId tableName nameParams) + (idParam docId |> Seq.singleton |> Seq.append nameParams) conn + /// Remove fields from documents via a comparison on JSON fields in the document + [] + let byFields tableName howMatched fields fieldNames conn = + let nameParams = fieldNameParams "@name" fieldNames + Custom.nonQuery + (Query.RemoveFields.byFields tableName howMatched fields nameParams) + (addFieldParams fields 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 + [] + [] + let byField tableName field fieldNames conn = + byFields tableName Any [ field ] fieldNames conn /// Commands to delete documents [] @@ -535,14 +568,17 @@ module WithConn = [] let byId tableName (docId: 'TKey) conn = Custom.nonQuery (Query.Delete.byId tableName) [ idParam docId ] conn - + + /// Delete documents by matching a comparison on JSON fields + [] + let byFields tableName howMatched fields conn = + Custom.nonQuery (Query.Delete.byFields tableName howMatched fields) (addFieldParams fields []) conn + /// Delete documents by matching a comparison on a JSON field [] + [] let byField tableName field conn = - Custom.nonQuery - (Query.Delete.byField tableName field) - (addFieldParams [ { field with ParameterName = Some "@field" } ] []) - conn + byFields tableName Any [ field ] conn /// Commands to execute custom SQL queries @@ -630,11 +666,17 @@ module Count = use conn = Configuration.dbConn () WithConn.Count.all tableName conn + /// Count matching documents using a comparison on JSON fields + [] + let byFields tableName howMatched fields = + use conn = Configuration.dbConn () + WithConn.Count.byFields tableName howMatched fields conn + /// Count matching documents using a comparison on a JSON field [] + [] let byField tableName field = - use conn = Configuration.dbConn () - WithConn.Count.byField tableName field conn + byFields tableName Any [ field ] /// Commands to determine if documents exist [] @@ -645,12 +687,18 @@ module Exists = let byId tableName (docId: 'TKey) = use conn = Configuration.dbConn () WithConn.Exists.byId tableName docId conn - + + /// Determine if a document exists using a comparison on JSON fields + [] + let byFields tableName howMatched fields = + use conn = Configuration.dbConn () + WithConn.Exists.byFields tableName howMatched fields conn + /// Determine if a document exists using a comparison on a JSON field [] + [] let byField tableName field = - use conn = Configuration.dbConn () - WithConn.Exists.byField tableName field conn + byFields tableName Any [ field ] /// Commands to determine if documents exist [] @@ -678,27 +726,49 @@ module Find = use conn = Configuration.dbConn () WithConn.Find.ById<'TKey, 'TDoc>(tableName, docId, conn) + /// Retrieve documents via a comparison on JSON fields + [] + let byFields<'TDoc> tableName howMatched fields = + use conn = Configuration.dbConn () + WithConn.Find.byFields<'TDoc> tableName howMatched fields conn + /// Retrieve documents via a comparison on a JSON field [] + [] let byField<'TDoc> tableName field = + byFields tableName Any [ field ] + + /// Retrieve documents via a comparison on JSON fields + let ByFields<'TDoc>(tableName, howMatched, fields) = use conn = Configuration.dbConn () - WithConn.Find.byField<'TDoc> tableName field conn - + WithConn.Find.ByFields<'TDoc>(tableName, howMatched, fields, conn) + /// Retrieve documents via a comparison on a JSON field + [] let ByField<'TDoc>(tableName, field) = - use conn = Configuration.dbConn () - WithConn.Find.ByField<'TDoc>(tableName, field, conn) + ByFields<'TDoc>(tableName, Any, [ field ]) + /// Retrieve documents via a comparison on JSON fields, returning only the first result + [] + let firstByFields<'TDoc> tableName howMatched fields = + use conn = Configuration.dbConn () + WithConn.Find.firstByFields<'TDoc> tableName howMatched fields conn + /// Retrieve documents via a comparison on a JSON field, returning only the first result [] + [] let firstByField<'TDoc> tableName field = + firstByFields<'TDoc> tableName Any [ field ] + + /// Retrieve documents via a comparison on JSON fields, returning only the first result + let FirstByFields<'TDoc when 'TDoc: null>(tableName, howMatched, fields) = use conn = Configuration.dbConn () - WithConn.Find.firstByField<'TDoc> tableName field conn - + WithConn.Find.FirstByFields<'TDoc>(tableName, howMatched, fields, conn) + /// Retrieve documents via a comparison on a JSON field, returning only the first result + [] let FirstByField<'TDoc when 'TDoc: null>(tableName, field) = - use conn = Configuration.dbConn () - WithConn.Find.FirstByField<'TDoc>(tableName, field, conn) + FirstByFields<'TDoc>(tableName, Any, [ field ]) /// Commands to update documents [] @@ -731,37 +801,39 @@ module Patch = use conn = Configuration.dbConn () WithConn.Patch.byId tableName docId patch conn + /// Patch documents using a comparison on JSON fields in the WHERE clause + [] + let byFields tableName howMatched fields (patch: 'TPatch) = + use conn = Configuration.dbConn () + WithConn.Patch.byFields tableName howMatched fields patch conn + /// Patch documents using a comparison on a JSON field in the WHERE clause [] + [] let byField tableName field (patch: 'TPatch) = - use conn = Configuration.dbConn () - WithConn.Patch.byField tableName field patch conn + byFields tableName Any [ field ] patch /// Commands to remove fields from documents [] module RemoveFields = /// Remove fields from a document by the document's ID - [] + [] let byId tableName (docId: 'TKey) fieldNames = use conn = Configuration.dbConn () WithConn.RemoveFields.byId tableName docId fieldNames conn - - /// Remove fields from a document by the document's ID - let ById(tableName, docId: 'TKey, fieldNames) = + + /// Remove field from documents via a comparison on JSON fields in the document + [] + let byFields tableName howMatched fields fieldNames = use conn = Configuration.dbConn () - WithConn.RemoveFields.ById(tableName, docId, fieldNames, conn) + WithConn.RemoveFields.byFields tableName howMatched fields 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) + byFields tableName Any [ field ] fieldNames /// Commands to delete documents [] @@ -772,9 +844,15 @@ module Delete = let byId tableName (docId: 'TKey) = use conn = Configuration.dbConn () WithConn.Delete.byId tableName docId conn - + + /// Delete documents by matching a comparison on JSON fields + [] + let byFields tableName howMatched fields = + use conn = Configuration.dbConn () + WithConn.Delete.byFields tableName howMatched fields conn + /// Delete documents by matching a comparison on a JSON field [] + [] let byField tableName field = - use conn = Configuration.dbConn () - WithConn.Delete.byField tableName field conn + byFields tableName Any [ field ] diff --git a/src/Tests.CSharp/PostgresCSharpTests.cs b/src/Tests.CSharp/PostgresCSharpTests.cs index 7bf446d..ddd9875 100644 --- a/src/Tests.CSharp/PostgresCSharpTests.cs +++ b/src/Tests.CSharp/PostgresCSharpTests.cs @@ -118,7 +118,6 @@ public static class PostgresCSharpTests Expect.isTrue(it[1].Item2.IsParameter, "Maximum field parameter value incorrect"); }) ]), -#pragma warning restore CS0618 TestList("FieldName", [ TestCase("succeeds for one name", () => @@ -140,6 +139,7 @@ public static class PostgresCSharpTests } }) ]) +#pragma warning restore CS0618 ]), TestList("Query", [ diff --git a/src/Tests.CSharp/SqliteCSharpExtensionTests.cs b/src/Tests.CSharp/SqliteCSharpExtensionTests.cs index 3501695..87ceeea 100644 --- a/src/Tests.CSharp/SqliteCSharpExtensionTests.cs +++ b/src/Tests.CSharp/SqliteCSharpExtensionTests.cs @@ -18,10 +18,10 @@ public static class SqliteCSharpExtensionTests /// Integration tests for the SQLite extension methods /// [Tests] - public static readonly Test Integration = TestList("Sqlite.C#.Extensions", new[] - { - TestList("CustomSingle", new[] - { + public static readonly Test Integration = TestList("Sqlite.C#.Extensions", + [ + TestList("CustomSingle", + [ TestCase("succeeds when a row is found", async () => { await using var db = await SqliteDb.BuildDb(); @@ -43,9 +43,9 @@ public static class SqliteCSharpExtensionTests new[] { Parameters.Id("eighty") }, Results.FromData); Expect.isNull(doc, "There should not have been a document returned"); }) - }), - TestList("CustomList", new[] - { + ]), + TestList("CustomList", + [ TestCase("succeeds when data is found", async () => { await using var db = await SqliteDb.BuildDb(); @@ -67,9 +67,9 @@ public static class SqliteCSharpExtensionTests new[] { new SqliteParameter("@value", 100) }, Results.FromData); Expect.isEmpty(docs, "There should have been no documents returned"); }) - }), - TestList("CustomNonQuery", new[] - { + ]), + TestList("CustomNonQuery", + [ TestCase("succeeds when operating on data", async () => { await using var db = await SqliteDb.BuildDb(); @@ -93,7 +93,7 @@ public static class SqliteCSharpExtensionTests var remaining = await conn.CountAll(SqliteDb.TableName); Expect.equal(remaining, 5L, "There should be 5 documents remaining in the table"); }) - }), + ]), TestCase("CustomScalar succeeds", async () => { await using var db = await SqliteDb.BuildDb(); @@ -140,8 +140,8 @@ public static class SqliteCSharpExtensionTests exists = await indexExists(); Expect.isTrue(exists, "The index should now exist"); }), - TestList("Insert", new[] - { + TestList("Insert", + [ TestCase("succeeds", async () => { await using var db = await SqliteDb.BuildDb(); @@ -168,9 +168,9 @@ public static class SqliteCSharpExtensionTests // This is what is supposed to happen } }) - }), - TestList("Save", new[] - { + ]), + TestList("Save", + [ TestCase("succeeds when a document is inserted", async () => { await using var db = await SqliteDb.BuildDb(); @@ -203,7 +203,7 @@ public static class SqliteCSharpExtensionTests Expect.equal(after!.Id, "test", "The updated document is not correct"); Expect.isNull(after.Sub, "There should not have been a sub-document in the updated document"); }) - }), + ]), TestCase("CountAll succeeds", async () => { await using var db = await SqliteDb.BuildDb(); @@ -213,6 +213,7 @@ 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(); @@ -222,8 +223,9 @@ public static class SqliteCSharpExtensionTests var theCount = await conn.CountByField(SqliteDb.TableName, Field.EQ("Value", "purple")); Expect.equal(theCount, 2L, "There should have been 2 matching documents"); }), - TestList("ExistsById", new[] - { +#pragma warning restore CS0618 + TestList("ExistsById", + [ TestCase("succeeds when a document exists", async () => { await using var db = await SqliteDb.BuildDb(); @@ -242,9 +244,10 @@ public static class SqliteCSharpExtensionTests var exists = await conn.ExistsById(SqliteDb.TableName, "seven"); Expect.isFalse(exists, "There should not have been an existing document"); }) - }), - TestList("ExistsByField", new[] - { + ]), +#pragma warning disable CS0618 + TestList("ExistsByField", + [ TestCase("succeeds when documents exist", async () => { await using var db = await SqliteDb.BuildDb(); @@ -263,9 +266,10 @@ public static class SqliteCSharpExtensionTests var exists = await conn.ExistsByField(SqliteDb.TableName, Field.EQ("Nothing", "none")); Expect.isFalse(exists, "There should not have been any existing documents"); }) - }), - TestList("FindAll", new[] - { + ]), +#pragma warning restore CS0618 + TestList("FindAll", + [ TestCase("succeeds when there is data", async () => { await using var db = await SqliteDb.BuildDb(); @@ -285,9 +289,9 @@ public static class SqliteCSharpExtensionTests var results = await conn.FindAll(SqliteDb.TableName); Expect.isEmpty(results, "There should have been no documents returned"); }) - }), - TestList("FindById", new[] - { + ]), + TestList("FindById", + [ TestCase("succeeds when a document is found", async () => { await using var db = await SqliteDb.BuildDb(); @@ -307,9 +311,10 @@ public static class SqliteCSharpExtensionTests var doc = await conn.FindById(SqliteDb.TableName, "eighty-seven"); Expect.isNull(doc, "There should not have been a document returned"); }) - }), - TestList("FindByField", new[] - { + ]), +#pragma warning disable CS0618 + TestList("FindByField", + [ TestCase("succeeds when documents are found", async () => { await using var db = await SqliteDb.BuildDb(); @@ -328,9 +333,9 @@ public static class SqliteCSharpExtensionTests var docs = await conn.FindByField(SqliteDb.TableName, Field.EQ("Value", "mauve")); Expect.isEmpty(docs, "There should have been no documents returned"); }) - }), - TestList("FindFirstByField", new[] - { + ]), + TestList("FindFirstByField", + [ TestCase("succeeds when a document is found", async () => { await using var db = await SqliteDb.BuildDb(); @@ -360,9 +365,10 @@ public static class SqliteCSharpExtensionTests var doc = await conn.FindFirstByField(SqliteDb.TableName, Field.EQ("Value", "absent")); Expect.isNull(doc, "There should not have been a document returned"); }) - }), - TestList("UpdateById", new[] - { + ]), +#pragma warning restore CS0618 + TestList("UpdateById", + [ TestCase("succeeds when a document is updated", async () => { await using var db = await SqliteDb.BuildDb(); @@ -389,9 +395,9 @@ public static class SqliteCSharpExtensionTests await conn.UpdateById(SqliteDb.TableName, "test", new JsonDocument { Id = "x", Sub = new() { Foo = "blue", Bar = "red" } }); }) - }), - TestList("UpdateByFunc", new[] - { + ]), + TestList("UpdateByFunc", + [ TestCase("succeeds when a document is updated", async () => { await using var db = await SqliteDb.BuildDb(); @@ -418,9 +424,9 @@ public static class SqliteCSharpExtensionTests await conn.UpdateByFunc(SqliteDb.TableName, doc => doc.Id, new JsonDocument { Id = "one", Value = "le un", NumValue = 1 }); }) - }), - TestList("PatchById", new[] - { + ]), + TestList("PatchById", + [ TestCase("succeeds when a document is updated", async () => { await using var db = await SqliteDb.BuildDb(); @@ -443,9 +449,10 @@ public static class SqliteCSharpExtensionTests // This not raising an exception is the test await conn.PatchById(SqliteDb.TableName, "test", new { Foo = "green" }); }) - }), - TestList("PatchByField", new[] - { + ]), +#pragma warning disable CS0618 + TestList("PatchByField", + [ TestCase("succeeds when a document is updated", async () => { await using var db = await SqliteDb.BuildDb(); @@ -466,9 +473,10 @@ public static class SqliteCSharpExtensionTests // This not raising an exception is the test await conn.PatchByField(SqliteDb.TableName, Field.EQ("Value", "burgundy"), new { Foo = "green" }); }) - }), - TestList("RemoveFieldsById", new[] - { + ]), +#pragma warning restore CS0618 + TestList("RemoveFieldsById", + [ TestCase("succeeds when fields are removed", async () => { await using var db = await SqliteDb.BuildDb(); @@ -498,9 +506,10 @@ public static class SqliteCSharpExtensionTests // This not raising an exception is the test await conn.RemoveFieldsById(SqliteDb.TableName, "two", new[] { "Value" }); }) - }), - TestList("RemoveFieldsByField", new[] - { + ]), +#pragma warning disable CS0618 + TestList("RemoveFieldsByField", + [ TestCase("succeeds when a field is removed", async () => { await using var db = await SqliteDb.BuildDb(); @@ -529,9 +538,10 @@ public static class SqliteCSharpExtensionTests // This not raising an exception is the test await conn.RemoveFieldsByField(SqliteDb.TableName, Field.NE("Abracadabra", "apple"), new[] { "Value" }); }) - }), - TestList("DeleteById", new[] - { + ]), +#pragma warning restore CS0618 + TestList("DeleteById", + [ TestCase("succeeds when a document is deleted", async () => { await using var db = await SqliteDb.BuildDb(); @@ -552,9 +562,10 @@ public static class SqliteCSharpExtensionTests var remaining = await conn.CountAll(SqliteDb.TableName); Expect.equal(remaining, 5L, "There should have been 5 documents remaining"); }) - }), - TestList("DeleteByField", new[] - { + ]), +#pragma warning disable CS0618 + TestList("DeleteByField", + [ TestCase("succeeds when documents are deleted", async () => { await using var db = await SqliteDb.BuildDb(); @@ -575,7 +586,8 @@ public static class SqliteCSharpExtensionTests 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 3b9ac72..cac780c 100644 --- a/src/Tests.CSharp/SqliteCSharpTests.cs +++ b/src/Tests.CSharp/SqliteCSharpTests.cs @@ -63,6 +63,7 @@ public static class SqliteCSharpTests "WHERE clause not correct"); }) ]), +#pragma warning disable CS0618 TestList("WhereByField", [ TestCase("succeeds when a logical operator is passed", () => @@ -81,6 +82,7 @@ public static class SqliteCSharpTests "data->>'aField' BETWEEN @rangemin AND @rangemax", "WHERE clause not correct"); }) ]), +#pragma warning restore CS0618 TestCase("WhereById succeeds", () => { Expect.equal(Sqlite.Query.WhereById("@id"), "data->>'Id' = @id", "WHERE clause not correct"); @@ -102,12 +104,14 @@ public static class SqliteCSharpTests Expect.equal(Sqlite.Query.Count.All("tbl"), "SELECT COUNT(*) AS it FROM tbl", "Count query not correct"); }), +#pragma warning disable CS0618 TestCase("ByField succeeds", () => { Expect.equal(Sqlite.Query.Count.ByField("tbl", Field.EQ("thatField", 0)), - "SELECT COUNT(*) AS it FROM tbl WHERE data->>'thatField' = @field", + "SELECT COUNT(*) AS it FROM tbl WHERE data->>'thatField' = @field0", "JSON field text comparison count query not correct"); }) +#pragma warning restore CS0618 ]), TestList("Exists", [ @@ -117,12 +121,14 @@ public static class SqliteCSharpTests "SELECT EXISTS (SELECT 1 FROM tbl WHERE data->>'Id' = @id) AS it", "ID existence query not correct"); }), +#pragma warning disable CS0618 TestCase("ByField succeeds", () => { Expect.equal(Sqlite.Query.Exists.ByField("tbl", Field.LT("Test", 0)), - "SELECT EXISTS (SELECT 1 FROM tbl WHERE data->>'Test' < @field) AS it", + "SELECT EXISTS (SELECT 1 FROM tbl WHERE data->>'Test' < @field0) AS it", "JSON field text comparison exists query not correct"); }) +#pragma warning restore CS0618 ]), TestList("Find", [ @@ -131,12 +137,14 @@ public static class SqliteCSharpTests Expect.equal(Sqlite.Query.Find.ById("tbl"), "SELECT data FROM tbl WHERE data->>'Id' = @id", "SELECT by ID query not correct"); }), +#pragma warning disable CS0618 TestCase("ByField succeeds", () => { Expect.equal(Sqlite.Query.Find.ByField("tbl", Field.GE("Golf", 0)), - "SELECT data FROM tbl WHERE data->>'Golf' >= @field", + "SELECT data FROM tbl WHERE data->>'Golf' >= @field0", "SELECT by JSON comparison query not correct"); }) +#pragma warning restore CS0618 ]), TestList("Patch", [ @@ -146,12 +154,14 @@ public static class SqliteCSharpTests "UPDATE tbl SET data = json_patch(data, json(@data)) WHERE data->>'Id' = @id", "UPDATE partial by ID statement not correct"); }), +#pragma warning disable CS0618 TestCase("ByField succeeds", () => { Expect.equal(Sqlite.Query.Patch.ByField("tbl", Field.NE("Part", 0)), - "UPDATE tbl SET data = json_patch(data, json(@data)) WHERE data->>'Part' <> @field", + "UPDATE tbl SET data = json_patch(data, json(@data)) WHERE data->>'Part' <> @field0", "UPDATE partial by JSON comparison query not correct"); }) +#pragma warning restore CS0618 ]), TestList("RemoveFields", [ @@ -161,13 +171,15 @@ public static class SqliteCSharpTests "UPDATE tbl SET data = json_remove(data, @name) WHERE data->>'Id' = @id", "Remove field by ID query not correct"); }), +#pragma warning disable CS0618 TestCase("ByField succeeds", () => { Expect.equal(Sqlite.Query.RemoveFields.ByField("tbl", Field.LT("Fly", 0), new[] { new SqliteParameter("@name0", "one"), new SqliteParameter("@name1", "two") }), - "UPDATE tbl SET data = json_remove(data, @name0, @name1) WHERE data->>'Fly' < @field", + "UPDATE tbl SET data = json_remove(data, @name0, @name1) WHERE data->>'Fly' < @field0", "Remove field by field query not correct"); }) +#pragma warning restore CS0618 ]), TestList("Delete", [ @@ -176,11 +188,13 @@ public static class SqliteCSharpTests Expect.equal(Sqlite.Query.Delete.ById("tbl"), "DELETE FROM tbl WHERE data->>'Id' = @id", "DELETE by ID query not correct"); }), +#pragma warning disable CS0618 TestCase("ByField succeeds", () => { Expect.equal(Sqlite.Query.Delete.ByField("tbl", Field.NEX("gone")), "DELETE FROM tbl WHERE data->>'gone' IS NULL", "DELETE by JSON comparison query not correct"); }) +#pragma warning restore CS0618 ]) ]), TestList("Parameters", @@ -197,6 +211,7 @@ public static class SqliteCSharpTests Expect.equal(theParam.ParameterName, "@test", "The parameter name is incorrect"); Expect.equal(theParam.Value, "{\"Nice\":\"job\"}", "The parameter value is incorrect"); }), +#pragma warning disable CS0618 TestCase("AddField succeeds when adding a parameter", () => { var paramList = Parameters.AddField("@field", Field.EQ("it", 99), []).ToList(); @@ -210,6 +225,7 @@ public static class SqliteCSharpTests var paramSeq = Parameters.AddField("@it", Field.EX("Coffee"), []); Expect.isEmpty(paramSeq, "There should not have been any parameters added"); }), +#pragma warning restore CS0618 TestCase("None succeeds", () => { Expect.isEmpty(Parameters.None, "The parameter list should have been empty"); @@ -442,6 +458,7 @@ public static class SqliteCSharpTests var theCount = await Count.All(SqliteDb.TableName); Expect.equal(theCount, 5L, "There should have been 5 matching documents"); }), +#pragma warning disable CS0618 TestCase("ByField succeeds for numeric range", async () => { await using var db = await SqliteDb.BuildDb(); @@ -458,6 +475,7 @@ public static class SqliteCSharpTests var theCount = await Count.ByField(SqliteDb.TableName, Field.BT("Value", "aardvark", "apple")); Expect.equal(theCount, 1L, "There should have been 1 matching document"); }) +#pragma warning restore CS0618 ]), TestList("Exists", [ @@ -480,6 +498,7 @@ public static class SqliteCSharpTests Expect.isFalse(exists, "There should not have been an existing document"); }) ]), +#pragma warning disable CS0618 TestList("ByField", [ TestCase("succeeds when documents exist", async () => @@ -499,6 +518,7 @@ public static class SqliteCSharpTests Expect.isFalse(exists, "There should not have been any existing documents"); }) ]) +#pragma warning restore CS0618 ]), TestList("Find", [ @@ -542,6 +562,7 @@ public static class SqliteCSharpTests Expect.isNull(doc, "There should not have been a document returned"); }) ]), +#pragma warning disable CS0618 TestList("ByField", [ TestCase("succeeds when documents are found", async () => @@ -590,6 +611,7 @@ public static class SqliteCSharpTests Expect.isNull(doc, "There should not have been a document returned"); }) ]) +#pragma warning restore CS0618 ]), TestList("Update", [ @@ -676,6 +698,7 @@ public static class SqliteCSharpTests await Patch.ById(SqliteDb.TableName, "test", new { Foo = "green" }); }) ]), +#pragma warning disable CS0618 TestList("ByField", [ TestCase("succeeds when a document is updated", async () => @@ -698,6 +721,7 @@ public static class SqliteCSharpTests await Patch.ByField(SqliteDb.TableName, Field.EQ("Value", "burgundy"), new { Foo = "green" }); }) ]) +#pragma warning restore CS0618 ]), TestList("RemoveFields", [ @@ -730,6 +754,7 @@ public static class SqliteCSharpTests await RemoveFields.ById(SqliteDb.TableName, "two", new[] { "Value" }); }) ]), +#pragma warning disable CS0618 TestList("ByField", [ TestCase("succeeds when a field is removed", async () => @@ -758,6 +783,7 @@ public static class SqliteCSharpTests await RemoveFields.ByField(SqliteDb.TableName, Field.NE("Abracadabra", "apple"), new[] { "Value" }); }) ]) +#pragma warning restore CS0618 ]), TestList("Delete", [ @@ -782,6 +808,7 @@ public static class SqliteCSharpTests Expect.equal(remaining, 5L, "There should have been 5 documents remaining"); }) ]), +#pragma warning disable CS0618 TestList("ByField", [ TestCase("succeeds when documents are deleted", async () => @@ -803,6 +830,7 @@ public static class SqliteCSharpTests 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/SqliteTests.fs b/src/Tests/SqliteTests.fs index 733d1d8..4fd7b75 100644 --- a/src/Tests/SqliteTests.fs +++ b/src/Tests/SqliteTests.fs @@ -94,7 +94,7 @@ let unitTests = test "byField succeeds" { Expect.equal (Query.Count.byField "tbl" (Field.EQ "thatField" 0)) - "SELECT COUNT(*) AS it FROM tbl WHERE data->>'thatField' = @field" + "SELECT COUNT(*) AS it FROM tbl WHERE data->>'thatField' = @field0" "JSON field text comparison count query not correct" } ] @@ -108,7 +108,7 @@ let unitTests = test "byField succeeds" { Expect.equal (Query.Exists.byField "tbl" (Field.LT "Test" 0)) - "SELECT EXISTS (SELECT 1 FROM tbl WHERE data->>'Test' < @field) AS it" + "SELECT EXISTS (SELECT 1 FROM tbl WHERE data->>'Test' < @field0) AS it" "JSON field text comparison exists query not correct" } ] @@ -122,7 +122,7 @@ let unitTests = test "byField succeeds" { Expect.equal (Query.Find.byField "tbl" (Field.GE "Golf" 0)) - "SELECT data FROM tbl WHERE data->>'Golf' >= @field" + "SELECT data FROM tbl WHERE data->>'Golf' >= @field0" "SELECT by JSON comparison query not correct" } ] @@ -136,7 +136,7 @@ let unitTests = test "byField succeeds" { Expect.equal (Query.Patch.byField "tbl" (Field.NE "Part" 0)) - "UPDATE tbl SET data = json_patch(data, json(@data)) WHERE data->>'Part' <> @field" + "UPDATE tbl SET data = json_patch(data, json(@data)) WHERE data->>'Part' <> @field0" "UPDATE partial by JSON comparison query not correct" } ] @@ -153,7 +153,7 @@ let unitTests = "tbl" (Field.GT "Fly" 0) [ SqliteParameter("@name0", "one"); SqliteParameter("@name1", "two") ]) - "UPDATE tbl SET data = json_remove(data, @name0, @name1) WHERE data->>'Fly' > @field" + "UPDATE tbl SET data = json_remove(data, @name0, @name1) WHERE data->>'Fly' > @field0" "Remove field by field query not correct" } ] @@ -187,7 +187,7 @@ let unitTests = test "succeeds when adding a parameter" { let paramList = addFieldParam "@field" (Field.EQ "it" 99) [] Expect.hasLength paramList 1 "There should have been a parameter added" - let theParam = paramList[0] + let theParam = Seq.head paramList Expect.equal theParam.ParameterName "@field" "The parameter name is incorrect" Expect.equal theParam.Value 99 "The parameter value is incorrect" }