Skip to content

Commit 764c42b

Browse files
authored
Release Candidate v4.0.2 (#222)
2 parents 15dbd8f + 9d5111e commit 764c42b

File tree

2 files changed

+44
-16
lines changed

2 files changed

+44
-16
lines changed

.version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
4.0.1
1+
4.0.2

src/db/alembic/versions/3f8b2e4c9a71_ensure_whatsapp_agent_exists.py renamed to src/db/alembic/versions/7a9c3e5f2b1d_fix_agent_id_with_correct_order.py

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
"""ensure_whatsapp_agent_exists
1+
"""fix_agent_id_with_correct_order
22
3-
Revision ID: 3f8b2e4c9a71
3+
Revision ID: 7a9c3e5f2b1d
44
Revises: d654ae68d8e9
5-
Create Date: 2025-10-29 01:30:00.000000
5+
Create Date: 2025-10-29 02:00:00.000000
66
77
"""
88
from typing import Sequence, Union
@@ -14,18 +14,18 @@
1414
from util.config import config
1515

1616
# revision identifiers, used by Alembic.
17-
revision: str = "3f8b2e4c9a71"
17+
revision: str = "7a9c3e5f2b1d"
1818
down_revision: Union[str, None] = "d654ae68d8e9"
1919
branch_labels: Union[str, Sequence[str], None] = None
2020
depends_on: Union[str, Sequence[str], None] = None
2121

2222

2323
def upgrade() -> None:
2424
# This migration ensures the agent exists with the correct ID and WhatsApp fields
25-
# Handles three scenarios:
26-
# 1. Production: agent exists with wrong ID (9e0c5a1a...) -> migrate messages, delete old, create correct
27-
# 2. Local/Staging: multiple agents exist -> migrate messages, delete duplicates, upsert correct one
28-
# 3. Fresh DB: agent doesn't exist -> create it
25+
# Order matters:
26+
# 1. Create/upsert correct agent FIRST (must exist before messages can reference it)
27+
# 2. Migrate messages from wrong agent -> correct agent (safe now)
28+
# 3. Delete wrong agent (safe because messages no longer reference it)
2929
# Idempotent: safe to run multiple times
3030

3131
assert THE_AGENT.whatsapp_phone_number is not None, "Agent phone number must be set"
@@ -34,8 +34,15 @@ def upgrade() -> None:
3434
encryption_key = config.token_encrypt_secret.get_secret_value()
3535
wa_phone_plaintext = THE_AGENT.whatsapp_phone_number.get_secret_value()
3636

37-
# Step 1: Migrate any chat messages from wrong agent ID to correct ID
38-
# This handles local/staging where messages reference the wrong agent
37+
# Temporarily drop foreign key constraints to allow ID updates
38+
# This is necessary because we may need to change the agent's primary key
39+
op.execute(text("ALTER TABLE chat_messages DROP CONSTRAINT IF EXISTS chat_messages_author_id_fkey"))
40+
op.execute(text("ALTER TABLE price_alerts DROP CONSTRAINT IF EXISTS price_alerts_owner_id_fkey"))
41+
op.execute(text("ALTER TABLE sponsorships DROP CONSTRAINT IF EXISTS sponsorships_sponsor_id_fkey"))
42+
op.execute(text("ALTER TABLE sponsorships DROP CONSTRAINT IF EXISTS sponsorships_receiver_id_fkey"))
43+
44+
# Step 1: Migrate messages from wrong agent ID to correct ID (before agent exists)
45+
# Safe because FK constraint is temporarily dropped
3946
op.execute(text("""
4047
UPDATE chat_messages
4148
SET author_id = :correct_id
@@ -50,7 +57,7 @@ def upgrade() -> None:
5057
))
5158

5259
# Step 2: Delete any agent with matching telegram_user_id but wrong ID
53-
# Now safe to delete since messages have been migrated
60+
# Safe now because messages no longer reference it
5461
op.execute(text("""
5562
DELETE FROM simulants
5663
WHERE telegram_user_id = :telegram_user_id
@@ -60,8 +67,8 @@ def upgrade() -> None:
6067
telegram_user_id = THE_AGENT.telegram_user_id,
6168
))
6269

63-
# Step 3: Upsert the agent with correct ID and all current fields
64-
# Insert if not exists, update if exists
70+
# Step 3: Insert correct agent (or update if somehow already exists)
71+
# Safe now because no unique constraint conflicts
6572
op.execute(text("""
6673
INSERT INTO simulants (
6774
id,
@@ -105,8 +112,29 @@ def upgrade() -> None:
105112
created_at = "2024-01-01",
106113
))
107114

115+
# Re-add foreign key constraints
116+
op.execute(text("""
117+
ALTER TABLE chat_messages
118+
ADD CONSTRAINT chat_messages_author_id_fkey
119+
FOREIGN KEY (author_id) REFERENCES simulants(id)
120+
"""))
121+
op.execute(text("""
122+
ALTER TABLE price_alerts
123+
ADD CONSTRAINT price_alerts_owner_id_fkey
124+
FOREIGN KEY (owner_id) REFERENCES simulants(id)
125+
"""))
126+
op.execute(text("""
127+
ALTER TABLE sponsorships
128+
ADD CONSTRAINT sponsorships_sponsor_id_fkey
129+
FOREIGN KEY (sponsor_id) REFERENCES simulants(id)
130+
"""))
131+
op.execute(text("""
132+
ALTER TABLE sponsorships
133+
ADD CONSTRAINT sponsorships_receiver_id_fkey
134+
FOREIGN KEY (receiver_id) REFERENCES simulants(id)
135+
"""))
136+
108137

109138
def downgrade() -> None:
110-
# No downgrade. We don't want to delete the agent in production.
111-
# Too risky - simply add a new migration.
139+
# No downgrade - we don't want to delete the agent in production
112140
pass

0 commit comments

Comments
 (0)