Fauna v10 .NET/C# Driver 0.2.0-beta
 
Loading...
Searching...
No Matches
QuerySourceDsl.cs
Go to the documentation of this file.
1using System.Diagnostics;
2using System.Linq.Expressions;
3using System.Runtime.CompilerServices;
5using Fauna.Mapping;
7using Fauna.Util;
9
10namespace Fauna.Linq;
11
12public partial class QuerySource<T>
13{
14 private Query Query { get => Pipeline.Query; }
15 private MappingContext MappingCtx { get => Ctx.MappingCtx; }
16 private LookupTable Lookup { get => Ctx.LookupTable; }
17
18 // Composition methods
19
21 {
22 RequireQueryMode();
23 return Chain<T>(q: QH.MethodCall(Query, "distinct"));
24 }
25
27 {
28 RequireQueryMode();
29 return Chain<T>(q: QH.MethodCall(Query, "order"));
30 }
31
32 public IQuerySource<T> OrderBy<K>(Expression<Func<T, K>> keySelector)
33 {
34 RequireQueryMode();
35 return Chain<T>(q: QH.MethodCall(Query, "order", SubQuery(keySelector)));
36 }
37
38 public IQuerySource<T> OrderByDescending<K>(Expression<Func<T, K>> keySelector)
39 {
40 RequireQueryMode();
41 return Chain<T>(q: QH.MethodCall(Query, "order", QH.FnCall("desc", SubQuery(keySelector))));
42 }
43
45 {
46 RequireQueryMode();
47 return Chain<T>(q: QH.MethodCall(Query, "order", QH.Expr("desc(x => x)")));
48 }
49
51 Chain<T>(q: QH.MethodCall(Query, "reverse"));
52
53 public IQuerySource<R> Select<R>(Expression<Func<T, R>> selector)
54 {
55 var pl = SelectCall(Query, selector);
56 return new QuerySource<R>(Ctx, pl);
57 }
58
59 public IQuerySource<T> Skip(int count) =>
60 Chain<T>(q: QH.MethodCall(Query, "drop", QH.Const(count)));
61
62 public IQuerySource<T> Take(int count) =>
63 Chain<T>(q: QH.MethodCall(Query, "take", QH.Const(count)));
64
65 public IQuerySource<T> Where(Expression<Func<T, bool>> predicate) =>
66 Chain<T>(q: WhereCall(Query, predicate));
67
68 // Terminal result methods
69
70 public bool All(Expression<Func<T, bool>> predicate) => Execute<bool>(AllImpl(predicate));
71 public Task<bool> AllAsync(Expression<Func<T, bool>> predicate, CancellationToken cancel = default) =>
72 ExecuteAsync<bool>(AllImpl(predicate), cancel);
73 private Pipeline AllImpl(Expression<Func<T, bool>> predicate)
74 {
75 RequireQueryMode("All");
76 return CopyPipeline(
77 mode: PipelineMode.Scalar,
78 q: QH.MethodCall(Query, "every", SubQuery(predicate)),
79 ety: typeof(bool));
80 }
81
82 public bool Any() => Execute<bool>(AnyImpl(null));
83 public Task<bool> AnyAsync(CancellationToken cancel = default) =>
84 ExecuteAsync<bool>(AnyImpl(null), cancel);
85 public bool Any(Expression<Func<T, bool>> predicate) => Execute<bool>(AnyImpl(predicate));
86 public Task<bool> AnyAsync(Expression<Func<T, bool>> predicate, CancellationToken cancel = default) =>
87 ExecuteAsync<bool>(AnyImpl(predicate), cancel);
88 private Pipeline AnyImpl(Expression<Func<T, bool>>? predicate) =>
89 CopyPipeline(
90 mode: PipelineMode.Scalar,
91 q: QH.MethodCall(MaybeWhereCall(Query, predicate), "nonEmpty"),
92 ety: typeof(bool));
93
94 public int Count() => Execute<int>(CountImpl(null));
95 public Task<int> CountAsync(CancellationToken cancel = default) =>
96 ExecuteAsync<int>(CountImpl(null), cancel);
97 public int Count(Expression<Func<T, bool>> predicate) => Execute<int>(CountImpl(predicate));
98 public Task<int> CountAsync(Expression<Func<T, bool>> predicate, CancellationToken cancel = default) =>
99 ExecuteAsync<int>(CountImpl(predicate), cancel);
100 private Pipeline CountImpl(Expression<Func<T, bool>>? predicate) =>
101 CopyPipeline(
102 mode: PipelineMode.Scalar,
103 q: QH.MethodCall(MaybeWhereCall(Query, predicate), "count"),
104 ety: typeof(int));
105
106 public T First() => Execute<T>(FirstImpl(null));
107 public Task<T> FirstAsync(CancellationToken cancel = default) =>
108 ExecuteAsync<T>(FirstImpl(null), cancel);
109 public T First(Expression<Func<T, bool>> predicate) => Execute<T>(FirstImpl(predicate));
110 public Task<T> FirstAsync(Expression<Func<T, bool>> predicate, CancellationToken cancel = default) =>
111 ExecuteAsync<T>(FirstImpl(predicate), cancel);
112 private Pipeline FirstImpl(Expression<Func<T, bool>>? predicate) =>
113 CopyPipeline(
114 mode: PipelineMode.Scalar,
115 q: QH.MethodCall(AbortIfEmpty(MaybeWhereCall(Query, predicate)), "first"));
116
117 public T? FirstOrDefault() => Execute<T?>(FirstOrDefaultImpl(null));
118 public Task<T?> FirstOrDefaultAsync(CancellationToken cancel = default) =>
119 ExecuteAsync<T?>(FirstOrDefaultImpl(null), cancel);
120 public T? FirstOrDefault(Expression<Func<T, bool>> predicate) => Execute<T?>(FirstOrDefaultImpl(predicate));
121 public Task<T?> FirstOrDefaultAsync(Expression<Func<T, bool>> predicate, CancellationToken cancel = default) =>
122 ExecuteAsync<T?>(FirstOrDefaultImpl(predicate), cancel);
123 private Pipeline FirstOrDefaultImpl(Expression<Func<T, bool>>? predicate) =>
124 CopyPipeline(
125 mode: PipelineMode.Scalar,
126 q: QH.MethodCall(MaybeWhereCall(Query, predicate), "first"),
127 ety: typeof(T),
128 enull: true);
129
130 public T Last() => Execute<T>(LastImpl(null));
131 public Task<T> LastAsync(CancellationToken cancel = default) =>
132 ExecuteAsync<T>(LastImpl(null), cancel);
133 public T Last(Expression<Func<T, bool>> predicate) => Execute<T>(LastImpl(predicate));
134 public Task<T> LastAsync(Expression<Func<T, bool>> predicate, CancellationToken cancel = default) =>
135 ExecuteAsync<T>(LastImpl(predicate), cancel);
136 private Pipeline LastImpl(Expression<Func<T, bool>>? predicate) =>
137 CopyPipeline(
138 mode: PipelineMode.Scalar,
139 q: QH.MethodCall(AbortIfEmpty(MaybeWhereCall(Query, predicate)), "last"));
140
141 public T? LastOrDefault() => Execute<T?>(LastOrDefaultImpl(null));
142 public Task<T?> LastOrDefaultAsync(CancellationToken cancel = default) =>
143 ExecuteAsync<T?>(LastOrDefaultImpl(null), cancel);
144 public T? LastOrDefault(Expression<Func<T, bool>> predicate) => Execute<T?>(LastOrDefaultImpl(predicate));
145 public Task<T?> LastOrDefaultAsync(Expression<Func<T, bool>> predicate, CancellationToken cancel = default) =>
146 ExecuteAsync<T?>(LastOrDefaultImpl(predicate), cancel);
147 private Pipeline LastOrDefaultImpl(Expression<Func<T, bool>>? predicate) =>
148 CopyPipeline(
149 mode: PipelineMode.Scalar,
150 q: QH.MethodCall(MaybeWhereCall(Query, predicate), "last"),
151 ety: typeof(T),
152 enull: true);
153
154 public long LongCount() => Execute<long>(LongCountImpl(null));
155 public Task<long> LongCountAsync(CancellationToken cancel = default) =>
156 ExecuteAsync<long>(LongCountImpl(null), cancel);
157 public long LongCount(Expression<Func<T, bool>> predicate) => Execute<long>(LongCountImpl(predicate));
158 public Task<long> LongCountAsync(Expression<Func<T, bool>> predicate, CancellationToken cancel = default) =>
159 ExecuteAsync<long>(LongCountImpl(predicate), cancel);
160 private Pipeline LongCountImpl(Expression<Func<T, bool>>? predicate) =>
161 CopyPipeline(
162 mode: PipelineMode.Scalar,
163 q: QH.MethodCall(MaybeWhereCall(Query, predicate), "count"),
164 ety: typeof(long));
165
166 private static readonly Query _maxReducer = QH.Expr("(a, b) => if (a >= b) a else b");
167
168 public T Max() => Execute<T>(MaxImpl<T>(null));
169 public Task<T> MaxAsync(CancellationToken cancel = default) =>
170 ExecuteAsync<T>(MaxImpl<T>(null), cancel);
171 public R Max<R>(Expression<Func<T, R>> selector) => Execute<R>(MaxImpl(selector));
172 public Task<R> MaxAsync<R>(Expression<Func<T, R>> selector, CancellationToken cancel = default) =>
173 ExecuteAsync<R>(MaxImpl(selector), cancel);
174 private Pipeline MaxImpl<R>(Expression<Func<T, R>>? selector, [CallerMemberName] string callerName = "")
175 {
176 RequireQueryMode(callerName);
177 return CopyPipeline(
178 mode: PipelineMode.Scalar,
179 q: QH.MethodCall(MaybeMap(AbortIfEmpty(Query), selector), "reduce", _maxReducer),
180 ety: typeof(R));
181 }
182
183 private static readonly Query _minReducer = QH.Expr("(a, b) => if (a <= b) a else b");
184
185 public T Min() => Execute<T>(MinImpl<T>(null));
186 public Task<T> MinAsync(CancellationToken cancel = default) => ExecuteAsync<T>(MinImpl<T>(null), cancel);
187 public R Min<R>(Expression<Func<T, R>> selector) => Execute<R>(MinImpl(selector));
188 public Task<R> MinAsync<R>(Expression<Func<T, R>> selector, CancellationToken cancel = default) =>
189 ExecuteAsync<R>(MinImpl(selector), cancel);
190 private Pipeline MinImpl<R>(Expression<Func<T, R>>? selector, [CallerMemberName] string callerName = "")
191 {
192 RequireQueryMode(callerName);
193 return CopyPipeline(
194 mode: PipelineMode.Scalar,
195 q: QH.MethodCall(MaybeMap(AbortIfEmpty(Query), selector), "reduce", _minReducer),
196 ety: typeof(R));
197 }
198
199 public double Average(Expression<Func<T, double>> selector) => Execute<double>(AverageImpl(selector));
200 public Task<double> AverageAsync(Expression<Func<T, double>> selector, CancellationToken cancel = default) =>
201 ExecuteAsync<double>(AverageImpl(selector), cancel);
202
203 private Pipeline AverageImpl<R>(Expression<Func<T, R>> selector)
204 {
205 RequireQueryMode("Average");
206
207 return CopyPipeline(
208 mode: PipelineMode.Scalar,
209 q: QH.FnCall("Math.mean", QH.MethodCall(QH.MethodCall(AbortIfEmpty(Query), "map", SubQuery(selector)), "toArray")),
210 ety: typeof(R));
211 }
212
213 public T Single() => Execute<T>(SingleImpl(null));
214 public Task<T> SingleAsync(CancellationToken cancel = default) => ExecuteAsync<T>(SingleImpl(null), cancel);
215 public T Single(Expression<Func<T, bool>> predicate) => Execute<T>(SingleImpl(predicate));
216 public Task<T> SingleAsync(Expression<Func<T, bool>> predicate, CancellationToken cancel = default) =>
217 ExecuteAsync<T>(SingleImpl(predicate), cancel);
218 private Pipeline SingleImpl(Expression<Func<T, bool>>? predicate) =>
219 CopyPipeline(
220 mode: PipelineMode.Scalar,
221 q: QH.MethodCall(AbortIfEmpty(Singularize(MaybeWhereCall(Query, predicate))), "first"));
222
223 public T SingleOrDefault() => Execute<T>(SingleOrDefaultImpl(null));
224 public Task<T> SingleOrDefaultAsync(CancellationToken cancel = default) => ExecuteAsync<T>(SingleOrDefaultImpl(null), cancel);
225 public T SingleOrDefault(Expression<Func<T, bool>> predicate) => Execute<T>(SingleOrDefaultImpl(predicate));
226 public Task<T> SingleOrDefaultAsync(Expression<Func<T, bool>> predicate, CancellationToken cancel = default) =>
227 ExecuteAsync<T>(SingleOrDefaultImpl(predicate), cancel);
228 private Pipeline SingleOrDefaultImpl(Expression<Func<T, bool>>? predicate) =>
229 CopyPipeline(
230 mode: PipelineMode.Scalar,
231 q: QH.MethodCall(Singularize(MaybeWhereCall(Query, predicate)), "first"),
232 ety: typeof(T),
233 enull: true);
234
235 private static readonly Query _sumReducer = QH.Expr("(a, b) => a + b");
236
237 public int Sum(Expression<Func<T, int>> selector) => Execute<int>(SumImpl<int>(selector));
238 public Task<int> SumAsync(Expression<Func<T, int>> selector, CancellationToken cancel = default) =>
239 ExecuteAsync<int>(SumImpl<int>(selector), cancel);
240 public long Sum(Expression<Func<T, long>> selector) => Execute<long>(SumImpl<long>(selector));
241 public Task<long> SumAsync(Expression<Func<T, long>> selector, CancellationToken cancel = default) =>
242 ExecuteAsync<long>(SumImpl<long>(selector), cancel);
243 public double Sum(Expression<Func<T, double>> selector) => Execute<double>(SumImpl<double>(selector));
244 public Task<double> SumAsync(Expression<Func<T, double>> selector, CancellationToken cancel = default) =>
245 ExecuteAsync<double>(SumImpl<double>(selector), cancel);
246 private Pipeline SumImpl<R>(Expression<Func<T, R>> selector)
247 {
248 RequireQueryMode("Sum");
249 var seed = (typeof(R) == typeof(int) || typeof(R) == typeof(long)) ?
250 QH.Expr("0") :
251 QH.Expr("0.0");
252 var mapped = QH.MethodCall(Query, "map", SubQuery(selector));
253 return CopyPipeline(
254 mode: PipelineMode.Scalar,
255 q: QH.MethodCall(mapped, "fold", seed, _sumReducer),
256 ety: typeof(R));
257 }
258
259 // helpers
260
261 private void RequireQueryMode([CallerMemberName] string callerName = "")
262 {
263 if (Pipeline.Mode != PipelineMode.Query)
264 {
265 throw IQuerySource.Fail(
266 callerName,
267 $"Query is not pure: Earlier `Select` could not be translated to pure FQL.");
268 }
269 }
270
271 private R Execute<R>(Pipeline pl)
272 {
273 try
274 {
275 var res = ExecuteAsync<R>(pl);
276 res.Wait();
277 return res.Result;
278 }
279 catch (AggregateException ex)
280 {
281 throw TranslateException(ex.InnerExceptions.First());
282 }
283 }
284
285 private async Task<R> ExecuteAsync<R>(Pipeline pl, CancellationToken cancel = default)
286 {
287 try
288 {
289 return await pl.GetExec(Ctx).Result<R>(queryOptions: null, cancel: cancel);
290 }
291 catch (AggregateException ex)
292 {
293 throw TranslateException(ex.InnerExceptions.First());
294 }
295 }
296
297 private QuerySource<R> Chain<R>(
298 PipelineMode? mode = null,
299 Query? q = null,
300 ISerializer? ser = null,
301 Type? ety = null,
302 bool enull = false,
303 LambdaExpression? proj = null) =>
304 new QuerySource<R>(Ctx, CopyPipeline(mode, q, ser, ety, enull, proj));
305
306 private Pipeline CopyPipeline(
307 PipelineMode? mode = null,
308 Query? q = null,
309 ISerializer? ser = null,
310 Type? ety = null,
311 bool enull = false,
312 LambdaExpression? proj = null)
313 {
314 if (ser is not null) Debug.Assert(ety is not null);
315
316 var mode0 = mode ?? Pipeline.Mode;
317 var q0 = q ?? Pipeline.Query;
318
319 // if ety is not null, reset ser and proj if not provided.
320 var (ety0, enull0, ser0, proj0) = ety is not null ?
321 (ety, enull, ser, proj) :
322 (Pipeline.ElemType,
323 Pipeline.ElemNullable,
324 Pipeline.ElemSerializer,
325 proj ?? Pipeline.ProjectExpr);
326
327 return new Pipeline(mode0, q0, ety0, enull0, ser0, proj0);
328 }
329
330 // There is a bug in abort data deserialization if the abort
331 // value is a string. Work around it by using an array.
332 // FIXME(matt) remove workaround and use a string
333 private Query AbortIfEmpty(Query setq) =>
334 QH.Expr(@"({ let s = (").Concat(setq).Concat(@")
335 if (s.isEmpty()) abort(['empty'])
336 s
337 })");
338
339 private Query Singularize(Query setq) =>
340 QH.Expr(@"({
341 let s = (").Concat(setq).Concat(@")
342 let s = if (s isa Set) s.toArray() else s
343 if (s isa Array) {
344 if (s.length > 1) abort(['not single'])
345 s.take(1)
346 } else {
347 [s]
348 }
349 })");
350
351 private Exception TranslateException(Exception ex) =>
352 ex switch
353 {
354 AbortException aex =>
355 aex.GetData<List<string>>()?.First() switch
356 {
357 "empty" => new InvalidOperationException("Empty set"),
358 "not single" => new InvalidOperationException("Set contains more than one element"),
359 _ => aex,
360 },
361 _ => ex
362 };
363
364 private Query MaybeWhereCall(Query callee, Expression? predicate, [CallerMemberName] string callerName = "") =>
365 predicate is null ? callee : WhereCall(callee, predicate, callerName);
366
367 private Query MaybeMap(Query setq, Expression? selector) =>
368 selector is null ? setq : QH.MethodCall(setq, "map", SubQuery(selector));
369
370 private Query SubQuery(Expression expr) =>
371 new SubQuerySwitch(Ctx.LookupTable).Apply(expr);
372
373 private Query WhereCall(Query callee, Expression predicate, [CallerMemberName] string callerName = "")
374 {
375 RequireQueryMode(callerName);
376 return QH.MethodCall(callee, "where", SubQuery(predicate));
377 }
378
379 private Pipeline SelectCall(Query callee, Expression proj, [CallerMemberName] string callerName = "")
380 {
381 var lambda = Expressions.UnwrapLambda(proj);
382 Debug.Assert(lambda is not null, $"lambda is {proj.NodeType}");
383 Debug.Assert(lambda.Parameters.Count() == 1);
384
385 // there is already a projection wired up, so tack on to its mapping lambda
386 if (Pipeline.Mode == PipelineMode.Project)
387 {
388 Debug.Assert(Pipeline.ProjectExpr is not null);
389 var prev = Pipeline.ProjectExpr;
390 var pbody = Expression.Invoke(lambda, new Expression[] { prev.Body });
391 var plambda = Expression.Lambda(pbody, prev.Parameters);
392
393 return CopyPipeline(proj: plambda);
394 }
395
396 Debug.Assert(Pipeline.Mode == PipelineMode.Query);
397
398 var lparam = lambda.Parameters.First()!;
399 var analysis = new ProjectionAnalysisVisitor(MappingCtx, lparam);
400 analysis.Visit(lambda.Body);
401
402 // select is a simple field access which we can translate directly to FQL.
403 // TODO(matt) translate more cases to pure FQL
404 if (lambda.Body is MemberExpression mexpr && mexpr.Expression == lparam)
405 {
406 Debug.Assert(!analysis.Escapes);
407 var info = MappingCtx.GetInfo(lparam.Type);
408 var access = analysis.Accesses.First();
409 var field = Lookup.FieldLookup(access, lparam);
410 Debug.Assert(field is not null);
411
412 return CopyPipeline(
413 q: QH.MethodCall(callee, "map", QH.Expr($".{field.Name}")),
414 ser: field.Serializer,
415 ety: field.Type);
416 }
417
418 if (analysis.Escapes)
419 {
420 return CopyPipeline(mode: PipelineMode.Project, proj: lambda);
421 }
422 else
423 {
424 var accesses = analysis.Accesses.OrderBy(f => f.Name).ToArray();
425 var fields = accesses.Select(a => Lookup.FieldLookup(a, lparam)!);
426
427 // projection query fragment
428 var accs = fields.Select(f => QH.Expr($"x.{f.Name}"));
429 var pquery = QH.Expr("x => ").Concat(QH.Array(accs));
430
431 // projected field deserializer
432 var deser = new ProjectionDeserializer(fields.Select(f => f.Serializer));
433 var ety = typeof(object?[]);
434
435 // build mapping lambda expression
436 var pparam = Expression.Parameter(typeof(object?[]), "x");
437 var rewriter = new ProjectionRewriteVisitor(lparam, accesses, pparam);
438 var pbody = rewriter.Visit(lambda.Body);
439 var plambda = Expression.Lambda(pbody, pparam);
440
441 return CopyPipeline(
442 q: QH.MethodCall(callee, "map", pquery),
443 mode: PipelineMode.Project,
444 ser: deser,
445 ety: ety,
446 proj: plambda);
447 }
448 }
449}
Fauna.Linq.IntermediateQueryHelpers QH
Represents an exception that occurs when the FQL abort function is called. This exception captures th...
object? GetData()
Retrieves the deserialized data associated with the abort operation as an object.
Task< int > CountAsync(CancellationToken cancel=default)
Task< T?> FirstOrDefaultAsync(Expression< Func< T, bool > > predicate, CancellationToken cancel=default)
double Average(Expression< Func< T, double > > selector)
Task< bool > AllAsync(Expression< Func< T, bool > > predicate, CancellationToken cancel=default)
Task< long > SumAsync(Expression< Func< T, long > > selector, CancellationToken cancel=default)
Task< T > SingleOrDefaultAsync(Expression< Func< T, bool > > predicate, CancellationToken cancel=default)
Task< T > FirstAsync(CancellationToken cancel=default)
Task< T > FirstAsync(Expression< Func< T, bool > > predicate, CancellationToken cancel=default)
double Sum(Expression< Func< T, double > > selector)
T SingleOrDefault(Expression< Func< T, bool > > predicate)
Task< T > MinAsync(CancellationToken cancel=default)
Task< double > AverageAsync(Expression< Func< T, double > > selector, CancellationToken cancel=default)
bool Any(Expression< Func< T, bool > > predicate)
Task< T?> FirstOrDefaultAsync(CancellationToken cancel=default)
Task< int > SumAsync(Expression< Func< T, int > > selector, CancellationToken cancel=default)
Task< int > CountAsync(Expression< Func< T, bool > > predicate, CancellationToken cancel=default)
IQuerySource< T > OrderByDescending< K >(Expression< Func< T, K > > keySelector)
R Min< R >(Expression< Func< T, R > > selector)
Task< T > LastAsync(Expression< Func< T, bool > > predicate, CancellationToken cancel=default)
T? FirstOrDefault(Expression< Func< T, bool > > predicate)
T First(Expression< Func< T, bool > > predicate)
Task< T > LastAsync(CancellationToken cancel=default)
IQuerySource< T > Reverse()
Task< R > MinAsync< R >(Expression< Func< T, R > > selector, CancellationToken cancel=default)
IQuerySource< T > Skip(int count)
Task< T > SingleOrDefaultAsync(CancellationToken cancel=default)
IQuerySource< T > Where(Expression< Func< T, bool > > predicate)
IQuerySource< T > OrderDescending()
bool All(Expression< Func< T, bool > > predicate)
Task< R > MaxAsync< R >(Expression< Func< T, R > > selector, CancellationToken cancel=default)
IQuerySource< T > Order()
long LongCount(Expression< Func< T, bool > > predicate)
Task< T?> LastOrDefaultAsync(Expression< Func< T, bool > > predicate, CancellationToken cancel=default)
int Sum(Expression< Func< T, int > > selector)
IQuerySource< T > Take(int count)
Task< T > SingleAsync(CancellationToken cancel=default)
T Single(Expression< Func< T, bool > > predicate)
IQuerySource< T > Distinct()
Task< long > LongCountAsync(CancellationToken cancel=default)
Task< double > SumAsync(Expression< Func< T, double > > selector, CancellationToken cancel=default)
Task< T?> LastOrDefaultAsync(CancellationToken cancel=default)
Task< T > SingleAsync(Expression< Func< T, bool > > predicate, CancellationToken cancel=default)
T? LastOrDefault(Expression< Func< T, bool > > predicate)
Task< bool > AnyAsync(Expression< Func< T, bool > > predicate, CancellationToken cancel=default)
T Last(Expression< Func< T, bool > > predicate)
IQuerySource< T > OrderBy< K >(Expression< Func< T, K > > keySelector)
Task< T > MaxAsync(CancellationToken cancel=default)
Task< long > LongCountAsync(Expression< Func< T, bool > > predicate, CancellationToken cancel=default)
long Sum(Expression< Func< T, long > > selector)
IQuerySource< R > Select< R >(Expression< Func< T, R > > selector)
Task< bool > AnyAsync(CancellationToken cancel=default)
R Max< R >(Expression< Func< T, R > > selector)
int Count(Expression< Func< T, bool > > predicate)
A class representing the mapping context to be used during serialization and deserialization.
MappingInfo GetInfo(Type ty, string? colName=null)
Gets the MappingInfo for a given Type.
Represents the abstract base class for constructing FQL queries.
Definition Query.cs:11
Definition Client.cs:8