From 37feb713be701bf2bedd70f5cc9e6394d4447fe9 Mon Sep 17 00:00:00 2001 From: fluo10 Date: Sun, 25 May 2025 17:19:37 +0900 Subject: [PATCH] Add entities --- Cargo.toml | 11 ++++ lazy-supplements-migration/Cargo.toml | 11 +--- ...1_000001_create_lazy_supplements_tables.rs | 16 ++--- lazy-supplements/Cargo.toml | 10 ++- lazy-supplements/src/entity/mod.rs | 16 +++++ lazy-supplements/src/entity/node.rs | 61 +++++++++++++++++++ .../src/entity/record_deletion.rs | 54 ++++++++++++++++ lazy-supplements/src/error.rs | 2 + lazy-supplements/src/global/database.rs | 56 +++++++++++++++++ lazy-supplements/src/global/mod.rs | 14 +++++ lazy-supplements/src/lib.rs | 4 +- 11 files changed, 235 insertions(+), 20 deletions(-) create mode 100644 lazy-supplements/src/entity/mod.rs create mode 100644 lazy-supplements/src/entity/node.rs create mode 100644 lazy-supplements/src/entity/record_deletion.rs create mode 100644 lazy-supplements/src/global/database.rs create mode 100644 lazy-supplements/src/global/mod.rs diff --git a/Cargo.toml b/Cargo.toml index fc57abd..0d6f0d4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,4 +10,15 @@ repository = "https://forgejo.fireturlte.net" [workspace.dependencies] lazy-supplements.path = "lazy-supplements" +lazy-supplements-migration.path = "lazy-supplements-migration" libp2p = "0.55.0" + +[workspace.dependencies.sea-orm-migration] +version = "1.1.0" +features = [ + # Enable at least one `ASYNC_RUNTIME` and `DATABASE_DRIVER` feature if you want to run migration via CLI. + # View the list of supported features at https://www.sea-ql.org/SeaORM/docs/install-and-config/database-and-async-runtime. + # e.g. + "runtime-tokio-rustls", # `ASYNC_RUNTIME` feature + "sqlx-postgres", # `DATABASE_DRIVER` feature +] \ No newline at end of file diff --git a/lazy-supplements-migration/Cargo.toml b/lazy-supplements-migration/Cargo.toml index 1103839..4a22b40 100644 --- a/lazy-supplements-migration/Cargo.toml +++ b/lazy-supplements-migration/Cargo.toml @@ -6,13 +6,4 @@ publish = false [dependencies] async-std = { version = "1", features = ["attributes", "tokio1"] } - -[dependencies.sea-orm-migration] -version = "1.1.0" -features = [ - # Enable at least one `ASYNC_RUNTIME` and `DATABASE_DRIVER` feature if you want to run migration via CLI. - # View the list of supported features at https://www.sea-ql.org/SeaORM/docs/install-and-config/database-and-async-runtime. - # e.g. - "runtime-tokio-rustls", # `ASYNC_RUNTIME` feature - "sqlx-postgres", # `DATABASE_DRIVER` feature -] +sea-orm-migration.workspace = true diff --git a/lazy-supplements-migration/src/m20220101_000001_create_lazy_supplements_tables.rs b/lazy-supplements-migration/src/m20220101_000001_create_lazy_supplements_tables.rs index 0e00793..88794c8 100644 --- a/lazy-supplements-migration/src/m20220101_000001_create_lazy_supplements_tables.rs +++ b/lazy-supplements-migration/src/m20220101_000001_create_lazy_supplements_tables.rs @@ -8,41 +8,41 @@ pub struct Migration; #[async_trait::async_trait] impl MigrationTrait for Migration { async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { - Device::up(manager).await?; + Node::up(manager).await?; RecordDeletion::up(manager).await?; Ok(()) } async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { - Device::down(manager).await?; + Node::down(manager).await?; RecordDeletion::down(manager).await?; Ok(()) } } #[derive(DeriveIden)] -enum Device { +enum Node { Table, Id, CreatedAt, UpdatedAt, SyncedAt, - Name, + PeerId, Note, } #[async_trait::async_trait] -impl TableMigration for Device { +impl TableMigration for Node { async fn up<'a>(manager: &'a SchemaManager<'a>) -> Result<(), DbErr> { manager.create_table( Table::create() .table(Self::Table) .if_not_exists() .col(pk_uuid(Self::Id)) - .col(timestamp_with_time_zone(Self::CreatedAt)) + .col(timestamp(Self::CreatedAt)) .col(timestamp(Self::UpdatedAt)) - .col(timestamp_with_time_zone_null(Self::SyncedAt)) - .col(string(Self::Name)) + .col(timestamp_null(Self::SyncedAt)) + .col(string_len(Self::PeerId, 255)) .col(text(Self::Note)) .to_owned() ).await?; diff --git a/lazy-supplements/Cargo.toml b/lazy-supplements/Cargo.toml index 04cf1e1..42b2e63 100644 --- a/lazy-supplements/Cargo.toml +++ b/lazy-supplements/Cargo.toml @@ -8,10 +8,18 @@ repository.workspace = true [dependencies] base64 = "0.22.1" +chrono = "0.4.41" +chrono-tz = "0.10.3" clap = { version = "4.5.38", features = ["derive"] } libp2p.workspace = true -sea-orm = "1.1.11" +sea-orm = { version = "1.1.11", features = ["sqlx-sqlite", "runtime-tokio-native-tls", "macros", "with-chrono", "with-uuid"] } +sea-orm-migration.workspace = true serde = { version = "1.0.219", features = ["derive"] } +tempfile = "3.20.0" thiserror = "2.0.12" tokio = { version = "1.45.0", features = ["macros", "rt"] } toml = "0.8.22" +uuid = { version = "1.17.0", features = ["v4"] } + +[dev-dependencies] +lazy-supplements-migration.workspace = true diff --git a/lazy-supplements/src/entity/mod.rs b/lazy-supplements/src/entity/mod.rs new file mode 100644 index 0000000..5e38d96 --- /dev/null +++ b/lazy-supplements/src/entity/mod.rs @@ -0,0 +1,16 @@ +mod node; +mod record_deletion; + +pub use node::{ + ActiveModel as NodeActiveModel, + Column as NodeColumn, + Entity as NodeEntity, + Model as NodeModel, +}; + +pub use record_deletion::{ + ActiveModel as RecordDeletionActiveModel, + Column as RecordDeletionColumn, + Entity as RecordDeletionEntity, + Model as RecordDeletionModel, +}; diff --git a/lazy-supplements/src/entity/node.rs b/lazy-supplements/src/entity/node.rs new file mode 100644 index 0000000..78a6723 --- /dev/null +++ b/lazy-supplements/src/entity/node.rs @@ -0,0 +1,61 @@ +use chrono::Local; +use sea_orm::entity::{ + *, + prelude::* +}; +use serde::{Deserialize, Serialize}; + + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)] +#[sea_orm(table_name = "node")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false)] + pub id: Uuid, + #[sea_orm(indexed)] + pub created_at: DateTimeUtc, + #[sea_orm(indexed)] + pub updated_at: DateTimeUtc, + #[sea_orm(indexed)] + pub synced_at: Option, + #[sea_orm(indexed)] + pub peer_id: String, + #[sea_orm(column_type = "Text")] + pub note: String, +} + +#[derive(Copy, Clone, Debug, DeriveRelation, EnumIter)] +pub enum Relation {} + +impl ActiveModelBehavior for ActiveModel {} + +impl ActiveModel { + pub fn new() -> Self { + let timestamp: DateTimeUtc = Local::now().to_utc(); + Self{ + id: Set(Uuid::new_v4()), + created_at: Set(timestamp), + updated_at: Set(timestamp), + ..Default::default() + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use libp2p::identity; + use crate::global::GLOBAL; + + #[tokio::test] + async fn check_insert_node() { + let db = GLOBAL.get_or_init_temporary_database().await; + + ActiveModel{ + peer_id: Set(identity::Keypair::generate_ed25519().public().to_peer_id().to_string()), + note: Set("test note".to_owned()), + ..ActiveModel::new() + }.insert(db).await.unwrap(); + } + +} \ No newline at end of file diff --git a/lazy-supplements/src/entity/record_deletion.rs b/lazy-supplements/src/entity/record_deletion.rs new file mode 100644 index 0000000..ff0f6f2 --- /dev/null +++ b/lazy-supplements/src/entity/record_deletion.rs @@ -0,0 +1,54 @@ +use chrono::Local; +use sea_orm::entity::{ + *, + prelude::* +}; +use serde::{Deserialize, Serialize}; + + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)] +#[sea_orm(table_name = "record_deletion")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false)] + pub id: Uuid, + #[sea_orm(indexed)] + pub created_at: DateTimeUtc, + pub table_name: String, + pub record_id: Uuid, +} + +#[derive(Copy, Clone, Debug, DeriveRelation, EnumIter)] +pub enum Relation{} + +impl ActiveModelBehavior for ActiveModel {} + +impl ActiveModel { + pub fn new() -> Self { + let timestamp: DateTimeUtc = Local::now().to_utc(); + Self{ + id: Set(Uuid::new_v4()), + created_at: Set(timestamp), + ..Default::default() + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use uuid::Uuid; + use crate::global::GLOBAL; + + #[tokio::test] + async fn check_insert_record_deletion() { + let db = GLOBAL.get_or_init_temporary_database().await; + + assert!(ActiveModel{ + table_name: Set("test_table".to_string()), + record_id: Set(Uuid::new_v4()), + ..ActiveModel::new() + }.insert(db).await.is_ok()); + } + +} \ No newline at end of file diff --git a/lazy-supplements/src/error.rs b/lazy-supplements/src/error.rs index cca475f..b90cb94 100644 --- a/lazy-supplements/src/error.rs +++ b/lazy-supplements/src/error.rs @@ -1,5 +1,7 @@ #[derive(thiserror::Error, Debug)] pub enum Error { + #[error("DB Error: {0}")] + Db(#[from]sea_orm::DbErr), #[error("mandatory config `{0}` is missing")] MissingConfig(String), } \ No newline at end of file diff --git a/lazy-supplements/src/global/database.rs b/lazy-supplements/src/global/database.rs new file mode 100644 index 0000000..c6863d8 --- /dev/null +++ b/lazy-supplements/src/global/database.rs @@ -0,0 +1,56 @@ +use sea_orm::{ConnectOptions, Database, DatabaseConnection}; +use sea_orm_migration::MigratorTrait; +use crate::error::Error; +use tokio::sync::OnceCell; + +use super::Global; + +impl Global { + fn get_database(&self) -> Option<&DatabaseConnection> { + self.database.get() + } + async fn get_or_try_init_database(&self, options: T, _: U) -> Result<&DatabaseConnection, Error> + where + T: Into, + U: MigratorTrait, + { + Ok(self.database.get_or_try_init(|| async { + let db = Database::connect(options).await?; + U::up(&db, None).await?; + Ok::(db) + }).await?) + } +} + +#[cfg(test)] +pub mod tests { + use std::sync::LazyLock; + + use lazy_supplements_migration::Migrator; + + use crate::global::GLOBAL; + + use super::*; + + pub static TEST_DATABASE_URL: LazyLock = LazyLock::new(|| { + let mut temp_path = tempfile::NamedTempFile::new().unwrap().into_temp_path(); + temp_path.disable_cleanup(true); + let url = "sqlite://".to_string() + temp_path.as_os_str().to_str().unwrap() + "?mode=rwc"; + println!("{}", &url); + url + }); + + impl Global { + pub async fn get_or_init_temporary_database(&self) -> &DatabaseConnection { + + self.get_or_try_init_database(&*TEST_DATABASE_URL, Migrator).await.unwrap() + } + } + + #[tokio::test] + async fn connect_database () { + let db = GLOBAL.get_or_init_temporary_database().await; + assert!(db.ping().await.is_ok()); + } + +} \ No newline at end of file diff --git a/lazy-supplements/src/global/mod.rs b/lazy-supplements/src/global/mod.rs new file mode 100644 index 0000000..ba53e22 --- /dev/null +++ b/lazy-supplements/src/global/mod.rs @@ -0,0 +1,14 @@ +use crate::config::{ServerConfig}; +use sea_orm::DatabaseConnection; +use tokio::sync::OnceCell; + +mod database; + +pub static GLOBAL: Global = Global{ + server_config: OnceCell::const_new(), + database: OnceCell::const_new(), +}; +pub struct Global { + server_config: OnceCell, + database: OnceCell, +} diff --git a/lazy-supplements/src/lib.rs b/lazy-supplements/src/lib.rs index bb3cdbf..40013b6 100644 --- a/lazy-supplements/src/lib.rs +++ b/lazy-supplements/src/lib.rs @@ -1,3 +1,5 @@ pub mod cli; pub mod config; -pub mod error; \ No newline at end of file +pub mod entity; +pub mod error; +pub mod global; \ No newline at end of file