Conversation
…schema not a declaration
|
Closing this one — the extraction gap turned out to be a lens spelling problem, not a missing primitive. Sources already do value = id / label = name when declared on the referenced model (that is how |
Why
ruleSourceValuesanswers "which values does this rule name at each declared source". A source exists to supply a picker's vocabulary, so declaring one commits the lens to fetching that vocabulary.There was no way to ask the other question: which rows does this rule name? A rule can name a row whose option set is supplied out of band, or that is never offered in a picker at all. Asking it through
sourcesforced a scan nobody wanted — in our case aDISTINCTover a very large table, returning unlabelled uuids and only rows someone had already touched.Consumers were working around this with hand-written tables of "which picks are references", which drift from the schema.
What
ruleReferences(lens, rule)— the rows a rule names, derived from the field map, declared by nobody:fromFields)toFields)Both facts the map already carries, so no lens author restates them.
Policy stays with the caller: every foreign key answers, including tenant keys and owner back-pointers. Filter by
referencedModel.Refactor, not duplication — the leaf walk (path resolution, scope refs, literal extraction, dedupe,
dynamic) moved to an internalruleLeafValuestaking a gate callback.ruleSourceValuesnow sits on it. One walker, two consumers; that is the −119.Edge cases handled
FieldMapviaWeakMap; the identity scan is O(models × fields) and this runs on every save.dynamicis reported the same wayruleSourceValuesdoes: abind/pathvalue or a non-enumerating operator means the rows cannot be listed. An emptyvaluesdoes not mean "references nothing".Testing
.d.tsagainstmain—REMOVED: none,ADDED: RuleReference, ruleReferences; theRuleSourceValuestype is byte-identicalMinor bump: 2.23.0 → 2.24.0.