|
1 | 1 | namespace FSharp.Data.GraphQL.Server.Middleware |
2 | 2 |
|
3 | 3 | open System |
| 4 | +open System.Linq |
| 5 | +open System.Linq.Expressions |
| 6 | +open System.Runtime.InteropServices |
| 7 | +open Microsoft.FSharp.Quotations |
4 | 8 |
|
5 | 9 | /// A filter definition for a field value. |
6 | 10 | type FieldFilter<'Val> = |
@@ -55,3 +59,117 @@ module ObjectListFilter = |
55 | 59 |
|
56 | 60 | /// Creates a new ObjectListFilter representing a NOT opreation for the existing one. |
57 | 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