4using System.Diagnostics;
 
    5using System.Reflection;
 
    6using System.Runtime.CompilerServices;
 
   10internal interface PipelineExecutor
 
   12    private static readonly MethodInfo _createEnumExec =
 
   13        typeof(PipelineExecutor).GetMethod(nameof(CreateEnumExec), BindingFlags.Public | BindingFlags.Static)!;
 
   15    private static readonly MethodInfo _createScalarExec =
 
   16        typeof(PipelineExecutor).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 PipelineExecutor Create(
 
   36        var innerTy = deser.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, deser, proj };
 
   54        var exec = method.MakeGenericMethod(typeArgs).Invoke(
null, args);
 
   56        return (PipelineExecutor)exec!;
 
   59    public static EnumExecutor<E> CreateEnumExec<I, E>(
 
   64        new EnumExecutor<E>(ctx, query, 
new PageDeserializer<E>(MapDeser(deser, proj)));
 
   66    public static ScalarExecutor<E> CreateScalarExec<I, E>(
 
   71        new ScalarExecutor<E>(ctx, query, MapDeser(deser, proj));
 
   77            return new MappedDeserializer<I, E>(inner, proj);
 
   80        Debug.Assert(typeof(I) == typeof(E));
 
   84    public readonly record 
struct EnumExecutor<E>(
 
   87        PageDeserializer<E> Deser) : PipelineExecutor
 
   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, Deser, 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, Deser, 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.