148 lines
6.3 KiB
Python
148 lines
6.3 KiB
Python
"""
|
|
Migration: Create unique_items table and refactor item tracking
|
|
|
|
This creates a proper architecture where:
|
|
1. unique_items table stores individual item instances with their properties
|
|
2. inventory/dropped_items reference unique_item_id instead of duplicating data
|
|
3. When item is picked up, only the reference changes (dropped_items -> inventory)
|
|
4. When item decays/breaks, delete from unique_items (cascades to references)
|
|
"""
|
|
|
|
import asyncio
|
|
from api.database import DatabaseSession, engine, metadata
|
|
from sqlalchemy import text
|
|
|
|
async def migrate():
|
|
"""Create unique_items table and refactor references"""
|
|
|
|
async with DatabaseSession() as session:
|
|
print("Starting migration: Create unique_items table...")
|
|
|
|
# Step 1: Create unique_items table
|
|
try:
|
|
await session.execute(text("""
|
|
CREATE TABLE IF NOT EXISTS unique_items (
|
|
id SERIAL PRIMARY KEY,
|
|
item_id VARCHAR NOT NULL,
|
|
durability INTEGER,
|
|
max_durability INTEGER,
|
|
tier INTEGER DEFAULT 1,
|
|
unique_stats JSONB,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
)
|
|
"""))
|
|
print("✓ Created unique_items table")
|
|
except Exception as e:
|
|
print(f"✗ Error creating unique_items table: {e}")
|
|
return
|
|
|
|
# Step 2: Add unique_item_id to inventory (nullable for now)
|
|
try:
|
|
await session.execute(text(
|
|
"ALTER TABLE inventory ADD COLUMN IF NOT EXISTS unique_item_id INTEGER REFERENCES unique_items(id) ON DELETE CASCADE"
|
|
))
|
|
print("✓ Added unique_item_id to inventory")
|
|
except Exception as e:
|
|
print(f"✗ unique_item_id may already exist in inventory: {e}")
|
|
|
|
# Step 3: Add unique_item_id to dropped_items (nullable for now)
|
|
try:
|
|
await session.execute(text(
|
|
"ALTER TABLE dropped_items ADD COLUMN IF NOT EXISTS unique_item_id INTEGER REFERENCES unique_items(id) ON DELETE CASCADE"
|
|
))
|
|
print("✓ Added unique_item_id to dropped_items")
|
|
except Exception as e:
|
|
print(f"✗ unique_item_id may already exist in dropped_items: {e}")
|
|
|
|
# Step 4: Migrate existing inventory items with durability to unique_items
|
|
print("\nMigrating existing inventory items to unique_items...")
|
|
result = await session.execute(text("""
|
|
SELECT id, item_id, durability, max_durability, tier, unique_stats
|
|
FROM inventory
|
|
WHERE durability IS NOT NULL OR tier IS NOT NULL OR unique_stats IS NOT NULL
|
|
"""))
|
|
inventory_items = result.fetchall()
|
|
|
|
migrated_count = 0
|
|
for inv_item in inventory_items:
|
|
# Create unique_item entry
|
|
result = await session.execute(text("""
|
|
INSERT INTO unique_items (item_id, durability, max_durability, tier, unique_stats)
|
|
VALUES (:item_id, :durability, :max_durability, :tier, :unique_stats)
|
|
RETURNING id
|
|
"""), {
|
|
'item_id': inv_item.item_id,
|
|
'durability': inv_item.durability,
|
|
'max_durability': inv_item.max_durability,
|
|
'tier': inv_item.tier,
|
|
'unique_stats': inv_item.unique_stats
|
|
})
|
|
unique_item_id = result.fetchone()[0]
|
|
|
|
# Update inventory to reference it
|
|
await session.execute(text("""
|
|
UPDATE inventory
|
|
SET unique_item_id = :unique_item_id
|
|
WHERE id = :inv_id
|
|
"""), {
|
|
'unique_item_id': unique_item_id,
|
|
'inv_id': inv_item.id
|
|
})
|
|
migrated_count += 1
|
|
|
|
print(f"✓ Migrated {migrated_count} inventory items to unique_items")
|
|
|
|
# Step 5: Migrate existing dropped_items with durability to unique_items
|
|
print("\nMigrating existing dropped items to unique_items...")
|
|
result = await session.execute(text("""
|
|
SELECT id, item_id, durability, max_durability, tier, unique_stats
|
|
FROM dropped_items
|
|
WHERE durability IS NOT NULL OR tier IS NOT NULL OR unique_stats IS NOT NULL
|
|
"""))
|
|
dropped_items_list = result.fetchall()
|
|
|
|
migrated_dropped = 0
|
|
for dropped_item in dropped_items_list:
|
|
# Create unique_item entry
|
|
result = await session.execute(text("""
|
|
INSERT INTO unique_items (item_id, durability, max_durability, tier, unique_stats)
|
|
VALUES (:item_id, :durability, :max_durability, :tier, :unique_stats)
|
|
RETURNING id
|
|
"""), {
|
|
'item_id': dropped_item.item_id,
|
|
'durability': dropped_item.durability,
|
|
'max_durability': dropped_item.max_durability,
|
|
'tier': dropped_item.tier,
|
|
'unique_stats': dropped_item.unique_stats
|
|
})
|
|
unique_item_id = result.fetchone()[0]
|
|
|
|
# Update dropped_items to reference it
|
|
await session.execute(text("""
|
|
UPDATE dropped_items
|
|
SET unique_item_id = :unique_item_id
|
|
WHERE id = :dropped_id
|
|
"""), {
|
|
'unique_item_id': unique_item_id,
|
|
'dropped_id': dropped_item.id
|
|
})
|
|
migrated_dropped += 1
|
|
|
|
print(f"✓ Migrated {migrated_dropped} dropped items to unique_items")
|
|
|
|
# Step 6: Drop old columns from inventory (keep for backward compatibility for now)
|
|
# We'll drop these in a future migration after verifying everything works
|
|
print("\n⚠️ Old durability/tier columns still exist for backward compatibility")
|
|
print(" They can be safely removed in a future migration")
|
|
|
|
await session.commit()
|
|
print("\n✅ Migration completed successfully!")
|
|
print(f"\n📊 Summary:")
|
|
print(f" - Created unique_items table")
|
|
print(f" - Migrated {migrated_count} inventory items")
|
|
print(f" - Migrated {migrated_dropped} dropped items")
|
|
print(f" - Total unique items: {migrated_count + migrated_dropped}")
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(migrate())
|