dynamodb-toolbox
Version:
Lightweight and type-safe query builder for DynamoDB and TypeScript.
84 lines (83 loc) • 3.68 kB
JavaScript
import { DynamoDBToolboxError } from '../../../errors/index.js';
import { formatArrayPath } from '../../../schema/actions/utils/formatArrayPath.js';
import { isObject } from '../../../utils/validation/isObject.js';
import { Formatter } from './formatter.js';
import { schemaFormatter } from './schema.js';
import { matchMapProjection } from './utils.js';
export function* recordSchemaFormatter(schema, rawValue, { attributes, valuePath, ...restOptions } = {}) {
const { format = true, transform = true, partial = false } = restOptions;
if (!isObject(rawValue)) {
const { type } = schema;
const path = valuePath !== undefined ? formatArrayPath(valuePath) : undefined;
throw new DynamoDBToolboxError('formatter.invalidAttribute', {
message: `Invalid attribute detected while formatting${path !== undefined ? `: '${path}'` : ''}. Should be a ${type}.`,
path,
payload: { received: rawValue, expected: type }
});
}
const formatters = [];
const missingEnumKeys = new Set(schema.keys.props.enum);
for (const [key, element] of Object.entries(rawValue)) {
if (element === undefined) {
continue;
}
// NOTE: If transform is true, `key` is the transformed value which is what we want
// If not, `key` should already be formatted, which is what we also want
const elmtValuePath = [...(valuePath !== null && valuePath !== void 0 ? valuePath : []), key];
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const formattedKey = new Formatter(schema.keys).format(key, {
transform,
valuePath: elmtValuePath
});
missingEnumKeys.delete(formattedKey);
const { isProjected, childrenAttributes } = matchMapProjection(formattedKey, attributes);
if (!isProjected) {
continue;
}
formatters.push([
formattedKey,
schemaFormatter(schema.elements, element, {
attributes: childrenAttributes,
valuePath: elmtValuePath,
...restOptions
})
]);
}
if (!schema.props.partial && !partial) {
for (const missingKey of missingEnumKeys) {
const { isProjected, childrenAttributes } = matchMapProjection(missingKey, attributes);
if (!isProjected) {
continue;
}
const elmtValuePath = transform && schema.keys.props.transform !== undefined
? [
...(valuePath !== null && valuePath !== void 0 ? valuePath : []),
schema.keys.props.transform.encode(missingKey)
]
: [...(valuePath !== null && valuePath !== void 0 ? valuePath : []), missingKey];
formatters.push([
missingKey,
schemaFormatter(schema.elements, undefined, {
attributes: childrenAttributes,
valuePath: elmtValuePath,
...restOptions
})
]);
}
}
if (transform) {
const transformedValue = Object.fromEntries(formatters
.map(([key, formatter]) => [key, formatter.next().value])
.filter(([, element]) => element !== undefined));
if (format) {
yield transformedValue;
}
else {
return transformedValue;
}
}
const formattedValue = Object.fromEntries(formatters
.map(([key, formatter]) => [key, formatter.next().value])
.filter(([, element]) => element !== undefined));
return formattedValue;
}