batch-get-item.js

'use strict';
/**
 * The `BatchGetItem` operation retrieves multiple items from a table in a single call.
 * @see https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchGetItem.html
 * @module BatchGetItem
 */
const { compose, map, curry, prop, objOf, apply, bind } = require('ramda');
const { mapMergeFirstPairOfArgs, overFirst } = require('./map-merge-args');
const generateKey = require('./generate-key');
const castArray = require('./cast-array');

/**
 * Generate an object containing a `Keys` property pointing to an array of
 * DynamoDB wrapped document keys, such as `{ Keys: [{ "name":{"S":"Flynamo"} }] }`.
 *
 * @private
 * @function
 * @param {Array|Object} keys The unwrapped keys to generate the `Keys` from
 * @returns {Object} An object containing a `Keys` property
 */
const generateKeys = compose(
  objOf('Keys'),
  map(
    compose(
      // The `BatchGetItem` expects a `Keys` array where each item
      // represents a document key without a wrapping `Key` property.
      // `generateKey` below returns an object such as `{ Key: { id: 42 } }`,
      // so we strip the `Key` field
      prop('Key'),
      generateKey
    )
  ),
  // Support fetching only one document, without passing in an array
  castArray
);

const createBatchGetFor = curry((batchGetItem, table) =>
  compose(
    apply(batchGetItem),
    overFirst(compose(objOf('RequestItems'), objOf(table))),
    mapMergeFirstPairOfArgs(generateKeys)
  )
);

/**
 * Creates a function to allow retrieval of several documents in a single batch.
 *
 * @private
 * @param {Object} dynamoWrapper The AWS DynamoDB client
 * @returns {Object}
 */
function createGetBatcher(dynamoWrapper) {
  const batchGetItem = bind(dynamoWrapper.batchGetItem, dynamoWrapper);
  return {
    /**
     * Returns the attributes of one or more items from a table. Requested items are identified by primary key.
     * A key represented by a `Number` or a `String` will be assumed to be named `id`.
     * Items will be fetched from `tableName`. You would typically use this function through {@link forTable}.
     *
     * @public
     * @function
     * @example
     *
     *  // Fetch documents of `id` 42, 33 and 7
     *  await batchGetFor('SomeTable')([42, 33, 7]);
     *
     * @example
     *
     *  // Fetch documents of keys `{ foo: 42 }` and `{ foo: 33 }`
     *  await batchGetFor('SomeTable')([{ foo: 42 }, { foo: 33 }]);
     *
     * @example
     *
     *  // Retrieve only `name` and `age` fields
     *  await batchGetFor('SomeTable')([42, 33], { ProjectionExpression: 'name, age' });
     *
     * @example
     *
     *  // Exported from `forTable`
     *  const { batchGet } = forTable('SomeTable');
     *  await batchGet([42, 33, 7]);
     *
     * @param {string} tableName The name of the DynamoDB table to run the query on
     * @param {Array<*> | *} keys Identifiers of elements to get from `tableName`
     * @returns {Promise} Resolves to the {@link https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchGetItem.html#API_BatchGetItem_ResponseSyntax response from DynamoDB client}.
     */
    batchGetFor: createBatchGetFor(batchGetItem)
  };
}

module.exports = createGetBatcher;