Skip to content

Commit 9196cd1

Browse files
author
Viktor Tochonov
committed
Merge branch 'additional-list-filter-operators' into dev
2 parents 8dd7d03 + 82d96da commit 9196cd1

File tree

5 files changed

+256
-35
lines changed

5 files changed

+256
-35
lines changed

src/FSharp.Data.GraphQL.Server.Middleware/ObjectListFilter.fs

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ type ObjectListFilter =
1212
| Not of ObjectListFilter
1313
| Equals of FieldFilter<System.IComparable>
1414
| GreaterThan of FieldFilter<System.IComparable>
15+
| GreaterThanOrEqual of FieldFilter<System.IComparable>
1516
| LessThan of FieldFilter<System.IComparable>
17+
| LessThanOrEqual of FieldFilter<System.IComparable>
18+
| In of FieldFilter<System.IComparable list>
1619
| StartsWith of FieldFilter<string>
1720
| EndsWith of FieldFilter<string>
1821
| Contains of FieldFilter<string>
@@ -92,10 +95,16 @@ module ObjectListFilter =
9295
let ( === ) fname value = Equals { FieldName = fname; Value = value }
9396

9497
/// Creates a new ObjectListFilter representing a GREATER THAN operation of a comparable value.
95-
let ( ==> ) fname value = GreaterThan { FieldName = fname; Value = value }
98+
let ( >>> ) fname value = GreaterThan { FieldName = fname; Value = value }
99+
100+
/// Creates a new ObjectListFilter representing a GREATER THAN OR EQUAL operation of a comparable value.
101+
let ( ==> ) fname value = GreaterThanOrEqual { FieldName = fname; Value = value }
96102

97103
/// Creates a new ObjectListFilter representing a LESS THAN operation of a comparable value.
98-
let ( <== ) fname value = LessThan { FieldName = fname; Value = value }
104+
let ( <<< ) fname value = LessThan { FieldName = fname; Value = value }
105+
106+
/// Creates a new ObjectListFilter representing a LESS THAN OR EQUAL operation of a comparable value.
107+
let ( <== ) fname value = LessThanOrEqual { FieldName = fname; Value = value }
99108

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

118+
/// Creates a new ObjectListFilter representing a IN operation.
119+
let ( =~= ) fname value = In { FieldName = fname; Value = value }
120+
109121
/// Creates a new ObjectListFilter representing a field sub comparison.
110122
let ( --> ) fname filter = FilterField { FieldName = fname; Value = filter }
111123

