mirror of
https://github.com/danbulant/Portfolio
synced 2026-06-09 01:30:18 +00:00
chore: project setup
This commit is contained in:
commit
63c7307e43
20 changed files with 560 additions and 0 deletions
14
.gitignore
vendored
Normal file
14
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
# Generated by Cargo
|
||||||
|
# will have compiled files and executables
|
||||||
|
debug/
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||||
|
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||||
|
Cargo.lock
|
||||||
|
|
||||||
|
# These are backup files generated by rustfmt
|
||||||
|
**/*.rs.bk
|
||||||
|
|
||||||
|
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||||
|
*.pdb
|
||||||
12
Cargo.toml
Normal file
12
Cargo.toml
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
[package]
|
||||||
|
name = "sea-orm-rocket-example"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Vojtěch Jungmann", "Sebastian Pravda"]
|
||||||
|
edition = "2021"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[workspace]
|
||||||
|
members = [".", "api", "core", "entity", "migration"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
portfolio-api = { path = "api" }
|
||||||
5
Rocket.toml
Normal file
5
Rocket.toml
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
#[default]
|
||||||
|
#template_dir = "api/templates/"
|
||||||
|
|
||||||
|
[default.databases.sea_orm]
|
||||||
|
#url = "postgres://root:root@localhost/rocket_example"
|
||||||
25
api/Cargo.toml
Normal file
25
api/Cargo.toml
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
[package]
|
||||||
|
name = "portfolio-api"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
async-stream = { version = "^0.3" }
|
||||||
|
async-trait = { version = "0.1" }
|
||||||
|
futures = { version = "^0.3" }
|
||||||
|
futures-util = { version = "^0.3" }
|
||||||
|
rocket = { version = "0.5.0-rc.2", features = [
|
||||||
|
"json",
|
||||||
|
] }
|
||||||
|
|
||||||
|
serde_json = { version = "^1" }
|
||||||
|
|
||||||
|
portfolio-entity = { path = "../entity" }
|
||||||
|
portfolio-migration = { path = "../migration" }
|
||||||
|
portfolio-core = { path = "../core" }
|
||||||
|
|
||||||
|
tokio = "1.21.2"
|
||||||
|
|
||||||
|
[dependencies.sea-orm-rocket]
|
||||||
|
version = "0.5.1"
|
||||||
100
api/src/lib.rs
Normal file
100
api/src/lib.rs
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
#[macro_use]
|
||||||
|
extern crate rocket;
|
||||||
|
|
||||||
|
use rocket::fairing::{self, AdHoc};
|
||||||
|
use rocket::form::{ Form};
|
||||||
|
use rocket::fs::{relative, FileServer};
|
||||||
|
use rocket::response::{Flash, Redirect};
|
||||||
|
use rocket::{Build, Rocket};
|
||||||
|
use portfolio_core::{Mutation, Query};
|
||||||
|
|
||||||
|
use migration::MigratorTrait;
|
||||||
|
use sea_orm_rocket::{Connection, Database};
|
||||||
|
|
||||||
|
mod pool;
|
||||||
|
use pool::Db;
|
||||||
|
|
||||||
|
pub use entity::post;
|
||||||
|
pub use entity::post::Entity as Post;
|
||||||
|
|
||||||
|
|
||||||
|
#[post("/", data = "<post_form>")]
|
||||||
|
async fn create(conn: Connection<'_, Db>, post_form: Form<post::Model>) -> Flash<Redirect> {
|
||||||
|
let db = conn.into_inner();
|
||||||
|
|
||||||
|
let form = post_form.into_inner();
|
||||||
|
|
||||||
|
Mutation::create_post(db, form)
|
||||||
|
.await
|
||||||
|
.expect("could not insert post");
|
||||||
|
|
||||||
|
Flash::success(Redirect::to("/"), "Post successfully added.")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[post("/<id>", data = "<post_form>")]
|
||||||
|
async fn update(
|
||||||
|
conn: Connection<'_, Db>,
|
||||||
|
id: i32,
|
||||||
|
post_form: Form<post::Model>,
|
||||||
|
) -> Flash<Redirect> {
|
||||||
|
let db = conn.into_inner();
|
||||||
|
|
||||||
|
let form = post_form.into_inner();
|
||||||
|
|
||||||
|
Mutation::update_post_by_id(db, id, form)
|
||||||
|
.await
|
||||||
|
.expect("could not update post");
|
||||||
|
|
||||||
|
Flash::success(Redirect::to("/"), "Post successfully edited.")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[delete("/<id>")]
|
||||||
|
async fn delete(conn: Connection<'_, Db>, id: i32) -> Flash<Redirect> {
|
||||||
|
let db = conn.into_inner();
|
||||||
|
|
||||||
|
Mutation::delete_post(db, id)
|
||||||
|
.await
|
||||||
|
.expect("could not delete post");
|
||||||
|
|
||||||
|
Flash::success(Redirect::to("/"), "Post successfully deleted.")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[delete("/")]
|
||||||
|
async fn destroy(conn: Connection<'_, Db>) -> Result<(), rocket::response::Debug<String>> {
|
||||||
|
let db = conn.into_inner();
|
||||||
|
|
||||||
|
Mutation::delete_all_posts(db)
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run_migrations(rocket: Rocket<Build>) -> fairing::Result {
|
||||||
|
let conn = &Db::fetch(&rocket).unwrap().conn;
|
||||||
|
let _ = migration::Migrator::up(conn, None).await;
|
||||||
|
Ok(rocket)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn start() -> Result<(), rocket::Error> {
|
||||||
|
rocket::build()
|
||||||
|
.attach(Db::init())
|
||||||
|
.attach(AdHoc::try_on_ignite("Migrations", run_migrations))
|
||||||
|
//.mount("/", FileServer::from(relative!("/static")))
|
||||||
|
.mount("/", routes![create, delete, destroy, update])
|
||||||
|
.register("/", catchers![])
|
||||||
|
.launch()
|
||||||
|
.await
|
||||||
|
.map(|_| ())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
let result = start();
|
||||||
|
|
||||||
|
println!("Rocket: deorbit.");
|
||||||
|
|
||||||
|
if let Some(err) = result.err() {
|
||||||
|
println!("Error: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
41
api/src/pool.rs
Normal file
41
api/src/pool.rs
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
use portfolio_core::sea_orm;
|
||||||
|
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use sea_orm::ConnectOptions;
|
||||||
|
use sea_orm_rocket::{rocket::figment::Figment, Config, Database};
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
#[derive(Database, Debug)]
|
||||||
|
#[database("sea_orm")]
|
||||||
|
pub struct Db(SeaOrmPool);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct SeaOrmPool {
|
||||||
|
pub conn: sea_orm::DatabaseConnection,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl sea_orm_rocket::Pool for SeaOrmPool {
|
||||||
|
type Error = sea_orm::DbErr;
|
||||||
|
|
||||||
|
type Connection = sea_orm::DatabaseConnection;
|
||||||
|
|
||||||
|
async fn init(figment: &Figment) -> Result<Self, Self::Error> {
|
||||||
|
let config = figment.extract::<Config>().unwrap();
|
||||||
|
let mut options: ConnectOptions = config.url.into();
|
||||||
|
options
|
||||||
|
.max_connections(config.max_connections as u32)
|
||||||
|
.min_connections(config.min_connections.unwrap_or_default())
|
||||||
|
.connect_timeout(Duration::from_secs(config.connect_timeout));
|
||||||
|
if let Some(idle_timeout) = config.idle_timeout {
|
||||||
|
options.idle_timeout(Duration::from_secs(idle_timeout));
|
||||||
|
}
|
||||||
|
let conn = sea_orm::Database::connect(options).await?;
|
||||||
|
|
||||||
|
Ok(SeaOrmPool { conn })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn borrow(&self) -> &Self::Connection {
|
||||||
|
&self.conn
|
||||||
|
}
|
||||||
|
}
|
||||||
25
core/Cargo.toml
Normal file
25
core/Cargo.toml
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
[package]
|
||||||
|
name = "portfolio-core"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
portfolio-entity = { path = "../entity" }
|
||||||
|
|
||||||
|
[dependencies.sea-orm]
|
||||||
|
version = "^0.10.0"
|
||||||
|
features = [
|
||||||
|
"runtime-tokio-native-tls",
|
||||||
|
"sqlx-postgres",
|
||||||
|
"sqlx-sqlite",
|
||||||
|
]
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
tokio = "1.21.2"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
mock = ["sea-orm/mock"]
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "mock"
|
||||||
|
required-features = ["mock"]
|
||||||
7
core/src/lib.rs
Normal file
7
core/src/lib.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
mod mutation;
|
||||||
|
mod query;
|
||||||
|
|
||||||
|
pub use mutation::*;
|
||||||
|
pub use query::*;
|
||||||
|
|
||||||
|
pub use sea_orm;
|
||||||
53
core/src/mutation.rs
Normal file
53
core/src/mutation.rs
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
use ::entity::{post, post::Entity as Post};
|
||||||
|
use sea_orm::*;
|
||||||
|
|
||||||
|
pub struct Mutation;
|
||||||
|
|
||||||
|
impl Mutation {
|
||||||
|
pub async fn create_post(
|
||||||
|
db: &DbConn,
|
||||||
|
form_data: post::Model,
|
||||||
|
) -> Result<post::ActiveModel, DbErr> {
|
||||||
|
post::ActiveModel {
|
||||||
|
title: Set(form_data.title.to_owned()),
|
||||||
|
text: Set(form_data.text.to_owned()),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
.save(db)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn update_post_by_id(
|
||||||
|
db: &DbConn,
|
||||||
|
id: i32,
|
||||||
|
form_data: post::Model,
|
||||||
|
) -> Result<post::Model, DbErr> {
|
||||||
|
let post: post::ActiveModel = Post::find_by_id(id)
|
||||||
|
.one(db)
|
||||||
|
.await?
|
||||||
|
.ok_or(DbErr::Custom("Cannot find post.".to_owned()))
|
||||||
|
.map(Into::into)?;
|
||||||
|
|
||||||
|
post::ActiveModel {
|
||||||
|
id: post.id,
|
||||||
|
title: Set(form_data.title.to_owned()),
|
||||||
|
text: Set(form_data.text.to_owned()),
|
||||||
|
}
|
||||||
|
.update(db)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn delete_post(db: &DbConn, id: i32) -> Result<DeleteResult, DbErr> {
|
||||||
|
let post: post::ActiveModel = Post::find_by_id(id)
|
||||||
|
.one(db)
|
||||||
|
.await?
|
||||||
|
.ok_or(DbErr::Custom("Cannot find post.".to_owned()))
|
||||||
|
.map(Into::into)?;
|
||||||
|
|
||||||
|
post.delete(db).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn delete_all_posts(db: &DbConn) -> Result<DeleteResult, DbErr> {
|
||||||
|
Post::delete_many().exec(db).await
|
||||||
|
}
|
||||||
|
}
|
||||||
26
core/src/query.rs
Normal file
26
core/src/query.rs
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
use ::entity::{post, post::Entity as Post};
|
||||||
|
use sea_orm::*;
|
||||||
|
|
||||||
|
pub struct Query;
|
||||||
|
|
||||||
|
impl Query {
|
||||||
|
pub async fn find_post_by_id(db: &DbConn, id: i32) -> Result<Option<post::Model>, DbErr> {
|
||||||
|
Post::find_by_id(id).one(db).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If ok, returns (post models, num pages).
|
||||||
|
pub async fn find_posts_in_page(
|
||||||
|
db: &DbConn,
|
||||||
|
page: u64,
|
||||||
|
posts_per_page: u64,
|
||||||
|
) -> Result<(Vec<post::Model>, u64), DbErr> {
|
||||||
|
// Setup paginator
|
||||||
|
let paginator = Post::find()
|
||||||
|
.order_by_asc(post::Column::Id)
|
||||||
|
.paginate(db, posts_per_page);
|
||||||
|
let num_pages = paginator.num_pages().await?;
|
||||||
|
|
||||||
|
// Fetch paginated posts
|
||||||
|
paginator.fetch_page(page - 1).await.map(|p| (p, num_pages))
|
||||||
|
}
|
||||||
|
}
|
||||||
79
core/tests/mock.rs
Normal file
79
core/tests/mock.rs
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
mod prepare;
|
||||||
|
|
||||||
|
use entity::post;
|
||||||
|
use prepare::prepare_mock_db;
|
||||||
|
use rocket_example_core::{Mutation, Query};
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn main() {
|
||||||
|
let db = &prepare_mock_db();
|
||||||
|
|
||||||
|
{
|
||||||
|
let post = Query::find_post_by_id(db, 1).await.unwrap().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(post.id, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let post = Query::find_post_by_id(db, 5).await.unwrap().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(post.id, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let post = Mutation::create_post(
|
||||||
|
db,
|
||||||
|
post::Model {
|
||||||
|
id: 0,
|
||||||
|
title: "Title D".to_owned(),
|
||||||
|
text: "Text D".to_owned(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
post,
|
||||||
|
post::ActiveModel {
|
||||||
|
id: sea_orm::ActiveValue::Unchanged(6),
|
||||||
|
title: sea_orm::ActiveValue::Unchanged("Title D".to_owned()),
|
||||||
|
text: sea_orm::ActiveValue::Unchanged("Text D".to_owned())
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let post = Mutation::update_post_by_id(
|
||||||
|
db,
|
||||||
|
1,
|
||||||
|
post::Model {
|
||||||
|
id: 1,
|
||||||
|
title: "New Title A".to_owned(),
|
||||||
|
text: "New Text A".to_owned(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
post,
|
||||||
|
post::Model {
|
||||||
|
id: 1,
|
||||||
|
title: "New Title A".to_owned(),
|
||||||
|
text: "New Text A".to_owned(),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let result = Mutation::delete_post(db, 5).await.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(result.rows_affected, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let result = Mutation::delete_all_posts(db).await.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(result.rows_affected, 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
50
core/tests/prepare.rs
Normal file
50
core/tests/prepare.rs
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
use ::entity::post;
|
||||||
|
use sea_orm::*;
|
||||||
|
|
||||||
|
#[cfg(feature = "mock")]
|
||||||
|
pub fn prepare_mock_db() -> DatabaseConnection {
|
||||||
|
MockDatabase::new(DatabaseBackend::Postgres)
|
||||||
|
.append_query_results(vec![
|
||||||
|
vec![post::Model {
|
||||||
|
id: 1,
|
||||||
|
title: "Title A".to_owned(),
|
||||||
|
text: "Text A".to_owned(),
|
||||||
|
}],
|
||||||
|
vec![post::Model {
|
||||||
|
id: 5,
|
||||||
|
title: "Title C".to_owned(),
|
||||||
|
text: "Text C".to_owned(),
|
||||||
|
}],
|
||||||
|
vec![post::Model {
|
||||||
|
id: 6,
|
||||||
|
title: "Title D".to_owned(),
|
||||||
|
text: "Text D".to_owned(),
|
||||||
|
}],
|
||||||
|
vec![post::Model {
|
||||||
|
id: 1,
|
||||||
|
title: "Title A".to_owned(),
|
||||||
|
text: "Text A".to_owned(),
|
||||||
|
}],
|
||||||
|
vec![post::Model {
|
||||||
|
id: 1,
|
||||||
|
title: "New Title A".to_owned(),
|
||||||
|
text: "New Text A".to_owned(),
|
||||||
|
}],
|
||||||
|
vec![post::Model {
|
||||||
|
id: 5,
|
||||||
|
title: "Title C".to_owned(),
|
||||||
|
text: "Text C".to_owned(),
|
||||||
|
}],
|
||||||
|
])
|
||||||
|
.append_exec_results(vec![
|
||||||
|
MockExecResult {
|
||||||
|
last_insert_id: 6,
|
||||||
|
rows_affected: 1,
|
||||||
|
},
|
||||||
|
MockExecResult {
|
||||||
|
last_insert_id: 6,
|
||||||
|
rows_affected: 5,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
.into_connection()
|
||||||
|
}
|
||||||
17
entity/Cargo.toml
Normal file
17
entity/Cargo.toml
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
[package]
|
||||||
|
name = "portfolio-entity"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "entity"
|
||||||
|
path = "src/lib.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rocket = { version = "0.5.0-rc.2", features = [
|
||||||
|
"json",
|
||||||
|
] }
|
||||||
|
|
||||||
|
[dependencies.sea-orm]
|
||||||
|
version = "^0.10.0"
|
||||||
4
entity/src/lib.rs
Normal file
4
entity/src/lib.rs
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
#[macro_use]
|
||||||
|
extern crate rocket;
|
||||||
|
|
||||||
|
pub mod post;
|
||||||
18
entity/src/post.rs
Normal file
18
entity/src/post.rs
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
use rocket::serde::{Deserialize, Serialize};
|
||||||
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel, Deserialize, Serialize, FromForm)]
|
||||||
|
#[serde(crate = "rocket::serde")]
|
||||||
|
#[sea_orm(table_name = "posts")]
|
||||||
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
|
pub id: i32,
|
||||||
|
pub title: String,
|
||||||
|
#[sea_orm(column_type = "Text")]
|
||||||
|
pub text: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
|
pub enum Relation {}
|
||||||
|
|
||||||
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
17
migration/Cargo.toml
Normal file
17
migration/Cargo.toml
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
[package]
|
||||||
|
name = "portfolio-migration"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "migration"
|
||||||
|
path = "src/lib.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rocket = { version = "0.5.0-rc.2" }
|
||||||
|
async-std = { version = "^1", features = ["attributes", "tokio1"] }
|
||||||
|
|
||||||
|
[dependencies.sea-orm-migration]
|
||||||
|
version = "^0.10.0"
|
||||||
|
features = [ "runtime-tokio-native-tls", "sqlx-postgres", "sqlx-sqlite"]
|
||||||
37
migration/README.md
Normal file
37
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
|
||||||
|
```
|
||||||
10
migration/src/lib.rs
Normal file
10
migration/src/lib.rs
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
pub use sea_orm_migration::prelude::*;
|
||||||
|
|
||||||
|
pub struct Migrator;
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl MigratorTrait for Migrator {
|
||||||
|
fn migrations() -> Vec<Box<dyn MigrationTrait>> {
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
}
|
||||||
17
migration/src/main.rs
Normal file
17
migration/src/main.rs
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
use sea_orm_migration::prelude::*;
|
||||||
|
|
||||||
|
#[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(migration::Migrator).await;
|
||||||
|
}
|
||||||
3
src/main.rs
Normal file
3
src/main.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
fn main() {
|
||||||
|
portfolio_api::main();
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue