import { map } from 'rxjs/operators';
import { metadataForClass } from '../../decorator/metadata/metadata-helper';
import { randomExponentialBackoffTimer } from '../../helper';
import { createToKeyFn, fromDb } from '../../mapper';
import { DynamoRx } from '../dynamo-rx';
import { getTableName } from '../get-table-name.function';
import { batchGetItemsFetchAll } from './batch-get-utils';
import { BATCH_GET_DEFAULT_TIME_SLOT, BATCH_GET_MAX_REQUEST_ITEM_COUNT } from './batch-get.const';
export 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 => fromDb(attributes, this.tables.get(key)));
                    return u;
                }, {});
            }
            return {
                ConsumedCapacity: response.ConsumedCapacity,
                UnprocessedKeys: response.UnprocessedKeys,
                Responses,
            };
        };
        this.dynamoRx = new 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 = 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 = 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_MAX_REQUEST_ITEM_COUNT) {
            throw new Error(`you can request at max ${BATCH_GET_MAX_REQUEST_ITEM_COUNT} items per request`);
        }
        this.params.RequestItems[tableName] = {
            Keys: keys.map(createToKeyFn(modelClazz)),
            ConsistentRead: consistentRead,
        };
        this.itemCounter += keys.length;
        return this;
    }
    execNoMap(backoffTimer = randomExponentialBackoffTimer, throttleTimeSlot = BATCH_GET_DEFAULT_TIME_SLOT) {
        return this.fetch(backoffTimer, throttleTimeSlot);
    }
    execFullResponse(backoffTimer = randomExponentialBackoffTimer, throttleTimeSlot = BATCH_GET_DEFAULT_TIME_SLOT) {
        return this.fetch(backoffTimer, throttleTimeSlot).pipe(map(this.mapResponse));
    }
    exec(backoffTimer = randomExponentialBackoffTimer, throttleTimeSlot = BATCH_GET_DEFAULT_TIME_SLOT) {
        return this.fetch(backoffTimer, throttleTimeSlot).pipe(map(this.mapResponse), map(r => r.Responses));
    }
    fetch(backoffTimer = randomExponentialBackoffTimer, throttleTimeSlot = BATCH_GET_DEFAULT_TIME_SLOT) {
        return batchGetItemsFetchAll(this.dynamoRx, Object.assign({}, this.params), backoffTimer(), throttleTimeSlot);
    }
}
//# sourceMappingURL=batch-get.request.js.map