Compare commits

...

2 commits

Author SHA1 Message Date
d93d3a83d1 Update examples 2025-05-27 17:58:32 +09:00
93170f4cb1 Update database initialization 2025-05-27 17:49:52 +09:00
22 changed files with 252 additions and 43 deletions

View file

@ -1,5 +1,5 @@
[workspace]
members = [ "examples/timestamper", "lazy-supplements", "lazy-supplements-*" ]
members = [ "examples/*", "lazy-supplements", "lazy-supplements-*" ]
[workspace.package]
edition = "2024"

View file

@ -0,0 +1,20 @@
[package]
name = "simple-list"
edition.workspace = true
version.workspace = true
description.workspace = true
license.workspace = true
repository.workspace = true
[dependencies]
chrono = "0.4.41"
clap = { version = "4.5.38", features = ["derive"] }
lazy-supplements.workspace = true
lazy-supplements-migration.workspace = true
sea-orm = "1.1.11"
sea-orm-migration.workspace = true
serde = { version = "1.0.219", features = ["derive"] }
tokio = "1.45.1"
[dev-dependencies]
lazy-supplements = { workspace = true, features = [ "test" ] }

View file

View file

View file

View file

@ -0,0 +1,16 @@
use clap::{Parser, Subcommand};
use lazy_supplements::{cli::ServerArgs, config::PartialServerConfig};
#[derive(Debug, Parser)]
pub struct Cli {
#[command(subcommand)]
command: CliCommand
}
#[derive(Debug, Subcommand)]
pub enum CliCommand {
Add,
Delete,
List,
Server(ServerArgs)
}

View file

View file

@ -0,0 +1,58 @@
use chrono::Local;
use sea_orm::entity::{
*,
prelude::*
};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
#[sea_orm(table_name = "list_item")]
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 is_trashed: bool,
#[sea_orm(indexed)]
pub content: 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),
is_trashed: Set(false),
..Default::default()
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::global::GLOBAL;
#[tokio::test]
async fn check_insert_node() {
let db = crate::tests::get_or_init_temporary_database().await;
ActiveModel{
content: Set("test note".to_owned()),
..ActiveModel::new()
}.insert(db).await.unwrap();
}
}

View file

@ -0,0 +1,10 @@
mod list_item;
pub use lazy_supplements::entity::*;
pub use list_item::{
ActiveModel as ListItemActiveModel,
Column as ListItemColumn,
Entity as ListItemEntity,
Model as ListItemModel,
};

View file

@ -0,0 +1,28 @@
use clap::Parser;
mod migration;
mod cli;
mod entity;
pub use lazy_supplements::error;
pub use lazy_supplements::global;
#[cfg(test)]
pub mod tests {
use sea_orm::DatabaseConnection;
use sea_orm_migration::MigratorTrait;
use super::*;
pub async fn get_or_init_temporary_database() -> &'static DatabaseConnection {
global::GLOBAL.get_or_try_init_temporary_database( |x| async {
migration::Migrator::up(&x, None).await?;
Ok(x)
}).await.unwrap()
}
}
#[tokio::main]
async fn main() {
let args = cli::Cli::parse();
println!("{:?}", args);
}

View file

@ -0,0 +1,50 @@
use sea_orm_migration::{prelude::*, schema::*};
use lazy_supplements_migration::TableMigration;
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
ListItem::up(manager).await?;
Ok(())
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
ListItem::down(manager).await?;
Ok(())
}
}
#[derive(DeriveIden)]
enum ListItem {
Table,
Id,
CreatedAt,
UpdatedAt,
IsTrashed,
Content,
}
#[async_trait::async_trait]
impl TableMigration for ListItem {
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(Self::CreatedAt))
.col(timestamp(Self::UpdatedAt))
.col(boolean(Self::IsTrashed))
.col(string_len(Self::Content, 255))
.to_owned()
).await?;
Ok(())
}
async fn down<'a>(manager: &'a SchemaManager<'a>) -> Result<(), DbErr>{
manager.drop_table(Table::drop().table(Self::Table).to_owned()).await
}
}

View file

@ -0,0 +1,15 @@
use sea_orm_migration::{prelude::*, schema::*};
use lazy_supplements_migration::m20220101_000001_create_lazy_supplements_tables;
mod m20220101_000002_create_simple_list_tables;
pub struct Migrator;
#[async_trait::async_trait]
impl MigratorTrait for Migrator {
fn migrations() -> Vec<Box<dyn MigrationTrait>> {
vec![
Box::new(m20220101_000002_create_simple_list_tables::Migration),
Box::new(m20220101_000001_create_lazy_supplements_tables::Migration)
]
}
}

View file

@ -1,10 +0,0 @@
[package]
name = "timestamper"
edition.workspace = true
version.workspace = true
description.workspace = true
license.workspace = true
repository.workspace = true
[dependencies]
lazy-supplements.workspace = true

View file

@ -1,3 +0,0 @@
fn main() {
println!("Hello, world!");
}

View file

@ -1,6 +1,6 @@
use sea_orm_migration::{prelude::*, schema::*};
mod m20220101_000001_create_lazy_supplements_tables;
pub mod m20220101_000001_create_lazy_supplements_tables;
pub struct Migrator;

