lemon-core
Version:
Lemon Serverless Micro-Service Platform
166 lines • 7.76 kB
JavaScript
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
;