UNPKG

dynamodb-toolbox

Version:

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

127 lines (126 loc) 5.24 kB
"use strict"; /** * DynamoDB Toolbox: A simple set of tools for working with Amazon DynamoDB * @author Jeremy Daly <jeremy@jeremydaly.com> * @license MIT */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const validateTypes_js_1 = __importDefault(require("./validateTypes.js")); const utils_js_1 = require("./utils.js"); // Normalize Data exports.default = () => (schema, linked, data, filter = false, throwOnMissingNonPartitionRequiredProperties = true) => { // Intialize validate type const validateType = (0, validateTypes_js_1.default)(); // Build and execute defaults dependency graph const dependsOn = (map, attr) => { // If the default depends on other attributes if (schema[attr].dependsOn) { (Array.isArray(schema[attr].dependsOn) ? schema[attr].dependsOn : [schema[attr].dependsOn]).forEach((dependent) => { // If the dependent is a valid attribute or alias if (schema[dependent]) { // If the dependent is a function if (typeof map[dependent] === 'function') { // Resolve the dependency graph map = dependsOn(map, dependent); } if (typeof map[dependent] === 'undefined') { throw new DependsOnUndefined(`'${dependent}' is undefined, bailing`); } } else { (0, utils_js_1.error)(`'${dependent}' is not a valid attribute or alias name`); } }); map[attr] = map[attr](map); return map; } else { try { map[attr] = map[attr](map); if (schema[attr].alias) map[schema[attr].alias] = map[attr]; if (schema[attr].map) map[schema[attr].map] = map[attr]; } catch (e) { // noop } return map; } }; // Generate normalized data object const dataMap = Object.keys(data).reduce((acc, field) => { // Return a map with normalized data and alias references return Object.assign(acc, schema[field] ? { data: { ...acc.data, [schema[field].map || field]: data[field] }, aliases: { ...acc.aliases, [schema[field].alias || field]: data[field] } } : filter ? {} // this will filter out non-mapped fields : field === '$remove' ? { data: { ...acc.data, $remove: data[field] } } // support for removes : (0, utils_js_1.error)(`Field '${field}' does not have a mapping or alias`)); }, { data: {}, aliases: {} }); // Create a combined data object for defaults let defaultMap = { ...dataMap.data, ...dataMap.aliases }; const defaults = Object.keys(defaultMap).reduce((acc, attr) => { // If a function, resolve the dependency graph if (typeof defaultMap[attr] === 'function') { try { const map = dependsOn(defaultMap, attr); defaultMap = map; } catch (e) { if (throwOnMissingNonPartitionRequiredProperties && e instanceof DependsOnUndefined && (schema[attr].partitionKey === true || schema[attr].sortKey === true || schema[attr].required)) { throw new Error(`Required field '${attr}' depends on attribute(s), one or more of which can't be resolved (${schema[attr].dependsOn})`); } delete defaultMap[attr]; } } return Object.assign(acc, { [attr]: defaultMap[attr] }); }, {}); // Generate final data and evaluate function expressions const _data = Object.keys(dataMap.data).reduce((acc, field) => { return Object.assign(acc, { [field]: defaults[field] }); }, {}); // Process linked const composites = Object.keys(linked).reduce((acc, attr) => { // Convert field to mapped field const field = (schema[attr] && schema[attr].map) || attr; if (_data[field] !== undefined) return acc; // if value exists, let override const values = linked[attr] .map((f) => { if (_data[f] === undefined) { return null; } return (0, utils_js_1.transformAttr)(schema[f], validateType(schema[f], f, _data[f]), _data); }) .filter((x) => x !== null); if (values.length === linked[attr].length) { return Object.assign(acc, { [field]: values.join(schema[attr].delimiter || '#') }); } else { return acc; } }, {}); // Return the merged data return Object.assign(composites, _data); }; class DependsOnUndefined extends Error { constructor(message) { super(message); } }