1
1
namespace FSharp.Data.GraphQL.Server.Middleware
2
2
3
+ open System
4
+ open System.Linq
5
+ open System.Linq .Expressions
6
+ open System.Runtime .InteropServices
7
+ open Microsoft.FSharp .Quotations
8
+
3
9
/// A filter definition for a field value.
4
10
type FieldFilter < 'Val > =
5
11
{ FieldName : string
@@ -16,10 +22,10 @@ type ObjectListFilter =
16
22
| StartsWith of FieldFilter < string >
17
23
| EndsWith of FieldFilter < string >
18
24
| Contains of FieldFilter < string >
25
+ | OfTypes of FieldFilter < Type list >
19
26
| FilterField of FieldFilter < ObjectListFilter >
20
27
| NoFilter
21
28
22
-
23
29
/// Contains tooling for working with ObjectListFilter.
24
30
module ObjectListFilter =
25
31
/// Contains operators for building and comparing ObjectListFilter values.
@@ -53,3 +59,117 @@ module ObjectListFilter =
53
59
54
60
/// Creates a new ObjectListFilter representing a NOT opreation for the existing one.
55
61
let ( !!! ) filter = Not filter
62
+
63
+ //[<AutoOpen>]
64
+ //module ObjectListFilterExtensions =
65
+
66
+ // type ObjectListFilter with
67
+
68
+ // member filter.Apply<'T, 'D>(query : IQueryable<'T>,
69
+ // compareDiscriminator : Expr<'T -> 'D -> 'D> | null,
70
+ // getDiscriminatorValue : (Type -> 'D) | null) =
71
+ // filter.Apply(query, compareDiscriminator, getDiscriminatorValue)
72
+
73
+ // member filter.Apply<'T, 'D>(query : IQueryable<'T>,
74
+ // [<Optional>] getDiscriminator : Expr<'T -> 'D> | null,
75
+ // [<Optional>] getDiscriminatorValue : (Type -> 'D) | null) =
76
+ // // Helper to create parameter expression for the lambda
77
+ // let param = Expression.Parameter(typeof<'T>, "x")
78
+
79
+ // // Helper to get property value
80
+ // let getPropertyExpr fieldName =
81
+ // Expression.PropertyOrField(param, fieldName)
82
+
83
+ // // Helper to create lambda from body expression
84
+ // let makeLambda (body: Expression) =
85
+ // let delegateType = typedefof<Func<_,_>>.MakeGenericType([|typeof<'T>; body.Type|])
86
+ // Expression.Lambda(delegateType, body, param)
87
+
88
+ // // Helper to create Where expression
89
+ // let whereExpr predicate =
90
+ // let whereMethod =
91
+ // typeof<Queryable>.GetMethods()
92
+ // |> Seq.where (fun m -> m.Name = "Where")
93
+ // |> Seq.find (fun m ->
94
+ // let parameters = m.GetParameters()
95
+ // parameters.Length = 2
96
+ // && parameters[1].ParameterType.GetGenericTypeDefinition() = typedefof<Expression<Func<_,_>>>)
97
+ // |> fun m -> m.MakeGenericMethod([|typeof<'T>|])
98
+ // Expression.Call(whereMethod, [|query.Expression; makeLambda predicate|])
99
+
100
+ // // Helper for discriminator comparison
101
+ // let buildTypeDiscriminatorCheck (t: Type) =
102
+ // match getDiscriminator, getDiscriminatorValue with
103
+ // | null, _ | _, null -> None
104
+ // | discExpr, discValueFn ->
105
+ // let compiled = QuotationEvaluator.Eval(discExpr)
106
+ // let discriminatorValue = discValueFn t
107
+ // let discExpr = getPropertyExpr "__discriminator" // Assuming discriminator field name
108
+ // let valueExpr = Expression.Constant(discriminatorValue)
109
+ // Some(Expression.Equal(discExpr, valueExpr))
110
+
111
+ // // Main filter logic
112
+ // let rec buildFilterExpr filter =
113
+ // match filter with
114
+ // | NoFilter -> query.Expression
115
+ // | And (f1, f2) ->
116
+ // let q1 = buildFilterExpr f1 |> Expression.Lambda<Func<IQueryable<'T>>>|> _.Compile().Invoke()
117
+ // buildFilterExpr f2 |> Expression.Lambda<Func<IQueryable<'T>>> |> _.Compile().Invoke(q1).Expression
118
+ // | Or (f1, f2) ->
119
+ // let expr1 = buildFilterExpr f1
120
+ // let expr2 = buildFilterExpr f2
121
+ // let unionMethod =
122
+ // typeof<Queryable>.GetMethods()
123
+ // |> Array.find (fun m -> m.Name = "Union")
124
+ // |> fun m -> m.MakeGenericMethod([|typeof<'T>|])
125
+ // Expression.Call(unionMethod, [|expr1; expr2|])
126
+ // | Not f ->
127
+ // let exceptMethod =
128
+ // typeof<Queryable>.GetMethods()
129
+ // |> Array.find (fun m -> m.Name = "Except")
130
+ // |> fun m -> m.MakeGenericMethod([|typeof<'T>|])
131
+ // Expression.Call(exceptMethod, [|query.Expression; buildFilterExpr f|])
132
+ // | Equals f ->
133
+ // Expression.Equal(getPropertyExpr f.FieldName, Expression.Constant(f.Value)) |> whereExpr
134
+ // | GreaterThan f ->
135
+ // Expression.GreaterThan(getPropertyExpr f.FieldName, Expression.Constant(f.Value)) |> whereExpr
136
+ // | LessThan f ->
137
+ // Expression.LessThan(getPropertyExpr f.FieldName, Expression.Constant(f.Value)) |> whereExpr
138
+ // | StartsWith f ->
139
+ // let methodInfo = typeof<string>.GetMethod("StartsWith", [|typeof<string>|])
140
+ // Expression.Call(getPropertyExpr f.FieldName, methodInfo, Expression.Constant(f.Value)) |> whereExpr
141
+ // | EndsWith f ->
142
+ // let methodInfo = typeof<string>.GetMethod("EndsWith", [|typeof<string>|])
143
+ // Expression.Call(getPropertyExpr f.FieldName, methodInfo, Expression.Constant(f.Value)) |> whereExpr
144
+ // | Contains f ->
145
+ // let methodInfo = typeof<string>.GetMethod("Contains", [|typeof<string>|])
146
+ // Expression.Call(getPropertyExpr f.FieldName, methodInfo, Expression.Constant(f.Value)) |> whereExpr
147
+ // | OfTypes types ->
148
+ // match types.Value with
149
+ // | [] -> query.Expression // No types specified, return original query
150
+ // | types ->
151
+ // let typeChecks =
152
+ // types
153
+ // |> List.choose buildTypeDiscriminatorCheck
154
+ // |> List.fold (fun acc expr ->
155
+ // match acc with
156
+ // | None -> Some expr
157
+ // | Some prevExpr -> Some(Expression.OrElse(prevExpr, expr))) None
158
+
159
+ // match typeChecks with
160
+ // | None -> query.Expression
161
+ // | Some expr -> whereExpr expr
162
+ // | FilterField f ->
163
+ // let propExpr = getPropertyExpr f.FieldName
164
+ // match propExpr.Type.GetInterfaces()
165
+ // |> Array.tryFind (fun t ->
166
+ // t.IsGenericType && t.GetGenericTypeDefinition() = typedefof<IQueryable<_>>) with
167
+ // | Some queryableType ->
168
+ // let elementType = queryableType.GetGenericArguments().[0]
169
+ // let subFilter = f.Value
170
+ // let subQuery = Expression.Convert(propExpr, queryableType)
171
+ // Expression.Call(typeof<Queryable>, "Any", [|elementType|], subQuery) |> whereExpr
172
+ // | None -> query.Expression
173
+
174
+ // // Create and execute the final expression
175
+ // query.Provider.CreateQuery<'T>(buildFilterExpr filter)
0 commit comments