Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ This is the backend API for Ashes.live, a fan-developed deckbuilder and communit
2. Rebuild the container: `make build`

### Database Migrations
1. Create the migration: `make migration-new ARGS='DESCRIPTION HERE'`
1. Create the migration: `make migrate-new ARGS='DESCRIPTION HERE'`
2. Review generated migration file to ensure no unexpected changes
3. Execute the migration: `make migrate`

Expand Down
2 changes: 2 additions & 0 deletions api/schemas/cards.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ class CardOut(BaseModel):
copies: int | None = None
effectRepeats: bool | None = None
is_legacy: bool | None = None
chained: bool | None = None


class CardUpdate(BaseModel):
Expand Down Expand Up @@ -171,6 +172,7 @@ class CardUpdate(BaseModel):
recover: Annotated[str | int | None, BeforeValidator(str_or_int)] = None
spellboard: int | None = None
copies: int | None = None
chained: bool | None = False


class CardUsageCounts(BaseModel):
Expand Down
6 changes: 3 additions & 3 deletions api/views/cards.py
Original file line number Diff line number Diff line change
Expand Up @@ -490,18 +490,18 @@ def update_card(
card.alt_dice_flags = 0
del json_data["altDice"]
# Update JSON-only data that doesn't need parsing
for prop in ("magicCost", "effectMagicCost", "effectRepeats"):
for prop in ("magicCost", "effectMagicCost", "effectRepeats", "chained"):
update_value = getattr(data, prop)
if update_value is not None and update_value != json_data.get(prop):
if update_value:
if update_value or update_value == 0:
json_data[prop] = update_value
elif prop in json_data:
del json_data[prop]
# Now that we've covered everything that's in the root Card, update the str or int values that are JSON-only
for prop in ("attack", "life", "recover", "battlefield", "spellboard"):
update_value = getattr(data, prop)
if update_value is not None and update_value != json_data.get(prop):
if update_value:
if update_value or update_value == 0:
json_data[prop] = str_or_int(update_value)
elif prop in json_data:
del json_data[prop]
Expand Down
49 changes: 49 additions & 0 deletions migrations/versions/2025-08-24_add_card_chains_489f5ba99de2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"""Add card chains

Revision ID: 489f5ba99de2
Revises: b5e78986c4b6
Create Date: 2025-08-24 15:46:54.114706+00:00

"""

import sqlalchemy as sa
from alembic import op

# revision identifiers, used by Alembic.
revision = "489f5ba99de2"
down_revision = "b5e78986c4b6"
branch_labels = None
depends_on = None


def upgrade():
# Update all cards with default chain status
op.execute(
"""
UPDATE card SET "json" = "json" || '{"chained": false}'::jsonb
WHERE is_legacy = FALSE
"""
)
op.execute(
"""
UPDATE card SET "json" = "json" || '{"chained": true}'::jsonb
WHERE is_legacy = FALSE AND stub IN (
'explosive-growth',
'golden-veil',
'hypnotize',
'psychic-vampire',
'river-skald',
'summon-shining-hydra',
'meteor'
)
"""
)


def downgrade():
op.execute(
"""
UPDATE card SET "json" = "json" - 'chained'
WHERE is_legacy = FALSE
"""
)