Back to Starrocks

Alembic Migration Rendering Design

contrib/starrocks-python-client/docs/design/render.md

4.1.03.5 KB
Original Source

Alembic Migration Rendering Design

This document describes the design of the migration rendering process in the starrocks-sqlalchemy dialect. Rendering is the final step in the autogenerate process, where the abstract migration operations generated by the compare step are converted into Python code in a new Alembic revision script.

The render Module

The logic for this process is located in the starrocks.alembic.render module. This module uses a dispatch mechanism provided by Alembic (@renderers.dispatch_for) to register custom rendering functions for StarRocks-specific operation objects.

  1. Operation Classes (ops.py):

    • These classes define the structure of the operation and its reverse() method for downgrades.
  2. Render Operations (render.py):

    • Implement a function for each custom op, decorated with @renderers.dispatch_for(CreateViewOp).
    • This function defines how Alembic generates the Python code (e.g., op.create_view(...)) that appears in the upgrade() and downgrade() methods of the migration script. The actual SQL generation and execution during alembic upgrade is handled by the Operations.implementation_for decorator in ops.py, which then utilizes the DDL Compiler.

Custom Renderer Functions

When Alembic's autogenerate process encounters a custom operation object from the starrocks.alembic.ops module, it looks for a registered renderer for that object's class.

For example, the starrocks.alembic.ops.CreateViewOp object is rendered by the _create_view function:

python
from .ops import CreateViewOp

@renderers.dispatch_for(CreateViewOp)
def _create_view(autogen_context, op):
    # ... logic to format the op into a string ...
    return f"op.create_view({op.view_name!r}, {op.definition!r})"

The key renderers include:

  • View Operations:
    • _create_view: Renders CreateViewOp objects into op.create_view(...) calls.
    • _drop_view: Renders DropViewOp objects into op.drop_view(...) calls.
    • _alter_view: Renders AlterViewOp objects into op.alter_view(...) calls.
  • Materialized View Operations:
    • _create_materialized_view: Renders CreateMaterializedViewOp objects into op.create_materialized_view(...) calls.
    • _drop_materialized_view: Renders DropMaterializedViewOp objects into op.drop_materialized_view(...) calls.
  • Table Alteration Operations:
    • _render_alter_table_distribution: Renders AlterTableDistributionOp objects into op.alter_table_distribution(...) calls.
    • _render_alter_table_order: Renders AlterTableOrderOp objects into op.alter_table_order(...) calls.
    • _render_alter_table_properties: Renders AlterTablePropertiesOp objects into op.alter_table_properties(...) calls.

How it Works

  1. Input from compare: The render process receives a list of migration operation objects (e.g., CreateViewOp, AlterTableProperties) that were generated by the compare process.
  2. Renderer Dispatch: For each operation object, Alembic's rendering engine dispatches to the appropriate function registered with @renderers.dispatch_for.
  3. Python Code Generation: The renderer function takes the attributes of the operation object (e.g., op.view_name, op.definition) and formats them into a Python string that represents a call to the Alembic op object (e.g., op.create_view(...)).
  4. Migration Script: This generated string is written into the new revision file in the upgrade() function. A corresponding downgrade() function is also generated based on the reverse() method of the operation object.