Add migration-core crate

This commit is contained in:
fluo10 2025-05-09 08:48:06 +09:00
parent 93879ba97d
commit 94d30ae4f9
19 changed files with 395 additions and 203 deletions

44
Cargo.lock generated
View file

@ -2267,14 +2267,6 @@ dependencies = [
"toml",
]
[[package]]
name = "progress-pile-client-migration"
version = "0.1.0"
dependencies = [
"async-std",
"sea-orm-migration",
]
[[package]]
name = "progress-pile-core"
version = "0.1.0"
@ -2289,7 +2281,7 @@ dependencies = [
"dotenv",
"iana-time-zone",
"log",
"progress-pile-server-migration",
"progress-pile-migration-server",
"sea-orm",
"serde",
"thiserror 2.0.12",
@ -2297,6 +2289,32 @@ dependencies = [
"toml",
]
[[package]]
name = "progress-pile-migration-client"
version = "0.1.0"
dependencies = [
"async-std",
"progress-pile-migration-core",
"sea-orm-migration",
]
[[package]]
name = "progress-pile-migration-core"
version = "0.1.0"
dependencies = [
"async-std",
"sea-orm-migration",
]
[[package]]
name = "progress-pile-migration-server"
version = "0.1.0"
dependencies = [
"async-std",
"progress-pile-migration-core",
"sea-orm-migration",
]
[[package]]
name = "progress-pile-server"
version = "0.1.0"
@ -2315,14 +2333,6 @@ dependencies = [
"toml",
]
[[package]]
name = "progress-pile-server-migration"
version = "0.1.0"
dependencies = [
"async-std",
"sea-orm-migration",
]
[[package]]
name = "quote"
version = "1.0.40"

View file

@ -10,10 +10,11 @@ dirs = "6.0.0"
dotenv = "0.15.0"
progress-pile-cli.path = "progress-pile-cli"
progress-pile-client.path = "progress-pile-client"
progress-pile-client-migration.path = "progress-pile-client-migration"
progress-pile-core = { path = "progress-pile-core" }
progress-pile-migration-client.path = "progress-pile-migration-client"
progress-pile-migration-core.path = "progress-pile-migration-core"
progress-pile-migration-server.path = "progress-pile-migration-server"
progress-pile-server.path = "progress-pile-server"
progress-pile-server-migration.path = "progress-pile-server-migration"
serde = { version = "1.0", features = ["derive"] }
thiserror = "2.0.12"
tokio = "1.44.2"

View file

@ -18,7 +18,7 @@ clap = { workspace = true, optional = true }
csv = "1.3.1"
cynic = "3.10.0"
dotenv = {workspace = true}
progress-pile-server-migration = { workspace = true }
progress-pile-migration-server.workspace = true
iana-time-zone = "0.1.63"
log = "0.4.27"
sea-orm.workspace = true

View file

@ -4,7 +4,7 @@ use crate::config::{
};
use std::time::Duration;
use sea_orm::{entity::*, query::*, ConnectOptions, Database, DatabaseConnection};
use progress_pile_server_migration::{Migrator, MigratorTrait};
use progress_pile_migration_server::{Migrator, MigratorTrait};
use tokio::sync::OnceCell;
@ -71,7 +71,7 @@ mod tests {
use std::time::Duration;
use chrono::{offset, FixedOffset, Local, TimeZone};
use sea_orm::{entity::*, query::*, ConnectOptions, Database};
use progress_pile_server_migration::{Migrator, MigratorTrait};
use progress_pile_migration_server::{Migrator, MigratorTrait};
use crate::entity::*;
#[tokio::test]

View file

@ -0,0 +1,19 @@
[package]
name = "progress-pile-migration-client"
version = "0.1.0"
edition = "2021"
publish = false
[dependencies]
async-std = { version = "1", features = ["attributes", "tokio1"] }
progress-pile-migration-core = {workspace = true, features = ["client"]}
[dependencies.sea-orm-migration]
version = "1.1.0"
features = [
# Enable at least one `ASYNC_RUNTIME` and `DATABASE_DRIVER` feature if you want to run migration via CLI.
# View the list of supported features at https://www.sea-ql.org/SeaORM/docs/install-and-config/database-and-async-runtime.
# e.g.
# "runtime-tokio-rustls", # `ASYNC_RUNTIME` feature
# "sqlx-postgres", # `DATABASE_DRIVER` feature
]

View file

@ -0,0 +1,12 @@
pub use sea_orm_migration::prelude::*;
mod m20220101_000001_create_table;
pub struct Migrator;
#[async_trait::async_trait]
impl MigratorTrait for Migrator {
fn migrations() -> Vec<Box<dyn MigrationTrait>> {
vec![Box::new(m20220101_000001_create_table::Migration)]
}
}

View file

@ -0,0 +1,22 @@
use sea_orm_migration::{prelude::*, schema::*};
#[derive(DeriveMigrationName)]
pub struct Migration;
use progress_pile_migration_core::m20220101_000001_create_table::*;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager.create_table(ProgressCategory::client_table_create_statement()).await?;
manager.create_table(ProgressEntry::client_table_create_statement()).await?;
Ok(())
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager.drop_table(ProgressCategory::table_drop_statement()).await?;
manager.drop_table(ProgressEntry::table_drop_statement()).await?;
Ok(())
}
}

