UNPKG

lemon-core

Version:
212 lines 8.37 kB
"use strict"; // origin from: https://github.com/baseprime/dynamodb @20191106 // Copyright (c) 2016 Ryan Fitzgerald /** * `expressions.ts` * - expressions * * * @author Steve Jung <steve@lemoncloud.io> * @date 2019-11-20 refactoring to ts via origin * * @copyright (C) lemoncloud.io 2019 - All Rights Reserved. */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.buildFilterExpression = exports.stringify = exports.serializeUpdateExpression = exports.parse = void 0; const lodash_1 = __importDefault(require("lodash")); const utils = __importStar(require("./utils")); const serializer_1 = __importDefault(require("./serializer")); const internals = {}; internals.actionWords = ['SET', 'ADD', 'REMOVE', 'DELETE']; internals.regexMap = lodash_1.default.reduce(internals.actionWords, function (result, key) { result[key] = new RegExp(key + '\\s*(.+?)\\s*(SET|ADD|REMOVE|DELETE|$)'); return result; }, {}); // explanation http://stackoverflow.com/questions/3428618/regex-to-find-commas-that-arent-inside-and internals.splitOperandsRegex = new RegExp(/\s*(?![^(]*\)),\s*/); internals.match = function (actionWord, str) { const match = internals.regexMap[actionWord].exec(str); if (match && match.length >= 2) { return match[1].split(internals.splitOperandsRegex); } else { return null; } }; const parse = function (str) { return lodash_1.default.reduce(internals.actionWords, function (result, actionWord) { result[actionWord] = internals.match(actionWord, str); return result; }, {}); }; exports.parse = parse; const serializeUpdateExpression = function (schema, item) { const datatypes = schema._modelDatatypes; const data = utils.omitPrimaryKeys(schema, item); const memo = { expressions: {}, attributeNames: {}, values: {}, }; memo.expressions = lodash_1.default.reduce(internals.actionWords, function (result, key) { result[key] = []; return result; }, {}); const result = lodash_1.default.reduce(data, function (result, value, key) { const valueKey = ':' + key; const nameKey = '#' + key; if (lodash_1.default.isNull(value) || (lodash_1.default.isString(value) && lodash_1.default.isEmpty(value))) { result.expressions.REMOVE.push(nameKey); result.attributeNames[nameKey] = key; } else if (lodash_1.default.isPlainObject(value) && value.$add) { result.expressions.ADD.push(nameKey + ' ' + valueKey); result.values[valueKey] = serializer_1.default.serializeAttribute(value.$add, datatypes[key]); result.attributeNames[nameKey] = key; } else if (lodash_1.default.isPlainObject(value) && value.$del) { result.expressions.DELETE.push(nameKey + ' ' + valueKey); result.values[valueKey] = serializer_1.default.serializeAttribute(value.$del, datatypes[key]); result.attributeNames[nameKey] = key; } else { result.expressions.SET.push(nameKey + ' = ' + valueKey); result.values[valueKey] = serializer_1.default.serializeAttribute(value, datatypes[key]); result.attributeNames[nameKey] = key; } return result; }, memo); return result; }; exports.serializeUpdateExpression = serializeUpdateExpression; const stringify = function (expressions) { return lodash_1.default.reduce(expressions, function (result, value, key) { if (!lodash_1.default.isEmpty(value)) { if (lodash_1.default.isArray(value)) { result.push(key + ' ' + value.join(', ')); } else { result.push(key + ' ' + value); } } return result; }, []).join(' '); }; exports.stringify = stringify; internals.formatAttributeValue = function (val) { if (lodash_1.default.isDate(val)) { return val.toISOString(); } return val; }; internals.isFunctionOperator = function (operator) { return lodash_1.default.includes([ 'attribute_exists', 'attribute_not_exists', 'attribute_type', 'begins_with', 'contains', 'NOT contains', 'size', ], operator); }; internals.uniqAttributeValueName = function (key, existingValueNames) { let potentialName = ':' + key; let idx = 1; while (lodash_1.default.includes(existingValueNames, potentialName)) { idx++; potentialName = ':' + key + '_' + idx; } return potentialName; }; const buildFilterExpression = function (key, operator, existingValueNames, val1, val2) { // IN filter expression is unlike all the others where val1 is an array of values if (operator === 'IN') { return internals.buildInFilterExpression(key, existingValueNames, val1); } let v1 = internals.formatAttributeValue(val1); const v2 = internals.formatAttributeValue(val2); if (operator === 'attribute_exists' && v1 === false) { operator = 'attribute_not_exists'; v1 = null; } else if (operator === 'attribute_exists' && v1 === true) { v1 = null; } const path = '#' + key; const v1ValueName = internals.uniqAttributeValueName(key, existingValueNames); const v2ValueName = internals.uniqAttributeValueName(key, [v1ValueName].concat(existingValueNames)); let statement = ''; if (internals.isFunctionOperator(operator)) { if (!lodash_1.default.isNull(v1) && !lodash_1.default.isUndefined(v1)) { statement = operator + '(' + path + ', ' + v1ValueName + ')'; } else { statement = operator + '(' + path + ')'; } } else if (operator === 'BETWEEN') { statement = path + ' BETWEEN ' + v1ValueName + ' AND ' + v2ValueName; } else { statement = [path, operator, v1ValueName].join(' '); } const attributeValues = {}; if (!lodash_1.default.isNull(v1) && !lodash_1.default.isUndefined(v1)) { attributeValues[v1ValueName] = v1; } if (!lodash_1.default.isNull(v2) && !lodash_1.default.isUndefined(v2)) { attributeValues[v2ValueName] = v2; } const attributeNames = {}; attributeNames[path] = key; return { attributeNames: attributeNames, statement: statement, attributeValues: attributeValues, }; }; exports.buildFilterExpression = buildFilterExpression; internals.buildInFilterExpression = function (key, existingValueNames, values) { const path = '#' + key; const attributeNames = {}; attributeNames[path] = key; const attributeValues = lodash_1.default.reduce(values, function (result, val) { const existing = lodash_1.default.keys(result).concat(existingValueNames); const p = internals.uniqAttributeValueName(key, existing); result[p] = internals.formatAttributeValue(val); return result; }, {}); return { attributeNames: attributeNames, statement: path + ' IN (' + lodash_1.default.keys(attributeValues) + ')', attributeValues: attributeValues, }; }; //# sourceMappingURL=expressions.js.map