import * as tslib_1 from "tslib";
import { map, tap } from 'rxjs/operators';
import { fetchAll } from '../../../helper';
import { createLogger } from '../../../logger/logger';
import { fromDb } from '../../../mapper';
import { and } from '../../expression';
import { addExpression } from '../../expression/param-util';
import { addCondition, addSortKeyCondition } from '../../expression/request-expression-builder';
import { Request } from '../request.model';
var QueryRequest = /** @class */ (function (_super) {
    tslib_1.__extends(QueryRequest, _super);
    function QueryRequest(dynamoRx, modelClazz, tableName) {
        var _this = _super.call(this, dynamoRx, modelClazz, tableName) || this;
        _this.logger = createLogger('dynamo.request.QueryRequest', modelClazz);
        return _this;
    }
    QueryRequest.prototype.wherePartitionKey = function (partitionKeyValue) {
        var partitionKey;
        if (this.params.IndexName) {
            var index = this.metadata.getIndex(this.params.IndexName);
            if (index) {
                partitionKey = index.partitionKey;
                if (!partitionKey) {
                    throw new Error("there is no parition key defined for index <" + this.params.IndexName + ">");
                }
            }
            else {
                throw new Error("the index <" + this.params.IndexName + "> does not exist on model " + this.modelClazz.name);
            }
        }
        else {
            partitionKey = this.metadata.getPartitionKey();
        }
        return addSortKeyCondition(partitionKey, this, this.metadata).equals(partitionKeyValue);
    };
    /**
     * used to define some condition for the sort key, use the secondary index to query based on a custom index
     * @returns {RequestConditionFunction<T>}
     */
    QueryRequest.prototype.whereSortKey = function () {
        var sortKey;
        if (this.params.IndexName) {
            var index = this.metadata.getIndex(this.params.IndexName);
            if (index) {
                if (index.sortKey) {
                    sortKey = index.sortKey;
                }
                else {
                    throw new Error("there is no sort key defined for index <" + this.params.IndexName + ">");
                }
            }
            else {
                throw new Error("the index <" + this.params.IndexName + "> does not exist on model " + this.modelClazz.name);
            }
        }
        else {
            sortKey = this.metadata.getSortKey();
        }
        if (!sortKey) {
            throw new Error('There was no sort key defined for current schema');
        }
        return addSortKeyCondition(sortKey, this, this.metadata);
    };
    // TODO TYPING how can we improve the typing to define the accepted value for condition function (see
    // update2.function)
    QueryRequest.prototype.whereAttribute = function (attributePath) {
        return addCondition('FilterExpression', attributePath, this, this.metadata);
    };
    QueryRequest.prototype.where = function () {
        var conditionDefFns = [];
        for (var _i = 0; _i < arguments.length; _i++) {
            conditionDefFns[_i] = arguments[_i];
        }
        var condition = and.apply(void 0, tslib_1.__spread(conditionDefFns))(undefined, this.metadata);
        addExpression('FilterExpression', condition, this.params);
        return this;
    };
    QueryRequest.prototype.ascending = function () {
        this.params.ScanIndexForward = true;
        return this;
    };
    QueryRequest.prototype.descending = function () {
        this.params.ScanIndexForward = false;
        return this;
    };
    QueryRequest.prototype.execCount = function () {
        var _this = this;
        var params = tslib_1.__assign({}, this.params);
        params.Select = 'COUNT';
        this.logger.debug('count request', params);
        return this.dynamoRx.query(params).pipe(tap(function (response) { return _this.logger.debug('response', response); }), map(function (response) { return response.Count || 0; }), tap(function (count) { return _this.logger.debug('count', count); }));
    };
    QueryRequest.prototype.execFullResponse = function () {
        var _this = this;
        this.logger.debug('request', this.params);
        return this.dynamoRx.query(this.params).pipe(tap(function (response) { return _this.logger.debug('response', response); }), map(function (queryResponse) {
            var response = tslib_1.__assign({}, queryResponse);
            response.Items = (queryResponse.Items || []).map(function (item) { return fromDb(item, _this.modelClazz); });
            return response;
        }), tap(function (response) { return _this.logger.debug('mapped items', response.Items); }));
    };
    QueryRequest.prototype.exec = function () {
        var _this = this;
        this.logger.debug('request', this.params);
        return this.dynamoRx.query(this.params).pipe(tap(function (response) { return _this.logger.debug('response', response); }), map(function (response) { return (response.Items || []).map(function (item) { return fromDb(item, _this.modelClazz); }); }), tap(function (items) { return _this.logger.debug('mapped items', items); }));
    };
    QueryRequest.prototype.execNoMap = function () {
        var _this = this;
        this.logger.debug('request (noMap)', this.params);
        return this.dynamoRx.query(this.params).pipe(tap(function (response) { return _this.logger.debug('response', response); }));
    };
    QueryRequest.prototype.execSingle = function () {
        var _this = this;
        this.limit(1);
        this.logger.debug('single request', this.params);
        return this.dynamoRx.query(this.params).pipe(tap(function (response) { return _this.logger.debug('response', response); }), map(function (response) {
            return response.Items && response.Items.length
                ? fromDb(response.Items[0], _this.modelClazz)
                : null;
        }), tap(function (item) { return _this.logger.debug('mapped item', item); }));
    };
    /**
     * fetches all pages. may uses all provisionedOutput, therefore for client side use cases rather use pagedDatasource (exec)
     */
    QueryRequest.prototype.execFetchAll = function () {
        return fetchAll(this);
    };
    return QueryRequest;
}(Request));
export { QueryRequest };
//# sourceMappingURL=query.request.js.map