1using System.Diagnostics;
2using System.Reflection;
3using System.Runtime.CompilerServices;
10internal interface IPipelineExecutor
12 private static readonly MethodInfo _createEnumExec =
13 typeof(IPipelineExecutor).GetMethod(nameof(CreateEnumExec), BindingFlags.Public | BindingFlags.Static)!;
15 private static readonly MethodInfo _createScalarExec =
16 typeof(IPipelineExecutor).GetMethod(nameof(CreateScalarExec), BindingFlags.Public | BindingFlags.Static)!;
18 Type ElemType {
get; }
21 IAsyncEnumerable<Page<object?>> PagedResult(
QueryOptions? queryOptions, CancellationToken cancel =
default);
22 Task<object?> Result(
QueryOptions? queryOptions, CancellationToken cancel =
default);
24 IAsyncEnumerable<Page<T>> PagedResult<T>(
QueryOptions? queryOptions, CancellationToken cancel =
default);
25 Task<T> Result<T>(
QueryOptions? queryOptions, CancellationToken cancel =
default);
27 public static IPipelineExecutor Create(
36 var innerTy = ser.GetType()
38 .GetGenericArguments()[0];
40 var elemTy = proj is
null ?
42 proj.GetType().GetGenInst(typeof(Func<,>))!
43 .GetGenericArguments()[1];
45 var method = mode
switch
47 PipelineMode.Query or PipelineMode.Project => _createEnumExec,
48 PipelineMode.Scalar => _createScalarExec,
49 _ =>
throw new Exception(
"unreachable"),
52 var typeArgs =
new Type[] { innerTy, elemTy };
53 var args =
new object?[] { ctx, query, ser, proj };
54 var exec = method.MakeGenericMethod(typeArgs).Invoke(
null, args);
56 return (IPipelineExecutor)exec!;
59 public static EnumExecutor<E> CreateEnumExec<I, E>(
64 new EnumExecutor<E>(ctx, query,
new PageSerializer<E>(MapSer(ser, proj)));
66 public static ScalarExecutor<E> CreateScalarExec<I, E>(
71 new ScalarExecutor<E>(ctx, query, MapSer(ser, proj));
77 return new MappedDeserializer<I, E>(inner, proj);
80 Debug.Assert(typeof(I) == typeof(E));
84 public readonly record
struct EnumExecutor<E>(
87 PageSerializer<E> Ser) : IPipelineExecutor
89 public Type ElemType {
get => typeof(E); }
90 public Type ResType {
get => typeof(IEnumerable<E>); }
92 public IAsyncEnumerable<Page<T>> PagedResult<T>(
QueryOptions? queryOptions, CancellationToken cancel =
default)
94 var pages = Ctx.PaginateAsyncInternal(
Query, Ser, queryOptions, cancel);
95 if (pages is IAsyncEnumerable<
Page<T>> ret)
100 Debug.Assert(typeof(T) == ElemType);
101 throw new Exception(
"unreachable");
104 public async Task<T> Result<T>(
QueryOptions? queryOptions, CancellationToken cancel =
default)
106 var pages = PagedResult<E>(queryOptions, cancel);
107 var elems =
new List<E>();
111 await
foreach (var page
in pages)
113 cancel.ThrowIfCancellationRequested();
114 elems.AddRange(page.Data);
120 Debug.Assert(typeof(T) == ResType, $
"{typeof(T)} is not {ResType}");
121 throw new Exception(
"unreachable");
124 public async IAsyncEnumerable<Page<object?>> PagedResult(
QueryOptions? queryOptions, [EnumeratorCancellation] CancellationToken cancel =
default)
126 await
foreach (var page
in PagedResult<E>(queryOptions, cancel))
128 var data = page.Data.Select(e => (
object?)e).ToList();
129 yield
return new Page<object?>(data, page.After);
133 public async Task<object?> Result(
QueryOptions? queryOptions, CancellationToken cancel =
default) =>
134 await Result<IEnumerable<E>>(queryOptions, cancel);
138 public readonly record
struct ScalarExecutor<E>(
143 public Type ElemType {
get => typeof(E); }
144 public Type ResType {
get => typeof(E); }
146 public async Task<T> Result<T>(
QueryOptions? queryOptions, CancellationToken cancel =
default)
148 var qres = await Ctx.QueryAsync(
Query, Ser, queryOptions, cancel);
149 if (qres.Data is T ret)
154 if (qres.Data is
null)
159 Debug.Assert(typeof(T) == ResType, $
"{typeof(T)} is not {ResType}");
160 throw new Exception(
"unreachable");
163 public async IAsyncEnumerable<Page<T>> PagedResult<T>(
QueryOptions? queryOptions, [EnumeratorCancellation] CancellationToken cancel =
default)
165 if (await Result<E>(queryOptions, cancel) is T ret)
167 yield
return new Page<T>(
new List<T> { ret },
null);
170 Debug.Assert(typeof(T) == ElemType);
171 throw new Exception(
"unreachable");
174 public async Task<object?> Result(
QueryOptions? queryOptions, CancellationToken cancel =
default) =>
175 await Result<E>(queryOptions, cancel);
177 public async IAsyncEnumerable<Page<object?>> PagedResult(
QueryOptions? queryOptions, [EnumeratorCancellation] CancellationToken cancel =
default)
179 yield
return new Page<object?>(
new List<object?> { await Result(queryOptions, cancel) },
null);
Represents the abstract base class for constructing FQL queries.
Represents the options for customizing Fauna queries.
record Page< T >(IReadOnlyList< T > Data, string? After)
Represents a page in a dataset for pagination.