Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 26 additions & 9 deletions src/FSharp.Data.GraphQL.Server.Middleware/ObjectListFilter.fs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ type ObjectListFilter =
| Not of ObjectListFilter
| Equals of FieldFilter<System.IComparable>
| GreaterThan of FieldFilter<System.IComparable>
| GreaterThanOrEqual of FieldFilter<System.IComparable>
| LessThan of FieldFilter<System.IComparable>
| LessThanOrEqual of FieldFilter<System.IComparable>
| In of FieldFilter<System.IComparable list>
| StartsWith of FieldFilter<string>
| EndsWith of FieldFilter<string>
| Contains of FieldFilter<string>
Expand Down Expand Up @@ -92,10 +95,16 @@ module ObjectListFilter =
let ( === ) fname value = Equals { FieldName = fname; Value = value }

/// Creates a new ObjectListFilter representing a GREATER THAN operation of a comparable value.
let ( ==> ) fname value = GreaterThan { FieldName = fname; Value = value }
let ( >>> ) fname value = GreaterThan { FieldName = fname; Value = value }

/// Creates a new ObjectListFilter representing a GREATER THAN OR EQUAL operation of a comparable value.
let ( ==> ) fname value = GreaterThanOrEqual { FieldName = fname; Value = value }

/// Creates a new ObjectListFilter representing a LESS THAN operation of a comparable value.
let ( <== ) fname value = LessThan { FieldName = fname; Value = value }
let ( <<< ) fname value = LessThan { FieldName = fname; Value = value }

/// Creates a new ObjectListFilter representing a LESS THAN OR EQUAL operation of a comparable value.
let ( <== ) fname value = LessThanOrEqual { FieldName = fname; Value = value }

/// Creates a new ObjectListFilter representing a STARTS WITH operation of a string value.
let ( =@@ ) fname value = StartsWith { FieldName = fname; Value = value }
Expand All @@ -106,6 +115,9 @@ module ObjectListFilter =
/// Creates a new ObjectListFilter representing a CONTAINS operation.
let ( @=@ ) fname value = Contains { FieldName = fname; Value = value }

/// Creates a new ObjectListFilter representing a IN operation.
let ( =~= ) fname value = In { FieldName = fname; Value = value }

/// Creates a new ObjectListFilter representing a field sub comparison.
let ( --> ) fname filter = FilterField { FieldName = fname; Value = filter }

