import { map } from 'rxjs/operators';
import { fetchAll } from '../../../helper';
import { Mapper } from '../../../mapper/mapper';
import { and } from '../../expression/logical-operator/and.function';
import { ParamUtil } from '../../expression/param-util';
import { RequestExpressionBuilder } from '../../expression/request-expression-builder';
import { Request } from '../request.model';
export class QueryRequest extends Request {
    constructor(dynamoRx, modelClazz, tableName) {
        super(dynamoRx, modelClazz, tableName);
    }
    wherePartitionKey(partitionKeyValue) {
        let partitionKey;
        if (this.params.IndexName) {
            const 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 RequestExpressionBuilder.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>}
     */
    whereSortKey() {
        let sortKey;
        if (this.params.IndexName) {
            const 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 RequestExpressionBuilder.addSortKeyCondition(sortKey, this, this.metaData);
    }
    // TODO TYPING how can we improve the typing to define the accepted value for condition function (see
    // update2.function)
    whereAttribute(attributePath) {
        return RequestExpressionBuilder.addCondition('FilterExpression', attributePath, this, this.metaData);
    }
    where(...conditionDefFns) {
        const condition = and(...conditionDefFns)(undefined, this.metaData);
        ParamUtil.addExpression('FilterExpression', condition, this.params);
        return this;
    }
    ascending() {
        this.params.ScanIndexForward = true;
        return this;
    }
    descending() {
        this.params.ScanIndexForward = false;
        return this;
    }
    execCount() {
        const params = Object.assign({}, this.params);
        params.Select = 'COUNT';
        return this.dynamoRx.query(params).pipe(map(response => response.Count));
    }
    execFullResponse() {
        return this.dynamoRx.query(this.params).pipe(map(queryResponse => {
            const response = Object.assign({}, queryResponse);
            response.Items = queryResponse.Items.map(item => Mapper.fromDb(item, this.modelClazz));
            return response;
        }));
    }
    exec() {
        return this.dynamoRx
            .query(this.params)
            .pipe(map(response => response.Items.map(item => Mapper.fromDb(item, this.modelClazz))));
    }
    execNoMap() {
        return this.dynamoRx.query(this.params);
    }
    execSingle() {
        this.limit(1);
        return this.dynamoRx.query(this.params).pipe(map(response => {
            if (response.Count) {
                return Mapper.fromDb(response.Items[0], this.modelClazz);
            }
            else {
                return null;
            }
        }));
    }
    /**
     * fetches all pages. may uses all provisionedOutput, therefore for client side use cases rather use pagedDatasource (exec)
     */
    execFetchAll() {
        return fetchAll(this);
    }
}
//# sourceMappingURL=query.request.js.map