@@ -169,6 +181,8 @@ module ObjectListFilter =
169181
| Equals f -> Expression.Equal (Expression.PropertyOrField (param, f.FieldName), Expression.Constant (f.Value))
170182
| GreaterThan f -> Expression.GreaterThan (Expression.PropertyOrField (param, f.FieldName), Expression.Constant (f.Value))
171183
| LessThan f -> Expression.LessThan (Expression.PropertyOrField (param, f.FieldName), Expression.Constant (f.Value))
184+
| GreaterThanOrEqual f -> Expression.GreaterThanOrEqual (Expression.PropertyOrField (param, f.FieldName), Expression.Constant (f.Value))
185+
| LessThanOrEqual f -> Expression.LessThanOrEqual (Expression.PropertyOrField (param, f.FieldName), Expression.Constant (f.Value))
172186
| StartsWith f -> Expression.Call (Expression.PropertyOrField (param, f.FieldName), StringStartsWithMethod, Expression.Constant (f.Value))
173187
| EndsWith f -> Expression.Call (Expression.PropertyOrField (param, f.FieldName), StringEndsWithMethod, Expression.Constant (f.Value))
174188
| Contains f ->
@@ -201,6 +215,14 @@ module ObjectListFilter =
201215
Expression.Constant (f.Value)
202216
)
203217
| _ -> Expression.Call (``member``, StringContainsMethod, Expression.Constant (f.Value))
218+
| In f ->
219+
let ``member`` = Expression.PropertyOrField (param, f.FieldName)
220+
let values =
221+
f.Value
222+
|> List.map (fun v -> Expression.Equal (``member``, Expression.Constant (v)))
223+
(values
224+
|> List.reduce (fun acc expr -> Expression.OrElse (acc, expr)))
225+
:> Expression
204226
| OfTypes types ->
205227
types
206228
|> Seq.map (fun t -> buildTypeDiscriminatorCheck param t)
@@ -222,26 +244,23 @@ module ObjectListFilter =
222244
Expression.PropertyOrField (param, "__typename"),
223245
// Default discriminator value
224246
Expression.Constant (t.FullName)
225-
)
226-
:> Expression
247+
) :> Expression
227248
| ValueSome discExpr, ValueNone ->
228249
Expression.Invoke (
229250
// Provided discriminator comparison
230251
discExpr,
231252
param,
232253
// Default discriminator value gathered from type
233-
Expression.Constant (t.FullName)
234-
)
235-
:> Expression
254+
Expression.Constant(t.FullName)
255+
) :> Expression
236256
| ValueNone, ValueSome discValueFn ->
237257
let discriminatorValue = discValueFn t
238258
Expression.Equal (
239259
// Default discriminator property
240260
Expression.PropertyOrField (param, "__typename"),
241261
// Provided discriminator value gathered from type
242262
Expression.Constant (discriminatorValue)
243-
)
244-
:> Expression
263+
) :> Expression
245264
| ValueSome discExpr, ValueSome discValueFn ->
246265
let discriminatorValue = discValueFn t
247266
Expression.Invoke (

src/FSharp.Data.GraphQL.Server.Middleware/SchemaDefinitions.fs

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,35 @@ open FSharp.Data.GraphQL.Ast
1212

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

15+
type private ComparisonOperator =
16+
| EndsWith of string
17+
| StartsWith of string
18+
| Contains of string
19+
| Equals of string
20+
| GreaterThan of string
21+
| GreaterThanOrEqual of string
22+
| LessThan of string
23+
| LessThanOrEqual of string
24+
1525
let rec private coerceObjectListFilterInput x : Result<ObjectListFilter, IGQLError list> =
1626

17-
let (|EndsWith|StartsWith|GreaterThan|LessThan|Contains|Equals|) (s : string) =
27+
let parseFieldCondition (s : string) =
1828
let s = s.ToLowerInvariant ()
1929
let prefix (suffix : string) (s : string) = s.Substring (0, s.Length - suffix.Length)
2030
match s with
2131
| s when s.EndsWith ("_ends_with") && s.Length > "_ends_with".Length -> EndsWith (prefix "_ends_with" s)
2232
| s when s.EndsWith ("_ew") && s.Length > "_ew".Length -> EndsWith (prefix "_ew" s)
2333
| s when s.EndsWith ("_starts_with") && s.Length > "_starts_with".Length -> StartsWith (prefix "_starts_with" s)
2434
| s when s.EndsWith ("_sw") && s.Length > "_sw".Length -> StartsWith (prefix "_sw" s)
35+
| s when s.EndsWith ("_contains") && s.Length > "_contains".Length -> Contains (prefix "_contains" s)
2536
| s when s.EndsWith ("_greater_than") && s.Length > "_greater_than".Length -> GreaterThan (prefix "_greater_than" s)
2637
| s when s.EndsWith ("_gt") && s.Length > "_gt".Length -> GreaterThan (prefix "_gt" s)
38+
| s when s.EndsWith ("_greater_than_or_equal") && s.Length > "_greater_than_or_equal".Length -> GreaterThanOrEqual (prefix "_greater_than_or_equal" s)
39+
| s when s.EndsWith ("_gte") && s.Length > "_gte".Length -> GreaterThanOrEqual (prefix "_gte" s)
2740
| s when s.EndsWith ("_less_than") && s.Length > "_less_than".Length -> LessThan (prefix "_less_than" s)
2841
| s when s.EndsWith ("_lt") && s.Length > "_lt".Length -> LessThan (prefix "_lt" s)
29-
| s when s.EndsWith ("_contains") && s.Length > "_contains".Length -> Contains (prefix "_contains" s)
42+
| s when s.EndsWith ("_less_than_or_equal") && s.Length > "_less_than_or_equal".Length -> LessThanOrEqual (prefix "_less_than_or_equal" s)
43+
| s when s.EndsWith ("_lte") && s.Length > "_lte".Length -> LessThanOrEqual (prefix "_lte" s)
3044
| s -> Equals s
3145

3246
let (|EquatableValue|Other|) v =
@@ -76,25 +90,27 @@ let rec private coerceObjectListFilterInput x : Result<ObjectListFilter, IGQLErr
7690
match coerceResults with
7791
| Error errs -> Error errs
7892
| Ok coerced -> coerced |> removeNoFilter |> Seq.toList |> Ok
79-
match name, value with
93+
match parseFieldCondition name, value with
8094
| Equals "and", ListValue fields -> fields |> mapFilters |> Result.map buildAnd
8195
| Equals "or", ListValue fields -> fields |> mapFilters |> Result.map buildOr
8296
| Equals "not", ObjectValue value ->
8397
match mapInput value with
8498
| Error errs -> Error errs
8599
| Ok NoFilter -> Ok NoFilter
86100
| Ok filter -> Ok (Not filter)
87-
| EndsWith fname, StringValue value -> Ok (EndsWith { FieldName = fname; Value = value })
88-
| StartsWith fname, StringValue value -> Ok (StartsWith { FieldName = fname; Value = value })
89-
| Contains fname, StringValue value -> Ok (Contains { FieldName = fname; Value = value })
101+
| EndsWith fname, StringValue value -> Ok (ObjectListFilter.EndsWith { FieldName = fname; Value = value })
102+
| StartsWith fname, StringValue value -> Ok (ObjectListFilter.StartsWith { FieldName = fname; Value = value })
103+
| Contains fname, StringValue value -> Ok (ObjectListFilter.Contains { FieldName = fname; Value = value })
90104
| Equals fname, ObjectValue value ->
91105
match mapInput value with
92106
| Error errs -> Error errs
93107
| Ok NoFilter -> Ok NoFilter
94108
| Ok filter -> Ok (FilterField { FieldName = fname; Value = filter })
95-
| Equals fname, EquatableValue value -> Ok (Equals { FieldName = fname; Value = value })
96-
| GreaterThan fname, ComparableValue value -> Ok (GreaterThan { FieldName = fname; Value = value })
97-
| LessThan fname, ComparableValue value -> Ok (LessThan { FieldName = fname; Value = value })
109+
| Equals fname, EquatableValue value -> Ok (ObjectListFilter.Equals { FieldName = fname; Value = value })
110+
| GreaterThan fname, ComparableValue value -> Ok (ObjectListFilter.GreaterThan { FieldName = fname; Value = value })
111+
| GreaterThanOrEqual fname, ComparableValue value -> Ok (ObjectListFilter.GreaterThanOrEqual { FieldName = fname; Value = value })
112+
| LessThan fname, ComparableValue value -> Ok (ObjectListFilter.LessThan { FieldName = fname; Value = value })
113+
| LessThanOrEqual fname, ComparableValue value -> Ok (ObjectListFilter.LessThanOrEqual { FieldName = fname; Value = value })
98114
| _ -> Ok NoFilter
99115

100116
and mapInput value =

src/FSharp.Data.GraphQL.Shared/Helpers/ObjAndStructConversions.fs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
namespace rec FSharp.Data.GraphQL
22

33
open System.Linq
4+
open System.Collections.Generic
45
open FsToolkit.ErrorHandling
56

67
module internal ValueOption =
@@ -11,6 +12,12 @@ module internal Option =
1112

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

15+
[<AutoOpen>]
16+
module KeyValuePair =
17+
18+
let inline kvp key value = KeyValuePair (key, value)
19+
let inline kvpObj key (value : obj) = KeyValuePair (key, value)
20+
1421
[<AutoOpen>]
1522
module internal ValueTuple =
1623

0 commit comments

Comments
 (0)