use sea_orm_migration::prelude::*;
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.get_connection()
.execute_unprepared(
r#"
ALTER TABLE ap_reactions ADD COLUMN remote_note_id INTEGER;
ALTER TABLE ap_reactions ADD COLUMN remote_note_object_url TEXT;
-- Add foreign key for remote_note_id
-- SQLite doesn't support ADD CONSTRAINT, so we just add the column
-- The relationship will be enforced at the application level
-- Make note_id nullable (SQLite requires recreating the table)
CREATE TABLE ap_reactions_new (
id INTEGER PRIMARY KEY AUTOINCREMENT,
note_id INTEGER,
remote_note_id INTEGER,
remote_note_object_url TEXT,
kind TEXT NOT NULL,
emoji TEXT,
remote_actor_id INTEGER,
local_user_id INTEGER,
activity_id TEXT,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (note_id) REFERENCES ap_notes(id) ON DELETE CASCADE,
FOREIGN KEY (remote_note_id) REFERENCES ap_remote_notes(id) ON DELETE CASCADE,
FOREIGN KEY (remote_actor_id) REFERENCES ap_remote_actors(id) ON DELETE CASCADE,
FOREIGN KEY (local_user_id) REFERENCES users(id) ON DELETE CASCADE,
CHECK (
((note_id IS NOT NULL) AND (remote_note_id IS NULL)) OR
((note_id IS NULL) AND (remote_note_id IS NOT NULL))
),
CHECK ((remote_actor_id IS NOT NULL) != (local_user_id IS NOT NULL))
);
INSERT INTO ap_reactions_new (id, note_id, kind, emoji, remote_actor_id, local_user_id, activity_id, created_at)
SELECT id, note_id, kind, emoji, remote_actor_id, local_user_id, activity_id, created_at
FROM ap_reactions;
DROP TABLE ap_reactions;
ALTER TABLE ap_reactions_new RENAME TO ap_reactions;
-- Recreate indexes with updated logic
CREATE UNIQUE INDEX unique_ap_remote_reaction_local_note ON ap_reactions (note_id, remote_actor_id, kind, COALESCE(emoji, '')) WHERE note_id IS NOT NULL;
CREATE UNIQUE INDEX unique_ap_local_reaction ON ap_reactions (note_id, local_user_id, kind) WHERE note_id IS NOT NULL;
CREATE UNIQUE INDEX unique_ap_remote_reaction_remote_note ON ap_reactions (remote_note_id, remote_actor_id, kind, COALESCE(emoji, '')) WHERE remote_note_id IS NOT NULL;
CREATE UNIQUE INDEX unique_ap_local_reaction_remote_note ON ap_reactions (remote_note_id, local_user_id, kind) WHERE remote_note_id IS NOT NULL;
"#,
)
.await?;
Ok(())
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.get_connection()
.execute_unprepared(
r#"
CREATE TABLE ap_reactions_old (
id INTEGER PRIMARY KEY AUTOINCREMENT,
note_id INTEGER NOT NULL,
kind TEXT NOT NULL,
emoji TEXT,
remote_actor_id INTEGER,
local_user_id INTEGER,
activity_id TEXT,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (note_id) REFERENCES ap_notes(id) ON DELETE CASCADE,
FOREIGN KEY (remote_actor_id) REFERENCES ap_remote_actors(id) ON DELETE CASCADE,
FOREIGN KEY (local_user_id) REFERENCES users(id) ON DELETE CASCADE,
CHECK ((remote_actor_id IS NOT NULL) != (local_user_id IS NOT NULL))
);
INSERT INTO ap_reactions_old
SELECT id, note_id, kind, emoji, remote_actor_id, local_user_id, activity_id, created_at
FROM ap_reactions
WHERE note_id IS NOT NULL;
DROP TABLE ap_reactions;
ALTER TABLE ap_reactions_old RENAME TO ap_reactions;
CREATE UNIQUE INDEX unique_ap_remote_reaction ON ap_reactions (note_id, remote_actor_id, kind, COALESCE(emoji, ''));
CREATE UNIQUE INDEX unique_ap_local_reaction ON ap_reactions (note_id, local_user_id, kind);
"#,
)
.await?;
Ok(())
}
}