"use strict";
/*!
  Copyright 2018 Ron Buckton (rbuckton@chronicles.org)

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
 */
/** @module "iterable-query" */
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const fn = require("./fn");
const internal_1 = require("./internal");
const types_1 = require("./types");
const query_1 = require("./query");
/**
 * Creates an `AsyncHierarchyQuery` from an [[AsyncQueryable]] source.
 *
 * @param source An [[AsyncQueryable]] object.
 * @param hierarchy A `HierarchyProvider` object.
 */
function fromAsync(source, hierarchy) {
    if (hierarchy)
        source = internal_1.MakeAsyncHierarchyIterable(source, hierarchy);
    return internal_1.IsPossiblyAsyncOrderedHierarchyIterable(source) ? new AsyncOrderedHierarchyQuery(source) :
        internal_1.IsPossiblyAsyncHierarchyIterable(source) ? new AsyncHierarchyQuery(source) :
            internal_1.IsPossiblyAsyncOrderedIterable(source) ? new AsyncOrderedQuery(source) :
                new AsyncQuery(source);
}
exports.fromAsync = fromAsync;
/**
 * An [[AsyncQuery]] represents a series of operations that act upon an [[AsyncIterable]], [[Iterable]]
 * or `ArrayLike`. Evaluation of these operations is deferred until the either a scalar value is
 * requested from the [[AsyncQuery]] or the [[AsyncQuery]] is iterated.
 */