View file

@ -2,5 +2,5 @@ use sea_orm_migration::prelude::*;
#[async_std::main]
async fn main() {
cli::run_cli(progress_pile_server_migration::Migrator).await;
cli::run_cli(progress_pile_migration_client::Migrator).await;
}

View file

@ -0,0 +1,21 @@
[package]
name = "progress-pile-migration-core"
version = "0.1.0"
edition = "2021"
publish = false
[dependencies]
async-std = { version = "1", features = ["attributes", "tokio1"] }
[features]
default = []
client = []
server = []
[dependencies.sea-orm-migration]
version = "1.1.0"
features = [
# Enable at least one `ASYNC_RUNTIME` and `DATABASE_DRIVER` feature if you want to run migration via CLI.
# View the list of supported features at https://www.sea-ql.org/SeaORM/docs/install-and-config/database-and-async-runtime.
# e.g.
# "runtime-tokio-rustls", # `ASYNC_RUNTIME` feature
# "sqlx-postgres", # `DATABASE_DRIVER` feature
]

View file

@ -0,0 +1,41 @@
# Running Migrator CLI
- Generate a new migration file
```sh
cargo run -- generate MIGRATION_NAME
```
- Apply all pending migrations
```sh
cargo run
```
```sh
cargo run -- up
```
- Apply first 10 pending migrations
```sh
cargo run -- up -n 10
```
- Rollback last applied migrations
```sh
cargo run -- down
```
- Rollback last 10 applied migrations
```sh
cargo run -- down -n 10
```
- Drop all tables from the database, then reapply all migrations
```sh
cargo run -- fresh
```
- Rollback all applied migrations, then reapply all migrations
```sh
cargo run -- refresh
```
- Rollback all applied migrations
```sh
cargo run -- reset
```
- Check the status of all migrations
```sh
cargo run -- status
```

View file

@ -0,0 +1,3 @@
pub use sea_orm_migration::prelude::*;
pub mod m20220101_000001_create_table;

View file

