@moicky/dynamodb
Version:
Contains a collection of convenience functions for working with AWS DynamoDB
160 lines (159 loc) • 5.83 kB
JavaScript
;
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;