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

View File

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

View File

@ -31,10 +31,10 @@ public class PostgresCSharpExtensionTests
/// Integration tests for the SQLite extension methods /// Integration tests for the SQLite extension methods
/// </summary> /// </summary>
[Tests] [Tests]
public static readonly Test Integration = TestList("Postgres.C#.Extensions", new[] public static readonly Test Integration = TestList("Postgres.C#.Extensions",
{ [
TestList("CustomList", new[] TestList("CustomList",
{ [
TestCase("succeeds when data is found", async () => TestCase("succeeds when data is found", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
@ -57,9 +57,9 @@ public class PostgresCSharpExtensionTests
Results.FromData<JsonDocument>); Results.FromData<JsonDocument>);
Expect.isEmpty(docs, "There should have been no documents returned"); Expect.isEmpty(docs, "There should have been no documents returned");
}) })
}), ]),
TestList("CustomSingle", new[] TestList("CustomSingle",
{ [
TestCase("succeeds when a row is found", async () => TestCase("succeeds when a row is found", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
@ -81,9 +81,9 @@ public class PostgresCSharpExtensionTests
new[] { Tuple.Create("@id", Sql.@string("eighty")) }, Results.FromData<JsonDocument>); new[] { Tuple.Create("@id", Sql.@string("eighty")) }, Results.FromData<JsonDocument>);
Expect.isNull(doc, "There should not have been a document returned"); Expect.isNull(doc, "There should not have been a document returned");
}) })
}), ]),
TestList("CustomNonQuery", new[] TestList("CustomNonQuery",
{ [
TestCase("succeeds when operating on data", async () => TestCase("succeeds when operating on data", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
@ -107,7 +107,7 @@ public class PostgresCSharpExtensionTests
var remaining = await conn.CountAll(PostgresDb.TableName); var remaining = await conn.CountAll(PostgresDb.TableName);
Expect.equal(remaining, 5, "There should be 5 documents remaining in the table"); Expect.equal(remaining, 5, "There should be 5 documents remaining in the table");
}) })
}), ]),
TestCase("Scalar succeeds", async () => TestCase("Scalar succeeds", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
@ -169,8 +169,8 @@ public class PostgresCSharpExtensionTests
exists = await indexExists(); exists = await indexExists();
Expect.isTrue(exists, "The index should now exist"); Expect.isTrue(exists, "The index should now exist");
}), }),
TestList("Insert", new[] TestList("Insert",
{ [
TestCase("succeeds", async () => TestCase("succeeds", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
@ -198,9 +198,9 @@ public class PostgresCSharpExtensionTests
// This is what should have happened // This is what should have happened
} }
}) })
}), ]),
TestList("save", new[] TestList("save",
{ [
TestCase("succeeds when a document is inserted", async () => TestCase("succeeds when a document is inserted", async () =>
{ {
await using var db = PostgresDb.BuildDb(); 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.isNotNull(after, "There should have been a document returned post-update");
Expect.equal(after.Sub!.Foo, "c", "The updated document is not correct"); Expect.equal(after.Sub!.Foo, "c", "The updated document is not correct");
}) })
}), ]),
TestCase("CountAll succeeds", async () => TestCase("CountAll succeeds", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
@ -240,6 +240,7 @@ public class PostgresCSharpExtensionTests
var theCount = await conn.CountAll(PostgresDb.TableName); var theCount = await conn.CountAll(PostgresDb.TableName);
Expect.equal(theCount, 5, "There should have been 5 matching documents"); Expect.equal(theCount, 5, "There should have been 5 matching documents");
}), }),
#pragma warning disable CS0618
TestCase("CountByField succeeds", async () => TestCase("CountByField succeeds", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
@ -249,6 +250,7 @@ public class PostgresCSharpExtensionTests
var theCount = await conn.CountByField(PostgresDb.TableName, Field.EQ("Value", "purple")); var theCount = await conn.CountByField(PostgresDb.TableName, Field.EQ("Value", "purple"));
Expect.equal(theCount, 2, "There should have been 2 matching documents"); Expect.equal(theCount, 2, "There should have been 2 matching documents");
}), }),
#pragma warning restore CS0618
TestCase("CountByContains succeeds", async () => TestCase("CountByContains succeeds", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
@ -267,8 +269,8 @@ public class PostgresCSharpExtensionTests
var theCount = await conn.CountByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ > 5)"); var theCount = await conn.CountByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ > 5)");
Expect.equal(theCount, 3, "There should have been 3 matching documents"); Expect.equal(theCount, 3, "There should have been 3 matching documents");
}), }),
TestList("ExistsById", new[] TestList("ExistsById",
{ [
TestCase("succeeds when a document exists", async () => TestCase("succeeds when a document exists", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
@ -287,9 +289,10 @@ public class PostgresCSharpExtensionTests
var exists = await conn.ExistsById(PostgresDb.TableName, "seven"); var exists = await conn.ExistsById(PostgresDb.TableName, "seven");
Expect.isFalse(exists, "There should not have been an existing document"); 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 () => TestCase("succeeds when documents exist", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
@ -308,9 +311,10 @@ public class PostgresCSharpExtensionTests
var exists = await conn.ExistsByField(PostgresDb.TableName, Field.EQ("NumValue", "six")); var exists = await conn.ExistsByField(PostgresDb.TableName, Field.EQ("NumValue", "six"));
Expect.isFalse(exists, "There should not have been existing documents"); 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 () => TestCase("succeeds when documents exist", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
@ -329,9 +333,9 @@ public class PostgresCSharpExtensionTests
var exists = await conn.ExistsByContains(PostgresDb.TableName, new { Nothing = "none" }); var exists = await conn.ExistsByContains(PostgresDb.TableName, new { Nothing = "none" });
Expect.isFalse(exists, "There should not have been any existing documents"); Expect.isFalse(exists, "There should not have been any existing documents");
}) })
}), ]),
TestList("ExistsByJsonPath", new[] TestList("ExistsByJsonPath",
{ [
TestCase("succeeds when documents exist", async () => TestCase("succeeds when documents exist", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
@ -350,9 +354,9 @@ public class PostgresCSharpExtensionTests
var exists = await conn.ExistsByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ > 1000)"); var exists = await conn.ExistsByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ > 1000)");
Expect.isFalse(exists, "There should not have been any existing documents"); Expect.isFalse(exists, "There should not have been any existing documents");
}) })
}), ]),
TestList("FindAll", new[] TestList("FindAll",
{ [
TestCase("succeeds when there is data", async () => TestCase("succeeds when there is data", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
@ -372,9 +376,9 @@ public class PostgresCSharpExtensionTests
var results = await conn.FindAll<JsonDocument>(PostgresDb.TableName); var results = await conn.FindAll<JsonDocument>(PostgresDb.TableName);
Expect.isEmpty(results, "There should have been no documents returned"); Expect.isEmpty(results, "There should have been no documents returned");
}) })
}), ]),
TestList("FindById", new[] TestList("FindById",
{ [
TestCase("succeeds when a document is found", async () => TestCase("succeeds when a document is found", async () =>
{ {
await using var db = PostgresDb.BuildDb(); 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"); var doc = await conn.FindById<string, JsonDocument>(PostgresDb.TableName, "three hundred eighty-seven");
Expect.isNull(doc, "There should not have been a document returned"); 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 () => TestCase("succeeds when documents are found", async () =>
{ {
await using var db = PostgresDb.BuildDb(); 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")); var docs = await conn.FindByField<JsonDocument>(PostgresDb.TableName, Field.EQ("Value", "mauve"));
Expect.isEmpty(docs, "There should have been no documents returned"); 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 () => TestCase("succeeds when documents are found", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
@ -437,9 +443,9 @@ public class PostgresCSharpExtensionTests
var docs = await conn.FindByContains<JsonDocument>(PostgresDb.TableName, new { Value = "mauve" }); var docs = await conn.FindByContains<JsonDocument>(PostgresDb.TableName, new { Value = "mauve" });
Expect.isEmpty(docs, "There should have been no documents returned"); Expect.isEmpty(docs, "There should have been no documents returned");
}) })
}), ]),
TestList("FindByJsonPath", new[] TestList("FindByJsonPath",
{ [
TestCase("succeeds when documents are found", async () => TestCase("succeeds when documents are found", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
@ -458,9 +464,10 @@ public class PostgresCSharpExtensionTests
var docs = await conn.FindByJsonPath<JsonDocument>(PostgresDb.TableName, "$.NumValue ? (@ < 0)"); var docs = await conn.FindByJsonPath<JsonDocument>(PostgresDb.TableName, "$.NumValue ? (@ < 0)");
Expect.isEmpty(docs, "There should have been no documents returned"); 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 () => TestCase("succeeds when a document is found", async () =>
{ {
await using var db = PostgresDb.BuildDb(); 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")); var doc = await conn.FindFirstByField<JsonDocument>(PostgresDb.TableName, Field.EQ("Value", "absent"));
Expect.isNull(doc, "There should not have been a document returned"); 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 () => TestCase("succeeds when a document is found", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
@ -523,9 +531,9 @@ public class PostgresCSharpExtensionTests
var doc = await conn.FindFirstByContains<JsonDocument>(PostgresDb.TableName, new { Value = "absent" }); var doc = await conn.FindFirstByContains<JsonDocument>(PostgresDb.TableName, new { Value = "absent" });
Expect.isNull(doc, "There should not have been a document returned"); Expect.isNull(doc, "There should not have been a document returned");
}) })
}), ]),
TestList("FindFirstByJsonPath", new[] TestList("FindFirstByJsonPath",
{ [
TestCase("succeeds when a document is found", async () => TestCase("succeeds when a document is found", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
@ -557,9 +565,9 @@ public class PostgresCSharpExtensionTests
var doc = await conn.FindFirstByJsonPath<JsonDocument>(PostgresDb.TableName, "$.Id ? (@ == \"nope\")"); var doc = await conn.FindFirstByJsonPath<JsonDocument>(PostgresDb.TableName, "$.Id ? (@ == \"nope\")");
Expect.isNull(doc, "There should not have been a document returned"); Expect.isNull(doc, "There should not have been a document returned");
}) })
}), ]),
TestList("UpdateById", new[] TestList("UpdateById",
{ [
TestCase("succeeds when a document is updated", async () => TestCase("succeeds when a document is updated", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
@ -588,9 +596,9 @@ public class PostgresCSharpExtensionTests
await conn.UpdateById(PostgresDb.TableName, "test", await conn.UpdateById(PostgresDb.TableName, "test",
new JsonDocument { Id = "x", Sub = new() { Foo = "blue", Bar = "red" } }); new JsonDocument { Id = "x", Sub = new() { Foo = "blue", Bar = "red" } });
}) })
}), ]),
TestList("UpdateByFunc", new[] TestList("UpdateByFunc",
{ [
TestCase("succeeds when a document is updated", async () => TestCase("succeeds when a document is updated", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
@ -617,9 +625,9 @@ public class PostgresCSharpExtensionTests
await conn.UpdateByFunc(PostgresDb.TableName, doc => doc.Id, await conn.UpdateByFunc(PostgresDb.TableName, doc => doc.Id,
new JsonDocument { Id = "one", Value = "le un", NumValue = 1 }); new JsonDocument { Id = "one", Value = "le un", NumValue = 1 });
}) })
}), ]),
TestList("PatchById", new[] TestList("PatchById",
{ [
TestCase("succeeds when a document is updated", async () => TestCase("succeeds when a document is updated", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
@ -641,9 +649,10 @@ public class PostgresCSharpExtensionTests
// This not raising an exception is the test // This not raising an exception is the test
await conn.PatchById(PostgresDb.TableName, "test", new { Foo = "green" }); 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 () => TestCase("succeeds when a document is updated", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
@ -664,9 +673,10 @@ public class PostgresCSharpExtensionTests
// This not raising an exception is the test // This not raising an exception is the test
await conn.PatchByField(PostgresDb.TableName, Field.EQ("Value", "burgundy"), new { Foo = "green" }); 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 () => TestCase("succeeds when a document is updated", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
@ -687,9 +697,9 @@ public class PostgresCSharpExtensionTests
// This not raising an exception is the test // This not raising an exception is the test
await conn.PatchByContains(PostgresDb.TableName, new { Value = "burgundy" }, new { Foo = "green" }); await conn.PatchByContains(PostgresDb.TableName, new { Value = "burgundy" }, new { Foo = "green" });
}) })
}), ]),
TestList("PatchByJsonPath", new[] TestList("PatchByJsonPath",
{ [
TestCase("succeeds when a document is updated", async () => TestCase("succeeds when a document is updated", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
@ -710,9 +720,9 @@ public class PostgresCSharpExtensionTests
// This not raising an exception is the test // This not raising an exception is the test
await conn.PatchByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ < 0)", new { Foo = "green" }); await conn.PatchByJsonPath(PostgresDb.TableName, "$.NumValue ? (@ < 0)", new { Foo = "green" });
}) })
}), ]),
TestList("RemoveFieldsById", new[] TestList("RemoveFieldsById",
{ [
TestCase("succeeds when multiple fields are removed", async () => TestCase("succeeds when multiple fields are removed", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
@ -754,9 +764,10 @@ public class PostgresCSharpExtensionTests
// This not raising an exception is the test // This not raising an exception is the test
await conn.RemoveFieldsById(PostgresDb.TableName, "two", new[] { "Value" }); 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 () => TestCase("succeeds when multiple fields are removed", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
@ -800,9 +811,10 @@ public class PostgresCSharpExtensionTests
await conn.RemoveFieldsByField(PostgresDb.TableName, Field.NE("Abracadabra", "apple"), await conn.RemoveFieldsByField(PostgresDb.TableName, Field.NE("Abracadabra", "apple"),
new[] { "Value" }); new[] { "Value" });
}) })
}), ]),
TestList("RemoveFieldsByContains", new[] #pragma warning restore CS0618
{ TestList("RemoveFieldsByContains",
[
TestCase("succeeds when multiple fields are removed", async () => TestCase("succeeds when multiple fields are removed", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
@ -846,9 +858,9 @@ public class PostgresCSharpExtensionTests
await conn.RemoveFieldsByContains(PostgresDb.TableName, new { Abracadabra = "apple" }, await conn.RemoveFieldsByContains(PostgresDb.TableName, new { Abracadabra = "apple" },
new[] { "Value" }); new[] { "Value" });
}) })
}), ]),
TestList("RemoveFieldsByJsonPath", new[] TestList("RemoveFieldsByJsonPath",
{ [
TestCase("succeeds when multiple fields are removed", async () => TestCase("succeeds when multiple fields are removed", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
@ -892,9 +904,9 @@ public class PostgresCSharpExtensionTests
await conn.RemoveFieldsByJsonPath(PostgresDb.TableName, "$.Abracadabra ? (@ == \"apple\")", await conn.RemoveFieldsByJsonPath(PostgresDb.TableName, "$.Abracadabra ? (@ == \"apple\")",
new[] { "Value" }); new[] { "Value" });
}) })
}), ]),
TestList("DeleteById", new[] TestList("DeleteById",
{ [
TestCase("succeeds when a document is deleted", async () => TestCase("succeeds when a document is deleted", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
@ -915,9 +927,10 @@ public class PostgresCSharpExtensionTests
var remaining = await conn.CountAll(PostgresDb.TableName); var remaining = await conn.CountAll(PostgresDb.TableName);
Expect.equal(remaining, 5, "There should have been 5 documents remaining"); 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 () => TestCase("succeeds when documents are deleted", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
@ -938,9 +951,10 @@ public class PostgresCSharpExtensionTests
var remaining = await conn.CountAll(PostgresDb.TableName); var remaining = await conn.CountAll(PostgresDb.TableName);
Expect.equal(remaining, 5, "There should have been 5 documents remaining"); 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 () => TestCase("succeeds when documents are deleted", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
@ -961,9 +975,9 @@ public class PostgresCSharpExtensionTests
var remaining = await conn.CountAll(PostgresDb.TableName); var remaining = await conn.CountAll(PostgresDb.TableName);
Expect.equal(remaining, 5, "There should have been 5 documents remaining"); Expect.equal(remaining, 5, "There should have been 5 documents remaining");
}) })
}), ]),
TestList("DeleteByJsonPath", new[] TestList("DeleteByJsonPath",
{ [
TestCase("succeeds when documents are deleted", async () => TestCase("succeeds when documents are deleted", async () =>
{ {
await using var db = PostgresDb.BuildDb(); await using var db = PostgresDb.BuildDb();
@ -984,6 +998,6 @@ public class PostgresCSharpExtensionTests
var remaining = await conn.CountAll(PostgresDb.TableName); var remaining = await conn.CountAll(PostgresDb.TableName);
Expect.equal(remaining, 5, "There should have been 5 documents remaining"); 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.Item1, "@test", "JSON parameter not constructed correctly");
Expect.equal(it.Item2, Sql.jsonb("{\"Something\":\"good\"}"), "JSON parameter value incorrect"); 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", TestList("AddField",
[ [
TestCase("succeeds when a parameter is added", () => 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.equal(it[1].Item1, "@fieldmax", "Maximum field name not correct");
Expect.isTrue(it[1].Item2.IsParameter, "Maximum field parameter value incorrect"); 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", TestList("Query",
@ -110,6 +194,7 @@ public static class PostgresCSharpTests
"WHERE clause not correct"); "WHERE clause not correct");
}) })
]), ]),
#pragma warning disable CS0618
TestList("WhereByField", TestList("WhereByField",
[ [
TestCase("succeeds when a logical operator is passed", () => 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"); "data->>'field0' BETWEEN @alphamin AND @alphamax", "WHERE clause not correct");
}) })
]), ]),
#pragma warning restore CS0618
TestCase("WhereById succeeds", () => TestCase("WhereById succeeds", () =>
{ {
Expect.equal(Postgres.Query.WhereById("@id"), "data->>'Id' = @id", "WHERE clause not correct"); 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), Expect.equal(Postgres.Query.Count.All(PostgresDb.TableName),
$"SELECT COUNT(*) AS it FROM {PostgresDb.TableName}", "Count query not correct"); $"SELECT COUNT(*) AS it FROM {PostgresDb.TableName}", "Count query not correct");
}), }),
#pragma warning disable CS0618
TestCase("ByField succeeds", () => TestCase("ByField succeeds", () =>
{ {
Expect.equal(Postgres.Query.Count.ByField(PostgresDb.TableName, Field.EQ("thatField", 0)), Expect.equal(Postgres.Query.Count.ByField(PostgresDb.TableName, Field.EQ("thatField", 0)),
$"SELECT COUNT(*) AS it FROM {PostgresDb.TableName} WHERE data->>'thatField' = @field0", $"SELECT COUNT(*) AS it FROM {PostgresDb.TableName} WHERE data->>'thatField' = @field0",
"JSON field text comparison count query not correct"); "JSON field text comparison count query not correct");
}), }),
#pragma warning restore CS0618
TestCase("ByContains succeeds", () => TestCase("ByContains succeeds", () =>
{ {
Expect.equal(Postgres.Query.Count.ByContains(PostgresDb.TableName), 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", $"SELECT EXISTS (SELECT 1 FROM {PostgresDb.TableName} WHERE data->>'Id' = @id) AS it",
"ID existence query not correct"); "ID existence query not correct");
}), }),
#pragma warning disable CS0618
TestCase("ByField succeeds", () => TestCase("ByField succeeds", () =>
{ {
Expect.equal(Postgres.Query.Exists.ByField(PostgresDb.TableName, Field.LT("Test", 0)), 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", $"SELECT EXISTS (SELECT 1 FROM {PostgresDb.TableName} WHERE data->>'Test' < @field0) AS it",
"JSON field text comparison exists query not correct"); "JSON field text comparison exists query not correct");
}), }),
#pragma warning restore CS0618
TestCase("ByContains succeeds", () => TestCase("ByContains succeeds", () =>
{ {
Expect.equal(Postgres.Query.Exists.ByContains(PostgresDb.TableName), 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 data FROM {PostgresDb.TableName} WHERE data->>'Id' = @id",
"SELECT by ID query not correct"); "SELECT by ID query not correct");
}), }),
#pragma warning disable CS0618
TestCase("ByField succeeds", () => TestCase("ByField succeeds", () =>
{ {
Expect.equal(Postgres.Query.Find.ByField(PostgresDb.TableName, Field.GE("Golf", 0)), Expect.equal(Postgres.Query.Find.ByField(PostgresDb.TableName, Field.GE("Golf", 0)),
$"SELECT data FROM {PostgresDb.TableName} WHERE data->>'Golf' >= @field0", $"SELECT data FROM {PostgresDb.TableName} WHERE data->>'Golf' >= @field0",
"SELECT by JSON comparison query not correct"); "SELECT by JSON comparison query not correct");
}), }),
#pragma warning restore CS0618
TestCase("byContains succeeds", () => TestCase("byContains succeeds", () =>
{ {
Expect.equal(Postgres.Query.Find.ByContains(PostgresDb.TableName), 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 {PostgresDb.TableName} SET data = data || @data WHERE data->>'Id' = @id",
"UPDATE partial by ID statement not correct"); "UPDATE partial by ID statement not correct");
}), }),
#pragma warning disable CS0618
TestCase("ByField succeeds", () => TestCase("ByField succeeds", () =>
{ {
Expect.equal(Postgres.Query.Patch.ByField(PostgresDb.TableName, Field.LT("Snail", 0)), Expect.equal(Postgres.Query.Patch.ByField(PostgresDb.TableName, Field.LT("Snail", 0)),
$"UPDATE {PostgresDb.TableName} SET data = data || @data WHERE data->>'Snail' < @field0", $"UPDATE {PostgresDb.TableName} SET data = data || @data WHERE data->>'Snail' < @field0",
"UPDATE partial by ID statement not correct"); "UPDATE partial by ID statement not correct");
}), }),
#pragma warning restore CS0618
TestCase("ByContains succeeds", () => TestCase("ByContains succeeds", () =>
{ {
Expect.equal(Postgres.Query.Patch.ByContains(PostgresDb.TableName), 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", $"UPDATE {PostgresDb.TableName} SET data = data - @name WHERE data->>'Id' = @id",
"Remove field by ID query not correct"); "Remove field by ID query not correct");
}), }),
#pragma warning disable CS0618
TestCase("ByField succeeds", () => TestCase("ByField succeeds", () =>
{ {
Expect.equal(Postgres.Query.RemoveFields.ByField(PostgresDb.TableName, Field.LT("Fly", 0)), Expect.equal(Postgres.Query.RemoveFields.ByField(PostgresDb.TableName, Field.LT("Fly", 0)),
$"UPDATE {PostgresDb.TableName} SET data = data - @name WHERE data->>'Fly' < @field0", $"UPDATE {PostgresDb.TableName} SET data = data - @name WHERE data->>'Fly' < @field0",
"Remove field by field query not correct"); "Remove field by field query not correct");
}), }),
#pragma warning restore CS0618
TestCase("ByContains succeeds", () => TestCase("ByContains succeeds", () =>
{ {
Expect.equal(Postgres.Query.RemoveFields.ByContains(PostgresDb.TableName), 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 FROM {PostgresDb.TableName} WHERE data->>'Id' = @id",
"DELETE by ID query not correct"); "DELETE by ID query not correct");
}), }),
#pragma warning disable CS0618
TestCase("ByField succeeds", () => TestCase("ByField succeeds", () =>
{ {
Expect.equal(Postgres.Query.Delete.ByField(PostgresDb.TableName, Field.NEX("gone")), Expect.equal(Postgres.Query.Delete.ByField(PostgresDb.TableName, Field.NEX("gone")),
$"DELETE FROM {PostgresDb.TableName} WHERE data->>'gone' IS NULL", $"DELETE FROM {PostgresDb.TableName} WHERE data->>'gone' IS NULL",
"DELETE by JSON comparison query not correct"); "DELETE by JSON comparison query not correct");
}), }),
#pragma warning restore CS0618
TestCase("byContains succeeds", () => TestCase("byContains succeeds", () =>
{ {
Expect.equal(Postgres.Query.Delete.ByContains(PostgresDb.TableName), Expect.equal(Postgres.Query.Delete.ByContains(PostgresDb.TableName),
@ -603,6 +701,7 @@ public static class PostgresCSharpTests
var theCount = await Count.All(PostgresDb.TableName); var theCount = await Count.All(PostgresDb.TableName);
Expect.equal(theCount, 5, "There should have been 5 matching documents"); Expect.equal(theCount, 5, "There should have been 5 matching documents");
}), }),
#pragma warning disable CS0618
TestCase("ByField succeeds for numeric range", async () => TestCase("ByField succeeds for numeric range", async () =>
{ {
await using var db = PostgresDb.BuildDb(); 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")); var theCount = await Count.ByField(PostgresDb.TableName, Field.BT("Value", "aardvark", "apple"));
Expect.equal(theCount, 1, "There should have been 1 matching document"); Expect.equal(theCount, 1, "There should have been 1 matching document");
}), }),
#pragma warning restore CS0618
TestCase("ByContains succeeds", async () => TestCase("ByContains succeeds", async () =>
{ {
await using var db = PostgresDb.BuildDb(); 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"); Expect.isFalse(exists, "There should not have been an existing document");
}) })
]), ]),
#pragma warning disable CS0618
TestList("ByField", TestList("ByField",
[ [
TestCase("succeeds when documents exist", async () => TestCase("succeeds when documents exist", async () =>
@ -676,6 +777,7 @@ public static class PostgresCSharpTests
Expect.isFalse(exists, "There should not have been existing documents"); Expect.isFalse(exists, "There should not have been existing documents");
}) })
]), ]),
#pragma warning restore CS0618
TestList("ByContains", TestList("ByContains",
[ [
TestCase("succeeds when documents exist", async () => 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"); Expect.isNull(doc, "There should not have been a document returned");
}) })
]), ]),
#pragma warning disable CS0618
TestList("ByField", TestList("ByField",
[ [
TestCase("succeeds when documents are found", async () => 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"); Expect.isEmpty(docs, "There should have been no documents returned");
}) })
]), ]),
#pragma warning restore CS0618
TestList("ByContains", TestList("ByContains",
[ [
TestCase("succeeds when documents are found", async () => 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"); Expect.isEmpty(docs, "There should have been no documents returned");
}) })
]), ]),
#pragma warning disable CS0618
TestList("FirstByField", TestList("FirstByField",
[ [
TestCase("succeeds when a document is found", async () => 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"); Expect.isNull(doc, "There should not have been a document returned");
}) })
]), ]),
#pragma warning restore CS0618
TestList("FirstByContains", TestList("FirstByContains",
[ [
TestCase("succeeds when a document is found", async () => 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" }); await Patch.ById(PostgresDb.TableName, "test", new { Foo = "green" });
}) })
]), ]),
#pragma warning disable CS0618
TestList("ByField", TestList("ByField",
[ [
TestCase("succeeds when a document is updated", async () => 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" }); await Patch.ByField(PostgresDb.TableName, Field.EQ("Value", "burgundy"), new { Foo = "green" });
}) })
]), ]),
#pragma warning restore CS0618
TestList("ByContains", TestList("ByContains",
[ [
TestCase("succeeds when a document is updated", async () => TestCase("succeeds when a document is updated", async () =>
@ -1101,6 +1209,7 @@ public static class PostgresCSharpTests
await RemoveFields.ById(PostgresDb.TableName, "two", new[] { "Value" }); await RemoveFields.ById(PostgresDb.TableName, "two", new[] { "Value" });
}) })
]), ]),
#pragma warning disable CS0618
TestList("ByField", TestList("ByField",
[ [
TestCase("succeeds when multiple fields are removed", async () => TestCase("succeeds when multiple fields are removed", async () =>
@ -1143,6 +1252,7 @@ public static class PostgresCSharpTests
new[] { "Value" }); new[] { "Value" });
}) })
]), ]),
#pragma warning restore CS0618
TestList("ByContains", TestList("ByContains",
[ [
TestCase("succeeds when multiple fields are removed", async () => 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"); Expect.equal(remaining, 5, "There should have been 5 documents remaining");
}) })
]), ]),
#pragma warning disable CS0618
TestList("ByField", TestList("ByField",
[ [
TestCase("succeeds when documents are deleted", async () => 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"); Expect.equal(remaining, 5, "There should have been 5 documents remaining");
}) })
]), ]),
#pragma warning restore CS0618
TestList("ByContains", TestList("ByContains",
[ [
TestCase("succeeds when documents are deleted", async () => TestCase("succeeds when documents are deleted", async () =>

View File

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

View File

@ -5,6 +5,8 @@ open BitBadger.Documents
open BitBadger.Documents.Postgres open BitBadger.Documents.Postgres
open BitBadger.Documents.Tests open BitBadger.Documents.Tests
#nowarn "0044"
/// Tests which do not hit the database /// Tests which do not hit the database
let unitTests = let unitTests =
testList "Unit" [ testList "Unit" [
@ -18,11 +20,69 @@ let unitTests =
("@test", Sql.jsonb """{"Something":"good"}""") ("@test", Sql.jsonb """{"Something":"good"}""")
"JSON parameter not constructed correctly" "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" [ testList "addFieldParam" [
test "succeeds when a parameter is added" { test "succeeds when a parameter is added" {
let paramList = addFieldParam "@field" (Field.EQ "it" "242") [] let paramList = addFieldParam "@field" (Field.EQ "it" "242") []
Expect.hasLength paramList 1 "There should have been a parameter added" 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" Expect.equal (fst it) "@field" "Field parameter name not correct"
match snd it with match snd it with
| SqlValue.Parameter value -> | SqlValue.Parameter value ->
@ -37,14 +97,14 @@ let unitTests =
test "succeeds when two parameters are added" { test "succeeds when two parameters are added" {
let paramList = addFieldParam "@field" (Field.BT "that" "eh" "zed") [] let paramList = addFieldParam "@field" (Field.BT "that" "eh" "zed") []
Expect.hasLength paramList 2 "There should have been 2 parameters added" 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" Expect.equal (fst min) "@fieldmin" "Minimum field name not correct"
match snd min with match snd min with
| SqlValue.Parameter value -> | SqlValue.Parameter value ->
Expect.equal value.ParameterName "@fieldmin" "Minimum parameter name not correct" Expect.equal value.ParameterName "@fieldmin" "Minimum parameter name not correct"
Expect.equal value.Value "eh" "Minimum parameter value not correct" Expect.equal value.Value "eh" "Minimum parameter value not correct"
| _ -> Expect.isTrue false "Minimum parameter was not a Parameter type" | _ -> 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" Expect.equal (fst max) "@fieldmax" "Maximum field name not correct"
match snd max with match snd max with
| SqlValue.Parameter value -> | SqlValue.Parameter value ->
@ -53,6 +113,23 @@ let unitTests =
| _ -> Expect.isTrue false "Maximum parameter was not a Parameter type" | _ -> 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" { test "noParams succeeds" {
Expect.isEmpty noParams "The no-params sequence should be empty" Expect.isEmpty noParams "The no-params sequence should be empty"
} }

View File

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