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