Añade migración de BD usando Refinery y Barrel
Realmente esta funcionalidad se va a sustituir por alguna otra librería ya que Refinery usa un único número de versión que dificulta su uso en un contexto de módulos independientes con migraciones propias.
This commit is contained in:
parent
76785af4dc
commit
619b7b73c6
15 changed files with 129 additions and 62 deletions
26
Cargo.toml
26
Cargo.toml
|
|
@ -29,7 +29,6 @@ once_cell = "1.9.0"
|
|||
figlet-rs = "0.1.3"
|
||||
|
||||
config_rs = { package = "config", version = "0.11.0", features = ["toml"] }
|
||||
url = "2.2.2"
|
||||
|
||||
tracing = "0.1"
|
||||
tracing-appender = "0.2"
|
||||
|
|
@ -44,24 +43,31 @@ actix-web-static-files = "3.0.5"
|
|||
|
||||
maud = { version = "0.23.0", features = ["actix-web"] }
|
||||
sycamore = { version = "0.7.1", features = ["ssr"] }
|
||||
|
||||
downcast-rs = "1.2.0"
|
||||
url = "2.2.2"
|
||||
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
||||
[dependencies.sea-orm]
|
||||
version = "0.6"
|
||||
features = ["macros", "debug-print", "runtime-async-std-native-tls"]
|
||||
[dependencies.sqlx]
|
||||
version = "0.5.11"
|
||||
features = ["migrate", "runtime-async-std-native-tls"]
|
||||
default-features = false
|
||||
|
||||
[dependencies.refinery]
|
||||
version = "0.8.4"
|
||||
|
||||
[dependencies.barrel]
|
||||
version = "0.7.0"
|
||||
|
||||
[features]
|
||||
default = ["mysql"]
|
||||
mysql = ["sqlx/mysql", "refinery/mysql", "barrel/mysql"]
|
||||
postgres = ["sqlx/postgres", "refinery/postgres", "barrel/pg"]
|
||||
|
||||
[build-dependencies]
|
||||
actix-web-static-files = "3.0.5"
|
||||
|
||||
[features]
|
||||
default = ["sea-orm/sqlx-mysql"]
|
||||
mysql = ["sea-orm/sqlx-mysql"]
|
||||
postgres = ["sea-orm/sqlx-postgres"]
|
||||
sqlite = ["sea-orm/sqlx-sqlite"]
|
||||
|
||||
[lib]
|
||||
name = "pagetop"
|
||||
|
||||
|
|
|
|||
|
|
@ -10,3 +10,4 @@ edition = "2021"
|
|||
pagetop = { path = "pagetop" }
|
||||
actix-web = "3.3.3"
|
||||
maud = { version = "0.23.0" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
|
|
|||
13
src/base/module/admin/migrations/V1__create_table_system.rs
Normal file
13
src/base/module/admin/migrations/V1__create_table_system.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
use crate::prelude::*;
|
||||
|
||||
pub fn migration() -> String {
|
||||
let mut m = db::Migration::new();
|
||||
|
||||
m.create_table("system", |t| {
|
||||
t.add_column("id", db::types::primary());
|
||||
t.add_column("title", db::types::varchar(255));
|
||||
t.add_column("is_completed", db::types::boolean().default(false));
|
||||
});
|
||||
|
||||
m.make::<db::Database>()
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
use crate::prelude::*;
|
||||
|
||||
localize!("en-US", "src/base/module/admin/locales");
|
||||
embed_migrations!("src/base/module/admin/migrations");
|
||||
|
||||
mod summary;
|
||||
|
||||
|
|
@ -25,4 +26,8 @@ impl Module for AdminModule {
|
|||
.route("", server::web::get().to(summary::summary))
|
||||
);
|
||||
}
|
||||
|
||||
fn configure_migrations(&self) -> Option<db::Migrations> {
|
||||
Some(migrations::runner())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
13
src/base/module/user/migrations/V1__create_table_user.rs
Normal file
13
src/base/module/user/migrations/V1__create_table_user.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
use crate::prelude::*;
|
||||
|
||||
pub fn migration() -> String {
|
||||
let mut m = db::Migration::new();
|
||||
|
||||
m.create_table("user", |t| {
|
||||
t.add_column("id", db::types::primary());
|
||||
t.add_column("title", db::types::varchar(255));
|
||||
t.add_column("is_completed", db::types::boolean().default(false));
|
||||
});
|
||||
|
||||
m.make::<db::Database>()
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
use crate::prelude::*;
|
||||
|
||||
localize!("en-US", "src/base/module/user/locales");
|
||||
embed_migrations!("src/base/module/user/migrations");
|
||||
|
||||
pub struct UserModule;
|
||||
|
||||
|
|
@ -20,6 +21,10 @@ impl Module for UserModule {
|
|||
fn configure_module(&self, cfg: &mut server::web::ServiceConfig) {
|
||||
cfg.route("/user/login", server::web::get().to(login));
|
||||
}
|
||||
|
||||
fn configure_migrations(&self) -> Option<db::Migrations> {
|
||||
Some(migrations::runner())
|
||||
}
|
||||
}
|
||||
|
||||
fn form_login() -> impl PageComponent {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::Lazy;
|
||||
use crate::{Lazy, db};
|
||||
use crate::core::theme::Theme;
|
||||
use crate::core::module::Module;
|
||||
use crate::core::response::page::PageContainer;
|
||||
|
|
@ -42,6 +42,18 @@ pub fn modules(cfg: &mut server::web::ServiceConfig) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn migrations(db_uri: db::Uri) {
|
||||
let mut conn = refinery::config::Config::try_from(db_uri).unwrap();
|
||||
for m in MODULES.read().unwrap().iter() {
|
||||
match m.configure_migrations() {
|
||||
Some(migrations) => {
|
||||
migrations.run(&mut conn).expect("Failed to run migrations");
|
||||
},
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Componentes globales.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use crate::db;
|
||||
use crate::core::server;
|
||||
|
||||
/// Los módulos deben implementar este *trait*.
|
||||
|
|
@ -13,4 +14,8 @@ pub trait Module: Send + Sync {
|
|||
#[allow(unused_variables)]
|
||||
fn configure_module(&self, cfg: &mut server::web::ServiceConfig) {
|
||||
}
|
||||
|
||||
fn configure_migrations(&self) -> Option<db::Migrations> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,23 @@
|
|||
use crate::{Lazy, base, locale, trace};
|
||||
use crate::{Lazy, base, db, locale, trace};
|
||||
use crate::config::SETTINGS;
|
||||
use crate::core::{Server, global, server};
|
||||
use crate::core::theme::register_theme;
|
||||
use crate::core::module::register_module;
|
||||
|
||||
use std::io::Error;
|
||||
use std::sync::RwLock;
|
||||
use actix_web::middleware::normalize::{NormalizePath, TrailingSlash};
|
||||
|
||||
#[cfg(feature = "mysql")]
|
||||
use sqlx::mysql::MySqlPoolOptions as DbPoolOptions;
|
||||
|
||||
#[cfg(feature = "postgres")]
|
||||
use sqlx::postgres::PgPoolOptions as DbPoolOptions;
|
||||
|
||||
static DBCONN: Lazy<RwLock<Option<db::Conn>>> = Lazy::new(|| {
|
||||
RwLock::new(None)
|
||||
});
|
||||
|
||||
pub struct Application {
|
||||
server: Server,
|
||||
}
|
||||
|
|
@ -52,49 +63,33 @@ impl Application {
|
|||
&SETTINGS.database.max_pool_size
|
||||
);
|
||||
|
||||
#[cfg(any(feature = "default", feature = "mysql"))]
|
||||
let db_uri = format!(
|
||||
"mysql://{}/{}",
|
||||
&SETTINGS.database.db_host,
|
||||
&SETTINGS.database.db_name
|
||||
);
|
||||
#[cfg(feature = "mysql")]
|
||||
let db_type = "mysql";
|
||||
|
||||
#[cfg(feature = "postgres")]
|
||||
let db_uri = format!(
|
||||
"postgres://{}/{}",
|
||||
&SETTINGS.database.db_host,
|
||||
&SETTINGS.database.db_name
|
||||
);
|
||||
|
||||
#[cfg(feature = "sqlite")]
|
||||
let db_uri = format!("sqlite://{}", &SETTINGS.database.db_name);
|
||||
|
||||
let mut uri = url::Url::parse(&db_uri).unwrap();
|
||||
let db_type = "postgres";
|
||||
|
||||
// https://github.com/launchbadge/sqlx/issues/1624
|
||||
|
||||
#[cfg(not(feature = "sqlite"))]
|
||||
uri.set_username(&SETTINGS.database.db_user.as_str()).unwrap();
|
||||
|
||||
#[cfg(not(feature = "sqlite"))]
|
||||
uri.set_password(Some(&SETTINGS.database.db_pass.as_str())).unwrap();
|
||||
|
||||
#[cfg(not(feature = "sqlite"))]
|
||||
let mut db_uri = db::Uri::parse(format!(
|
||||
"{}://{}/{}",
|
||||
db_type,
|
||||
&SETTINGS.database.db_host,
|
||||
&SETTINGS.database.db_name
|
||||
).as_str()).unwrap();
|
||||
db_uri.set_username(&SETTINGS.database.db_user.as_str()).unwrap();
|
||||
db_uri.set_password(Some(&SETTINGS.database.db_pass.as_str())).unwrap();
|
||||
if SETTINGS.database.db_port != 0 {
|
||||
uri.set_port(Some(SETTINGS.database.db_port)).unwrap();
|
||||
db_uri.set_port(Some(SETTINGS.database.db_port)).unwrap();
|
||||
}
|
||||
|
||||
let mut db_options = sea_orm::ConnectOptions::new(uri.to_string());
|
||||
db_options.max_connections(SETTINGS.database.max_pool_size);
|
||||
|
||||
let mut db_conn = server::dbconn::DBCONN.write().unwrap();
|
||||
*db_conn = Some(
|
||||
sea_orm::Database::connect::<sea_orm::ConnectOptions>(
|
||||
db_options.into()
|
||||
)
|
||||
let db_pool = DbPoolOptions::new()
|
||||
.max_connections(SETTINGS.database.max_pool_size)
|
||||
.connect(db_uri.as_str())
|
||||
.await
|
||||
.expect("Failed to connect to database")
|
||||
);
|
||||
.expect("Failed to connect to database");
|
||||
|
||||
let mut dbconn = DBCONN.write().unwrap();
|
||||
*dbconn = Some(db_pool);
|
||||
|
||||
// Registra los temas predefinidos.
|
||||
register_theme(&base::theme::aliner::AlinerTheme);
|
||||
|
|
@ -107,7 +102,7 @@ impl Application {
|
|||
|
||||
// Ejecuta la función de inicio de la aplicación.
|
||||
if bootstrap != None {
|
||||
trace::debug!("Calling application bootstrap");
|
||||
trace::info!("Calling application bootstrap.");
|
||||
let _ = &(bootstrap.unwrap())();
|
||||
}
|
||||
|
||||
|
|
@ -115,6 +110,10 @@ impl Application {
|
|||
// Al ser el último, puede sobrecargarse con la función de inicio.
|
||||
register_module(&base::module::homepage::HomepageModule);
|
||||
|
||||
// Run migrations.
|
||||
trace::info!("Running migrations.");
|
||||
global::migrations(db_uri);
|
||||
|
||||
// Prepara el servidor web.
|
||||
let server = server::HttpServer::new(|| {
|
||||
server::App::new()
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
use crate::Lazy;
|
||||
use crate::database::DatabaseConnection;
|
||||
|
||||
use std::sync::RwLock;
|
||||
|
||||
pub static DBCONN: Lazy<RwLock<Option<DatabaseConnection>>> = Lazy::new(|| {
|
||||
RwLock::new(None)
|
||||
});
|
||||
|
|
@ -4,7 +4,5 @@ pub use actix_web::{
|
|||
|
||||
mod tracing;
|
||||
|
||||
mod dbconn;
|
||||
|
||||
mod app;
|
||||
pub use app::Application;
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
pub use sea_orm::DatabaseConnection;
|
||||
17
src/db.rs
Normal file
17
src/db.rs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
pub use url::Url as Uri;
|
||||
|
||||
#[cfg(feature = "mysql")]
|
||||
pub use {
|
||||
barrel::backend::MySql as Database,
|
||||
sqlx::MySqlPool as Conn,
|
||||
};
|
||||
|
||||
#[cfg(feature = "postgres")]
|
||||
pub use {
|
||||
barrel::backend::Pg as Database,
|
||||
sqlx::PgPool as Conn,
|
||||
};
|
||||
|
||||
pub use barrel::{Migration, types};
|
||||
pub use refinery::embed_migrations;
|
||||
pub use refinery::Runner as Migrations;
|
||||
|
|
@ -10,8 +10,8 @@ pub use once_cell::sync::Lazy;
|
|||
pub mod config; // Gestión de la configuración.
|
||||
pub mod trace; // Registro de trazas y eventos de la aplicación.
|
||||
pub mod locale; // Localización.
|
||||
pub mod database; // Acceso a la base de datos.
|
||||
pub mod core; // Servidor web y sistemas para Temas, Módulos y Respuestas.
|
||||
pub mod db; // Acceso a la base de datos.
|
||||
pub mod core; // Servidor web y APIs para Temas, Módulos y Respuestas web.
|
||||
pub mod base; // Temas, Módulos y Componentes base.
|
||||
pub mod util; // Macros y funciones útiles.
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@ pub use crate::util;
|
|||
pub use crate::config::SETTINGS;
|
||||
pub use crate::trace;
|
||||
pub use crate::localize;
|
||||
pub use crate::database;
|
||||
|
||||
pub use crate::db;
|
||||
pub use crate::db::embed_migrations;
|
||||
|
||||
pub use crate::core::theme::*;
|
||||
pub use crate::core::module::*;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue