UNPKG

mock-table-data

Version:

`mock-table-data`는 JavaScript/TypeScript 환경에서 테이블 형태의 데이터를 조건, 정렬, 페이징 기반으로 필터링하거나 가공할 수 있는 유틸리티 클래스입니다. 테스트용 또는 실제 클라이언트 필터링 용도로 사용할 수 있습니다.

147 lines (146 loc) 5.65 kB
"use strict"; 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;