Expand Down Expand Up @@ -169,6 +181,8 @@ module ObjectListFilter =
| Equals f -> Expression.Equal (Expression.PropertyOrField (param, f.FieldName), Expression.Constant (f.Value))
| GreaterThan f -> Expression.GreaterThan (Expression.PropertyOrField (param, f.FieldName), Expression.Constant (f.Value))
| LessThan f -> Expression.LessThan (Expression.PropertyOrField (param, f.FieldName), Expression.Constant (f.Value))
| GreaterThanOrEqual f -> Expression.GreaterThanOrEqual (Expression.PropertyOrField (param, f.FieldName), Expression.Constant (f.Value))
| LessThanOrEqual f -> Expression.LessThanOrEqual (Expression.PropertyOrField (param, f.FieldName), Expression.Constant (f.Value))
| StartsWith f -> Expression.Call (Expression.PropertyOrField (param, f.FieldName), StringStartsWithMethod, Expression.Constant (f.Value))
| EndsWith f -> Expression.Call (Expression.PropertyOrField (param, f.FieldName), StringEndsWithMethod, Expression.Constant (f.Value))
| Contains f ->
Expand Down Expand Up @@ -201,6 +215,12 @@ module ObjectListFilter =
Expression.Constant (f.Value)
)
| _ -> Expression.Call (``member``, StringContainsMethod, Expression.Constant (f.Value))
| In f ->
let ``member`` = Expression.PropertyOrField (param, f.FieldName)
f.Value
|> Seq.map (fun v -> Expression.Equal (``member``, Expression.Constant (v)))
|> Seq.reduce (fun acc expr -> Expression.OrElse (acc, expr))
:> Expression
| OfTypes types ->
types
|> Seq.map (fun t -> buildTypeDiscriminatorCheck param t)
Expand All @@ -222,26 +242,23 @@ module ObjectListFilter =
Expression.PropertyOrField (param, "__typename"),
// Default discriminator value
Expression.Constant (t.FullName)
)
:> Expression
) :> Expression
| ValueSome discExpr, ValueNone ->
Expression.Invoke (
// Provided discriminator comparison
discExpr,
param,
// Default discriminator value gathered from type
Expression.Constant (t.FullName)
)
:> Expression
Expression.Constant(t.FullName)
) :> Expression
| ValueNone, ValueSome discValueFn ->
let discriminatorValue = discValueFn t
Expression.Equal (
// Default discriminator property
Expression.PropertyOrField (param, "__typename"),
// Provided discriminator value gathered from type
Expression.Constant (discriminatorValue)
)
:> Expression
) :> Expression
| ValueSome discExpr, ValueSome discValueFn ->
let discriminatorValue = discValueFn t
Expression.Invoke (
Expand Down
34 changes: 25 additions & 9 deletions src/FSharp.Data.GraphQL.Server.Middleware/SchemaDefinitions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,35 @@ open FSharp.Data.GraphQL.Ast

let internal removeNoFilter = Seq.where (fun filter -> filter <> NoFilter)

type private ComparisonOperator =
| EndsWith of string
| StartsWith of string
| Contains of string
| Equals of string
| GreaterThan of string
| GreaterThanOrEqual of string
| LessThan of string
| LessThanOrEqual of string

let rec private coerceObjectListFilterInput x : Result<ObjectListFilter, IGQLError list> =

let (|EndsWith|StartsWith|GreaterThan|LessThan|Contains|Equals|) (s : string) =
let parseFieldCondition (s : string) =
let s = s.ToLowerInvariant ()
let prefix (suffix : string) (s : string) = s.Substring (0, s.Length - suffix.Length)
match s with
| s when s.EndsWith ("_ends_with") && s.Length > "_ends_with".Length -> EndsWith (prefix "_ends_with" s)
| s when s.EndsWith ("_ew") && s.Length > "_ew".Length -> EndsWith (prefix "_ew" s)
| s when s.EndsWith ("_starts_with") && s.Length > "_starts_with".Length -> StartsWith (prefix "_starts_with" s)
| s when s.EndsWith ("_sw") && s.Length > "_sw".Length -> StartsWith (prefix "_sw" s)
| s when s.EndsWith ("_contains") && s.Length > "_contains".Length -> Contains (prefix "_contains" s)
| s when s.EndsWith ("_greater_than") && s.Length > "_greater_than".Length -> GreaterThan (prefix "_greater_than" s)
| s when s.EndsWith ("_gt") && s.Length > "_gt".Length -> GreaterThan (prefix "_gt" s)
| s when s.EndsWith ("_greater_than_or_equal") && s.Length > "_greater_than_or_equal".Length -> GreaterThanOrEqual (prefix "_greater_than_or_equal" s)
| s when s.EndsWith ("_gte") && s.Length > "_gte".Length -> GreaterThanOrEqual (prefix "_gte" s)
| s when s.EndsWith ("_less_than") && s.Length > "_less_than".Length -> LessThan (prefix "_less_than" s)
| s when s.EndsWith ("_lt") && s.Length > "_lt".Length -> LessThan (prefix "_lt" s)
| s when s.EndsWith ("_contains") && s.Length > "_contains".Length -> Contains (prefix "_contains" s)
| s when s.EndsWith ("_less_than_or_equal") && s.Length > "_less_than_or_equal".Length -> LessThanOrEqual (prefix "_less_than_or_equal" s)
| s when s.EndsWith ("_lte") && s.Length > "_lte".Length -> LessThanOrEqual (prefix "_lte" s)
| s -> Equals s

let (|EquatableValue|Other|) v =
Expand Down Expand Up @@ -76,25 +90,27 @@ let rec private coerceObjectListFilterInput x : Result<ObjectListFilter, IGQLErr
match coerceResults with
| Error errs -> Error errs
| Ok coerced -> coerced |> removeNoFilter |> Seq.toList |> Ok
match name, value with
match parseFieldCondition name, value with
| Equals "and", ListValue fields -> fields |> mapFilters |> Result.map buildAnd
| Equals "or", ListValue fields -> fields |> mapFilters |> Result.map buildOr
| Equals "not", ObjectValue value ->
match mapInput value with
| Error errs -> Error errs
| Ok NoFilter -> Ok NoFilter
| Ok filter -> Ok (Not filter)
| EndsWith fname, StringValue value -> Ok (EndsWith { FieldName = fname; Value = value })
| StartsWith fname, StringValue value -> Ok (StartsWith { FieldName = fname; Value = value })
| Contains fname, StringValue value -> Ok (Contains { FieldName = fname; Value = value })
| EndsWith fname, StringValue value -> Ok (ObjectListFilter.EndsWith { FieldName = fname; Value = value })
| StartsWith fname, StringValue value -> Ok (ObjectListFilter.StartsWith { FieldName = fname; Value = value })
| Contains fname, StringValue value -> Ok (ObjectListFilter.Contains { FieldName = fname; Value = value })
| Equals fname, ObjectValue value ->
match mapInput value with
| Error errs -> Error errs
| Ok NoFilter -> Ok NoFilter
| Ok filter -> Ok (FilterField { FieldName = fname; Value = filter })
| Equals fname, EquatableValue value -> Ok (Equals { FieldName = fname; Value = value })
| GreaterThan fname, ComparableValue value -> Ok (GreaterThan { FieldName = fname; Value = value })
| LessThan fname, ComparableValue value -> Ok (LessThan { FieldName = fname; Value = value })
| Equals fname, EquatableValue value -> Ok (ObjectListFilter.Equals { FieldName = fname; Value = value })
| GreaterThan fname, ComparableValue value -> Ok (ObjectListFilter.GreaterThan { FieldName = fname; Value = value })
| GreaterThanOrEqual fname, ComparableValue value -> Ok (ObjectListFilter.GreaterThanOrEqual { FieldName = fname; Value = value })
| LessThan fname, ComparableValue value -> Ok (ObjectListFilter.LessThan { FieldName = fname; Value = value })
| LessThanOrEqual fname, ComparableValue value -> Ok (ObjectListFilter.LessThanOrEqual { FieldName = fname; Value = value })
| _ -> Ok NoFilter

and mapInput value =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
namespace rec FSharp.Data.GraphQL

open System.Linq
open System.Collections.Generic
open FsToolkit.ErrorHandling

module internal ValueOption =
Expand All @@ -11,6 +12,12 @@ module internal Option =

let mapValueOption mapping voption = voption |> ValueOption.map mapping |> ValueOption.toOption

[<AutoOpen>]
module KeyValuePair =

let inline kvp key value = KeyValuePair (key, value)
let inline kvpObj key (value : obj) = KeyValuePair (key, value)

[<AutoOpen>]
module internal ValueTuple =

Expand Down
Loading