UNPKG

lemon-core

Version:
166 lines 7.76 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.DynamoScanService = void 0; /** * `dynamo-scan-service.ts` * - common service to scan with filters+sort via dynamo * * * @author Tim Hong <tim@lemoncloud.io> * @date 2020-01-20 initial version * * @copyright (C) 2020 LemonCloud Co Ltd. - All Rights Reserved. */ const engine_1 = require("../../engine/"); const dynamo_service_1 = require("./dynamo-service"); const NS = engine_1.$U.NS('DSCN', 'green'); // NAMESPACE TO BE PRINTED. function isComparisonCondition(c) { return 'comparator' in c; } function isBetweenCondition(c) { return 'from' in c && 'to' in c; } function isExistenceCondition(c) { return 'exists' in c; } function isStringCondition(c) { return 'operator' in c; } /** **************************************************************************************************************** * Service Main ** ****************************************************************************************************************/ const scan_1 = __importDefault(require("../../lib/dynamo/scan")); const serializer_1 = __importDefault(require("../../lib/dynamo/serializer")); /** * class: `DynamoScanService` * - support simple scan like range scan. */ class DynamoScanService { constructor(options) { /** * say hello of identity. */ this.hello = () => `dynamo-scan-service:${this.options.tableName}`; // eslint-disable-next-line prettier/prettier (0, engine_1._inf)(NS, `DynamoScanService(${options.tableName}/${options.idName}${options.sortName ? '/' : ''}${options.sortName || ''})...`); if (!options.tableName) throw new Error('.tableName is required'); if (!options.idName) throw new Error('.idName is required'); this.options = options; } scan(limit, last, filter) { var _a; return __awaiter(this, void 0, void 0, function* () { (0, engine_1._log)(NS, `scan()...`); //! build scan input payload const payload = this.buildPayload(limit, last, filter); (0, engine_1._log)(NS, `> payload =`, engine_1.$U.json(payload)); //! get instance of dynamodoc, and execute query(). const { dynamodoc } = dynamo_service_1.DynamoService.instance(); const res = yield dynamodoc.scan(payload).promise(); (0, engine_1._log)(NS, `> scan.res =`, engine_1.$U.json(Object.assign(Object.assign({}, res), { Items: undefined }))); (res === null || res === void 0 ? void 0 : res.Items) && (0, engine_1._log)(NS, `> scan[0] =`, engine_1.$U.json((_a = res === null || res === void 0 ? void 0 : res.Items) === null || _a === void 0 ? void 0 : _a[0])); const items = res.Items || []; const count = res.Count; const scannedCount = res.ScannedCount; const $lek = res.LastEvaluatedKey || {}; (0, engine_1._log)(NS, `> scan.count =`, count); (0, engine_1._log)(NS, `> scan.items.len =`, items.length); (0, engine_1._log)(NS, `> scan.scannedCount =`, scannedCount); (0, engine_1._log)(NS, `> scan.last =`, $lek); //! return result-set return { list: items, count, last: $lek, }; }); } buildPayload(limit, last, filter) { const { tableName, idName, sortName } = this.options; const scan = new scan_1.default({ schema: { hashKey: idName, rangeKey: sortName }, tableName: () => tableName }, serializer_1.default); // Limit & Last if (limit > 0) scan.limit(limit); if (last) scan.startKey(last[this.options.idName], last[this.options.sortName]); // Filter if (filter) { const expAttrNames = {}; const expAttrValues = {}; const asFilterExpression = (filter) => { const asAttrName = (key) => { const attrNameVar = `#${key}`; expAttrNames[attrNameVar] = key; return attrNameVar; }; const asAttrValue = (key, value) => { const attrValueVar = (function () { for (let i = 0;; i++) { const valueVar = `:${key}${i}`; if (!(valueVar in expAttrValues)) return valueVar; } })(); expAttrValues[attrValueVar] = value; return attrValueVar; }; if (Array.isArray(filter)) { return `(${filter.map(asFilterExpression).join(' AND ')})`; } else if ('or' in filter && Array.isArray(filter.or)) { return `(${filter.or.map(asFilterExpression).join(' OR ')})`; } else if ('not' in filter) { return `NOT ${asFilterExpression(filter.not)}`; } else { const cond = filter; if (isComparisonCondition(cond)) { const [name, value] = [asAttrName(cond.key), asAttrValue(cond.key, cond.value)]; return cond.comparator === '!=' ? `NOT ${name} = ${value}` : `${name} ${cond.comparator} ${value}`; } else if (isBetweenCondition(cond)) { const [name, from, to] = [ asAttrName(cond.key), asAttrValue(cond.key, cond.from), asAttrValue(cond.key, cond.to), ]; return `${name} BETWEEN ${from} AND ${to}`; } else if (isExistenceCondition(cond)) { const name = asAttrName(cond.key); return cond.exists ? `attribute_exists(${name})` : `attribute_not_exists(${name})`; } else if (isStringCondition(cond)) { const [name, value] = [asAttrName(cond.key), asAttrValue(cond.key, cond.value)]; return `${cond.operator}(${name}, ${value})`; } } }; scan.filterExpression(asFilterExpression(filter)); if (Object.keys(expAttrNames).length) scan.expressionAttributeNames(expAttrNames); if (Object.keys(expAttrValues).length) scan.expressionAttributeValues(expAttrValues); } return scan.buildRequest(); } } exports.DynamoScanService = DynamoScanService; //# sourceMappingURL=dynamo-scan-service.js.map