import { of } from 'rxjs';
import { delay, map, mergeMap } from 'rxjs/operators';
/**
 * Function which executes batchGetItem operations until all given items (as params) are processed (fetched).
 * Between each follow-up request (in case of unprocessed items) a delay is interposed calculated by the given backoffTime and throttleTimeSlot.
 * @param dynamoRx
 * @param params containing the keys per table to create the batchGet operation
 * @param backoffTimer used to determine how many time slots the follow-up request should be delayed
 * @param throttleTimeSlot used to calculate the effective wait time
 */
export function batchGetItemsFetchAll(dynamoRx, params, backoffTimer, throttleTimeSlot) {
    return dynamoRx.batchGetItems(params).pipe(mergeMap(response => {
        if (hasUnprocessedKeys(response)) {
            // in case of unprocessedItems do a follow-up requests
            return of(response.UnprocessedKeys).pipe(
            // delay before doing the follow-up request
            delay(backoffTimer.next().value * throttleTimeSlot), mergeMap((UnprocessedKeys) => {
                const nextParams = Object.assign({}, params, { RequestItems: UnprocessedKeys });
                // call recursively batchGetItemsFetchAll with the returned UnprocessedItems params
                return batchGetItemsFetchAll(dynamoRx, nextParams, backoffTimer, throttleTimeSlot);
            }), map(combineBatchGetResponses(response)));
        }
        // no follow-up request necessary, return result
        return of(response);
    }));
}
export function hasUnprocessedKeys(response) {
    if (!response.UnprocessedKeys) {
        return false;
    }
    return Object.values(response.UnprocessedKeys).some(t => !!t && t.Keys && t.Keys.length > 0);
}
/**
 * combines a first with a second response. ConsumedCapacity is always from the latter.
 * @param response1
 */
export function combineBatchGetResponses(response1) {
    return (response2) => {
        const tableNames = Object.keys(response1.Responses || {});
        Object.keys(response2.Responses || {})
            .filter(tn => !tableNames.includes(tn))
            .forEach(tn => tableNames.push(tn));
        const Responses = tableNames.reduce((u, tableName) => (Object.assign({}, u, { [tableName]: [
                ...((response1.Responses && response1.Responses[tableName]) || []),
                ...((response2.Responses && response2.Responses[tableName]) || []),
            ] })), {});
        return Object.assign({}, response2, { Responses });
    };
}
//# sourceMappingURL=batch-get-utils.js.map