class AsyncQuery {
    /**
     * Creates an [[AsyncQuery]] from an [[AsyncQueryable]] source.
     *
     * @param source An [[AsyncQueryable]] object.
     */
    constructor(source) {
        internal_1.assert.mustBeAsyncQueryable(source, "source");
        this._source = source instanceof AsyncQuery
            ? source._source
            : source;
    }
    [Symbol.asyncIterator]() {
        return internal_1.GetAsyncIterator(internal_1.ToPossiblyAsyncIterable(internal_1.GetAsyncSource(this)));
    }
    static from(source, hierarchy) {
        return fromAsync(source, hierarchy);
    }
    static of() {
        return fromAsync(arguments);
    }
    /**
     * Creates an [[AsyncQuery]] with no elements.
     * @category Query
     */
    static empty() {
        // TODO: Consider contextual typing here?
        // return fromAsync(fn.emptyAsync());
        return fromAsync(fn.emptyAsync());
    }
    /**
     * Creates an [[AsyncQuery]] over a single element.
     *
     * @param value The only element for the `Query`.
     * @category Query
     */
    static once(value) {
        return fromAsync(fn.onceAsync(value));
    }
    /**
     * Creates an [[AsyncQuery]] for a value repeated a provided number of times.
     *
     * @param value The value for each element of the `Query`.
     * @param count The number of times to repeat the value.
     * @category Query
     */
    static repeat(value, count) {
        return fromAsync(fn.repeatAsync(value, count));
    }
    /**
     * Creates an [[AsyncQuery]] that repeats the provided value forever.
     *
     * @param value The value for each element of the `Query`.
     * @category Query
     */
    static continuous(value) {
        return fromAsync(fn.continuousAsync(value));
    }
    /**
     * Creates an [[AsyncQuery]] whose values are provided by a callback executed a provided number of
     * times.
     *
     * @param count The number of times to execute the callback.
     * @param generator The callback to execute.
     * @category Query
     */
    static generate(count, generator) {
        return fromAsync(fn.generateAsync(count, generator));
    }
    /**
     * Creates an `AsyncHierarchyQuery` from a root node and a `HierarchyProvider`.
     *
     * @param root The root node of the hierarchy.
     * @param hierarchy A `HierarchyProvider` object.
     * @category Query
     */
    static hierarchy(root, hierarchy) {
        return fromAsync(fn.hierarchyAsync(root, hierarchy));
    }
    /**
     * Creates an [[AsyncQuery]] that, when iterated, consumes the provided `AsyncIterator`.
     *
     * @param iterator An `AsyncIterator` object.
     * @category Query
     */
    static consume(iterator, options) {
        return fromAsync(fn.consumeAsync(iterator, options));
    }
    /**
     * Creates an [[AsyncQuery]] that iterates the elements from one of two sources based on the result of a
     * lazily evaluated condition.
     *
     * @param condition A callback used to choose a source.
     * @param thenQueryable The source to use when the callback evaluates to `true`.
     * @param elseQueryable The source to use when the callback evaluates to `false`.
     * @category Query
     */
    static if(condition, thenQueryable, elseQueryable) {
        return fromAsync(fn.ifAsync(condition, thenQueryable, elseQueryable));
    }
    /**
     * Creates an [[AsyncQuery]] that iterates the elements from sources picked from a list based on the
     * result of a lazily evaluated choice.
     *
     * @param chooser A callback used to choose a source.
     * @param choices A list of sources
     * @param otherwise A default source to use when another choice could not be made.
     * @category Query
     */
    static choose(chooser, choices, otherwise) {
        return fromAsync(fn.chooseAsync(chooser, choices, otherwise));
    }
    /**
     * Creates an [[AsyncQuery]] for the own property keys of an object.
     *
     * @param source An object.
     * @category Query
     */
    static objectKeys(source) {
        return fromAsync(fn.objectKeysAsync(source));
    }
    /**
     * Creates an [[AsyncQuery]] for the own property values of an object.
     *
     * @param source An object.
     * @category Query
     */
    static objectValues(source) {
        return fromAsync(fn.objectValuesAsync(source));
    }
    /**
     * Creates an [[AsyncQuery]] for the own property key-value pairs of an object.
     *
     * @param source An object.
     * @category Query
     */
    static objectEntries(source) {
        return fromAsync(fn.objectEntriesAsync(source));
    }
    filter(predicate) {
        return fromAsync(fn.filterAsync(internal_1.GetAsyncSource(this), predicate));
    }
    /**
     * Creates a subquery where the selected key for each element matches the supplied predicate.
     *
     * @param keySelector A callback used to select the key for each element.
     * @param predicate A callback used to match each key.
     * @category Subquery
     */
    filterBy(keySelector, predicate) {
        return fromAsync(fn.filterByAsync(internal_1.GetAsyncSource(this), keySelector, predicate));
    }
    where(predicate) {
        return fromAsync(fn.whereAsync(internal_1.GetAsyncSource(this), predicate));
    }
    /**
     * Creates a subquery where the selected key for each element matches the supplied predicate.
     *
     * @param keySelector A callback used to select the key for each element.
     * @param predicate A callback used to match each key.
     * @category Subquery
     */
    whereBy(keySelector, predicate) {
        return fromAsync(fn.whereByAsync(internal_1.GetAsyncSource(this), keySelector, predicate));
    }
    filterDefined(keySelector) {
        return fromAsync(fn.filterDefinedAsync(internal_1.GetAsyncSource(this), keySelector));
    }
    whereDefined(keySelector) {
        return fromAsync(fn.whereDefinedAsync(internal_1.GetAsyncSource(this), keySelector));
    }
    /**
     * Creates a subquery by applying a callback to each element.
     *
     * @param selector A callback used to map each element.
     * @category Subquery
     */
    map(selector) {
        return fromAsync(fn.mapAsync(internal_1.GetAsyncSource(this), selector));
    }
    /**
     * Creates a subquery by applying a callback to each element.
     * This is an alias for `map`.
     *
     * @param selector A callback used to map each element.
     * @category Subquery
     */
    select(selector) {
        return fromAsync(fn.selectAsync(internal_1.GetAsyncSource(this), selector));
    }
    flatMap(projection, resultSelector) {
        return fromAsync(fn.flatMapAsync(internal_1.GetAsyncSource(this), projection, resultSelector));
    }
    selectMany(projection, resultSelector) {
        return fromAsync(fn.selectManyAsync(internal_1.GetAsyncSource(this), projection, resultSelector));
    }
    /**
     * Creates a subquery that iterates the results of recursively expanding the
     * elements of the source.
     *
     * @param projection A callback used to recusively expand each element.
     * @category Subquery
     */
    expand(projection) {
        return fromAsync(fn.expandAsync(internal_1.GetAsyncSource(this), projection));
    }
    do(callback) {
        return fromAsync(fn.doAsync(internal_1.GetAsyncSource(this), callback));
    }
    tap(callback) {
        return fromAsync(fn.tapAsync(internal_1.GetAsyncSource(this), callback));
    }
    /**
     * Pass the entire query to the provided callback, creating a new query from the result.
     *
     * @param callback A callback function.
     * @category Subquery
     */
    through(callback) {
        return fromAsync(fn.throughAsync(this, callback));
    }
    /**
     * Creates a subquery whose elements are in the reverse order.
     * @category Subquery
     */
    reverse() {
        return fromAsync(fn.reverseAsync(internal_1.GetAsyncSource(this)));
    }
    /**
     * Creates a subquery with every instance of the specified value removed.
     *
     * @param values The values to exclude.
     * @category Subquery
     */
    exclude(...values) {
        return fromAsync(fn.excludeAsync(internal_1.GetAsyncSource(this), ...values));
    }
    /**
     * Creates a subquery containing all elements except the first elements up to the supplied
     * count.
     *
     * @param count The number of elements to skip.
     * @category Subquery
     */
    skip(count) {
        return fromAsync(fn.skipAsync(internal_1.GetAsyncSource(this), count));
    }
    /**
     * Creates a subquery containing all elements except the last elements up to the supplied
     * count.
     *
     * @param count The number of elements to skip.
     * @category Subquery
     */
    skipRight(count) {
        return fromAsync(fn.skipRightAsync(internal_1.GetAsyncSource(this), count));
    }
    /**
     * Creates a subquery containing all elements except the first elements that match
     * the supplied predicate.
     *
     * @param predicate A callback used to match each element.
     * @category Subquery
     */
    skipWhile(predicate) {
        return fromAsync(fn.skipWhileAsync(internal_1.GetAsyncSource(this), predicate));
    }
    /**
     * Creates a subquery containing all elements except the first elements that do not match
     * the supplied predicate.
     *
     * @param predicate A callback used to match each element.
     * @category Subquery
     */
    skipUntil(predicate) {
        return fromAsync(fn.skipUntilAsync(internal_1.GetAsyncSource(this), predicate));
    }
    /**
     * Creates a subquery containing the first elements up to the supplied
     * count.
     *
     * @param count The number of elements to take.
     * @category Subquery
     */
    take(count) {
        return fromAsync(fn.takeAsync(internal_1.GetAsyncSource(this), count));
    }
    /**
     * Creates a subquery containing the last elements up to the supplied
     * count.
     *
     * @param count The number of elements to take.
     * @category Subquery
     */
    takeRight(count) {
        return fromAsync(fn.takeRightAsync(internal_1.GetAsyncSource(this), count));
    }
    takeWhile(predicate) {
        return fromAsync(fn.takeWhileAsync(internal_1.GetAsyncSource(this), predicate));
    }
    /**
     * Creates a subquery containing the first elements that do not match the supplied predicate.
     *
     * @param predicate A callback used to match each element.
     * @category Subquery
     */
    takeUntil(predicate) {
        return fromAsync(fn.takeUntilAsync(internal_1.GetAsyncSource(this), predicate));
    }
    intersect(right, equaler) {
        return fromAsync(fn.intersectAsync(internal_1.GetAsyncSource(this), internal_1.GetAsyncSource(right), equaler));
    }
    intersectBy(right, keySelector, keyEqualer) {
        return fromAsync(fn.intersectByAsync(internal_1.GetAsyncSource(this), internal_1.GetAsyncSource(right), keySelector, keyEqualer));
    }
    /**
     * Creates a subquery for the set union of this [[AsyncQuery]] and another [[AsyncQueryable]].
     *
     * @param right An [[AsyncQueryable]] object.
     * @param equaler An [[Equaler]] object used to compare equality.
     * @category Subquery
     */
    union(right, equaler) {
        return fromAsync(fn.unionAsync(internal_1.GetAsyncSource(this), internal_1.GetAsyncSource(right), equaler));
    }
    /**
     * Creates a subquery for the set union of this [[AsyncQuery]] and another [[AsyncQueryable]], where set identity is determined by the selected key.
     *
     * @param right An [[AsyncQueryable]] object.
     * @param keySelector A callback used to select the key for each element.
     * @param keyEqualer An [[Equaler]] object used to compare key equality.
     * @category Subquery
     */
    unionBy(right, keySelector, keyEqualer) {
        return fromAsync(fn.unionByAsync(internal_1.GetAsyncSource(this), internal_1.GetAsyncSource(right), keySelector, keyEqualer));
    }
    /**
     * Creates a subquery for the set difference (a.k.a. 'relative complement') between this [[AsyncQuery]] and another [[AsyncQueryable]].
     *
     * @param right An [[AsyncQueryable]] object.
     * @param equaler An [[Equaler]] object used to compare equality.
     * @category Subquery
     */
    except(right, equaler) {
        return fromAsync(fn.exceptAsync(internal_1.GetAsyncSource(this), internal_1.GetAsyncSource(right), equaler));
    }
    /**
     * Creates a subquery for the set difference between this and another [[AsyncQueryable]], where set identity is determined by the selected key.
     *
     * @param right An [[AsyncQueryable]] object.
     * @param keySelector A callback used to select the key for each element.
     * @param keyEqualer An [[Equaler]] object used to compare key equality.
     * @category Subquery
     */
    exceptBy(right, keySelector, keyEqualer) {
        return fromAsync(fn.exceptByAsync(internal_1.GetAsyncSource(this), internal_1.GetAsyncSource(right), keySelector, keyEqualer));
    }
    /**
     * Creates a subquery for the set difference between this [[AsyncQuery]] and another [[AsyncQueryable]].
     *
     * This is an alias for `except`.
     *
     * @param right An [[AsyncQueryable]] object.
     * @param equaler An [[Equaler]] object used to compare equality.
     * @category Subquery
     */
    relativeComplement(right, equaler) {
        return fromAsync(fn.relativeComplementAsync(internal_1.GetAsyncSource(this), internal_1.GetAsyncSource(right), equaler));
    }
    /**
     * Creates a subquery for the set difference between this [[AsyncQuery]] and another [[AsyncQueryable]].
     *
     * This is an alias for `except`.
     *
     * @param right An [[AsyncQueryable]] object.
     * @param keySelector A callback used to select the key for each element.
     * @param keyEqualer An [[Equaler]] object used to compare key equality.
     * @category Subquery
     */
    relativeComplementBy(right, keySelector, keyEqualer) {
        return fromAsync(fn.relativeComplementByAsync(internal_1.GetAsyncSource(this), internal_1.GetAsyncSource(right), keySelector, keyEqualer));
    }
    /**
     * Creates a subquery for the symmetric difference between this [[AsyncQuery]] and another [[AsyncQueryable]].
     *
     * @param right An [[AsyncQueryable]] object.
     * @param equaler An [[Equaler]] object used to compare equality.
     * @category Subquery
     */
    symmetricDifference(right, equaler) {
        return fromAsync(fn.symmetricDifferenceAsync(internal_1.GetAsyncSource(this), internal_1.GetAsyncSource(right), equaler));
    }
    /**
     * Creates a subquery for the symmetric difference between this [[AsyncQuery]] and another [[AsyncQueryable]].
     *
     * @param right An [[AsyncQueryable]] object.
     * @param keySelector A callback used to select the key for each element.
     * @param keyEqualer An [[Equaler]] object used to compare key equality.
     * @category Subquery
     */
    symmetricDifferenceBy(right, keySelector, keyEqualer) {
        return fromAsync(fn.symmetricDifferenceByAsync(internal_1.GetAsyncSource(this), internal_1.GetAsyncSource(right), keySelector, keyEqualer));
    }
    /**
     * Creates a subquery for the symmetric difference between this [[AsyncQuery]] and another [[AsyncQueryable]].
     *
     * This is an alias for `symmetricDifference`.
     *
     * @param right An [[AsyncQueryable]] object.
     * @param equaler An [[Equaler]] object used to compare equality.
     * @category Subquery
     */
    xor(right, equaler) {
        return fromAsync(fn.xorAsync(internal_1.GetAsyncSource(this), internal_1.GetAsyncSource(right), equaler));
    }
    /**
     * Creates a subquery for the symmetric difference between this [[AsyncQuery]] and another [[AsyncQueryable]].
     *
     * This is an alias for `symmetricDifference`.
     *
     * @param right An [[AsyncQueryable]] object.
     * @param keySelector A callback used to select the key for each element.
     * @param keyEqualer An [[Equaler]] object used to compare key equality.
     * @category Subquery
     */
    xorBy(right, keySelector, keyEqualer) {
        return fromAsync(fn.xorByAsync(internal_1.GetAsyncSource(this), internal_1.GetAsyncSource(right), keySelector, keyEqualer));
    }
    /**
     * Creates a subquery that concatenates this [[AsyncQuery]] with another [[AsyncQueryable]].
     *
     * @param right An [[AsyncQueryable]] object.
     * @category Subquery
     */
    concat(right) {
        return fromAsync(fn.concatAsync(internal_1.GetAsyncSource(this), internal_1.GetAsyncSource(right)));
    }
    /**
     * Creates a subquery for the distinct elements of this [[AsyncQuery]].
     *
     * @param equaler An [[Equaler]] object used to compare key equality.
     * @category Subquery
     */
    distinct(equaler) {
        return fromAsync(fn.distinctAsync(internal_1.GetAsyncSource(this), equaler));
    }
    /**
     * Creates a subquery for the distinct elements of this [[AsyncQuery]].
     *
     * @param keySelector A callback used to select the key to determine uniqueness.
     * @param keyEqualer An [[Equaler]] object used to compare key equality.
     * @category Subquery
     */
    distinctBy(keySelector, keyEqualer) {
        return fromAsync(fn.distinctByAsync(internal_1.GetAsyncSource(this), keySelector, keyEqualer));
    }
    /**
     * Creates a subquery for the elements of this [[AsyncQuery]] with the provided value appended to the end.
     *
     * @param value The value to append.
     * @category Subquery
     */
    append(value) {
        return fromAsync(fn.appendAsync(internal_1.GetAsyncSource(this), value));
    }
    /**
     * Creates a subquery for the elements of this [[AsyncQuery]] with the provided value prepended to the beginning.
     *
     * @param value The value to prepend.
     * @category Subquery
     */
    prepend(value) {
        return fromAsync(fn.prependAsync(internal_1.GetAsyncSource(this), value));
    }
    /**
     * Creates a subquery for the elements of this [[AsyncQuery]] with the provided range
     * patched into the results.
     *
     * @param start The offset at which to patch the range.
     * @param skipCount The number of elements to skip from start.
     * @param range The range to patch into the result.
     * @category Subquery
     */
    patch(start, skipCount, range) {
        return fromAsync(fn.patchAsync(internal_1.GetAsyncSource(this), start, skipCount, range && internal_1.GetAsyncSource(range)));
    }
    /**
     * Creates a subquery that contains the provided default value if this [[AsyncQuery]]
     * contains no elements.
     *
     * @param defaultValue The default value.
     * @category Subquery
     */
    defaultIfEmpty(defaultValue) {
        return fromAsync(fn.defaultIfEmptyAsync(internal_1.GetAsyncSource(this), defaultValue));
    }
    /**
     * Creates a subquery that splits this [[AsyncQuery]] into one or more pages.
     * While advancing from page to page is evaluated lazily, the elements of the page are
     * evaluated eagerly.
     *
     * @param pageSize The number of elements per page.
     * @category Subquery
     */
    pageBy(pageSize) {
        return fromAsync(fn.pageByAsync(internal_1.GetAsyncSource(this), pageSize));
    }
    spanMap(keySelector, elementSelector, spanSelector) {
        return fromAsync(fn.spanMapAsync(internal_1.GetAsyncSource(this), keySelector, elementSelector, wrapResultSelector(spanSelector)));
    }
    groupBy(keySelector, elementSelector, resultSelector, keyEqualer) {
        if (internal_1.IsEqualer(elementSelector)) {
            resultSelector = elementSelector;
            elementSelector = undefined;
        }
        if (internal_1.IsEqualer(resultSelector)) {
            keyEqualer = resultSelector;
            resultSelector = undefined;
        }
        return fromAsync(fn.groupByAsync(internal_1.GetAsyncSource(this), keySelector, elementSelector, wrapResultSelector(resultSelector), keyEqualer));
    }
    scan(accumulator, seed) {
        return fromAsync(arguments.length > 1
            ? fn.scanAsync(internal_1.GetAsyncSource(this), accumulator, seed)
            : fn.scanAsync(internal_1.GetAsyncSource(this), accumulator));
    }
    scanRight(accumulator, seed) {
        return fromAsync(arguments.length > 1
            ? fn.scanRightAsync(internal_1.GetAsyncSource(this), accumulator, seed)
            : fn.scanRightAsync(internal_1.GetAsyncSource(this), accumulator));
    }
    // #endregion Subquery
    // #region Join
    /**
     * Creates a grouped subquery for the correlated elements of this [[AsyncQuery]] and another [[AsyncQueryable]] object.
     *
     * @param inner A [[Queryable]] object.
     * @param outerKeySelector A callback used to select the key for an element in this [[AsyncQuery]].
     * @param innerKeySelector A callback used to select the key for an element in the other [[Queryable]] object.
     * @param resultSelector A callback used to select the result for the correlated elements.
     * @param keyEqualer An [[Equaler]] object used to compare key equality.
     * @category Join
     */
    groupJoin(inner, outerKeySelector, innerKeySelector, resultSelector, keyEqualer) {
        return fromAsync(fn.groupJoinAsync(internal_1.GetAsyncSource(this), internal_1.GetAsyncSource(inner), outerKeySelector, innerKeySelector, wrapResultSelector(resultSelector), keyEqualer));
    }
    /**
     * Creates a subquery for the correlated elements of this [[AsyncQuery]] and another [[AsyncQueryable]].
     *
     * @param inner A [[Queryable]] object.
     * @param outerKeySelector A callback used to select the key for an element in this [[AsyncQuery]].
     * @param innerKeySelector A callback used to select the key for an element in the other Queryable.
     * @param resultSelector A callback used to select the result for the correlated elements.
     * @param keyEqualer An [[Equaler]] object used to compare key equality.
     * @category Join
     */
    join(inner, outerKeySelector, innerKeySelector, resultSelector, keyEqualer) {
        return fromAsync(fn.joinAsync(internal_1.GetAsyncSource(this), internal_1.GetAsyncSource(inner), outerKeySelector, innerKeySelector, resultSelector, keyEqualer));
    }
    /**
     * Creates a subquery for the correlated elements of this [[AsyncQuery]] and another [[AsyncQueryable]].
     *
     * @param inner A [[Queryable]] object.
     * @param outerKeySelector A callback used to select the key for an element in this [[AsyncQuery]].
     * @param innerKeySelector A callback used to select the key for an element in the other Queryable.
     * @param resultSelector A callback used to select the result for the correlated elements.
     * @param keyEqualer An [[Equaler]] object used to compare key equality.
     * @category Join
     */
    fullJoin(inner, outerKeySelector, innerKeySelector, resultSelector, keyEqualer) {
        return fromAsync(fn.joinAsync(internal_1.GetAsyncSource(this), internal_1.GetAsyncSource(inner), outerKeySelector, innerKeySelector, resultSelector, keyEqualer));
    }
    zip(right, selector) {
        return fromAsync(fn.zipAsync(internal_1.GetAsyncSource(this), internal_1.GetAsyncSource(right), selector));
    }
    // #endregion
    // #region Order
    /**
     * Creates an ordered subquery whose elements are sorted in ascending order by the provided key.
     *
     * @param keySelector A callback used to select the key for an element.
     * @param comparer An optional callback used to compare two keys.
     * @category Order
     */
    orderBy(keySelector, comparer) {
        return fromAsync(fn.orderByAsync(internal_1.GetAsyncSource(this), keySelector, comparer));
    }
    /**
     * Creates an ordered subquery whose elements are sorted in descending order by the provided key.
     *
     * @param keySelector A callback used to select the key for an element.
     * @param comparer An optional callback used to compare two keys.
     * @category Order
     */
    orderByDescending(keySelector, comparer) {
        return fromAsync(fn.orderByDescendingAsync(internal_1.GetAsyncSource(this), keySelector, comparer));
    }
    // #endregion Order
    // #region Hierarchy
    /**
     * Creates a HierarchyQuery using the provided HierarchyProvider.
     *
     * @param hierarchy A HierarchyProvider.
     * @category Hierarchy
     */
    toHierarchy(hierarchy) {
        return fromAsync(fn.toHierarchyAsync(internal_1.GetAsyncSource(this), hierarchy));
    }
    reduce(accumulator, seed, resultSelector) {
        return arguments.length > 1
            ? fn.reduceAsync(internal_1.GetAsyncSource(this), accumulator, seed, resultSelector)
            : fn.reduceAsync(internal_1.GetAsyncSource(this), accumulator);
    }
    reduceRight(accumulator, seed, resultSelector) {
        return arguments.length > 1
            ? fn.reduceAsync(internal_1.GetAsyncSource(this), accumulator, seed, resultSelector)
            : fn.reduceAsync(internal_1.GetAsyncSource(this), accumulator);
    }
    /**
     * Counts the number of elements in the Query, optionally filtering elements using the supplied
     * callback.
     *
     * @param predicate An optional callback used to match each element.
     * @category Scalar
     */
    count(predicate) {
        return fn.countAsync(internal_1.GetAsyncSource(this), predicate);
    }
    first(predicate) {
        return fn.firstAsync(internal_1.GetAsyncSource(this), predicate);
    }
    last(predicate) {
        return fn.lastAsync(internal_1.GetAsyncSource(this), predicate);
    }
    single(predicate) {
        return fn.singleAsync(internal_1.GetAsyncSource(this), predicate);
    }
    /**
     * Gets the minimum element in the query, optionally comparing elements using the supplied
     * callback.
     *
     * @param comparer An optional callback used to compare two elements.
     * @category Scalar
     */
    min(comparer) {
        return fn.minAsync(internal_1.GetAsyncSource(this), comparer);
    }
    /**
     * Gets the minimum element in the query, optionally comparing the keys of each element using the supplied callback.
     *
     * @param keySelector A callback used to choose the key to compare.
     * @param keyComparer An optional callback used to compare the keys.
     * @category Scalar
     */
    minBy(keySelector, keyComparer) {
        return fn.minByAsync(internal_1.GetAsyncSource(this), keySelector, keyComparer);
    }
    /**
     * Gets the maximum element in the query, optionally comparing elements using the supplied
     * callback.
     *
     * @param comparer An optional callback used to compare two elements.
     * @category Scalar
     */
    max(comparer) {
        return fn.maxAsync(internal_1.GetAsyncSource(this), comparer);
    }
    /**
     * Gets the maximum element in the query, optionally comparing the keys of each element using the supplied callback.
     *
     * @param keySelector A callback used to choose the key to compare.
     * @param keyComparer An optional callback used to compare the keys.
     * @category Scalar
     */
    maxBy(keySelector, keyComparer) {
        return fn.maxByAsync(internal_1.GetAsyncSource(this), keySelector, keyComparer);
    }
    sum(elementSelector) {
        return fn.sumAsync(internal_1.GetAsyncSource(this), elementSelector);
    }
    average(elementSelector) {
        return fn.averageAsync(internal_1.GetAsyncSource(this), elementSelector);
    }
    /**
     * Computes a scalar value indicating whether the Query contains any elements,
     * optionally filtering the elements using the supplied callback.
     *
     * @param predicate An optional callback used to match each element.
     * @category Scalar
     */
    some(predicate) {
        return fn.someAsync(internal_1.GetAsyncSource(this), predicate);
    }
    /**
     * Computes a scalar value indicating whether all elements of the Query
     * match the supplied callback.
     *
     * @param predicate A callback used to match each element.
     * @category Scalar
     */
    every(predicate) {
        return fn.everyAsync(internal_1.GetAsyncSource(this), predicate);
    }
    corresponds(right, equalityComparison) {
        return fn.correspondsAsync(internal_1.GetAsyncSource(this), internal_1.GetAsyncSource(right), equalityComparison);
    }
    correspondsBy(right, leftKeySelector, rightKeySelector, keyEqualer) {
        return fn.correspondsByAsync(internal_1.GetAsyncSource(this), internal_1.GetAsyncSource(right), leftKeySelector, rightKeySelector, keyEqualer);
    }
    includes(value, equaler) {
        return fn.includesAsync(internal_1.GetAsyncSource(this), value, equaler);
    }
    includesSequence(right, equaler) {
        return fn.includesSequenceAsync(internal_1.GetAsyncSource(this), internal_1.GetAsyncSource(right), equaler);
    }
    startsWith(right, equaler) {
        return fn.startsWithAsync(internal_1.GetAsyncSource(this), internal_1.GetAsyncSource(right), equaler);
    }
    endsWith(right, equaler) {
        return fn.endsWithAsync(internal_1.GetAsyncSource(this), internal_1.GetAsyncSource(right), equaler);
    }
    /**
     * Finds the value in the Query at the provided offset. A negative offset starts from the
     * last element.
     *
     * @param offset An offset.
     * @category Scalar
     */
    elementAt(offset) {
        return fn.elementAtAsync(internal_1.GetAsyncSource(this), offset);
    }
    /**
     * Finds the value in the Query at the provided offset. A negative offset starts from the
     * last element.
     *
     * This is an alias for `elementAt`.
     *
     * @param offset An offset.
     * @category Scalar
     */
    nth(offset) {
        return fn.nthAsync(internal_1.GetAsyncSource(this), offset);
    }
    span(predicate) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const [first, rest] = yield fn.spanAsync(internal_1.GetAsyncSource(this), predicate);
            return [query_1.from(first), fromAsync(rest)];
        });
    }
    /**
     * Creates a tuple whose first element is a subquery containing the first span of
     * elements that do not match the supplied predicate, and whose second element is a subquery
     * containing the remaining elements.
     *
     * The first subquery is eagerly evaluated, while the second subquery is lazily
     * evaluated.
     *
     * @param predicate The predicate used to match elements.
     * @category Scalar
     */
    break(predicate) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const [first, rest] = yield fn.breakAsync(internal_1.GetAsyncSource(this), predicate);
            return [query_1.from(first), fromAsync(rest)];
        });
    }
    forEach(callback) {
        return fn.forEachAsync(internal_1.GetAsyncSource(this), callback);
    }
    /**
     * Iterates over all of the elements in the query, ignoring the results.
     * @category Scalar
     */
    drain() {
        return fn.drainAsync(internal_1.GetAsyncSource(this));
    }
    /**
     * Eagerly evaluate the query, returning a new `Query`.
     * @category Scalar
     */
    eval() {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            return query_1.from(yield fn.evalAsync(internal_1.GetAsyncSource(this)));
        });
    }
    unzip(partSelector) {
        return fn.unzipAsync(internal_1.GetAsyncSource(this), partSelector);
    }
    toArray(elementSelector) {
        return fn.toArrayAsync(internal_1.GetAsyncSource(this), elementSelector);
    }
    toSet(elementSelector, equaler) {
        return fn.toSetAsync(internal_1.GetAsyncSource(this), elementSelector, equaler);
    }
    toMap(keySelector, elementSelector, keyEqualer) {
        return fn.toMapAsync(internal_1.GetAsyncSource(this), keySelector, elementSelector, keyEqualer);
    }
    toLookup(keySelector, elementSelector, keyEqualer) {
        return fn.toLookupAsync(internal_1.GetAsyncSource(this), keySelector, elementSelector, keyEqualer);
    }
    toObject(prototype, keySelector, elementSelector, descriptorSelector) {
        return fn.toObjectAsync(internal_1.GetAsyncSource(this), prototype, keySelector, elementSelector, descriptorSelector);
    }
    /**
     * Writes each element to a destination array.
     *
     * @param dest The destination array.
     * @param start The offset into the array at which to start writing.
     * @param count The number of elements to write to the array.
     * @category Scalar
     */
    copyTo(dest, start, count) {
        return fn.copyToAsync(internal_1.GetAsyncSource(this), dest, start, count);
    }
    // #endregion Scalar
    /** @internal */ [internal_1.AsyncQuerySource.source]() {
        return this._source;
    }
}
exports.AsyncQuery = AsyncQuery;
/**
 * Represents a sequence of hierarchically organized values.
 */
