Prefer seq over list for parameters

- This greatly reduces the duplicated functions needed
between F# and C#; F# lists satisfy the sequence reqs
This commit is contained in:
Daniel J. Summers 2024-08-08 17:32:44 -04:00
parent 8a15bdce2e
commit 202fca272e
7 changed files with 354 additions and 246 deletions

View File

@ -260,7 +260,7 @@ type NpgsqlConnectionCSharpExtensions =
/// Count matching documents using a JSON field comparison query (->> =)
[<Extension>]
static member inline CountByFields(conn, tableName, howMatched, fields) =
WithProps.Count.ByFields(tableName, howMatched, fields, Sql.existingConnection conn)
WithProps.Count.byFields tableName howMatched fields (Sql.existingConnection conn)
/// Count matching documents using a JSON field comparison query (->> =)
[<Extension>]
@ -286,7 +286,7 @@ type NpgsqlConnectionCSharpExtensions =
/// Determine if documents exist using a JSON field comparison query (->> =)
[<Extension>]
static member inline ExistsByFields(conn, tableName, howMatched, fields) =
WithProps.Exists.ByFields(tableName, howMatched, fields, Sql.existingConnection conn)
WithProps.Exists.byFields tableName howMatched fields (Sql.existingConnection conn)
/// Determine if documents exist using a JSON field comparison query (->> =)
[<Extension>]
@ -374,7 +374,7 @@ type NpgsqlConnectionCSharpExtensions =
/// Patch documents using a JSON field comparison query in the WHERE clause (->> =)
[<Extension>]
static member inline PatchByFields(conn, tableName, howMatched, fields, patch: 'TPatch) =
WithProps.Patch.ByFields(tableName, howMatched, fields, patch, Sql.existingConnection conn)
WithProps.Patch.byFields tableName howMatched fields patch (Sql.existingConnection conn)
/// Patch documents using a JSON field comparison query in the WHERE clause (->> =)
[<Extension>]
@ -400,13 +400,13 @@ type NpgsqlConnectionCSharpExtensions =
/// Remove fields from documents via a comparison on JSON fields in the document
[<Extension>]
static member inline RemoveFieldsByFields(conn, tableName, howMatched, fields, fieldNames) =
WithProps.RemoveFields.ByFields(tableName, howMatched, fields, fieldNames, Sql.existingConnection conn)
WithProps.RemoveFields.byFields tableName howMatched fields fieldNames (Sql.existingConnection conn)
/// Remove fields from documents via a comparison on a JSON field in the document
[<Extension>]
[<System.Obsolete "Use RemoveFieldsByFields instead; will be removed in v4">]
static member inline RemoveFieldsByField(conn, tableName, field, fieldNames) =
WithProps.RemoveFields.ByField(tableName, field, fieldNames, Sql.existingConnection conn)
WithProps.RemoveFields.byField tableName field fieldNames (Sql.existingConnection conn)
/// Remove fields from documents via a JSON containment query (@>)
[<Extension>]
@ -426,7 +426,7 @@ type NpgsqlConnectionCSharpExtensions =
/// Delete documents by matching a JSON field comparison query (->> =)
[<Extension>]
static member inline DeleteByFields(conn, tableName, howMatched, fields) =
WithProps.Delete.ByFields(tableName, howMatched, fields, Sql.existingConnection conn)
WithProps.Delete.byFields tableName howMatched fields (Sql.existingConnection conn)
/// Delete documents by matching a JSON field comparison query (->> =)
[<Extension>]

View File

@ -63,8 +63,9 @@ module Parameters =
let jsonParam (name: string) (it: 'TJson) =
name, Sql.jsonb (Configuration.serializer().Serialize it)
/// Convert the fields to their parameters
let private convertFieldsToParameters fields =
/// Create JSON field parameters
[<CompiledName "AddFields">]
let addFieldParams fields parameters =
let name = ParameterName()
fields
|> Seq.map (fun it ->
@ -80,39 +81,20 @@ module Parameters =
let p = name.Derive it.ParameterName
yield (p, Sql.parameter (NpgsqlParameter(p, it.Value))) })
|> Seq.collect id
/// Create JSON field parameters
[<CompiledName "FSharpAddFields">]
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
[<CompiledName "FSharpAddField">]
[<System.Obsolete "Use addFieldParams instead; will be removed in v4">]
[<CompiledName "AddField">]
[<System.Obsolete "Use addFieldParams (F#) / AddFields (C#) instead; will be removed in v4">]
let addFieldParam name field parameters =
addFieldParams [ { field with ParameterName = Some name } ] parameters
/// Create a JSON field parameter
[<System.Obsolete "Use AddFields instead; will be removed in v4">]
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
[<CompiledName "FSharpFieldName">]
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)
[<CompiledName "FieldName">]
let fieldNameParam (fieldNames: string seq) =
if Seq.length fieldNames = 1 then "@name", Sql.string (Seq.head fieldNames)
else "@name", Sql.stringArray (Array.ofSeq fieldNames)
/// An empty parameter sequence
@ -126,11 +108,11 @@ module Parameters =
module Query =
/// Create a WHERE clause fragment to implement a comparison on fields in a JSON document
[<CompiledName "FSharpWhereByFields">]
[<CompiledName "WhereByFields">]
let whereByFields howMatched fields =
let name = ParameterName()
fields
|> List.map (fun it ->
|> Seq.map (fun it ->
match it.Op with
| EX | NEX -> $"{it.PgSqlPath} {it.Op}"
| BT ->
@ -144,10 +126,6 @@ module Query =
| _ -> $"{it.PgSqlPath} {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
[<CompiledName "WhereByField">]
[<System.Obsolete "Use WhereByFields instead; will be removed in v4">]
@ -198,7 +176,7 @@ module Query =
$"SELECT COUNT(*) AS it FROM %s{tableName}"
/// Query to count matching documents using a text comparison on JSON fields
[<CompiledName "FSharpByFields">]
[<CompiledName "ByFields">]
let byFields tableName howMatched fields =
$"SELECT COUNT(*) AS it FROM %s{tableName} WHERE {whereByFields howMatched fields}"
@ -208,10 +186,6 @@ module Query =
let byField tableName field =
byFields tableName Any [ field ]
/// Query to count matching documents using a text comparison on JSON fields
let ByFields tableName howMatched fields =
byFields tableName howMatched (List.ofSeq fields)
/// Query to count matching documents using a JSON containment query (@>)
[<CompiledName "ByContains">]
let byContains tableName =
@ -231,7 +205,7 @@ module Query =
$"""SELECT EXISTS (SELECT 1 FROM %s{tableName} WHERE {whereById "@id"}) AS it"""
/// Query to determine if documents exist using a comparison on JSON fields
[<CompiledName "FSharpByFields">]
[<CompiledName "ByFields">]
let byFields tableName howMatched fields =
$"SELECT EXISTS (SELECT 1 FROM %s{tableName} WHERE {whereByFields howMatched fields}) AS it"
@ -241,10 +215,6 @@ module Query =
let byField tableName field =
byFields tableName Any [ field ]
/// Query to determine if documents exist using a comparison on JSON fields
let ByFields tableName howMatched fields =
byFields tableName howMatched (List.ofSeq fields)
/// Query to determine if documents exist using a JSON containment query (@>)
[<CompiledName "ByContains">]
let byContains tableName =
@ -264,7 +234,7 @@ module Query =
$"""{Query.selectFromTable tableName} WHERE {whereById "@id"}"""
/// Query to retrieve documents using a comparison on JSON fields
[<CompiledName "FSharpByFields">]
[<CompiledName "ByFields">]
let byFields tableName howMatched fields =
$"{Query.selectFromTable tableName} WHERE {whereByFields howMatched fields}"
@ -274,10 +244,6 @@ module Query =
let byField tableName field =
byFields tableName Any [ field ]
/// Query to retrieve documents using a comparison on JSON fields
let ByFields tableName howMatched fields =
byFields tableName howMatched (List.ofSeq fields)
/// Query to retrieve documents using a JSON containment query (@>)
[<CompiledName "ByContains">]
let byContains tableName =
@ -301,7 +267,7 @@ module Query =
whereById "@id" |> update tableName
/// Query to patch documents match JSON field comparisons (->> =)
[<CompiledName "FSharpByFields">]
[<CompiledName "ByFields">]
let byFields tableName howMatched fields =
whereByFields howMatched fields |> update tableName
@ -311,10 +277,6 @@ module Query =
let byField tableName field =
byFields tableName Any [ field ]
/// Query to patch documents match JSON field comparisons (->> =)
let ByFields tableName howMatched fields =
whereByFields howMatched (List.ofSeq fields) |> update tableName
/// Query to patch documents matching a JSON containment query (@>)
[<CompiledName "ByContains">]
let byContains tableName =
@ -338,7 +300,7 @@ module Query =
whereById "@id" |> update tableName
/// Query to remove fields from documents via a comparison on JSON fields within the document
[<CompiledName "FSharpByFields">]
[<CompiledName "ByFields">]
let byFields tableName howMatched fields =
whereByFields howMatched fields |> update tableName
@ -348,10 +310,6 @@ module Query =
let byField tableName field =
byFields tableName Any [ field ]
/// Query to remove fields from documents via a comparison on JSON fields within the document
let ByFields tableName howMatched fields =
whereByFields howMatched (List.ofSeq fields) |> update tableName
/// Query to patch documents matching a JSON containment query (@>)
[<CompiledName "ByContains">]
let byContains tableName =
@ -371,7 +329,7 @@ module Query =
$"""DELETE FROM %s{tableName} WHERE {whereById "@id"}"""
/// Query to delete documents using a comparison on JSON fields
[<CompiledName "FSharpByFields">]
[<CompiledName "ByFields">]
let byFields tableName howMatched fields =
$"DELETE FROM %s{tableName} WHERE {whereByFields howMatched fields}"
@ -381,10 +339,6 @@ module Query =
let byField tableName field =
byFields tableName Any [ field ]
/// Query to delete documents using a comparison on JSON fields
let ByFields tableName howMatched fields =
byFields tableName howMatched (List.ofSeq fields)
/// Query to delete documents using a JSON containment query (@>)
[<CompiledName "ByContains">]
let byContains tableName =
@ -424,6 +378,8 @@ module Results =
/// Versions of queries that accept SqlProps as the last parameter
module WithProps =
module FSharpList = Microsoft.FSharp.Collections.List
/// Commands to execute custom SQL queries
[<RequireQualifiedAccess>]
module Custom =
@ -432,12 +388,12 @@ module WithProps =
[<CompiledName "FSharpList">]
let list<'TDoc> query parameters (mapFunc: RowReader -> 'TDoc) sqlProps =
Sql.query query sqlProps
|> Sql.parameters parameters
|> Sql.parameters (List.ofSeq parameters)
|> Sql.executeAsync mapFunc
/// Execute a query that returns a list of results
let List<'TDoc>(query, parameters, mapFunc: System.Func<RowReader, 'TDoc>, sqlProps) = backgroundTask {
let! results = list<'TDoc> query (List.ofSeq parameters) mapFunc.Invoke sqlProps
let! results = list<'TDoc> query parameters mapFunc.Invoke sqlProps
return ResizeArray results
}
@ -451,7 +407,7 @@ module WithProps =
/// Execute a query that returns one or no results; returns null if not found
let Single<'TDoc when 'TDoc: null>(
query, parameters, mapFunc: System.Func<RowReader, 'TDoc>, sqlProps) = backgroundTask {
let! result = single<'TDoc> query (FSharp.Collections.List.ofSeq parameters) mapFunc.Invoke sqlProps
let! result = single<'TDoc> query parameters mapFunc.Invoke sqlProps
return Option.toObj result
}
@ -459,7 +415,7 @@ module WithProps =
[<CompiledName "NonQuery">]
let nonQuery query parameters sqlProps =
Sql.query query sqlProps
|> Sql.parameters (FSharp.Collections.List.ofSeq parameters)
|> Sql.parameters (FSharpList.ofSeq parameters)
|> Sql.executeNonQueryAsync
|> ignoreTask
@ -467,12 +423,12 @@ module WithProps =
[<CompiledName "FSharpScalar">]
let scalar<'T when 'T: struct> query parameters (mapFunc: RowReader -> 'T) sqlProps =
Sql.query query sqlProps
|> Sql.parameters parameters
|> Sql.parameters (FSharpList.ofSeq parameters)
|> Sql.executeRowAsync mapFunc
/// Execute a query that returns a scalar value
let Scalar<'T when 'T: struct>(query, parameters, mapFunc: System.Func<RowReader, 'T>, sqlProps) =
scalar<'T> query (FSharp.Collections.List.ofSeq parameters) mapFunc.Invoke sqlProps
scalar<'T> query parameters mapFunc.Invoke sqlProps
/// Table and index definition commands
module Definition =
@ -518,7 +474,7 @@ module WithProps =
Custom.scalar (Query.Count.all tableName) [] toCount sqlProps
/// Count matching documents using JSON field comparisons (->> =)
[<CompiledName "FSharpByFields">]
[<CompiledName "ByFields">]
let byFields tableName howMatched fields sqlProps =
Custom.scalar (Query.Count.byFields tableName howMatched fields) (addFieldParams fields []) toCount sqlProps
@ -528,10 +484,6 @@ module WithProps =
let byField tableName field sqlProps =
byFields tableName Any [ field ] sqlProps
/// Count matching documents using JSON field comparisons (->> =)
let ByFields(tableName, howMatched, fields, sqlProps) =
Custom.Scalar(Query.Count.ByFields tableName howMatched fields, AddFields fields [], toCount, sqlProps)
/// Count matching documents using a JSON containment query (@>)
[<CompiledName "ByContains">]
let byContains tableName (criteria: 'TContains) sqlProps =
@ -552,7 +504,7 @@ module WithProps =
Custom.scalar (Query.Exists.byId tableName) [ idParam docId ] toExists sqlProps
/// Determine if a document exists using JSON field comparisons (->> =)
[<CompiledName "FSharpByFields">]
[<CompiledName "ByFields">]
let byFields tableName howMatched fields sqlProps =
Custom.scalar
(Query.Exists.byFields tableName howMatched fields) (addFieldParams fields []) toExists sqlProps
@ -563,10 +515,6 @@ module WithProps =
let byField tableName field sqlProps =
byFields tableName Any [ field ] sqlProps
/// Determine if a document exists using JSON field comparisons (->> =)
let ByFields(tableName, howMatched, fields, sqlProps) =
Custom.Scalar(Query.Exists.ByFields tableName howMatched fields, AddFields fields [], toExists, sqlProps)
/// Determine if a document exists using a JSON containment query (@>)
[<CompiledName "ByContains">]
let byContains tableName (criteria: 'TContains) sqlProps =
@ -614,7 +562,7 @@ module WithProps =
/// Retrieve documents matching JSON field comparisons (->> =)
let ByFields<'TDoc>(tableName, howMatched, fields, sqlProps) =
Custom.List<'TDoc>(
Query.Find.ByFields tableName howMatched fields, AddFields fields [], fromData<'TDoc>, sqlProps)
Query.Find.byFields tableName howMatched fields, addFieldParams fields [], fromData<'TDoc>, sqlProps)
/// Retrieve documents matching a JSON field comparison (->> =)
[<System.Obsolete "Use ByFields instead; will be removed in v4">]
@ -661,8 +609,8 @@ module WithProps =
/// Retrieve the first document matching JSON field comparisons (->> =); returns null if not found
let FirstByFields<'TDoc when 'TDoc: null>(tableName, howMatched, fields, sqlProps) =
Custom.Single<'TDoc>(
$"{Query.Find.ByFields tableName howMatched fields} LIMIT 1",
AddFields fields [],
$"{Query.Find.byFields tableName howMatched fields} LIMIT 1",
addFieldParams fields [],
fromData<'TDoc>,
sqlProps)
@ -727,7 +675,7 @@ module WithProps =
Custom.nonQuery (Query.Patch.byId tableName) [ idParam docId; jsonParam "@data" patch ] sqlProps
/// Patch documents using a JSON field comparison query in the WHERE clause (->> =)
[<CompiledName "FSharpByFields">]
[<CompiledName "ByFields">]
let byFields tableName howMatched fields (patch: 'TPatch) sqlProps =
Custom.nonQuery
(Query.Patch.byFields tableName howMatched fields)
@ -740,13 +688,6 @@ module WithProps =
let byField tableName field (patch: 'TPatch) sqlProps =
byFields tableName Any [ field ] patch sqlProps
/// Patch documents using a JSON field comparison query in the WHERE clause (->> =)
let ByFields(tableName, howMatched, fields, patch: 'TPatch, sqlProps) =
Custom.nonQuery
(Query.Patch.ByFields tableName howMatched fields)
(AddFields fields [ jsonParam "@data" patch ])
sqlProps
/// Patch documents using a JSON containment query in the WHERE clause (@>)
[<CompiledName "ByContains">]
let byContains tableName (criteria: 'TContains) (patch: 'TPatch) sqlProps =
@ -773,7 +714,7 @@ module WithProps =
byId tableName docId (List.ofSeq fieldNames) sqlProps
/// Remove fields from documents via a comparison on JSON fields in the document
[<CompiledName "FSharpByFields">]
[<CompiledName "ByFields">]
let byFields tableName howMatched fields fieldNames sqlProps =
Custom.nonQuery
(Query.RemoveFields.byFields tableName howMatched fields)
@ -781,23 +722,11 @@ module WithProps =
sqlProps
/// Remove fields from documents via a comparison on a JSON field in the document
[<CompiledName "FSharpByField">]
[<CompiledName "ByField">]
[<System.Obsolete "Use byFields instead; will be removed in v4">]
let byField tableName field fieldNames sqlProps =
byFields tableName Any [ field ] fieldNames sqlProps
/// Remove fields from documents via a comparison on JSON fields in the document
let ByFields(tableName, howMatched, fields, fieldNames, sqlProps) =
Custom.nonQuery
(Query.RemoveFields.ByFields tableName howMatched fields)
(AddFields fields [ FieldName fieldNames ])
sqlProps
/// Remove fields from documents via a comparison on a JSON field in the document
[<System.Obsolete "Use ByFields instead; will be removed in v4">]
let ByField(tableName, field, fieldNames, sqlProps) =
ByFields(tableName, Any, Seq.singleton field, fieldNames, sqlProps)
/// Remove fields from documents via a JSON containment query (@>)
[<CompiledName "FSharpByContains">]
let byContains tableName (criteria: 'TContains) fieldNames sqlProps =
@ -832,7 +761,7 @@ module WithProps =
Custom.nonQuery (Query.Delete.byId tableName) [ idParam docId ] sqlProps
/// Delete documents by matching a JSON field comparison query (->> =)
[<CompiledName "FSharpByFields">]
[<CompiledName "ByFields">]
let byFields tableName howMatched fields sqlProps =
Custom.nonQuery (Query.Delete.byFields tableName howMatched fields) (addFieldParams fields []) sqlProps
@ -842,9 +771,6 @@ module WithProps =
let byField tableName field sqlProps =
byFields tableName Any [ field ] sqlProps
let ByFields(tableName, howMatched, fields, sqlProps) =
Custom.nonQuery (Query.Delete.ByFields tableName howMatched fields) (AddFields fields []) sqlProps
/// Delete documents by matching a JSON contains query (@>)
[<CompiledName "ByContains">]
let byContains tableName (criteria: 'TCriteria) sqlProps =
@ -938,7 +864,7 @@ module Count =
WithProps.Count.all tableName (fromDataSource ())
/// Count matching documents using a JSON field comparison query (->> =)
[<CompiledName "FSharpByFields">]
[<CompiledName "ByFields">]
let byFields tableName howMatched fields =
WithProps.Count.byFields tableName howMatched fields (fromDataSource ())
@ -948,10 +874,6 @@ module Count =
let byField tableName field =
byFields tableName Any [ field ]
/// Count matching documents using a JSON field comparison query (->> =)
let ByFields(tableName, howMatched, fields) =
WithProps.Count.ByFields(tableName, howMatched, fields, fromDataSource ())
/// Count matching documents using a JSON containment query (@>)
[<CompiledName "ByContains">]
let byContains tableName criteria =
@ -973,7 +895,7 @@ module Exists =
WithProps.Exists.byId tableName docId (fromDataSource ())
/// Determine if documents exist using a JSON field comparison query (->> =)
[<CompiledName "FSharpByFields">]
[<CompiledName "ByFields">]
let byFields tableName howMatched fields =
WithProps.Exists.byFields tableName howMatched fields (fromDataSource ())
@ -983,10 +905,6 @@ module Exists =
let byField tableName field =
byFields tableName Any [ field ]
/// Determine if documents exist using a JSON field comparison query (->> =)
let ByFields(tableName, howMatched, fields) =
WithProps.Exists.ByFields(tableName, howMatched, fields, fromDataSource ())
/// Determine if documents exist using a JSON containment query (@>)
[<CompiledName "ByContains">]
let byContains tableName criteria =
@ -1126,7 +1044,7 @@ module Patch =
WithProps.Patch.byId tableName docId patch (fromDataSource ())
/// Patch documents using a JSON field comparison query in the WHERE clause (->> =)
[<CompiledName "FSharpByFields">]
[<CompiledName "ByFields">]
let byFields tableName howMatched fields (patch: 'TPatch) =
WithProps.Patch.byFields tableName howMatched fields patch (fromDataSource ())
@ -1136,10 +1054,6 @@ module Patch =
let byField tableName field (patch: 'TPatch) =
byFields tableName Any [ field ] patch
/// Patch documents using a JSON field comparison query in the WHERE clause (->> =)
let ByFields(tableName, howMatched, fields, patch: 'TPatch) =
WithProps.Patch.ByFields(tableName, howMatched, fields, patch, fromDataSource ())
/// Patch documents using a JSON containment query in the WHERE clause (@>)
[<CompiledName "ByContains">]
let byContains tableName (criteria: 'TCriteria) (patch: 'TPatch) =
@ -1165,25 +1079,16 @@ module RemoveFields =
WithProps.RemoveFields.ById(tableName, docId, fieldNames, fromDataSource ())
/// Remove fields from documents via a comparison on JSON fields in the document
[<CompiledName "FSharpByFields">]
[<CompiledName "ByFields">]
let byFields tableName howMatched fields fieldNames =
WithProps.RemoveFields.byFields tableName howMatched fields fieldNames (fromDataSource ())
/// Remove fields from documents via a comparison on a JSON field in the document
[<CompiledName "FSharpByField">]
[<CompiledName "ByField">]
[<System.Obsolete "Use byFields instead; will be removed in v4">]
let byField tableName field fieldNames =
byFields tableName Any [ field ] fieldNames
/// Remove fields from documents via a comparison on JSON fields in the document
let ByFields(tableName, howMatched, fields, fieldNames) =
WithProps.RemoveFields.ByFields(tableName, howMatched, fields, fieldNames, fromDataSource ())
/// Remove fields from documents via a comparison on a JSON field in the document
[<System.Obsolete "Use ByFields instead; will be removed in v4">]
let ByField(tableName, field, fieldNames) =
ByFields(tableName, Any, Seq.singleton field, fieldNames)
/// Remove fields from documents via a JSON containment query (@>)
[<CompiledName "FSharpByContains">]
let byContains tableName (criteria: 'TContains) fieldNames =
@ -1213,7 +1118,7 @@ module Delete =
WithProps.Delete.byId tableName docId (fromDataSource ())
/// Delete documents by matching a JSON field comparison query (->> =)
[<CompiledName "FSharpByFields">]
[<CompiledName "ByFields">]
let byFields tableName howMatched fields =
WithProps.Delete.byFields tableName howMatched fields (fromDataSource ())
@ -1223,10 +1128,6 @@ module Delete =
let byField tableName field =
byFields tableName Any [ field ]
/// Delete documents by matching a JSON field comparison query (->> =)
let ByFields(tableName, howMatched, fields) =
WithProps.Delete.ByFields(tableName, howMatched, fields, fromDataSource ())
/// Delete documents by matching a JSON containment query (@>)
[<CompiledName "ByContains">]
let byContains tableName (criteria: 'TContains) =

View File

@ -31,10 +31,10 @@ public class PostgresCSharpExtensionTests
/// Integration tests for the SQLite extension methods
/// </summary>
[Tests]
public static readonly Test Integration = TestList("Postgres.C#.Extensions", new[]
{
TestList("CustomList", new[]
{
public static readonly Test Integration = TestList("Postgres.C#.Extensions",
[
TestList("CustomList",
[
TestCase("succeeds when data is found", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -57,9 +57,9 @@ public class PostgresCSharpExtensionTests
Results.FromData<JsonDocument>);
Expect.isEmpty(docs, "There should have been no documents returned");
})
}),
TestList("CustomSingle", new[]
{
]),
TestList("CustomSingle",
[
TestCase("succeeds when a row is found", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -81,9 +81,9 @@ public class PostgresCSharpExtensionTests
new[] { Tuple.Create("@id", Sql.@string("eighty")) }, Results.FromData<JsonDocument>);
Expect.isNull(doc, "There should not have been a document returned");
})
}),
TestList("CustomNonQuery", new[]
{
]),
TestList("CustomNonQuery",
[
TestCase("succeeds when operating on data", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -107,7 +107,7 @@ public class PostgresCSharpExtensionTests
var remaining = await conn.CountAll(PostgresDb.TableName);
Expect.equal(remaining, 5, "There should be 5 documents remaining in the table");
})
}),
]),
TestCase("Scalar succeeds", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -169,8 +169,8 @@ public class PostgresCSharpExtensionTests
exists = await indexExists();
Expect.isTrue(exists, "The index should now exist");
}),
TestList("Insert", new[]
{
TestList("Insert",
[
TestCase("succeeds", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -198,9 +198,9 @@ public class PostgresCSharpExtensionTests
// This is what should have happened
}
})
}),
TestList("save", new[]
{
]),
TestList("save",
[
TestCase("succeeds when a document is inserted", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -230,7 +230,7 @@ public class PostgresCSharpExtensionTests
Expect.isNotNull(after, "There should have been a document returned post-update");
Expect.equal(after.Sub!.Foo, "c", "The updated document is not correct");
})
}),
]),
TestCase("CountAll succeeds", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -240,6 +240,7 @@ public class PostgresCSharpExtensionTests
var theCount = await conn.CountAll(PostgresDb.TableName);
Expect.equal(theCount, 5, "There should have been 5 matching documents");
}),
#pragma warning disable CS0618
TestCase("CountByField succeeds", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -249,6 +250,7 @@ public class PostgresCSharpExtensionTests
var theCount = await conn.CountByField(PostgresDb.TableName, Field.EQ("Value", "purple"));
Expect.equal(theCount, 2, "There should have been 2 matching documents");
}),
#pragma warning restore CS0618
TestCase("CountByContains succeeds", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -267,8 +269,8 @@ public class PostgresCSharpExtensionTests
var theCount = await conn.CountByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ > 5)");
Expect.equal(theCount, 3, "There should have been 3 matching documents");
}),
TestList("ExistsById", new[]
{
TestList("ExistsById",
[
TestCase("succeeds when a document exists", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -287,9 +289,10 @@ public class PostgresCSharpExtensionTests
var exists = await conn.ExistsById(PostgresDb.TableName, "seven");
Expect.isFalse(exists, "There should not have been an existing document");
})
}),
TestList("ExistsByField", new[]
{
]),
#pragma warning disable CS0618
TestList("ExistsByField",
[
TestCase("succeeds when documents exist", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -308,9 +311,10 @@ public class PostgresCSharpExtensionTests
var exists = await conn.ExistsByField(PostgresDb.TableName, Field.EQ("NumValue", "six"));
Expect.isFalse(exists, "There should not have been existing documents");
})
}),
TestList("ExistsByContains", new[]
{
]),
#pragma warning restore CS0618
TestList("ExistsByContains",
[
TestCase("succeeds when documents exist", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -329,9 +333,9 @@ public class PostgresCSharpExtensionTests
var exists = await conn.ExistsByContains(PostgresDb.TableName, new { Nothing = "none" });
Expect.isFalse(exists, "There should not have been any existing documents");
})
}),
TestList("ExistsByJsonPath", new[]
{
]),
TestList("ExistsByJsonPath",
[
TestCase("succeeds when documents exist", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -350,9 +354,9 @@ public class PostgresCSharpExtensionTests
var exists = await conn.ExistsByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ > 1000)");
Expect.isFalse(exists, "There should not have been any existing documents");
})
}),
TestList("FindAll", new[]
{
]),
TestList("FindAll",
[
TestCase("succeeds when there is data", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -372,9 +376,9 @@ public class PostgresCSharpExtensionTests
var results = await conn.FindAll<JsonDocument>(PostgresDb.TableName);
Expect.isEmpty(results, "There should have been no documents returned");
})
}),
TestList("FindById", new[]
{
]),
TestList("FindById",
[
TestCase("succeeds when a document is found", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -394,9 +398,10 @@ public class PostgresCSharpExtensionTests
var doc = await conn.FindById<string, JsonDocument>(PostgresDb.TableName, "three hundred eighty-seven");
Expect.isNull(doc, "There should not have been a document returned");
})
}),
TestList("FindByField", new[]
{
]),
#pragma warning disable CS0618
TestList("FindByField",
[
TestCase("succeeds when documents are found", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -415,9 +420,10 @@ public class PostgresCSharpExtensionTests
var docs = await conn.FindByField<JsonDocument>(PostgresDb.TableName, Field.EQ("Value", "mauve"));
Expect.isEmpty(docs, "There should have been no documents returned");
})
}),
TestList("FindByContains", new[]
{
]),
#pragma warning restore CS0618
TestList("FindByContains",
[
TestCase("succeeds when documents are found", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -437,9 +443,9 @@ public class PostgresCSharpExtensionTests
var docs = await conn.FindByContains<JsonDocument>(PostgresDb.TableName, new { Value = "mauve" });
Expect.isEmpty(docs, "There should have been no documents returned");
})
}),
TestList("FindByJsonPath", new[]
{
]),
TestList("FindByJsonPath",
[
TestCase("succeeds when documents are found", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -458,9 +464,10 @@ public class PostgresCSharpExtensionTests
var docs = await conn.FindByJsonPath<JsonDocument>(PostgresDb.TableName, "$.NumValue ? (@ < 0)");
Expect.isEmpty(docs, "There should have been no documents returned");
})
}),
TestList("FindFirstByField", new[]
{
]),
#pragma warning disable CS0618
TestList("FindFirstByField",
[
TestCase("succeeds when a document is found", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -490,9 +497,10 @@ public class PostgresCSharpExtensionTests
var doc = await conn.FindFirstByField<JsonDocument>(PostgresDb.TableName, Field.EQ("Value", "absent"));
Expect.isNull(doc, "There should not have been a document returned");
})
}),
TestList("FindFirstByContains", new[]
{
]),
#pragma warning restore CS0618
TestList("FindFirstByContains",
[
TestCase("succeeds when a document is found", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -523,9 +531,9 @@ public class PostgresCSharpExtensionTests
var doc = await conn.FindFirstByContains<JsonDocument>(PostgresDb.TableName, new { Value = "absent" });
Expect.isNull(doc, "There should not have been a document returned");
})
}),
TestList("FindFirstByJsonPath", new[]
{
]),
TestList("FindFirstByJsonPath",
[
TestCase("succeeds when a document is found", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -557,9 +565,9 @@ public class PostgresCSharpExtensionTests
var doc = await conn.FindFirstByJsonPath<JsonDocument>(PostgresDb.TableName, "$.Id ? (@ == \"nope\")");
Expect.isNull(doc, "There should not have been a document returned");
})
}),
TestList("UpdateById", new[]
{
]),
TestList("UpdateById",
[
TestCase("succeeds when a document is updated", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -588,9 +596,9 @@ public class PostgresCSharpExtensionTests
await conn.UpdateById(PostgresDb.TableName, "test",
new JsonDocument { Id = "x", Sub = new() { Foo = "blue", Bar = "red" } });
})
}),
TestList("UpdateByFunc", new[]
{
]),
TestList("UpdateByFunc",
[
TestCase("succeeds when a document is updated", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -617,9 +625,9 @@ public class PostgresCSharpExtensionTests
await conn.UpdateByFunc(PostgresDb.TableName, doc => doc.Id,
new JsonDocument { Id = "one", Value = "le un", NumValue = 1 });
})
}),
TestList("PatchById", new[]
{
]),
TestList("PatchById",
[
TestCase("succeeds when a document is updated", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -641,9 +649,10 @@ public class PostgresCSharpExtensionTests
// This not raising an exception is the test
await conn.PatchById(PostgresDb.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 = PostgresDb.BuildDb();
@ -664,9 +673,10 @@ public class PostgresCSharpExtensionTests
// This not raising an exception is the test
await conn.PatchByField(PostgresDb.TableName, Field.EQ("Value", "burgundy"), new { Foo = "green" });
})
}),
TestList("PatchByContains", new[]
{
]),
#pragma warning restore CS0618
TestList("PatchByContains",
[
TestCase("succeeds when a document is updated", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -687,9 +697,9 @@ public class PostgresCSharpExtensionTests
// This not raising an exception is the test
await conn.PatchByContains(PostgresDb.TableName, new { Value = "burgundy" }, new { Foo = "green" });
})
}),
TestList("PatchByJsonPath", new[]
{
]),
TestList("PatchByJsonPath",
[
TestCase("succeeds when a document is updated", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -710,9 +720,9 @@ public class PostgresCSharpExtensionTests
// This not raising an exception is the test
await conn.PatchByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ < 0)", new { Foo = "green" });
})
}),
TestList("RemoveFieldsById", new[]
{
]),
TestList("RemoveFieldsById",
[
TestCase("succeeds when multiple fields are removed", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -754,9 +764,10 @@ public class PostgresCSharpExtensionTests
// This not raising an exception is the test
await conn.RemoveFieldsById(PostgresDb.TableName, "two", new[] { "Value" });
})
}),
TestList("RemoveFieldsByField", new[]
{
]),
#pragma warning disable CS0618
TestList("RemoveFieldsByField",
[
TestCase("succeeds when multiple fields are removed", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -800,9 +811,10 @@ public class PostgresCSharpExtensionTests
await conn.RemoveFieldsByField(PostgresDb.TableName, Field.NE("Abracadabra", "apple"),
new[] { "Value" });
})
}),
TestList("RemoveFieldsByContains", new[]
{
]),
#pragma warning restore CS0618
TestList("RemoveFieldsByContains",
[
TestCase("succeeds when multiple fields are removed", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -846,9 +858,9 @@ public class PostgresCSharpExtensionTests
await conn.RemoveFieldsByContains(PostgresDb.TableName, new { Abracadabra = "apple" },
new[] { "Value" });
})
}),
TestList("RemoveFieldsByJsonPath", new[]
{
]),
TestList("RemoveFieldsByJsonPath",
[
TestCase("succeeds when multiple fields are removed", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -892,9 +904,9 @@ public class PostgresCSharpExtensionTests
await conn.RemoveFieldsByJsonPath(PostgresDb.TableName, "$.Abracadabra ? (@ == \"apple\")",
new[] { "Value" });
})
}),
TestList("DeleteById", new[]
{
]),
TestList("DeleteById",
[
TestCase("succeeds when a document is deleted", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -915,9 +927,10 @@ public class PostgresCSharpExtensionTests
var remaining = await conn.CountAll(PostgresDb.TableName);
Expect.equal(remaining, 5, "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 = PostgresDb.BuildDb();
@ -938,9 +951,10 @@ public class PostgresCSharpExtensionTests
var remaining = await conn.CountAll(PostgresDb.TableName);
Expect.equal(remaining, 5, "There should have been 5 documents remaining");
})
}),
TestList("DeleteByContains", new[]
{
]),
#pragma warning restore CS0618
TestList("DeleteByContains",
[
TestCase("succeeds when documents are deleted", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -961,9 +975,9 @@ public class PostgresCSharpExtensionTests
var remaining = await conn.CountAll(PostgresDb.TableName);
Expect.equal(remaining, 5, "There should have been 5 documents remaining");
})
}),
TestList("DeleteByJsonPath", new[]
{
]),
TestList("DeleteByJsonPath",
[
TestCase("succeeds when documents are deleted", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -984,6 +998,6 @@ public class PostgresCSharpExtensionTests
var remaining = await conn.CountAll(PostgresDb.TableName);
Expect.equal(remaining, 5, "There should have been 5 documents remaining");
})
}),
});
]),
]);
}

