From d9d2673939e1cae99fe6df9b061d50bbacb68c60 Mon Sep 17 00:00:00 2001 From: Namekuji Date: Thu, 1 Jun 2023 12:32:15 -0400 Subject: [PATCH] use thread to copy data --- .../native-utils/crates/migration/Cargo.toml | 7 + .../native-utils/crates/migration/src/lib.rs | 4 +- .../src/m20230531_180824_drop_reversi.rs | 49 ++ .../src/m20230531_180824_stringvec.rs | 437 ------------------ .../native-utils/crates/migration/src/main.rs | 5 + .../crates/migration/src/vec_to_json.rs | 279 +++++++++++ 6 files changed, 342 insertions(+), 439 deletions(-) create mode 100644 packages/backend/native-utils/crates/migration/src/m20230531_180824_drop_reversi.rs delete mode 100644 packages/backend/native-utils/crates/migration/src/m20230531_180824_stringvec.rs create mode 100644 packages/backend/native-utils/crates/migration/src/vec_to_json.rs diff --git a/packages/backend/native-utils/crates/migration/Cargo.toml b/packages/backend/native-utils/crates/migration/Cargo.toml index 46108c68c5..49accc9a20 100644 --- a/packages/backend/native-utils/crates/migration/Cargo.toml +++ b/packages/backend/native-utils/crates/migration/Cargo.toml @@ -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" diff --git a/packages/backend/native-utils/crates/migration/src/lib.rs b/packages/backend/native-utils/crates/migration/src/lib.rs index a2a1b932f2..4835c2d3d7 100644 --- a/packages/backend/native-utils/crates/migration/src/lib.rs +++ b/packages/backend/native-utils/crates/migration/src/lib.rs @@ -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> { - vec![Box::new(m20230531_180824_stringvec::Migration)] + vec![Box::new(m20230531_180824_drop_reversi::Migration)] } } diff --git a/packages/backend/native-utils/crates/migration/src/m20230531_180824_drop_reversi.rs b/packages/backend/native-utils/crates/migration/src/m20230531_180824_drop_reversi.rs new file mode 100644 index 0000000000..c2726dd765 --- /dev/null +++ b/packages/backend/native-utils/crates/migration/src/m20230531_180824_drop_reversi.rs @@ -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, +} diff --git a/packages/backend/native-utils/crates/migration/src/m20230531_180824_stringvec.rs b/packages/backend/native-utils/crates/migration/src/m20230531_180824_stringvec.rs deleted file mode 100644 index e561e18d5c..0000000000 --- a/packages/backend/native-utils/crates/migration/src/m20230531_180824_stringvec.rs +++ /dev/null @@ -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::>(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::>(db, query).await?; - convert_col(manager, Poll::Table, Poll::Choices).await?; - let models: Vec = 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::>(db, query).await?; - convert_col(manager, Poll::Table, Poll::Votes).await?; - let models: Vec = 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::>(db, query).await?; - convert_col( - manager, - UserProfile::Table, - UserProfile::MutingNotificationTypes, - ) - .await?; - let models: Vec = 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(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, 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 -} diff --git a/packages/backend/native-utils/crates/migration/src/main.rs b/packages/backend/native-utils/crates/migration/src/main.rs index c6b6e48dbc..31a72026ee 100644 --- a/packages/backend/native-utils/crates/migration/src/main.rs +++ b/packages/backend/native-utils/crates/migration/src/main.rs @@ -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; } diff --git a/packages/backend/native-utils/crates/migration/src/vec_to_json.rs b/packages/backend/native-utils/crates/migration/src/vec_to_json.rs new file mode 100644 index 0000000000..eccd801149 --- /dev/null +++ b/packages/backend/native-utils/crates/migration/src/vec_to_json.rs @@ -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::, StringVec>(db.clone(), mp.clone(), AccessToken::Table, AccessToken::Id, AccessToken::Permission)), + tokio::spawn(to_json::, StringVec>(db.clone(), mp.clone(), Antenna::Table, Antenna::Id, Antenna::Users)), + tokio::spawn(to_json::, StringVec>(db.clone(), mp.clone(), App::Table, App::Id, App::Permission)), + tokio::spawn(to_json::, StringVec>(db.clone(), mp.clone(), Emoji::Table, Emoji::Id, Emoji::Aliases)), + tokio::spawn(to_json::, StringVec>(db.clone(), mp.clone(), GalleryPost::Table, GalleryPost::Id, GalleryPost::FileIds)), + tokio::spawn(to_json::, StringVec>(db.clone(), mp.clone(), GalleryPost::Table, GalleryPost::Id, GalleryPost::Tags)), + tokio::spawn(to_json::, StringVec>(db.clone(), mp.clone(), Hashtag::Table, Hashtag::Id, Hashtag::MentionedUserIds)), + tokio::spawn(to_json::, StringVec>(db.clone(), mp.clone(), Hashtag::Table, Hashtag::Id, Hashtag::MentionedLocalUserIds)), + tokio::spawn(to_json::, StringVec>(db.clone(), mp.clone(), Hashtag::Table, Hashtag::Id, Hashtag::MentionedRemoteUserIds)), + tokio::spawn(to_json::, StringVec>(db.clone(), mp.clone(), Hashtag::Table, Hashtag::Id, Hashtag::AttachedUserIds)), + tokio::spawn(to_json::, StringVec>(db.clone(), mp.clone(), Hashtag::Table, Hashtag::Id, Hashtag::AttachedLocalUserIds)), + tokio::spawn(to_json::, StringVec>(db.clone(), mp.clone(), Hashtag::Table, Hashtag::Id, Hashtag::AttachedRemoteUserIds)), + tokio::spawn(to_json::, StringVec>(db.clone(), mp.clone(), MessagingMessage::Table, MessagingMessage::Id, MessagingMessage::Reads)), + tokio::spawn(to_json::, StringVec>(db.clone(), mp.clone(), Meta::Table, Meta::Id, Meta::Langs)), + tokio::spawn(to_json::, StringVec>(db.clone(), mp.clone(), Meta::Table, Meta::Id, Meta::BlockedHosts)), + tokio::spawn(to_json::, StringVec>(db.clone(), mp.clone(), Meta::Table, Meta::Id, Meta::HiddenTags)), + tokio::spawn(to_json::, StringVec>(db.clone(), mp.clone(), Meta::Table, Meta::Id, Meta::PinnedUsers)), + tokio::spawn(to_json::, StringVec>(db.clone(), mp.clone(), Meta::Table, Meta::Id, Meta::PinnedPages)), + tokio::spawn(to_json::, StringVec>(db.clone(), mp.clone(), Meta::Table, Meta::Id, Meta::RecommendedInstances)), + tokio::spawn(to_json::, StringVec>(db.clone(), mp.clone(), Meta::Table, Meta::Id, Meta::SilencedHosts)), + tokio::spawn(to_json::, StringVec>(db.clone(), mp.clone(), Note::Table, Note::Id, Note::FileIds)), + tokio::spawn(to_json::, StringVec>(db.clone(), mp.clone(), Note::Table, Note::Id, Note::AttachedFileTypes)), + tokio::spawn(to_json::, StringVec>(db.clone(), mp.clone(), Note::Table, Note::Id, Note::VisibleUserIds)), + tokio::spawn(to_json::, StringVec>(db.clone(), mp.clone(), Note::Table, Note::Id, Note::Mentions)), + tokio::spawn(to_json::, StringVec>(db.clone(), mp.clone(), Note::Table, Note::Id, Note::Emojis)), + tokio::spawn(to_json::, StringVec>(db.clone(), mp.clone(), Note::Table, Note::Id, Note::Tags)), + tokio::spawn(to_json::, StringVec>(db.clone(), mp.clone(), NoteEdit::Table, NoteEdit::Id, NoteEdit::FileIds)), + tokio::spawn(to_json::, StringVec>(db.clone(), mp.clone(), Page::Table, Page::Id, Page::VisibleUserIds)), + tokio::spawn(to_json::, StringVec>(db.clone(), mp.clone(), RegistryItem::Table, RegistryItem::Id, RegistryItem::Scope)), + tokio::spawn(to_json::, StringVec>(db.clone(), mp.clone(), User::Table, User::Id, User::Tags)), + tokio::spawn(to_json::, StringVec>(db.clone(), mp.clone(), User::Table, User::Id, User::Emojis)), + tokio::spawn(to_json::, StringVec>(db.clone(), mp.clone(), Webhook::Table, Webhook::Id, Webhook::On)), + tokio::spawn(to_json::, StringVec>(db.clone(), mp.clone(), Poll::Table, Poll::NoteId, Poll::Choices)), + tokio::spawn(to_json::, I32Vec>(db.clone(), mp.clone(), Poll::Table, Poll::NoteId, Poll::Votes)), + tokio::spawn(to_json::, StringVec>(db.clone(), mp.clone(), UserProfile::Table, UserProfile::UserId, UserProfile::MutingNotificationTypes)), + ]; + + futures::future::join_all(handlers).await; +} + +fn select_query(table: T, id: T, col: T) -> String { + Query::select() + .column(id) + .column(col) + .from(table) + .to_string(PostgresQueryBuilder) +} + +async fn get_vec( + db: &DbConn, + query: String, +) -> Result, 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( + 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( + db: DbConn, + mp: MultiProgress, + table: T, + id: T, + col: T, +) -> Result<(), DbErr> +where + T: Iden + Clone + 'static, + U: TryGetable + Clone, + V: From + Into, +{ + 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::(&db, query).await?; + let models: Vec<(String, V)> = res + .iter() + .map(|(id, r)| (id.clone(), ::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, +}