server: Fix schema migration from v8 for sqlite and postgres

Neither supports limits, but we can delete all the duplicate memberships and re-insert a single one
This commit is contained in:
Valentin Tolmer
2024-11-21 23:22:53 +01:00
committed by nitnelave
parent 64514ddfc6
commit 0ddeab8caa
+22 -37
View File
@@ -5,8 +5,8 @@ use crate::domain::{
use itertools::Itertools; use itertools::Itertools;
use sea_orm::{ use sea_orm::{
sea_query::{ sea_query::{
self, all, Alias, BinOper, BlobSize::Blob, ColumnDef, Expr, ForeignKey, ForeignKeyAction, self, all, BinOper, BlobSize::Blob, ColumnDef, Expr, ForeignKey, ForeignKeyAction, Func,
Func, Index, Query, SimpleExpr, Table, Value, Index, Query, SimpleExpr, Table, Value,
}, },
ConnectionTrait, DatabaseTransaction, DbErr, DeriveIden, FromQueryResult, Iden, Order, ConnectionTrait, DatabaseTransaction, DbErr, DeriveIden, FromQueryResult, Iden, Order,
Statement, TransactionTrait, Statement, TransactionTrait,
@@ -970,21 +970,15 @@ async fn migrate_to_v8(transaction: DatabaseTransaction) -> Result<DatabaseTrans
let builder = transaction.get_database_backend(); let builder = transaction.get_database_backend();
// Remove duplicate memberships. // Remove duplicate memberships.
#[derive(FromQueryResult)] #[derive(FromQueryResult)]
#[allow(dead_code)]
struct MembershipInfo { struct MembershipInfo {
user_id: UserId, user_id: UserId,
group_id: GroupId, group_id: GroupId,
cnt: i64,
} }
let mut delete_queries = MembershipInfo::find_by_statement( for MembershipInfo { user_id, group_id } in MembershipInfo::find_by_statement(
builder.build( builder.build(
Query::select() Query::select()
.from(Memberships::Table) .from(Memberships::Table)
.columns([Memberships::UserId, Memberships::GroupId]) .columns([Memberships::UserId, Memberships::GroupId])
.expr_as(
Expr::count(Expr::col((Memberships::Table, Memberships::UserId))),
Alias::new("cnt"),
)
.group_by_columns([Memberships::UserId, Memberships::GroupId]) .group_by_columns([Memberships::UserId, Memberships::GroupId])
.cond_having(all![SimpleExpr::Binary( .cond_having(all![SimpleExpr::Binary(
Box::new(Expr::col((Memberships::Table, Memberships::UserId)).count()), Box::new(Expr::col((Memberships::Table, Memberships::UserId)).count()),
@@ -996,38 +990,29 @@ async fn migrate_to_v8(transaction: DatabaseTransaction) -> Result<DatabaseTrans
.all(&transaction) .all(&transaction)
.await? .await?
.into_iter() .into_iter()
.map( {
|MembershipInfo { transaction
user_id, .execute(
group_id, builder.build(
cnt,
}| {
builder
.build(
Query::delete() Query::delete()
.from_table(Memberships::Table) .from_table(Memberships::Table)
.cond_where(all![ .cond_where(all![
Expr::col(Memberships::UserId).eq(user_id), Expr::col(Memberships::UserId).eq(&user_id),
Expr::col(Memberships::GroupId).eq(group_id) Expr::col(Memberships::GroupId).eq(group_id)
]) ]),
.limit(cnt as u64 - 1), ),
) )
.to_owned() .await?;
}, transaction
) .execute(
.peekable(); builder.build(
if delete_queries.peek().is_some() { Query::insert()
match transaction.get_database_backend() { .into_table(Memberships::Table)
sea_orm::DatabaseBackend::Sqlite => { .columns([Memberships::UserId, Memberships::GroupId])
return Err(DbErr::Migration(format!( .values_panic([user_id.into(), group_id.into()]),
"The Sqlite driver does not support LIMIT in DELETE. Run these queries manually:\n{}" , delete_queries.map(|s| s.to_string()).join("\n")))); ),
} )
sea_orm::DatabaseBackend::MySql | sea_orm::DatabaseBackend::Postgres => { .await?;
for query in delete_queries {
transaction.execute(query).await?;
}
}
}
} }
transaction transaction
.execute( .execute(