feat(tables): expand filter operators (not-contains, starts/ends-with, not-in, empty)#4827
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
PR SummaryMedium Risk Overview New operators: case-insensitive SQL behavior: pattern ops share an Filter builder fixes: multiple AND rules on the same column merge into one operator object (e.g. age range) instead of the last rule overwriting. Tests cover SQL generation and converter round-trips for the new operators and merge behavior. Reviewed by Cursor Bugbot for commit 8c41203. Configure here. |
Greptile SummaryThis PR wires five new filter operators (
Confidence Score: 5/5This PR is safe to merge. All new operators are validated through the existing field-name and operator allowlists before reaching the SQL builder, and the empty-pattern and non-boolean operand guards follow the same defensive pattern already used for range and The implementation is complete and internally consistent across all layers: SQL builder, converter, UI, types, tools, and docs. The same-column AND merge fix is correct and tested. The No files require special attention. The converter and SQL builder changes are the most complex, but both are well-tested by the new test suites. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
UI["Filter UI (table-filter.tsx)"]
CONV["filterRulesToFilter (converters.ts)"]
SQL["buildFilterClause (sql.ts)"]
DB[(PostgreSQL JSONB)]
UI -->|"FilterRule[]"| CONV
CONV -->|"Filter object"| SQL
CONV -->|"isEmpty/isNotEmpty → {$empty: bool}"| SQL
CONV -->|"contains/ncontains/startsWith/endsWith → {$op: string}"| SQL
CONV -->|"in/nin → {$op: array}"| SQL
CONV -->|"same-column AND → mergeConditions()"| CONV
SQL -->|"$contains / $ncontains → buildLikeClause()"| BL["ILIKE / NOT ILIKE\n(empty-pattern rejection)"]
SQL -->|"$startsWith → buildLikeClause('startsWith')"| BL
SQL -->|"$endsWith → buildLikeClause('endsWith')"| BL
SQL -->|"$empty → coerceEmptyFlag() → buildEmptyClause()"| BE["IS NULL OR = ''\nIS NOT NULL AND <> ''"]
BL --> DB
BE --> DB
FTRULES["filterToRules (converters.ts)"]
DB -->|"stored Filter"| FTRULES
FTRULES -->|"$empty: true → isEmpty\n$empty: false → isNotEmpty"| UI
FTRULES -->|"$startsWith/etc → op.substring(1)"| UI
Reviews (2): Last reviewed commit: "feat(tables): expand filter operators (n..." | Re-trigger Greptile |
145e18c to
5d81d54
Compare
…, not-in, empty) Add does-not-contain ($ncontains), starts-with ($startsWith), ends-with ($endsWith), not-in-array ($nin, previously executed server-side but unexposed in the UI), and is-empty/is-not-empty ($empty) filter operators end-to-end — SQL builder, condition types, query-builder converters/constants, the filter UI, the Table tools/block descriptions, and docs. Also fix correctness bugs in the filter builder surfaced by the wider operator set: - Same-column AND rules (e.g. age > 18 AND age < 65, or name startsWith 'A' AND name endsWith 'Z') silently overwrote each other because the AND group was keyed by column name. They now merge into one operator object, which also makes Filter -> rules -> Filter round-trip losslessly for multi-operator columns. - $nin values were not split into an array like $in, and textual-match values like "123" were numeric-coerced (breaking the ILIKE path). - A non-boolean $empty operand from the raw API silently inverted the check; it now coerces 'true'/'false' strings and otherwise returns a 400.
5d81d54 to
8c41203
Compare
|
@greptile |
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 8c41203. Configure here.
Summary
$ncontains), starts with ($startsWith), ends with ($endsWith), not in array ($nin— already executed server-side but unexposed in the UI), and is empty / is not empty ($empty).ConditionOperatorstype, query-builder converters/constants, the filter UI (valueless operators hide the value input), the Table tools/block descriptions, and docs.age > 18 AND age < 65, orname startsWith 'A' AND name endsWith 'Z') silently overwrote each other. They now merge into one operator object, which also makesFilter → rules → Filterround-trip losslessly for multi-operator columns.$ninvalues weren't split into an array like$in, and textual-match values like"123"were numeric-coerced (breaking the ILIKE path).$empty: a non-boolean operand from the raw API silently inverted the check; it now coerces'true'/'false'strings and otherwise returns a 400.Type of Change
Testing
Added unit tests for the SQL builder (each pattern operator, wildcard escaping,
$emptytrue/false + string coercion + non-boolean throw) and converter round-trips (per-operator serialization, same-column merge, bare-eq normalization, OR-boundary separation, lossless multi-operator round-trip). Note: this workspace has nonode_modules, so the suite runs in CI rather than locally.Checklist