|
| 1 | +--- |
| 2 | +"@objectstack/spec": minor |
| 3 | +--- |
| 4 | + |
| 5 | +feat(spec): a stored record-form `filter` at the converged rule-array doors is converted to the rule array wherever the mapping is lossless — the ADR-0087 D2 conversion `page-component-filter-record-to-rule-array` (#17321, ruling B) |
| 6 | + |
| 7 | +The one-filter-orthography convergence moved every page-component `filter` door onto the |
| 8 | +`ViewFilterRule` array and refused the MongoDB-style record it used to take — but converted |
| 9 | +nothing at rest. A page saved with the old form kept rendering, and the next person to open it |
| 10 | +in the builder and press Save was refused. This release adds the mechanical half. |
| 11 | + |
| 12 | +**What converts** — at `dataSource.filter` on any page component, at `properties.filter` on the |
| 13 | +`object-grid`, `object-metric`, `object-kanban`, `object-calendar`, `object-map`, `object-gantt`, |
| 14 | +`object-tree`, `object-timeline`, `element:number` and `element:record_picker` blocks, and at |
| 15 | +`properties.defaultFilters` on `object-grid`: |
| 16 | + |
| 17 | +| Stored | Becomes | |
| 18 | +| --- | --- | |
| 19 | +| `{ status: 'active' }` | `[{ field: 'status', operator: 'equals', value: 'active' }]` | |
| 20 | +| `{ amount: { $gt: 100 } }` | `[{ field: 'amount', operator: 'greater_than', value: 100 }]` | |
| 21 | +| `{ amount: { $gte: 1, $lte: 9 }, owner_id: 'u1' }` | three rules — they AND | |
| 22 | +| `[['owner_id', '=', '{current_user_id}']]` | `[{ field: 'owner_id', operator: 'equals', value: '{current_user_id}' }]` | |
| 23 | +| `{}` | `[]` | |
| 24 | + |
| 25 | +Values are carried verbatim, value placeholders and date macros included. The operator comes |
| 26 | +from the two tables the doors already use — a declared FilterCondition operator (`$gt`, `$nin`, |
| 27 | +`$notContains`, …) folded through `normalizeFilterOperator`, and an AST infix spelling (`=`, |
| 28 | +`!=`, `>=`, …) lowered through `parseFilterAST` — and every produced rule must parse at the |
| 29 | +door, so a converted page re-saves cleanly. |
| 30 | + |
| 31 | +**Where it runs.** On every stored-row read (`applyConversionsToStoredItem` replays it), so |
| 32 | +the metadata API already serves such a page in the rule-array form; `os migrate meta --stored --apply` |
| 33 | +persists it; `os migrate meta --from 17` lists the edits for author sources. It is retired from |
| 34 | +the authoring load path, so `defineStack` / `os validate` still refuse an author who writes the |
| 35 | +record form and teach the rule array — no accept-set change. |
| 36 | + |
| 37 | +**What is left exactly as stored.** A filter carrying `$and` / `$or` / `$not` is never |
| 38 | +flattened: the rule array only ANDs, and flattening `$or` or `$not` changes which rows the page |
| 39 | +selects. So is any filter with a part that has no lossless rule spelling — a `null` value (the |
| 40 | +renderer skips that key today, where a rule would test IS NULL), `$null` / `$exists`, an AST |
| 41 | +`like` / `ilike`, an array or object comparand in equality position, an AST `and` / `or` group. |
| 42 | +Conversion is all-or-nothing per filter: converting the mappable keys and dropping the rest |
| 43 | +would widen the filter. And every filter — the binding's included — of a component whose rows |
| 44 | +are **inline** (`data: { provider: 'value', … }`, a `data` array, or `staticData`) is left as |
| 45 | +stored: the `object-map`, `object-tree`, `object-calendar` and `object-gantt` renderers match |
| 46 | +that filter against their own rows in an in-memory data source that reads the record form but |
| 47 | +excludes every row for a rule array, so a rewrite there would empty the block. The same filter |
| 48 | +on a block that queries an object converts. Such a page keeps loading and rendering unchanged and is refused at its |
| 49 | +`filter` door on its next save — and for a combinator record that refusal no longer renders the |
| 50 | +combinator as a field (`{ field: '$or', … }`); it names the combinator and says why no rule |
| 51 | +spells it. `os migrate meta --stored` does not list these rows yet: a row the conversion leaves |
| 52 | +as stored reports there as already on protocol. |
0 commit comments