use thread to copy data
This commit is contained in:
parent
3010ac9e74
commit
d9d2673939
6 changed files with 342 additions and 439 deletions
|
@ -8,10 +8,17 @@ publish = false
|
|||
name = "migration"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
convert = []
|
||||
|
||||
[dependencies]
|
||||
async-std = { version = "1", features = ["attributes", "tokio1"] }
|
||||
serde_json = "1.0.96"
|
||||
model = { path = "../model" }
|
||||
indicatif = { version = "0.17.4", features = ["tokio"] }
|
||||
tokio = { version = "1.28.2", features = ["full"] }
|
||||
futures = "0.3.28"
|
||||
|
||||
[dependencies.sea-orm-migration]
|
||||
version = "0.11.0"
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
pub use sea_orm_migration::prelude::*;
|
||||
|
||||
mod m20230531_180824_stringvec;
|
||||
mod m20230531_180824_drop_reversi;
|
||||
|
||||
pub struct Migrator;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigratorTrait for Migrator {
|
||||
fn migrations() -> Vec<Box<dyn MigrationTrait>> {
|
||||
vec![Box::new(m20230531_180824_stringvec::Migration)]
|
||||
vec![Box::new(m20230531_180824_drop_reversi::Migration)]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
use sea_orm_migration::{
|
||||
prelude::*,
|
||||
sea_orm::{DbBackend, Statement},
|
||||
};
|
||||
|
||||
#[derive(DeriveMigrationName)]
|
||||
pub struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
if manager.get_database_backend() == DbBackend::Sqlite {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let db = manager.get_connection();
|
||||
db.query_one(Statement::from_string(
|
||||
DbBackend::Postgres,
|
||||
Table::drop()
|
||||
.table(ReversiGame::Table)
|
||||
.to_string(PostgresQueryBuilder),
|
||||
))
|
||||
.await?;
|
||||
db.query_one(Statement::from_string(
|
||||
DbBackend::Postgres,
|
||||
Table::drop()
|
||||
.table(ReversiMatching::Table)
|
||||
.to_string(PostgresQueryBuilder),
|
||||
))
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn down(&self, _manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
// Replace the sample below with your own migration scripts
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Learn more at https://docs.rs/sea-query#iden
|
||||
#[derive(Iden)]
|
||||
enum ReversiGame {
|
||||
Table,
|
||||
}
|
||||
#[derive(Iden)]
|
||||
enum ReversiMatching {
|
||||
Table,
|
||||
}
|
|
@ -1,437 +0,0 @@
|
|||
use model::entity::{
|
||||
access_token, antenna, app, emoji, gallery_post, hashtag, messaging_message, meta,
|
||||
newtype::{I32Vec, StringVec},
|
||||
note, note_edit, page, poll, registry_item, user, user_profile, webhook,
|
||||
};
|
||||
use sea_orm_migration::{
|
||||
prelude::*,
|
||||
sea_orm::{DbBackend, EntityTrait, Statement, TryGetable},
|
||||
};
|
||||
use serde_json::json;
|
||||
|
||||
#[derive(DeriveMigrationName)]
|
||||
pub struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.drop_table(
|
||||
Table::drop()
|
||||
.if_exists()
|
||||
.table(ReversiGame::Table)
|
||||
.to_owned(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.drop_table(
|
||||
Table::drop()
|
||||
.if_exists()
|
||||
.table(ReversiMatching::Table)
|
||||
.to_owned(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
if manager.get_database_backend() == DbBackend::Sqlite {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let db = manager.get_connection();
|
||||
|
||||
macro_rules! copy_data {
|
||||
($data:ident, $ent:ident, $col:tt) => {
|
||||
let models: Vec<$ent::ActiveModel> = $data
|
||||
.iter()
|
||||
.map(|(id, r)| $ent::ActiveModel {
|
||||
id: sea_orm::Set(id.to_owned()),
|
||||
$col: sea_orm::Set(StringVec::from(r.to_owned())),
|
||||
..Default::default()
|
||||
})
|
||||
.collect();
|
||||
for model in models {
|
||||
$ent::Entity::update(model).exec(db).await?;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! convert_to_stringvec_json {
|
||||
($table:expr, $id:expr, $col:expr, $ent:ident, $col_name:tt) => {
|
||||
let query = select_query($table, $id, $col);
|
||||
let res = get_vec::<Vec<String>>(db, query).await?;
|
||||
convert_col(manager, $table, $col).await?;
|
||||
copy_data!(res, $ent, $col_name);
|
||||
};
|
||||
}
|
||||
|
||||
convert_to_stringvec_json!(
|
||||
AccessToken::Table,
|
||||
AccessToken::Id,
|
||||
AccessToken::Permission,
|
||||
access_token,
|
||||
permission
|
||||
);
|
||||
convert_to_stringvec_json!(Antenna::Table, Antenna::Id, Antenna::Users, antenna, users);
|
||||
convert_to_stringvec_json!(App::Table, App::Id, App::Permission, app, permission);
|
||||
convert_to_stringvec_json!(Emoji::Table, Emoji::Id, Emoji::Aliases, emoji, aliases);
|
||||
convert_to_stringvec_json!(
|
||||
GalleryPost::Table,
|
||||
GalleryPost::Id,
|
||||
GalleryPost::FileIds,
|
||||
gallery_post,
|
||||
file_ids
|
||||
);
|
||||
convert_to_stringvec_json!(
|
||||
GalleryPost::Table,
|
||||
GalleryPost::Id,
|
||||
GalleryPost::Tags,
|
||||
gallery_post,
|
||||
tags
|
||||
);
|
||||
convert_to_stringvec_json!(
|
||||
Hashtag::Table,
|
||||
Hashtag::Id,
|
||||
Hashtag::MentionedUserIds,
|
||||
hashtag,
|
||||
mentioned_user_ids
|
||||
);
|
||||
convert_to_stringvec_json!(
|
||||
Hashtag::Table,
|
||||
Hashtag::Id,
|
||||
Hashtag::MentionedLocalUserIds,
|
||||
hashtag,
|
||||
mentioned_local_user_ids
|
||||
);
|
||||
convert_to_stringvec_json!(
|
||||
Hashtag::Table,
|
||||
Hashtag::Id,
|
||||
Hashtag::MentionedRemoteUserIds,
|
||||
hashtag,
|
||||
mentioned_remote_user_ids
|
||||
);
|
||||
convert_to_stringvec_json!(
|
||||
Hashtag::Table,
|
||||
Hashtag::Id,
|
||||
Hashtag::AttachedUserIds,
|
||||
hashtag,
|
||||
attached_user_ids
|
||||
);
|
||||
convert_to_stringvec_json!(
|
||||
Hashtag::Table,
|
||||
Hashtag::Id,
|
||||
Hashtag::AttachedLocalUserIds,
|
||||
hashtag,
|
||||
attached_local_user_ids
|
||||
);
|
||||
convert_to_stringvec_json!(
|
||||
Hashtag::Table,
|
||||
Hashtag::Id,
|
||||
Hashtag::AttachedRemoteUserIds,
|
||||
hashtag,
|
||||
attached_remote_user_ids
|
||||
);
|
||||
convert_to_stringvec_json!(
|
||||
MessagingMessage::Table,
|
||||
MessagingMessage::Id,
|
||||
MessagingMessage::Reads,
|
||||
messaging_message,
|
||||
reads
|
||||
);
|
||||
convert_to_stringvec_json!(Meta::Table, Meta::Id, Meta::Langs, meta, langs);
|
||||
convert_to_stringvec_json!(
|
||||
Meta::Table,
|
||||
Meta::Id,
|
||||
Meta::BlockedHosts,
|
||||
meta,
|
||||
blocked_hosts
|
||||
);
|
||||
convert_to_stringvec_json!(Meta::Table, Meta::Id, Meta::HiddenTags, meta, hidden_tags);
|
||||
convert_to_stringvec_json!(Meta::Table, Meta::Id, Meta::PinnedUsers, meta, pinned_users);
|
||||
convert_to_stringvec_json!(Meta::Table, Meta::Id, Meta::PinnedPages, meta, pinned_pages);
|
||||
convert_to_stringvec_json!(
|
||||
Meta::Table,
|
||||
Meta::Id,
|
||||
Meta::RecommendedInstances,
|
||||
meta,
|
||||
recommended_instances
|
||||
);
|
||||
convert_to_stringvec_json!(
|
||||
Meta::Table,
|
||||
Meta::Id,
|
||||
Meta::SilencedHosts,
|
||||
meta,
|
||||
silenced_hosts
|
||||
);
|
||||
convert_to_stringvec_json!(Note::Table, Note::Id, Note::FileIds, note, file_ids);
|
||||
convert_to_stringvec_json!(
|
||||
Note::Table,
|
||||
Note::Id,
|
||||
Note::AttachedFileTypes,
|
||||
note,
|
||||
attached_file_types
|
||||
);
|
||||
convert_to_stringvec_json!(
|
||||
Note::Table,
|
||||
Note::Id,
|
||||
Note::VisibleUserIds,
|
||||
note,
|
||||
visible_user_ids
|
||||
);
|
||||
convert_to_stringvec_json!(Note::Table, Note::Id, Note::Mentions, note, mentions);
|
||||
convert_to_stringvec_json!(Note::Table, Note::Id, Note::Emojis, note, emojis);
|
||||
convert_to_stringvec_json!(Note::Table, Note::Id, Note::Tags, note, tags);
|
||||
convert_to_stringvec_json!(
|
||||
NoteEdit::Table,
|
||||
NoteEdit::Id,
|
||||
NoteEdit::FileIds,
|
||||
note_edit,
|
||||
file_ids
|
||||
);
|
||||
convert_to_stringvec_json!(
|
||||
Page::Table,
|
||||
Page::Id,
|
||||
Page::VisibleUserIds,
|
||||
page,
|
||||
visible_user_ids
|
||||
);
|
||||
convert_to_stringvec_json!(
|
||||
RegistryItem::Table,
|
||||
RegistryItem::Id,
|
||||
RegistryItem::Scope,
|
||||
registry_item,
|
||||
scope
|
||||
);
|
||||
convert_to_stringvec_json!(User::Table, User::Id, User::Tags, user, tags);
|
||||
convert_to_stringvec_json!(User::Table, User::Id, User::Emojis, user, emojis);
|
||||
convert_to_stringvec_json!(Webhook::Table, Webhook::Id, Webhook::On, webhook, on);
|
||||
|
||||
// Convert poll here because its primary key is not id, but note_id.
|
||||
let query = select_query(Poll::Table, Poll::NoteId, Poll::Choices);
|
||||
let res = get_vec::<Vec<String>>(db, query).await?;
|
||||
convert_col(manager, Poll::Table, Poll::Choices).await?;
|
||||
let models: Vec<poll::ActiveModel> = res
|
||||
.iter()
|
||||
.map(|(id, r)| poll::ActiveModel {
|
||||
note_id: sea_orm::Set(id.to_owned()),
|
||||
choices: sea_orm::Set(StringVec::from(r.to_owned())),
|
||||
..Default::default()
|
||||
})
|
||||
.collect();
|
||||
for model in models {
|
||||
poll::Entity::update(model).exec(db).await?;
|
||||
}
|
||||
let query = select_query(Poll::Table, Poll::NoteId, Poll::Votes);
|
||||
let res = get_vec::<Vec<i32>>(db, query).await?;
|
||||
convert_col(manager, Poll::Table, Poll::Votes).await?;
|
||||
let models: Vec<poll::ActiveModel> = res
|
||||
.iter()
|
||||
.map(|(id, r)| poll::ActiveModel {
|
||||
note_id: sea_orm::Set(id.to_owned()),
|
||||
votes: sea_orm::Set(I32Vec::from(r.to_owned())),
|
||||
..Default::default()
|
||||
})
|
||||
.collect();
|
||||
for model in models {
|
||||
poll::Entity::update(model).exec(db).await?;
|
||||
}
|
||||
|
||||
// Convert user_profile here because its primary key is not id, but user_id.
|
||||
let query = select_query(
|
||||
UserProfile::Table,
|
||||
UserProfile::UserId,
|
||||
UserProfile::MutingNotificationTypes,
|
||||
);
|
||||
let res = get_vec::<Vec<String>>(db, query).await?;
|
||||
convert_col(
|
||||
manager,
|
||||
UserProfile::Table,
|
||||
UserProfile::MutingNotificationTypes,
|
||||
)
|
||||
.await?;
|
||||
let models: Vec<user_profile::ActiveModel> = res
|
||||
.iter()
|
||||
.map(|(id, r)| user_profile::ActiveModel {
|
||||
user_id: sea_orm::Set(id.to_owned()),
|
||||
muting_notification_types: sea_orm::Set(StringVec::from(r.to_owned())),
|
||||
..Default::default()
|
||||
})
|
||||
.collect();
|
||||
for model in models {
|
||||
user_profile::Entity::update(model).exec(db).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn down(&self, _manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
// Replace the sample below with your own migration scripts
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Learn more at https://docs.rs/sea-query#iden
|
||||
#[derive(Iden, Clone)]
|
||||
enum Antenna {
|
||||
Table,
|
||||
Id,
|
||||
Users,
|
||||
}
|
||||
#[derive(Iden, Clone)]
|
||||
enum AccessToken {
|
||||
Table,
|
||||
Id,
|
||||
Permission,
|
||||
}
|
||||
#[derive(Iden, Clone)]
|
||||
enum App {
|
||||
Table,
|
||||
Id,
|
||||
Permission,
|
||||
}
|
||||
#[derive(Iden, Clone)]
|
||||
enum Emoji {
|
||||
Table,
|
||||
Id,
|
||||
Aliases,
|
||||
}
|
||||
#[derive(Iden, Clone)]
|
||||
enum GalleryPost {
|
||||
Table,
|
||||
Id,
|
||||
FileIds,
|
||||
Tags,
|
||||
}
|
||||
#[derive(Iden, Clone)]
|
||||
enum Hashtag {
|
||||
Table,
|
||||
Id,
|
||||
MentionedUserIds,
|
||||
MentionedLocalUserIds,
|
||||
MentionedRemoteUserIds,
|
||||
AttachedUserIds,
|
||||
AttachedLocalUserIds,
|
||||
AttachedRemoteUserIds,
|
||||
}
|
||||
#[derive(Iden, Clone)]
|
||||
enum MessagingMessage {
|
||||
Table,
|
||||
Id,
|
||||
Reads,
|
||||
}
|
||||
#[derive(Iden, Clone)]
|
||||
enum Meta {
|
||||
Table,
|
||||
Id,
|
||||
Langs,
|
||||
HiddenTags,
|
||||
BlockedHosts,
|
||||
PinnedUsers,
|
||||
PinnedPages,
|
||||
RecommendedInstances,
|
||||
SilencedHosts,
|
||||
}
|
||||
#[derive(Iden, Clone)]
|
||||
enum Note {
|
||||
Table,
|
||||
Id,
|
||||
FileIds,
|
||||
AttachedFileTypes,
|
||||
VisibleUserIds,
|
||||
Mentions,
|
||||
Emojis,
|
||||
Tags,
|
||||
}
|
||||
#[derive(Iden, Clone)]
|
||||
enum NoteEdit {
|
||||
Table,
|
||||
Id,
|
||||
FileIds,
|
||||
}
|
||||
#[derive(Iden, Clone)]
|
||||
enum Page {
|
||||
Table,
|
||||
Id,
|
||||
VisibleUserIds,
|
||||
}
|
||||
#[derive(Iden, Clone)]
|
||||
enum Poll {
|
||||
Table,
|
||||
NoteId,
|
||||
Choices,
|
||||
Votes, // I32Vec
|
||||
}
|
||||
#[derive(Iden, Clone)]
|
||||
enum RegistryItem {
|
||||
Table,
|
||||
Id,
|
||||
Scope,
|
||||
}
|
||||
#[derive(Iden, Clone)]
|
||||
enum User {
|
||||
Table,
|
||||
Id,
|
||||
Tags,
|
||||
Emojis,
|
||||
}
|
||||
#[derive(Iden, Clone)]
|
||||
enum UserProfile {
|
||||
Table,
|
||||
UserId,
|
||||
MutingNotificationTypes,
|
||||
}
|
||||
#[derive(Iden, Clone)]
|
||||
enum Webhook {
|
||||
Table,
|
||||
Id,
|
||||
On,
|
||||
}
|
||||
#[derive(Iden)]
|
||||
enum ReversiGame {
|
||||
Table,
|
||||
}
|
||||
#[derive(Iden)]
|
||||
enum ReversiMatching {
|
||||
Table,
|
||||
}
|
||||
|
||||
fn select_query<T: Iden + 'static>(table: T, id: T, col: T) -> String {
|
||||
Query::select()
|
||||
.column(id)
|
||||
.column(col)
|
||||
.from(table)
|
||||
.to_string(PostgresQueryBuilder)
|
||||
}
|
||||
|
||||
async fn get_vec<'a, T: TryGetable>(
|
||||
db: &SchemaManagerConnection<'a>,
|
||||
query: String,
|
||||
) -> Result<Vec<(String, T)>, DbErr> {
|
||||
let res: Vec<(String, T)> = db
|
||||
.query_all(Statement::from_string(DbBackend::Postgres, query))
|
||||
.await?
|
||||
.iter()
|
||||
.filter_map(|r| r.try_get_many_by_index().ok())
|
||||
.collect();
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
async fn convert_col<'a, T: Iden + Clone + 'static>(
|
||||
manager: &SchemaManager<'a>,
|
||||
table: T,
|
||||
col: T,
|
||||
) -> Result<(), DbErr> {
|
||||
manager
|
||||
.alter_table(
|
||||
Table::alter()
|
||||
.table(table)
|
||||
.drop_column(col.to_owned())
|
||||
.add_column(
|
||||
ColumnDef::new(col.to_owned())
|
||||
.json_binary()
|
||||
.not_null()
|
||||
.default(json!([])),
|
||||
)
|
||||
.to_owned(),
|
||||
)
|
||||
.await
|
||||
}
|
|
@ -1,6 +1,11 @@
|
|||
use sea_orm_migration::prelude::*;
|
||||
|
||||
mod vec_to_json;
|
||||
|
||||
#[async_std::main]
|
||||
async fn main() {
|
||||
cli::run_cli(migration::Migrator).await;
|
||||
|
||||
#[cfg(feature = "convert")]
|
||||
vec_to_json::convert().await;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,279 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use sea_orm_migration::{prelude::*, sea_orm::{DbConn, DbBackend, Statement, TryGetable, Database}};
|
||||
use serde_json::json;
|
||||
use std::time::Duration;
|
||||
use indicatif::{ProgressBar, ProgressStyle, MultiProgress};
|
||||
use model::entity::newtype::{I32Vec, StringVec};
|
||||
use std::env;
|
||||
|
||||
pub async fn convert() {
|
||||
let uri = env::var("DATABASE_URL").expect("Environment variable 'DATABASE_URL' not set");
|
||||
|
||||
let db = Database::connect(uri).await.expect("Unable to connect");
|
||||
let mp = MultiProgress::new();
|
||||
|
||||
let handlers = vec![
|
||||
tokio::spawn(to_json::<AccessToken, Vec<String>, StringVec>(db.clone(), mp.clone(), AccessToken::Table, AccessToken::Id, AccessToken::Permission)),
|
||||
tokio::spawn(to_json::<Antenna, Vec<String>, StringVec>(db.clone(), mp.clone(), Antenna::Table, Antenna::Id, Antenna::Users)),
|
||||
tokio::spawn(to_json::<App, Vec<String>, StringVec>(db.clone(), mp.clone(), App::Table, App::Id, App::Permission)),
|
||||
tokio::spawn(to_json::<Emoji, Vec<String>, StringVec>(db.clone(), mp.clone(), Emoji::Table, Emoji::Id, Emoji::Aliases)),
|
||||
tokio::spawn(to_json::<GalleryPost, Vec<String>, StringVec>(db.clone(), mp.clone(), GalleryPost::Table, GalleryPost::Id, GalleryPost::FileIds)),
|
||||
tokio::spawn(to_json::<GalleryPost, Vec<String>, StringVec>(db.clone(), mp.clone(), GalleryPost::Table, GalleryPost::Id, GalleryPost::Tags)),
|
||||
tokio::spawn(to_json::<Hashtag, Vec<String>, StringVec>(db.clone(), mp.clone(), Hashtag::Table, Hashtag::Id, Hashtag::MentionedUserIds)),
|
||||
tokio::spawn(to_json::<Hashtag, Vec<String>, StringVec>(db.clone(), mp.clone(), Hashtag::Table, Hashtag::Id, Hashtag::MentionedLocalUserIds)),
|
||||
tokio::spawn(to_json::<Hashtag, Vec<String>, StringVec>(db.clone(), mp.clone(), Hashtag::Table, Hashtag::Id, Hashtag::MentionedRemoteUserIds)),
|
||||
tokio::spawn(to_json::<Hashtag, Vec<String>, StringVec>(db.clone(), mp.clone(), Hashtag::Table, Hashtag::Id, Hashtag::AttachedUserIds)),
|
||||
tokio::spawn(to_json::<Hashtag, Vec<String>, StringVec>(db.clone(), mp.clone(), Hashtag::Table, Hashtag::Id, Hashtag::AttachedLocalUserIds)),
|
||||
tokio::spawn(to_json::<Hashtag, Vec<String>, StringVec>(db.clone(), mp.clone(), Hashtag::Table, Hashtag::Id, Hashtag::AttachedRemoteUserIds)),
|
||||
tokio::spawn(to_json::<MessagingMessage, Vec<String>, StringVec>(db.clone(), mp.clone(), MessagingMessage::Table, MessagingMessage::Id, MessagingMessage::Reads)),
|
||||
tokio::spawn(to_json::<Meta, Vec<String>, StringVec>(db.clone(), mp.clone(), Meta::Table, Meta::Id, Meta::Langs)),
|
||||
tokio::spawn(to_json::<Meta, Vec<String>, StringVec>(db.clone(), mp.clone(), Meta::Table, Meta::Id, Meta::BlockedHosts)),
|
||||
tokio::spawn(to_json::<Meta, Vec<String>, StringVec>(db.clone(), mp.clone(), Meta::Table, Meta::Id, Meta::HiddenTags)),
|
||||
tokio::spawn(to_json::<Meta, Vec<String>, StringVec>(db.clone(), mp.clone(), Meta::Table, Meta::Id, Meta::PinnedUsers)),
|
||||
tokio::spawn(to_json::<Meta, Vec<String>, StringVec>(db.clone(), mp.clone(), Meta::Table, Meta::Id, Meta::PinnedPages)),
|
||||
tokio::spawn(to_json::<Meta, Vec<String>, StringVec>(db.clone(), mp.clone(), Meta::Table, Meta::Id, Meta::RecommendedInstances)),
|
||||
tokio::spawn(to_json::<Meta, Vec<String>, StringVec>(db.clone(), mp.clone(), Meta::Table, Meta::Id, Meta::SilencedHosts)),
|
||||
tokio::spawn(to_json::<Note, Vec<String>, StringVec>(db.clone(), mp.clone(), Note::Table, Note::Id, Note::FileIds)),
|
||||
tokio::spawn(to_json::<Note, Vec<String>, StringVec>(db.clone(), mp.clone(), Note::Table, Note::Id, Note::AttachedFileTypes)),
|
||||
tokio::spawn(to_json::<Note, Vec<String>, StringVec>(db.clone(), mp.clone(), Note::Table, Note::Id, Note::VisibleUserIds)),
|
||||
tokio::spawn(to_json::<Note, Vec<String>, StringVec>(db.clone(), mp.clone(), Note::Table, Note::Id, Note::Mentions)),
|
||||
tokio::spawn(to_json::<Note, Vec<String>, StringVec>(db.clone(), mp.clone(), Note::Table, Note::Id, Note::Emojis)),
|
||||
tokio::spawn(to_json::<Note, Vec<String>, StringVec>(db.clone(), mp.clone(), Note::Table, Note::Id, Note::Tags)),
|
||||
tokio::spawn(to_json::<NoteEdit, Vec<String>, StringVec>(db.clone(), mp.clone(), NoteEdit::Table, NoteEdit::Id, NoteEdit::FileIds)),
|
||||
tokio::spawn(to_json::<Page, Vec<String>, StringVec>(db.clone(), mp.clone(), Page::Table, Page::Id, Page::VisibleUserIds)),
|
||||
tokio::spawn(to_json::<RegistryItem, Vec<String>, StringVec>(db.clone(), mp.clone(), RegistryItem::Table, RegistryItem::Id, RegistryItem::Scope)),
|
||||
tokio::spawn(to_json::<User, Vec<String>, StringVec>(db.clone(), mp.clone(), User::Table, User::Id, User::Tags)),
|
||||
tokio::spawn(to_json::<User, Vec<String>, StringVec>(db.clone(), mp.clone(), User::Table, User::Id, User::Emojis)),
|
||||
tokio::spawn(to_json::<Webhook, Vec<String>, StringVec>(db.clone(), mp.clone(), Webhook::Table, Webhook::Id, Webhook::On)),
|
||||
tokio::spawn(to_json::<Poll, Vec<String>, StringVec>(db.clone(), mp.clone(), Poll::Table, Poll::NoteId, Poll::Choices)),
|
||||
tokio::spawn(to_json::<Poll, Vec<i32>, I32Vec>(db.clone(), mp.clone(), Poll::Table, Poll::NoteId, Poll::Votes)),
|
||||
tokio::spawn(to_json::<UserProfile, Vec<String>, StringVec>(db.clone(), mp.clone(), UserProfile::Table, UserProfile::UserId, UserProfile::MutingNotificationTypes)),
|
||||
];
|
||||
|
||||
futures::future::join_all(handlers).await;
|
||||
}
|
||||
|
||||
fn select_query<T: Iden + 'static>(table: T, id: T, col: T) -> String {
|
||||
Query::select()
|
||||
.column(id)
|
||||
.column(col)
|
||||
.from(table)
|
||||
.to_string(PostgresQueryBuilder)
|
||||
}
|
||||
|
||||
async fn get_vec<T: TryGetable>(
|
||||
db: &DbConn,
|
||||
query: String,
|
||||
) -> Result<Vec<(String, T)>, DbErr> {
|
||||
let res: Vec<(String, T)> = db
|
||||
.query_all(Statement::from_string(DbBackend::Postgres, query))
|
||||
.await?
|
||||
.iter()
|
||||
.filter_map(|r| r.try_get_many_by_index().ok())
|
||||
.collect();
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
async fn convert_col<T: Iden + Clone + 'static>(
|
||||
db: &DbConn,
|
||||
table: T,
|
||||
col: T,
|
||||
) -> Result<(), DbErr> {
|
||||
let stmt = Table::alter()
|
||||
.table(table)
|
||||
.drop_column(col.to_owned())
|
||||
.add_column(
|
||||
ColumnDef::new(col.to_owned())
|
||||
.json_binary()
|
||||
.not_null()
|
||||
.default(json!([])),
|
||||
).to_string(PostgresQueryBuilder);
|
||||
db.query_one(Statement::from_string(DbBackend::Postgres, stmt)).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn to_json<T, U, V>(
|
||||
db: DbConn,
|
||||
mp: MultiProgress,
|
||||
table: T,
|
||||
id: T,
|
||||
col: T,
|
||||
) -> Result<(), DbErr>
|
||||
where
|
||||
T: Iden + Clone + 'static,
|
||||
U: TryGetable + Clone,
|
||||
V: From<U> + Into<SimpleExpr>,
|
||||
{
|
||||
let query = select_query(table.clone(), id.clone(), col.clone());
|
||||
let loading = ProgressBar::new_spinner()
|
||||
.with_style(ProgressStyle::with_template("{prefix} {msg} {spinner}").unwrap())
|
||||
.with_prefix("[-]")
|
||||
.with_message(format!("Loading data from {}.{}", table.to_string(), col.to_string()));
|
||||
loading.enable_steady_tick(Duration::from_millis(100));
|
||||
let loading = mp.add(loading);
|
||||
let res = get_vec::<U>(&db, query).await?;
|
||||
let models: Vec<(String, V)> = res
|
||||
.iter()
|
||||
.map(|(id, r)| (id.clone(), <V>::from(r.clone())))
|
||||
.collect();
|
||||
loading.finish_and_clear();
|
||||
convert_col(&db, table.clone(), col.clone()).await?;
|
||||
|
||||
let progress = ProgressBar::new(models.len() as u64)
|
||||
.with_style(ProgressStyle::with_template("{prefix} {msg} {wide_bar} {pos}/{len}").unwrap().progress_chars("##-"))
|
||||
.with_prefix("[*]")
|
||||
.with_message(format!("Copying {}.{}", table.to_string(), col.to_string()));
|
||||
let progress = mp.add(progress);
|
||||
|
||||
for model in models {
|
||||
progress.inc(1);
|
||||
let q = Query::update()
|
||||
.table(table.clone())
|
||||
.values([(col.clone(), model.1.into())])
|
||||
.and_where(Expr::col(id.clone()).eq(model.0))
|
||||
.to_string(PostgresQueryBuilder);
|
||||
db.query_one(Statement::from_string(DbBackend::Postgres, q))
|
||||
.await?;
|
||||
}
|
||||
progress.finish_with_message(format!("Complete {}.{}", table.to_string(), col.to_string()));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Iden, Clone)]
|
||||
enum AccessToken {
|
||||
Table,
|
||||
Id,
|
||||
Permission,
|
||||
}
|
||||
#[derive(Iden, Clone)]
|
||||
enum Antenna {
|
||||
Table,
|
||||
Id,
|
||||
Users,
|
||||
}
|
||||
#[derive(Iden, Clone)]
|
||||
enum App {
|
||||
Table,
|
||||
Id,
|
||||
Permission,
|
||||
}
|
||||
#[derive(Iden, Clone)]
|
||||
enum Emoji {
|
||||
Table,
|
||||
Id,
|
||||
Aliases,
|
||||
}
|
||||
#[derive(Iden, Clone)]
|
||||
enum GalleryPost {
|
||||
Table,
|
||||
Id,
|
||||
#[iden = "fileIds"]
|
||||
FileIds,
|
||||
Tags,
|
||||
}
|
||||
#[derive(Iden, Clone)]
|
||||
enum Hashtag {
|
||||
Table,
|
||||
Id,
|
||||
#[iden = "mentionedUserIds"]
|
||||
MentionedUserIds,
|
||||
#[iden = "mentionedLocalUserIds"]
|
||||
MentionedLocalUserIds,
|
||||
#[iden = "mentionedRemoteUserIds"]
|
||||
MentionedRemoteUserIds,
|
||||
#[iden = "attachedUserIds"]
|
||||
AttachedUserIds,
|
||||
#[iden = "attachedLocalUserIds"]
|
||||
AttachedLocalUserIds,
|
||||
#[iden = "attachedRemoteUserIds"]
|
||||
AttachedRemoteUserIds,
|
||||
}
|
||||
#[derive(Iden, Clone)]
|
||||
enum MessagingMessage {
|
||||
Table,
|
||||
Id,
|
||||
Reads,
|
||||
}
|
||||
#[derive(Iden, Clone)]
|
||||
enum Meta {
|
||||
Table,
|
||||
Id,
|
||||
Langs,
|
||||
#[iden = "hiddenTags"]
|
||||
HiddenTags,
|
||||
#[iden = "blockedHosts"]
|
||||
BlockedHosts,
|
||||
#[iden = "pinnedUsers"]
|
||||
PinnedUsers,
|
||||
#[iden = "pinnedPages"]
|
||||
PinnedPages,
|
||||
#[iden = "recommendedInstances"]
|
||||
RecommendedInstances,
|
||||
#[iden = "silencedHosts"]
|
||||
SilencedHosts,
|
||||
}
|
||||
#[derive(Iden, Clone)]
|
||||
enum Note {
|
||||
Table,
|
||||
Id,
|
||||
#[iden = "fileIds"]
|
||||
FileIds,
|
||||
#[iden = "attachedFileTypes"]
|
||||
AttachedFileTypes,
|
||||
#[iden = "visibleUserIds"]
|
||||
VisibleUserIds,
|
||||
Mentions,
|
||||
Emojis,
|
||||
Tags,
|
||||
}
|
||||
#[derive(Iden, Clone)]
|
||||
enum NoteEdit {
|
||||
Table,
|
||||
Id,
|
||||
#[iden = "fileIds"]
|
||||
FileIds,
|
||||
}
|
||||
#[derive(Iden, Clone)]
|
||||
enum Page {
|
||||
Table,
|
||||
Id,
|
||||
#[iden = "visibleUserIds"]
|
||||
VisibleUserIds,
|
||||
}
|
||||
#[derive(Iden, Clone)]
|
||||
enum Poll {
|
||||
Table,
|
||||
#[iden = "noteId"]
|
||||
NoteId,
|
||||
Choices,
|
||||
Votes, // I32Vec
|
||||
}
|
||||
#[derive(Iden, Clone)]
|
||||
enum RegistryItem {
|
||||
Table,
|
||||
Id,
|
||||
Scope,
|
||||
}
|
||||
#[derive(Iden, Clone)]
|
||||
enum User {
|
||||
Table,
|
||||
Id,
|
||||
Tags,
|
||||
Emojis,
|
||||
}
|
||||
#[derive(Iden, Clone)]
|
||||
enum UserProfile {
|
||||
Table,
|
||||
#[iden = "userId"]
|
||||
UserId,
|
||||
#[iden = "mutingNotificationTypes"]
|
||||
MutingNotificationTypes,
|
||||
}
|
||||
#[derive(Iden, Clone)]
|
||||
enum Webhook {
|
||||
Table,
|
||||
Id,
|
||||
On,
|
||||
}
|
Loading…
Reference in a new issue