Repository navigation
feat(data-blocks): per-property AND/OR mode + in-operator collapse - #1748
jwalkingjew wants to merge 1 commit into
Conversation
Replaces the global filter `mode` with per-property modes and collapses multi-value selections into single GraphQL `in` clauses where the schema supports it. Cuts GraphQL filter payloads, expresses "tagged with both X and Y" cleanly, and hides the toggle for value-typed groups where AND within a property has no representation on the wire. Why: - The single global `'AND' | 'OR'` toggle was the wrong granularity. Users want "type is Person OR Author, AND status is Active" — per-property OR with implicit AND between columns. The global mode couldn't express it. - Multi-value selections expanded to N nested `OR` clauses on the wire. The connection schema has `in` on every relevant scalar, so RELATION multi-select collapses to one `toEntity.id.in: [...]` clause and TEXT multi-select to one `text.inInsensitive: [...]` clause. What changed: - `experimental_query-layer.ts`: `NumberCondition.in: number[]`, `ValueCondition.dataType` discriminator so the converter can route to the right scalar field on `ValueFilter`. - `converters.ts`: `convertValueConditionToValueFilter` switches on `dataType` and emits `text.inInsensitive` / `integer.in` (BigInt strings) / `float.in` / `decimal.in` (BigFloat strings) / `datetime`, `date`, `time` (StringFilter `inInsensitive`) / `boolean.is`. The legacy `text`-fallback path is kept for callers that don't supply dataType. - `filters.ts`: persisted shape gains `modes: Record<columnId, 'AND' | 'OR'>`. Legacy top-level `mode` stays in the schema for read-time compat; the writer never emits it. Read-time migration: legacy `mode: 'OR'` fans out to every present property group; absent or `'AND'` => empty modes (per-group default at the WHERE-builder is OR, which collapses cleanly to `in`). Old blocks read fine; the next save rewrites in the new shape and the legacy keyword disappears. - `use-filters.ts`: replaced `filterMode` / `setFilterMode` (and temporary equivalents) with `modesByColumn` / `setGroupMode(columnId, mode)`. `setFilterState` trims mode entries for removed columns. - `use-data-block.tsx`: new `buildGroupWhere(filters, groupMode)` — RELATION + OR (or single) collapses to one `in` clause across relations / backlinks / types / spaces; AND keeps `AND-of-singles` so intersection semantics stay expressible. TEXT collapses to `inInsensitive` (or `name.in`). Numeric / date groups remain `OR-of-singles` — UI doesn't surface multi-value chips for them today, but the converter is ready when it does. - `table-block-filter-pill.tsx`: toggle hidden for non-relation groups. `FilterGroup` carries `isRelationGroup` so the pill knows. - `table-block.tsx` / `power-tools-screen.tsx` / `use-power-tools-data`: swap `setActiveFilterMode` closures for `setActiveGroupMode(columnId, next)` with per-group state. - `edit-types.ts` / `edit-dispatcher.ts` / chat `data-block.ts` write tool: `setDataBlockFilters` intent now carries `modesByColumn` instead of `mode`. Tool input schema accepts `modesByColumn?: Record<columnId, 'AND' | 'OR'>` (optional). Tests: 75/75 in touched files (converters + filters + edit-dispatcher + chat data-block tool). New cases for per-property mode round-trip, legacy fan-out, OR omission when default, scalar `in` routing per dataType, relation multi-value `in` collapse.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Closing as part of a sweep of the open-PR queue. Not a judgement on the work — reopen if you still want it and I will help get it current. Opened 2026-05-01 and now conflicting with master. At this distance a rebase is usually more work than redoing the change against current code, and the surrounding code has moved a long way underneath "feat(data-blocks): per-property AND/OR mode + in-operator collapse". @jwalkingjew — if the idea still stands but the branch does not, a fresh PR or a ticket is probably a better route than reviving this one. Nothing is discarded: the branch and its history remain, and reopening costs a click. Context: 74 PRs were open, 25 older than two months, the oldest from February. The point is to make the queue mean something so genuinely ready work is visible rather than buried — #2449 sat ready for three days this week partly because of the noise. Only non-draft, conflicting PRs are in scope; drafts and anything still mergeable are being left alone. |
Summary
modewith per-property modes (one AND/OR per column).inclauses: RELATION →toEntity.id.in, TEXT →text.inInsensitive, numeric/date filters route to the right scalar via a newdataTypediscriminator onValueCondition.dataType-aware scalar routing in the converter so future numeric / date / datetime UI lands without converter changes.mode: 'OR'fans out to every property group); next save writes the new shape only — no compat shim long-term.Why
'AND' | 'OR'toggle was the wrong granularity. Users want "type is Person OR Author, AND status is Active" — per-property OR with implicit AND between columns. The global mode couldn't express that.ORclauses on the wire (each its ownrelations.some {...}/values.some {...}). The schema hasineverywhere relevant, so a multi-value selection collapses to one clause — smaller payload, simpler filter, less work on the API.Architecture notes
buildGroupWhere(filters, groupMode)inuse-data-block.tsxreplaces the priorbuildSingleFilterWhere/buildOrWhere/buildAndWheretrio.WhereCondition(DSL) gainsValueCondition.dataTypeandNumberCondition.in. The localEntityQueryengine doesn't need updates for the dataType hint — the converter is the only consumer that uses it.modes: Record<columnId, 'AND' | 'OR'>and stops emitting the legacy top-levelmode. Schema keepsmodeoptional for read-time compat.'OR'(collapses cleanly toin); the persistedmodesmap only stores entries that diverge from default — keeps wire noise down.Out of scope (separate PRs)
isBacklinkround-trips through persistence + WHERE-builder + converter), but the picker has no path to add one. Tracked as PR B.ANDfor spaces. Kept OR-only (matches the top-levelspaceIds.inAPI shape).Test plan
relations.some.toEntity.id.in: [...](one clause), not nested OR.and: [{...}, {...}](one per chip). Results narrow to entities matching all values.inclause; the two clauses are AND'd between groups regardless of per-group toggle.text.inInsensitive: [...].mode: 'OR', multiple property groups). Renders correctly. Edit any chip → save. Reopen the entity values raw and confirm the persisted filter string now usesmodesand the legacymodekey is gone.modes[columnId]entries persist when the group goes empty.setDataBlockFilterswrite withmodesByColumn: { typeId: 'AND' }→ verify the persisted filter has the rightmodes.🤖 Generated with Claude Code