feat: functional/expression indexes via override_expression - #153
Open
arreyder wants to merge 2 commits into
Open
feat: functional/expression indexes via override_expression#153arreyder wants to merge 2 commits into
arreyder wants to merge 2 commits into
Conversation
Add an `override_expression` field to the `pgdb.v1.MessageOptions.Index`
option. When set, it replaces the "(column, ...)" body of the generated
CREATE INDEX with raw SQL, enabling functional/expression indexes — e.g. a
btree over a JSONB path:
option (pgdb.v1.msg).indexes = {
name: "primary_owner"
method: INDEX_METHOD_BTREE
partial_deleted_at_is_null: true
override_expression: "tenant_id, ((\"pb$role_to_entitlement_id\" ->> 'primary'))"
};
The DDL renderer already honored Index.OverrideExpression (HNSW vector
indexes use it); this exposes it to proto authors for any index method.
`columns` is ignored for DDL when an override is set, matching the vector
precedent. Partial predicates (partial_deleted_at_is_null) still apply.
Also escape the emitted OverrideExpression literal with %q in the descriptor
template. It was previously interpolated unescaped, which produced invalid Go
("missing ',' in composite literal") for any expression containing a quoted
identifier. Vector overrides never tripped this; expression indexes do.
Adds a Pet example index and a DB-free regression test asserting the rendered
DDL.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…visible test
Review follow-ups to the override_expression feature:
- Physical columns are ALL pb$-prefixed (including tenant_id/deleted_at), so
the example override and the doc comment were wrong — bare `tenant_id`
generates `column "tenant_id" does not exist`. Corrected to "pb$tenant_id"
and fixed the proto doc ("system columns are bare" was false).
- Reject bit_hamming_ops + override_expression together (both write
OverrideExpression; silent last-writer-wins). This also removes the
Columns[0] out-of-range path for an override-only index with no columns.
- Add a renderer-level index2sql test in pgdb/v1 (the root module CI actually
runs; the example/ module is a nested module excluded by `go test ./...`).
- Update TestSchemaPet migration count (dropping pb$profile now cascades to
two dependent indexes, not one).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
What & why
Adds an
override_expressionfield to thepgdb.v1.MessageOptions.Indexoption so proto authors can declare functional/expression indexes — e.g. a btree over a JSONB path. Today the only way to index a value derived from a JSONB/proto-map field is to denormalize it into a real column (proto field + write-path + backfill migration + Dynamo re-mirror). This exposes a capability the DDL layer already has.Motivating case:
SearchUserOwnershipfilters(role_to_entitlement_id ->> 'primary') IN (...)with no serving index (the only index on that column is GIN/containment). With this, the fix is one index declaration:How
index2sqlalready rendersIndex.OverrideExpressionverbatim (HNSW vector indexes use it). This just threads the new proto field throughextraIndexesinto that existing path. When set,columnsis ignored for DDL (matching the vector precedent);partial_deleted_at_is_nullstill applies.OverrideExpressionunescaped ("{{ .DB.OverrideExpression }}"). Any expression containing a quoted identifier produced invalid Go (missing ',' in composite literal). Now emitted via%q. Vector overrides never tripped this (no quotes); expression indexes do.Author contract
The override body is emitted verbatim, so it carries physical column tokens: proto fields are
pb$-prefixed and quoted, system columns are bare — same convention the vector overrides already use.Validation
TestIndexOverrideExpression) asserts the renderedCREATE INDEX(verbatim body + preserved partial predicate).TestSchemaPetnow exercises the newPetfunctional index against a real Postgres.Index Scan).Diff shape
Core change is ~16 lines (proto field + one passthrough + template escape). The rest is regenerated
.pb.go/ example output.🤖 Generated with Claude Code