UNPKG

dynamodb-toolbox

Version:

Lightweight and type-safe query builder for DynamoDB and TypeScript.

166 lines (165 loc) 7.63 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AnyOfSchema = void 0; const index_js_1 = require("../../errors/index.js"); const isArray_js_1 = require("../../utils/validation/isArray.js"); const checkSchemaProps_js_1 = require("../utils/checkSchemaProps.js"); const hasDefinedDefault_js_1 = require("../utils/hasDefinedDefault.js"); const constants_js_1 = require("./constants.js"); class AnyOfSchema { constructor(elements, props) { this.type = 'anyOf'; this.elements = elements; this.props = props; this[constants_js_1.$discriminators_] = { [constants_js_1.$computed]: false }; this[constants_js_1.$discriminations_] = { [constants_js_1.$computed]: false }; } get checked() { return Object.isFrozen(this.props); } check(path) { if (this.checked) { return; } (0, checkSchemaProps_js_1.checkSchemaProps)(this.props, path); if (!(0, isArray_js_1.isArray)(this.elements)) { throw new index_js_1.DynamoDBToolboxError('schema.anyOf.invalidElements', { message: `Invalid anyOf elements${path !== undefined ? ` at path '${path}'` : ''}: AnyOf elements must be an array.`, path }); } if (this.elements.length === 0) { throw new index_js_1.DynamoDBToolboxError('schema.anyOf.missingElements', { message: `Invalid anyOf elements${path !== undefined ? ` at path '${path}'` : ''}: AnyOf attributes must have at least one element.`, path }); } for (const element of this.elements) { const { required, hidden, savedAs } = element.props; if (required !== undefined && required !== 'atLeastOnce' && required !== 'always') { throw new index_js_1.DynamoDBToolboxError('schema.anyOf.optionalElements', { message: `Invalid anyOf elements${path !== undefined ? ` at path '${path}'` : ''}: AnyOf elements must be required.`, path }); } if (hidden !== undefined && hidden !== false) { throw new index_js_1.DynamoDBToolboxError('schema.anyOf.hiddenElements', { message: `Invalid anyOf elements${path !== undefined ? ` at path '${path}'` : ''}: AnyOf elements cannot be hidden.`, path }); } if (savedAs !== undefined) { throw new index_js_1.DynamoDBToolboxError('schema.anyOf.savedAsElements', { message: `Invalid anyOf elements${path !== undefined ? ` at path '${path}'` : ''}: AnyOf elements cannot be renamed (have savedAs prop).`, path }); } if ((0, hasDefinedDefault_js_1.hasDefinedDefault)(element)) { throw new index_js_1.DynamoDBToolboxError('schema.anyOf.defaultedElements', { message: `Invalid anyOf elements${path !== undefined ? ` at path '${path}'` : ''}: AnyOf elements cannot have default or linked values.`, path }); } } const { discriminator } = this.props; if (discriminator !== undefined) { if (!(discriminator in this[constants_js_1.$discriminators])) { throw new index_js_1.DynamoDBToolboxError('schema.anyOf.invalidDiscriminator', { message: `Invalid discriminator${path !== undefined ? ` at path '${path}'` : ''}: All elements must be map or anyOf schemas and discriminator must be the key of a string enum schema.`, path, payload: { discriminator } }); } } this.elements.forEach((element, index) => { element.check(`${path !== null && path !== void 0 ? path : ''}[${index}]`); }); Object.freeze(this.props); Object.freeze(this.elements); } get [constants_js_1.$discriminators]() { var _a; if (!this[constants_js_1.$discriminators_][constants_js_1.$computed]) { Object.assign(this[constants_js_1.$discriminators_], (_a = this.elements.map(getDiscriminators).reduce(intersectDiscriminators, undefined)) !== null && _a !== void 0 ? _a : {}, { [constants_js_1.$computed]: true }); } return this[constants_js_1.$discriminators_]; } match(value) { if (!this[constants_js_1.$discriminations_][constants_js_1.$computed]) { const { discriminator } = this.props; if (discriminator === undefined) { return undefined; } for (const elementSchema of this.elements) { Object.assign(this[constants_js_1.$discriminations_], getDiscriminations(elementSchema, discriminator)); } Object.assign(this[constants_js_1.$discriminations_], { [constants_js_1.$computed]: true }); } return this[constants_js_1.$discriminations_][value]; } } exports.AnyOfSchema = AnyOfSchema; const getDiscriminators = (schema) => { var _a; switch (schema.type) { case 'anyOf': return schema[constants_js_1.$discriminators]; case 'map': { const discriminators = {}; for (const [attrName, attr] of Object.entries(schema.attributes)) { if (attr.type === 'string' && attr.props.enum !== undefined && (attr.props.required === undefined || attr.props.required !== 'never') && attr.props.transform === undefined) { discriminators[attrName] = (_a = attr.props.savedAs) !== null && _a !== void 0 ? _a : attrName; } } return discriminators; } default: return {}; } }; const intersectDiscriminators = (discriminatorsA, discriminatorsB) => { if (discriminatorsA === undefined) { return discriminatorsB; } if (discriminatorsB === undefined) { return discriminatorsA; } const [smallestDiscr, largestDiscr] = [discriminatorsA, discriminatorsB].sort((discA, discB) => Object.keys(discA).length > Object.keys(discB).length ? 1 : -1); const intersectedDiscriminators = {}; for (const [attrName, attrSavedAs] of Object.entries(smallestDiscr)) { if (attrName in largestDiscr && largestDiscr[attrName] === attrSavedAs) { intersectedDiscriminators[attrName] = attrSavedAs; } } return intersectedDiscriminators; }; const getDiscriminations = (schema, discriminator) => { var _a; switch (schema.type) { case 'anyOf': { let discriminations = {}; for (const elementSchema of schema.elements) { discriminations = { ...discriminations, ...getDiscriminations(elementSchema, discriminator) }; } return discriminations; } case 'map': { const discriminations = {}; const discriminatorAttr = schema.attributes[discriminator]; if ((discriminatorAttr === null || discriminatorAttr === void 0 ? void 0 : discriminatorAttr.type) === 'string') { for (const enumValue of (_a = discriminatorAttr.props.enum) !== null && _a !== void 0 ? _a : []) { discriminations[enumValue] = schema; } } return discriminations; } default: return {}; } };