class AsyncHierarchyQuery extends AsyncQuery {
    constructor(source, hierarchy) {
        if (hierarchy) {
            internal_1.assert.mustBeAsyncQueryable(source, "source");
            internal_1.assert.mustBeHierarchyProvider(hierarchy, "hierarchy");
            source = internal_1.MakeAsyncHierarchyIterable(source, hierarchy);
        }
        else {
            internal_1.assert.mustBePossiblyAsyncHierarchyIterable(source, "source");
        }
        super(source);
    }
    root(predicate) {
        return fromAsync(fn.rootAsync(internal_1.GetAsyncSource(this), predicate));
    }
    ancestors(predicate) {
        return fromAsync(fn.ancestorsAsync(internal_1.GetAsyncSource(this), predicate));
    }
    ancestorsAndSelf(predicate) {
        return fromAsync(fn.ancestorsAndSelfAsync(internal_1.GetAsyncSource(this), predicate));
    }
    descendants(predicate) {
        return fromAsync(fn.descendantsAsync(internal_1.GetAsyncSource(this), predicate));
    }
    descendantsAndSelf(predicate) {
        return fromAsync(fn.descendantsAndSelfAsync(internal_1.GetAsyncSource(this), predicate));
    }
    self(predicate) {
        return fromAsync(fn.selfAsync(internal_1.GetAsyncSource(this), predicate));
    }
    parents(predicate) {
        return fromAsync(fn.parentsAsync(internal_1.GetAsyncSource(this), predicate));
    }
    children(predicate) {
        return fromAsync(fn.childrenAsync(internal_1.GetAsyncSource(this), predicate));
    }
    siblings(predicate) {
        return fromAsync(fn.siblingsAsync(internal_1.GetAsyncSource(this), predicate));
    }
    siblingsAndSelf(predicate) {
        return fromAsync(fn.siblingsAndSelfAsync(internal_1.GetAsyncSource(this), predicate));
    }
    siblingsBeforeSelf(predicate) {
        return fromAsync(fn.siblingsBeforeSelfAsync(internal_1.GetAsyncSource(this), predicate));
    }
    siblingsAfterSelf(predicate) {
        return fromAsync(fn.siblingsAfterSelfAsync(internal_1.GetAsyncSource(this), predicate));
    }
    /**
     * Creates a subquery for the child of each element at the specified offset. A negative offset
     * starts from the last child.
     *
     * @param offset The offset for the child.
     * @category Hierarchy
     */
    nthChild(offset) {
        return fromAsync(fn.nthChildAsync(internal_1.GetAsyncSource(this), offset));
    }
    topMost(predicate) {
        return fromAsync(fn.topMostAsync(internal_1.GetAsyncSource(this), predicate));
    }
    bottomMost(predicate) {
        return fromAsync(fn.bottomMostAsync(internal_1.GetAsyncSource(this), predicate));
    }
    // #endregion Hierarchy
    [types_1.Hierarchical.hierarchy]() {
        return internal_1.GetHierarchy(internal_1.GetAsyncSource(this));
    }
}
exports.AsyncHierarchyQuery = AsyncHierarchyQuery;
/**
 * Represents an ordered sequence of elements.
 */
