UNPKG

dynamodb-toolbox

Version:

A simple set of tools for working with Amazon DynamoDB and the DocumentClient.

148 lines (147 loc) 7.27 kB
"use strict"; /** * DynamoDB Toolbox: A simple set of tools for working with Amazon DynamoDB * @author Jeremy Daly <jeremy@jeremydaly.com> * @license MIT */ Object.defineProperty(exports, "__esModule", { value: true }); const utils_js_1 = require("./utils.js"); // Parse and validate mapping config exports.default = (field, config, track) => { // Validate props Object.keys(config).forEach(prop => { switch (prop) { case 'type': case 'default': break; case 'dependsOn': if (typeof config[prop] !== 'string' && !Array.isArray(config[prop])) (0, utils_js_1.error)(`'dependsOn' must be the string name of an attribute or alias`); break; case 'transform': if (typeof config[prop] !== 'function') (0, utils_js_1.error)(`'${prop}' must be a function`); break; case 'format': if (typeof config[prop] !== 'function') (0, utils_js_1.error)(`'${prop}' must be a function`); break; case 'coerce': case 'onUpdate': case 'hidden': case 'save': if (typeof config[prop] !== 'boolean') (0, utils_js_1.error)(`'${prop}' must be a boolean`); break; case 'required': if (typeof config[prop] !== 'boolean' && config[prop] !== 'always') (0, utils_js_1.error)(`'required' must be a boolean or set to 'always'`); break; case 'alias': case 'map': if (typeof config[prop] !== 'string' || // check for alias uniqueness (field !== config[prop] && track.fields.includes((config[prop] || '').trim())) || (config[prop] || '').trim().length === 0) (0, utils_js_1.error)(`'${prop}' must be a unique string`); break; case 'setType': if (config.type !== 'set') (0, utils_js_1.error)(`'setType' is only valid for type 'set'`); if (!['string', 'number', 'bigint', 'binary'].includes(config[prop] || '')) (0, utils_js_1.error)(`Invalid 'setType', must be 'string', 'number', 'bigint', or 'binary'`); break; case 'delimiter': if (typeof config[prop] !== 'string' || (config[prop] || '').trim().length === 0) (0, utils_js_1.error)(`'delimiter' must be a 'string'`); config[prop] = (config[prop] || '').trim(); break; case 'prefix': case 'suffix': if (config.type && config.type !== 'string') (0, utils_js_1.error)(`'${prop}' can only be used on 'string' types`); if (typeof config[prop] !== 'string' || (config[prop] || '').trim().length === 0) (0, utils_js_1.error)(`'${prop}' must be a 'string'`); break; case 'partitionKey': case 'sortKey': if (config.map || config.alias) (0, utils_js_1.error)(`Attributes with a ${prop} cannot have a 'map' or 'alias' associated`); if (typeof config[prop] === 'boolean' || typeof config[prop] === 'string' || Array.isArray(config[prop])) { // Coerce/cast to an array of strings/booleans const indexes = (Array.isArray(config[prop]) ? config[prop] : [config[prop]]); // Loop through values and track keys for (const i in indexes) { // If a boolean, set primary pk/sk if (typeof indexes[i] === 'boolean') { // Check that another prop isn't already a key if (track.keys[prop]) (0, utils_js_1.error)(`'${track.keys[prop]}' has already been declared as the ${prop}`); // If true, add the field as the key if (indexes[i]) track.keys[prop] = field; // If the partionKey is the same as the sortKey, throw an error if (track.keys.partitionKey && track.keys.partitionKey === track.keys.sortKey) (0, utils_js_1.error)(`'${field}' attribute cannot be both the partitionKey and sortKey`); // If string, set index pk/sk } else if (typeof indexes[i] === 'string') { const index = indexes[i]; // If the index isn't being tracked yet, add it if (!track.keys[index]) track.keys[index] = {}; // If the index's pk/sk already exist if (track.keys[index][prop]) { (0, utils_js_1.error)(`'${track.keys[index][prop]}' has already been declared as the ${prop} for the ${index} index`); } track.keys[index][prop] = field; if (track.keys[index].partitionKey === track.keys[index].sortKey) (0, utils_js_1.error)(`'${field}' attribute cannot be both the partitionKey and sortKey for the ${index} index`); } else { (0, utils_js_1.error)(`Index assignments for '${field}' must be string or boolean values`); } } } else { (0, utils_js_1.error)(`'${prop}' must be a boolean, string, or array`); } break; default: (0, utils_js_1.error)(`'${prop}' is not a valid property type`); } }); // Error on alias and map if (config.alias && config.map) (0, utils_js_1.error)(`'${field}' cannot contain both an alias and a map`); // Default the type if (!config.type) config.type = 'string'; // Default coerce based on type if (['string', 'boolean', 'number', 'bigint'].includes(config.type) && typeof config.coerce === 'undefined') config.coerce = true; // Set defaults if (config.default !== undefined) track.defaults[field] = config.default; // Track required settings if (config.required === true) track.required[config.map || field] = false; if (config.required === 'always') track.required[config.map || field] = true; // Destructure the config to pull out map and alias const { map, alias, ..._config } = config; // Return the original config return Object.assign({ [field]: config }, alias ? { [alias]: Object.assign({}, _config, { map: field }) } : {}, map ? { [map]: Object.assign({}, _config, { alias: field }) } : {}); };