WIP on PG Query.whereByFIelds

This commit is contained in:
Daniel J. Summers 2024-08-07 08:30:28 -04:00
parent 433302d995
commit e96c449324
3 changed files with 44 additions and 13 deletions

View File

@ -98,6 +98,15 @@ type Field = {
{ this with Qualifier = Some alias } { this with Qualifier = Some alias }
/// How fields should be matched
[<Struct>]
type FieldMatch =
/// Any field matches (OR)
| Any
/// All fields match (AND)
| All
/// The required document serialization implementation /// The required document serialization implementation
type IDocumentSerializer = type IDocumentSerializer =

View File

@ -109,24 +109,46 @@ module Parameters =
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
module Query = module Query =
/// Create a WHERE clause fragment to implement a comparison on fields in a JSON document
[<CompiledName "WhereByFields">]
let whereByFields fields howMatched =
let mutable idx = 0
let nameField () =
let name = $"field{idx}"
idx <- idx + 1
name
fields
|> List.map (fun it ->
let fieldName = it.Qualifier |> Option.map (fun q -> $"{q}.data") |> Option.defaultValue "data"
let jsonPath =
if it.Name.Contains '.' then "#>>'{" + String.concat "," (it.Name.Split '.') + "}'"
else $"->>'{it.Name}'"
let column = fieldName + jsonPath
match it.Op with
| EX | NEX -> $"{column} {it.Op}"
| BT ->
let p = defaultArg it.ParameterName (nameField ())
let names = $"{p}min AND {p}max"
let values = it.Value :?> obj list
match values[0] with
| :? int8 | :? uint8 | :? int16 | :? uint16 | :? int | :? uint32 | :? int64 | :? uint64
| :? decimal | :? single | :? double -> $"({column})::numeric {it.Op} {names}"
| _ -> $"{column} {it.Op} {names}"
| _ ->
let p = defaultArg it.ParameterName (nameField ())
$"{column} {it.Op} {p}")
|> String.concat (match howMatched with Any -> " OR " | All -> " AND ")
/// Create a WHERE clause fragment to implement a comparison on a field in a JSON document /// Create a WHERE clause fragment to implement a comparison on a field in a JSON document
[<CompiledName "WhereByField">] [<CompiledName "WhereByField">]
//[<Obsolete "Use whereByFields / WhereByFields instead">]
let whereByField field paramName = let whereByField field paramName =
match field.Op with whereByFields [ { field with ParameterName = Some paramName } ] Any
| EX | NEX -> $"data->>'{field.Name}' {field.Op}"
| BT ->
let names = $"{paramName}min AND {paramName}max"
let values = field.Value :?> obj list
match values[0] with
| :? int8 | :? uint8 | :? int16 | :? uint16 | :? int | :? uint32 | :? int64 | :? uint64
| :? decimal | :? single | :? double -> $"(data->>'{field.Name}')::numeric {field.Op} {names}"
| _ -> $"data->>'{field.Name}' {field.Op} {names}"
| _ -> $"data->>'{field.Name}' {field.Op} %s{paramName}"
/// Create a WHERE clause fragment to implement an ID-based query /// Create a WHERE clause fragment to implement an ID-based query
[<CompiledName "WhereById">] [<CompiledName "WhereById">]
let whereById paramName = let whereById paramName =
whereByField (Field.EQ (Configuration.idField ()) 0) paramName whereByFields [ { Field.EQ (Configuration.idField ()) 0 with ParameterName = Some paramName } ] Any
/// Table and index definition queries /// Table and index definition queries
module Definition = module Definition =

View File

@ -115,9 +115,9 @@ let all =
Expect.equal "@name" field.ParameterName.Value "The parameter name is incorrect" Expect.equal "@name" field.ParameterName.Value "The parameter name is incorrect"
} }
test "WithQualifier succeeds" { test "WithQualifier succeeds" {
let field = (Field.EQ "Bill" "Matt").WithParameterName "@joe" let field = (Field.EQ "Bill" "Matt").WithQualifier "joe"
Expect.isSome field.Qualifier "The table qualifier should have been filled" Expect.isSome field.Qualifier "The table qualifier should have been filled"
Expect.equal "@joe" field.Qualifier.Value "The table qualifier is incorrect" Expect.equal "joe" field.Qualifier.Value "The table qualifier is incorrect"
} }
] ]
testList "Query" [ testList "Query" [