Files
shopdb-flask/plugins/endpoints/migrations/versions/0002_endpoint_commands.py
benjamin.baker 01734e5449 harden CSV import reconciliation and preserve saved model selections
Default fuzzy reconcile threshold to 0 and refuse merges when digit runs differ so numbered labels like Bay 311 never bind to Bay 310. Keep edit forms from clearing saved model fields when category filtering hides untyped rows. Includes in-progress computers policy and endpoints command feature work.
2026-08-28 09:29:09 -04:00

85 lines
3.3 KiB
Python

"""endpoint commands queue + cached MTConnect state.
Adds the endpointcommands queue (one WebUI-issued, server-allowlisted action
per row, claimed and finalized by the agent long-poll) and two cached MTConnect
run-state columns on endpointstates so the WebUI toggle can show a real state
between command polls.
Idempotent: create_table_if_missing guards the new table, and the column adds
check the live schema first so a db.create_all() site (which already built the
columns) re-runs clean on strict MySQL 8.
"""
from alembic import op
from shopdb.plugins.alembic_template import (
create_index_if_missing,
create_table_if_missing,
)
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'endpoints0002commands'
down_revision = 'endpoints0001baseline'
branch_labels = None
depends_on = None
def _has_column(table_name, column_name):
from sqlalchemy import inspect
inspector = inspect(op.get_bind())
if not inspector.has_table(table_name):
return False
return any(col['name'] == column_name
for col in inspector.get_columns(table_name))
def upgrade():
if not _has_column('endpointstates', 'mtconnectrunning'):
op.add_column('endpointstates',
sa.Column('mtconnectrunning', sa.Boolean(),
nullable=True))
if not _has_column('endpointstates', 'mtconnectcheckedat'):
op.add_column('endpointstates',
sa.Column('mtconnectcheckedat', sa.DateTime(),
nullable=True))
create_table_if_missing(
'endpointcommands',
sa.Column('endpointcommandid', sa.Integer(), nullable=False),
sa.Column('assetid', sa.Integer(), nullable=False),
sa.Column('action', sa.String(length=64), nullable=False),
sa.Column('status', sa.String(length=20), nullable=False),
sa.Column('requestedby', sa.Integer(), nullable=True),
sa.Column('resultmessage', sa.Text(), nullable=True),
sa.Column('resultjson', sa.Text(length=16777215), nullable=True),
sa.Column('createdat', sa.DateTime(), nullable=False),
sa.Column('claimedat', sa.DateTime(), nullable=True),
sa.Column('completedat', sa.DateTime(), nullable=True),
sa.ForeignKeyConstraint(['assetid'], ['assets.assetid'],
ondelete='CASCADE'),
sa.PrimaryKeyConstraint('endpointcommandid'),
)
create_index_if_missing('ix_endpointcommands_assetid',
'endpointcommands', ['assetid'])
create_index_if_missing('ix_endpointcommands_status',
'endpointcommands', ['status'])
create_index_if_missing('idx_endpointcommands_assetstatus',
'endpointcommands', ['assetid', 'status'])
def downgrade():
op.drop_index('idx_endpointcommands_assetstatus',
table_name='endpointcommands')
op.drop_index('ix_endpointcommands_status',
table_name='endpointcommands')
op.drop_index('ix_endpointcommands_assetid',
table_name='endpointcommands')
op.drop_table('endpointcommands')
if _has_column('endpointstates', 'mtconnectcheckedat'):
op.drop_column('endpointstates', 'mtconnectcheckedat')
if _has_column('endpointstates', 'mtconnectrunning'):
op.drop_column('endpointstates', 'mtconnectrunning')