@ -0,0 +1,166 @@
use sea_orm_migration::{prelude::*, schema::*};
#[cfg(feature="server")]
#[derive(DeriveIden)]
pub enum User {
Table,
Id,
CreatedAt,
UpdatedAt,
DeletedAt,
LoginName,
PasswordHash,
}
#[cfg(feature="server")]
impl User {
pub fn server_table_create_statement() -> TableCreateStatement{
Table::create()
.table(Self::Table)
.if_not_exists()
.col(pk_auto(Self::Id))
.col(timestamp_with_time_zone(Self::CreatedAt))
.col(timestamp_with_time_zone(Self::UpdatedAt))
.col(timestamp_with_time_zone_null(Self::DeletedAt))
.col(string_uniq(Self::LoginName))
.col(string(Self::PasswordHash))
.to_owned()
}
pub fn table_drop_statement() -> TableDropStatement {
Table::drop().table(Self::Table).to_owned()
}
}
#[cfg(feature="server")]
#[derive(DeriveIden)]
pub enum AccessToken{
Table,
Id,
UserId,
CreatedAt,
UpdatedAt,
ExpiredAt,
AccessToken,
Note,
}
#[cfg(feature="server")]
impl AccessToken {
pub fn server_table_create_statement() -> TableCreateStatement {
Table::create()
.table(Self::Table)
.if_not_exists()
.col(pk_auto(Self::Id))
.col(timestamp_with_time_zone(Self::CreatedAt))
.col(timestamp_with_time_zone(Self::UpdatedAt))
.col(timestamp_with_time_zone_null(Self::ExpiredAt))
.col(string(Self::AccessToken))
.col(string(Self::Note))
.to_owned()
}
pub fn table_drop_statement() -> TableDropStatement {
Table::drop().table(Self::Table).to_owned()
}
}
#[derive(DeriveIden)]
pub enum ProgressCategory {
Table,
#[cfg(feature="server")]
Id,
#[cfg(feature="server")]
UserId,
Uuid,
CreatedAt,
UpdatedAt,
DeletedAt,
Name,
}
impl ProgressCategory {
fn default_table_create_statement() -> TableCreateStatement {
Table::create()
.table(Self::Table)
.if_not_exists()
.col(timestamp_with_time_zone(Self::CreatedAt))
.col(timestamp_with_time_zone(Self::UpdatedAt))
.col(timestamp_with_time_zone_null(Self::DeletedAt))
.to_owned()
}
#[cfg(feature="client")]
pub fn client_table_create_statement() -> TableCreateStatement{
let mut tcs = Self::default_table_create_statement();
tcs.col(pk_uuid(Self::Uuid))
.col(string_uniq(Self::Name));
tcs
}
#[cfg(feature="server")]
pub fn server_table_create_statement() -> TableCreateStatement{
todo!()
}
pub fn table_drop_statement() -> TableDropStatement {
Table::drop().table(Self::Table).to_owned()
}
}
#[derive(DeriveIden)]
pub enum ProgressEntry {
Table,
#[cfg(feature="server")]
Id,
#[cfg(feature="server")]
UserId,
Uuid,
ProgressCategoryUuid,
CreatedAt,
UpdatedAt,
DeletedAt,
EnteredAt,
Quantity,
Note,
}
static PROGRESS_ENTRY_PROGRESS_CATEGORY_FOREIGN_KEY_NAME: &str = "fk__progress_entry__progress__category";
impl ProgressEntry {
fn default_table_create_statement() -> TableCreateStatement {
Table::create()
.table(Self::Table)
.if_not_exists()
.col(uuid(Self::ProgressCategoryUuid))
.col(timestamp_with_time_zone(Self::CreatedAt))
.col(timestamp_with_time_zone(Self::UpdatedAt))
.col(timestamp_with_time_zone_null(Self::DeletedAt))
.col(timestamp_with_time_zone(Self::EnteredAt))
.col(integer(Self::Quantity))
.col(string(Self::Note))
.to_owned()
}
#[cfg(feature="client")]
pub fn client_table_create_statement() -> TableCreateStatement{
let mut tcs = Self::default_table_create_statement();
tcs.col(pk_uuid(Self::Uuid))
.foreign_key(ForeignKey::create()
.name(PROGRESS_ENTRY_PROGRESS_CATEGORY_FOREIGN_KEY_NAME)
.from(Self::Table, Self::ProgressCategoryUuid)
.to(ProgressCategory::Table, ProgressCategory::Uuid)
.on_delete(ForeignKeyAction::Cascade)
.on_update(ForeignKeyAction::Cascade)
);
tcs
}
#[cfg(feature="server")]
pub fn server_table_create_statement() -> TableCreateStatement{
todo!()
}
pub fn table_drop_statement() -> TableDropStatement {
Table::drop().table(Self::Table).to_owned()
}
}

View file

@ -1,12 +1,12 @@
[package]
name = "progress-pile-server-migration"
name = "progress-pile-migration-server"
version = "0.1.0"
edition = "2021"
publish = false
[dependencies]
async-std = { version = "1", features = ["attributes", "tokio1"] }
progress-pile-migration-core = {workspace = true, features = ["server"]}
[dependencies.sea-orm-migration]
version = "1.1.0"
features = [

View file

@ -0,0 +1,41 @@
# Running Migrator CLI
- Generate a new migration file
```sh
cargo run -- generate MIGRATION_NAME
```
- Apply all pending migrations
```sh
cargo run
```
```sh
cargo run -- up
```
- Apply first 10 pending migrations
```sh
cargo run -- up -n 10
```
- Rollback last applied migrations
```sh
cargo run -- down
```
- Rollback last 10 applied migrations
```sh
cargo run -- down -n 10
```
- Drop all tables from the database, then reapply all migrations
```sh
cargo run -- fresh
```
- Rollback all applied migrations, then reapply all migrations
```sh
cargo run -- refresh
```
- Rollback all applied migrations
```sh
cargo run -- reset
```
- Check the status of all migrations
```sh
cargo run -- status
```

View file

@ -0,0 +1,28 @@
use sea_orm_migration::{prelude::*, schema::*};
#[derive(DeriveMigrationName)]
pub struct Migration;
use progress_pile_migration_core::m20220101_000001_create_table::*;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager.create_table(User::server_table_create_statement()).await?;
manager.create_table(AccessToken::server_table_create_statement()).await?;
Ok(())
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager.drop_table(User::table_drop_statement()).await?;
manager.drop_table(AccessToken::table_drop_statement()).await?;
manager.drop_table(ProgressCategory::table_drop_statement()).await?;
manager.drop_table(ProgressEntry::table_drop_statement()).await?;
Ok(())
}
}

View file

@ -0,0 +1,6 @@
use sea_orm_migration::prelude::*;
#[async_std::main]
async fn main() {
cli::run_cli(progress_pile_migration_server::Migrator).await;
}

