Repository navigation
Support composite primary keys in search scopes - #601
Merged
Merged
Conversation
There was a problem hiding this comment.
🟢 Approval recommended
Static review found no blocking issues, and focused regression examples cover the changed behavior; runtime tests were not executed.
0 open findings
What changed in this PR
Adds composite primary-key support to pg_search_scope, addressing #531 while leaving multisearch unchanged.
Changes:
- Uses every key column for rank joins and default tie ordering.
- Updates association subqueries to join and group by all key columns.
- Adds regression examples and documents the support contract.
| File | Description |
|---|---|
| spec/integration/composite_primary_key_spec.rb | Tests composite-key searches, ordering, and associations. |
| lib/pg_search/scope_options.rb | Projects, joins, and orders all primary-key columns. |
| lib/pg_search/configuration/association.rb | Handles multiple keys in association joins and grouping. |
| doc/plans/2026-10-14-composite-primary-keys.md | Documents scope, limitations, and verification plans. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Merge #537 onto master, which moved scope SQL construction to Arel after the pull request branched. Rebuild its composite-key rank subquery, rank join, and default order within rank as Arel expressions, and apply the module-inclusion spacing required by the current Standard.
Model the examples on books keyed by author and number, letting Rails infer the composite key from the schema. Give the keys a shared leading column so a rank join or ordering on only part of the key fails.
Searching associated_against from a composite-key model selected, grouped, and joined the association subquery on the inspected key Array, which PostgreSQL rejects as a missing column. Give each key column its own subquery alias and join on all of them. Association#to_arel now takes the key attributes as arguments. Its remaining caller passes Arel attributes, so drop the orphaned trusted SQL String coercion.
nertzy
force-pushed
the
composite-primary-keys
branch
from
October 16, 2026 21:11
a4235e6 to
fa4816f
Compare
Association#to_arel took the model's primary-key attributes from its only caller, though the association already holds the model. It now derives them itself and selects and joins the primary-key columns under their own names: the subquery's other columns carry hashed pg_search aliases, so the id_N aliases guarded against no collision.
nertzy
force-pushed
the
composite-primary-keys
branch
from
October 16, 2026 21:42
cdd25f8 to
9d89474
Compare
Association#to_arel built its subquery and ON condition in locals. Both now live in private methods. The subquery is memoized, so the condition's column references do not rebuild its relation.
ScopeOptions built its rank key selects, rank join condition, and primary-key attributes inline. Each now has a named private method, matching Association#primary_keys.
The rank subquery is joined into the caller's query, so its key columns need aliases that cannot collide with unqualified user SQL or with the rank column. Hashed Configuration aliases do that for single and composite keys alike, replacing the pg_search_id and pg_search_id_N branches. Chained scopes stay distinct because each rank subquery has its own counted table alias.
The composite-key helpers grew endless methods past 80 columns, most wrapping a block. Give them conventional def/end bodies.
index_by states the alias-to-attribute mapping directly instead of building pairs for to_h.
nertzy
force-pushed
the
composite-primary-keys
branch
from
October 16, 2026 21:54
9d89474 to
ad65b30
Compare
2 tasks done
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.
Supersedes #537 by @causztic and keeps their commits. Fixes #531.
On a model with a composite primary key,
pg_search_scopesent the key Array to SQL as a single quoted column name, so PostgreSQL rejected the query. The scope now projects, joins, groups, and orders by each primary-key column:pg_search_…alias, for single and composite keys alike, so it cannot collide with an unqualified column in the caller's SQL or with therankcolumn. This replaces the undocumentedpg_search_idalias; a GitHub code search found no code that depends on it.associated_against: the association subquery selects and groups by every key column of the searching model and joins on all of them. Searching through an association to a composite-key model already worked once the rank join was fixed, because Rails builds that association join itself.#537 was written against the string-built SQL, which master has since replaced with Arel. The merge commit rebuilds its changes as Arel expressions. Later commits simplify the spec fixtures, add composite-key support for associations searched from a composite-key model, which #537 deferred, and credit the change to yaojie in the changelog.
Association#to_arelnow reads the key columns from its own model instead of taking them as arguments, and its subquery keeps their column names rather than aliasing them.Multisearch is unchanged.
pg_search_documents.searchable_idholds a single value, and Rails already raisesCompositePrimaryKeyMismatchErrorfor the polymorphic association on a composite-key model.