// SPDX-FileCopyrightText: 2026 Ololduck <ololduck@vit.am> and contributors
//
// SPDX-License-Identifier: GPL-3.0-or-later
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> {
// Recreate ap_actors without the XOR constraint to allow instance actor
// (both user_id and repo_id NULL)
manager
.get_connection()
.execute_unprepared(
"CREATE TABLE IF NOT EXISTS ap_actors_new (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER,
repo_id INTEGER,
private_key_pem TEXT NOT NULL,
public_key_pem TEXT NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (repo_id) REFERENCES repositories(id) ON DELETE CASCADE,
UNIQUE (user_id),
UNIQUE (repo_id)
)",
)
.await?;
// Copy data from old table
manager
.get_connection()
.execute_unprepared("INSERT INTO ap_actors_new SELECT * FROM ap_actors")
.await?;
// Drop old table and rename new one
manager
.get_connection()
.execute_unprepared("DROP TABLE ap_actors")
.await?;
manager
.get_connection()
.execute_unprepared("ALTER TABLE ap_actors_new RENAME TO ap_actors")
.await?;
Ok(())
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
// Recreate with XOR constraint
manager
.get_connection()
.execute_unprepared(
"CREATE TABLE IF NOT EXISTS ap_actors_old (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER UNIQUE,
repo_id INTEGER UNIQUE,
private_key_pem TEXT NOT NULL,
public_key_pem TEXT NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (repo_id) REFERENCES repositories(id) ON DELETE CASCADE,
CHECK ((user_id IS NOT NULL) != (repo_id IS NOT NULL))
)",
)
.await?;
// Copy data (excluding instance actor if it exists)
manager
.get_connection()
.execute_unprepared(
"INSERT INTO ap_actors_old
SELECT * FROM ap_actors
WHERE user_id IS NOT NULL OR repo_id IS NOT NULL",
)
.await?;
manager
.get_connection()
.execute_unprepared("DROP TABLE ap_actors")
.await?;
manager
.get_connection()
.execute_unprepared("ALTER TABLE ap_actors_old RENAME TO ap_actors")
.await?;
Ok(())
}
}