11namespace FSharp.Data.GraphQL.Server.Middleware
22
3+ open System
4+ open System.Linq
5+ open System.Linq .Expressions
6+ open System.Runtime .InteropServices
7+ open Microsoft.FSharp .Quotations
8+
39/// A filter definition for a field value.
410type FieldFilter < 'Val > =
511 { FieldName : string
@@ -16,10 +22,10 @@ type ObjectListFilter =
1622 | StartsWith of FieldFilter < string >
1723 | EndsWith of FieldFilter < string >
1824 | Contains of FieldFilter < string >
25+ | OfTypes of FieldFilter < Type list >
1926 | FilterField of FieldFilter < ObjectListFilter >
2027 | NoFilter
2128
22-
2329/// Contains tooling for working with ObjectListFilter.
2430module ObjectListFilter =
2531 /// Contains operators for building and comparing ObjectListFilter values.
@@ -53,3 +59,117 @@ module ObjectListFilter =
5359
5460 /// Creates a new ObjectListFilter representing a NOT opreation for the existing one.
5561 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