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:
Manuel Cillero 2022-03-12 01:39:08 +01:00
parent 76785af4dc
commit 619b7b73c6
15 changed files with 129 additions and 62 deletions

View file

@ -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"

View file

@ -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"] }

View 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>()
}

View file

@ -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())
}
}

View 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>()
}

View file

@ -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 {

View file

@ -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.
// -----------------------------------------------------------------------------

View file

@ -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
}
}

View file

@ -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()

View file

@ -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)
});

View file

@ -4,7 +4,5 @@ pub use actix_web::{
mod tracing;
mod dbconn;
mod app;
pub use app::Application;

View file

@ -1 +0,0 @@
pub use sea_orm::DatabaseConnection;

17
src/db.rs Normal file
View 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;

View file

@ -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.

View file

@ -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::*;