dynamodb-toolbox
Version:
Lightweight and type-safe query builder for DynamoDB and TypeScript.
201 lines (200 loc) • 8.68 kB
JavaScript
import { DynamoDBToolboxError } from '../../../../../errors/index.js';
import { Parser } from '../../../../../schema/actions/parse/index.js';
import { formatArrayPath } from '../../../../../schema/actions/utils/formatArrayPath.js';
import { isArray } from '../../../../../utils/validation/isArray.js';
import { isInteger } from '../../../../../utils/validation/isInteger.js';
import { isObject } from '../../../../../utils/validation/isObject.js';
import { $APPEND, $PREPEND, $SET, isAppending, isPrepending, isRemoval, isSetting } from '../../symbols/index.js';
import { parseUpdateExtension } from './attribute.js';
import { parseReferenceExtension } from './reference.js';
function* listElementParser(schema, inputValue, { transform = true, valuePath }) {
if (isRemoval(inputValue)) {
const parsedValue = inputValue;
if (transform) {
yield parsedValue;
}
else {
return parsedValue;
}
const transformedValue = parsedValue;
return transformedValue;
}
if (inputValue === undefined) {
const parsedValue = undefined;
if (transform) {
yield parsedValue;
}
else {
return parsedValue;
}
const transformedValue = undefined;
return transformedValue;
}
return yield* new Parser(schema.elements).start(inputValue, {
mode: 'update',
fill: false,
transform,
parseExtension: parseUpdateExtension,
valuePath
});
}
export const parseListExtension = (schema, input, { transform = true, valuePath }) => {
if (isSetting(input) && input[$SET] !== undefined) {
return {
isExtension: true,
*extensionParser() {
const parser = new Parser(schema).start(input[$SET], {
fill: false,
transform,
valuePath: [...(valuePath !== null && valuePath !== void 0 ? valuePath : []), '$SET']
});
const parsedValue = { [$SET]: parser.next().value };
if (transform) {
yield parsedValue;
}
else {
return parsedValue;
}
const transformedValue = { [$SET]: parser.next().value };
return transformedValue;
}
};
}
if (isObject(input) || isArray(input)) {
if (isAppending(input) && input[$APPEND] !== undefined) {
const appendedValue = input[$APPEND];
const appendedValuePath = [...(valuePath !== null && valuePath !== void 0 ? valuePath : []), '$APPEND'];
if (isArray(appendedValue)) {
return {
isExtension: true,
*extensionParser() {
const parsers = appendedValue.map((element, index) =>
// Should be a simple list of valid elements (not extended)
new Parser(schema.elements).start(element, {
fill: false,
transform,
valuePath: [...appendedValuePath, index]
}));
const parsedValue = { [$APPEND]: parsers.map(parser => parser.next().value) };
if (transform) {
yield parsedValue;
}
else {
return parsedValue;
}
const transformedValue = { [$APPEND]: parsers.map(parser => parser.next().value) };
return transformedValue;
}
};
}
return {
isExtension: true,
*extensionParser() {
const parser = new Parser(schema).start(appendedValue, {
fill: false,
transform,
parseExtension: parseReferenceExtension,
valuePath: appendedValuePath
});
const parsedValue = { [$APPEND]: parser.next().value };
if (transform) {
yield parsedValue;
}
else {
return parsedValue;
}
const transformedValue = { [$APPEND]: parser.next().value };
return transformedValue;
}
};
}
if (isPrepending(input) && input[$PREPEND] !== undefined) {
const prependedValue = input[$PREPEND];
const prependedValuePath = [...(valuePath !== null && valuePath !== void 0 ? valuePath : []), '$PREPEND'];
if (isArray(prependedValue)) {
return {
isExtension: true,
*extensionParser() {
const parsers = prependedValue.map((element, index) => new Parser(schema.elements).start(element, {
fill: false,
transform,
valuePath: [...prependedValuePath, index]
}));
const parsedValue = { [$PREPEND]: parsers.map(parser => parser.next().value) };
if (transform) {
yield parsedValue;
}
else {
return parsedValue;
}
const transformedValue = { [$PREPEND]: parsers.map(parser => parser.next().value) };
return transformedValue;
}
};
}
return {
isExtension: true,
*extensionParser() {
const parser = new Parser(schema).start(prependedValue, {
fill: false,
transform,
parseExtension: parseReferenceExtension,
valuePath: prependedValuePath
});
const parsedValue = { [$PREPEND]: parser.next().value };
if (transform) {
yield parsedValue;
}
else {
return parsedValue;
}
const transformedValue = { [$PREPEND]: parser.next().value };
return transformedValue;
}
};
}
return {
isExtension: true,
*extensionParser() {
let maxUpdatedIndex = 0;
const parsers = Object.fromEntries(Object.entries(input).map(([index, element]) => [
index,
listElementParser(schema, element, {
transform,
valuePath: [...(valuePath !== null && valuePath !== void 0 ? valuePath : []), index]
})
]));
for (const inputKey of Object.keys(parsers)) {
const parsedInputKey = parseFloat(inputKey);
const path = valuePath !== undefined ? formatArrayPath(valuePath) : undefined;
if (!isInteger(parsedInputKey)) {
throw new DynamoDBToolboxError('parsing.invalidAttributeInput', {
message: `Index of array attribute ${path !== undefined ? `'${path}' ` : ''}is not a valid integer`,
path,
payload: { received: inputKey }
});
}
maxUpdatedIndex = Math.max(maxUpdatedIndex, parsedInputKey);
}
const parsedValue = Object.fromEntries(Object.entries(parsers)
.map(([index, parser]) => [index, parser.next().value])
.filter(([, element]) => element !== undefined));
if (transform) {
yield parsedValue;
}
else {
return parsedValue;
}
const transformedValue = [...Array(maxUpdatedIndex + 1).keys()].map(index => {
const parser = parsers[index];
return parser === undefined ? undefined : parser.next().value;
});
return transformedValue;
}
};
}
return {
isExtension: false,
unextendedInput: input
};
};