Elimina Refinery y Barrel en favor de SeaORM

Se integran las funcionalidades de SeaORM en el funcionamiento de
PageTop para abstraer el uso y acceso a la base de datos.
This commit is contained in:
Manuel Cillero 2022-03-13 00:19:05 +01:00
parent 619b7b73c6
commit 4b5d8ce38a
16 changed files with 150 additions and 98 deletions

View file

@ -25,8 +25,11 @@ categories = [
[dependencies] [dependencies]
doc-comment = "0.3.3" doc-comment = "0.3.3"
once_cell = "1.9.0" downcast-rs = "1.2.0"
figlet-rs = "0.1.3" figlet-rs = "0.1.3"
futures = "0.3"
once_cell = "1.9.0"
url = "2.2.2"
config_rs = { package = "config", version = "0.11.0", features = ["toml"] } config_rs = { package = "config", version = "0.11.0", features = ["toml"] }
@ -44,26 +47,22 @@ actix-web-static-files = "3.0.5"
maud = { version = "0.23.0", features = ["actix-web"] } maud = { version = "0.23.0", features = ["actix-web"] }
sycamore = { version = "0.7.1", features = ["ssr"] } sycamore = { version = "0.7.1", features = ["ssr"] }
downcast-rs = "1.2.0"
url = "2.2.2"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
[dependencies.sqlx] [dependencies.sea-orm]
version = "0.5.11" version = "0.6"
features = ["migrate", "runtime-async-std-native-tls"] features = ["debug-print", "macros", "runtime-async-std-native-tls"]
default-features = false default-features = false
[dependencies.refinery] [dependencies.sea-schema]
version = "0.8.4" version = "0.5"
features = ["debug-print", "migration"]
[dependencies.barrel] default-features = false
version = "0.7.0"
[features] [features]
default = ["mysql"] default = ["mysql"]
mysql = ["sqlx/mysql", "refinery/mysql", "barrel/mysql"] mysql = ["sea-orm/sqlx-mysql"]
postgres = ["sqlx/postgres", "refinery/postgres", "barrel/pg"] postgres = ["sea-orm/sqlx-postgres"]
[build-dependencies] [build-dependencies]
actix-web-static-files = "3.0.5" actix-web-static-files = "3.0.5"

View file

@ -1,13 +0,0 @@
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,7 +1,6 @@
use crate::prelude::*; use crate::prelude::*;
localize!("en-US", "src/base/module/admin/locales"); localize!("en-US", "src/base/module/admin/locales");
embed_migrations!("src/base/module/admin/migrations");
mod summary; mod summary;
@ -26,8 +25,4 @@ impl Module for AdminModule {
.route("", server::web::get().to(summary::summary)) .route("", server::web::get().to(summary::summary))
); );
} }
fn configure_migrations(&self) -> Option<db::Migrations> {
Some(migrations::runner())
}
} }

View file

@ -0,0 +1 @@
pub mod user;

View file

@ -0,0 +1,18 @@
use crate::db::entity::*;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Deserialize, Serialize)]
#[sea_orm(table_name = "user")]
pub struct Model {
#[sea_orm(primary_key)]
#[serde(skip_deserializing)]
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 {}

View file

@ -0,0 +1,54 @@
use crate::db::migration::*;
#[derive(Iden)]
enum User {
Table,
Id,
Title,
Text,
}
pub struct Migration;
impl MigrationName for Migration {
fn name(&self) -> &str {
"m20220312_000001_create_table_user"
}
}
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table(
Table::create()
.table(User::Table)
.if_not_exists()
.col(ColumnDef::new(User::Id)
.integer()
.not_null()
.auto_increment()
.primary_key(),
)
.col(ColumnDef::new(User::Title)
.string()
.not_null()
)
.col(ColumnDef::new(User::Text)
.string()
.not_null()
)
.to_owned()
)
.await
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.drop_table(Table::drop()
.table(User::Table)
.to_owned()
)
.await
}
}

View file

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

View file

@ -1,13 +0,0 @@
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,7 +1,9 @@
use crate::prelude::*; use crate::prelude::*;
localize!("en-US", "src/base/module/user/locales"); localize!("en-US", "src/base/module/user/locales");
embed_migrations!("src/base/module/user/migrations");
mod entity;
mod migration;
pub struct UserModule; pub struct UserModule;
@ -22,8 +24,8 @@ impl Module for UserModule {
cfg.route("/user/login", server::web::get().to(login)); cfg.route("/user/login", server::web::get().to(login));
} }
fn configure_migrations(&self) -> Option<db::Migrations> { fn migrations(&self, dbconn: &db::DbConn) -> Result<(), db::DbErr> {
Some(migrations::runner()) db_migrations!(dbconn)
} }
} }

View file

@ -42,15 +42,9 @@ pub fn modules(cfg: &mut server::web::ServiceConfig) {
} }
} }
pub fn migrations(db_uri: db::Uri) { pub fn migrations(dbconn: &db::DbConn) {
let mut conn = refinery::config::Config::try_from(db_uri).unwrap();
for m in MODULES.read().unwrap().iter() { for m in MODULES.read().unwrap().iter() {
match m.configure_migrations() { m.migrations(dbconn).expect("Failed to run migrations");
Some(migrations) => {
migrations.run(&mut conn).expect("Failed to run migrations");
},
_ => {}
};
} }
} }

View file