View File

@ -32,6 +32,68 @@ public static class PostgresCSharpTests
Expect.equal(it.Item1, "@test", "JSON parameter not constructed correctly");
Expect.equal(it.Item2, Sql.jsonb("{\"Something\":\"good\"}"), "JSON parameter value incorrect");
}),
TestList("AddFields",
[
TestCase("succeeds when a parameter is added", () =>
{
var paramList = Parameters.AddFields([Field.EQ("it", "242")], []).ToList();
Expect.hasLength(paramList, 1, "There should have been a parameter added");
var (name, value) = paramList[0];
Expect.equal(name, "@field0", "Field parameter name not correct");
if (!value.IsParameter)
{
Expect.isTrue(false, "The parameter was not a Parameter type");
}
}),
TestCase("succeeds when multiple independent parameters are added", () =>
{
var paramList = Parameters.AddFields([Field.EQ("me", "you"), Field.GT("us", "them")],
[Parameters.Id(14)]).ToList();
Expect.hasLength(paramList, 3, "There should have been 2 parameters added");
var (name, value) = paramList[0];
Expect.equal(name, "@id", "First field parameter name not correct");
if (!value.IsString)
{
Expect.isTrue(false, "First parameter was not a String type");
}
(name, value) = paramList[1];
Expect.equal(name, "@field0", "Second field parameter name not correct");
if (!value.IsParameter)
{
Expect.isTrue(false, "Second parameter was not a Parameter type");
}
(name, value) = paramList[2];
Expect.equal(name, "@field1", "Third parameter name not correct");
if (!value.IsParameter)
{
Expect.isTrue(false, "Third parameter was not a Parameter type");
}
}),
TestCase("succeeds when a parameter is not added", () =>
{
var paramList = Parameters.AddFields([Field.EX("tacos")], []).ToList();
Expect.isEmpty(paramList, "There should not have been any parameters added");
}),
TestCase("succeeds when two parameters are added for one field", () =>
{
var paramList =
Parameters.AddFields([Field.BT("that", "eh", "zed").WithParameterName("@test")], []).ToList();
Expect.hasLength(paramList, 2, "There should have been 2 parameters added");
var (name, value) = paramList[0];
Expect.equal(name, "@testmin", "Minimum field name not correct");
if (!value.IsParameter)
{
Expect.isTrue(false, "Minimum parameter was not a Parameter type");
}
(name, value) = paramList[1];
Expect.equal(name, "@testmax", "Maximum field name not correct");
if (!value.IsParameter)
{
Expect.isTrue(false, "Maximum parameter was not a Parameter type");
}
})
]),
#pragma warning disable CS0618
TestList("AddField",
[
TestCase("succeeds when a parameter is added", () =>
@ -55,6 +117,28 @@ public static class PostgresCSharpTests
Expect.equal(it[1].Item1, "@fieldmax", "Maximum field name not correct");
Expect.isTrue(it[1].Item2.IsParameter, "Maximum field parameter value incorrect");
})
]),
#pragma warning restore CS0618
TestList("FieldName",
[
TestCase("succeeds for one name", () =>
{
var (name, value) = Parameters.FieldName(["bob"]);
Expect.equal(name, "@name", "The parameter name was incorrect");
if (!value.IsString)
{
Expect.isTrue(false, "The parameter was not a String type");
}
}),
TestCase("succeeds for multiple names", () =>
{
var (name, value) = Parameters.FieldName(["bob", "tom", "mike"]);
Expect.equal(name, "@name", "The parameter name was incorrect");
if (!value.IsStringArray)
{
Expect.isTrue(false, "The parameter was not a StringArray type");
}
})
])
]),
TestList("Query",
@ -110,6 +194,7 @@ public static class PostgresCSharpTests
"WHERE clause not correct");
})
]),
#pragma warning disable CS0618
TestList("WhereByField",
[
TestCase("succeeds when a logical operator is passed", () =>
@ -133,6 +218,7 @@ public static class PostgresCSharpTests
"data->>'field0' BETWEEN @alphamin AND @alphamax", "WHERE clause not correct");
})
]),
#pragma warning restore CS0618
TestCase("WhereById succeeds", () =>
{
Expect.equal(Postgres.Query.WhereById("@id"), "data->>'Id' = @id", "WHERE clause not correct");
@ -183,12 +269,14 @@ public static class PostgresCSharpTests
Expect.equal(Postgres.Query.Count.All(PostgresDb.TableName),
$"SELECT COUNT(*) AS it FROM {PostgresDb.TableName}", "Count query not correct");
}),
#pragma warning disable CS0618
TestCase("ByField succeeds", () =>
{
Expect.equal(Postgres.Query.Count.ByField(PostgresDb.TableName, Field.EQ("thatField", 0)),
$"SELECT COUNT(*) AS it FROM {PostgresDb.TableName} WHERE data->>'thatField' = @field0",
"JSON field text comparison count query not correct");
}),
#pragma warning restore CS0618
TestCase("ByContains succeeds", () =>
{
Expect.equal(Postgres.Query.Count.ByContains(PostgresDb.TableName),
@ -210,12 +298,14 @@ public static class PostgresCSharpTests
$"SELECT EXISTS (SELECT 1 FROM {PostgresDb.TableName} WHERE data->>'Id' = @id) AS it",
"ID existence query not correct");
}),
#pragma warning disable CS0618
TestCase("ByField succeeds", () =>
{
Expect.equal(Postgres.Query.Exists.ByField(PostgresDb.TableName, Field.LT("Test", 0)),
$"SELECT EXISTS (SELECT 1 FROM {PostgresDb.TableName} WHERE data->>'Test' < @field0) AS it",
"JSON field text comparison exists query not correct");
}),
#pragma warning restore CS0618
TestCase("ByContains succeeds", () =>
{
Expect.equal(Postgres.Query.Exists.ByContains(PostgresDb.TableName),
@ -237,12 +327,14 @@ public static class PostgresCSharpTests
$"SELECT data FROM {PostgresDb.TableName} WHERE data->>'Id' = @id",
"SELECT by ID query not correct");
}),
#pragma warning disable CS0618
TestCase("ByField succeeds", () =>
{
Expect.equal(Postgres.Query.Find.ByField(PostgresDb.TableName, Field.GE("Golf", 0)),
$"SELECT data FROM {PostgresDb.TableName} WHERE data->>'Golf' >= @field0",
"SELECT by JSON comparison query not correct");
}),
#pragma warning restore CS0618
TestCase("byContains succeeds", () =>
{
Expect.equal(Postgres.Query.Find.ByContains(PostgresDb.TableName),
@ -264,12 +356,14 @@ public static class PostgresCSharpTests
$"UPDATE {PostgresDb.TableName} SET data = data || @data WHERE data->>'Id' = @id",
"UPDATE partial by ID statement not correct");
}),
#pragma warning disable CS0618
TestCase("ByField succeeds", () =>
{
Expect.equal(Postgres.Query.Patch.ByField(PostgresDb.TableName, Field.LT("Snail", 0)),
$"UPDATE {PostgresDb.TableName} SET data = data || @data WHERE data->>'Snail' < @field0",
"UPDATE partial by ID statement not correct");
}),
#pragma warning restore CS0618
TestCase("ByContains succeeds", () =>
{
Expect.equal(Postgres.Query.Patch.ByContains(PostgresDb.TableName),
@ -291,12 +385,14 @@ public static class PostgresCSharpTests
$"UPDATE {PostgresDb.TableName} SET data = data - @name WHERE data->>'Id' = @id",
"Remove field by ID query not correct");
}),
#pragma warning disable CS0618
TestCase("ByField succeeds", () =>
{
Expect.equal(Postgres.Query.RemoveFields.ByField(PostgresDb.TableName, Field.LT("Fly", 0)),
$"UPDATE {PostgresDb.TableName} SET data = data - @name WHERE data->>'Fly' < @field0",
"Remove field by field query not correct");
}),
#pragma warning restore CS0618
TestCase("ByContains succeeds", () =>
{
Expect.equal(Postgres.Query.RemoveFields.ByContains(PostgresDb.TableName),
@ -318,12 +414,14 @@ public static class PostgresCSharpTests
$"DELETE FROM {PostgresDb.TableName} WHERE data->>'Id' = @id",
"DELETE by ID query not correct");
}),
#pragma warning disable CS0618
TestCase("ByField succeeds", () =>
{
Expect.equal(Postgres.Query.Delete.ByField(PostgresDb.TableName, Field.NEX("gone")),
$"DELETE FROM {PostgresDb.TableName} WHERE data->>'gone' IS NULL",
"DELETE by JSON comparison query not correct");
}),
#pragma warning restore CS0618
TestCase("byContains succeeds", () =>
{
Expect.equal(Postgres.Query.Delete.ByContains(PostgresDb.TableName),
@ -603,6 +701,7 @@ public static class PostgresCSharpTests
var theCount = await Count.All(PostgresDb.TableName);
Expect.equal(theCount, 5, "There should have been 5 matching documents");
}),
#pragma warning disable CS0618
TestCase("ByField succeeds for numeric range", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -619,6 +718,7 @@ public static class PostgresCSharpTests
var theCount = await Count.ByField(PostgresDb.TableName, Field.BT("Value", "aardvark", "apple"));
Expect.equal(theCount, 1, "There should have been 1 matching document");
}),
#pragma warning restore CS0618
TestCase("ByContains succeeds", async () =>
{
await using var db = PostgresDb.BuildDb();
@ -657,6 +757,7 @@ public static class PostgresCSharpTests
Expect.isFalse(exists, "There should not have been an existing document");
})
]),
#pragma warning disable CS0618
TestList("ByField",
[
TestCase("succeeds when documents exist", async () =>
@ -676,6 +777,7 @@ public static class PostgresCSharpTests
Expect.isFalse(exists, "There should not have been existing documents");
})
]),
#pragma warning restore CS0618
TestList("ByContains",
[
TestCase("succeeds when documents exist", async () =>
@ -757,6 +859,7 @@ public static class PostgresCSharpTests
Expect.isNull(doc, "There should not have been a document returned");
})
]),
#pragma warning disable CS0618
TestList("ByField",
[
TestCase("succeeds when documents are found", async () =>
@ -776,6 +879,7 @@ public static class PostgresCSharpTests
Expect.isEmpty(docs, "There should have been no documents returned");
})
]),
#pragma warning restore CS0618
TestList("ByContains",
[
TestCase("succeeds when documents are found", async () =>
@ -815,6 +919,7 @@ public static class PostgresCSharpTests
Expect.isEmpty(docs, "There should have been no documents returned");
})
]),
#pragma warning disable CS0618
TestList("FirstByField",
[
TestCase("succeeds when a document is found", async () =>
@ -844,6 +949,7 @@ public static class PostgresCSharpTests
Expect.isNull(doc, "There should not have been a document returned");
})
]),
#pragma warning restore CS0618
TestList("FirstByContains",
[
TestCase("succeeds when a document is found", async () =>
@ -992,6 +1098,7 @@ public static class PostgresCSharpTests
await Patch.ById(PostgresDb.TableName, "test", new { Foo = "green" });
})
]),
#pragma warning disable CS0618
TestList("ByField",
[
TestCase("succeeds when a document is updated", async () =>
@ -1014,6 +1121,7 @@ public static class PostgresCSharpTests
await Patch.ByField(PostgresDb.TableName, Field.EQ("Value", "burgundy"), new { Foo = "green" });
})
]),
#pragma warning restore CS0618
TestList("ByContains",
[
TestCase("succeeds when a document is updated", async () =>
@ -1101,6 +1209,7 @@ public static class PostgresCSharpTests
await RemoveFields.ById(PostgresDb.TableName, "two", new[] { "Value" });
})
]),
#pragma warning disable CS0618
TestList("ByField",
[
TestCase("succeeds when multiple fields are removed", async () =>
@ -1143,6 +1252,7 @@ public static class PostgresCSharpTests
new[] { "Value" });
})
]),
#pragma warning restore CS0618
TestList("ByContains",
[
TestCase("succeeds when multiple fields are removed", async () =>
@ -1251,6 +1361,7 @@ public static class PostgresCSharpTests
Expect.equal(remaining, 5, "There should have been 5 documents remaining");
})
]),
#pragma warning disable CS0618
TestList("ByField",
[
TestCase("succeeds when documents are deleted", async () =>
@ -1272,6 +1383,7 @@ public static class PostgresCSharpTests
Expect.equal(remaining, 5, "There should have been 5 documents remaining");
})
]),
#pragma warning restore CS0618
TestList("ByContains",
[
TestCase("succeeds when documents are deleted", async () =>

View File

@ -7,6 +7,8 @@ open Expecto
open Npgsql
open Types
#nowarn "0044"
/// Open a connection to the throwaway database
let private mkConn (db: ThrowawayPostgresDb) =
let conn = new NpgsqlConnection(db.ConnectionString)

View File

@ -5,6 +5,8 @@ open BitBadger.Documents
open BitBadger.Documents.Postgres
open BitBadger.Documents.Tests
#nowarn "0044"
/// Tests which do not hit the database
let unitTests =
testList "Unit" [
@ -18,11 +20,69 @@ let unitTests =
("@test", Sql.jsonb """{"Something":"good"}""")
"JSON parameter not constructed correctly"
}
testList "addFieldParams" [
test "succeeds when a parameter is added" {
let paramList = addFieldParams [ Field.EQ "it" "242" ] []
Expect.hasLength paramList 1 "There should have been a parameter added"
let it = Seq.head paramList
Expect.equal (fst it) "@field0" "Field parameter name not correct"
match snd it with
| SqlValue.Parameter value ->
Expect.equal value.ParameterName "@field0" "Parameter name not correct"
Expect.equal value.Value "242" "Parameter value not correct"
| _ -> Expect.isTrue false "The parameter was not a Parameter type"
}
test "succeeds when multiple independent parameters are added" {
let paramList = addFieldParams [ Field.EQ "me" "you"; Field.GT "us" "them" ] [ idParam 14 ]
Expect.hasLength paramList 3 "There should have been 2 parameters added"
let p = Array.ofSeq paramList
Expect.equal (fst p[0]) "@id" "First field parameter name not correct"
match snd p[0] with
| SqlValue.String value ->
Expect.equal value "14" "First parameter value not correct"
| _ -> Expect.isTrue false "First parameter was not a String type"
Expect.equal (fst p[1]) "@field0" "Second field parameter name not correct"
match snd p[1] with
| SqlValue.Parameter value ->
Expect.equal value.ParameterName "@field0" "Second parameter name not correct"
Expect.equal value.Value "you" "Second parameter value not correct"
| _ -> Expect.isTrue false "Second parameter was not a Parameter type"
Expect.equal (fst p[2]) "@field1" "Third parameter name not correct"
match snd p[2] with
| SqlValue.Parameter value ->
Expect.equal value.ParameterName "@field1" "Third parameter name not correct"
Expect.equal value.Value "them" "Third parameter value not correct"
| _ -> Expect.isTrue false "Third parameter was not a Parameter type"
}
test "succeeds when a parameter is not added" {
let paramList = addFieldParams [ Field.EX "tacos" ] []
Expect.isEmpty paramList "There should not have been any parameters added"
}
test "succeeds when two parameters are added for one field" {
let paramList =
addFieldParams [ { Field.BT "that" "eh" "zed" with ParameterName = Some "@test" } ] []
Expect.hasLength paramList 2 "There should have been 2 parameters added"
let min = Seq.head paramList
Expect.equal (fst min) "@testmin" "Minimum field name not correct"
match snd min with
| SqlValue.Parameter value ->
Expect.equal value.ParameterName "@testmin" "Minimum parameter name not correct"
Expect.equal value.Value "eh" "Minimum parameter value not correct"
| _ -> Expect.isTrue false "Minimum parameter was not a Parameter type"
let max = paramList |> Seq.skip 1 |> Seq.head
Expect.equal (fst max) "@testmax" "Maximum field name not correct"
match snd max with
| SqlValue.Parameter value ->
Expect.equal value.ParameterName "@testmax" "Maximum parameter name not correct"
Expect.equal value.Value "zed" "Maximum parameter value not correct"
| _ -> Expect.isTrue false "Maximum parameter was not a Parameter type"
}
]
testList "addFieldParam" [
test "succeeds when a parameter is added" {
let paramList = addFieldParam "@field" (Field.EQ "it" "242") []
Expect.hasLength paramList 1 "There should have been a parameter added"
let it = paramList[0]
let it = Seq.head paramList
Expect.equal (fst it) "@field" "Field parameter name not correct"
match snd it with
| SqlValue.Parameter value ->
@ -37,14 +97,14 @@ let unitTests =
test "succeeds when two parameters are added" {
let paramList = addFieldParam "@field" (Field.BT "that" "eh" "zed") []
Expect.hasLength paramList 2 "There should have been 2 parameters added"
let min = paramList[0]
let min = Seq.head paramList
Expect.equal (fst min) "@fieldmin" "Minimum field name not correct"
match snd min with
| SqlValue.Parameter value ->
Expect.equal value.ParameterName "@fieldmin" "Minimum parameter name not correct"
Expect.equal value.Value "eh" "Minimum parameter value not correct"
| _ -> Expect.isTrue false "Minimum parameter was not a Parameter type"
let max = paramList[1]
let max = paramList |> Seq.skip 1 |> Seq.head
Expect.equal (fst max) "@fieldmax" "Maximum field name not correct"
match snd max with
| SqlValue.Parameter value ->
@ -53,6 +113,23 @@ let unitTests =
| _ -> Expect.isTrue false "Maximum parameter was not a Parameter type"
}
]
testList "fieldNameParam" [
test "succeeds for one name" {
let name, value = fieldNameParam [ "bob" ]
Expect.equal name "@name" "The parameter name was incorrect"
match value with
| SqlValue.String it -> Expect.equal it "bob" "The parameter value was incorrect"
| _ -> Expect.isTrue false "The parameter was not a String type"
}
test "succeeds for multiple names" {
let name, value = fieldNameParam [ "bob"; "tom"; "mike" ]
Expect.equal name "@name" "The parameter name was incorrect"
match value with
| SqlValue.StringArray it ->
Expect.equal it [| "bob"; "tom"; "mike" |] "The parameter value was incorrect"
| _ -> Expect.isTrue false "The parameter was not a StringArray type"
}
]
test "noParams succeeds" {
Expect.isEmpty noParams "The no-params sequence should be empty"
}

View File

@ -8,6 +8,8 @@ open Expecto
open Microsoft.Data.Sqlite
open Types
#nowarn "0044"
/// Unit tests for the SQLite library
let unitTests =
testList "Unit" [