View file

@ -1,178 +0,0 @@
use sea_orm_migration::{prelude::*, schema::*};
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager.create_table(
Table::create()
.table(User::Table)
.if_not_exists()
.col(pk_auto(User::Id))
.col(string_uniq(User::LoginName))
.col(string(User::PasswordHash))
.col(timestamp_with_time_zone(User::CreatedAt))
.col(timestamp_with_time_zone(User::UpdatedAt))
.to_owned(),
).await?;
manager.create_table(
Table::create()
.table(RecordHeader::Table)
.if_not_exists()
.col(pk_auto(RecordHeader::Id))
.col(integer(RecordHeader::UserId))
.col(timestamp_with_time_zone(RecordHeader::RecordedAt))
.col(timestamp_with_time_zone(RecordHeader::CreatedAt))
.col(timestamp_with_time_zone(RecordHeader::UpdatedAt))
.col(string(RecordHeader::Comment))
.foreign_key(
ForeignKey::create()
.name("FK_RecordHeader_User")
.from(RecordHeader::Table, RecordHeader::UserId)
.to(User::Table, User::Id)
.on_delete(ForeignKeyAction::Cascade)
.on_update(ForeignKeyAction::Cascade)
)
.to_owned(),
).await?;
manager.create_table(
Table::create()
.table(RecordTag::Table)
.if_not_exists()
.col(pk_auto(RecordTag::Id))
.col(integer(RecordTag::UserId))
.col(string(RecordTag::Name))
.foreign_key(
ForeignKey::create()
.name("FK_RecordTag_User")
.from(RecordTag::Table, RecordHeader::UserId)
.to(User::Table, User::Id)
.on_delete(ForeignKeyAction::Cascade)
.on_update(ForeignKeyAction::Cascade)
)
.to_owned(),
).await?;
manager.create_table(
Table::create()
.table(RecordDetail::Table)
.if_not_exists()
.col(pk_auto(RecordDetail::Id))
.col(integer(RecordDetail::RecordHeaderId))
.col(integer(RecordDetail::RecordTagId))
.col(integer(RecordDetail::Count))
.foreign_key(
ForeignKey::create()
.name("FK_RecordDetail_RecordHeader")
.from(RecordDetail::Table, RecordDetail::RecordHeaderId)
.to(RecordHeader::Table, RecordHeader::Id)
.on_delete(ForeignKeyAction::Cascade)
.on_update(ForeignKeyAction::Cascade)
)
.foreign_key(
ForeignKey::create()
.name("FK_RecordDetail_RecordTag")
.from(RecordDetail::Table, RecordDetail::RecordTagId)
.to(RecordTag::Table, RecordTag::Id)
.on_delete(ForeignKeyAction::Cascade)
.on_update(ForeignKeyAction::Cascade)
)
.to_owned(),
).await?;
manager.create_index(
Index::create()
.name("IDX_User_LoginName")
.table(User::Table)
.col(User::LoginName)
.to_owned(),
).await?;
manager.create_index(
Index::create()
.name("IDX_RecordHeader_RecordedAt")
.table(RecordHeader::Table)
.col(RecordHeader::RecordedAt)
.to_owned(),
).await?;
manager.create_index(
Index::create()
.name("IDX_RecordTag_Name")
.table(RecordTag::Table)
.col(RecordTag::Name)
.to_owned(),
).await?;
Ok(())
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
// Replace the sample below with your own migration scripts
manager.drop_index(Index::drop().name("IDX_User_LoginName").to_owned()).await?;
manager.drop_index(Index::drop().name("IDX_RecordHeader_RecordedAt").to_owned()).await?;
manager.drop_index(Index::drop().name("IDX_RecordTag_Name").to_owned()).await?;
manager.drop_table(
Table::drop().table(RecordDetail::Table).to_owned()
).await?;
manager.drop_table(
Table::drop().table(RecordTag::Table).to_owned()
).await?;
manager.drop_table(
Table::drop().table(RecordHeader::Table).to_owned()
).await?;
manager.drop_table(
Table::drop().table(User::Table).to_owned()
).await?;
Ok(())
}
}
#[derive(DeriveIden)]
enum User {
Table,
Id,
CreatedAt,
UpdatedAt,
LoginName,
PasswordHash,
}
#[derive(DeriveIden)]
enum RecordHeader {
Table,
Id,
UserId,
CreatedAt,
UpdatedAt,
RecordedAt,
Comment,
}
#[derive(DeriveIden)]
enum RecordTag {
Table,
Id,
UserId,
Name,
}
#[derive(DeriveIden)]
enum RecordDetail {
Table,
Id,
RecordHeaderId,
RecordTagId,
Count,
}