fix(users): handle active discounts on delete
Ensure active_discounts cascades on user/promo removal, clean orphan rows during migration, and rely on DB cascade for user deletion.
This commit is contained in:
@@ -168,6 +168,48 @@ def _migration_0004_add_discount_promo_codes(connection: Connection) -> None:
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _migration_0005_fix_active_discounts_fk_cascade(connection: Connection) -> None:
|
||||||
|
inspector = inspect(connection)
|
||||||
|
if not inspector.has_table("active_discounts"):
|
||||||
|
return
|
||||||
|
|
||||||
|
connection.execute(
|
||||||
|
text(
|
||||||
|
"DELETE FROM active_discounts ad "
|
||||||
|
"WHERE NOT EXISTS (SELECT 1 FROM users u WHERE u.user_id = ad.user_id) "
|
||||||
|
"OR NOT EXISTS (SELECT 1 FROM promo_codes p WHERE p.promo_code_id = ad.promo_code_id)"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
connection.execute(
|
||||||
|
text("ALTER TABLE active_discounts DROP CONSTRAINT IF EXISTS active_discounts_user_id_fkey")
|
||||||
|
)
|
||||||
|
connection.execute(
|
||||||
|
text("ALTER TABLE active_discounts DROP CONSTRAINT IF EXISTS fk_active_discounts_user")
|
||||||
|
)
|
||||||
|
connection.execute(
|
||||||
|
text("ALTER TABLE active_discounts DROP CONSTRAINT IF EXISTS active_discounts_promo_code_id_fkey")
|
||||||
|
)
|
||||||
|
connection.execute(
|
||||||
|
text("ALTER TABLE active_discounts DROP CONSTRAINT IF EXISTS fk_active_discounts_promo_code")
|
||||||
|
)
|
||||||
|
|
||||||
|
connection.execute(
|
||||||
|
text(
|
||||||
|
"ALTER TABLE active_discounts "
|
||||||
|
"ADD CONSTRAINT fk_active_discounts_user "
|
||||||
|
"FOREIGN KEY (user_id) REFERENCES users (user_id) ON DELETE CASCADE"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
connection.execute(
|
||||||
|
text(
|
||||||
|
"ALTER TABLE active_discounts "
|
||||||
|
"ADD CONSTRAINT fk_active_discounts_promo_code "
|
||||||
|
"FOREIGN KEY (promo_code_id) REFERENCES promo_codes (promo_code_id) ON DELETE CASCADE"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
MIGRATIONS: List[Migration] = [
|
MIGRATIONS: List[Migration] = [
|
||||||
Migration(
|
Migration(
|
||||||
id="0001_add_channel_subscription_fields",
|
id="0001_add_channel_subscription_fields",
|
||||||
@@ -189,6 +231,11 @@ MIGRATIONS: List[Migration] = [
|
|||||||
description="Add support for percentage discount promo codes",
|
description="Add support for percentage discount promo codes",
|
||||||
upgrade=_migration_0004_add_discount_promo_codes,
|
upgrade=_migration_0004_add_discount_promo_codes,
|
||||||
),
|
),
|
||||||
|
Migration(
|
||||||
|
id="0005_fix_active_discounts_fk_cascade",
|
||||||
|
description="Ensure active_discounts FKs cascade on user/promo delete",
|
||||||
|
upgrade=_migration_0005_fix_active_discounts_fk_cascade,
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+10
-2
@@ -210,8 +210,16 @@ class ActiveDiscount(Base):
|
|||||||
"""Tracks pending discount promo codes awaiting payment (permanent until used)"""
|
"""Tracks pending discount promo codes awaiting payment (permanent until used)"""
|
||||||
__tablename__ = "active_discounts"
|
__tablename__ = "active_discounts"
|
||||||
|
|
||||||
user_id = Column(BigInteger, ForeignKey("users.user_id"), primary_key=True)
|
user_id = Column(
|
||||||
promo_code_id = Column(Integer, ForeignKey("promo_codes.promo_code_id"), nullable=False)
|
BigInteger,
|
||||||
|
ForeignKey("users.user_id", ondelete="CASCADE"),
|
||||||
|
primary_key=True,
|
||||||
|
)
|
||||||
|
promo_code_id = Column(
|
||||||
|
Integer,
|
||||||
|
ForeignKey("promo_codes.promo_code_id", ondelete="CASCADE"),
|
||||||
|
nullable=False,
|
||||||
|
)
|
||||||
discount_percentage = Column(Integer, nullable=False)
|
discount_percentage = Column(Integer, nullable=False)
|
||||||
activated_at = Column(DateTime(timezone=True), server_default=func.now())
|
activated_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user