@@ -20,6 +20,75 @@ type ObjectListFilter =
2020 | FilterField of FieldFilter < ObjectListFilter >
2121 | NoFilter
2222
23+ open System.Linq
24+ open System.Linq .Expressions
25+ open System.Runtime .InteropServices
26+ open System.Reflection
27+
28+ /// <remarks>
29+ /// Represents a value that can be either None or Some.
30+ /// </remarks>
31+
32+ /// <summary>
33+ /// Allows to specify discriminator comparison or discriminator getter
34+ /// and a function that return discriminator value depending on entity type
35+ /// </summary>
36+ /// <example id="item-1"><code lang="fsharp">
37+ /// // discriminator custom condition
38+ /// let result () =
39+ /// queryable.Apply(
40+ /// filter,
41+ /// ObjectListFilterLinqOptions (
42+ /// (fun entity discriminator -> entity.Discriminator.StartsWith discriminator),
43+ /// (function
44+ /// | t when Type.(=)(t, typeof<Cat>) -> "cat+v1"
45+ /// | t when Type.(=)(t, typeof<Dog>) -> "dog+v1")
46+ /// )
47+ /// )
48+ /// </code></example>
49+ /// <example id="item-2"><code lang="fsharp">
50+ /// // discriminator equals
51+ /// let result () =
52+ /// queryable.Apply(
53+ /// filter,
54+ /// ObjectListFilterLinqOptions (
55+ /// (fun entity -> entity.Discriminator),
56+ /// (function
57+ /// | t when Type.(=)(t, typeof<Cat>) -> "cat"
58+ /// | t when Type.(=)(t, typeof<Dog>) -> "dog")
59+ /// )
60+ /// )
61+ /// </code></example>
62+ [<Struct>]
63+ type ObjectListFilterLinqOptions < 'T , 'D > (
64+ [<Optional>] compareDiscriminator : Expression< Func< 'T, 'D, bool>> | null ,
65+ [<Optional>] getDiscriminatorValue : ( Type -> 'D) | null ,
66+ [<Optional>] serializeMemberName : ( MemberInfo -> string) | null
67+ ) =
68+
69+ member _.CompareDiscriminator = compareDiscriminator |> ValueOption.ofObj
70+ member _.GetDiscriminatorValue = getDiscriminatorValue |> ValueOption.ofObj
71+ //member _.SerializeMemberName = serializeMemberName |> ValueOption.ofObj
72+
73+ static member None = ObjectListFilterLinqOptions< 'T, 'D> ( null , null , null )
74+
75+ static member GetCompareDiscriminator ( getDiscriminatorValue : Expression < Func < 'T , 'D >>) =
76+ let tParam = Expression.Parameter ( typeof< 'T>, " x" )
77+ let dParam = Expression.Parameter ( typeof< 'D>, " d" )
78+ let body = Expression.Equal( Expression.Invoke( getDiscriminatorValue, tParam), dParam)
79+ Expression.Lambda< Func< 'T, 'D, bool>> ( body, tParam, dParam)
80+
81+ new ( getDiscriminator : Expression < Func < 'T , 'D >>) = ObjectListFilterLinqOptions< 'T, 'D> ( ObjectListFilterLinqOptions.GetCompareDiscriminator getDiscriminator, null , null )
82+ new ( compareDiscriminator : Expression < Func < 'T , 'D , bool >>) = ObjectListFilterLinqOptions< 'T, 'D> ( compareDiscriminator, null , null )
83+ new ( getDiscriminatorValue : Type -> 'D ) = ObjectListFilterLinqOptions< 'T, 'D> ( null , getDiscriminatorValue, null )
84+ //new (serializeMemberName : MemberInfo -> string) = ObjectListFilterLinqOptions<'T, 'D> (null, null, serializeMemberName)
85+
86+ new ( getDiscriminator : Expression < Func < 'T , 'D >>, getDiscriminatorValue : Type -> 'D ) = ObjectListFilterLinqOptions< 'T, 'D> ( ObjectListFilterLinqOptions.GetCompareDiscriminator getDiscriminator, getDiscriminatorValue, null )
87+
88+ //new (getDiscriminator : Expression<Func<'T, 'D>>, serializeMemberName : MemberInfo -> string) = ObjectListFilterLinqOptions<'T, 'D> (ObjectListFilterLinqOptions.GetCompareDiscriminator getDiscriminator, null, serializeMemberName)
89+ //new (compareDiscriminator : Expression<Func<'T, 'D, bool>>, serializeMemberName : MemberInfo -> string) = ObjectListFilterLinqOptions<'T, 'D> (compareDiscriminator, null, serializeMemberName)
90+ //new (getDiscriminatorValue : Type -> 'D, serializeMemberName : MemberInfo -> string) = ObjectListFilterLinqOptions<'T, 'D> (null, getDiscriminatorValue, serializeMemberName)
91+
2392/// Contains tooling for working with ObjectListFilter.
2493module ObjectListFilter =
2594 /// Contains operators for building and comparing ObjectListFilter values.
@@ -54,34 +123,6 @@ module ObjectListFilter =
54123 /// Creates a new ObjectListFilter representing a NOT opreation for the existing one.
55124 let ( !!! ) filter = Not filter
56125
57- open System.Linq
58- open System.Linq .Expressions
59- open System.Runtime .InteropServices
60- open System.Reflection
61-
62- [<AutoOpen>]
63- module ObjectListFilterExtensions =
64-
65-
66- //// discriminator custom condition
67- //let a () =
68- // filter.Apply(
69- // queryable,
70- // <@ fun e d -> e.Discriminator.StartsWith d @>,
71- // function
72- // | t when Type.(=)(t, typeof<Complex>) -> ResidentialPropertiesConstants.Discriminators.Complex
73- // | t when Type.(=)(t, typeof<Building>) -> ResidentialPropertiesConstants.Discriminators.Building
74- // )
75- //// discriminator equals
76- //let b () =
77- // filter.Apply(
78- // queryable,
79- // <@ fun e -> e.Discriminator @>,
80- // function
81- // | t when Type.(=)(t, typeof<Complex>) -> ResidentialPropertiesConstants.Discriminators.Complex
82- // | t when Type.(=)(t, typeof<Building>) -> ResidentialPropertiesConstants.Discriminators.Building
83- // )
84-
85126 let private genericWhereMethod =
86127 typeof< Queryable>. GetMethods ()
87128 |> Seq.where ( fun m -> m.Name = " Where" )
@@ -98,6 +139,18 @@ module ObjectListFilterExtensions =
98139 let private StringStartsWithMethod = typeof< string>. GetMethod ( " StartsWith" , [| typeof< string> |])
99140 let private StringEndsWithMethod = typeof< string>. GetMethod ( " EndsWith" , [| typeof< string> |])
100141 let private StringContainsMethod = typeof< string>. GetMethod ( " Contains" , [| typeof< string> |])
142+ let private getEnumerableContainsMethod ( memberType : Type ) =
143+ match memberType.GetMethods( BindingFlags.Instance &&& BindingFlags.Public) .FirstOrDefault( fun m -> m.Name = " Contains" && m.GetParameters() .Length = 2 ) with
144+ | null ->
145+ match typeof< Enumerable>. GetMethods( BindingFlags.Static ||| BindingFlags.Public) .FirstOrDefault( fun m -> m.Name = " Contains" && m.GetParameters() .Length = 2 ) with
146+ | null -> raise ( MissingMemberException " Static 'Contains' method with 2 parameters not found on 'Enumerable' class" )
147+ | containsGenericStaticMethod ->
148+ if memberType.IsGenericType && memberType.GenericTypeArguments.Length = 1 then
149+ containsGenericStaticMethod.MakeGenericMethod( memberType.GenericTypeArguments)
150+ else
151+ let ienumerable = memberType.GetType() .GetInterfaces() .First( fun i -> i.FullName.StartsWith " System.Collections.Generic.IEnumerable`1" )
152+ containsGenericStaticMethod.MakeGenericMethod([| ienumerable.GenericTypeArguments[ 0 ] |])
153+ | instanceContainsMethod -> instanceContainsMethod
101154
102155 let getField ( param : ParameterExpression ) fieldName = Expression.PropertyOrField ( param, fieldName)
103156
@@ -125,7 +178,18 @@ module ObjectListFilterExtensions =
125178 | EndsWith f ->
126179 Expression.Call ( Expression.PropertyOrField ( param, f.FieldName), StringEndsWithMethod, Expression.Constant ( f.Value))
127180 | Contains f ->
128- Expression.Call ( Expression.PropertyOrField ( param, f.FieldName), StringContainsMethod, Expression.Constant ( f.Value))
181+ let ``member`` = Expression.PropertyOrField ( param, f.FieldName)
182+ let isEnumerable ( memberType : Type ) =
183+ not ( Type.(=)( memberType, typeof< string>))
184+ && typeof< System.Collections.IEnumerable>. IsAssignableFrom( memberType)
185+ && memberType.GetInterfaces() .Any( fun i -> i.FullName.StartsWith " System.Collections.Generic.IEnumerable`1" )
186+ match `` member `` .Member with
187+ | :? PropertyInfo as prop when prop.PropertyType |> isEnumerable ->
188+ Expression.Call ( getEnumerableContainsMethod prop.PropertyType, Expression.PropertyOrField ( param, f.FieldName), Expression.Constant ( f.Value))
189+ | :? FieldInfo as field when field.FieldType |> isEnumerable ->
190+ Expression.Call ( getEnumerableContainsMethod field.FieldType, Expression.PropertyOrField ( param, f.FieldName), Expression.Constant ( f.Value))
191+ | _ ->
192+ Expression.Call ( `` member `` , StringContainsMethod, Expression.Constant ( f.Value))
129193 | OfTypes types ->
130194 types
131195 |> Seq.map ( fun t -> buildTypeDiscriminatorCheck param t)
@@ -134,39 +198,7 @@ module ObjectListFilterExtensions =
134198 let paramExpr = Expression.PropertyOrField ( param, f.FieldName)
135199 buildFilterExpr ( SourceExpression paramExpr) buildTypeDiscriminatorCheck f.Value
136200
137- [<Struct>]
138- type ObjectListFilterLinqOptions < 'T , 'D > (
139- [<Optional>] compareDiscriminator : Expression< Func< 'T, 'D, bool>> | null ,
140- [<Optional>] getDiscriminatorValue : ( Type -> 'D) | null ,
141- [<Optional>] serializeMemberName : ( MemberInfo -> string) | null ) =
142-
143- member _.CompareDiscriminator = compareDiscriminator |> ValueOption.ofObj
144- member _.GetDiscriminatorValue = getDiscriminatorValue |> ValueOption.ofObj
145- //member _.SerializeMemberName = serializeMemberName |> ValueOption.ofObj
146-
147- static member None = ObjectListFilterLinqOptions< 'T, 'D> ( null , null , null )
148-
149- static member GetCompareDiscriminator ( getDiscriminatorValue : Expression < Func < 'T , 'D >>) =
150- let tParam = Expression.Parameter ( typeof< 'T>, " x" )
151- let dParam = Expression.Parameter ( typeof< 'D>, " d" )
152- let body = Expression.Equal( Expression.Invoke( getDiscriminatorValue, tParam), dParam)
153- Expression.Lambda< Func< 'T, 'D, bool>> ( body, tParam, dParam)
154-
155- new ( getDiscriminator : Expression < Func < 'T , 'D >>) = ObjectListFilterLinqOptions< 'T, 'D> ( ObjectListFilterLinqOptions.GetCompareDiscriminator getDiscriminator, null , null )
156- new ( compareDiscriminator : Expression < Func < 'T , 'D , bool >>) = ObjectListFilterLinqOptions< 'T, 'D> ( compareDiscriminator, null , null )
157- new ( getDiscriminatorValue : Type -> 'D ) = ObjectListFilterLinqOptions< 'T, 'D> ( null , getDiscriminatorValue, null )
158- //new (serializeMemberName : MemberInfo -> string) = ObjectListFilterLinqOptions<'T, 'D> (null, null, serializeMemberName)
159-
160- new ( getDiscriminator : Expression < Func < 'T , 'D >>, getDiscriminatorValue : Type -> 'D ) = ObjectListFilterLinqOptions< 'T, 'D> ( ObjectListFilterLinqOptions.GetCompareDiscriminator getDiscriminator, getDiscriminatorValue, null )
161-
162- //new (getDiscriminator : Expression<Func<'T, 'D>>, serializeMemberName : MemberInfo -> string) = ObjectListFilterLinqOptions<'T, 'D> (ObjectListFilterLinqOptions.GetCompareDiscriminator getDiscriminator, null, serializeMemberName)
163- //new (compareDiscriminator : Expression<Func<'T, 'D, bool>>, serializeMemberName : MemberInfo -> string) = ObjectListFilterLinqOptions<'T, 'D> (compareDiscriminator, null, serializeMemberName)
164- //new (getDiscriminatorValue : Type -> 'D, serializeMemberName : MemberInfo -> string) = ObjectListFilterLinqOptions<'T, 'D> (null, getDiscriminatorValue, serializeMemberName)
165-
166- type ObjectListFilter with
167-
168- member filter.Apply < 'T , 'D > ( query : IQueryable < 'T >, [<Optional>] options : ObjectListFilterLinqOptions < 'T , 'D >) =
169-
201+ let apply ( options : ObjectListFilterLinqOptions < 'T , 'D >) ( filter : ObjectListFilter ) ( query : IQueryable < 'T >) =
170202 match filter with
171203 | NoFilter -> query
172204 | _ ->
@@ -196,3 +228,18 @@ type ObjectListFilter with
196228 whereExpr< 'T> query param body
197229 // Create and execute the final expression
198230 query.Provider.CreateQuery< 'T> ( queryExpr)
231+
232+ [<AutoOpen>]
233+ module ObjectListFilterExtensions =
234+
235+ open ObjectListFilter
236+
237+ type ObjectListFilter with
238+
239+ member inline filter.ApplyTo < 'T , 'D > ( query : IQueryable < 'T >, [<Optional>] options : ObjectListFilterLinqOptions < 'T , 'D >) =
240+ apply options filter query
241+
242+ type IQueryable < 'T > with
243+
244+ member inline query.Apply ( filter : ObjectListFilter , [<Optional>] options : ObjectListFilterLinqOptions < 'T , 'D >) =
245+ apply options filter query
0 commit comments