Repository navigation
Conversation
…own alias A <HasMany> with filter, orderBy, limit or offset collected its children through the collector's map(), which wrote them into the plain relation as well. The query therefore carried the whole relation with the children's fields next to the parameterised subquery, and at render the HasMany read the plain relation: the list it showed ignored its parameters. SelectionScope now keeps a has-many read with parameters as its own child keyed by the params alias, and the collector hands <HasMany> an item over that child, in every collection path including a component's implicit one. At render, HasMany resolves its params alias through the parent entity (HAS_MANY_ALIAS_RESOLVER) and reads the data fetched under it. The compiled field-map format has no params, so the compiler now bails on any parameterised <HasMany> (HASMANY_PARAMS), not only in an <Entity> root. Fixes #158
…t, and fall back when unfetched The resolver now declares the alias's view membership like the fields getter does, so an orderBy-only <HasMany> keeps showing items added to the relation. It returns nothing for an alias the parent's selection did not fetch, and <HasMany> then reads the field as given. The compiler also bails on a <HasMany> with spread props, which may carry params, and a has-many child merged with totalCount keeps it.
…ection HasManyDataGrid rows are entity handles without a selection, so the resolver could not find the alias and the HasMany read the plain relation, which now carries only ids. The resolver takes the params, computes the alias itself and, without a selection, returns the alias handle with its view membership derived from the params.
…o data under the alias In create mode, and on any entity without a selection whose alias was never fetched, the alias view fell back to the plain relation's server data but was declared partial, so items added to the relation never showed in a filtered or limited list. Without a selection the resolver now returns the alias handle only when the entity's data holds the alias.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #158. Also item 2 of
docs/issues/036-jsx-conditional-underselection-and-overfetch.md.Problem
<HasMany filter|orderBy|limit|offset>collected its children through the collector'smap(), which wrote them into the plain relation as well as returning the parameterised alias. So:HasManyImplread the field it was given, andEntityHandle.resolveSelectionFieldprefers the direct plain field over the alias — the list ignored its parameters (filter={{ name: { eq: 'React' } }}renderedJavaScriptReact). The aliased subquery was fetched and never read.Inside a component the implicit collection path dropped the params alias altogether, so there only the plain relation existed.
Change
SelectionScope.hasManyChild(fieldName, params)keeps a parameterised has-many as its own child keyed by the params alias, next to the plain one;merge/mergeFromSelectionMeta/toSelectionMetacarry it. The collector ref exposesHAS_MANY_PARAMS_COLLECTOR, and<HasMany>with parameters collects its children through it — in every path (an<Entity>root, a component's implicit pass, nested). Without parameters nothing changes.HasManyListHandlecarriesHAS_MANY_ALIAS_RESOLVER, provided by the parentEntityHandle;<HasMany>computes its params alias and reads that list. The resolver declares the alias's view membership (as thefieldsgetter does), so an orderBy-only list keeps showing items added to the relation. For an alias the parent's selection did not fetch (auseEntitydefiner, params changed since collection) it returns nothing and<HasMany>reads the field as given, as onmain. An entity without a selection gets the alias handle only when its data holds the alias (aHasManyDataGridrow); otherwise, as in create mode, it keeps the field as given.<HasMany>, and on one with spread props (HASMANY_PARAMS, formerlyHASMANY_PARAMS_AT_ROOTfor roots only) and the runtime pass handles it. Dropped the now unusedisSelectionRootflag.Behaviour change
A filtered, limited or offset
<HasMany>now shows the filtered list, so an item added through the outer field (article.tags.add(…)) does not appear in it until it is persisted and refetched — the store's'partial'view semantics. Onmainit appeared only because the whole unfiltered list was rendered. An orderBy-only list keeps showing added items. In create mode nothing has been fetched, so a parameterised<HasMany>shows the relation as given, including added items, as onmain.Remaining
fieldsgetter onmainfor auseEntitydefiner whose params change.asalias in a fluent definer (.tags({ as: 'reactTags', filter }, …)) is still re-keyed to the generated alias when merged into a scope; onmainit was lost too.Reading
article.tagsat all still registers the plain relation withid(SelectionScope.childseeds it), so a filtered<HasMany>still fetches the relation's ids. Making that registration lazy would break plain runtime reads likearticle.tags.lengththat the collector does not see; left as is.Tests
tests/react/relations/hasMany/filteredHasManyFetchesUnfilteredRelation.test.tsx: children fields only under the alias (plain relation isidonly); a filtered list renders filtered; sibling<HasMany>s with different parameters each render their own list (these three fail onmain); an orderBy-only list keeps showing an added item; acreateComponentwith a filtered<HasMany>renders the filtered list; an entity handle without a selection (asHasManyDataGridbuilds its rows) renders the filtered list; in create mode a filtered and a limited list show an item added through the outer field.tests/selectionCollection.test.tsx: the inline<HasMany orderBy>case now looks the relation up under its alias.bun run test: 2531 pass.bun run typecheckclean.