@ -15,7 +15,8 @@ pub trait Module: Send + Sync {
fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { fn configure_module(&self, cfg: &mut server::web::ServiceConfig) {
} }
fn configure_migrations(&self) -> Option<db::Migrations> { #[allow(unused_variables)]
None fn migrations(&self, dbconn: &db::DbConn) -> Result<(), db::DbErr> {
Ok(())
} }
} }

View file

@ -5,19 +5,8 @@ use crate::core::theme::register_theme;
use crate::core::module::register_module; use crate::core::module::register_module;
use std::io::Error; use std::io::Error;
use std::sync::RwLock;
use actix_web::middleware::normalize::{NormalizePath, TrailingSlash}; 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 { pub struct Application {
server: Server, server: Server,
} }
@ -70,7 +59,7 @@ impl Application {
let db_type = "postgres"; let db_type = "postgres";
// https://github.com/launchbadge/sqlx/issues/1624 // https://github.com/launchbadge/sqlx/issues/1624
let mut db_uri = db::Uri::parse(format!( let mut db_uri = db::DbUri::parse(format!(
"{}://{}/{}", "{}://{}/{}",
db_type, db_type,
&SETTINGS.database.db_host, &SETTINGS.database.db_host,
@ -82,15 +71,15 @@ impl Application {
db_uri.set_port(Some(SETTINGS.database.db_port)).unwrap(); db_uri.set_port(Some(SETTINGS.database.db_port)).unwrap();
} }
let db_pool = DbPoolOptions::new() let mut db_options = sea_orm::ConnectOptions::new(db_uri.to_string());
.max_connections(SETTINGS.database.max_pool_size) db_options.max_connections(SETTINGS.database.max_pool_size);
.connect(db_uri.as_str())
let dbconn = sea_orm::Database::connect::<sea_orm::ConnectOptions>(
db_options.into()
)
.await .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. // Registra los temas predefinidos.
register_theme(&base::theme::aliner::AlinerTheme); register_theme(&base::theme::aliner::AlinerTheme);
register_theme(&base::theme::minimal::MinimalTheme); register_theme(&base::theme::minimal::MinimalTheme);
@ -112,13 +101,14 @@ impl Application {
// Run migrations. // Run migrations.
trace::info!("Running migrations."); trace::info!("Running migrations.");
global::migrations(db_uri); global::migrations(&dbconn);
// Prepara el servidor web. // Prepara el servidor web.
let server = server::HttpServer::new(|| { let server = server::HttpServer::new(move || {
server::App::new() server::App::new()
.wrap(tracing_actix_web::TracingLogger) .wrap(tracing_actix_web::TracingLogger)
.wrap(NormalizePath::new(TrailingSlash::Trim)) .wrap(NormalizePath::new(TrailingSlash::Trim))
.data(dbconn.clone())
.configure(&global::themes) .configure(&global::themes)
.configure(&global::modules) .configure(&global::modules)
}) })

View file

@ -1,17 +1,14 @@
pub use url::Url as Uri; pub use url::Url as DbUri;
#[cfg(feature = "mysql")] pub use sea_orm::{
pub use { DbErr,
barrel::backend::MySql as Database, DatabaseConnection as DbConn,
sqlx::MySqlPool as Conn,
}; };
#[cfg(feature = "postgres")] pub mod entity {
pub use { pub use sea_orm::entity::prelude::*;
barrel::backend::Pg as Database, }
sqlx::PgPool as Conn,
};
pub use barrel::{Migration, types}; pub mod migration {
pub use refinery::embed_migrations; pub use sea_schema::migration::prelude::*;
pub use refinery::Runner as Migrations; }

View file

@ -2,6 +2,7 @@
pub use doc_comment::doc_comment; pub use doc_comment::doc_comment;
pub use once_cell::sync::Lazy; pub use once_cell::sync::Lazy;
pub use futures::executor::block_on as run_now;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// APIs públicas. // APIs públicas.

View file

@ -1,14 +1,15 @@
//! Re-exporta recursos comunes. //! Re-exporta recursos comunes.
pub use crate::args; pub use crate::{
pub use crate::util; args,
db_migrations,
};
pub use crate::config::SETTINGS; pub use crate::config::SETTINGS;
pub use crate::trace; pub use crate::trace;
pub use crate::localize; pub use crate::localize;
pub use crate::db; pub use crate::db;
pub use crate::db::embed_migrations;
pub use crate::core::theme::*; pub use crate::core::theme::*;
pub use crate::core::module::*; pub use crate::core::module::*;
@ -16,3 +17,5 @@ pub use crate::core::response::page::*;
pub use crate::core::server; pub use crate::core::server;
pub use crate::base::component::*; pub use crate::base::component::*;
pub use crate::util;

View file

@ -9,15 +9,26 @@
/// ]; /// ];
/// ``` /// ```
macro_rules! args { macro_rules! args {
( $($key:expr => $value:expr),* ) => {{ ( $($KEY:expr => $VALUE:expr),* ) => {{
let mut a = std::collections::HashMap::new(); let mut a = std::collections::HashMap::new();
$( $(
a.insert(String::from($key), $value.into()); a.insert(String::from($KEY), $VALUE.into());
)* )*
a a
}}; }};
} }
#[macro_export]
macro_rules! db_migrations {
( $DBCONN:ident ) => {{
$crate::run_now({
use $crate::db::migration::MigratorTrait;
migration::Migrator::up($DBCONN, None)
})
}};
}
pub fn valid_id(id: &str) -> Option<String> { pub fn valid_id(id: &str) -> Option<String> {
let id = id.trim().replace(" ", "_").to_lowercase(); let id = id.trim().replace(" ", "_").to_lowercase();
match id.is_empty() { match id.is_empty() {