Add database module

This commit is contained in:
fluo10 2025-05-01 20:43:03 +09:00
parent e91fd0f2bf
commit c4c5ef0027
7 changed files with 185 additions and 72 deletions

17
Cargo.lock generated
View file

@ -775,6 +775,7 @@ name = "dpts"
version = "0.1.0"
dependencies = [
"dpts-csv",
"dpts-database",
"dpts-entity",
"dpts-error",
"dpts-migration",
@ -800,6 +801,21 @@ dependencies = [
"serde",
]
[[package]]
name = "dpts-database"
version = "0.1.0"
dependencies = [
"async-graphql",
"axum",
"chrono",
"dotenv",
"dpts-entity",
"dpts-migration",
"log",
"sea-orm",
"tokio",
]
[[package]]
name = "dpts-entity"
version = "0.1.0"
@ -808,6 +824,7 @@ dependencies = [
"axum",
"chrono",
"dotenv",
"dpts-database",
"dpts-migration",
"log",
"sea-orm",

View file

@ -10,6 +10,7 @@ dpts-csv = { workspace = true }
dpts-entity = { workspace = true }
dpts-error = { workspace = true }
dpts-migration = { workspace = true }
dpts-database = { workspace = true }
[workspace]
members = [".", "dpts-*"]
@ -17,13 +18,14 @@ members = [".", "dpts-*"]
[workspace.dependencies]
dpts = { path = "." }
dpts-csv = { path = "dpts-csv" }
dpts-database = { path = "dpts-database" }
dpts-entity = { path = "dpts-entity" }
dpts-error = { path = "dpts-error" }
dpts-migration = {path = "dpts-migration"}
chrono = {version = "0.4", features = ["serde"]}
clap = "4.5"
dotenv = "0.15.0"
serde = "1.0.219"
serde = { version = "1.0", features = ["derive"] }
[workspace.package]
version = "0.1.0"

31
dpts-database/Cargo.toml Normal file
View file

@ -0,0 +1,31 @@
[package]
name = "dpts-database"
version.workspace = true
edition.workspace = true
license.workspace = true
repository.workspace = true
[features]
default = []
test = []
[dependencies]
dpts-entity = { workspace = true }
dpts-migration = { workspace = true }
async-graphql = {version = "7.0", features = ["chrono"]}
axum = "0.8"
chrono = {workspace = true}
dotenv = {workspace = true}
log = "0.4.27"
tokio = "1.44.2"
[dependencies.sea-orm]
version = "1.1"
features = [
"macros",
"debug-print",
"runtime-tokio-native-tls",
"sqlx-sqlite",
"with-chrono",
]
default-features = false

View file

@ -0,0 +1,123 @@
use std::time::Duration;
use sea_orm::{entity::*, query::*, ConnectOptions, Database, DatabaseConnection};
use dpts_migration::{Migrator, MigratorTrait};
use tokio::sync::OnceCell;
pub struct OnceDatabaseConnection {
inner: OnceCell<DatabaseConnection>,
}
impl OnceDatabaseConnection {
const fn new() -> Self {
Self {
inner: OnceCell::const_new(),
}
}
pub fn get(&self) -> Option<&DatabaseConnection> {
self.inner.get()
}
pub async fn get_or_init<F, T>(&self, f: F) -> &DatabaseConnection where
F: FnOnce() -> T,
T: Future<Output = DatabaseConnection>
{
self.inner.get_or_init(f).await
}
#[cfg(test)]
pub async fn init_test(&self) {
self.get_or_init( || async {
let mut opt = ConnectOptions::new("sqlite::memory:");
opt.max_connections(100)
.min_connections(5)
.connect_timeout(Duration::from_secs(8))
.acquire_timeout(Duration::from_secs(8))
.idle_timeout(Duration::from_secs(8))
.max_lifetime(Duration::from_secs(8))
.sqlx_logging(true)
.sqlx_logging_level(log::LevelFilter::Info);
//.set_schema_search_path("my_schema"); // Setting default PostgreSQL schema
let db = Database::connect(opt).await.unwrap();
Migrator::fresh(&db).await.unwrap();
db
}).await;
}
}
pub static DATABASE_CONNECTION: OnceDatabaseConnection = OnceDatabaseConnection::new();
#[cfg(test)]
mod tests {
use super::*;
use std::time::Duration;
use chrono::{offset, FixedOffset, Local, TimeZone};
use sea_orm::{entity::*, query::*, ConnectOptions, Database};
use dpts_migration::{Migrator, MigratorTrait};
use dpts_entity::*;
#[tokio::test]
async fn check_database_connection() {
DATABASE_CONNECTION.init_test().await;
let db = DATABASE_CONNECTION.get().unwrap();
assert!(db.ping().await.is_ok());
}
#[tokio::test]
async fn check_insert_entity() {
DATABASE_CONNECTION.init_test().await;
let db = DATABASE_CONNECTION.get().unwrap();
let local_date_time = Local::now();
let offset_date_time = local_date_time.with_timezone(local_date_time.offset());
let user = UserActiveModel{
login_name: Set("admin".to_owned()),
password_hash: Set("admin".to_owned()),
created_at: Set(offset_date_time),
updated_at: Set(offset_date_time),
..Default::default()
}.insert(db)
.await.unwrap();
let record_tag = RecordTagActiveModel{
user_id: Set(user.id),
name: Set("test".to_owned()),
..Default::default()
}.insert(db)
.await.unwrap();
let record_header = RecordHeaderActiveModel{
user_id: Set(user.id),
created_at: Set(offset_date_time),
updated_at: Set(offset_date_time),
recorded_at: Set(offset_date_time),
comment: Set("".to_owned()),
..Default::default()
}.insert(db)
.await.unwrap();
RecordDetailActiveModel {
record_header_id: Set(record_header.id),
record_tag_id: Set(record_tag.id),
count: Set(1),
..Default::default()
}.insert(db)
.await.unwrap();
RecordDetailActiveModel {
record_header_id: Set(record_header.id),
record_tag_id: Set(record_tag.id),
count: Set(2),
..Default::default()
}.insert(db)
.await.unwrap();
Migrator::reset(db).await.unwrap();
db.clone().close().await.unwrap();
}
}

7
dpts-database/src/lib.rs Normal file
View file

@ -0,0 +1,7 @@
mod connection;
pub use connection::*;
#[cfg(test)]
mod tests {
}

View file

@ -12,7 +12,7 @@ axum = "0.8"
chrono = {workspace = true}
dotenv = {workspace = true}
log = "0.4.27"
serde = { version = "1.0", features = ["derive"] }
serde = { workspace = true }
tokio = "1.44.2"
[dependencies.sea-orm]
@ -25,3 +25,6 @@ features = [
"with-chrono",
]
default-features = false
[dev-dependencies]
dpts-database = { workspace = true, features = ["test"] }

View file

@ -1,70 +0,0 @@
use std::time::Duration;
use chrono::{offset, FixedOffset, Local, TimeZone};
use sea_orm::{entity::*, query::*, ConnectOptions, Database};
use dpts_migration::{Migrator, MigratorTrait};
use dpts_entity::*;
#[tokio::test]
async fn main() {
let mut opt = ConnectOptions::new("sqlite::memory:");
opt.max_connections(100)
.min_connections(5)
.connect_timeout(Duration::from_secs(8))
.acquire_timeout(Duration::from_secs(8))
.idle_timeout(Duration::from_secs(8))
.max_lifetime(Duration::from_secs(8))
.sqlx_logging(true)
.sqlx_logging_level(log::LevelFilter::Info);
//.set_schema_search_path("my_schema"); // Setting default PostgreSQL schema
let db= Database::connect(opt).await.unwrap();
Migrator::fresh(&db).await.unwrap();
let local_date_time = Local::now();
let offset_date_time = local_date_time.with_timezone(local_date_time.offset());
let user = UserActiveModel{
login_name: Set("admin".to_owned()),
password_hash: Set("admin".to_owned()),
created_at: Set(offset_date_time),
updated_at: Set(offset_date_time),
..Default::default()
}.insert(&db)
.await.unwrap();
let record_tag = RecordTagActiveModel{
user_id: Set(user.id),
name: Set("test".to_owned()),
..Default::default()
}.insert(&db)
.await.unwrap();
let record_header = RecordHeaderActiveModel{
user_id: Set(user.id),
created_at: Set(offset_date_time),
updated_at: Set(offset_date_time),
recorded_at: Set(offset_date_time),
comment: Set("".to_owned()),
..Default::default()
}.insert(&db)
.await.unwrap();
RecordDetailActiveModel {
record_header_id: Set(record_header.id),
record_tag_id: Set(record_tag.id),
count: Set(1),
..Default::default()
}.insert(&db)
.await.unwrap();
RecordDetailActiveModel {
record_header_id: Set(record_header.id),
record_tag_id: Set(record_tag.id),
count: Set(2),
..Default::default()
}.insert(&db)
.await.unwrap();
Migrator::reset(&db).await.unwrap();
db.close().await.unwrap();
}