"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const operators_1 = require("rxjs/operators");
const metadata_helper_1 = require("../../decorator/metadata/metadata-helper");
const helper_1 = require("../../helper");
const mapper_1 = require("../../mapper");
const dynamo_rx_1 = require("../dynamo-rx");
const get_table_name_function_1 = require("../get-table-name.function");
const batch_get_utils_1 = require("./batch-get-utils");
const batch_get_const_1 = require("./batch-get.const");
class BatchGetRequest {
    constructor() {
        this.tables = new Map();
        this.itemCounter = 0;
        this.mapResponse = (response) => {
            let Responses = {};
            if (response.Responses && Object.keys(response.Responses).length) {
                Responses = Object.entries(response.Responses).reduce((u, [key, val]) => {
                    u[key] = val.map(attributes => mapper_1.fromDb(attributes, this.tables.get(key)));
                    return u;
                }, {});
            }
            return {
                ConsumedCapacity: response.ConsumedCapacity,
                UnprocessedKeys: response.UnprocessedKeys,
                Responses,
            };
        };
        this.dynamoRx = new dynamo_rx_1.DynamoRx();
        this.params = {
            RequestItems: {},
        };
    }
    /**
     * @param {ModelConstructor<T>} modelClazz
     * @param {Partial<T>[]} keys a partial of T that contains Partition key and SortKey (if necessary). Throws if missing.
     * @param consistentRead
     * @returns {BatchGetSingleTableRequest}
     */
    forModel(modelClazz, keys, consistentRead = false) {
        // check if modelClazz is really an @Model() decorated class
        const metadata = metadata_helper_1.metadataForClass(modelClazz);
        if (!metadata.modelOptions) {
            throw new Error('given ModelConstructor has no @Model decorator');
        }
        // check if table was already used in this request
        const tableName = get_table_name_function_1.getTableName(metadata);
        if (this.tables.has(tableName)) {
            throw new Error('table name already exists, please provide all the keys for the same table at once');
        }
        this.tables.set(tableName, modelClazz);
        // check if keys to add do not exceed max count
        if (this.itemCounter + keys.length > batch_get_const_1.BATCH_GET_MAX_REQUEST_ITEM_COUNT) {
            throw new Error(`you can request at max ${batch_get_const_1.BATCH_GET_MAX_REQUEST_ITEM_COUNT} items per request`);
        }
        this.params.RequestItems[tableName] = {
            Keys: keys.map(mapper_1.createToKeyFn(modelClazz)),
            ConsistentRead: consistentRead,
        };
        this.itemCounter += keys.length;
        return this;
    }
    execNoMap(backoffTimer = helper_1.randomExponentialBackoffTimer, throttleTimeSlot = batch_get_const_1.BATCH_GET_DEFAULT_TIME_SLOT) {
        return this.fetch(backoffTimer, throttleTimeSlot);
    }
    execFullResponse(backoffTimer = helper_1.randomExponentialBackoffTimer, throttleTimeSlot = batch_get_const_1.BATCH_GET_DEFAULT_TIME_SLOT) {
        return this.fetch(backoffTimer, throttleTimeSlot).pipe(operators_1.map(this.mapResponse));
    }
    exec(backoffTimer = helper_1.randomExponentialBackoffTimer, throttleTimeSlot = batch_get_const_1.BATCH_GET_DEFAULT_TIME_SLOT) {
        return this.fetch(backoffTimer, throttleTimeSlot).pipe(operators_1.map(this.mapResponse), operators_1.map(r => r.Responses));
    }
    fetch(backoffTimer = helper_1.randomExponentialBackoffTimer, throttleTimeSlot = batch_get_const_1.BATCH_GET_DEFAULT_TIME_SLOT) {
        return batch_get_utils_1.batchGetItemsFetchAll(this.dynamoRx, Object.assign({}, this.params), backoffTimer(), throttleTimeSlot);
    }
}
exports.BatchGetRequest = BatchGetRequest;
//# sourceMappingURL=batch-get.request.js.map