kokotable 0.95.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +320 -0
- package/contract/table-request.schema.json +424 -0
- package/dist/core/src/adapters/sources.d.ts +59 -0
- package/dist/core/src/adapters/sources.js +235 -0
- package/dist/core/src/client/aggregate.d.ts +94 -0
- package/dist/core/src/client/aggregate.js +222 -0
- package/dist/core/src/client/groupRows.d.ts +40 -0
- package/dist/core/src/client/groupRows.js +145 -0
- package/dist/core/src/client/runClientQuery.d.ts +67 -0
- package/dist/core/src/client/runClientQuery.js +157 -0
- package/dist/core/src/columns/ColumnBuilder.d.ts +121 -0
- package/dist/core/src/columns/ColumnBuilder.js +273 -0
- package/dist/core/src/columns/cascade.d.ts +24 -0
- package/dist/core/src/columns/cascade.js +93 -0
- package/dist/core/src/columns/deriveOperators.d.ts +38 -0
- package/dist/core/src/columns/deriveOperators.js +94 -0
- package/dist/core/src/columns/expandSorting.d.ts +19 -0
- package/dist/core/src/columns/expandSorting.js +52 -0
- package/dist/core/src/columns/helper.d.ts +196 -0
- package/dist/core/src/columns/helper.js +250 -0
- package/dist/core/src/columns/labels.d.ts +12 -0
- package/dist/core/src/columns/labels.js +21 -0
- package/dist/core/src/contract.d.ts +12 -0
- package/dist/core/src/contract.js +12 -0
- package/dist/core/src/contracts/aiColumnMeta.d.ts +102 -0
- package/dist/core/src/contracts/aiColumnMeta.js +197 -0
- package/dist/core/src/contracts/describeColumns.d.ts +48 -0
- package/dist/core/src/contracts/describeColumns.js +40 -0
- package/dist/core/src/contracts/exportData.d.ts +150 -0
- package/dist/core/src/contracts/exportData.js +228 -0
- package/dist/core/src/contracts/index.d.ts +6 -0
- package/dist/core/src/contracts/index.js +12 -0
- package/dist/core/src/contracts/legacyUrl.d.ts +47 -0
- package/dist/core/src/contracts/legacyUrl.js +156 -0
- package/dist/core/src/contracts/preset.d.ts +104 -0
- package/dist/core/src/contracts/preset.js +141 -0
- package/dist/core/src/contracts/presetStore.d.ts +81 -0
- package/dist/core/src/contracts/presetStore.js +146 -0
- package/dist/core/src/contracts/usePresets.d.ts +51 -0
- package/dist/core/src/contracts/usePresets.js +170 -0
- package/dist/core/src/defaults.d.ts +7 -0
- package/dist/core/src/defaults.js +9 -0
- package/dist/core/src/filters/codec.d.ts +20 -0
- package/dist/core/src/filters/codec.js +61 -0
- package/dist/core/src/filters/date.d.ts +30 -0
- package/dist/core/src/filters/date.js +179 -0
- package/dist/core/src/filters/describe.d.ts +45 -0
- package/dist/core/src/filters/describe.js +189 -0
- package/dist/core/src/filters/kind.d.ts +52 -0
- package/dist/core/src/filters/kind.js +110 -0
- package/dist/core/src/filters/kinds/_list.d.ts +13 -0
- package/dist/core/src/filters/kinds/_list.js +42 -0
- package/dist/core/src/filters/kinds/boolean.d.ts +3 -0
- package/dist/core/src/filters/kinds/boolean.js +21 -0
- package/dist/core/src/filters/kinds/cascade.d.ts +6 -0
- package/dist/core/src/filters/kinds/cascade.js +16 -0
- package/dist/core/src/filters/kinds/commonCode.d.ts +3 -0
- package/dist/core/src/filters/kinds/commonCode.js +13 -0
- package/dist/core/src/filters/kinds/date.d.ts +9 -0
- package/dist/core/src/filters/kinds/date.js +32 -0
- package/dist/core/src/filters/kinds/enum.d.ts +4 -0
- package/dist/core/src/filters/kinds/enum.js +13 -0
- package/dist/core/src/filters/kinds/index.d.ts +49 -0
- package/dist/core/src/filters/kinds/index.js +39 -0
- package/dist/core/src/filters/kinds/linear.d.ts +5 -0
- package/dist/core/src/filters/kinds/linear.js +16 -0
- package/dist/core/src/filters/kinds/number.d.ts +5 -0
- package/dist/core/src/filters/kinds/number.js +19 -0
- package/dist/core/src/filters/kinds/period.d.ts +4 -0
- package/dist/core/src/filters/kinds/period.js +17 -0
- package/dist/core/src/filters/kinds/relation.d.ts +5 -0
- package/dist/core/src/filters/kinds/relation.js +17 -0
- package/dist/core/src/filters/kinds/schedule.d.ts +5 -0
- package/dist/core/src/filters/kinds/schedule.js +16 -0
- package/dist/core/src/filters/kinds/text.d.ts +4 -0
- package/dist/core/src/filters/kinds/text.js +18 -0
- package/dist/core/src/filters/linear.d.ts +33 -0
- package/dist/core/src/filters/linear.js +65 -0
- package/dist/core/src/filters/list.d.ts +32 -0
- package/dist/core/src/filters/list.js +87 -0
- package/dist/core/src/filters/number.d.ts +17 -0
- package/dist/core/src/filters/number.js +82 -0
- package/dist/core/src/filters/registry.d.ts +23 -0
- package/dist/core/src/filters/registry.js +121 -0
- package/dist/core/src/filters/relation.d.ts +26 -0
- package/dist/core/src/filters/relation.js +75 -0
- package/dist/core/src/filters/schedule.d.ts +21 -0
- package/dist/core/src/filters/schedule.js +60 -0
- package/dist/core/src/filters/text.d.ts +44 -0
- package/dist/core/src/filters/text.js +127 -0
- package/dist/core/src/hooks/index.d.ts +6 -0
- package/dist/core/src/hooks/index.js +6 -0
- package/dist/core/src/hooks/useDataTable.d.ts +13 -0
- package/dist/core/src/hooks/useDataTable.js +109 -0
- package/dist/core/src/hooks/useGrouping.d.ts +33 -0
- package/dist/core/src/hooks/useGrouping.js +57 -0
- package/dist/core/src/hooks/useSearchHistory.d.ts +20 -0
- package/dist/core/src/hooks/useSearchHistory.js +52 -0
- package/dist/core/src/hooks/useTableData.d.ts +25 -0
- package/dist/core/src/hooks/useTableData.js +49 -0
- package/dist/core/src/hooks/useTableFromDefinition.d.ts +47 -0
- package/dist/core/src/hooks/useTableFromDefinition.js +174 -0
- package/dist/core/src/hooks/useTableSearch.d.ts +10 -0
- package/dist/core/src/hooks/useTableSearch.js +434 -0
- package/dist/core/src/hooks/useUrlSync.d.ts +64 -0
- package/dist/core/src/hooks/useUrlSync.js +145 -0
- package/dist/core/src/index.d.ts +38 -0
- package/dist/core/src/index.js +43 -0
- package/dist/core/src/pivot/runClientPivot.d.ts +101 -0
- package/dist/core/src/pivot/runClientPivot.js +230 -0
- package/dist/core/src/pivot/transforms.d.ts +19 -0
- package/dist/core/src/pivot/transforms.js +105 -0
- package/dist/core/src/registry.d.ts +46 -0
- package/dist/core/src/registry.js +67 -0
- package/dist/core/src/types/column.d.ts +213 -0
- package/dist/core/src/types/column.js +1 -0
- package/dist/core/src/types/data.d.ts +63 -0
- package/dist/core/src/types/data.js +1 -0
- package/dist/core/src/types/definition.d.ts +239 -0
- package/dist/core/src/types/definition.js +59 -0
- package/dist/core/src/types/filter.d.ts +94 -0
- package/dist/core/src/types/filter.js +1 -0
- package/dist/core/src/types/filterKind.d.ts +204 -0
- package/dist/core/src/types/filterKind.js +1 -0
- package/dist/core/src/types/grouping.d.ts +80 -0
- package/dist/core/src/types/grouping.js +4 -0
- package/dist/core/src/types/index.d.ts +8 -0
- package/dist/core/src/types/index.js +8 -0
- package/dist/core/src/types/operators.d.ts +64 -0
- package/dist/core/src/types/operators.js +108 -0
- package/dist/core/src/types/request.d.ts +114 -0
- package/dist/core/src/types/request.js +1 -0
- package/dist/core/src/types/search.d.ts +112 -0
- package/dist/core/src/types/search.js +1 -0
- package/dist/core/src/types/sources.d.ts +84 -0
- package/dist/core/src/types/sources.js +1 -0
- package/dist/core/src/types/table.d.ts +40 -0
- package/dist/core/src/types/table.js +1 -0
- package/dist/core/src/utils/compare.d.ts +13 -0
- package/dist/core/src/utils/compare.js +53 -0
- package/dist/core/src/utils/dateText.d.ts +12 -0
- package/dist/core/src/utils/dateText.js +30 -0
- package/dist/core/src/utils/getValue.d.ts +9 -0
- package/dist/core/src/utils/getValue.js +32 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/mui/src/TableLayout.d.ts +75 -0
- package/dist/mui/src/TableLayout.js +162 -0
- package/dist/mui/src/TableScreen.d.ts +70 -0
- package/dist/mui/src/TableScreen.js +174 -0
- package/dist/mui/src/addons/FilterModal.d.ts +45 -0
- package/dist/mui/src/addons/FilterModal.js +39 -0
- package/dist/mui/src/addons/FilterStatusModal.d.ts +40 -0
- package/dist/mui/src/addons/FilterStatusModal.js +68 -0
- package/dist/mui/src/addons/PresetBar.d.ts +56 -0
- package/dist/mui/src/addons/PresetBar.js +145 -0
- package/dist/mui/src/addons/ShareDropdown.d.ts +35 -0
- package/dist/mui/src/addons/ShareDropdown.js +41 -0
- package/dist/mui/src/addons/searchStore.d.ts +44 -0
- package/dist/mui/src/addons/searchStore.js +112 -0
- package/dist/mui/src/addons/searchSummary.d.ts +106 -0
- package/dist/mui/src/addons/searchSummary.js +109 -0
- package/dist/mui/src/columns/displayColumns.d.ts +100 -0
- package/dist/mui/src/columns/displayColumns.js +174 -0
- package/dist/mui/src/content/CardContent.d.ts +24 -0
- package/dist/mui/src/content/CardContent.js +25 -0
- package/dist/mui/src/content/ColumnMenu.d.ts +43 -0
- package/dist/mui/src/content/ColumnMenu.js +40 -0
- package/dist/mui/src/content/ColumnVisibilityMenu.d.ts +14 -0
- package/dist/mui/src/content/ColumnVisibilityMenu.js +37 -0
- package/dist/mui/src/content/EditCell.d.ts +19 -0
- package/dist/mui/src/content/EditCell.js +61 -0
- package/dist/mui/src/content/HeaderCell.d.ts +59 -0
- package/dist/mui/src/content/HeaderCell.js +88 -0
- package/dist/mui/src/content/SelectionActionBar.d.ts +17 -0
- package/dist/mui/src/content/SelectionActionBar.js +19 -0
- package/dist/mui/src/content/SortControl.d.ts +17 -0
- package/dist/mui/src/content/SortControl.js +45 -0
- package/dist/mui/src/content/TableContent.d.ts +191 -0
- package/dist/mui/src/content/TableContent.js +525 -0
- package/dist/mui/src/content/TableErrorFallback.d.ts +24 -0
- package/dist/mui/src/content/TableErrorFallback.js +29 -0
- package/dist/mui/src/content/cellError.d.ts +13 -0
- package/dist/mui/src/content/cellError.js +20 -0
- package/dist/mui/src/content/cellRenderers.d.ts +71 -0
- package/dist/mui/src/content/cellRenderers.js +127 -0
- package/dist/mui/src/content/cellValue.d.ts +27 -0
- package/dist/mui/src/content/cellValue.js +82 -0
- package/dist/mui/src/content/columnOrder.d.ts +7 -0
- package/dist/mui/src/content/columnOrder.js +48 -0
- package/dist/mui/src/content/density.d.ts +13 -0
- package/dist/mui/src/content/density.js +12 -0
- package/dist/mui/src/content/menuItems.d.ts +118 -0
- package/dist/mui/src/content/menuItems.js +128 -0
- package/dist/mui/src/content/pinning.d.ts +17 -0
- package/dist/mui/src/content/pinning.js +65 -0
- package/dist/mui/src/exporters/index.d.ts +1 -0
- package/dist/mui/src/exporters/index.js +1 -0
- package/dist/mui/src/exporters/useExportFormatters.d.ts +13 -0
- package/dist/mui/src/exporters/useExportFormatters.js +17 -0
- package/dist/mui/src/filter/FilterArea.d.ts +40 -0
- package/dist/mui/src/filter/FilterArea.js +37 -0
- package/dist/mui/src/filter/FilterInput.d.ts +14 -0
- package/dist/mui/src/filter/FilterInput.js +18 -0
- package/dist/mui/src/filter/inputs/DateFilterInput.d.ts +14 -0
- package/dist/mui/src/filter/inputs/DateFilterInput.js +112 -0
- package/dist/mui/src/filter/inputs/LinearFilterInput.d.ts +10 -0
- package/dist/mui/src/filter/inputs/LinearFilterInput.js +35 -0
- package/dist/mui/src/filter/inputs/NumberFilterInput.d.ts +12 -0
- package/dist/mui/src/filter/inputs/NumberFilterInput.js +111 -0
- package/dist/mui/src/filter/inputs/OperatorMenu.d.ts +14 -0
- package/dist/mui/src/filter/inputs/OperatorMenu.js +25 -0
- package/dist/mui/src/filter/inputs/RelationFilterInput.d.ts +11 -0
- package/dist/mui/src/filter/inputs/RelationFilterInput.js +67 -0
- package/dist/mui/src/filter/inputs/ScheduleFilterInput.d.ts +8 -0
- package/dist/mui/src/filter/inputs/ScheduleFilterInput.js +17 -0
- package/dist/mui/src/filter/inputs/SelectFilterInput.d.ts +16 -0
- package/dist/mui/src/filter/inputs/SelectFilterInput.js +57 -0
- package/dist/mui/src/filter/inputs/TextFilterInput.d.ts +13 -0
- package/dist/mui/src/filter/inputs/TextFilterInput.js +55 -0
- package/dist/mui/src/filter/kinds.d.ts +58 -0
- package/dist/mui/src/filter/kinds.js +103 -0
- package/dist/mui/src/grouping/AggregateChip.d.ts +55 -0
- package/dist/mui/src/grouping/AggregateChip.js +128 -0
- package/dist/mui/src/grouping/AggregationChips.d.ts +49 -0
- package/dist/mui/src/grouping/AggregationChips.js +80 -0
- package/dist/mui/src/grouping/AggregationSettingsButton.d.ts +14 -0
- package/dist/mui/src/grouping/AggregationSettingsButton.js +19 -0
- package/dist/mui/src/grouping/GroupingBar.d.ts +59 -0
- package/dist/mui/src/grouping/GroupingBar.js +267 -0
- package/dist/mui/src/grouping/StepExpandButton.d.ts +12 -0
- package/dist/mui/src/grouping/StepExpandButton.js +18 -0
- package/dist/mui/src/grouping/groupRow.d.ts +68 -0
- package/dist/mui/src/grouping/groupRow.js +129 -0
- package/dist/mui/src/headers/defaultHeader.d.ts +28 -0
- package/dist/mui/src/headers/defaultHeader.js +90 -0
- package/dist/mui/src/headers/defineHeader.d.ts +21 -0
- package/dist/mui/src/headers/defineHeader.js +68 -0
- package/dist/mui/src/headers/index.d.ts +5 -0
- package/dist/mui/src/headers/index.js +3 -0
- package/dist/mui/src/headers/meta.d.ts +18 -0
- package/dist/mui/src/headers/meta.js +11 -0
- package/dist/mui/src/headers/types.d.ts +84 -0
- package/dist/mui/src/headers/types.js +1 -0
- package/dist/mui/src/index.d.ts +110 -0
- package/dist/mui/src/index.js +79 -0
- package/dist/mui/src/layout/ResizeHandle.d.ts +30 -0
- package/dist/mui/src/layout/ResizeHandle.js +66 -0
- package/dist/mui/src/menus/columnMenu.d.ts +45 -0
- package/dist/mui/src/menus/columnMenu.js +144 -0
- package/dist/mui/src/menus/copy.d.ts +5 -0
- package/dist/mui/src/menus/copy.js +25 -0
- package/dist/mui/src/menus/index.d.ts +6 -0
- package/dist/mui/src/menus/index.js +4 -0
- package/dist/mui/src/menus/resolve.d.ts +15 -0
- package/dist/mui/src/menus/resolve.js +60 -0
- package/dist/mui/src/menus/rowMenu.d.ts +46 -0
- package/dist/mui/src/menus/rowMenu.js +76 -0
- package/dist/mui/src/pagination/PaginationArea.d.ts +16 -0
- package/dist/mui/src/pagination/PaginationArea.js +23 -0
- package/dist/mui/src/pivot/PivotTable.d.ts +18 -0
- package/dist/mui/src/pivot/PivotTable.js +100 -0
- package/dist/mui/src/provider/KokoTableProvider.d.ts +184 -0
- package/dist/mui/src/provider/KokoTableProvider.js +118 -0
- package/dist/mui/src/provider/labels.d.ts +85 -0
- package/dist/mui/src/provider/labels.js +104 -0
- package/dist/mui/src/registry.d.ts +30 -0
- package/dist/mui/src/registry.js +5 -0
- package/dist/mui/src/toolbar/GlobalFilterField.d.ts +36 -0
- package/dist/mui/src/toolbar/GlobalFilterField.js +78 -0
- package/dist/mui/src/virtual/VirtualTableContent.d.ts +41 -0
- package/dist/mui/src/virtual/VirtualTableContent.js +58 -0
- package/dist/mui/src/virtual/VirtualTableScreen.d.ts +13 -0
- package/dist/mui/src/virtual/VirtualTableScreen.js +23 -0
- package/dist/mui/src/virtual.d.ts +4 -0
- package/dist/mui/src/virtual.js +4 -0
- package/dist/mui/src/virtualColumns/VirtualColumnCard.d.ts +26 -0
- package/dist/mui/src/virtualColumns/VirtualColumnCard.js +29 -0
- package/dist/mui/src/virtualColumns/VirtualColumnDialog.d.ts +27 -0
- package/dist/mui/src/virtualColumns/VirtualColumnDialog.js +154 -0
- package/dist/mui/src/virtualColumns/VirtualColumnSection.d.ts +31 -0
- package/dist/mui/src/virtualColumns/VirtualColumnSection.js +55 -0
- package/dist/mui/src/virtualColumns/expression.d.ts +68 -0
- package/dist/mui/src/virtualColumns/expression.js +489 -0
- package/dist/mui/src/virtualColumns/useVirtualColumns.d.ts +67 -0
- package/dist/mui/src/virtualColumns/useVirtualColumns.js +111 -0
- package/dist/mui/src/virtualColumns/virtualColumnDefs.d.ts +29 -0
- package/dist/mui/src/virtualColumns/virtualColumnDefs.js +51 -0
- package/dist/mui-virtual.d.ts +1 -0
- package/dist/mui-virtual.js +2 -0
- package/dist/mui.d.ts +1 -0
- package/dist/mui.js +2 -0
- package/dist/query/src/index.d.ts +6 -0
- package/dist/query/src/index.js +7 -0
- package/dist/query/src/serverPivot.d.ts +42 -0
- package/dist/query/src/serverPivot.js +153 -0
- package/dist/query/src/useServerGrouping.d.ts +52 -0
- package/dist/query/src/useServerGrouping.js +186 -0
- package/dist/query/src/useServerTable.d.ts +20 -0
- package/dist/query/src/useServerTable.js +106 -0
- package/dist/query/src/useServerTableData.d.ts +48 -0
- package/dist/query/src/useServerTableData.js +64 -0
- package/dist/query/src/wire.d.ts +16 -0
- package/dist/query/src/wire.js +32 -0
- package/dist/query.d.ts +1 -0
- package/dist/query.js +2 -0
- package/package.json +125 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { filterKinds } from "../kind";
|
|
2
|
+
import { textKind } from "./text";
|
|
3
|
+
import { numberKind } from "./number";
|
|
4
|
+
import { dateKind } from "./date";
|
|
5
|
+
import { periodKind } from "./period";
|
|
6
|
+
import { booleanKind } from "./boolean";
|
|
7
|
+
import { enumKind } from "./enum";
|
|
8
|
+
import { commonCodeKind } from "./commonCode";
|
|
9
|
+
import { cascadeKind } from "./cascade";
|
|
10
|
+
import { relationKind } from "./relation";
|
|
11
|
+
import { scheduleKind } from "./schedule";
|
|
12
|
+
import { linearKind } from "./linear";
|
|
13
|
+
export { textKind, numberKind, dateKind, periodKind, booleanKind, enumKind, commonCodeKind, cascadeKind, relationKind, scheduleKind, linearKind };
|
|
14
|
+
export { ENUM_OPERATORS, matchListOperator } from "./_list";
|
|
15
|
+
export const BUILTIN_FILTER_KINDS = [
|
|
16
|
+
textKind, numberKind, dateKind, periodKind, booleanKind, enumKind,
|
|
17
|
+
commonCodeKind, cascadeKind, relationKind, scheduleKind, linearKind,
|
|
18
|
+
];
|
|
19
|
+
for (const kind of BUILTIN_FILTER_KINDS)
|
|
20
|
+
filterKinds.register(kind);
|
|
21
|
+
/**
|
|
22
|
+
* variant → 내장 kind. `ColumnBuilder.setVariant` / `dataType` 유추가 kind 를 함께 붙이는 표.
|
|
23
|
+
* `custom` 은 kind 가 없다(호출부가 `render` 로 값 해석을 전담).
|
|
24
|
+
*/
|
|
25
|
+
export const BUILTIN_KIND_BY_VARIANT = {
|
|
26
|
+
text: textKind,
|
|
27
|
+
number: numberKind,
|
|
28
|
+
date: dateKind,
|
|
29
|
+
datetime: dateKind,
|
|
30
|
+
boolean: booleanKind,
|
|
31
|
+
select: enumKind,
|
|
32
|
+
multiSelect: enumKind,
|
|
33
|
+
relation: relationKind,
|
|
34
|
+
linear: linearKind,
|
|
35
|
+
schedule: scheduleKind,
|
|
36
|
+
};
|
|
37
|
+
export function builtinKindForVariant(variant) {
|
|
38
|
+
return BUILTIN_KIND_BY_VARIANT[variant];
|
|
39
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { LinearOperator } from "../../types/operators";
|
|
2
|
+
import { type LinearFilterValue } from "../linear";
|
|
3
|
+
export type { LinearFilterValue };
|
|
4
|
+
/** 선형결합(수량 조건) — `terms` 가 비면 미입력 */
|
|
5
|
+
export declare const linearKind: import("../..").FilterKind<"linear", LinearFilterValue, LinearOperator, unknown>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { LINEAR_OPERATORS } from "../../types/operators";
|
|
2
|
+
import { defineFilterKind, operatorTable } from "../kind";
|
|
3
|
+
import { matchLinear } from "../linear";
|
|
4
|
+
import { describeLinear } from "../describe";
|
|
5
|
+
/** 선형결합(수량 조건) — `terms` 가 비면 미입력 */
|
|
6
|
+
export const linearKind = defineFilterKind({
|
|
7
|
+
id: "linear",
|
|
8
|
+
variant: "linear",
|
|
9
|
+
operators: operatorTable(LINEAR_OPERATORS, (op) => ({
|
|
10
|
+
client: (_cell, value, ctx) => matchLinear(ctx.row, ctx.columnId, value, op),
|
|
11
|
+
describe: (value, ctx) => describeLinear(value, ctx),
|
|
12
|
+
})),
|
|
13
|
+
defaultOperator: "linearContains",
|
|
14
|
+
offered: ["linearContains", "linearExists", "linearExact"],
|
|
15
|
+
isEmpty: (value) => !value?.terms?.length,
|
|
16
|
+
});
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { NumberOperator } from "../../types/operators";
|
|
2
|
+
export type NumberBound = number | null;
|
|
3
|
+
/** 단일 값 · 범위 `[lo, hi]`(빈 쪽 null) · `isEmpty` 방향 boolean */
|
|
4
|
+
export type NumberFilterValue = number | [NumberBound, NumberBound] | boolean;
|
|
5
|
+
export declare const numberKind: import("../..").FilterKind<"number", NumberFilterValue, NumberOperator, unknown>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { NUMBER_OPERATORS } from "../../types/operators";
|
|
2
|
+
import { defineFilterKind, operatorTable } from "../kind";
|
|
3
|
+
import { matchNumber } from "../number";
|
|
4
|
+
import { describeRange, describeScalar } from "../describe";
|
|
5
|
+
import { isUnsetFilterValue } from "../../utils/getValue";
|
|
6
|
+
const RANGE = new Set(["between", "betweenInclusive", "outsideRange"]);
|
|
7
|
+
export const numberKind = defineFilterKind({
|
|
8
|
+
id: "number",
|
|
9
|
+
dataKind: "number",
|
|
10
|
+
variant: "number",
|
|
11
|
+
operators: operatorTable(NUMBER_OPERATORS, (op) => ({
|
|
12
|
+
client: (cell, value) => matchNumber(cell, value, op),
|
|
13
|
+
describe: (value, ctx) => (RANGE.has(op) ? describeRange(value, ctx) : describeScalar(value, ctx)),
|
|
14
|
+
valueless: op === "isEmpty",
|
|
15
|
+
})),
|
|
16
|
+
defaultOperator: "betweenInclusive",
|
|
17
|
+
offered: ["betweenInclusive", "outsideRange", "isEmpty"],
|
|
18
|
+
isEmpty: isUnsetFilterValue,
|
|
19
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { defineFilterKind } from "../kind";
|
|
2
|
+
import { matchInPeriod, PERIOD_TOKENS } from "../date";
|
|
3
|
+
import { describeScalar } from "../describe";
|
|
4
|
+
/** 기간 토큰만 고르는 날짜 컬럼 — `date` kind 의 `inPeriod` 하나를 떼어 낸 것 */
|
|
5
|
+
export const periodKind = defineFilterKind({
|
|
6
|
+
id: "period",
|
|
7
|
+
dataKind: "date",
|
|
8
|
+
variant: "date",
|
|
9
|
+
operators: {
|
|
10
|
+
inPeriod: {
|
|
11
|
+
client: (cell, value, ctx) => matchInPeriod(cell, value, ctx.now),
|
|
12
|
+
describe: (value, ctx) => ctx.labels.periods?.[value] ?? describeScalar(value, ctx),
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
defaultOperator: "inPeriod",
|
|
16
|
+
isEmpty: (value) => !value || !PERIOD_TOKENS.includes(String(value)),
|
|
17
|
+
});
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { RelationOperator } from "../../types/operators";
|
|
2
|
+
import { type RelationFilterValue } from "../relation";
|
|
3
|
+
/** `{ groups }` · `hasChild`/`hasNotChild` 는 방향 boolean */
|
|
4
|
+
export type RelationKindValue = RelationFilterValue | boolean;
|
|
5
|
+
export declare const relationKind: import("../..").FilterKind<"relation", RelationKindValue, RelationOperator, unknown>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { RELATION_OPERATORS } from "../../types/operators";
|
|
2
|
+
import { defineFilterKind, operatorTable } from "../kind";
|
|
3
|
+
import { matchRelation } from "../relation";
|
|
4
|
+
import { describeRelation } from "../describe";
|
|
5
|
+
import { isUnsetFilterValue } from "../../utils/getValue";
|
|
6
|
+
export const relationKind = defineFilterKind({
|
|
7
|
+
id: "relation",
|
|
8
|
+
dataKind: "relation",
|
|
9
|
+
variant: "relation",
|
|
10
|
+
operators: operatorTable(RELATION_OPERATORS, (op) => ({
|
|
11
|
+
client: (_cell, value, ctx) => matchRelation(ctx.row, ctx.columnId, value, op),
|
|
12
|
+
describe: (value, ctx) => describeRelation(value, ctx),
|
|
13
|
+
valueless: op === "hasChild" || op === "hasNotChild",
|
|
14
|
+
})),
|
|
15
|
+
defaultOperator: "hasAny",
|
|
16
|
+
isEmpty: isUnsetFilterValue,
|
|
17
|
+
});
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ScheduleOperator } from "../../types/operators";
|
|
2
|
+
import { type ScheduleContainsValue, type ScheduleOverlapsValue } from "../schedule";
|
|
3
|
+
export type ScheduleFilterValue = ScheduleContainsValue | ScheduleOverlapsValue;
|
|
4
|
+
/** 예정/실제 기간을 OR 로 보는 일정 통합 컬럼 — 값 객체는 URL·프리셋에 그대로 실린다 */
|
|
5
|
+
export declare const scheduleKind: import("../..").FilterKind<"schedule", ScheduleFilterValue, ScheduleOperator, unknown>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { SCHEDULE_OPERATORS } from "../../types/operators";
|
|
2
|
+
import { defineFilterKind, operatorTable } from "../kind";
|
|
3
|
+
import { matchSchedule } from "../schedule";
|
|
4
|
+
import { describeSchedule } from "../describe";
|
|
5
|
+
import { isUnsetFilterValue } from "../../utils/getValue";
|
|
6
|
+
/** 예정/실제 기간을 OR 로 보는 일정 통합 컬럼 — 값 객체는 URL·프리셋에 그대로 실린다 */
|
|
7
|
+
export const scheduleKind = defineFilterKind({
|
|
8
|
+
id: "schedule",
|
|
9
|
+
variant: "schedule",
|
|
10
|
+
operators: operatorTable(SCHEDULE_OPERATORS, (op) => ({
|
|
11
|
+
client: (_cell, value, ctx) => matchSchedule(ctx.row, value, op),
|
|
12
|
+
describe: (value, ctx) => describeSchedule(value, ctx),
|
|
13
|
+
})),
|
|
14
|
+
defaultOperator: "scheduleContains",
|
|
15
|
+
isEmpty: isUnsetFilterValue,
|
|
16
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { TEXT_OPERATORS } from "../../types/operators";
|
|
2
|
+
import { defineFilterKind, operatorTable } from "../kind";
|
|
3
|
+
import { matchText } from "../text";
|
|
4
|
+
import { describeScalar } from "../describe";
|
|
5
|
+
import { isUnsetFilterValue } from "../../utils/getValue";
|
|
6
|
+
export const textKind = defineFilterKind({
|
|
7
|
+
id: "text",
|
|
8
|
+
dataKind: "text",
|
|
9
|
+
variant: "text",
|
|
10
|
+
operators: operatorTable(TEXT_OPERATORS, (op) => ({
|
|
11
|
+
client: (cell, value) => matchText(cell, value, op),
|
|
12
|
+
describe: (value, ctx) => describeScalar(value, ctx),
|
|
13
|
+
valueless: op === "empty" || op === "notEmpty",
|
|
14
|
+
})),
|
|
15
|
+
defaultOperator: "fuzzy",
|
|
16
|
+
offered: ["fuzzy", "equals", "empty"],
|
|
17
|
+
isEmpty: isUnsetFilterValue,
|
|
18
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** 수량 비교 연산자 — 백엔드 `LINEAR_QUANTITY_OPERATORS` 와 같다 */
|
|
2
|
+
export type LinearQuantityOp = "eq" | "gte" | "lte" | "gt" | "lt";
|
|
3
|
+
export type LinearOperatorName = "linearExact" | "linearContains" | "linearExists";
|
|
4
|
+
export interface LinearFilterTerm {
|
|
5
|
+
/** 대상 엔티티 idx (SKU, Item 등) */
|
|
6
|
+
target_idx: number;
|
|
7
|
+
target_name?: string;
|
|
8
|
+
target_code?: string;
|
|
9
|
+
/** 수량 조건. 없으면 수량 무관 */
|
|
10
|
+
quantity?: number;
|
|
11
|
+
/** 기본값 `"gte"` */
|
|
12
|
+
quantity_op?: LinearQuantityOp;
|
|
13
|
+
}
|
|
14
|
+
export interface LinearFilterValue {
|
|
15
|
+
/** 관계 경로 (`"composition.items"`) */
|
|
16
|
+
relation: string;
|
|
17
|
+
mode: "exact" | "contains" | "exists";
|
|
18
|
+
terms: LinearFilterTerm[];
|
|
19
|
+
/** true = 모든 term 충족(AND), false = 하나라도(OR) */
|
|
20
|
+
match_all: boolean;
|
|
21
|
+
/** 대상 FK 컬럼명. 기본 `"idx"` */
|
|
22
|
+
target_fk?: string;
|
|
23
|
+
/** 수량 필드명. 기본 `"quantity"` */
|
|
24
|
+
quantity_field?: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* 선형결합 필터 — 1:N 관계에 "무엇을 몇 개 이상" 조건을 건다.
|
|
28
|
+
*
|
|
29
|
+
* - `linearExists`: 수량 무관, 항목 존재만
|
|
30
|
+
* - `linearContains`: 수량 조건 포함
|
|
31
|
+
* - `linearExact`: 지정 항목만 정확히 (여분 항목 없음)
|
|
32
|
+
*/
|
|
33
|
+
export declare function matchLinear(row: unknown, columnId: string, filterValue: unknown, operator: LinearOperatorName): boolean;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { getValue } from "../utils/getValue";
|
|
2
|
+
function evalQuantity(itemQty, required, op = "gte") {
|
|
3
|
+
switch (op) {
|
|
4
|
+
case "eq": return itemQty === required;
|
|
5
|
+
case "gte": return itemQty >= required;
|
|
6
|
+
case "lte": return itemQty <= required;
|
|
7
|
+
case "gt": return itemQty > required;
|
|
8
|
+
case "lt": return itemQty < required;
|
|
9
|
+
default: return true;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function relationItems(row, columnId, relation) {
|
|
13
|
+
const data = getValue(row, relation || columnId);
|
|
14
|
+
return Array.isArray(data) ? data : [];
|
|
15
|
+
}
|
|
16
|
+
const termExists = (items, term, fk) => items.some((item) => getValue(item, fk) === term.target_idx);
|
|
17
|
+
function termContains(items, term, fk, quantityField) {
|
|
18
|
+
const matched = items.find((item) => getValue(item, fk) === term.target_idx);
|
|
19
|
+
if (!matched)
|
|
20
|
+
return false;
|
|
21
|
+
if (term.quantity == null)
|
|
22
|
+
return true;
|
|
23
|
+
const qty = Number(getValue(matched, quantityField) ?? 0);
|
|
24
|
+
return evalQuantity(qty, term.quantity, term.quantity_op ?? "gte");
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* exact 모드의 항 — 서버 `_apply_exact` 는 `quantity_op` 를 **무시**하고
|
|
28
|
+
* `quantity_column == quantity` 로 판정한다. contains 의 `gte` 기본값을 재사용하면
|
|
29
|
+
* "정확히 1개" 가 "1개 이상" 이 되어 서버보다 많은 행이 나온다.
|
|
30
|
+
*/
|
|
31
|
+
function termExact(items, term, fk, quantityField) {
|
|
32
|
+
return items.some((item) => {
|
|
33
|
+
if (getValue(item, fk) !== term.target_idx)
|
|
34
|
+
return false;
|
|
35
|
+
if (term.quantity == null)
|
|
36
|
+
return true;
|
|
37
|
+
return Number(getValue(item, quantityField) ?? 0) === term.quantity;
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* 선형결합 필터 — 1:N 관계에 "무엇을 몇 개 이상" 조건을 건다.
|
|
42
|
+
*
|
|
43
|
+
* - `linearExists`: 수량 무관, 항목 존재만
|
|
44
|
+
* - `linearContains`: 수량 조건 포함
|
|
45
|
+
* - `linearExact`: 지정 항목만 정확히 (여분 항목 없음)
|
|
46
|
+
*/
|
|
47
|
+
export function matchLinear(row, columnId, filterValue, operator) {
|
|
48
|
+
const value = filterValue;
|
|
49
|
+
if (!value?.terms?.length)
|
|
50
|
+
return true;
|
|
51
|
+
const items = relationItems(row, columnId, value.relation);
|
|
52
|
+
const fk = value.target_fk || "idx";
|
|
53
|
+
const quantityField = value.quantity_field || "quantity";
|
|
54
|
+
if (operator === "linearExact") {
|
|
55
|
+
// 서버와 같은 두 조건: (1) 각 항이 정확한 수량으로 존재 (2) 항에 없는 대상이 없음.
|
|
56
|
+
// 항목 수 비교는 하지 않는다 — 서버도 (parent, target) 유니크를 전제로 개수를 세지 않는다.
|
|
57
|
+
const allMatched = value.terms.every((t) => termExact(items, t, fk, quantityField));
|
|
58
|
+
const noExtra = items.every((item) => value.terms.some((t) => t.target_idx === getValue(item, fk)));
|
|
59
|
+
return allMatched && noExtra;
|
|
60
|
+
}
|
|
61
|
+
const check = operator === "linearExists"
|
|
62
|
+
? (t) => termExists(items, t, fk)
|
|
63
|
+
: (t) => termContains(items, t, fk, quantityField);
|
|
64
|
+
return value.match_all ? value.terms.every(check) : value.terms.some(check);
|
|
65
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* "비어 있음"을 선택지로 쓰는 센티널 값.
|
|
3
|
+
* 백엔드 `list_filter.EMPTY_FILTER_VALUE` 와 같은 문자열이어야 한다.
|
|
4
|
+
*/
|
|
5
|
+
export declare const EMPTY_FILTER_VALUE = "EMPTY";
|
|
6
|
+
/** "전체" 선택 — 서버가 필터를 통째로 건너뛴다 */
|
|
7
|
+
export declare const ALL_FILTER_VALUE = "_ALL_SELECTED";
|
|
8
|
+
/**
|
|
9
|
+
* 리스트 연산자의 값은 **항상 배열**이어야 한다.
|
|
10
|
+
*
|
|
11
|
+
* 서버 `ListFilter.apply` 는 `if "" in value` 를 문자열에도 그대로 돌려 스칼라
|
|
12
|
+
* `"NORMAL"` 을 글자 단위 리스트 `['N','O',…]` 로 쪼갠다 — enum 컬럼에서 500 이
|
|
13
|
+
* 났던 원인이다. 요청을 만드는 쪽(`TableSearch.request`)과 클라이언트 매칭이
|
|
14
|
+
* 같은 규칙으로 감싼다. 센티널(`EMPTY`, `_ALL_SELECTED`)도 배열 원소가 되어
|
|
15
|
+
* 의미가 보존된다.
|
|
16
|
+
*/
|
|
17
|
+
export declare function toListFilterValue(value: unknown): unknown[];
|
|
18
|
+
/**
|
|
19
|
+
* 리스트 필터 — `inArray` / `notInArray` / `in` / `notIn` 계열.
|
|
20
|
+
*
|
|
21
|
+
* 백엔드 `ListFilter._build_condition_with_empty` 규칙:
|
|
22
|
+
* - 빈 문자열 값은 목록에서 제거한다 (EMPTY 센티널은 유지)
|
|
23
|
+
* - EMPTY 가 선택되면 NULL/빈 문자열도 대상에 포함 (negate 면 반대)
|
|
24
|
+
* - EMPTY 만 선택된 경우, 비어 있지 않은 값은 포함 모드에서 탈락 / 제외 모드에서 통과
|
|
25
|
+
* - 제외 모드(`~column.in_()`)는 SQL 3값 논리라 **NULL 행을 제외**한다 —
|
|
26
|
+
* NULL 은 "목록에 없음" 이 아니라 "알 수 없음" 이다
|
|
27
|
+
*/
|
|
28
|
+
export declare function matchList(cellValue: unknown, filterValue: unknown, negate: boolean): boolean;
|
|
29
|
+
/** 리스트 `between` — 백엔드는 닫힌 구간(`>= lo && <= hi`) */
|
|
30
|
+
export declare function matchListBetween(cellValue: unknown, filterValue: unknown): boolean;
|
|
31
|
+
/** `arrIncludes*` — 셀 값이 배열인 경우의 포함 판정 */
|
|
32
|
+
export declare function matchArrayCell(cellValue: unknown, filterValue: unknown, mode: "some" | "all" | "one"): boolean;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { compareValues } from "../utils/compare";
|
|
2
|
+
/**
|
|
3
|
+
* "비어 있음"을 선택지로 쓰는 센티널 값.
|
|
4
|
+
* 백엔드 `list_filter.EMPTY_FILTER_VALUE` 와 같은 문자열이어야 한다.
|
|
5
|
+
*/
|
|
6
|
+
export const EMPTY_FILTER_VALUE = "EMPTY";
|
|
7
|
+
/** "전체" 선택 — 서버가 필터를 통째로 건너뛴다 */
|
|
8
|
+
export const ALL_FILTER_VALUE = "_ALL_SELECTED";
|
|
9
|
+
/**
|
|
10
|
+
* 리스트 연산자의 값은 **항상 배열**이어야 한다.
|
|
11
|
+
*
|
|
12
|
+
* 서버 `ListFilter.apply` 는 `if "" in value` 를 문자열에도 그대로 돌려 스칼라
|
|
13
|
+
* `"NORMAL"` 을 글자 단위 리스트 `['N','O',…]` 로 쪼갠다 — enum 컬럼에서 500 이
|
|
14
|
+
* 났던 원인이다. 요청을 만드는 쪽(`TableSearch.request`)과 클라이언트 매칭이
|
|
15
|
+
* 같은 규칙으로 감싼다. 센티널(`EMPTY`, `_ALL_SELECTED`)도 배열 원소가 되어
|
|
16
|
+
* 의미가 보존된다.
|
|
17
|
+
*/
|
|
18
|
+
export function toListFilterValue(value) {
|
|
19
|
+
if (Array.isArray(value))
|
|
20
|
+
return value;
|
|
21
|
+
if (value === null || value === undefined)
|
|
22
|
+
return [];
|
|
23
|
+
return [value];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 리스트 필터 — `inArray` / `notInArray` / `in` / `notIn` 계열.
|
|
27
|
+
*
|
|
28
|
+
* 백엔드 `ListFilter._build_condition_with_empty` 규칙:
|
|
29
|
+
* - 빈 문자열 값은 목록에서 제거한다 (EMPTY 센티널은 유지)
|
|
30
|
+
* - EMPTY 가 선택되면 NULL/빈 문자열도 대상에 포함 (negate 면 반대)
|
|
31
|
+
* - EMPTY 만 선택된 경우, 비어 있지 않은 값은 포함 모드에서 탈락 / 제외 모드에서 통과
|
|
32
|
+
* - 제외 모드(`~column.in_()`)는 SQL 3값 논리라 **NULL 행을 제외**한다 —
|
|
33
|
+
* NULL 은 "목록에 없음" 이 아니라 "알 수 없음" 이다
|
|
34
|
+
*/
|
|
35
|
+
export function matchList(cellValue, filterValue, negate) {
|
|
36
|
+
if (filterValue === null || filterValue === undefined)
|
|
37
|
+
return true;
|
|
38
|
+
const list = toListFilterValue(filterValue);
|
|
39
|
+
if (list.length === 0)
|
|
40
|
+
return true;
|
|
41
|
+
// 빈 문자열 제거 (EMPTY 센티널은 유지)
|
|
42
|
+
const values = list.filter((v) => v !== "");
|
|
43
|
+
// 전부 제거되면 걸 조건이 없다 — 백엔드 `_build_condition_with_empty` 도
|
|
44
|
+
// `if not conditions: return 항상 참` 으로 전행을 통과시킨다.
|
|
45
|
+
if (values.length === 0)
|
|
46
|
+
return true;
|
|
47
|
+
const includeEmpty = values.includes(EMPTY_FILTER_VALUE);
|
|
48
|
+
const actual = values.filter((v) => v !== EMPTY_FILTER_VALUE);
|
|
49
|
+
const isNull = cellValue === null || cellValue === undefined;
|
|
50
|
+
const isEmpty = isNull || cellValue === "";
|
|
51
|
+
if (negate) {
|
|
52
|
+
// notIn + EMPTY: `column IS NOT NULL AND column != ''` 가 AND 로 붙는다
|
|
53
|
+
if (includeEmpty && isEmpty)
|
|
54
|
+
return false;
|
|
55
|
+
// 실제 값이 없으면(EMPTY 만 선택) 남은 조건이 없어 통과
|
|
56
|
+
if (actual.length === 0)
|
|
57
|
+
return true;
|
|
58
|
+
// `NULL NOT IN (...)` 은 NULL → 행 제외 (빈 문자열은 값이라 비교된다)
|
|
59
|
+
if (isNull)
|
|
60
|
+
return false;
|
|
61
|
+
return !actual.some((v) => String(v) === String(cellValue));
|
|
62
|
+
}
|
|
63
|
+
// 포함 모드: NULL/빈 문자열은 EMPTY 를 골랐을 때만 통과
|
|
64
|
+
if (isEmpty)
|
|
65
|
+
return includeEmpty;
|
|
66
|
+
// EMPTY 만 선택됨 — 비어 있지 않은 값은 탈락
|
|
67
|
+
if (actual.length === 0)
|
|
68
|
+
return false;
|
|
69
|
+
return actual.some((v) => String(v) === String(cellValue));
|
|
70
|
+
}
|
|
71
|
+
/** 리스트 `between` — 백엔드는 닫힌 구간(`>= lo && <= hi`) */
|
|
72
|
+
export function matchListBetween(cellValue, filterValue) {
|
|
73
|
+
if (!Array.isArray(filterValue) || filterValue.length !== 2)
|
|
74
|
+
return true;
|
|
75
|
+
const [lo, hi] = filterValue;
|
|
76
|
+
return compareValues(cellValue, lo) >= 0 && compareValues(cellValue, hi) <= 0;
|
|
77
|
+
}
|
|
78
|
+
/** `arrIncludes*` — 셀 값이 배열인 경우의 포함 판정 */
|
|
79
|
+
export function matchArrayCell(cellValue, filterValue, mode) {
|
|
80
|
+
const cells = Array.isArray(cellValue) ? cellValue.map(String) : [String(cellValue)];
|
|
81
|
+
const wanted = (Array.isArray(filterValue) ? filterValue : [filterValue]).map(String);
|
|
82
|
+
if (wanted.length === 0)
|
|
83
|
+
return true;
|
|
84
|
+
if (mode === "all")
|
|
85
|
+
return wanted.every((w) => cells.includes(w));
|
|
86
|
+
return wanted.some((w) => cells.includes(w));
|
|
87
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** 문자열 값을 숫자로 (실패 시 원본 유지 — 백엔드 `_to_number` 와 같다) */
|
|
2
|
+
export declare function toNumber(value: unknown): unknown;
|
|
3
|
+
/**
|
|
4
|
+
* 범위 필터 — `between`(열림) / `betweenInclusive`(닫힘) / `outsideRange`.
|
|
5
|
+
*
|
|
6
|
+
* 백엔드 `NumberFilter.apply` 의 한쪽-경계 규칙을 따른다:
|
|
7
|
+
* 하한만 있으면 `>= lo`, 상한만 있으면 `<= hi` (열림/닫힘 무관).
|
|
8
|
+
* `outsideRange` 는 두 경계가 **모두** 있어야 뜻이 정해지므로 하나라도 비면 전행 통과.
|
|
9
|
+
*/
|
|
10
|
+
export declare function matchRange(cellValue: unknown, filterValue: unknown, operator: "between" | "betweenInclusive" | "outsideRange"): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* 숫자 NULL 필터. 값이 `false` 면 방향이 뒤집힌다
|
|
13
|
+
* (텍스트 `empty` 와 같은 boolean 방향 규약).
|
|
14
|
+
*/
|
|
15
|
+
export declare function matchIsEmpty(cellValue: unknown, filterValue: unknown): boolean;
|
|
16
|
+
/** 단일 값 비교 — 백엔드 `NumberFilter` 의 스칼라 분기 */
|
|
17
|
+
export declare function matchNumber(cellValue: unknown, filterValue: unknown, operator: string): boolean;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { compareValues, isEmptyBound } from "../utils/compare";
|
|
2
|
+
/** 문자열 값을 숫자로 (실패 시 원본 유지 — 백엔드 `_to_number` 와 같다) */
|
|
3
|
+
export function toNumber(value) {
|
|
4
|
+
if (value === null || value === undefined)
|
|
5
|
+
return null;
|
|
6
|
+
if (typeof value === "number")
|
|
7
|
+
return value;
|
|
8
|
+
if (typeof value === "string") {
|
|
9
|
+
const trimmed = value.trim();
|
|
10
|
+
if (trimmed === "")
|
|
11
|
+
return null;
|
|
12
|
+
const parsed = trimmed.includes(".") ? Number.parseFloat(trimmed) : Number.parseInt(trimmed, 10);
|
|
13
|
+
return Number.isNaN(parsed) ? value : parsed;
|
|
14
|
+
}
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* 범위 필터 — `between`(열림) / `betweenInclusive`(닫힘) / `outsideRange`.
|
|
19
|
+
*
|
|
20
|
+
* 백엔드 `NumberFilter.apply` 의 한쪽-경계 규칙을 따른다:
|
|
21
|
+
* 하한만 있으면 `>= lo`, 상한만 있으면 `<= hi` (열림/닫힘 무관).
|
|
22
|
+
* `outsideRange` 는 두 경계가 **모두** 있어야 뜻이 정해지므로 하나라도 비면 전행 통과.
|
|
23
|
+
*/
|
|
24
|
+
export function matchRange(cellValue, filterValue, operator) {
|
|
25
|
+
if (!Array.isArray(filterValue))
|
|
26
|
+
return true;
|
|
27
|
+
const [rawLo, rawHi] = filterValue;
|
|
28
|
+
const loEmpty = isEmptyBound(rawLo);
|
|
29
|
+
const hiEmpty = isEmptyBound(rawHi);
|
|
30
|
+
if (operator === "outsideRange") {
|
|
31
|
+
if (loEmpty || hiEmpty)
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
else if (loEmpty && hiEmpty) {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
if (cellValue === null || cellValue === undefined || cellValue === "")
|
|
38
|
+
return false;
|
|
39
|
+
if (operator === "outsideRange") {
|
|
40
|
+
return compareValues(cellValue, rawLo) < 0 || compareValues(cellValue, rawHi) > 0;
|
|
41
|
+
}
|
|
42
|
+
// 한쪽만 있으면 열림/닫힘 구분 없이 포함 비교 (백엔드와 동일)
|
|
43
|
+
if (loEmpty || hiEmpty) {
|
|
44
|
+
if (!loEmpty)
|
|
45
|
+
return compareValues(cellValue, rawLo) >= 0;
|
|
46
|
+
return compareValues(cellValue, rawHi) <= 0;
|
|
47
|
+
}
|
|
48
|
+
if (operator === "between") {
|
|
49
|
+
return compareValues(cellValue, rawLo) > 0 && compareValues(cellValue, rawHi) < 0;
|
|
50
|
+
}
|
|
51
|
+
return compareValues(cellValue, rawLo) >= 0 && compareValues(cellValue, rawHi) <= 0;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* 숫자 NULL 필터. 값이 `false` 면 방향이 뒤집힌다
|
|
55
|
+
* (텍스트 `empty` 와 같은 boolean 방향 규약).
|
|
56
|
+
*/
|
|
57
|
+
export function matchIsEmpty(cellValue, filterValue) {
|
|
58
|
+
const isNull = cellValue === null || cellValue === undefined;
|
|
59
|
+
return filterValue === false ? !isNull : isNull;
|
|
60
|
+
}
|
|
61
|
+
/** 단일 값 비교 — 백엔드 `NumberFilter` 의 스칼라 분기 */
|
|
62
|
+
export function matchNumber(cellValue, filterValue, operator) {
|
|
63
|
+
if (operator === "isEmpty")
|
|
64
|
+
return matchIsEmpty(cellValue, filterValue);
|
|
65
|
+
if (operator === "between" || operator === "betweenInclusive" || operator === "outsideRange") {
|
|
66
|
+
return matchRange(cellValue, filterValue, operator);
|
|
67
|
+
}
|
|
68
|
+
// 리스트가 오면 첫 값을 쓴다 (백엔드와 동일)
|
|
69
|
+
const raw = Array.isArray(filterValue) ? filterValue[0] : filterValue;
|
|
70
|
+
if (cellValue === null || cellValue === undefined)
|
|
71
|
+
return false;
|
|
72
|
+
const cmp = compareValues(cellValue, raw);
|
|
73
|
+
switch (operator) {
|
|
74
|
+
case "notEquals": return cmp !== 0;
|
|
75
|
+
case "lessThan": return cmp < 0;
|
|
76
|
+
case "lessThanOrEqualTo": return cmp <= 0;
|
|
77
|
+
case "greaterThan": return cmp > 0;
|
|
78
|
+
case "greaterThanOrEqualTo": return cmp >= 0;
|
|
79
|
+
case "equals":
|
|
80
|
+
default: return cmp === 0;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { RowData } from "@tanstack/react-table";
|
|
2
|
+
import type { TableColumnDef } from "../types/column";
|
|
3
|
+
import type { FilterOperator } from "../types/operators";
|
|
4
|
+
/**
|
|
5
|
+
* 필터를 고르는 기준이 되는 데이터 종류.
|
|
6
|
+
* 백엔드는 SQLAlchemy 컬럼 타입(`path_info.column_type`)으로 고르는데,
|
|
7
|
+
* 클라이언트의 대응물은 `meta.dataType` 이고 없으면 `filter.variant` 로 유추한다.
|
|
8
|
+
*/
|
|
9
|
+
export type DataKind = "number" | "date" | "boolean" | "relation" | "text";
|
|
10
|
+
export declare function isVirtualColumn<T extends RowData>(column?: TableColumnDef<T>): boolean;
|
|
11
|
+
export declare function resolveDataKind<T extends RowData>(column?: TableColumnDef<T>): DataKind;
|
|
12
|
+
export interface MatchContext {
|
|
13
|
+
/** 상대 기간(`inPeriod`) 해석 기준 시각. 테스트에서 고정한다 */
|
|
14
|
+
now?: Date;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 컬럼 필터 하나를 행에 적용한다.
|
|
18
|
+
*
|
|
19
|
+
* 분기 순서는 백엔드 `_apply_filter_by_type` 을 그대로 따른다 —
|
|
20
|
+
* 순서가 어긋나면 같은 요청이 client/server 에서 다른 결과를 낸다.
|
|
21
|
+
* (예: `between` 은 숫자·날짜·리스트 셋 다 지원하므로 컬럼 종류가 먼저 결정돼야 한다)
|
|
22
|
+
*/
|
|
23
|
+
export declare function matchColumnFilter<T extends RowData>(row: unknown, columnId: string, filterValue: unknown, operator: FilterOperator, column?: TableColumnDef<T>, ctx?: MatchContext): boolean;
|