UNPKG

@nerdware/ddb-single-table

Version:

A schema-based DynamoDB modeling tool, high-level API, and type-generator built to supercharge single-table designs!⚡

113 lines (112 loc) 5.58 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ModelSchema = void 0; const ts_type_safety_utils_1 = require("@nerdware/ts-type-safety-utils"); const errors_js_1 = require("../utils/errors.js"); const BaseSchema_js_1 = require("./BaseSchema.js"); const timestampAttributes_js_1 = require("./timestampAttributes.js"); /** * This class and its `BaseSchema` parent currently only serve to organize schema-related types, * validation methods, etc., but may be used to create schema instances in the future. This is * currently not the case, as schema attributes would need to be nested under an instance property * (e.g. `this.attributes`), which would require a lot of refactoring. If/when this is implemented, * schema instances would also be given "metadata" props like "name", "version", "schemaType", etc. */ class ModelSchema extends BaseSchema_js_1.BaseSchema { static DEFAULT_OPTIONS = { allowUnknownAttributes: false, autoAddTimestamps: false, }; static TIMESTAMP_ATTRIBUTES = timestampAttributes_js_1.TIMESTAMP_ATTRIBUTES; /** * This function validates the provided `modelSchema`, and if valid, returns an * object specifying the Model's alias maps: * - `attributesToAliasesMap` * - `aliasesToAttributesMap` * * This function performs the following validation checks: * * 1. Ensure ModelSchema does not specify key-attribute configs which are only valid in the * TableKeysSchema (e.g. "isHashKey", "isRangeKey", "index") * 2. Ensure all "alias" values are unique * * @param modelSchema - The schema to validate. * @param name - A name to identify the schema in any error messages. * @returns An object specifying the Model's alias maps. * @throws `SchemaValidationError` if the provided ModelSchema is invalid. */ static validate = (modelSchema, { name: schemaName }) => { // First run the base Schema validation checks: BaseSchema_js_1.BaseSchema.validateAttributeTypes(modelSchema, { schemaType: "ModelSchema", name: schemaName, }); // Then run the ModelSchema-specific validation checks: const attributesToAliasesMap = {}; const aliasesToAttributesMap = {}; for (const attrName in modelSchema) { const { alias, ...attrConfigs } = modelSchema[attrName]; // Ensure ModelSchema doesn't include key/index configs which are only valid in the TableKeysSchema ["isHashKey", "isRangeKey", "index"].forEach((keyConfigProperty) => { if ((0, ts_type_safety_utils_1.hasKey)(attrConfigs, keyConfigProperty)) { throw new errors_js_1.SchemaValidationError({ schemaName, problem: `attribute "${attrName}" includes an "${keyConfigProperty}" config, which is only valid in the TableKeysSchema`, }); } }); // If an "alias" is specified, ensure it's unique, and add it to the alias maps if (alias) { // If alias already exists in accum, there's a dupe alias in the schema, throw error if (alias in aliasesToAttributesMap) { throw new errors_js_1.SchemaValidationError({ schemaName, problem: `the ModelSchema contains duplicate alias "${alias}"`, }); } // Add attrName/alias to the alias maps attributesToAliasesMap[attrName] = alias; aliasesToAttributesMap[alias] = attrName; } } return { attributesToAliasesMap, aliasesToAttributesMap, }; }; /** * This function provides sorted ModelSchema entries for IO-Actions. After passing the provided * `modelSchema` into Object.entries, the resulting entries array is sorted as follows: * * 1. The `tableHashKey` is sorted to the front. * 2. The `tableRangeKey`, if present, goes after the `tableHashKey`. * 3. Index PKs, if any, go after the `tableRangeKey`. * 4. For all other attributes, the order in the provided `modelSchema` is preserved. * * @param modelSchema - The ModelSchema object to use to obtain sorted entries. * @returns An array of sorted ModelSchema entries. */ static getSortedSchemaEntries = (modelSchema, { tableHashKey, tableRangeKey, indexes = {} }) => { // Create a map of index PKs for quick lookup const indexPKs = {}; for (const index of Object.values(indexes)) { indexPKs[index.indexPK] = true; } return Object.entries(modelSchema).sort(([attrNameA], [attrNameB]) => { return attrNameA === tableHashKey // Sort tableHashKey to the front ? -1 : attrNameB === tableHashKey ? 1 : attrNameA === tableRangeKey // tableRangeKey goes after tableHashKey ? -1 : attrNameB === tableRangeKey ? 1 : attrNameA in indexPKs // index PKs, if any, go after tableRangeKey ? -1 : attrNameB in indexPKs ? 1 : 0; // For all other attributes the order is unchanged }); }; } exports.ModelSchema = ModelSchema;