class AsyncOrderedQuery extends AsyncQuery {
    constructor(source) {
        internal_1.assert.mustBePossiblyAsyncOrderedIterable(source, "source");
        super(internal_1.ToAsyncOrderedIterable(source));
    }
    // #region Order
    /**
     * Creates a subsequent ordered subquery whose elements are sorted in ascending order by the provided key.
     *
     * @param keySelector A callback used to select the key for an element.
     * @param comparer An optional callback used to compare two keys.
     * @category Order
     */
    thenBy(keySelector, comparer) {
        return fromAsync(fn.thenByAsync(internal_1.GetAsyncSource(this), keySelector, comparer));
    }
    /**
     * Creates a subsequent ordered subquery whose elements are sorted in descending order by the provided key.
     *
     * @param keySelector A callback used to select the key for an element.
     * @param comparer An optional callback used to compare two keys.
     * @category Order
     */
    thenByDescending(keySelector, comparer) {
        return fromAsync(fn.thenByDescendingAsync(internal_1.GetAsyncSource(this), keySelector, comparer));
    }
    // #endregion Order
    [types_1.AsyncOrderedIterable.thenByAsync](keySelector, comparer, descending) {
        return internal_1.ThenByAsync(internal_1.GetAsyncSource(this), keySelector, comparer, descending);
    }
}
exports.AsyncOrderedQuery = AsyncOrderedQuery;
/**
 * Represents an ordered sequence of hierarchically organized values.
 */
