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