@forzalabs/remora
Version:
A powerful CLI tool for seamless data translation.
101 lines (100 loc) • 4.81 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const Affirm_1 = __importDefault(require("../../core/Affirm"));
class RequestExecutorClass {
constructor() {
/**
* Applies the filters, limit, offset and order on the in-memory-data
*/
this.execute = (data, request) => {
(0, Affirm_1.default)(data, 'Invalid data');
(0, Affirm_1.default)(request, 'Invalid request');
(0, Affirm_1.default)(Array.isArray(data), `Invalid data type: should be an array`);
if (request.filters)
data = this._applyFilters(data, request.filters);
if (request.order)
data = this._applyOrdering(data, request.order);
return data;
};
this._applyFilters = (data, filters) => {
return data.filter((item) => {
return filters.every(filter => this._evaluateFilter(item, filter));
});
};
this._evaluateFilter = (item, filter) => {
const evaluate = (baseItem, baseFilter) => {
const { member, operator, values } = baseFilter;
const value = baseItem[member];
const singleValue = values[0];
switch (operator) {
case 'equals':
return value === singleValue;
case 'notEquals':
return value !== singleValue;
case 'contains':
return typeof value === 'string' && value.includes(singleValue);
case 'notContains':
return typeof value === 'string' && !value.includes(singleValue);
case 'startsWith':
return typeof value === 'string' && value.startsWith(singleValue);
case 'endsWith':
return typeof value === 'string' && value.endsWith(singleValue);
case 'greaterThan':
return typeof value === 'number' && value > Number(singleValue);
case 'greaterThanOrEquals':
return typeof value === 'number' && value >= Number(singleValue);
case 'lessThan':
return typeof value === 'number' && value < Number(singleValue);
case 'lessThanOrEquals':
return typeof value === 'number' && value <= Number(singleValue);
case 'in':
return values.includes(value);
case 'notIn':
return !values.includes(value);
case 'between':
return values.length === 2 && value >= values[0] && value <= values[1];
case 'notBetween':
return values.length === 2 && (value < values[0] || value > values[1]);
case 'isNull':
return value === null || value === undefined;
case 'isNotNull':
return value !== null && value !== undefined;
case 'true':
return value === true;
case 'false':
return value === false;
case 'matches':
return typeof value === 'string' && new RegExp(singleValue).test(value);
case 'notMatches':
return typeof value === 'string' && !new RegExp(singleValue).test(value);
default:
throw new Error(`Unsupported filter operator: ${operator}`);
}
};
const { and, or } = filter;
const baseResult = evaluate(item, filter);
if (and)
return baseResult && and.every(subFilter => this._evaluateFilter(item, subFilter));
if (or)
return baseResult || or.some(subFilter => this._evaluateFilter(item, subFilter));
else
return baseResult;
};
this._applyOrdering = (data, order) => {
return data.sort((a, b) => {
for (const [field, direction] of order) {
if (a[field] < b[field])
return direction === 'asc' ? -1 : 1;
if (a[field] > b[field])
return direction === 'asc' ? 1 : -1;
}
return 0;
});
};
}
}
const RequestExecutor = new RequestExecutorClass();
exports.default = RequestExecutor;