UNPKG

@moicky/dynamodb

Version:

Contains a collection of convenience functions for working with AWS DynamoDB

138 lines (137 loc) 5.75 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Transaction = void 0; const client_dynamodb_1 = require("@aws-sdk/client-dynamodb"); const __1 = require(".."); const operations_1 = require("./operations"); // https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html const OPERATIONS_LIMIT = 100; class Transaction { tableName; timestamp = Date.now(); operations = {}; constructor({ tableName = (0, __1.getDefaultTable)(), timestamp = Date.now(), } = {}) { this.tableName = tableName; this.timestamp = timestamp; } getItemKey(item, tableName) { return (0, __1.getItemKey)(item, { TableName: tableName || this.tableName }); } create(item, args) { const itemKey = this.getItemKey(item, args?.TableName); const createOperation = { _type: "create", item: item, args: { TableName: this.tableName, ...args }, }; this.operations[itemKey] = createOperation; return new operations_1.CreateOperations(createOperation, this); } update(item, args) { const itemKey = this.getItemKey(item, args?.TableName); const updateOperation = { _type: "update", item, actions: [{ _type: "set", values: { updatedAt: this.timestamp } }], args: { TableName: this.tableName, ...args }, }; this.operations[itemKey] = updateOperation; return new operations_1.UpdateOperations(updateOperation, this); } delete(item, args) { const itemKey = this.getItemKey(item, args?.TableName); this.operations[itemKey] = { _type: "delete", item, args: { TableName: this.tableName, ...args }, }; } addConditionFor(item, args) { return new operations_1.ConditionOperations(this.operations, item, { TableName: this.tableName, ...args, }); } handleOperation(operation) { switch (operation._type) { case "create": { const { item, args } = operation; return { Put: { Item: (0, __1.marshallWithOptions)({ createdAt: this.timestamp, ...item }), ...args, }, }; } case "update": { const { item, actions, args } = operation; const expressions = { add: [], delete: [], remove: [], set: [], }; const { ExpressionAttributeValues, ExpressionAttributeNames, ...otherArgs } = args; const attr = new __1.ExpressionAttributes(ExpressionAttributeValues, ExpressionAttributeNames); actions.forEach((action) => { switch (action._type) { case "set": attr.appendBoth(action.values); expressions.set.push(Object.keys(action.values) .map((key) => `${attr.getName(key)} = ${attr.getValue(key)}`) .join(", ")); break; case "remove": attr.appendNames(action.attributes); expressions.remove.push(action.attributes.map((key) => attr.getName(key)).join(", ")); break; case "add": attr.appendBoth(action.values); expressions.add.push(Object.keys(action.values) .map((key) => `${attr.getName(key)} ${attr.getValue(key)}`) .join(", ")); break; case "delete": attr.appendBoth(action.values); expressions.delete.push(Object.keys(action.values) .map((key) => `${attr.getName(key)} ${attr.getValue(key)}`) .join(", ")); break; } }); const joinedExpressions = Object.entries(expressions) .filter(([, value]) => value?.length) .reduce((acc, [t, v]) => [...acc, `${t.toUpperCase()} ${v.join(", ")}`], []) .join(" "); return { Update: { Key: (0, __1.stripKey)(item), UpdateExpression: joinedExpressions, ...attr.getAttributes(), ...otherArgs, }, }; } case "delete": { const { item, args } = operation; return { Delete: { Key: (0, __1.stripKey)(item), ...args } }; } case "condition": { const { item, args } = operation; return { ConditionCheck: { Key: (0, __1.stripKey)(item), ...args } }; } } } async execute(args) { const operations = Object.values(this.operations).map((op) => this.handleOperation(op)); if (operations.length === 0 || operations.length > OPERATIONS_LIMIT) { throw new Error("Invalid number of operations"); } const input = { TransactItems: operations, ...args, }; return (0, __1.getClient)().send(new client_dynamodb_1.TransactWriteItemsCommand(input)); } } exports.Transaction = Transaction;