chore(ui): завершить миграцию Filters и удалить старый API
This commit is contained in:
1 parent
4fd844f977
commit
0d418e2e39
6 files changed
+37
-2025
No files matched your search
@@ -1,8 +1,6 @@
|
||||
import assert from "node:assert/strict"
|
||||
import { test } from "node:test"
|
||||
import { applyFilterQuery } from "./apply-filter-query"
|
||||
import { migrateFilterQuery } from "./migrate-filter-query"
|
||||
import { applyReuiFilters } from "./apply-reui-filters"
|
||||
import { createFilterQuery, createFilterRule } from "../../components/reui/filters/filters-query"
|
||||
|
||||
const rows = [{ country: "RU", status: "online" }, { country: "DE", status: "offline" }, { country: "NL", status: "offline" }]
|
||||
@@ -36,10 +34,17 @@ test("text prefix and suffix use case-insensitive matching and support negation"
|
||||
assert.deepEqual(applyFilterQuery(rows, createFilterQuery([{ ...rule("country", "starts_with", "r"), negated: true }]), accessors), rows.slice(1))
|
||||
})
|
||||
|
||||
test("migration preserves the existing operators and implicit AND", () => {
|
||||
for (const operator of ["is", "isNot", "isAnyOf", "isNotAnyOf", "contains", "doesNotContain"]) {
|
||||
const filters = [{ id: "country", field: "country", operator, values: ["RU", "DE"] },
|
||||
{ id: "status", field: "status", operator: "isNot", values: ["online"] }]
|
||||
assert.deepEqual(applyFilterQuery(rows, migrateFilterQuery(filters), accessors), applyReuiFilters(rows, filters, accessors))
|
||||
test("scalar operators keep their expected results when combined with AND", () => {
|
||||
const cases: [string, unknown, typeof rows][] = [
|
||||
["is", "RU", []],
|
||||
["is_not", "RU", [rows[1], rows[2]]],
|
||||
["is_any_of", ["RU", "DE"], [rows[1]]],
|
||||
["is_none_of", ["RU", "DE"], [rows[2]]],
|
||||
["contains", "e", [rows[1]]],
|
||||
["not_contains", "e", [rows[2]]],
|
||||
]
|
||||
for (const [operator, value, expected] of cases) {
|
||||
const query = createFilterQuery([rule("country", operator, value), rule("status", "is_not", "online")])
|
||||
assert.deepEqual(applyFilterQuery(rows, query, accessors), expected)
|
||||
}
|
||||
})
|
||||
@@ -1,40 +0,0 @@
|
||||
import type { Filter } from "@/components/reui/filters"
|
||||
|
||||
type FieldAccessor<T> = Record<string, (row: T) => unknown>
|
||||
|
||||
function matchFilter<T>(row: T, filter: Filter, accessors: FieldAccessor<T>): boolean {
|
||||
const getValue = accessors[filter.field]
|
||||
if (!getValue) return true
|
||||
|
||||
const value = getValue(row)
|
||||
const vals = filter.values
|
||||
const str = (v: unknown) => String(v ?? "").toLowerCase()
|
||||
|
||||
switch (filter.operator) {
|
||||
case "is":
|
||||
return vals.length > 0 && String(value) === String(vals[0])
|
||||
case "isNot":
|
||||
return vals.length === 0 || String(value) !== String(vals[0])
|
||||
case "isAnyOf":
|
||||
return vals.some((v) => String(value) === String(v))
|
||||
case "isNotAnyOf":
|
||||
return !vals.some((v) => String(value) === String(v))
|
||||
case "contains":
|
||||
return vals.some((v) => str(value).includes(str(v)))
|
||||
case "doesNotContain":
|
||||
return !vals.some((v) => str(value).includes(str(v)))
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
export function applyReuiFilters<T>(
|
||||
rows: T[],
|
||||
filters: Filter[],
|
||||
accessors: FieldAccessor<T>,
|
||||
): T[] {
|
||||
if (filters.length === 0) return rows
|
||||
return rows.filter((row) =>
|
||||
filters.every((f) => matchFilter(row, f, accessors)),
|
||||
)
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { createFilterQuery, createFilterRule } from "@/components/reui/filters/filters-query"
|
||||
|
||||
const OPERATORS: Record<string, string> = {
|
||||
is: "is", isNot: "is_not", isAnyOf: "is_any_of", isNotAnyOf: "is_none_of",
|
||||
contains: "contains", doesNotContain: "not_contains",
|
||||
}
|
||||
|
||||
/** Temporary input contract, independent of the old UI component. */
|
||||
export function migrateFilterQuery(filters: { id: string; field: string; operator: string; values: unknown[] }[]) {
|
||||
return createFilterQuery(filters.map(filter => {
|
||||
const operator = OPERATORS[filter.operator]
|
||||
if (!operator) throw new Error(`Неподдерживаемое условие: ${filter.operator}`)
|
||||
return createFilterRule({ id: filter.id, path: [filter.field], operator, value: filter.values })
|
||||
}))
|
||||
}
|
||||
Reference in new issue
Block a user