dynamodb-toolbox
Version:
A simple set of tools for working with Amazon DynamoDB and the DocumentClient.
148 lines (147 loc) • 7.27 kB
JavaScript
;
/**
* 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 })
}
: {});
};