Skip to content

matview versioning v2, now with better index support - #560

Draft
MoralCode wants to merge 23 commits into
mainfrom
feat/version_matview_indexes
Draft

MoralCode wants to merge 23 commits into
mainfrom
feat/version_matview_indexes

Conversation

@MoralCode

@MoralCode MoralCode commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Description
This change is essentially a v2 of #292. It aims to address problems discovered in #449.

The previous system of matview versioning accepted a tuple of strings (unique_index_columns) that were turned into an CREATE INDEX SQL call. It was intended only for the columns that have unique indexes (i.e. a candidate key that allows for concurrent matview refresh to happen).

Some of the views coming in via #449 do not have candidate keys, or had their candidate keys removed in 8Knot. This (i believe since its been a while) is the main driving force behind needing a more robust materialized view versioning system that can support a wider range of index types.

Notes for Reviewers
this PR introduces yet another library - alembic_utils_extended (AUE), a fork of alembic_utils that can handle passing regular Sqlalchemy Index objects to materialized views.

It has a key weakness, which is that it only drops/recreates the matview when its definition changes. if only an index changes, then this is not detected.

When asking about this upstream, it seems as though the answer is to write a custom comparator, which this change also includes.

Testing

While this change includes unit tests for the new comparator, this still needs extensive testing to ensure it is reliable, since this is core data schema versioning functionality.

needed:

  • confirm that changes to the matview models are correctly detected and trigger a drop/replace migration (this should be built into the AUE library
    • with regeneration of indexes (unsure if this is AUE behavior)
  • confirm that index-only changes result in the index (and only the index) getting regenerated (custom comparator in this PR)

Other Todos:

  • confirm the source of the mismatch between my dev db and the data models to ensure we are making no changes to the DB/need no alembic migration

Signed commits

  • Yes, I signed my commits.

Generative AI disclosure

Please select one option:

  • This contribution was NOT assisted or created by Generative AI tools.
  • This contribution was assisted or created by Generative AI tools.

If AI tools were used, please provide details below:
- What tools were used? Sonnet 4.6 medium via cursor, GLM 5.3 Low/High via Claude Code CLI
- How were these tools used? Code edits and drafting of changes, writing unit tests
- Did you review these outputs before submitting this PR? The non-test code has been reviewed and manually edited as it was committed and also afterwards via additional commits.

step 1 of quickstart in the repo

Signed-off-by: Adrian Edwards <adredwar@redhat.com>
per step 2 of the quickstart

Signed-off-by: Adrian Edwards <adredwar@redhat.com>
Signed-off-by: Adrian Edwards <adredwar@redhat.com>
Signed-off-by: Adrian Edwards <adredwar@redhat.com>
Signed-off-by: Adrian Edwards <adredwar@redhat.com>
Signed-off-by: Adrian Edwards <adredwar@redhat.com>
Generated-by: Sonnet 4.6 medium
Signed-off-by: Adrian Edwards <adredwar@redhat.com>
Signed-off-by: Adrian Edwards <adredwar@redhat.com>
…l override

Signed-off-by: Adrian Edwards <adredwar@redhat.com>
changes made above what sonnet did:
- remove a numbered list from the docs and clean up the language a little
- change the with_data param to be an override for what we already defined on self, not a straight up setting of the value

Generated-by: Sonnet 4.6 Medium
Signed-off-by: Adrian Edwards <adredwar@redhat.com>
Signed-off-by: Adrian Edwards <adredwar@redhat.com>
…is silently ignored.

Assisted-by: GLM 5.3 Low
Signed-off-by: Adrian Edwards <adredwar@redhat.com>
Assisted-by: GLM 5.3 Low
Signed-off-by: Adrian Edwards <adredwar@redhat.com>
Generated-by: GLM 5.3 Low
Signed-off-by: Adrian Edwards <adredwar@redhat.com>
Generated-by: GLM 5.3 High
Signed-off-by: Adrian Edwards <adredwar@redhat.com>
Generated-by: GLM 5.3 High
Signed-off-by: Adrian Edwards <adredwar@redhat.com>
Generated-by: GLM 5.3 High
Signed-off-by: Adrian Edwards <adredwar@redhat.com>
Generated-by: GLM 5.3 High
Signed-off-by: Adrian Edwards <adredwar@redhat.com>
expression-bearing indexes would otherwise render as `op.create_index(..., [])` (broken SQL)

Generated-by: GLM 5.3 High
Signed-off-by: Adrian Edwards <adredwar@redhat.com>
Unsure about whether the remaining ones should be added individually in multiple indexes or together in one compound index

Generated-by: GLM 5.3 Low
Signed-off-by: Adrian Edwards <adredwar@redhat.com>
collectoss-new-schema.sql does these as compound indexes. This is likely quite inefficient and could use review

Generated-by: GLM 5.3 Low
Signed-off-by: Adrian Edwards <adredwar@redhat.com>
Signed-off-by: Adrian Edwards <adredwar@redhat.com>
Signed-off-by: Adrian Edwards <adredwar@redhat.com>
db = db_sigs.get(name)
if db is None:
# Added (or renamed-to) index.
logger.info(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[pylint] reported by reviewdog 🐶
E1205: Too many arguments for logging format string (logging-too-many-args)

# list): CREATE INDEX cannot overwrite, so drop + create.
# (If either side is expression-bearing — columns is None
# — the comparison above is name-only; skip.)
logger.info(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[pylint] reported by reviewdog 🐶
E1205: Too many arguments for logging format string (logging-too-many-args)

# Removed (or renamed-from) index. Columns are attached
# to the reverse op only when parseable, so the
# downgrade recreates it faithfully.
logger.info(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[pylint] reported by reviewdog 🐶
E1205: Too many arguments for logging format string (logging-too-many-args)

# comparator. MUST be imported after register_entities above: the entity
# comparator registers first, so views with a pending create/replace op
# (which already render index creation) are skipped by the index comparator.
from collectoss.application.db import matview_index_comparator # noqa: E402,F401

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[pylint] reported by reviewdog 🐶
W0611: Unused matview_index_comparator imported from collectoss.application.db (unused-import)

@MoralCode MoralCode added the database Related to the unifed data model/schema label Nov 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

database Related to the unifed data model/schema

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant