Repository navigation
Resolve joined table aliases in where() and orderby() at query time - #23
Closed
robinvandernoord wants to merge 4 commits into
Closed
robinvandernoord wants to merge 4 commits into
robinvandernoord wants to merge 4 commits into
Conversation
…ery runs A builder that is returned and extended later can't use condition_and anymore, and a plain where() on a joined table used to raise AliasedTableMismatchError. Fields of a table that is joined under exactly one alias are now pointed at that alias in where/orderby/groupby/having, at collect time, so where().join() and join().where() behave the same. - A table joined more than once still raises; pick the join with a lambda whose extra arguments name the relationship (`where(lambda article, reviewer: ...)`, nested as `parent__child`). These lambdas are resolved at collect time too. - The limitby id subquery and count() include the left joins the predicate filters on, so pagination and counts match the rows. - The distinct-ids pagination subquery names its id column, which no longer collides with an ordered-by id of a joined table. - delete()/update() refuse relationship lambdas instead of dropping them. - Cache keys use relationship paths instead of per-process alias hashes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FXZN6UgVPuRxvHzMMTShAE
- A nested relationship to the root table (`Article.join("writer.articles")`)
renamed the root's own select fields to the nested alias, so collecting
raised KeyError. It is now aliased upfront like a self-reference.
- Nested relationships lost every row after the first one: once a parent
instance was seen, later rows (e.g. an article's second comment) were
skipped before their nested data was read. Rows reached through
different parents also shared one dedup set keyed by the nested row's
id. Dedup is now per parent instance, and a seen instance still takes
nested data from later rows.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FXZN6UgVPuRxvHzMMTShAE
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.
Summary
This PR enables filtering and ordering on joined relationship tables by resolving their aliases at query execution time. Previously, filtering on a joined table would raise
AliasedTableMismatchErrorbecause the table reference didn't match the aliased table in the SQL. Now, field references to joined tables are automatically rewritten to point to their aliases, and lambda-based filters can request joined tables by name.Key Changes
Deferred query resolution: Added
deferred_queriestoQueryBuilderto storewhere()calls with lambdas that request joined tables. These are resolved when the builder executes, after all joins are known.Lambda argument binding: Implemented
_requested_tables()to inspect lambda signatures and extract which joined tables they request by parameter name. Supports nested relationships with__notation (e.g.,articles__comments).Alias rewriting: Added
_rewrite_tables()to recursively rewrite field references in queries, expressions, and orderby/groupby clauses to point to their aliased tables instead of the original table names.Join tracking: New
_JoinedTabledata structure and_joined_tables()method to collect all joined relationships with their aliases and metadata._alias_rewrites()maps original table names to their single alias (when unambiguous).Ambiguity detection: Enhanced
_validate_joins()to detect when the same table is joined multiple times under different aliases and require the user to disambiguate using lambda arguments.Mutation safety: Added
_mutation_query()to preventdelete()andupdate()from using deferred where() lambdas, since mutations ignore joins and would delete/update more rows than intended.Pagination support: Updated
_apply_limitby_optimization()to include required left joins in the ID subquery, ensuring pagination works correctly with joined table filters.Cache key stability: Implemented
_cache_key_query()to replace per-process alias hashes with relationship paths in cache keys, making caches stable across process restarts.Notable Implementation Details
where()comes before or afterjoin(), since it happens at execution time.post__writer__articles) and unambiguous short names (articles).on=relationship type (which joins without an alias) is excluded from rewriting, keeping the original table name.https://claude.ai/code/session_01FXZN6UgVPuRxvHzMMTShAE