Skip to content

Commit 4b5cc32

Browse files
author
Viktor Tochonov
committed
Add new operators In, GreaterThanOrEqual, LessThanOrEqual
1 parent 952757e commit 4b5cc32

File tree

1 file changed

+72
-36
lines changed

1 file changed

+72
-36
lines changed

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

Lines changed: 72 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,8 @@ open System.Reflection
5959
/// )
6060
/// </code></example>
6161
[<Struct>]
62-
type ObjectListFilterLinqOptions<'T, 'D> (
63-
[<Optional>] compareDiscriminator : Expression<Func<'T, 'D, bool>> | null,
64-
[<Optional>] getDiscriminatorValue : (Type -> 'D) | null
65-
) =
62+
type ObjectListFilterLinqOptions<'T, 'D>
63+
([<Optional>] compareDiscriminator : Expression<Func<'T, 'D, bool>> | null, [<Optional>] getDiscriminatorValue : (Type -> 'D) | null) =
6664

6765
member _.CompareDiscriminator = compareDiscriminator |> ValueOption.ofObj
6866
member _.GetDiscriminatorValue = getDiscriminatorValue |> ValueOption.ofObj
@@ -72,13 +70,16 @@ type ObjectListFilterLinqOptions<'T, 'D> (
7270
static member GetCompareDiscriminator (getDiscriminatorValue : Expression<Func<'T, 'D>>) =
7371
let tParam = Expression.Parameter (typeof<'T>, "x")
7472
let dParam = Expression.Parameter (typeof<'D>, "d")
75-
let body = Expression.Equal(Expression.Invoke(getDiscriminatorValue, tParam), dParam)
73+
let body = Expression.Equal (Expression.Invoke (getDiscriminatorValue, tParam), dParam)
7674
Expression.Lambda<Func<'T, 'D, bool>> (body, tParam, dParam)
7775

78-
new (getDiscriminator : Expression<Func<'T, 'D>>) = ObjectListFilterLinqOptions<'T, 'D> (ObjectListFilterLinqOptions.GetCompareDiscriminator getDiscriminator, null)
76+
new (getDiscriminator : Expression<Func<'T, 'D>>) =
77+
ObjectListFilterLinqOptions<'T, 'D> (ObjectListFilterLinqOptions.GetCompareDiscriminator getDiscriminator, null)
7978
new (compareDiscriminator : Expression<Func<'T, 'D, bool>>) = ObjectListFilterLinqOptions<'T, 'D> (compareDiscriminator, null)
80-
new (getDiscriminatorValue : Type -> 'D) = ObjectListFilterLinqOptions<'T, 'D> (compareDiscriminator = null , getDiscriminatorValue = getDiscriminatorValue)
81-
new (getDiscriminator : Expression<Func<'T, 'D>>, getDiscriminatorValue : Type -> 'D) = ObjectListFilterLinqOptions<'T, 'D> (ObjectListFilterLinqOptions.GetCompareDiscriminator getDiscriminator, getDiscriminatorValue)
79+
new (getDiscriminatorValue : Type -> 'D) =
80+
ObjectListFilterLinqOptions<'T, 'D> (compareDiscriminator = null, getDiscriminatorValue = getDiscriminatorValue)
81+
new (getDiscriminator : Expression<Func<'T, 'D>>, getDiscriminatorValue : Type -> 'D) =
82+
ObjectListFilterLinqOptions<'T, 'D> (ObjectListFilterLinqOptions.GetCompareDiscriminator getDiscriminator, getDiscriminatorValue)
8283

8384
/// Contains tooling for working with ObjectListFilter.
8485
module ObjectListFilter =
@@ -94,10 +95,16 @@ module ObjectListFilter =
9495
let ( === ) fname value = Equals { FieldName = fname; Value = value }
9596

9697
/// Creates a new ObjectListFilter representing a GREATER THAN operation of a comparable value.
97-
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 }
98102

99103
/// Creates a new ObjectListFilter representing a LESS THAN operation of a comparable value.
100-
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 }
101108

102109
/// Creates a new ObjectListFilter representing a STARTS WITH operation of a string value.
103110
let ( =@@ ) fname value = StartsWith { FieldName = fname; Value = value }
@@ -108,6 +115,9 @@ module ObjectListFilter =
108115
/// Creates a new ObjectListFilter representing a CONTAINS operation.
109116
let ( @=@ ) fname value = Contains { FieldName = fname; Value = value }
110117

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

@@ -131,15 +141,25 @@ module ObjectListFilter =
131141
let private StringEndsWithMethod = typeof<string>.GetMethod ("EndsWith", [| typeof<string> |])
132142
let private StringContainsMethod = typeof<string>.GetMethod ("Contains", [| typeof<string> |])
133143
let private getEnumerableContainsMethod (memberType : Type) =
134-
match typeof<Enumerable>.GetMethods(BindingFlags.Static ||| BindingFlags.Public).FirstOrDefault(fun m -> m.Name = "Contains" && m.GetParameters().Length = 2) with
144+
match
145+
typeof<Enumerable>
146+
.GetMethods(BindingFlags.Static ||| BindingFlags.Public)
147+
.FirstOrDefault (fun m -> m.Name = "Contains" && m.GetParameters().Length = 2)
148+
with
135149
| null -> raise (MissingMemberException "Static 'Contains' method with 2 parameters not found on 'Enumerable' class")
136150
| containsGenericStaticMethod ->
137-
if memberType.IsGenericType && memberType.GenericTypeArguments.Length = 1 then
138-
containsGenericStaticMethod.MakeGenericMethod(memberType.GenericTypeArguments)
151+
if
152+
memberType.IsGenericType
153+
&& memberType.GenericTypeArguments.Length = 1
154+
then
155+
containsGenericStaticMethod.MakeGenericMethod (memberType.GenericTypeArguments)
139156
else
140-
let ienumerable = memberType.GetInterfaces().First(fun i -> i.FullName.StartsWith "System.Collections.Generic.IEnumerable`1")
141-
containsGenericStaticMethod.MakeGenericMethod([| ienumerable.GenericTypeArguments[0] |])
142-
157+
let ienumerable =
158+
memberType
159+
.GetInterfaces()
160+
.First (fun i -> i.FullName.StartsWith "System.Collections.Generic.IEnumerable`1")
161+
containsGenericStaticMethod.MakeGenericMethod ([| ienumerable.GenericTypeArguments[0] |])
162+
143163
let getField (param : ParameterExpression) fieldName = Expression.PropertyOrField (param, fieldName)
144164

145165
[<Struct>]
@@ -161,31 +181,48 @@ module ObjectListFilter =
161181
| Equals f -> Expression.Equal (Expression.PropertyOrField (param, f.FieldName), Expression.Constant (f.Value))
162182
| GreaterThan f -> Expression.GreaterThan (Expression.PropertyOrField (param, f.FieldName), Expression.Constant (f.Value))
163183
| LessThan f -> Expression.LessThan (Expression.PropertyOrField (param, f.FieldName), Expression.Constant (f.Value))
164-
| GreaterThanOrEqual f -> Expression.GreaterThanOrEqual(Expression.PropertyOrField (param, f.FieldName), Expression.Constant (f.Value))
184+
| GreaterThanOrEqual f -> Expression.GreaterThanOrEqual (Expression.PropertyOrField (param, f.FieldName), Expression.Constant (f.Value))
165185
| LessThanOrEqual f -> Expression.LessThanOrEqual (Expression.PropertyOrField (param, f.FieldName), Expression.Constant (f.Value))
166-
| StartsWith f ->
167-
Expression.Call (Expression.PropertyOrField (param, f.FieldName), StringStartsWithMethod, Expression.Constant (f.Value))
168-
| EndsWith f ->
169-
Expression.Call (Expression.PropertyOrField (param, f.FieldName), StringEndsWithMethod, Expression.Constant (f.Value))
186+
| StartsWith f -> Expression.Call (Expression.PropertyOrField (param, f.FieldName), StringStartsWithMethod, Expression.Constant (f.Value))
187+
| EndsWith f -> Expression.Call (Expression.PropertyOrField (param, f.FieldName), StringEndsWithMethod, Expression.Constant (f.Value))
170188
| Contains f ->
171189
let ``member`` = Expression.PropertyOrField (param, f.FieldName)
172-
let isEnumerable (memberType: Type) =
173-
not (Type.(=)(memberType, typeof<string>))
174-
&& typeof<System.Collections.IEnumerable>.IsAssignableFrom(memberType)
175-
&& memberType.GetInterfaces().Any(fun i -> i.FullName.StartsWith "System.Collections.Generic.IEnumerable`1")
176-
match ``member``.Member with
190+
let isEnumerable (memberType : Type) =
191+
not (Type.(=) (memberType, typeof<string>))
192+
&& typeof<System.Collections.IEnumerable>.IsAssignableFrom (memberType)
193+
&& memberType
194+
.GetInterfaces()
195+
.Any (fun i -> i.FullName.StartsWith "System.Collections.Generic.IEnumerable`1")
196+
match ``member``.Member with
177197
| :? PropertyInfo as prop when prop.PropertyType |> isEnumerable ->
178-
match prop.PropertyType.GetMethods(BindingFlags.Instance ||| BindingFlags.Public).FirstOrDefault(fun m -> m.Name = "Contains" && m.GetParameters().Length = 1) with
179-
| null -> Expression.Call (getEnumerableContainsMethod prop.PropertyType, Expression.PropertyOrField (param, f.FieldName), Expression.Constant (f.Value))
180-
| instanceContainsMethod -> Expression.Call (Expression.PropertyOrField (param, f.FieldName),instanceContainsMethod, Expression.Constant (f.Value))
198+
match
199+
prop.PropertyType
200+
.GetMethods(BindingFlags.Instance ||| BindingFlags.Public)
201+
.FirstOrDefault (fun m -> m.Name = "Contains" && m.GetParameters().Length = 1)
202+
with
203+
| null ->
204+
Expression.Call (
205+
getEnumerableContainsMethod prop.PropertyType,
206+
Expression.PropertyOrField (param, f.FieldName),
207+
Expression.Constant (f.Value)
208+
)
209+
| instanceContainsMethod ->
210+
Expression.Call (Expression.PropertyOrField (param, f.FieldName), instanceContainsMethod, Expression.Constant (f.Value))
181211
| :? FieldInfo as field when field.FieldType |> isEnumerable ->
182-
Expression.Call (getEnumerableContainsMethod field.FieldType, Expression.PropertyOrField (param, f.FieldName), Expression.Constant (f.Value))
183-
| _ ->
184-
Expression.Call (``member``, StringContainsMethod, Expression.Constant (f.Value))
212+
Expression.Call (
213+
getEnumerableContainsMethod field.FieldType,
214+
Expression.PropertyOrField (param, f.FieldName),
215+
Expression.Constant (f.Value)
216+
)
217+
| _ -> Expression.Call (``member``, StringContainsMethod, Expression.Constant (f.Value))
185218
| In f ->
186219
let ``member`` = Expression.PropertyOrField (param, f.FieldName)
187-
let values = f.Value |> List.map (fun v -> Expression.Equal(``member``, Expression.Constant(v)))
188-
(values |> List.reduce (fun acc expr -> Expression.OrElse(acc, expr))) :> Expression
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
189226
| OfTypes types ->
190227
types
191228
|> Seq.map (fun t -> buildTypeDiscriminatorCheck param t)
@@ -237,5 +274,4 @@ module ObjectListFilterExtensions =
237274

238275
type IQueryable<'T> with
239276

240-
member inline query.Apply (filter : ObjectListFilter, [<Optional>] options : ObjectListFilterLinqOptions<'T, 'D>) =
241-
apply options filter query
277+
member inline query.Apply (filter : ObjectListFilter, [<Optional>] options : ObjectListFilterLinqOptions<'T, 'D>) = apply options filter query

0 commit comments

Comments
 (0)