mock-table-data
Version:
`mock-table-data`는 JavaScript/TypeScript 환경에서 테이블 형태의 데이터를 조건, 정렬, 페이징 기반으로 필터링하거나 가공할 수 있는 유틸리티 클래스입니다. 테스트용 또는 실제 클라이언트 필터링 용도로 사용할 수 있습니다.
147 lines (146 loc) • 5.65 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
const fp_1 = require("lodash/fp");
class TableData {
_dataSource;
_primaryKey;
dataProcessing;
constructor(dataSource, tableOptions = {}) {
this._dataSource = dataSource;
this._primaryKey = tableOptions.primaryKey;
this.dataProcessing = tableOptions.dataProcessing;
}
static getSortOption(sort) {
if (typeof sort === 'string')
return [sort];
if (Array.isArray(sort))
return sort;
return undefined;
}
static validateConditionItem(item) {
const key = Object.keys(item).find((k) => !['type', 'required', 'like'].includes(k));
if (!key)
throw new Error('Invalid condition item: no key provided');
const value = item[key];
const { required, type } = item;
if (required && (value === undefined || value === null || value === '')) {
throw new Error(`Missing required field: ${key}`);
}
if (value !== undefined && value !== null && type) {
const typeCheck = {
string: (v) => typeof v === 'string',
number: (v) => typeof v === 'number' || !isNaN(parseFloat(v)),
boolean: (v) => typeof v === 'boolean' || v === 'true' || v === 'false',
}[type];
if (typeCheck && !typeCheck(value)) {
throw new Error(`Type mismatch for key '${key}': expected ${type}, got ${typeof value}`);
}
}
}
evaluateCondition(row, node) {
if ('conditions' in node) {
const logic = node.logic ?? 'AND';
const results = node.conditions.map((child) => this.evaluateCondition(row, child));
return logic === 'AND' ? results.every(Boolean) : results.some(Boolean);
}
TableData.validateConditionItem(node);
const key = Object.keys(node).find((k) => !['type', 'required', 'like'].includes(k));
if (!key)
return false;
const value = node[key];
if (value === undefined || value === '')
return true;
const rowValue = (0, fp_1.get)(key, row);
const like = node.like === true;
if (typeof value === 'string') {
const cmp = (rowValue ?? '').toString().toUpperCase();
const target = value.toUpperCase();
return like ? (0, fp_1.includes)(target, cmp) : cmp === target;
}
return (0, fp_1.eq)(value, rowValue);
}
get dataSource() {
return this._dataSource;
}
sortedList(rows, sorts) {
const sortKeys = [];
const sortOrders = [];
for (const s of sorts) {
const [key, order] = s.split(':');
sortKeys.push(key);
sortOrders.push(order === 'desc' ? 'desc' : 'asc');
}
return (0, fp_1.orderBy)(sortKeys, sortOrders, rows);
}
filteredList(conditions) {
const conditionTree = Array.isArray(conditions)
? { logic: 'AND', conditions: conditions }
: conditions;
return (0, fp_1.filter)((row) => this.evaluateCondition(row, conditionTree), this._dataSource);
}
getRows(limit, offset, conditions, sorts, meta) {
const nLimit = parseInt(limit, 10);
const nOffset = offset ? parseInt(offset, 10) : 0;
if (!this._dataSource || !this._dataSource.length || nLimit === 0) {
if (!meta)
return [];
return {
result: [],
meta: {
totalCount: 0,
currentCount: 0,
limit: nLimit,
offset: nOffset,
},
};
}
let result = this._dataSource;
if (conditions)
result = this.filteredList(conditions);
const totalCount = result.length;
if (sorts)
result = this.sortedList(result, sorts);
result = result.slice(nOffset, limit ? nOffset + nLimit : undefined);
if (!meta)
return result;
if (this.dataProcessing)
result = this.dataProcessing(result);
return {
result: [...result],
meta: {
totalCount,
currentCount: result.length,
limit: nLimit,
offset: nOffset,
},
};
}
selectRow(conditions) {
const tree = Array.isArray(conditions) ? { logic: 'AND', conditions: conditions } : conditions;
return this._dataSource.find((row) => this.evaluateCondition(row, tree));
}
insertRow(item) {
if (this._primaryKey && this._dataSource.find((row) => row[this._primaryKey] === item[this._primaryKey])) {
throw new Error('primary key duplicate error');
}
this._dataSource.push(item);
return item;
}
updateRow(conditions, newItem) {
const index = this._dataSource.findIndex((row) => this.evaluateCondition(row, Array.isArray(conditions) ? { logic: 'AND', conditions: conditions } : conditions));
if (index === -1)
throw new Error('not found condition');
if (newItem)
this._dataSource.splice(index, 1, newItem);
else
this._dataSource.splice(index, 1);
return true;
}
deleteRow(conditions) {
return this.updateRow(conditions);
}
selectRows(limit, offset, conditions = [], sort, meta) {
return this.getRows(limit, offset, conditions, TableData.getSortOption(sort), meta);
}
}
exports.default = TableData;
;