import { isObject } from 'lodash';
import { map, tap } from 'rxjs/operators';
import { hasSortKey, metadataForClass } from '../../../decorator/metadata';
import { createLogger } from '../../../logger/logger';
import { fromDb, toDbOne } from '../../../mapper';
// TODO add support for indexes
export class BatchGetSingleTableRequest {
    // todo: make use of toKey<T>(item: T, modelConstructor: ModelConstructor<T>)
    constructor(dynamoRx, modelClazz, tableName, keys) {
        this.logger = createLogger('dynamo.request.BatchGetSingleTableRequest', modelClazz);
        this.dynamoRx = dynamoRx;
        if (modelClazz === null || modelClazz === undefined) {
            throw new Error("please provide the model clazz for the request, won't work otherwise");
        }
        this.modelClazz = modelClazz;
        this.params = {
            RequestItems: {},
        };
        this.tableName = tableName;
        this.metadata = metadataForClass(this.modelClazz);
        this.addKeyParams(keys);
    }
    execFullResponse() {
        this.logger.debug('request', this.params);
        return this.dynamoRx.batchGetItems(this.params).pipe(tap(response => this.logger.debug('response', response)), map(response => {
            let items;
            if (response.Responses && Object.keys(response.Responses).length && response.Responses[this.tableName]) {
                const mapped = response.Responses[this.tableName].map(attributeMap => fromDb(attributeMap, this.modelClazz));
                items = mapped;
            }
            else {
                items = [];
            }
            return {
                Items: items,
                UnprocessedKeys: response.UnprocessedKeys,
                ConsumedCapacity: response.ConsumedCapacity,
            };
        }), tap(response => this.logger.debug('mapped items', response.Items)));
    }
    exec() {
        this.logger.debug('request', this.params);
        return this.dynamoRx.batchGetItems(this.params).pipe(tap(response => this.logger.debug('response', response)), map(response => {
            if (response.Responses && Object.keys(response.Responses).length && response.Responses[this.tableName]) {
                return response.Responses[this.tableName].map(attributeMap => fromDb(attributeMap, this.modelClazz));
            }
            else {
                return [];
            }
        }), tap(items => this.logger.debug('mapped items', items)));
    }
    addKeyParams(keys) {
        const attributeMaps = [];
        keys.forEach(key => {
            const idOb = {};
            if (isObject(key)) {
                // TODO add some more checks
                // got a composite primary key
                // partition key
                const mappedPartitionKey = toDbOne(key.partitionKey);
                if (mappedPartitionKey === null) {
                    throw Error('please provide an actual value for partition key');
                }
                idOb[this.metadata.getPartitionKey()] = mappedPartitionKey;
                // sort key
                if (key.sortKey && hasSortKey(this.metadata)) {
                    const mappedSortKey = toDbOne(key.sortKey);
                    if (mappedSortKey === null) {
                        throw Error('please provide an actual value for sort key');
                    }
                    idOb[this.metadata.getSortKey()] = mappedSortKey;
                }
            }
            else {
                // got a simple primary key
                const value = toDbOne(key);
                if (value === null) {
                    throw Error('please provide an actual value for partition key');
                }
                idOb[this.metadata.getPartitionKey()] = value;
            }
            attributeMaps.push(idOb);
        });
        this.params.RequestItems[this.tableName] = {
            Keys: attributeMaps,
        };
    }
}
//# sourceMappingURL=batch-get-single-table.request.js.map