@nerdware/ddb-single-table
Version:
A schema-based DynamoDB modeling tool, high-level API, and type-generator built to supercharge single-table designs!⚡
70 lines (69 loc) • 2.84 kB
JavaScript
import { isObjectLike, isDate, isBuffer, isArray } from "@nerdware/ts-type-safety-utils";
import { buildAttrPathTokens } from "./buildAttrPathTokens.js";
/**
* This function uses the provided `itemAttributes` to generate the following `updateItem` args:
*
* - `UpdateExpression` (may include `"SET"` and/or `"REMOVE"` clauses)
* - `ExpressionAttributeNames`
* - `ExpressionAttributeValues`
*
* `UpdateExpression` Clauses:
* - The `"SET"` clause includes all attributes which are _not_ explicitly `undefined`.
* - The `"REMOVE"` clause includes all attributes which are explicitly set to `undefined`.
* - If {@link GenerateUpdateExpressionOpts|nullHandling} is `"REMOVE"` (default), then
* attributes with `null` values are added to the `"REMOVE"` clause, otherwise they are
* added to the `"SET"` clause.
*/
export const generateUpdateExpression = (itemAttributes, { nullHandling } = {}) => {
const shouldAddToRemoveClause = nullHandling !== "SET"
? (value) => value === undefined || value === null
: (value) => value === undefined;
const updateExpressionClauses = { SET: [], REMOVE: [] };
const ExpressionAttributeNames = {};
const ExpressionAttributeValues = {};
const recurse = (value, path) => {
if (isObjectLike(value)
&& !isDate(value)
&& !isBuffer(value)
&& !(value instanceof Set) //
) {
if (isArray(value)) {
value.forEach((arrayElement, index) => {
recurse(arrayElement, [...path, index]);
});
}
else {
for (const key of Object.keys(value)) {
const keyValue = value[key];
recurse(keyValue, [...path, key]);
}
}
}
else {
const { namePath, valueToken } = buildAttrPathTokens(path, ExpressionAttributeNames);
// Derive and append the appropriate UpdateExpression clause
if (shouldAddToRemoveClause(value)) {
updateExpressionClauses.REMOVE.push(namePath);
}
else {
updateExpressionClauses.SET.push(`${namePath} = ${valueToken}`);
ExpressionAttributeValues[valueToken] = value;
}
}
};
recurse(itemAttributes, []);
// Combine the clauses into UpdateExpression
const UpdateExpression = [
...(updateExpressionClauses.SET.length > 0
? [`SET ${updateExpressionClauses.SET.join(", ")}`]
: []),
...(updateExpressionClauses.REMOVE.length > 0
? [`REMOVE ${updateExpressionClauses.REMOVE.join(", ")}`]
: []),
].join(" ");
return {
UpdateExpression,
ExpressionAttributeNames,
ExpressionAttributeValues,
};
};