insert.js

'use strict';
/**
 * Create new items, or replace old items with new ones.
 * @see https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html
 * @module PutItem
 */
const { curry, bind, compose, apply } = require('ramda');
const generateItem = require('./generate-item');
const addTableName = require('./table-name');
const { mapMergeFirstPairOfArgs } = require('./map-merge-args');

/**
 * @private
 */
const createInsert = putItem => compose(apply(putItem), mapMergeFirstPairOfArgs(generateItem));

/**
 * @private
 */
const createInsertFor = curry((putItem, table) =>
  compose(apply(putItem), mapMergeFirstPairOfArgs(compose(addTableName(table), generateItem)))
);

function createInserter(dynamoWrapper) {
  const putItem = bind(dynamoWrapper.putItem, dynamoWrapper);
  return {
    /**
     * Creates a new item, or replaces an old item with a new item.
     * If an item that has the same primary key as the new item already exists in the specified table,
     * the new item completely replaces the existing item. This function uses `PutItem` internally.
     *
     * @function
     * @example
     *
     *  await insert({ id: 42, foo: 'bar' }, { TableName: 'SomeTable' });
     *  // Upserts item of primary key `{id: 42}` of `SomTable`
     *
     * @see https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html#API_PutItem_RequestSyntax
     * @param {Object} item The item to insert. Will be converted into a map of DynamoDB attributes.
     * @param {Object} request Parameters as expected by DynamoDB `PutItem` operation. Must contain, at least, `TableName` attribute.
     * @returns {Promise} Resolves to the response from DynamoDB client.
     */
    insert: createInsert(putItem),

    /**
     * Returns a function Creates a new item, or replaces an old item with a new item.
     * If an item that has the same primary key as the new item already exists in the specified table,
     * the new item completely replaces the existing item. This function uses `PutItem` internally.
     * The last `request` argument is optional and is only required if any non mandatory attribute
     * needs to be included in the request.
     * You would typically use this function through {@link forTable}.
     *
     * @function
     * @example
     *
     *  // Upserts item of primary key `{id: 42}` of `SomeTable`
     *  await insertFor('SomeTable')({ id: 42, foo: 'bar' });
     *
     * @example
     *
     *  // Upserts item of primaty key `{id: 42}` as long as `name` is not 'Alice'
     *  await insertFor('SomeTable')(
     *    { id: 42, name: 'Bob' },
     *    { ConditionExpression: 'name <> :f', ExpressionAttributeValues: { ':f': { 'S': 'Alice' } } }
     *  );
     *
     * @example
     *
     *  // Upserts item of primary key `{id: 42}` of `SomeTable`
     *  const { insert } = forTable('SomeTable');
     *  await insert({ id: 42, name: 'Bob' });
     *
     * @see https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html#API_PutItem_RequestSyntax
     * @param {string} tableName The name of the DynamoDB table to run the query on
     * @param {Object} item The item to insert. Will be converted into a map of DynamoDB attributes.
     * @param {Object=} request Parameters as expected by DynamoDB `PutItem` operation. Must contain, at least, `TableName` attribute.
     * @returns {Promise} Resolves to the response from DynamoDB client.
     */
    insertFor: createInsertFor(putItem)
  };
}

module.exports = createInserter;