Skip to main content

Module relation_chain_composite_key

Module relation_chain_composite_key 

Source
Expand description

Chain relation methods on Many where one or more hops in the chain has a composite key. Parallels crate::tests::relation_chain which covers the all-single-key case.

Two positions are interesting:

  • A BelongsTo second hop whose foreign key spans multiple columns.
  • A HasMany first hop whose paired BelongsTo on the target has a composite foreign key.

The shared scenario crate::scenarios::composite_chain_relations arranges User → Todo → Category so both positions are reachable from a single dataset: Category has composite PK (id, revision) and Todo’s FK to it spans (category_id, category_revision). The Todo→User FK is single-column, so category.todos().user() cross-checks that a composite first hop chains cleanly into a single-column second hop.

Functions§

category_todos_filter
A category.todos() chain that ends in .filter(...) narrows the terminal model the same way as in the single-key chain tests. This pairs with composite_chain_then_filter (which exercises the second-hop composite case) to make sure both endpoints respect filters.
category_todos_respects_revision
Category(id=X, revision=1) and Category(id=X, revision=2) are two distinct categories. The chain starting at one must not pick up the other’s todos — the filter has to discriminate on both FK columns.
category_todos_user_composite_first_hop
Chain starting at a model with a composite PK. The first hop’s pair (Todo’s belongs_to back to Category) is composite, so the filter generated for Todo.category_id must include both category_id and category_revision.
composite_chain_from_empty_source_is_empty
A chain whose source produces no rows (user has no todos) must short-circuit to an empty result, even when there is unrelated data of the matching shape in the table.
composite_chain_then_filter
Filter applied to the chain’s terminal model narrows the chain’s result. Mirrors relation_chain::chain_then_filter but the terminal model has a composite PK.
composite_has_many_through_has_many
Author → posts → comments with composite keys on Author and Post. The chain involves two HasMany hops, each producing an IN-subquery against a composite-FK pair. Mirrors relation_chain::has_many_through_has_many.
filtered_category_todos_user_composite
Category::filter(name = ...).todos().user() — the chain’s source query is filtered by a non-FK column (name). The fallback path inside lift_belongs_to_in_subquery (which can’t lift the filter onto FK columns) must still produce a working composite-FK IN subquery rather than panicking on todo!("composite keys").
user_todos_category_composite
Happy path mirroring relation_chain::user_todos_category but the Todo → Category belongs_to spans (category_id, category_revision). The result must dedupe on the composite key, not just on id.
user_todos_category_distinguishes_by_revision
Two Categories that share id but differ in revision must both come back as distinct rows from a chain query. This protects against a regression where the IN-subquery was generated over category_id only, silently merging different revisions.