From 17612e544631463d4cf80b04f3548c400b04b989 Mon Sep 17 00:00:00 2001 From: Leo Hemsted Date: Mon, 24 Sep 2018 15:36:05 +0100 Subject: [PATCH] add postage constraint to notification history A not valid constraint only checks against new rows, not existing rows. We can call VALIDATE CONSTRAINT against this new constraint to check the old rows (which we know are good, having run the command from 74961781). Adding a normal constraint acquires an ACCESS EXCLUSIVE lock, but validate constraint only needs a SHARE UPDATE EXCLUSIVE lock. see 9d4b8961 and 0a50993f for more information on marking constraints as not valid. --- app/models.py | 16 ++++++- .../versions/0230_noti_postage_constraint.py | 44 +++++++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 migrations/versions/0230_noti_postage_constraint.py diff --git a/app/models.py b/app/models.py index fbd1b7419..cf58a6867 100644 --- a/app/models.py +++ b/app/models.py @@ -1191,7 +1191,13 @@ class Notification(db.Model): reply_to_text = db.Column(db.String, nullable=True) postage = db.Column(db.String, nullable=True) - CheckConstraint("notification_type != 'letter' or postage in ('first', 'second')") + CheckConstraint(""" + CASE WHEN notification_type = 'letter' THEN + postage in ('first', 'second') + ELSE + postage is null + END + """) __table_args__ = ( db.ForeignKeyConstraint( @@ -1445,7 +1451,13 @@ class NotificationHistory(db.Model, HistoryModel): created_by_id = db.Column(UUID(as_uuid=True), db.ForeignKey('users.id'), nullable=True) postage = db.Column(db.String, nullable=True) - CheckConstraint("notification_type != 'letter' or postage in ('first', 'second')") + CheckConstraint(""" + CASE WHEN notification_type = 'letter' THEN + postage in ('first', 'second') + ELSE + postage is null + END + """) __table_args__ = ( db.ForeignKeyConstraint( diff --git a/migrations/versions/0230_noti_postage_constraint.py b/migrations/versions/0230_noti_postage_constraint.py new file mode 100644 index 000000000..118d51b39 --- /dev/null +++ b/migrations/versions/0230_noti_postage_constraint.py @@ -0,0 +1,44 @@ +""" + +Revision ID: 0230_noti_postage_constraint +Revises: 0229_new_letter_rates +Create Date: 2018-09-19 11:42:52.229430 + +""" +from alembic import op + + +revision = '0230_noti_postage_constraint' +down_revision = '0229_new_letter_rates' + + +def upgrade(): + op.execute(""" + ALTER TABLE notifications ADD CONSTRAINT "chk_notifications_postage_null" + CHECK ( + CASE WHEN notification_type = 'letter' THEN + postage in ('first', 'second') + ELSE + postage is null + END + ) + NOT VALID + """) + op.execute(""" + ALTER TABLE notification_history ADD CONSTRAINT "chk_notification_history_postage_null" + CHECK ( + CASE WHEN notification_type = 'letter' THEN + postage in ('first', 'second') + ELSE + postage is null + END + ) + NOT VALID + """) + op.execute('ALTER TABLE notifications VALIDATE CONSTRAINT "chk_notifications_postage_null"') + op.execute('ALTER TABLE notification_history VALIDATE CONSTRAINT "chk_notification_history_postage_null"') + + +def downgrade(): + op.drop_constraint('chk_notifications_postage_null', 'notifications', type_='check') + op.drop_constraint('chk_notification_history_postage_null', 'notification_history', type_='check')