From 6eae448626f1a5881eb76a6c00508459c1ecb364 Mon Sep 17 00:00:00 2001 From: Vladimir Filonov Date: Sun, 24 Nov 2024 13:11:12 +0400 Subject: [PATCH] Fix foreign key in lastalerttoincident for complex primary key in lastalert --- keep/api/models/db/alert.py | 2 +- .../versions/2024-11-13-22-48_bdae8684d0b4.py | 82 +++++++++++-------- 2 files changed, 49 insertions(+), 35 deletions(-) diff --git a/keep/api/models/db/alert.py b/keep/api/models/db/alert.py index 9e80f9599..a31a3089b 100644 --- a/keep/api/models/db/alert.py +++ b/keep/api/models/db/alert.py @@ -82,7 +82,7 @@ class LastAlert(SQLModel, table=True): class LastAlertToIncident(SQLModel, table=True): - tenant_id: str = Field(foreign_key="tenant.id", nullable=False) + tenant_id: str = Field(foreign_key="tenant.id", nullable=False, primary_key=True) timestamp: datetime = Field(default_factory=datetime.utcnow) fingerprint: str = Field(foreign_key="lastalert.fingerprint", primary_key=True) diff --git a/keep/api/models/db/migrations/versions/2024-11-13-22-48_bdae8684d0b4.py b/keep/api/models/db/migrations/versions/2024-11-13-22-48_bdae8684d0b4.py index 908495fa0..587f072f9 100644 --- a/keep/api/models/db/migrations/versions/2024-11-13-22-48_bdae8684d0b4.py +++ b/keep/api/models/db/migrations/versions/2024-11-13-22-48_bdae8684d0b4.py @@ -20,6 +20,7 @@ migration_metadata = sa.MetaData() + def populate_db(): session = Session(op.get_bind()) @@ -32,8 +33,8 @@ def populate_db(): select alert.fingerprint, max(alert.timestamp) as last_received from alert - group by fingerprint - ) as a ON alert.fingerprint = a.fingerprint and alert.timestamp = a.last_received + group by fingerprint, tenant_id + ) as a ON alert.fingerprint = a.fingerprint and alert.timestamp = a.last_received and alert.tenant_id = a.tenant_id on conflict do nothing """ @@ -44,14 +45,14 @@ def populate_db(): from alerttoincident as ati join ( - select alert.id, alert.fingerprint + select alert.tenant_id, alert.id, alert.fingerprint from alert join ( select - alert.fingerprint, max(alert.timestamp) as last_received + alert.tenant_id, alert.fingerprint, max(alert.timestamp) as last_received from alert - group by fingerprint - ) as a on alert.fingerprint = a.fingerprint and alert.timestamp = a.last_received + group by fingerprint, tenant_id + ) as a on alert.fingerprint = a.fingerprint and alert.timestamp = a.last_received and alert.tenant_id = a.tenant_id ) as lf on ati.alert_id = lf.id on conflict do nothing @@ -59,33 +60,43 @@ def populate_db(): else: migrate_lastalert_query = """ - replace into lastalert (tenant_id, fingerprint, alert_id, timestamp) - select alert.tenant_id, alert.fingerprint, alert.id as alert_id, alert.timestamp + INSERT INTO lastalert (tenant_id, fingerprint, alert_id, timestamp) + SELECT + grouped_alerts.tenant_id, + grouped_alerts.fingerprint, + MAX(grouped_alerts.alert_id) as alert_id, -- Using MAX to consistently pick one alert_id + grouped_alerts.timestamp + FROM ( + select alert.tenant_id, alert.fingerprint, alert.id as alert_id, alert.timestamp + from alert + join ( + select + alert.tenant_id, alert.fingerprint, max(alert.timestamp) as last_received from alert - join ( - select - alert.fingerprint, max(alert.timestamp) as last_received - from alert - group by fingerprint - ) as a ON alert.fingerprint = a.fingerprint and alert.timestamp = a.last_received; - """ + group by fingerprint, tenant_id + ) as a ON alert.fingerprint = a.fingerprint + and alert.timestamp = a.last_received + and alert.tenant_id = a.tenant_id + ) as grouped_alerts + GROUP BY grouped_alerts.tenant_id, grouped_alerts.fingerprint, grouped_alerts.timestamp; +""" migrate_lastalerttoincident_query = """ - replace into lastalerttoincident (incident_id, tenant_id, timestamp, fingerprint, is_created_by_ai, deleted_at) - select ati.incident_id, ati.tenant_id, ati.timestamp, lf.fingerprint, ati.is_created_by_ai, ati.deleted_at - from alerttoincident as ati - join - ( - select alert.id, alert.fingerprint + REPLACE INTO lastalerttoincident (incident_id, tenant_id, timestamp, fingerprint, is_created_by_ai, deleted_at) + select ati.incident_id, ati.tenant_id, ati.timestamp, lf.fingerprint, ati.is_created_by_ai, ati.deleted_at + from alerttoincident as ati + join + ( + select alert.id, alert.fingerprint, alert.tenant_id + from alert + join ( + select + alert.tenant_id,alert.fingerprint, max(alert.timestamp) as last_received from alert - join ( - select - alert.fingerprint, max(alert.timestamp) as last_received - from alert - group by fingerprint - ) as a on alert.fingerprint = a.fingerprint and alert.timestamp = a.last_received - ) as lf on ati.alert_id = lf.id - """ + group by fingerprint, tenant_id + ) as a on alert.fingerprint = a.fingerprint and alert.timestamp = a.last_received and alert.tenant_id = a.tenant_id + ) as lf on ati.alert_id = lf.id; + """ session.execute(migrate_lastalert_query) session.execute(migrate_lastalerttoincident_query) @@ -102,12 +113,14 @@ def upgrade() -> None: ["alert_id"], ["alert.id"], ), - sa.PrimaryKeyConstraint("fingerprint"), + sa.PrimaryKeyConstraint("tenant_id", "fingerprint"), ) with op.batch_alter_table("lastalert", schema=None) as batch_op: batch_op.create_index( batch_op.f("ix_lastalert_timestamp"), ["timestamp"], unique=False ) + # Add index for the fingerprint column that will be referenced by foreign key + batch_op.create_index("ix_lastalert_fingerprint", ["fingerprint"], unique=False) op.create_table( "lastalerttoincident", @@ -122,22 +135,23 @@ def upgrade() -> None: sa.Column("is_created_by_ai", sa.Boolean(), nullable=False), sa.Column("deleted_at", sa.DateTime(), nullable=True), sa.ForeignKeyConstraint( - ["fingerprint"], - ["lastalert.fingerprint"], + ["tenant_id", "fingerprint"], + ["lastalert.tenant_id", "lastalert.fingerprint"], ), sa.ForeignKeyConstraint(["incident_id"], ["incident.id"], ondelete="CASCADE"), sa.ForeignKeyConstraint( ["tenant_id"], ["tenant.id"], ), - sa.PrimaryKeyConstraint("incident_id", "fingerprint", "deleted_at"), + sa.PrimaryKeyConstraint("tenant_id", "incident_id", "fingerprint", "deleted_at"), ) populate_db() + def downgrade() -> None: op.drop_table("lastalerttoincident") with op.batch_alter_table("lastalert", schema=None) as batch_op: batch_op.drop_index(batch_op.f("ix_lastalert_timestamp")) - op.drop_table("lastalert") + op.drop_table("lastalert") \ No newline at end of file