UNPKG

@moicky/dynamodb

Version:

Contains a collection of convenience functions for working with AWS DynamoDB

160 lines (159 loc) 5.83 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getAllItems = exports.getItems = exports.getItem = void 0; const client_dynamodb_1 = require("@aws-sdk/client-dynamodb"); const lib_1 = require("../lib"); /** * Retrieves an item from the DynamoDB table using its key schema. * @param key - The item with at least the partition key and the sort key (if applicable) of the item to get. * @param args - The additional arguments to override or specify for {@link GetItemCommandInput} * @returns A promise that resolves to the unmarshalled item * * @example * Get a single item * ```javascript * await getItem({ * PK: "User/1", * SK: "Book/1", * title: "The Great Gatsby", * author: "F. Scott Fitzgerald", * released: 1925, * }); * ``` * @example * Get a single item in a different table * ```javascript * await getItem( * { PK: "User/1", SK: "Book/1" }, * { TableName: "AnotherTable" } * ); * ``` */ async function getItem(key, args = {}) { args = (0, lib_1.withDefaults)(args, "getItem"); return (0, lib_1.getClient)() .send(new client_dynamodb_1.GetItemCommand({ Key: (0, lib_1.stripKey)(key, args), ...args, TableName: args?.TableName || (0, lib_1.getDefaultTable)(), })) .then((res) => res?.Item ? (0, lib_1.unmarshallWithOptions)(res.Item) : undefined); } exports.getItem = getItem; /** * Retrieves multiple items from the DynamoDB table using their key schema. * @param keys - The items with at least the partition key and the sort key (if applicable) of the items to get. * @param args - The additional arguments to override or specify for {@link GetItemsArgs} * @returns A promise that resolves to an array of unmarshalled items * * @example * Get items in default table * ```javascript * await getItems([ * { PK: "User/1", SK: "Book/1", title: "The Great Gatsby", released: 1925 }, * { PK: "User/1", SK: "Book/2" }, * { PK: "User/1", SK: "Book/3" }, * // ... infinite more items (will be grouped into batches of 100 due to aws limit) and retried up to 3 times * ]); * ``` * @example * Get items in a different table * ```javascript * await getItems( * [ * { PK: "User/1", SK: "Book/1", title: "The Great Gatsby", released: 1925 }, * { PK: "User/1", SK: "Book/2" }, * { PK: "User/1", SK: "Book/3" }, * ], * { TableName: "AnotherTable" } * ); * ``` */ async function getItems(keys, args = {}, retry = 0) { args = (0, lib_1.withDefaults)(args, "getItems"); // creates batches of 100 items each and performs batchGet on every batch. // also retries up to 3 times if there are unprocessed items (due to size limit of 16MB) // returns items in same order as keys (not sorted by default when using batchGet) if (retry > 3) return []; const batchReadLimit = 100; // duplicate key entries would cause an error, so we remove them const uniqueKeys = Object.values(keys.reduce((acc, key) => { const strippedKey = (0, lib_1.stripKey)(key, args); const keyString = JSON.stringify(strippedKey); if (!acc[keyString]) { acc[keyString] = strippedKey; } return acc; }, {})); const batches = (0, lib_1.splitEvery)(uniqueKeys, batchReadLimit); const results = []; if (retry > 2) { return results; } const TableName = args?.TableName || (0, lib_1.getDefaultTable)(); delete args.TableName; await Promise.all(batches.map(async (batch) => { await (0, lib_1.getClient)() .send(new client_dynamodb_1.BatchGetItemCommand({ RequestItems: { [TableName]: { Keys: batch, ...args, }, }, })) .then((res) => { const unprocessed = res?.UnprocessedKeys?.[TableName]; const allItemsFromBatch = res?.Responses?.[TableName] || []; if (unprocessed) { return getItems(unprocessed.Keys, { ...args, TableName }, retry + 1).then((items) => allItemsFromBatch.concat(items)); } return allItemsFromBatch.map((item) => item && (0, lib_1.unmarshallWithOptions)(item)); }) .then((items) => results.push(...items)); })); const resultItems = results .filter(Boolean) .reduce((acc, item) => { const keyString = JSON.stringify((0, lib_1.stripKey)(item, { TableName })); acc[keyString] = item; return acc; }, {}); return keys.map((key) => resultItems[JSON.stringify((0, lib_1.stripKey)(key, { TableName }))] || undefined); } exports.getItems = getItems; /** * Retrieves all items from the DynamoDB table. * @param args - The additional arguments to override or specify for {@link ScanCommandInput} * @returns A promise that resolves to an array of unmarshalled items * * @example * Retrieve all items in default table * ```javascript * await getAllItems(); * ``` * @example * Retrieve all items in a different table * ```javascript * await getAllItems( * { TableName: "AnotherTable" } * ); * ``` */ async function getAllItems(args = {}) { args = (0, lib_1.withFixes)((0, lib_1.withDefaults)(args, "getAllItems")); let items = []; let lastEvaluatedKey; do { const response = await (0, lib_1.getClient)().send(new client_dynamodb_1.ScanCommand({ ...args, TableName: args?.TableName || (0, lib_1.getDefaultTable)(), ExclusiveStartKey: lastEvaluatedKey, })); items = items.concat(response.Items.map((item) => (0, lib_1.unmarshallWithOptions)(item))); lastEvaluatedKey = response.LastEvaluatedKey; } while (lastEvaluatedKey); return items; } exports.getAllItems = getAllItems;