utils_dataset_remove-rows-by-condition.js
/**
* @typedef RemoveRowsByCondtionOptions
* @property {boolean} [mutate=false] 원본을 직접 수정할지 여부 (true면 수정)
* @property {boolean} [skipEvent=false] 이벤트 활성화 여부, 속도 문제로 기본 값인 false 유지 권장
*/
/**
* 데이터 저장용 훅
*
* @callback HCmbSmrTypeRowConditionUseMemoHook
* @param {function(): T} func
* @param {any[]} deps
* 의존성 키 배열
* 데이터를 반환하는 함수
* @template T
* @example
* useMemo(() => {
* return "data";
* }, []);
*
*/
/**
* @callback RemoveRowsByCondtionFunc
* @param {RemoveRowByConditionFuncContext} context
* 참조 함수 및 변수
* @returns {boolean}
* true 일 시 삭제
*/
/**
* @callback FilterRowsByCondtionFunc
* @param {RemoveRowByConditionFuncContext} context
* 참조 함수 및 변수
* @returns {boolean}
* true 값인 행만 남음
*/
/**
* @typedef RemoveRowByConditionFuncContext
* @property {nexacro.Dataset} dataset
* 대상 데이터셋
* @property {number} row
* 행
* @property {Object} rowData
* 컬럼 데이터
* @property {HCmbSmrTypeRowConditionUseMemoHook} useMemo
* 데이터 기억용
*/
/**
* 인수로 받은 데이터셋에서 조건을 검사하여 행을 삭제
*
* @function removeRowsByCondition
* @param {nexacro.Dataset} dataset
* 대상 데이터셋
* @param {RemoveRowsByCondtionFunc} condition
* 검사 조건
* @param {RemoveRowsByCondtionOptions} [options]
* @returns {nexacro.Dataset | null}
* 행 삭제 한 데이터셋
* @example
* $f.removeRowsByCondition(this.ds_main, (context) => {
* return context.row % 2;
* });
*
* @memberOf $f
*/
export function removeRowsByCondition(dataset, condition, options) {
const isMutate = options?.mutate ?? false;
const isSkipEvent = options?.skipEvent ?? true;
const ds = isMutate ? dataset : $ds.clone(dataset);
const previousDeps = [];
const memoData = [];
let initialHookCallIdx = -1;
if (!(ds instanceof nexacro.Dataset)) {
return null;
}
if (typeof condition !== "function") {
return ds;
}
const defaultEnableEvent = ds.enableevent;
if (isSkipEvent) {
ds.enableevent = false;
}
for (let i = ds.rowcount - 1; i >= 0; i--) {
let hookCallIdx = -1;
/**
* @type {HCmbSmrTypeRowConditionUseMemoHook}
*/
const useMemo = function (func, deps) {
hookCallIdx++;
if (initialHookCallIdx !== -1 && initialHookCallIdx > hookCallIdx) {
throw new HookOrderMismatchError();
}
let isChanged =
!previousDeps[hookCallIdx] ||
deps.length !== previousDeps[hookCallIdx].length ||
deps.some((dep, i) => dep !== previousDeps[hookCallIdx][i]);
if (isChanged) {
memoData[hookCallIdx] = func();
previousDeps[hookCallIdx] = deps;
}
return memoData[hookCallIdx];
};
if (
condition({
dataset: ds,
row: i,
rowData: $ds.getRowData(ds, i),
useMemo,
})
) {
ds.deleteRow(i);
}
if (initialHookCallIdx !== -1) {
initialHookCallIdx = hookCallIdx;
}
if (initialHookCallIdx !== -1 && initialHookCallIdx < hookCallIdx) {
throw new HookOrderMismatchError();
}
}
if (isSkipEvent) {
ds.enableevent = defaultEnableEvent;
}
return ds;
}
/**
* 인수로 받은 데이터셋에서 조건을 검사하여 통과한 행만 남김
*
* @function filterRowsByCondition
* @param {nexacro.Dataset} dataset
* 대상 데이터셋
* @param {RemoveRowsByCondtionFunc} condition
* 검사 조건
* @param {RemoveRowsByCondtionOptions} [options]
* @returns {nexacro.Dataset | null}
* 행 삭제 한 데이터셋
* @example
* $f.filterRowsByCondition(this.ds_main, (context) => {
* return context.row % 2;
* });
*
* @memberOf $f
*/
export function filterRowsByCondition(dataset, condition, options) {
return removeRowsByCondition(
dataset,
typeof condition === "function" ? (e) => !condition(e) : null,
options,
);
}
export class HookOrderMismatchError extends Error {
constructor() {
super("호출 순서가 일치 하지 않습니다. 제어문에서 사용 불가합니다.");
}
}