class AsyncOrderedHierarchyQuery extends AsyncHierarchyQuery {
    constructor(source, hierarchy) {
        internal_1.assert.mustBePossiblyAsyncOrderedIterable(source, "source");
        if (hierarchy === undefined && internal_1.IsPossiblyAsyncHierarchyIterable(source)) {
            super(internal_1.ToAsyncOrderedHierarchyIterable(source));
        }
        else {
            super(internal_1.ToAsyncOrderedIterable(source), hierarchy);
        }
    }
    // #region Order
    /**
     * Creates a subsequent ordered subquery whose elements are sorted in ascending order by the provided key.
     *
     * @param keySelector A callback used to select the key for an element.
     * @param comparison An optional callback used to compare two keys.
     * @category Order
     */
    thenBy(keySelector, comparison) {
        return fromAsync(fn.thenByAsync(internal_1.GetAsyncSource(this), keySelector, comparison));
    }
    /**
     * Creates a subsequent ordered subquery whose elements are sorted in descending order by the provided key.
     *
     * @param keySelector A callback used to select the key for an element.
     * @param comparison An optional callback used to compare two keys.
     * @category Order
     */
    thenByDescending(keySelector, comparison) {
        return fromAsync(fn.thenByDescendingAsync(internal_1.GetAsyncSource(this), keySelector, comparison));
    }
    // #endregion Order
    [types_1.AsyncOrderedIterable.thenByAsync](keySelector, comparison, descending) {
        return internal_1.ThenByAsync(internal_1.GetAsyncSource(this), keySelector, comparison, descending);
    }
}
exports.AsyncOrderedHierarchyQuery = AsyncOrderedHierarchyQuery;
function wrapResultSelector(selector) {
    if (typeof selector === "function") {
        return (inner, outer) => selector(inner, query_1.from(outer));
    }
    return selector;
}
//# sourceMappingURL=asyncQuery.js.map