View file

@ -6,6 +6,10 @@ description.workspace = true
license.workspace = true
repository.workspace = true
[features]
default = []
test = ["dep:tempfile"]
[dependencies]
base64 = "0.22.1"
chrono = "0.4.41"
@ -13,9 +17,8 @@ chrono-tz = "0.10.3"
clap = { version = "4.5.38", features = ["derive"] }
libp2p.workspace = true
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"
tempfile = { version = "3.20.0", optional = true }
thiserror = "2.0.12"
tokio = { version = "1.45.0", features = ["macros", "rt"] }
toml = "0.8.22"
@ -23,3 +26,5 @@ uuid = { version = "1.17.0", features = ["v4"] }
[dev-dependencies]
lazy-supplements-migration.workspace = true
sea-orm-migration.workspace = true
tempfile = "3.20.0"

View file

@ -4,6 +4,8 @@ mod connect;
mod init;
mod server;
pub use server::ServerArgs;
pub fn default_config_path() -> PathBuf {
todo!()
}

View file

@ -49,7 +49,7 @@ mod tests {
#[tokio::test]
async fn check_insert_node() {
let db = GLOBAL.get_or_init_temporary_database().await;
let db = crate::global::get_or_init_temporary_database().await;
ActiveModel{
peer_id: Set(identity::Keypair::generate_ed25519().public().to_peer_id().to_string()),

View file

@ -38,11 +38,11 @@ mod tests {
use super::*;
use uuid::Uuid;
use crate::global::GLOBAL;
use crate::global::get_or_init_temporary_database;
#[tokio::test]
async fn check_insert_record_deletion() {
let db = GLOBAL.get_or_init_temporary_database().await;
let db = get_or_init_temporary_database().await;
assert!(ActiveModel{
table_name: Set("test_table".to_string()),

View file

@ -1,55 +1,70 @@
use sea_orm::{ConnectOptions, Database, DatabaseConnection};
use sea_orm_migration::MigratorTrait;
use std::path::Path;
use sea_orm::{ConnectOptions, Database, DbErr, DatabaseConnection};
use crate::error::Error;
use tokio::sync::OnceCell;
use super::Global;
#[cfg(any(test, feature="test"))]
pub static TEST_DATABASE_URL: std::sync::LazyLock<tempfile::TempPath> = std::sync::LazyLock::new(|| {
let mut temp_path = tempfile::NamedTempFile::new().unwrap().into_temp_path();
temp_path.disable_cleanup(true);
println!("{}", temp_path.as_os_str().to_str().unwrap());
temp_path
});
impl Global {
fn get_database(&self) -> Option<&DatabaseConnection> {
self.database.get()
}
async fn get_or_try_init_database<T, U>(&self, options: T, _: U) -> Result<&DatabaseConnection, Error>
async fn get_or_try_init_database<T, F, Fut>(&self, path: T, migration: F) -> Result<&DatabaseConnection, Error>
where
T: Into<ConnectOptions>,
U: MigratorTrait,
T: AsRef<Path>,
F: FnOnce(DatabaseConnection) -> Fut,
Fut: Future<Output = Result<DatabaseConnection, DbErr>>
{
let url = "sqlite://".to_string() + path.as_ref().to_str().unwrap() + "?mode=rwc";
Ok(self.database.get_or_try_init(|| async {
let db = Database::connect(options).await?;
U::up(&db, None).await?;
Ok::<DatabaseConnection, Error>(db)
let db = Database::connect(&url).await?;
Ok::<DatabaseConnection, DbErr>(migration(db).await?)
}).await?)
}
#[cfg(any(test, feature="test"))]
pub async fn get_or_try_init_temporary_database<F, Fut>(&self, migration: F) -> Result<&DatabaseConnection, Error>
where
F: FnOnce(DatabaseConnection) -> Fut,
Fut: Future<Output = Result<DatabaseConnection, DbErr>>
{
self.get_or_try_init_database(&*TEST_DATABASE_URL, migration).await
}
}
#[cfg(test)]
pub mod tests {
use std::sync::LazyLock;
use lazy_supplements_migration::Migrator;
use sea_orm_migration::MigratorTrait;
use crate::global::GLOBAL;
use super::*;
pub static TEST_DATABASE_URL: LazyLock<String> = 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()
}
pub async fn get_or_init_temporary_database() -> &'static DatabaseConnection {
GLOBAL.get_or_try_init_temporary_database( |x| async {
Migrator::up(&x, None).await?;
Ok(x)
}).await.unwrap()
}
#[tokio::test]
async fn connect_database () {
let db = GLOBAL.get_or_init_temporary_database().await;
let db = get_or_init_temporary_database().await;
assert!(db.ping().await.is_ok());
}

View file

@ -12,3 +12,6 @@ pub struct Global {
server_config: OnceCell<ServerConfig>,
database: OnceCell<DatabaseConnection>,
}
#[cfg(test)]
pub use database::tests::get_or_init_temporary_database;

View file

@ -2,4 +2,4 @@ pub mod cli;
pub mod config;
pub mod entity;
pub mod error;
pub mod global;
pub mod global;