From fc027bcb81c81cb290c61220caeefc3e48949d02 Mon Sep 17 00:00:00 2001 From: chuks68 Date: Sat, 20 Jun 2026 01:29:49 +0100 Subject: [PATCH] refactor: Migrate Position, ExtraDeposit, and Vault amount columns to Numeric(38, 18) --- .../versions/20230620_amount_numeric.py | 75 +++++++++++++++++++ quantara/web_app/db/crud/deposit.py | 7 +- quantara/web_app/db/crud/position.py | 8 +- quantara/web_app/db/models.py | 6 +- quantara/web_app/tests/db/deposit_db_tests.py | 4 +- 5 files changed, 88 insertions(+), 12 deletions(-) create mode 100644 quantara/web_app/alembic/versions/20230620_amount_numeric.py diff --git a/quantara/web_app/alembic/versions/20230620_amount_numeric.py b/quantara/web_app/alembic/versions/20230620_amount_numeric.py new file mode 100644 index 000000000..4e2e90484 --- /dev/null +++ b/quantara/web_app/alembic/versions/20230620_amount_numeric.py @@ -0,0 +1,75 @@ +"""migration: convert amount columns to Numeric(38,18) + +Revision ID: 20230620_amount_numeric +Revises: b705d1435b64 +Create Date: 2026-06-20 01:18:00.000000 +""" + +from alembic import op +import sqlalchemy as sa + +# revision identifiers, used by Alembic. +revision = '20230620_amount_numeric' +down_revision = 'b705d1435b64' +branch_labels = None +depends_on = None + + +def upgrade() -> None: + # Position.amount + op.alter_column( + 'position', + 'amount', + existing_type=sa.String(), + type_=sa.Numeric(38, 18), + postgresql_using='amount::numeric', + nullable=False, + ) + # ExtraDeposit.amount + op.alter_column( + 'extra_deposits', + 'amount', + existing_type=sa.String(), + type_=sa.Numeric(38, 18), + postgresql_using='amount::numeric', + nullable=False, + ) + # Vault.amount + op.alter_column( + 'vault', + 'amount', + existing_type=sa.String(), + type_=sa.Numeric(38, 18), + postgresql_using='amount::numeric', + nullable=True, + ) + + +def downgrade() -> None: + # Position.amount back to String + op.alter_column( + 'position', + 'amount', + existing_type=sa.Numeric(38, 18), + type_=sa.String(), + postgresql_using='amount::text', + nullable=False, + ) + # ExtraDeposit.amount back to String + op.alter_column( + 'extra_deposits', + 'amount', + existing_type=sa.Numeric(38, 18), + type_=sa.String(), + postgresql_using='amount::text', + nullable=False, + ) + # Vault.amount back to String (nullable) + op.alter_column( + 'vault', + 'amount', + existing_type=sa.Numeric(38, 18), + type_=sa.String(), + postgresql_using='amount::text', + nullable=True, + ) diff --git a/quantara/web_app/db/crud/deposit.py b/quantara/web_app/db/crud/deposit.py index c8cb361ae..bbea60b93 100644 --- a/quantara/web_app/db/crud/deposit.py +++ b/quantara/web_app/db/crud/deposit.py @@ -64,8 +64,8 @@ def add_vault_balance(self, wallet_id: str, symbol: str, amount: str) -> Vault: if not vault: raise ValueError("Vault not found") with self.Session() as db: - new_amount = Decimal(vault.amount) + Decimal(amount) - db.query(Vault).filter_by(id=vault.id).update(amount=str(new_amount)) + new_amount = Decimal(str(vault.amount or 0)) + Decimal(amount) + db.query(Vault).filter_by(id=vault.id).update({"amount": new_amount}) db.commit() vault = self.get_vault(wallet_id, symbol) return vault @@ -80,4 +80,5 @@ def get_vault_balance(self, wallet_id: str, symbol: str) -> str | None: :returns: str or None """ vault = self.get_vault(wallet_id, symbol) - return vault.amount if vault else None + return str(vault.amount) if (vault and vault.amount is not None) else None + diff --git a/quantara/web_app/db/crud/position.py b/quantara/web_app/db/crud/position.py index cc10277a7..7a5e151d0 100644 --- a/quantara/web_app/db/crud/position.py +++ b/quantara/web_app/db/crud/position.py @@ -39,7 +39,7 @@ def _position_to_dict(position: Position) -> dict: "id": str(position.id), "user_id": str(position.user_id), "token_symbol": position.token_symbol, - "amount": position.amount, + "amount": str(position.amount), "multiplier": position.multiplier, "created_at": ( position.created_at.isoformat() if position.created_at else None @@ -334,7 +334,7 @@ def get_total_amounts_for_open_positions(self) -> dict[str, Decimal]: token_amounts = ( db.query( Position.token_symbol, - func.sum(cast(Position.amount, Numeric)).label("total_amount"), + func.sum(Position.amount).label("total_amount"), ) .filter(Position.status != Status.PENDING.value) .group_by(Position.token_symbol) @@ -487,7 +487,7 @@ def add_extra_deposit_to_position( .on_conflict_do_update( index_elements=["position_id", "token_symbol"], set_={ - "amount": cast(ExtraDeposit.amount, Numeric) + cast(amount, Numeric) + "amount": ExtraDeposit.amount + cast(amount, Numeric) }, ) ) @@ -507,7 +507,7 @@ def get_extra_deposits_data(self, position_id: UUID) -> dict[str, str]: .filter(ExtraDeposit.position_id == position_id) .all() ) - return {deposit.token_symbol: deposit.amount for deposit in deposits} + return {deposit.token_symbol: str(deposit.amount) for deposit in deposits} def get_extra_deposits_by_position_id(self, position_id: UUID) -> list[ExtraDeposit]: """ diff --git a/quantara/web_app/db/models.py b/quantara/web_app/db/models.py index f367524a4..f85212ddd 100644 --- a/quantara/web_app/db/models.py +++ b/quantara/web_app/db/models.py @@ -83,7 +83,7 @@ class Position(Base): UUID(as_uuid=True), ForeignKey("user.id"), index=True, nullable=False ) token_symbol = Column(String, nullable=False) - amount = Column(String, nullable=False) + amount = Column(NUMERIC(38, 18), nullable=False) multiplier = Column(NUMERIC, nullable=False) created_at = Column(DateTime, nullable=False, default=func.now()) @@ -154,7 +154,7 @@ class Vault(Base): UUID(as_uuid=True), ForeignKey("user.id"), index=True, nullable=False ) symbol = Column(String) - amount = Column(String) + amount = Column(NUMERIC(38, 18)) created_at = Column(DateTime, nullable=False, default=func.now()) updated_at = Column( DateTime, nullable=False, default=func.now(), onupdate=func.now() @@ -217,7 +217,7 @@ class ExtraDeposit(Base): id = Column(UUID(as_uuid=True), primary_key=True, default=uuid4) token_symbol = Column(String, nullable=False) - amount = Column(String, nullable=False) + amount = Column(NUMERIC(38, 18), nullable=False) added_at = Column(DateTime, default=func.now()) updated_at = Column( DateTime, nullable=False, default=func.now(), onupdate=func.now() diff --git a/quantara/web_app/tests/db/deposit_db_tests.py b/quantara/web_app/tests/db/deposit_db_tests.py index 478142de0..ddef9f503 100644 --- a/quantara/web_app/tests/db/deposit_db_tests.py +++ b/quantara/web_app/tests/db/deposit_db_tests.py @@ -104,9 +104,9 @@ def test_add_balance_success( amount="50.00", ) - updated_amount = Decimal(mock_vault.amount) + Decimal("50.00") + updated_amount = Decimal(str(mock_vault.amount)) + Decimal("50.00") mock_db_connector.Session().query().filter_by().update.assert_called_once_with( - {"amount": str(updated_amount)} + {"amount": updated_amount} ) def test_add_balance_failure_vault_not_found(