Migration (#335)
* Refactor `ConnectionTrait` * Refactoring * Build index & foreign key statements * Fix imports * Fixup * Rocket example with migration * async-std compatible with the tokio 1.0 runtime * Use reexported dependency * Compile without selecting any db backend * Updating sea-orm-cli dep * sea-orm-cli migrate commands * cargo fmt * Test [cli] * Refactoring * Clap app name should be "sea-orm-cli" * Correctly capture MIGRATION_DIR * Rename README * Add `sea-orm-cli migrate init` command * Update README * Try restructured sea-query dependency (SeaQL/sea-schema#41) * Set `DATABASE_URL` environment variable
This commit is contained in:
parent
e63d463155
commit
8eb095385d
@ -43,7 +43,7 @@ once_cell = "1.8"
|
|||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
smol = { version = "^1.2" }
|
smol = { version = "^1.2" }
|
||||||
smol-potat = { version = "^1.1" }
|
smol-potat = { version = "^1.1" }
|
||||||
async-std = { version = "^1.9", features = ["attributes"] }
|
async-std = { version = "^1.9", features = ["attributes", "tokio1"] }
|
||||||
tokio = { version = "^1.6", features = ["full"] }
|
tokio = { version = "^1.6", features = ["full"] }
|
||||||
actix-rt = { version = "2.2.0" }
|
actix-rt = { version = "2.2.0" }
|
||||||
maplit = { version = "^1" }
|
maplit = { version = "^1" }
|
||||||
|
@ -8,7 +8,7 @@ edition = "2021"
|
|||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
async-std = { version = "^1.9", features = [ "attributes" ] }
|
async-std = { version = "^1.9", features = [ "attributes", "tokio1" ] }
|
||||||
sea-orm = { path = "../../", features = [ "sqlx-all", "runtime-async-std-native-tls" ] }
|
sea-orm = { path = "../../", features = [ "sqlx-all", "runtime-async-std-native-tls" ] }
|
||||||
serde_json = { version = "^1" }
|
serde_json = { version = "^1" }
|
||||||
futures = { version = "^0.3" }
|
futures = { version = "^0.3" }
|
||||||
|
@ -6,6 +6,7 @@ edition = "2021"
|
|||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
|
members = [".", "entity", "migration"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
async-stream = { version = "^0.3" }
|
async-stream = { version = "^0.3" }
|
||||||
@ -19,18 +20,9 @@ rocket_dyn_templates = { version = "0.1.0-rc.1", features = [
|
|||||||
"tera",
|
"tera",
|
||||||
] }
|
] }
|
||||||
serde_json = { version = "^1" }
|
serde_json = { version = "^1" }
|
||||||
|
entity = { path = "entity" }
|
||||||
[dependencies.sea-orm]
|
migration = { path = "migration" }
|
||||||
path = "../../" # remove this line in your own project
|
|
||||||
version = "^0.5.0"
|
|
||||||
features = ["macros", "runtime-tokio-native-tls"]
|
|
||||||
default-features = false
|
|
||||||
|
|
||||||
[dependencies.sea-orm-rocket]
|
[dependencies.sea-orm-rocket]
|
||||||
path = "../../sea-orm-rocket/lib" # remove this line in your own project and use the git line
|
path = "../../sea-orm-rocket/lib" # remove this line in your own project and use the git line
|
||||||
# git = "https://github.com/SeaQL/sea-orm"
|
# git = "https://github.com/SeaQL/sea-orm"
|
||||||
|
|
||||||
[features]
|
|
||||||
default = ["sqlx-postgres"]
|
|
||||||
sqlx-mysql = ["sea-orm/sqlx-mysql"]
|
|
||||||
sqlx-postgres = ["sea-orm/sqlx-postgres"]
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
1. Modify the `url` var in `Rocket.toml` to point to your chosen database
|
1. Modify the `url` var in `Rocket.toml` to point to your chosen database
|
||||||
|
|
||||||
1. Turn on the appropriate database feature for your chosen db in `Cargo.toml` (the `default = ["sqlx-postgres"]` line)
|
1. Turn on the appropriate database feature for your chosen db in `entity/Cargo.toml` (the `"sqlx-postgres",` line)
|
||||||
|
|
||||||
1. `cargo run` to start the server
|
1. `cargo run` to start the server
|
||||||
|
|
||||||
|
27
examples/rocket_example/entity/Cargo.toml
Normal file
27
examples/rocket_example/entity/Cargo.toml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
[package]
|
||||||
|
name = "entity"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "entity"
|
||||||
|
path = "src/lib.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rocket = { version = "0.5.0-rc.1", features = [
|
||||||
|
"json",
|
||||||
|
] }
|
||||||
|
|
||||||
|
[dependencies.sea-orm]
|
||||||
|
# path = "../../../" # remove this line in your own project
|
||||||
|
git = "https://github.com/SeaQL/sea-orm"
|
||||||
|
branch = "migration"
|
||||||
|
version = "^0.5.0"
|
||||||
|
features = [
|
||||||
|
"macros",
|
||||||
|
"runtime-tokio-native-tls",
|
||||||
|
"sqlx-postgres",
|
||||||
|
# "sqlx-mysql",
|
||||||
|
]
|
||||||
|
default-features = false
|
6
examples/rocket_example/entity/src/lib.rs
Normal file
6
examples/rocket_example/entity/src/lib.rs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#[macro_use]
|
||||||
|
extern crate rocket;
|
||||||
|
|
||||||
|
pub mod post;
|
||||||
|
|
||||||
|
pub use sea_orm;
|
14
examples/rocket_example/migration/Cargo.toml
Normal file
14
examples/rocket_example/migration/Cargo.toml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
[package]
|
||||||
|
name = "migration"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "migration"
|
||||||
|
path = "src/lib.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
sea-schema = { git = "https://github.com/SeaQL/sea-schema.git", branch = "restructure-sea-query-dep", default-features = false, features = [ "migration", "debug-print" ] }
|
||||||
|
entity = { path = "../entity" }
|
||||||
|
rocket = { version = "0.5.0-rc.1" }
|
37
examples/rocket_example/migration/README.md
Normal file
37
examples/rocket_example/migration/README.md
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# Running Migrator CLI
|
||||||
|
|
||||||
|
- 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
|
||||||
|
```
|
12
examples/rocket_example/migration/src/lib.rs
Normal file
12
examples/rocket_example/migration/src/lib.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
pub use sea_schema::migration::*;
|
||||||
|
|
||||||
|
mod m20220120_000001_create_post_table;
|
||||||
|
|
||||||
|
pub struct Migrator;
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl MigratorTrait for Migrator {
|
||||||
|
fn migrations() -> Vec<Box<dyn MigrationTrait>> {
|
||||||
|
vec![Box::new(m20220120_000001_create_post_table::Migration)]
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
use entity::post::*;
|
||||||
|
use sea_schema::migration::{
|
||||||
|
sea_query::{self, *},
|
||||||
|
*,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Migration;
|
||||||
|
|
||||||
|
impl MigrationName for Migration {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"m20220120_000001_create_post_table"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl MigrationTrait for Migration {
|
||||||
|
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
manager
|
||||||
|
.create_table(
|
||||||
|
Table::create()
|
||||||
|
.table(Entity)
|
||||||
|
.if_not_exists()
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(Column::Id)
|
||||||
|
.integer()
|
||||||
|
.not_null()
|
||||||
|
.auto_increment()
|
||||||
|
.primary_key(),
|
||||||
|
)
|
||||||
|
.col(ColumnDef::new(Column::Title).string().not_null())
|
||||||
|
.col(ColumnDef::new(Column::Text).string().not_null())
|
||||||
|
.to_owned(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
manager
|
||||||
|
.drop_table(Table::drop().table(Entity).to_owned())
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
18
examples/rocket_example/migration/src/main.rs
Normal file
18
examples/rocket_example/migration/src/main.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
use migration::Migrator;
|
||||||
|
use sea_schema::migration::*;
|
||||||
|
|
||||||
|
#[async_std::main]
|
||||||
|
async fn main() {
|
||||||
|
// Setting `DATABASE_URL` environment variable
|
||||||
|
let key = "DATABASE_URL";
|
||||||
|
if std::env::var(key).is_err() {
|
||||||
|
// Getting the database URL from Rocket.toml if it's not set
|
||||||
|
let figment = rocket::Config::figment();
|
||||||
|
let database_url: String = figment
|
||||||
|
.extract_inner("databases.sea_orm.url")
|
||||||
|
.expect("Cannot find Database URL in Rocket.toml");
|
||||||
|
std::env::set_var(key, database_url);
|
||||||
|
}
|
||||||
|
|
||||||
|
cli::run_cli(Migrator).await;
|
||||||
|
}
|
@ -10,16 +10,16 @@ use rocket::{Build, Request, Rocket};
|
|||||||
use rocket_dyn_templates::Template;
|
use rocket_dyn_templates::Template;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
||||||
|
use entity::sea_orm;
|
||||||
|
use migration::MigratorTrait;
|
||||||
use sea_orm::{entity::*, query::*};
|
use sea_orm::{entity::*, query::*};
|
||||||
use sea_orm_rocket::{Connection, Database};
|
use sea_orm_rocket::{Connection, Database};
|
||||||
|
|
||||||
mod pool;
|
mod pool;
|
||||||
use pool::Db;
|
use pool::Db;
|
||||||
|
|
||||||
mod setup;
|
pub use entity::post;
|
||||||
|
pub use entity::post::Entity as Post;
|
||||||
mod post;
|
|
||||||
pub use post::Entity as Post;
|
|
||||||
|
|
||||||
const DEFAULT_POSTS_PER_PAGE: usize = 5;
|
const DEFAULT_POSTS_PER_PAGE: usize = 5;
|
||||||
|
|
||||||
@ -114,7 +114,7 @@ async fn list(
|
|||||||
"num_pages": num_pages,
|
"num_pages": num_pages,
|
||||||
"posts": posts,
|
"posts": posts,
|
||||||
"flash": flash.map(FlashMessage::into_inner),
|
"flash": flash.map(FlashMessage::into_inner),
|
||||||
})
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,7 +131,7 @@ async fn edit(conn: Connection<'_, Db>, id: i32) -> Template {
|
|||||||
"edit",
|
"edit",
|
||||||
json! ({
|
json! ({
|
||||||
"post": post,
|
"post": post,
|
||||||
})
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,13 +160,13 @@ pub fn not_found(req: &Request<'_>) -> Template {
|
|||||||
"error/404",
|
"error/404",
|
||||||
json! ({
|
json! ({
|
||||||
"uri": req.uri()
|
"uri": req.uri()
|
||||||
})
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run_migrations(rocket: Rocket<Build>) -> fairing::Result {
|
async fn run_migrations(rocket: Rocket<Build>) -> fairing::Result {
|
||||||
let conn = &Db::fetch(&rocket).unwrap().conn;
|
let conn = &Db::fetch(&rocket).unwrap().conn;
|
||||||
let _ = setup::create_post_table(conn).await;
|
let _ = migration::Migrator::up(conn, None).await;
|
||||||
Ok(rocket)
|
Ok(rocket)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use entity::sea_orm;
|
||||||
use sea_orm::ConnectOptions;
|
use sea_orm::ConnectOptions;
|
||||||
use sea_orm_rocket::{rocket::figment::Figment, Config, Database};
|
use sea_orm_rocket::{rocket::figment::Figment, Config, Database};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
use sea_orm::sea_query::{ColumnDef, TableCreateStatement};
|
|
||||||
use sea_orm::{error::*, query::*, sea_query, DbConn, ExecResult};
|
|
||||||
|
|
||||||
async fn create_table(db: &DbConn, stmt: &TableCreateStatement) -> Result<ExecResult, DbErr> {
|
|
||||||
let builder = db.get_database_backend();
|
|
||||||
db.execute(builder.build(stmt)).await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn create_post_table(db: &DbConn) -> Result<ExecResult, DbErr> {
|
|
||||||
let stmt = sea_query::Table::create()
|
|
||||||
.table(super::post::Entity)
|
|
||||||
.if_not_exists()
|
|
||||||
.col(
|
|
||||||
ColumnDef::new(super::post::Column::Id)
|
|
||||||
.integer()
|
|
||||||
.not_null()
|
|
||||||
.auto_increment()
|
|
||||||
.primary_key(),
|
|
||||||
)
|
|
||||||
.col(
|
|
||||||
ColumnDef::new(super::post::Column::Title)
|
|
||||||
.string()
|
|
||||||
.not_null(),
|
|
||||||
)
|
|
||||||
.col(
|
|
||||||
ColumnDef::new(super::post::Column::Text)
|
|
||||||
.string()
|
|
||||||
.not_null(),
|
|
||||||
)
|
|
||||||
.to_owned();
|
|
||||||
|
|
||||||
create_table(db, &stmt).await
|
|
||||||
}
|
|
@ -9,4 +9,4 @@ publish = false
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
sea-orm = { path = "../../", features = [ "sqlx-all", "runtime-async-std-native-tls", "debug-print" ] }
|
sea-orm = { path = "../../", features = [ "sqlx-all", "runtime-async-std-native-tls", "debug-print" ] }
|
||||||
async-std = { version = "^1", features = ["attributes"] }
|
async-std = { version = "^1", features = ["attributes", "tokio1"] }
|
||||||
|
@ -8,7 +8,7 @@ edition = "2021"
|
|||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
async-std = { version = "^1", features = ["attributes"] }
|
async-std = { version = "^1", features = ["attributes", "tokio1"] }
|
||||||
serde = { version = "^1", features = ["derive"] }
|
serde = { version = "^1", features = ["derive"] }
|
||||||
sea-orm = { path = "../../", features = [
|
sea-orm = { path = "../../", features = [
|
||||||
"sqlx-mysql",
|
"sqlx-mysql",
|
||||||
|
@ -20,15 +20,16 @@ path = "src/main.rs"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "^2.33.3" }
|
clap = { version = "^2.33.3" }
|
||||||
dotenv = { version = "^0.15" }
|
dotenv = { version = "^0.15" }
|
||||||
async-std = { version = "^1.9", features = [ "attributes" ] }
|
async-std = { version = "^1.9", features = [ "attributes", "tokio1" ] }
|
||||||
sea-orm-codegen = { version = "^0.5.0", path = "../sea-orm-codegen" }
|
sea-orm-codegen = { version = "^0.5.0", path = "../sea-orm-codegen" }
|
||||||
sea-schema = { version = "0.4.0", default-features = false, features = [
|
sea-schema = { git = "https://github.com/SeaQL/sea-schema.git", branch = "restructure-sea-query-dep", default-features = false, features = [
|
||||||
"debug-print",
|
"debug-print",
|
||||||
"sqlx-mysql",
|
"sqlx-mysql",
|
||||||
"sqlx-sqlite",
|
"sqlx-sqlite",
|
||||||
"sqlx-postgres",
|
"sqlx-postgres",
|
||||||
"discovery",
|
"discovery",
|
||||||
"writer",
|
"writer",
|
||||||
|
"migration",
|
||||||
] }
|
] }
|
||||||
sqlx = { version = "^0.5", default-features = false, features = [ "mysql", "postgres" ] }
|
sqlx = { version = "^0.5", default-features = false, features = [ "mysql", "postgres" ] }
|
||||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||||
|
@ -6,7 +6,7 @@ Getting Help:
|
|||||||
cargo run -- -h
|
cargo run -- -h
|
||||||
```
|
```
|
||||||
|
|
||||||
Running Entity Generator:
|
## Running Entity Generator:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
# MySQL (`--database-schema` option is ignored)
|
# MySQL (`--database-schema` option is ignored)
|
||||||
@ -18,3 +18,46 @@ cargo run -- generate entity -u sqlite://bakery.db -o out
|
|||||||
# PostgreSQL
|
# PostgreSQL
|
||||||
cargo run -- generate entity -u postgres://sea:sea@localhost/bakery -s public -o out
|
cargo run -- generate entity -u postgres://sea:sea@localhost/bakery -s public -o out
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Running Migration:
|
||||||
|
|
||||||
|
- Initialize migration directory
|
||||||
|
```sh
|
||||||
|
cargo run -- migrate init
|
||||||
|
```
|
||||||
|
- Apply all pending migrations
|
||||||
|
```sh
|
||||||
|
cargo run -- migrate
|
||||||
|
```
|
||||||
|
```sh
|
||||||
|
cargo run -- migrate up
|
||||||
|
```
|
||||||
|
- Apply first 10 pending migrations
|
||||||
|
```sh
|
||||||
|
cargo run -- migrate up -n 10
|
||||||
|
```
|
||||||
|
- Rollback last applied migrations
|
||||||
|
```sh
|
||||||
|
cargo run -- migrate down
|
||||||
|
```
|
||||||
|
- Rollback last 10 applied migrations
|
||||||
|
```sh
|
||||||
|
cargo run -- migrate down -n 10
|
||||||
|
```
|
||||||
|
- Drop all tables from the database, then reapply all migrations
|
||||||
|
```sh
|
||||||
|
cargo run -- migrate fresh
|
||||||
|
```
|
||||||
|
- Rollback all applied migrations, then reapply all migrations
|
||||||
|
```sh
|
||||||
|
cargo run -- migrate refresh
|
||||||
|
```
|
||||||
|
- Rollback all applied migrations
|
||||||
|
```sh
|
||||||
|
cargo run -- migrate reset
|
||||||
|
```
|
||||||
|
- Check the status of all migrations
|
||||||
|
```sh
|
||||||
|
cargo run -- migrate status
|
||||||
|
```
|
||||||
|
|
||||||
|
@ -74,10 +74,30 @@ pub fn build_cli() -> App<'static, 'static> {
|
|||||||
)
|
)
|
||||||
.setting(AppSettings::SubcommandRequiredElseHelp);
|
.setting(AppSettings::SubcommandRequiredElseHelp);
|
||||||
|
|
||||||
App::new("sea-orm")
|
let arg_migration_dir = Arg::with_name("MIGRATION_DIR")
|
||||||
|
.long("migration-dir")
|
||||||
|
.short("d")
|
||||||
|
.help("Migration script directory")
|
||||||
|
.takes_value(true)
|
||||||
|
.default_value("./migration");
|
||||||
|
let mut migrate_subcommands = SubCommand::with_name("migrate")
|
||||||
|
.about("Migration related commands")
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("init")
|
||||||
|
.about("Initialize migration directory")
|
||||||
|
.arg(arg_migration_dir.clone()),
|
||||||
|
)
|
||||||
|
.arg(arg_migration_dir.clone());
|
||||||
|
for subcommand in sea_schema::migration::get_subcommands() {
|
||||||
|
migrate_subcommands =
|
||||||
|
migrate_subcommands.subcommand(subcommand.arg(arg_migration_dir.clone()));
|
||||||
|
}
|
||||||
|
|
||||||
|
App::new("sea-orm-cli")
|
||||||
.version(env!("CARGO_PKG_VERSION"))
|
.version(env!("CARGO_PKG_VERSION"))
|
||||||
.setting(AppSettings::VersionlessSubcommands)
|
.setting(AppSettings::VersionlessSubcommands)
|
||||||
.subcommand(entity_subcommand)
|
.subcommand(entity_subcommand)
|
||||||
|
.subcommand(migrate_subcommands)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("VERBOSE")
|
Arg::with_name("VERBOSE")
|
||||||
.long("verbose")
|
.long("verbose")
|
||||||
|
@ -16,6 +16,7 @@ async fn main() {
|
|||||||
("generate", Some(matches)) => run_generate_command(matches)
|
("generate", Some(matches)) => run_generate_command(matches)
|
||||||
.await
|
.await
|
||||||
.unwrap_or_else(handle_error),
|
.unwrap_or_else(handle_error),
|
||||||
|
("migrate", Some(matches)) => run_migrate_command(matches).unwrap_or_else(handle_error),
|
||||||
_ => unreachable!("You should never see this message"),
|
_ => unreachable!("You should never see this message"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -187,6 +188,78 @@ async fn run_generate_command(matches: &ArgMatches<'_>) -> Result<(), Box<dyn Er
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn run_migrate_command(matches: &ArgMatches<'_>) -> Result<(), Box<dyn Error>> {
|
||||||
|
let migrate_subcommand = matches.subcommand();
|
||||||
|
// If it's `migrate init`
|
||||||
|
if let ("init", Some(args)) = migrate_subcommand {
|
||||||
|
let migration_dir = args.value_of("MIGRATION_DIR").unwrap();
|
||||||
|
let migration_dir = match migration_dir.ends_with('/') {
|
||||||
|
true => migration_dir.to_string(),
|
||||||
|
false => format!("{}/", migration_dir),
|
||||||
|
};
|
||||||
|
println!("Initializing migration directory...");
|
||||||
|
macro_rules! write_file {
|
||||||
|
($filename: literal) => {
|
||||||
|
let filepath = [&migration_dir, $filename].join("");
|
||||||
|
println!("Creating file `{}`", filepath);
|
||||||
|
let path = Path::new(&filepath);
|
||||||
|
let prefix = path.parent().unwrap();
|
||||||
|
fs::create_dir_all(prefix).unwrap();
|
||||||
|
let mut file = fs::File::create(path)?;
|
||||||
|
let content = include_str!(concat!("../template/migration/", $filename));
|
||||||
|
file.write_all(content.as_bytes())?;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
write_file!("src/lib.rs");
|
||||||
|
write_file!("src/m20220101_000001_create_table.rs");
|
||||||
|
write_file!("src/main.rs");
|
||||||
|
write_file!("Cargo.toml");
|
||||||
|
write_file!("README.md");
|
||||||
|
println!("Done!");
|
||||||
|
// Early exit!
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let (subcommand, migration_dir, steps, verbose) = match migrate_subcommand {
|
||||||
|
// Catch all command with pattern `migrate xxx`
|
||||||
|
(subcommand, Some(args)) => {
|
||||||
|
let migration_dir = args.value_of("MIGRATION_DIR").unwrap();
|
||||||
|
let steps = args.value_of("NUM_MIGRATION");
|
||||||
|
let verbose = args.is_present("VERBOSE");
|
||||||
|
(subcommand, migration_dir, steps, verbose)
|
||||||
|
}
|
||||||
|
// Catch command `migrate`, this will be treated as `migrate up`
|
||||||
|
_ => {
|
||||||
|
let migration_dir = matches.value_of("MIGRATION_DIR").unwrap();
|
||||||
|
let verbose = matches.is_present("VERBOSE");
|
||||||
|
("up", migration_dir, None, verbose)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Construct the `--manifest-path`
|
||||||
|
let manifest_path = if migration_dir.ends_with('/') {
|
||||||
|
format!("{}Cargo.toml", migration_dir)
|
||||||
|
} else {
|
||||||
|
format!("{}/Cargo.toml", migration_dir)
|
||||||
|
};
|
||||||
|
// Construct the arguments that will be supplied to `cargo` command
|
||||||
|
let mut args = vec![
|
||||||
|
"run",
|
||||||
|
"--manifest-path",
|
||||||
|
manifest_path.as_str(),
|
||||||
|
"--",
|
||||||
|
subcommand,
|
||||||
|
];
|
||||||
|
if let Some(steps) = steps {
|
||||||
|
args.extend(["-n", steps]);
|
||||||
|
}
|
||||||
|
if verbose {
|
||||||
|
args.push("-v");
|
||||||
|
}
|
||||||
|
// Run migrator CLI on user's behalf
|
||||||
|
println!("Running `cargo {}`", args.join(" "));
|
||||||
|
Command::new("cargo").args(args).spawn()?.wait()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_error<E>(error: E)
|
fn handle_error<E>(error: E)
|
||||||
where
|
where
|
||||||
E: Display,
|
E: Display,
|
||||||
@ -197,11 +270,13 @@ where
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use clap::AppSettings;
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use clap::AppSettings;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "called `Result::unwrap()` on an `Err` value: RelativeUrlWithoutBase")]
|
#[should_panic(
|
||||||
|
expected = "called `Result::unwrap()` on an `Err` value: RelativeUrlWithoutBase"
|
||||||
|
)]
|
||||||
fn test_generate_entity_no_protocol() {
|
fn test_generate_entity_no_protocol() {
|
||||||
let matches = cli::build_cli()
|
let matches = cli::build_cli()
|
||||||
.setting(AppSettings::NoBinaryName)
|
.setting(AppSettings::NoBinaryName)
|
||||||
@ -216,7 +291,9 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "There is no database name as part of the url path: postgresql://root:root@localhost:3306")]
|
#[should_panic(
|
||||||
|
expected = "There is no database name as part of the url path: postgresql://root:root@localhost:3306"
|
||||||
|
)]
|
||||||
fn test_generate_entity_no_database_section() {
|
fn test_generate_entity_no_database_section() {
|
||||||
let matches = cli::build_cli()
|
let matches = cli::build_cli()
|
||||||
.setting(AppSettings::NoBinaryName)
|
.setting(AppSettings::NoBinaryName)
|
||||||
@ -231,7 +308,9 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "There is no database name as part of the url path: mysql://root:root@localhost:3306/")]
|
#[should_panic(
|
||||||
|
expected = "There is no database name as part of the url path: mysql://root:root@localhost:3306/"
|
||||||
|
)]
|
||||||
fn test_generate_entity_no_database_path() {
|
fn test_generate_entity_no_database_path() {
|
||||||
let matches = cli::build_cli()
|
let matches = cli::build_cli()
|
||||||
.setting(AppSettings::NoBinaryName)
|
.setting(AppSettings::NoBinaryName)
|
||||||
|
12
sea-orm-cli/template/migration/Cargo.toml
Normal file
12
sea-orm-cli/template/migration/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "migration"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "migration"
|
||||||
|
path = "src/lib.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
sea-schema = { git = "https://github.com/SeaQL/sea-schema.git", branch = "restructure-sea-query-dep", default-features = false, features = [ "migration", "debug-print" ] }
|
37
sea-orm-cli/template/migration/README.md
Normal file
37
sea-orm-cli/template/migration/README.md
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# Running Migrator CLI
|
||||||
|
|
||||||
|
- 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
|
||||||
|
```
|
12
sea-orm-cli/template/migration/src/lib.rs
Normal file
12
sea-orm-cli/template/migration/src/lib.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
pub use sea_schema::migration::*;
|
||||||
|
|
||||||
|
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)]
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
use sea_schema::migration::{
|
||||||
|
sea_query::{self, *},
|
||||||
|
*,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Migration;
|
||||||
|
|
||||||
|
impl MigrationName for Migration {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"m20220101_000001_create_table"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl MigrationTrait for Migration {
|
||||||
|
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
7
sea-orm-cli/template/migration/src/main.rs
Normal file
7
sea-orm-cli/template/migration/src/main.rs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
use migration::Migrator;
|
||||||
|
use sea_schema::migration::*;
|
||||||
|
|
||||||
|
#[async_std::main]
|
||||||
|
async fn main() {
|
||||||
|
cli::run_cli(Migrator).await;
|
||||||
|
}
|
@ -15,7 +15,7 @@ name = "sea_orm_codegen"
|
|||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
sea-query = { version = "0.20.0" }
|
sea-query = { version = "0.21.0" }
|
||||||
syn = { version = "^1", default-features = false, features = [
|
syn = { version = "^1", default-features = false, features = [
|
||||||
"derive",
|
"derive",
|
||||||
"parsing",
|
"parsing",
|
||||||
|
@ -7,10 +7,7 @@ use std::{future::Future, pin::Pin};
|
|||||||
/// Creates constraints for any structure that can create a database connection
|
/// Creates constraints for any structure that can create a database connection
|
||||||
/// and execute SQL statements
|
/// and execute SQL statements
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
pub trait ConnectionTrait<'a>: Sync {
|
pub trait ConnectionTrait: Sync {
|
||||||
/// Create a stream for the [QueryResult]
|
|
||||||
type Stream: Stream<Item = Result<QueryResult, DbErr>>;
|
|
||||||
|
|
||||||
/// Fetch the database backend as specified in [DbBackend].
|
/// Fetch the database backend as specified in [DbBackend].
|
||||||
/// This depends on feature flags enabled.
|
/// This depends on feature flags enabled.
|
||||||
fn get_database_backend(&self) -> DbBackend;
|
fn get_database_backend(&self) -> DbBackend;
|
||||||
@ -24,12 +21,34 @@ pub trait ConnectionTrait<'a>: Sync {
|
|||||||
/// Execute a [Statement] and return a collection Vec<[QueryResult]> on success
|
/// Execute a [Statement] and return a collection Vec<[QueryResult]> on success
|
||||||
async fn query_all(&self, stmt: Statement) -> Result<Vec<QueryResult>, DbErr>;
|
async fn query_all(&self, stmt: Statement) -> Result<Vec<QueryResult>, DbErr>;
|
||||||
|
|
||||||
|
/// Check if the connection supports `RETURNING` syntax on insert and update
|
||||||
|
fn support_returning(&self) -> bool {
|
||||||
|
let db_backend = self.get_database_backend();
|
||||||
|
db_backend.support_returning()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if the connection is a test connection for the Mock database
|
||||||
|
fn is_mock_connection(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stream query results
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
pub trait StreamTrait<'a>: Sync {
|
||||||
|
/// Create a stream for the [QueryResult]
|
||||||
|
type Stream: Stream<Item = Result<QueryResult, DbErr>>;
|
||||||
|
|
||||||
/// Execute a [Statement] and return a stream of results
|
/// Execute a [Statement] and return a stream of results
|
||||||
fn stream(
|
fn stream(
|
||||||
&'a self,
|
&'a self,
|
||||||
stmt: Statement,
|
stmt: Statement,
|
||||||
) -> Pin<Box<dyn Future<Output = Result<Self::Stream, DbErr>> + 'a>>;
|
) -> Pin<Box<dyn Future<Output = Result<Self::Stream, DbErr>> + 'a>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Spawn database transaction
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
pub trait TransactionTrait {
|
||||||
/// Execute SQL `BEGIN` transaction.
|
/// Execute SQL `BEGIN` transaction.
|
||||||
/// Returns a Transaction that can be committed or rolled back
|
/// Returns a Transaction that can be committed or rolled back
|
||||||
async fn begin(&self) -> Result<DatabaseTransaction, DbErr>;
|
async fn begin(&self) -> Result<DatabaseTransaction, DbErr>;
|
||||||
@ -44,15 +63,4 @@ pub trait ConnectionTrait<'a>: Sync {
|
|||||||
+ Send,
|
+ Send,
|
||||||
T: Send,
|
T: Send,
|
||||||
E: std::error::Error + Send;
|
E: std::error::Error + Send;
|
||||||
|
|
||||||
/// Check if the connection supports `RETURNING` syntax on insert and update
|
|
||||||
fn support_returning(&self) -> bool {
|
|
||||||
let db_backend = self.get_database_backend();
|
|
||||||
db_backend.support_returning()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check if the connection is a test connection for the Mock database
|
|
||||||
fn is_mock_connection(&self) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error::*, ConnectionTrait, DatabaseTransaction, ExecResult, QueryResult, Statement,
|
error::*, ConnectionTrait, DatabaseTransaction, ExecResult, QueryResult, Statement,
|
||||||
StatementBuilder, TransactionError,
|
StatementBuilder, StreamTrait, TransactionError, TransactionTrait,
|
||||||
};
|
};
|
||||||
use sea_query::{MysqlQueryBuilder, PostgresQueryBuilder, QueryBuilder, SqliteQueryBuilder};
|
use sea_query::{MysqlQueryBuilder, PostgresQueryBuilder, QueryBuilder, SqliteQueryBuilder};
|
||||||
use std::{future::Future, pin::Pin};
|
use std::{future::Future, pin::Pin};
|
||||||
@ -89,9 +89,7 @@ impl std::fmt::Debug for DatabaseConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl<'a> ConnectionTrait<'a> for DatabaseConnection {
|
impl ConnectionTrait for DatabaseConnection {
|
||||||
type Stream = crate::QueryStream;
|
|
||||||
|
|
||||||
fn get_database_backend(&self) -> DbBackend {
|
fn get_database_backend(&self) -> DbBackend {
|
||||||
match self {
|
match self {
|
||||||
#[cfg(feature = "sqlx-mysql")]
|
#[cfg(feature = "sqlx-mysql")]
|
||||||
@ -151,6 +149,16 @@ impl<'a> ConnectionTrait<'a> for DatabaseConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "mock")]
|
||||||
|
fn is_mock_connection(&self) -> bool {
|
||||||
|
matches!(self, DatabaseConnection::MockDatabaseConnection(_))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl<'a> StreamTrait<'a> for DatabaseConnection {
|
||||||
|
type Stream = crate::QueryStream;
|
||||||
|
|
||||||
#[instrument(level = "trace")]
|
#[instrument(level = "trace")]
|
||||||
fn stream(
|
fn stream(
|
||||||
&'a self,
|
&'a self,
|
||||||
@ -172,7 +180,10 @@ impl<'a> ConnectionTrait<'a> for DatabaseConnection {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl TransactionTrait for DatabaseConnection {
|
||||||
#[instrument(level = "trace")]
|
#[instrument(level = "trace")]
|
||||||
async fn begin(&self) -> Result<DatabaseTransaction, DbErr> {
|
async fn begin(&self) -> Result<DatabaseTransaction, DbErr> {
|
||||||
match self {
|
match self {
|
||||||
@ -221,11 +232,6 @@ impl<'a> ConnectionTrait<'a> for DatabaseConnection {
|
|||||||
DatabaseConnection::Disconnected => panic!("Disconnected"),
|
DatabaseConnection::Disconnected => panic!("Disconnected"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "mock")]
|
|
||||||
fn is_mock_connection(&self) -> bool {
|
|
||||||
matches!(self, DatabaseConnection::MockDatabaseConnection(_))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
|
@ -311,8 +311,8 @@ impl OpenTransaction {
|
|||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
entity::*, tests_cfg::*, ConnectionTrait, DbBackend, DbErr, MockDatabase, Statement,
|
entity::*, tests_cfg::*, DbBackend, DbErr, MockDatabase, Statement, Transaction,
|
||||||
Transaction, TransactionError,
|
TransactionError, TransactionTrait,
|
||||||
};
|
};
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
|
@ -124,6 +124,10 @@ build_schema_stmt!(sea_query::TableDropStatement);
|
|||||||
build_schema_stmt!(sea_query::TableAlterStatement);
|
build_schema_stmt!(sea_query::TableAlterStatement);
|
||||||
build_schema_stmt!(sea_query::TableRenameStatement);
|
build_schema_stmt!(sea_query::TableRenameStatement);
|
||||||
build_schema_stmt!(sea_query::TableTruncateStatement);
|
build_schema_stmt!(sea_query::TableTruncateStatement);
|
||||||
|
build_schema_stmt!(sea_query::IndexCreateStatement);
|
||||||
|
build_schema_stmt!(sea_query::IndexDropStatement);
|
||||||
|
build_schema_stmt!(sea_query::ForeignKeyCreateStatement);
|
||||||
|
build_schema_stmt!(sea_query::ForeignKeyDropStatement);
|
||||||
|
|
||||||
macro_rules! build_type_stmt {
|
macro_rules! build_type_stmt {
|
||||||
($stmt: ty) => {
|
($stmt: ty) => {
|
||||||
|
@ -156,6 +156,8 @@ impl QueryStream {
|
|||||||
}
|
}
|
||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
InnerConnection::Mock(c) => c.fetch(stmt),
|
InnerConnection::Mock(c) => c.fetch(stmt),
|
||||||
|
#[allow(unreachable_patterns)]
|
||||||
|
_ => unreachable!(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
.build()
|
.build()
|
||||||
|
@ -85,6 +85,8 @@ impl<'a> TransactionStream<'a> {
|
|||||||
}
|
}
|
||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
InnerConnection::Mock(c) => c.fetch(stmt),
|
InnerConnection::Mock(c) => c.fetch(stmt),
|
||||||
|
#[allow(unreachable_patterns)]
|
||||||
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
debug_print, ConnectionTrait, DbBackend, DbErr, ExecResult, InnerConnection, QueryResult,
|
debug_print, ConnectionTrait, DbBackend, DbErr, ExecResult, InnerConnection, QueryResult,
|
||||||
Statement, TransactionStream,
|
Statement, StreamTrait, TransactionStream, TransactionTrait,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "sqlx-dep")]
|
#[cfg(feature = "sqlx-dep")]
|
||||||
use crate::{sqlx_error_to_exec_err, sqlx_error_to_query_err};
|
use crate::{sqlx_error_to_exec_err, sqlx_error_to_query_err};
|
||||||
@ -226,6 +226,8 @@ impl DatabaseTransaction {
|
|||||||
InnerConnection::Mock(c) => {
|
InnerConnection::Mock(c) => {
|
||||||
c.rollback();
|
c.rollback();
|
||||||
}
|
}
|
||||||
|
#[allow(unreachable_patterns)]
|
||||||
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//this should never happen
|
//this should never happen
|
||||||
@ -242,9 +244,7 @@ impl Drop for DatabaseTransaction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl<'a> ConnectionTrait<'a> for DatabaseTransaction {
|
impl ConnectionTrait for DatabaseTransaction {
|
||||||
type Stream = TransactionStream<'a>;
|
|
||||||
|
|
||||||
fn get_database_backend(&self) -> DbBackend {
|
fn get_database_backend(&self) -> DbBackend {
|
||||||
// this way we don't need to lock
|
// this way we don't need to lock
|
||||||
self.backend
|
self.backend
|
||||||
@ -278,6 +278,8 @@ impl<'a> ConnectionTrait<'a> for DatabaseTransaction {
|
|||||||
}
|
}
|
||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
InnerConnection::Mock(conn) => return conn.execute(stmt),
|
InnerConnection::Mock(conn) => return conn.execute(stmt),
|
||||||
|
#[allow(unreachable_patterns)]
|
||||||
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
#[cfg(feature = "sqlx-dep")]
|
#[cfg(feature = "sqlx-dep")]
|
||||||
_res.map_err(sqlx_error_to_exec_err)
|
_res.map_err(sqlx_error_to_exec_err)
|
||||||
@ -305,6 +307,8 @@ impl<'a> ConnectionTrait<'a> for DatabaseTransaction {
|
|||||||
}
|
}
|
||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
InnerConnection::Mock(conn) => return conn.query_one(stmt),
|
InnerConnection::Mock(conn) => return conn.query_one(stmt),
|
||||||
|
#[allow(unreachable_patterns)]
|
||||||
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
#[cfg(feature = "sqlx-dep")]
|
#[cfg(feature = "sqlx-dep")]
|
||||||
if let Err(sqlx::Error::RowNotFound) = _res {
|
if let Err(sqlx::Error::RowNotFound) = _res {
|
||||||
@ -345,10 +349,17 @@ impl<'a> ConnectionTrait<'a> for DatabaseTransaction {
|
|||||||
}
|
}
|
||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
InnerConnection::Mock(conn) => return conn.query_all(stmt),
|
InnerConnection::Mock(conn) => return conn.query_all(stmt),
|
||||||
|
#[allow(unreachable_patterns)]
|
||||||
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
#[cfg(feature = "sqlx-dep")]
|
#[cfg(feature = "sqlx-dep")]
|
||||||
_res.map_err(sqlx_error_to_query_err)
|
_res.map_err(sqlx_error_to_query_err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl<'a> StreamTrait<'a> for DatabaseTransaction {
|
||||||
|
type Stream = TransactionStream<'a>;
|
||||||
|
|
||||||
#[instrument(level = "trace")]
|
#[instrument(level = "trace")]
|
||||||
fn stream(
|
fn stream(
|
||||||
@ -364,7 +375,10 @@ impl<'a> ConnectionTrait<'a> for DatabaseTransaction {
|
|||||||
.await)
|
.await)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl TransactionTrait for DatabaseTransaction {
|
||||||
#[instrument(level = "trace")]
|
#[instrument(level = "trace")]
|
||||||
async fn begin(&self) -> Result<DatabaseTransaction, DbErr> {
|
async fn begin(&self) -> Result<DatabaseTransaction, DbErr> {
|
||||||
DatabaseTransaction::begin(
|
DatabaseTransaction::begin(
|
||||||
|
@ -276,7 +276,7 @@ pub trait ActiveModelTrait: Clone + Debug {
|
|||||||
where
|
where
|
||||||
<Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
|
<Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
|
||||||
Self: ActiveModelBehavior + 'a,
|
Self: ActiveModelBehavior + 'a,
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait,
|
||||||
{
|
{
|
||||||
let am = ActiveModelBehavior::before_save(self, true)?;
|
let am = ActiveModelBehavior::before_save(self, true)?;
|
||||||
let model = <Self::Entity as EntityTrait>::insert(am)
|
let model = <Self::Entity as EntityTrait>::insert(am)
|
||||||
@ -398,7 +398,7 @@ pub trait ActiveModelTrait: Clone + Debug {
|
|||||||
where
|
where
|
||||||
<Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
|
<Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
|
||||||
Self: ActiveModelBehavior + 'a,
|
Self: ActiveModelBehavior + 'a,
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait,
|
||||||
{
|
{
|
||||||
let am = ActiveModelBehavior::before_save(self, false)?;
|
let am = ActiveModelBehavior::before_save(self, false)?;
|
||||||
let model: <Self::Entity as EntityTrait>::Model = Self::Entity::update(am).exec(db).await?;
|
let model: <Self::Entity as EntityTrait>::Model = Self::Entity::update(am).exec(db).await?;
|
||||||
@ -411,7 +411,7 @@ pub trait ActiveModelTrait: Clone + Debug {
|
|||||||
where
|
where
|
||||||
<Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
|
<Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
|
||||||
Self: ActiveModelBehavior + 'a,
|
Self: ActiveModelBehavior + 'a,
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait,
|
||||||
{
|
{
|
||||||
let mut is_update = true;
|
let mut is_update = true;
|
||||||
for key in <Self::Entity as EntityTrait>::PrimaryKey::iter() {
|
for key in <Self::Entity as EntityTrait>::PrimaryKey::iter() {
|
||||||
@ -475,7 +475,7 @@ pub trait ActiveModelTrait: Clone + Debug {
|
|||||||
async fn delete<'a, C>(self, db: &'a C) -> Result<DeleteResult, DbErr>
|
async fn delete<'a, C>(self, db: &'a C) -> Result<DeleteResult, DbErr>
|
||||||
where
|
where
|
||||||
Self: ActiveModelBehavior + 'a,
|
Self: ActiveModelBehavior + 'a,
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait,
|
||||||
{
|
{
|
||||||
let am = ActiveModelBehavior::before_delete(self)?;
|
let am = ActiveModelBehavior::before_delete(self)?;
|
||||||
let am_clone = am.clone();
|
let am_clone = am.clone();
|
||||||
|
@ -41,7 +41,7 @@ pub trait ModelTrait: Clone + Send + Debug {
|
|||||||
async fn delete<'a, A, C>(self, db: &'a C) -> Result<DeleteResult, DbErr>
|
async fn delete<'a, A, C>(self, db: &'a C) -> Result<DeleteResult, DbErr>
|
||||||
where
|
where
|
||||||
Self: IntoActiveModel<A>,
|
Self: IntoActiveModel<A>,
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait,
|
||||||
A: ActiveModelTrait<Entity = Self::Entity> + ActiveModelBehavior + Send + 'a,
|
A: ActiveModelTrait<Entity = Self::Entity> + ActiveModelBehavior + Send + 'a,
|
||||||
{
|
{
|
||||||
self.into_active_model().delete(db).await
|
self.into_active_model().delete(db).await
|
||||||
|
@ -24,7 +24,7 @@ where
|
|||||||
/// Execute a DELETE operation on one ActiveModel
|
/// Execute a DELETE operation on one ActiveModel
|
||||||
pub fn exec<C>(self, db: &'a C) -> impl Future<Output = Result<DeleteResult, DbErr>> + '_
|
pub fn exec<C>(self, db: &'a C) -> impl Future<Output = Result<DeleteResult, DbErr>> + '_
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait,
|
||||||
{
|
{
|
||||||
// so that self is dropped before entering await
|
// so that self is dropped before entering await
|
||||||
exec_delete_only(self.query, db)
|
exec_delete_only(self.query, db)
|
||||||
@ -38,7 +38,7 @@ where
|
|||||||
/// Execute a DELETE operation on many ActiveModels
|
/// Execute a DELETE operation on many ActiveModels
|
||||||
pub fn exec<C>(self, db: &'a C) -> impl Future<Output = Result<DeleteResult, DbErr>> + '_
|
pub fn exec<C>(self, db: &'a C) -> impl Future<Output = Result<DeleteResult, DbErr>> + '_
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait,
|
||||||
{
|
{
|
||||||
// so that self is dropped before entering await
|
// so that self is dropped before entering await
|
||||||
exec_delete_only(self.query, db)
|
exec_delete_only(self.query, db)
|
||||||
@ -54,7 +54,7 @@ impl Deleter {
|
|||||||
/// Execute a DELETE operation
|
/// Execute a DELETE operation
|
||||||
pub fn exec<'a, C>(self, db: &'a C) -> impl Future<Output = Result<DeleteResult, DbErr>> + '_
|
pub fn exec<'a, C>(self, db: &'a C) -> impl Future<Output = Result<DeleteResult, DbErr>> + '_
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait,
|
||||||
{
|
{
|
||||||
let builder = db.get_database_backend();
|
let builder = db.get_database_backend();
|
||||||
exec_delete(builder.build(&self.query), db)
|
exec_delete(builder.build(&self.query), db)
|
||||||
@ -63,14 +63,14 @@ impl Deleter {
|
|||||||
|
|
||||||
async fn exec_delete_only<'a, C>(query: DeleteStatement, db: &'a C) -> Result<DeleteResult, DbErr>
|
async fn exec_delete_only<'a, C>(query: DeleteStatement, db: &'a C) -> Result<DeleteResult, DbErr>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait,
|
||||||
{
|
{
|
||||||
Deleter::new(query).exec(db).await
|
Deleter::new(query).exec(db).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn exec_delete<'a, C>(statement: Statement, db: &'a C) -> Result<DeleteResult, DbErr>
|
async fn exec_delete<'a, C>(statement: Statement, db: &'a C) -> Result<DeleteResult, DbErr>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait,
|
||||||
{
|
{
|
||||||
let result = db.execute(statement).await?;
|
let result = db.execute(statement).await?;
|
||||||
Ok(DeleteResult {
|
Ok(DeleteResult {
|
||||||
|
@ -46,6 +46,8 @@ impl ExecResult {
|
|||||||
}
|
}
|
||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
ExecResultHolder::Mock(result) => result.last_insert_id,
|
ExecResultHolder::Mock(result) => result.last_insert_id,
|
||||||
|
#[allow(unreachable_patterns)]
|
||||||
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,6 +62,8 @@ impl ExecResult {
|
|||||||
ExecResultHolder::SqlxSqlite(result) => result.rows_affected(),
|
ExecResultHolder::SqlxSqlite(result) => result.rows_affected(),
|
||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
ExecResultHolder::Mock(result) => result.rows_affected,
|
ExecResultHolder::Mock(result) => result.rows_affected,
|
||||||
|
#[allow(unreachable_patterns)]
|
||||||
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ where
|
|||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
pub fn exec<'a, C>(self, db: &'a C) -> impl Future<Output = Result<InsertResult<A>, DbErr>> + '_
|
pub fn exec<'a, C>(self, db: &'a C) -> impl Future<Output = Result<InsertResult<A>, DbErr>> + '_
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait,
|
||||||
A: 'a,
|
A: 'a,
|
||||||
{
|
{
|
||||||
// so that self is dropped before entering await
|
// so that self is dropped before entering await
|
||||||
@ -58,7 +58,7 @@ where
|
|||||||
) -> impl Future<Output = Result<<A::Entity as EntityTrait>::Model, DbErr>> + '_
|
) -> impl Future<Output = Result<<A::Entity as EntityTrait>::Model, DbErr>> + '_
|
||||||
where
|
where
|
||||||
<A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
|
<A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait,
|
||||||
A: 'a,
|
A: 'a,
|
||||||
{
|
{
|
||||||
Inserter::<A>::new(self.primary_key, self.query).exec_with_returning(db)
|
Inserter::<A>::new(self.primary_key, self.query).exec_with_returning(db)
|
||||||
@ -81,7 +81,7 @@ where
|
|||||||
/// Execute an insert operation
|
/// Execute an insert operation
|
||||||
pub fn exec<'a, C>(self, db: &'a C) -> impl Future<Output = Result<InsertResult<A>, DbErr>> + '_
|
pub fn exec<'a, C>(self, db: &'a C) -> impl Future<Output = Result<InsertResult<A>, DbErr>> + '_
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait,
|
||||||
A: 'a,
|
A: 'a,
|
||||||
{
|
{
|
||||||
let builder = db.get_database_backend();
|
let builder = db.get_database_backend();
|
||||||
@ -95,7 +95,7 @@ where
|
|||||||
) -> impl Future<Output = Result<<A::Entity as EntityTrait>::Model, DbErr>> + '_
|
) -> impl Future<Output = Result<<A::Entity as EntityTrait>::Model, DbErr>> + '_
|
||||||
where
|
where
|
||||||
<A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
|
<A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait,
|
||||||
A: 'a,
|
A: 'a,
|
||||||
{
|
{
|
||||||
exec_insert_with_returning::<A, _>(self.primary_key, self.query, db)
|
exec_insert_with_returning::<A, _>(self.primary_key, self.query, db)
|
||||||
@ -108,7 +108,7 @@ async fn exec_insert<'a, A, C>(
|
|||||||
db: &'a C,
|
db: &'a C,
|
||||||
) -> Result<InsertResult<A>, DbErr>
|
) -> Result<InsertResult<A>, DbErr>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait,
|
||||||
A: ActiveModelTrait,
|
A: ActiveModelTrait,
|
||||||
{
|
{
|
||||||
type PrimaryKey<A> = <<A as ActiveModelTrait>::Entity as EntityTrait>::PrimaryKey;
|
type PrimaryKey<A> = <<A as ActiveModelTrait>::Entity as EntityTrait>::PrimaryKey;
|
||||||
@ -143,7 +143,7 @@ async fn exec_insert_with_returning<'a, A, C>(
|
|||||||
) -> Result<<A::Entity as EntityTrait>::Model, DbErr>
|
) -> Result<<A::Entity as EntityTrait>::Model, DbErr>
|
||||||
where
|
where
|
||||||
<A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
|
<A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait,
|
||||||
A: ActiveModelTrait,
|
A: ActiveModelTrait,
|
||||||
{
|
{
|
||||||
let db_backend = db.get_database_backend();
|
let db_backend = db.get_database_backend();
|
||||||
|
@ -14,7 +14,7 @@ pub type PinBoxStream<'db, Item> = Pin<Box<dyn Stream<Item = Item> + 'db>>;
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Paginator<'db, C, S>
|
pub struct Paginator<'db, C, S>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'db>,
|
C: ConnectionTrait,
|
||||||
S: SelectorTrait + 'db,
|
S: SelectorTrait + 'db,
|
||||||
{
|
{
|
||||||
pub(crate) query: SelectStatement,
|
pub(crate) query: SelectStatement,
|
||||||
@ -28,7 +28,7 @@ where
|
|||||||
|
|
||||||
impl<'db, C, S> Paginator<'db, C, S>
|
impl<'db, C, S> Paginator<'db, C, S>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'db>,
|
C: ConnectionTrait,
|
||||||
S: SelectorTrait + 'db,
|
S: SelectorTrait + 'db,
|
||||||
{
|
{
|
||||||
/// Fetch a specific page; page index starts from zero
|
/// Fetch a specific page; page index starts from zero
|
||||||
@ -184,7 +184,7 @@ where
|
|||||||
/// A Trait for any type that can paginate results
|
/// A Trait for any type that can paginate results
|
||||||
pub trait PaginatorTrait<'db, C>
|
pub trait PaginatorTrait<'db, C>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'db>,
|
C: ConnectionTrait,
|
||||||
{
|
{
|
||||||
/// Select operation
|
/// Select operation
|
||||||
type Selector: SelectorTrait + Send + Sync + 'db;
|
type Selector: SelectorTrait + Send + Sync + 'db;
|
||||||
@ -203,7 +203,7 @@ where
|
|||||||
|
|
||||||
impl<'db, C, S> PaginatorTrait<'db, C> for Selector<S>
|
impl<'db, C, S> PaginatorTrait<'db, C> for Selector<S>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'db>,
|
C: ConnectionTrait,
|
||||||
S: SelectorTrait + Send + Sync + 'db,
|
S: SelectorTrait + Send + Sync + 'db,
|
||||||
{
|
{
|
||||||
type Selector = S;
|
type Selector = S;
|
||||||
@ -221,7 +221,7 @@ where
|
|||||||
|
|
||||||
impl<'db, C, M, E> PaginatorTrait<'db, C> for Select<E>
|
impl<'db, C, M, E> PaginatorTrait<'db, C> for Select<E>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'db>,
|
C: ConnectionTrait,
|
||||||
E: EntityTrait<Model = M>,
|
E: EntityTrait<Model = M>,
|
||||||
M: FromQueryResult + Sized + Send + Sync + 'db,
|
M: FromQueryResult + Sized + Send + Sync + 'db,
|
||||||
{
|
{
|
||||||
@ -234,7 +234,7 @@ where
|
|||||||
|
|
||||||
impl<'db, C, M, N, E, F> PaginatorTrait<'db, C> for SelectTwo<E, F>
|
impl<'db, C, M, N, E, F> PaginatorTrait<'db, C> for SelectTwo<E, F>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'db>,
|
C: ConnectionTrait,
|
||||||
E: EntityTrait<Model = M>,
|
E: EntityTrait<Model = M>,
|
||||||
F: EntityTrait<Model = N>,
|
F: EntityTrait<Model = N>,
|
||||||
M: FromQueryResult + Sized + Send + Sync + 'db,
|
M: FromQueryResult + Sized + Send + Sync + 'db,
|
||||||
|
@ -75,6 +75,8 @@ impl fmt::Debug for QueryResultRow {
|
|||||||
Self::SqlxSqlite(_) => write!(f, "QueryResultRow::SqlxSqlite cannot be inspected"),
|
Self::SqlxSqlite(_) => write!(f, "QueryResultRow::SqlxSqlite cannot be inspected"),
|
||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
Self::Mock(row) => write!(f, "{:?}", row),
|
Self::Mock(row) => write!(f, "{:?}", row),
|
||||||
|
#[allow(unreachable_patterns)]
|
||||||
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -124,6 +126,8 @@ macro_rules! try_getable_all {
|
|||||||
debug_print!("{:#?}", e.to_string());
|
debug_print!("{:#?}", e.to_string());
|
||||||
TryGetError::Null
|
TryGetError::Null
|
||||||
}),
|
}),
|
||||||
|
#[allow(unreachable_patterns)]
|
||||||
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -160,6 +164,8 @@ macro_rules! try_getable_unsigned {
|
|||||||
debug_print!("{:#?}", e.to_string());
|
debug_print!("{:#?}", e.to_string());
|
||||||
TryGetError::Null
|
TryGetError::Null
|
||||||
}),
|
}),
|
||||||
|
#[allow(unreachable_patterns)]
|
||||||
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -193,6 +199,8 @@ macro_rules! try_getable_mysql {
|
|||||||
debug_print!("{:#?}", e.to_string());
|
debug_print!("{:#?}", e.to_string());
|
||||||
TryGetError::Null
|
TryGetError::Null
|
||||||
}),
|
}),
|
||||||
|
#[allow(unreachable_patterns)]
|
||||||
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -236,6 +244,8 @@ macro_rules! try_getable_date_time {
|
|||||||
debug_print!("{:#?}", e.to_string());
|
debug_print!("{:#?}", e.to_string());
|
||||||
TryGetError::Null
|
TryGetError::Null
|
||||||
}),
|
}),
|
||||||
|
#[allow(unreachable_patterns)]
|
||||||
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -321,6 +331,8 @@ impl TryGetable for Decimal {
|
|||||||
debug_print!("{:#?}", e.to_string());
|
debug_print!("{:#?}", e.to_string());
|
||||||
TryGetError::Null
|
TryGetError::Null
|
||||||
}),
|
}),
|
||||||
|
#[allow(unreachable_patterns)]
|
||||||
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error::*, ConnectionTrait, EntityTrait, FromQueryResult, IdenStatic, Iterable, ModelTrait,
|
error::*, ConnectionTrait, EntityTrait, FromQueryResult, IdenStatic, Iterable, ModelTrait,
|
||||||
PrimaryKeyToColumn, QueryResult, Select, SelectA, SelectB, SelectTwo, SelectTwoMany, Statement,
|
PrimaryKeyToColumn, QueryResult, Select, SelectA, SelectB, SelectTwo, SelectTwoMany, Statement,
|
||||||
TryGetableMany,
|
StreamTrait, TryGetableMany,
|
||||||
};
|
};
|
||||||
use futures::{Stream, TryStreamExt};
|
use futures::{Stream, TryStreamExt};
|
||||||
use sea_query::SelectStatement;
|
use sea_query::SelectStatement;
|
||||||
@ -256,7 +256,7 @@ where
|
|||||||
/// Get one Model from the SELECT query
|
/// Get one Model from the SELECT query
|
||||||
pub async fn one<'a, C>(self, db: &C) -> Result<Option<E::Model>, DbErr>
|
pub async fn one<'a, C>(self, db: &C) -> Result<Option<E::Model>, DbErr>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait,
|
||||||
{
|
{
|
||||||
self.into_model().one(db).await
|
self.into_model().one(db).await
|
||||||
}
|
}
|
||||||
@ -264,7 +264,7 @@ where
|
|||||||
/// Get all Models from the SELECT query
|
/// Get all Models from the SELECT query
|
||||||
pub async fn all<'a, C>(self, db: &C) -> Result<Vec<E::Model>, DbErr>
|
pub async fn all<'a, C>(self, db: &C) -> Result<Vec<E::Model>, DbErr>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait,
|
||||||
{
|
{
|
||||||
self.into_model().all(db).await
|
self.into_model().all(db).await
|
||||||
}
|
}
|
||||||
@ -275,7 +275,7 @@ where
|
|||||||
db: &'a C,
|
db: &'a C,
|
||||||
) -> Result<impl Stream<Item = Result<E::Model, DbErr>> + 'b, DbErr>
|
) -> Result<impl Stream<Item = Result<E::Model, DbErr>> + 'b, DbErr>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait + StreamTrait<'a>,
|
||||||
{
|
{
|
||||||
self.into_model().stream(db).await
|
self.into_model().stream(db).await
|
||||||
}
|
}
|
||||||
@ -310,7 +310,7 @@ where
|
|||||||
/// Get one Model from the Select query
|
/// Get one Model from the Select query
|
||||||
pub async fn one<'a, C>(self, db: &C) -> Result<Option<(E::Model, Option<F::Model>)>, DbErr>
|
pub async fn one<'a, C>(self, db: &C) -> Result<Option<(E::Model, Option<F::Model>)>, DbErr>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait,
|
||||||
{
|
{
|
||||||
self.into_model().one(db).await
|
self.into_model().one(db).await
|
||||||
}
|
}
|
||||||
@ -318,7 +318,7 @@ where
|
|||||||
/// Get all Models from the Select query
|
/// Get all Models from the Select query
|
||||||
pub async fn all<'a, C>(self, db: &C) -> Result<Vec<(E::Model, Option<F::Model>)>, DbErr>
|
pub async fn all<'a, C>(self, db: &C) -> Result<Vec<(E::Model, Option<F::Model>)>, DbErr>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait,
|
||||||
{
|
{
|
||||||
self.into_model().all(db).await
|
self.into_model().all(db).await
|
||||||
}
|
}
|
||||||
@ -329,7 +329,7 @@ where
|
|||||||
db: &'a C,
|
db: &'a C,
|
||||||
) -> Result<impl Stream<Item = Result<(E::Model, Option<F::Model>), DbErr>> + 'b, DbErr>
|
) -> Result<impl Stream<Item = Result<(E::Model, Option<F::Model>), DbErr>> + 'b, DbErr>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait + StreamTrait<'a>,
|
||||||
{
|
{
|
||||||
self.into_model().stream(db).await
|
self.into_model().stream(db).await
|
||||||
}
|
}
|
||||||
@ -364,7 +364,7 @@ where
|
|||||||
/// Select one Model
|
/// Select one Model
|
||||||
pub async fn one<'a, C>(self, db: &C) -> Result<Option<(E::Model, Option<F::Model>)>, DbErr>
|
pub async fn one<'a, C>(self, db: &C) -> Result<Option<(E::Model, Option<F::Model>)>, DbErr>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait,
|
||||||
{
|
{
|
||||||
self.into_model().one(db).await
|
self.into_model().one(db).await
|
||||||
}
|
}
|
||||||
@ -375,7 +375,7 @@ where
|
|||||||
db: &'a C,
|
db: &'a C,
|
||||||
) -> Result<impl Stream<Item = Result<(E::Model, Option<F::Model>), DbErr>> + 'b, DbErr>
|
) -> Result<impl Stream<Item = Result<(E::Model, Option<F::Model>), DbErr>> + 'b, DbErr>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait + StreamTrait<'a>,
|
||||||
{
|
{
|
||||||
self.into_model().stream(db).await
|
self.into_model().stream(db).await
|
||||||
}
|
}
|
||||||
@ -383,7 +383,7 @@ where
|
|||||||
/// Get all Models from the select operation
|
/// Get all Models from the select operation
|
||||||
pub async fn all<'a, C>(self, db: &C) -> Result<Vec<(E::Model, Vec<F::Model>)>, DbErr>
|
pub async fn all<'a, C>(self, db: &C) -> Result<Vec<(E::Model, Vec<F::Model>)>, DbErr>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait,
|
||||||
{
|
{
|
||||||
let rows = self.into_model().all(db).await?;
|
let rows = self.into_model().all(db).await?;
|
||||||
Ok(consolidate_query_result::<E, F>(rows))
|
Ok(consolidate_query_result::<E, F>(rows))
|
||||||
@ -421,7 +421,7 @@ where
|
|||||||
|
|
||||||
fn into_selector_raw<'a, C>(self, db: &C) -> SelectorRaw<S>
|
fn into_selector_raw<'a, C>(self, db: &C) -> SelectorRaw<S>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait,
|
||||||
{
|
{
|
||||||
let builder = db.get_database_backend();
|
let builder = db.get_database_backend();
|
||||||
let stmt = builder.build(&self.query);
|
let stmt = builder.build(&self.query);
|
||||||
@ -434,7 +434,7 @@ where
|
|||||||
/// Get an item from the Select query
|
/// Get an item from the Select query
|
||||||
pub async fn one<'a, C>(mut self, db: &C) -> Result<Option<S::Item>, DbErr>
|
pub async fn one<'a, C>(mut self, db: &C) -> Result<Option<S::Item>, DbErr>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait,
|
||||||
{
|
{
|
||||||
self.query.limit(1);
|
self.query.limit(1);
|
||||||
self.into_selector_raw(db).one(db).await
|
self.into_selector_raw(db).one(db).await
|
||||||
@ -443,7 +443,7 @@ where
|
|||||||
/// Get all items from the Select query
|
/// Get all items from the Select query
|
||||||
pub async fn all<'a, C>(self, db: &C) -> Result<Vec<S::Item>, DbErr>
|
pub async fn all<'a, C>(self, db: &C) -> Result<Vec<S::Item>, DbErr>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait,
|
||||||
{
|
{
|
||||||
self.into_selector_raw(db).all(db).await
|
self.into_selector_raw(db).all(db).await
|
||||||
}
|
}
|
||||||
@ -454,7 +454,7 @@ where
|
|||||||
db: &'a C,
|
db: &'a C,
|
||||||
) -> Result<Pin<Box<dyn Stream<Item = Result<S::Item, DbErr>> + 'b>>, DbErr>
|
) -> Result<Pin<Box<dyn Stream<Item = Result<S::Item, DbErr>> + 'b>>, DbErr>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait + StreamTrait<'a>,
|
||||||
S: 'b,
|
S: 'b,
|
||||||
{
|
{
|
||||||
self.into_selector_raw(db).stream(db).await
|
self.into_selector_raw(db).stream(db).await
|
||||||
@ -672,7 +672,7 @@ where
|
|||||||
/// ```
|
/// ```
|
||||||
pub async fn one<'a, C>(self, db: &C) -> Result<Option<S::Item>, DbErr>
|
pub async fn one<'a, C>(self, db: &C) -> Result<Option<S::Item>, DbErr>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait,
|
||||||
{
|
{
|
||||||
let row = db.query_one(self.stmt).await?;
|
let row = db.query_one(self.stmt).await?;
|
||||||
match row {
|
match row {
|
||||||
@ -723,7 +723,7 @@ where
|
|||||||
/// ```
|
/// ```
|
||||||
pub async fn all<'a, C>(self, db: &C) -> Result<Vec<S::Item>, DbErr>
|
pub async fn all<'a, C>(self, db: &C) -> Result<Vec<S::Item>, DbErr>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait,
|
||||||
{
|
{
|
||||||
let rows = db.query_all(self.stmt).await?;
|
let rows = db.query_all(self.stmt).await?;
|
||||||
let mut models = Vec::new();
|
let mut models = Vec::new();
|
||||||
@ -739,7 +739,7 @@ where
|
|||||||
db: &'a C,
|
db: &'a C,
|
||||||
) -> Result<Pin<Box<dyn Stream<Item = Result<S::Item, DbErr>> + 'b>>, DbErr>
|
) -> Result<Pin<Box<dyn Stream<Item = Result<S::Item, DbErr>> + 'b>>, DbErr>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait + StreamTrait<'a>,
|
||||||
S: 'b,
|
S: 'b,
|
||||||
{
|
{
|
||||||
let stream = db.stream(self.stmt).await?;
|
let stream = db.stream(self.stmt).await?;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error::*, ActiveModelTrait, ColumnTrait, ConnectionTrait, EntityTrait, Iterable, SelectModel,
|
error::*, ActiveModelTrait, ColumnTrait, ConnectionTrait, EntityTrait, IntoActiveModel,
|
||||||
SelectorRaw, Statement, UpdateMany, UpdateOne,
|
Iterable, SelectModel, SelectorRaw, Statement, UpdateMany, UpdateOne,
|
||||||
};
|
};
|
||||||
use sea_query::{Alias, Expr, FromValueTuple, Query, UpdateStatement};
|
use sea_query::{Alias, Expr, FromValueTuple, Query, UpdateStatement};
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
@ -26,7 +26,8 @@ where
|
|||||||
/// Execute an update operation on an ActiveModel
|
/// Execute an update operation on an ActiveModel
|
||||||
pub async fn exec<'b, C>(self, db: &'b C) -> Result<<A::Entity as EntityTrait>::Model, DbErr>
|
pub async fn exec<'b, C>(self, db: &'b C) -> Result<<A::Entity as EntityTrait>::Model, DbErr>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'b>,
|
<A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
|
||||||
|
C: ConnectionTrait,
|
||||||
{
|
{
|
||||||
// so that self is dropped before entering await
|
// so that self is dropped before entering await
|
||||||
exec_update_and_return_updated(self.query, self.model, db).await
|
exec_update_and_return_updated(self.query, self.model, db).await
|
||||||
@ -40,7 +41,7 @@ where
|
|||||||
/// Execute an update operation on multiple ActiveModels
|
/// Execute an update operation on multiple ActiveModels
|
||||||
pub fn exec<C>(self, db: &'a C) -> impl Future<Output = Result<UpdateResult, DbErr>> + '_
|
pub fn exec<C>(self, db: &'a C) -> impl Future<Output = Result<UpdateResult, DbErr>> + '_
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait,
|
||||||
{
|
{
|
||||||
// so that self is dropped before entering await
|
// so that self is dropped before entering await
|
||||||
exec_update_only(self.query, db)
|
exec_update_only(self.query, db)
|
||||||
@ -65,7 +66,7 @@ impl Updater {
|
|||||||
/// Execute an update operation
|
/// Execute an update operation
|
||||||
pub fn exec<'a, C>(self, db: &'a C) -> impl Future<Output = Result<UpdateResult, DbErr>> + '_
|
pub fn exec<'a, C>(self, db: &'a C) -> impl Future<Output = Result<UpdateResult, DbErr>> + '_
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait,
|
||||||
{
|
{
|
||||||
let builder = db.get_database_backend();
|
let builder = db.get_database_backend();
|
||||||
exec_update(builder.build(&self.query), db, self.check_record_exists)
|
exec_update(builder.build(&self.query), db, self.check_record_exists)
|
||||||
@ -74,7 +75,7 @@ impl Updater {
|
|||||||
|
|
||||||
async fn exec_update_only<'a, C>(query: UpdateStatement, db: &'a C) -> Result<UpdateResult, DbErr>
|
async fn exec_update_only<'a, C>(query: UpdateStatement, db: &'a C) -> Result<UpdateResult, DbErr>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait,
|
||||||
{
|
{
|
||||||
Updater::new(query).exec(db).await
|
Updater::new(query).exec(db).await
|
||||||
}
|
}
|
||||||
@ -86,7 +87,7 @@ async fn exec_update_and_return_updated<'a, A, C>(
|
|||||||
) -> Result<<A::Entity as EntityTrait>::Model, DbErr>
|
) -> Result<<A::Entity as EntityTrait>::Model, DbErr>
|
||||||
where
|
where
|
||||||
A: ActiveModelTrait,
|
A: ActiveModelTrait,
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait,
|
||||||
{
|
{
|
||||||
match db.support_returning() {
|
match db.support_returning() {
|
||||||
true => {
|
true => {
|
||||||
@ -141,7 +142,7 @@ async fn exec_update<'a, C>(
|
|||||||
check_record_exists: bool,
|
check_record_exists: bool,
|
||||||
) -> Result<UpdateResult, DbErr>
|
) -> Result<UpdateResult, DbErr>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait,
|
||||||
{
|
{
|
||||||
let result = db.execute(statement).await?;
|
let result = db.execute(statement).await?;
|
||||||
if check_record_exists && result.rows_affected() == 0 {
|
if check_record_exists && result.rows_affected() == 0 {
|
||||||
|
@ -23,5 +23,6 @@ pub use update::*;
|
|||||||
pub use util::*;
|
pub use util::*;
|
||||||
|
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
ConnectionTrait, InsertResult, PaginatorTrait, Statement, UpdateResult, Value, Values,
|
ConnectionTrait, InsertResult, PaginatorTrait, Statement, StreamTrait, TransactionTrait,
|
||||||
|
UpdateResult, Value, Values,
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user