Expand description
Multi-step (via) has_many relations: a has_many reached by following a
path of existing relations rather than a single foreign key.
The shape under test is User → Comment → Article: a user has many
comments, each comment belongs to an article, so a user has many
commented_articles via comments.article.
Functions§
- eager_
scalar_ via_ auto_ loads - A non-deferred scalar via (
tag_names: Vec<String>, noDeferred) is an eager relation edge: querying the parent auto-loads the projected terminal values without an explicit.include(). Every other via scenario wraps the field inDeferred, so this is the only test exercising theViaManyField for Vec<E>(DEFERRED = false) impl and via auto-loading. The load groups per user and collapses duplicate values, like the explicit.include()paths. - filter_
parent_ by_ via_ any .any()on aviafield filters parent records through the expanded relation path. The same predicate works when the path contains anotherviafield.- include_
via_ has_ one .include()of ahas_one(single-result)viarelation:User→Account→Subscription, both stepshas_one. The via target is a single record, so this exercises thequery.singlebranch of via-include lowering that the all-has_manyscenarios never reach. TheINNER JOINdrops a parent whose chain is incomplete at either step, so a missing leaf and a missing intermediate both surface asNone.- include_
via_ nested_ via .include()over a via-of-via:User::nested_todosreaches todos throughorganizations.todos, whereOrganization::todosis itself a via. The outer path’s second step expands into a nested via during lowering, so this exercises recursive via flattening. The result must match the flat 3-stepUser::todosinclude ininclude_via_three_stepexactly — same data shape, same expected grouping.- include_
via_ three_ step .include()over a 3-stepvia: User → Organization → Project → Todo, allHasManysteps. Verifies that the child query joins every intermediate and groups todos by the root user.- include_
via_ three_ step_ no_ intermediates - A user with no intermediates yields an empty included set — the
INNER JOINexcludes them but the parent row is still returned. - include_
with_ newtype_ foreign_ key - A nullable one-field newtype foreign key uses its leaf column rather than its presence-guarded embed expression when preloading a via relation.
- include_
with_ unit_ enum_ foreign_ key - A unit enum key and foreign key link through the enum’s discriminant column when preloading a via relation.
- query_
and_ include_ two_ step_ targets_ and_ values - Querying and including a two-step
viareturns distinct target models and scalar terminal values, grouped by parent for includes. - query_
chain_ scalar_ via - A scalar-terminal
viacan also be navigated off a query (not just a loaded instance):User::filter(…).article_titles()yields the distinct titles reachable from the matched users. - query_
scalar_ via_ two_ step - A 2-step scalar via (
comments.body): the terminal field sits directly on the first relation’s target, so the relation chain is a single step ([comments]) — the minimal scalar-via walk, distinct from the 3-stepcomments.article.title. Distinct values still apply, so a body repeated across comments appears once. Navigation and.include()must agree. - query_
with_ no_ intermediates_ is_ empty - A user with no comments reaches no articles — an empty result, no error.
- scalar_
via_ distinct_ values_ across_ distinct_ targets - Pins the distinct values decision against the alternative (distinct
targets). The case that tells them apart is a user commenting on two
different articles that happen to share a title: the model-via reaches two
distinct targets, but the scalar via collapses their equal terminal values
to one —
["Rust"], not["Rust", "Rust"]. - scalar_
via_ of_ via - A via-of-via with a scalar terminal:
nested_todo_titlesroutes throughorganizations.todos— whereOrganization::todosis itself a via — then projectsTodo::title. This drives the nested-via splice (flatten_via_steps/RewriteVia) on the scalar-terminal code paths, which the model via-of-via (include_via_nested_via) leaves untested. Distinct values still apply, so a title shared by todos in different orgs collapses to one. Navigation and.include()must agree. - select_
scalar_ via .select()of a scalar-terminalviareturns the projected titles per parent row.- select_
via_ has_ one .select()of a single (has_one)viarelation. Likeinclude_via_has_onethis drives thequery.singlevia path, but through.select(), which projects each parent straight to its target rather than into a record slot. The missing-row path is already covered by the include test, so this focuses on a matched chain returning the target.- select_
via_ two_ step .select()of a multi-stepviarelation..select()and.include()share the via-JOIN child query (build_relation_subquery); the difference is that.select()uses the subquery as the whole projection (each parent row decodes to its ownVec<Article>) rather than splicing it into a record slot. Distinct targets still apply, so Rust appears once though commented twice.- via_
relation_ query_ can_ be_ filtered - A
viarelation query can be further filtered, like any other relation query.