{# === Macros === #} {% macro icon_check() %}{% endmacro %} {% macro icon_x() %}{% endmacro %} {% macro icon_alert() %}{% endmacro %} {% macro icon_db() %}{% endmacro %} {% macro icon_clock() %}{% endmacro %} {% macro icon_user() %}{% endmacro %} {% macro icon_branch() %}{% endmacro %} {% macro icon_search() %}{% endmacro %} {% macro icon_copy() %}{% endmacro %} {% macro icon_chev() %}{% endmacro %} {% macro icon_dl() %}{% endmacro %} {% macro icon_print() %}{% endmacro %} {% macro icon_file() %}{% endmacro %} {% macro icon_diff() %}{% endmacro %} {% macro icon_chart() %}{% endmacro %} {% macro icon_table() %}{% endmacro %} {% macro icon_wrench() %}{% endmacro %} {% macro tab_icon(t) %} {% if t == 'MIGRATE' %}{{ icon_branch() }} {% elif t == 'INFO' %}{{ icon_table() }} {% elif t == 'DIFF' %}{{ icon_diff() }} {% elif t == 'REPAIR' %}{{ icon_wrench() }} {% elif t == 'INTROSPECTION' or t == 'INTROSPECT' %}{{ icon_db() }} {% elif t == 'UNDO' %}{{ icon_branch() }} {% else %}{{ icon_chart() }}{% endif %} {% endmacro %} {% macro op_chip(stmt) %} {% set s = (stmt or '')|upper|trim %} {% if s.startswith('CREATE') %}CREATE {% elif s.startswith('ALTER') %}ALTER {% elif s.startswith('DROP') or s.startswith('TRUNCATE') %}{% if s.startswith('TRUNCATE') %}TRUNCATE{% else %}DROP{% endif %} {% elif s.startswith('INSERT') %}INSERT {% elif s.startswith('UPDATE') %}UPDATE {% elif s.startswith('DELETE') %}DELETE {% elif s.startswith('SELECT') %}SELECT {% endif %} {% endmacro %} {% macro is_risky(stmt) %}{% set s = (stmt or '')|upper %}{% if 'DROP ' in s or s.startswith('TRUNCATE') or 'DELETE FROM' in s %}1{% endif %}{% endmacro %} {# === Counts (computed up front) === #} {% set ns = namespace(total=unified_commands|length, ok=0, fail=0, total_stmts=0, total_time=0, has_diff=false, has_failed_mig=false) %} {% for cmd in unified_commands %} {% if cmd.success %}{% set ns.ok = ns.ok + 1 %}{% else %}{% set ns.fail = ns.fail + 1 %}{% endif %} {% if cmd.command_type == 'DIFF' %}{% set ns.has_diff = true %}{% endif %} {% if cmd.command_type in ['MIGRATE','UNDO'] and cmd.per_migration_journal %} {% for mig_script, mj in cmd.per_migration_journal.items() %} {% if mj.statements %} {% set ns.total_stmts = ns.total_stmts + (mj.statements|length) %} {% set ns.total_time = ns.total_time + (mj.total_execution_time or 0) %} {% endif %} {% endfor %} {% endif %} {% endfor %}
DBLift Migration Report
{{ database_name|default('Database') }}{% if environment %} · {{ environment }}{% endif %}
Reports/ {{ database_name|default('database') }}/ Run {{ run_id|default(timestamp|default('latest')) }}
{{ icon_db() }} Database
{{ database_name|default('—') }}
{{ icon_branch() }} Schema
{{ schema_name|default(default_schema|default('public')) }}
{{ icon_clock() }} Generated
{{ report_generated_at|default(timestamp|default('—')) }}
{{ icon_user() }} User
{{ db_user|default(executed_by|default('—')) }}
{{ icon_file() }} DBLift
v{{ dblift_version|default('—') }}
{{ icon_chart() }} Run
{{ run_id|default('—') }}
Status
{% if ns.fail > 0 %}Failed{% else %}Success{% endif %}
{{ ns.ok }} ok · {{ ns.fail }} failed of {{ ns.total }}
Commands
{{ ns.total }}
executed in this run
Statements
{{ ns.total_stmts }}
across migrate/undo
Total SQL Time
{{ ns.total_time }}ms
{% if ns.total_stmts > 0 %}~{{ (ns.total_time / ns.total_stmts)|round(1) }} ms / stmt{% else %}—{% endif %}
Schema Drift
{% if ns.has_diff %}Detected{% else %}—{% endif %}
{% if ns.has_diff %}see DIFF tab{% else %}no diff in run{% endif %}
{% for cmd in unified_commands %} {% endfor %}
{% for cmd in unified_commands %}
{# Tab-level header banner #}
{{ tab_icon(cmd.command_type) }} {{ cmd.command_type }} command
{{ cmd.timestamp }} · {{ cmd.execution_time }} ms · {% if cmd.command_type == 'DIFF' %}{% if cmd.success %}No differences{% else %}Differences found{% endif %}{% else %}{% if cmd.success %}Success{% else %}Failed{% endif %}{% endif %}
{% if not cmd.success and cmd.error_message and cmd.command_type != 'DIFF' %} {% endif %} {% if cmd.command_type == 'PLAN' %} {% set plan = cmd.result %}
Pending versioned
{{ plan.pending_migrations|length }}
Pending repeatable
{{ plan.repeatables_pending|length }}
Checksum drift
{{ plan.checksum_drift|length }}
Already applied
{{ plan.already_applied_count }}
SQL validation
{{ plan.sql_validation.status|default('SKIPPED') }}
{% endif %} {# Overall stats summary for MIGRATE/UNDO #} {% if cmd.command_type in ['MIGRATE','UNDO'] and cmd.per_migration_journal %} {% set s = namespace(total_stmts=0, total_time=0, min_time=999999, max_time=0) %} {% for mig_script, mj in cmd.per_migration_journal.items() %} {% if mj.statements %} {% set s.total_stmts = s.total_stmts + (mj.statements|length) %} {% set s.total_time = s.total_time + (mj.total_execution_time or 0) %} {% if mj.min_statement_time and mj.min_statement_time < s.min_time %}{% set s.min_time = mj.min_statement_time %}{% endif %} {% if mj.max_statement_time and mj.max_statement_time > s.max_time %}{% set s.max_time = mj.max_statement_time %}{% endif %} {% endif %} {% endfor %} {% if s.total_stmts > 0 %}
Statements
{{ s.total_stmts }}
Total time
{{ s.total_time }} ms
Avg / stmt
{{ (s.total_time / s.total_stmts)|round(2) }} ms
Min / Max
{{ s.min_time }} / {{ s.max_time }} ms
{% endif %} {% endif %}
{# ========== INFO ========== #} {% if cmd.command_type == 'INFO' and cmd.migrations %}
{{ icon_table() }} Schema history
{{ cmd.migrations|length }} migrations
{{ icon_search() }}
All {{ cmd.migrations|length }}
{% set ns_inf = namespace(success=0, pending=0, failed=0, ignored=0) %} {% for m in cmd.migrations %} {% set st = (m.state|default(m.status|default('')))|upper %} {% if 'SUCC' in st or 'INSTALL' in st %}{% set ns_inf.success = ns_inf.success + 1 %} {% elif 'PENDING' in st %}{% set ns_inf.pending = ns_inf.pending + 1 %} {% elif 'FAIL' in st %}{% set ns_inf.failed = ns_inf.failed + 1 %} {% elif 'IGNOR' in st %}{% set ns_inf.ignored = ns_inf.ignored + 1 %} {% endif %} {% endfor %}
Success {{ ns_inf.success }}
Pending {{ ns_inf.pending }}
Failed {{ ns_inf.failed }}
{% if ns_inf.ignored > 0 %}
Ignored {{ ns_inf.ignored }}
{% endif %}
{% for m in cmd.migrations %} {% set st = (m.state|default(m.status|default('')))|upper %} {% set status_class = 'neutral' %}{% set status_label = m.state|default(m.status|default('—')) %}{% set status_key = 'other' %} {% if 'SUCC' in st or 'INSTALL' in st %}{% set status_class = 'ok' %}{% set status_key = 'success' %} {% elif 'PENDING' in st %}{% set status_class = 'warn' %}{% set status_key = 'pending' %} {% elif 'FAIL' in st %}{% set status_class = 'fail' %}{% set status_key = 'failed' %} {% elif 'IGNOR' in st %}{% set status_class = 'neutral' %}{% set status_key = 'ignored' %} {% endif %} {% endfor %}
VersionDescriptionTypeStatusInstalled onInstalled byExec
{{ m.version|default('—') }} {{ m.description|default(m.script|default('—')) }}{% if m.script and m.description %}
{{ m.script }}
{% endif %}
{% set t = (m.type|default(''))|upper %}{% if 'REPEAT' in t %}Repeatable{% elif 'UNDO' in t %}Undo{% elif t %}Versioned{% else %}{% endif %} {{ status_label }} {{ m.installed_on|default('—') }} {{ m.installed_by|default('—') }} {% if m.execution_time %}{{ m.execution_time }} ms{% else %}—{% endif %}
{% endif %} {% if cmd.command_type in ['MIGRATE','UNDO'] and cmd.result.show_sql and cmd.sql %}
{{ icon_file() }} SQL statements
{% for mig_sql in cmd.sql %}
{{ mig_sql.version|default(loop.index) }}
{{ mig_sql.description|default(mig_sql.script) }} {{ mig_sql.script }}
{{ mig_sql.statements|length }} stmt{% if mig_sql.statements|length != 1 %}s{% endif %}
{% if mig_sql.statements %}
{% for statement in mig_sql.statements %}
{{ loop.index }}
{{ statement|e }}
{% endfor %}
{% else %}

No SQL statements recorded.

{% endif %}
{% endfor %}
{% endif %} {% if cmd.command_type in ['MIGRATE','UNDO','CLEAN'] and cmd.result.show_query_results and cmd.query_results %}
{{ icon_db() }} Query results
{% for info in cmd.query_results %}
{{ info.version|default(loop.index) }}
{{ info.description|default(info.script) }} {{ info.script }}
{{ info.results|length }} result{% if info.results|length != 1 %}s{% endif %}
{% if info.results %} {% for entry in info.results %}
{{ entry.statement|e }}
{% if entry.rows %}
{% for col in entry.columns %}{% endfor %} {% for row in entry.rows %} {% for cell in row %}{% endfor %} {% endfor %}
{{ col }}
{{ cell if cell is not none else '—' }}
{% else %}

Query returned 0 rows.

{% endif %} {% endfor %} {% else %}

No query results recorded.

{% endif %}
{% endfor %}
{% endif %} {% if cmd.command_type == 'PLAN' %} {% set plan = cmd.result %}
{{ icon_branch() }} Migration plan
{% if plan.snapshot_model %}{{ plan.snapshot_model }}{% endif %} {% if plan.target_last_version %}Target {{ plan.target_last_version }}{% endif %}
{% if plan.pending_migrations or plan.repeatables_pending %}
{% for m in plan.pending_migrations + plan.repeatables_pending %} {% endfor %}
VersionScriptDescriptionTypeChecksum
{{ m.version|default('—') }} {{ m.script }} {{ m.description|default('—') }} {{ m.type|default('SQL') }} {{ m.checksum|default('—') }}
{% else %} {% endif %}
{% if plan.checksum_drift %}
{{ icon_alert() }} Checksum drift
{{ plan.checksum_drift|length }} drift{% if plan.checksum_drift|length != 1 %}s{% endif %}
{% for drift in plan.checksum_drift %} {% endfor %}
VersionScriptExpectedActual
{{ drift.version|default('—') }} {{ drift.script }} {{ drift.expected_checksum|default('—') }} {{ drift.actual_checksum|default('—') }}
{% endif %} {% if plan.sql_validation %}
{{ icon_check() }} SQL validation
{{ plan.sql_validation.status }} {{ plan.sql_validation.files_checked }} file{% if plan.sql_validation.files_checked != 1 %}s{% endif %}
{% if plan.sql_validation.errors or plan.sql_validation.warnings or plan.sql_validation.messages %} {% endif %}
{% endif %} {% endif %} {# ========== MIGRATE / UNDO ========== #} {% if cmd.command_type in ['MIGRATE','UNDO'] and cmd.per_migration_journal %} {# Identify failed migration #} {% set ns_fail = namespace(script=None, stmt=None, idx=0) %} {% if not cmd.success %} {% for mig_script, mj in cmd.per_migration_journal.items() %} {% if mj.statements %} {% for st in mj.statements %} {% if not st.success %} {% if not ns_fail.script %}{% set ns_fail.script = mig_script %}{% set ns_fail.stmt = st %}{% set ns_fail.idx = loop.index %}{% endif %} {% endif %} {% endfor %} {% endif %} {% endfor %} {% endif %} {% if ns_fail.script %} {% endif %}
{{ icon_branch() }} Per-migration execution
{% set max_time = namespace(v=1) %} {% for mig_script, mj in cmd.per_migration_journal.items() %} {% if mj.statements %}{% for st in mj.statements %}{% if (st.execution_time or 0) > max_time.v %}{% set max_time.v = st.execution_time %}{% endif %}{% endfor %}{% endif %} {% endfor %} {% for mig_script, mj in cmd.per_migration_journal.items() %} {% set ns_mig = namespace(has_fail=false) %} {% if mj.statements %}{% for st in mj.statements %}{% if not st.success %}{% set ns_mig.has_fail = true %}{% endif %}{% endfor %}{% endif %} {% set has_fail = ns_mig.has_fail %}
{{ icon_chev() }} {{ mj.version|default(loop.index) }}
{{ mj.description|default(mig_script) }} {{ mig_script }}
{% if mj.statements %}{{ mj.statements|length }} stmt{% if mj.statements|length != 1 %}s{% endif %}{% endif %} {{ mj.total_execution_time|default(0) }} ms {% if has_fail %}Failed{% else %}OK{% endif %}
{% if mj.statements %} {# Show per-statement SQL here only when the dedicated SQL panel will not render it. The SQL panel (above) requires show_sql=True AND cmd.sql to be populated. When both conditions hold the SQL is already visible there — no need to duplicate. When show_sql is False the user has opted out of SQL display entirely. #} {% set show_sql_here = cmd.result.show_sql and not cmd.sql %} {% if show_sql_here %}
{% endif %}
#
Operation
Timeline
Time
{% for st in mj.statements %} {% set risky = is_risky(st.statement) %} {% set pct = ((st.execution_time or 0) / max_time.v * 100)|round(1) %}
{{ loop.index }}
{{ op_chip(st.statement) }} {% if not st.success %}Error{% endif %} {% if risky %}Risky{% endif %}
{% if show_sql_here %}
{{ st.statement|e }}
{% endif %} {% if not st.success and st.error %} {% endif %}
{{ st.execution_time|default(0) }} ms
{% endfor %}
{% else %}

No statements recorded.

{% endif %}
{% endfor %}
{% endif %} {# ========== DIFF ========== #} {% if cmd.command_type == 'DIFF' %} {% set diff = cmd.diff_data|default(cmd.diff|default(None)) %} {% if diff %} {# Summary banner #} {% set total_diffs = diff.total_differences|default(0) %} {% if total_diffs > 0 %} {% endif %} {# Modified Tables #} {% if diff.modified_tables %}
{{ icon_table()|default('') }} Modified Tables
{{ diff.modified_tables|length }} modified
{% for tbl in diff.modified_tables %}
{{ tbl.table_name }} {{ tbl.severity|default('warning') }} {% if tbl.diff_count %}{{ tbl.diff_count }} change{% if tbl.diff_count != 1 %}s{% endif %}{% endif %}
{% if tbl.missing_columns %}
Missing columns {% for col in tbl.missing_columns %}{{ col.column_name|default(col) }}{% endfor %}
{% endif %} {% if tbl.extra_columns %}
Extra columns {% for col in tbl.extra_columns %}{{ col.column_name|default(col) }}{% endfor %}
{% endif %} {% if tbl.modified_columns %}
Modified columns {% for col in tbl.modified_columns %}
{{ col.column_name }} {% for chg in col.changes %} · {{ chg.property }}: {{ chg.expected }}{{ chg.actual }}{% endfor %}
{% endfor %}
{% endif %} {% if tbl.missing_constraints %}
Missing constraints {% for c in tbl.missing_constraints %}{{ c.constraint_name|default(c) }}{% endfor %}
{% endif %} {% if tbl.extra_constraints %}
Extra constraints {% for c in tbl.extra_constraints %}{{ c.constraint_name|default(c) }}{% endfor %}
{% endif %} {% if tbl.unified_diff and tbl.unified_diff.lines %}
{{ icon_diff() }}SQL diff
{% for ln in tbl.unified_diff.lines %} {% if ln.type == 'removed' %}
{{ ln.before_num|default('') }}
{{ ln.content|e }}
{% elif ln.type == 'added' %}
{{ ln.after_num|default('') }}
{{ ln.content|e }}
{% else %}
{{ ln.before_num|default('') }}
{{ ln.after_num|default('') }}
{{ ln.content|e }}
{% endif %} {% endfor %}
{% endif %}
{% endfor %}
{% endif %} {# Missing / Extra Tables #} {% if diff.missing_tables or diff.extra_tables %}
Tables
{% if diff.missing_tables %}−{{ diff.missing_tables|length }} missing{% endif %} {% if diff.extra_tables %}+{{ diff.extra_tables|length }} extra{% endif %}
{% for t in diff.missing_tables %}
TABLEmissing
{{ t.table_name|default(t) }}
{% endfor %} {% for t in diff.extra_tables %}
TABLEextra
{{ t.table_name|default(t) }}
{% endfor %}
{% endif %} {# Views #} {% if diff.missing_views or diff.extra_views or diff.modified_views %}
Views
{% if diff.missing_views %}−{{ diff.missing_views|length }}{% endif %} {% if diff.extra_views %}+{{ diff.extra_views|length }}{% endif %} {% if diff.modified_views %}~{{ diff.modified_views|length }}{% endif %}
{% for v in diff.missing_views %}
VIEWmissing
{{ v.view_name|default(v) }}
{% endfor %} {% for v in diff.extra_views %}
VIEWextra
{{ v.view_name|default(v) }}
{% endfor %} {% for v in diff.modified_views %}
VIEWmodified
{{ v.view_name|default(v) }}
{% endfor %}
{% endif %} {# Indexes #} {% if diff.missing_indexes or diff.extra_indexes or diff.modified_indexes %}
Indexes
{% if diff.missing_indexes %}−{{ diff.missing_indexes|length }}{% endif %} {% if diff.extra_indexes %}+{{ diff.extra_indexes|length }}{% endif %}
{% for i in diff.missing_indexes %}
INDEXmissing
{{ i.index_name|default(i) }}
{% endfor %} {% for i in diff.extra_indexes %}
INDEXextra
{{ i.index_name|default(i) }}
{% endfor %}
{% endif %} {# Sequences #} {% if diff.missing_sequences or diff.extra_sequences %}
Sequences
{% if diff.missing_sequences %}−{{ diff.missing_sequences|length }}{% endif %} {% if diff.extra_sequences %}+{{ diff.extra_sequences|length }}{% endif %}
{% for s in diff.missing_sequences %}
SEQUENCEmissing
{{ s.sequence_name|default(s) }}
{% endfor %} {% for s in diff.extra_sequences %}
SEQUENCEextra
{{ s.sequence_name|default(s) }}
{% endfor %}
{% endif %} {# Triggers #} {% if diff.missing_triggers or diff.extra_triggers %}
Triggers
{% if diff.missing_triggers %}−{{ diff.missing_triggers|length }}{% endif %} {% if diff.extra_triggers %}+{{ diff.extra_triggers|length }}{% endif %}
{% for t in diff.missing_triggers %}
TRIGGERmissing
{{ t.trigger_name|default(t) }}
{% endfor %} {% for t in diff.extra_triggers %}
TRIGGERextra
{{ t.trigger_name|default(t) }}
{% endfor %}
{% endif %} {# Functions & Procedures #} {% if diff.missing_functions or diff.extra_functions or diff.missing_procedures or diff.extra_procedures %} {% set fn_miss = (diff.missing_functions|default([]))|length + (diff.missing_procedures|default([]))|length %} {% set fn_extra = (diff.extra_functions|default([]))|length + (diff.extra_procedures|default([]))|length %}
Functions & Procedures
{% if fn_miss > 0 %}−{{ fn_miss }}{% endif %} {% if fn_extra > 0 %}+{{ fn_extra }}{% endif %}
{% for f in diff.missing_functions %}
FUNCTIONmissing
{{ f.function_name|default(f) }}
{% endfor %} {% for f in diff.extra_functions %}
FUNCTIONextra
{{ f.function_name|default(f) }}
{% endfor %} {% for p in diff.missing_procedures %}
PROCEDUREmissing
{{ p.procedure_name|default(p) }}
{% endfor %} {% for p in diff.extra_procedures %}
PROCEDUREextra
{{ p.procedure_name|default(p) }}
{% endfor %}
{% endif %} {# All clean #} {% if not diff.modified_tables and not diff.missing_tables and not diff.extra_tables and not diff.missing_views and not diff.extra_views and not diff.modified_views and not diff.missing_indexes and not diff.extra_indexes and not diff.missing_sequences and not diff.extra_sequences and not diff.missing_triggers and not diff.extra_triggers and not diff.missing_functions and not diff.extra_functions and not diff.missing_procedures and not diff.extra_procedures %} {% endif %} {% else %} {% endif %} {% endif %} {# ========== CLEAN ========== #} {% if cmd.command_type == 'CLEAN' %} {% if cmd.result and cmd.result.get_objects_by_type %} {% set objects_map = cmd.result.get_objects_by_type() %} {% set ns_clean = namespace(total=0) %} {% for obj_type, names in objects_map.items() %}{% set ns_clean.total = ns_clean.total + (names|length) %}{% endfor %}
{{ icon_x() }} Dropped objects
{{ ns_clean.total }} object{% if ns_clean.total != 1 %}s{% endif %} dropped
{% for obj_type, names in objects_map|dictsort %} {% set names_list = names|list|sort %} {% if names_list %} {% endif %} {% endfor %}
Object typeCountObjects
{{ obj_type.replace('_',' ')|upper }} {{ names_list|length }} {{ names_list|join(', ') }}
{% else %} {% endif %} {% endif %} {# ========== REPAIR ========== #} {% if cmd.command_type == 'REPAIR' %}
{{ icon_wrench() }} Repair actions
{% if cmd.actions or cmd.repair_actions %} {% set acts = cmd.actions|default(cmd.repair_actions) %} {% for a in acts %} {% endfor %}
ActionTargetOutcomeTime
{{ a.action|default(a.type|default('—')) }} {{ a.target|default(a.script|default('—')) }} {% if a.success %}OK{% else %}Failed{% endif %}{% if a.message %}
{{ a.message }}
{% endif %}
{% if a.execution_time %}{{ a.execution_time }} ms{% else %}—{% endif %}
{% else %} {% endif %}
{% endif %} {# ========== INTROSPECTION ========== #} {% if cmd.command_type in ['INTROSPECTION','INTROSPECT'] %} {% set ins = cmd.introspection|default(cmd) %}
{{ icon_db() }} Database introspection
{% if ins.tables %} {% for tbl in ins.tables %} {% endfor %}
ObjectTypeSchemaRowsSize
{{ tbl.name|default(tbl) }} {{ tbl.type|default('TABLE') }} {{ tbl.schema|default('—') }} {% if tbl.row_count is defined %}{{ tbl.row_count }}{% else %}—{% endif %} {{ tbl.size|default('—') }}
{% else %} {% endif %} {% if cmd.raw_output %}
{{ cmd.raw_output|e }}
{% endif %}
{% endif %}
{% endfor %}
{# /.page #}