backups plugin with NTLARS revision history; shopfloor dashboard upcoming cards and state chips
This commit is contained in:
16
plugins/backups/migrations/env.py
Normal file
16
plugins/backups/migrations/env.py
Normal file
@@ -0,0 +1,16 @@
|
||||
"""Alembic environment for the backups plugin migration chain.
|
||||
|
||||
Delegates to the shared runner in shopdb.plugins.alembic_template, which filters
|
||||
the metadata to this plugin's tables and drives Alembic against the per-plugin
|
||||
version table alembic_version_backups. See ADR-008 for the ownership
|
||||
model. Unlike the ten cutover plugins whose 0001 is a no-op anchor, this plugin
|
||||
is NEW: its 0001 baseline really CREATES its tables, because the core chain
|
||||
never built them.
|
||||
"""
|
||||
import os
|
||||
|
||||
os.environ['PLUGIN_NAME'] = 'backups'
|
||||
|
||||
from shopdb.plugins.alembic_template import run_migrations # noqa: E402
|
||||
|
||||
run_migrations()
|
||||
24
plugins/backups/migrations/script.py.mako
Normal file
24
plugins/backups/migrations/script.py.mako
Normal file
@@ -0,0 +1,24 @@
|
||||
"""${message}
|
||||
|
||||
Revision ID: ${up_revision}
|
||||
Revises: ${down_revision | comma,n}
|
||||
Create Date: ${create_date}
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
${imports if imports else ""}
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = ${repr(up_revision)}
|
||||
down_revision = ${repr(down_revision)}
|
||||
branch_labels = ${repr(branch_labels)}
|
||||
depends_on = ${repr(depends_on)}
|
||||
|
||||
|
||||
def upgrade():
|
||||
${upgrades if upgrades else "pass"}
|
||||
|
||||
|
||||
def downgrade():
|
||||
${downgrades if downgrades else "pass"}
|
||||
61
plugins/backups/migrations/versions/0001_backups_baseline.py
Normal file
61
plugins/backups/migrations/versions/0001_backups_baseline.py
Normal file
@@ -0,0 +1,61 @@
|
||||
"""backups plugin baseline (real create).
|
||||
|
||||
Built after the ADR-008 ownership cutover, so unlike the ten cutover plugins
|
||||
whose 0001 is a stamp-only anchor, this baseline genuinely CREATES the table.
|
||||
The core chain never knew about backuprevisions, so this per-plugin chain is its
|
||||
sole authoritative creator.
|
||||
|
||||
Emits explicit Alembic ops rather than using the create_plugin_tables helper:
|
||||
the helper builds a per-plugin MetaData filtered to the plugin's own tables, so
|
||||
the foreign key to the core assets table cannot resolve at CreateTable-compile
|
||||
time (NoReferencedTableError). Same shape autogenerate produces. Tables inherit
|
||||
the connection's default charset, matching how the core chain creates its own.
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'backups0001baseline'
|
||||
down_revision = None
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.create_table(
|
||||
'backuprevisions',
|
||||
sa.Column('backuprevisionid', sa.Integer(), nullable=False),
|
||||
sa.Column('assetid', sa.Integer(), nullable=False),
|
||||
sa.Column('backupkind', sa.String(length=50), nullable=False),
|
||||
sa.Column('storagebackend', sa.String(length=20), nullable=False,
|
||||
server_default='shopdb'),
|
||||
sa.Column('contenthash', sa.String(length=64), nullable=False),
|
||||
sa.Column('payloadjson', sa.Text(length=16777215), nullable=True),
|
||||
sa.Column('sharepath', sa.String(length=500), nullable=True),
|
||||
sa.Column('sourcefilename', sa.String(length=255), nullable=True),
|
||||
sa.Column('bytesize', sa.Integer(), nullable=True),
|
||||
sa.Column('sourcehostname', sa.String(length=255), nullable=True),
|
||||
sa.Column('collectedat', sa.DateTime(), nullable=True),
|
||||
sa.Column('createdat', sa.DateTime(), nullable=False),
|
||||
sa.ForeignKeyConstraint(['assetid'], ['assets.assetid'],
|
||||
ondelete='CASCADE'),
|
||||
sa.PrimaryKeyConstraint('backuprevisionid'),
|
||||
)
|
||||
op.create_index('ixbackuprevisionsassetid', 'backuprevisions', ['assetid'])
|
||||
op.create_index('ixbackuprevisionsbackupkind', 'backuprevisions',
|
||||
['backupkind'])
|
||||
op.create_index('ixbackuprevisionscontenthash', 'backuprevisions',
|
||||
['contenthash'])
|
||||
# The dedup read path is "latest revision for this asset+kind", so the
|
||||
# composite index is the one that actually gets used on every collector post.
|
||||
op.create_index('ixbackuprevisionsassetkind', 'backuprevisions',
|
||||
['assetid', 'backupkind'])
|
||||
|
||||
|
||||
def downgrade():
|
||||
op.drop_index('ixbackuprevisionsassetkind', table_name='backuprevisions')
|
||||
op.drop_index('ixbackuprevisionscontenthash', table_name='backuprevisions')
|
||||
op.drop_index('ixbackuprevisionsbackupkind', table_name='backuprevisions')
|
||||
op.drop_index('ixbackuprevisionsassetid', table_name='backuprevisions')
|
||||
op.drop_table('backuprevisions')
|
||||
Reference in New Issue
Block a user