mirror of
https://github.com/Routstr/routstr-core.git
synced 2026-10-05 12:28:22 +00:00
reapply fee migration
This commit is contained in:
@@ -0,0 +1,47 @@
|
|||||||
|
"""repair missing fee payout checkpoint columns
|
||||||
|
|
||||||
|
Revision ID: 9c4d8e2f1a6b
|
||||||
|
Revises: 7f2843d3f4e4
|
||||||
|
Create Date: 2026-07-25 00:00:00.000000
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from alembic import op
|
||||||
|
|
||||||
|
revision = "9c4d8e2f1a6b"
|
||||||
|
down_revision = "7f2843d3f4e4"
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
"""Repair databases stamped past the original checkpoint migration."""
|
||||||
|
conn = op.get_bind()
|
||||||
|
columns = {
|
||||||
|
column["name"] for column in sa.inspect(conn).get_columns("routstr_fees")
|
||||||
|
}
|
||||||
|
|
||||||
|
if "payout_in_progress_msats" not in columns:
|
||||||
|
op.add_column(
|
||||||
|
"routstr_fees",
|
||||||
|
sa.Column(
|
||||||
|
"payout_in_progress_msats",
|
||||||
|
sa.Integer(),
|
||||||
|
nullable=False,
|
||||||
|
server_default="0",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
if "payout_started_at" not in columns:
|
||||||
|
op.add_column(
|
||||||
|
"routstr_fees",
|
||||||
|
sa.Column("payout_started_at", sa.Integer(), nullable=True),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
# The preceding revision already expects both columns. This migration only
|
||||||
|
# repairs schema drift, so downgrading it must preserve the expected schema.
|
||||||
|
pass
|
||||||
@@ -18,6 +18,37 @@ def _run_alembic(root: Path, database_url: str, revision: str) -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_fresh_node_migrates_fee_payout_schema_to_head(tmp_path: Path) -> None:
|
||||||
|
root = Path(__file__).resolve().parents[2]
|
||||||
|
database_path = tmp_path / "fresh-node.db"
|
||||||
|
database_url = f"sqlite+aiosqlite:///{database_path}"
|
||||||
|
|
||||||
|
_run_alembic(root, database_url, "head")
|
||||||
|
|
||||||
|
with sqlite3.connect(database_path) as connection:
|
||||||
|
version = connection.execute(
|
||||||
|
"SELECT version_num FROM alembic_version"
|
||||||
|
).fetchone()
|
||||||
|
columns = {
|
||||||
|
row[1] for row in connection.execute("PRAGMA table_info(routstr_fees)")
|
||||||
|
}
|
||||||
|
fee = connection.execute(
|
||||||
|
"SELECT id, accumulated_msats, total_paid_msats, last_paid_at, "
|
||||||
|
"payout_in_progress_msats, payout_started_at FROM routstr_fees"
|
||||||
|
).fetchone()
|
||||||
|
|
||||||
|
assert version == ("9c4d8e2f1a6b",)
|
||||||
|
assert {
|
||||||
|
"id",
|
||||||
|
"accumulated_msats",
|
||||||
|
"total_paid_msats",
|
||||||
|
"last_paid_at",
|
||||||
|
"payout_in_progress_msats",
|
||||||
|
"payout_started_at",
|
||||||
|
} <= columns
|
||||||
|
assert fee == (1, 0, 0, None, 0, None)
|
||||||
|
|
||||||
|
|
||||||
def test_fee_payout_checkpoint_migration_preserves_existing_row(
|
def test_fee_payout_checkpoint_migration_preserves_existing_row(
|
||||||
tmp_path: Path,
|
tmp_path: Path,
|
||||||
) -> None:
|
) -> None:
|
||||||
@@ -44,3 +75,36 @@ def test_fee_payout_checkpoint_migration_preserves_existing_row(
|
|||||||
).fetchone()
|
).fetchone()
|
||||||
|
|
||||||
assert row == (5000, 1000, 123, 0, None)
|
assert row == (5000, 1000, 123, 0, None)
|
||||||
|
|
||||||
|
|
||||||
|
def test_fee_payout_checkpoint_repair_restores_columns_missing_at_old_head(
|
||||||
|
tmp_path: Path,
|
||||||
|
) -> None:
|
||||||
|
root = Path(__file__).resolve().parents[2]
|
||||||
|
database_path = tmp_path / "migration.db"
|
||||||
|
database_url = f"sqlite+aiosqlite:///{database_path}"
|
||||||
|
old_head = "7f2843d3f4e4"
|
||||||
|
_run_alembic(root, database_url, old_head)
|
||||||
|
|
||||||
|
# Reproduce a database that was stamped to head after a duplicate-column or
|
||||||
|
# unknown-revision recovery skipped part of the migration chain.
|
||||||
|
with sqlite3.connect(database_path) as connection:
|
||||||
|
connection.execute("ALTER TABLE routstr_fees DROP COLUMN payout_started_at")
|
||||||
|
connection.execute(
|
||||||
|
"ALTER TABLE routstr_fees DROP COLUMN payout_in_progress_msats"
|
||||||
|
)
|
||||||
|
connection.commit()
|
||||||
|
|
||||||
|
_run_alembic(root, database_url, "head")
|
||||||
|
|
||||||
|
with sqlite3.connect(database_path) as connection:
|
||||||
|
columns = {
|
||||||
|
row[1] for row in connection.execute("PRAGMA table_info(routstr_fees)")
|
||||||
|
}
|
||||||
|
row = connection.execute(
|
||||||
|
"SELECT payout_in_progress_msats, payout_started_at "
|
||||||
|
"FROM routstr_fees WHERE id = 1"
|
||||||
|
).fetchone()
|
||||||
|
|
||||||
|
assert {"payout_in_progress_msats", "payout_started_at"} <= columns
|
||||||
|
assert row == (0, None)
|
||||||
|
|||||||
Reference in New Issue
Block a user