Implement migration and entity for client
This commit is contained in:
parent
c88605e5d6
commit
47da8152e6
21 changed files with 215 additions and 355 deletions
22
Cargo.lock
generated
22
Cargo.lock
generated
|
@ -2257,14 +2257,19 @@ dependencies = [
|
||||||
name = "progress-pile-client"
|
name = "progress-pile-client"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"async-graphql",
|
||||||
|
"chrono",
|
||||||
"chrono-tz",
|
"chrono-tz",
|
||||||
"clap",
|
"clap",
|
||||||
"dirs",
|
"dirs",
|
||||||
"progress-pile-core",
|
"progress-pile-core",
|
||||||
|
"progress-pile-migration",
|
||||||
|
"sea-orm",
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
"tokio",
|
"tokio",
|
||||||
"toml",
|
"toml",
|
||||||
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2630,6 +2635,7 @@ dependencies = [
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
"tracing",
|
"tracing",
|
||||||
"url",
|
"url",
|
||||||
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2689,6 +2695,7 @@ dependencies = [
|
||||||
"inherent",
|
"inherent",
|
||||||
"ordered-float",
|
"ordered-float",
|
||||||
"sea-query-derive",
|
"sea-query-derive",
|
||||||
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2700,6 +2707,7 @@ dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"sea-query",
|
"sea-query",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2973,6 +2981,7 @@ dependencies = [
|
||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
"tracing",
|
"tracing",
|
||||||
"url",
|
"url",
|
||||||
|
"uuid",
|
||||||
"webpki-roots",
|
"webpki-roots",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -3055,6 +3064,7 @@ dependencies = [
|
||||||
"stringprep",
|
"stringprep",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
"uuid",
|
||||||
"whoami",
|
"whoami",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -3093,6 +3103,7 @@ dependencies = [
|
||||||
"stringprep",
|
"stringprep",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
"uuid",
|
||||||
"whoami",
|
"whoami",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -3119,6 +3130,7 @@ dependencies = [
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
"tracing",
|
"tracing",
|
||||||
"url",
|
"url",
|
||||||
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3594,6 +3606,16 @@ version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uuid"
|
||||||
|
version = "1.16.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.3.2",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "value-bag"
|
name = "value-bag"
|
||||||
version = "1.11.1"
|
version = "1.11.1"
|
||||||
|
|
|
@ -17,6 +17,7 @@ serde = { version = "1.0", features = ["derive"] }
|
||||||
thiserror = "2.0.12"
|
thiserror = "2.0.12"
|
||||||
tokio = "1.44.2"
|
tokio = "1.44.2"
|
||||||
toml = "0.8.22"
|
toml = "0.8.22"
|
||||||
|
uuid = { version = "1.16.0", features = [ "serde", "v4" ] }
|
||||||
|
|
||||||
[workspace.dependencies.sea-orm]
|
[workspace.dependencies.sea-orm]
|
||||||
version = "1.1"
|
version = "1.1"
|
||||||
|
@ -26,6 +27,7 @@ features = [
|
||||||
"runtime-tokio-native-tls",
|
"runtime-tokio-native-tls",
|
||||||
"sqlx-sqlite",
|
"sqlx-sqlite",
|
||||||
"with-chrono",
|
"with-chrono",
|
||||||
|
"with-uuid",
|
||||||
]
|
]
|
||||||
default-features = false
|
default-features = false
|
||||||
|
|
||||||
|
|
|
@ -8,11 +8,16 @@ default = ["clap"]
|
||||||
clap = ["dep:clap"]
|
clap = ["dep:clap"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
async-graphql.workspace = true
|
||||||
|
chrono.workspace = true
|
||||||
chrono-tz.workspace = true
|
chrono-tz.workspace = true
|
||||||
clap = { workspace = true, optional = true }
|
clap = { workspace = true, optional = true }
|
||||||
dirs.workspace = true
|
dirs.workspace = true
|
||||||
progress-pile-core.workspace = true
|
progress-pile-core.workspace = true
|
||||||
|
progress-pile-migration = { workspace = true, features = ["client"]}
|
||||||
|
sea-orm.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
thiserror.workspace = true
|
thiserror.workspace = true
|
||||||
tokio.workspace = true
|
tokio.workspace = true
|
||||||
toml.workspace = true
|
toml.workspace = true
|
||||||
|
uuid.workspace = true
|
49
progress-pile-client/src/entity/mod.rs
Normal file
49
progress-pile-client/src/entity/mod.rs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
mod progress_category;
|
||||||
|
mod progress_entry;
|
||||||
|
|
||||||
|
pub use progress_category::{
|
||||||
|
ActiveModel as ProgressCategoryActiveModel,
|
||||||
|
Column as ProgressCategoryColumn,
|
||||||
|
Entity as ProgressCategoryEntity,
|
||||||
|
Model as ProgressCategoryModel,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub use progress_entry::{
|
||||||
|
ActiveModel as ProgressEntryActiveModel,
|
||||||
|
Column as ProgressEntryColumn,
|
||||||
|
Entity as ProgressEntryEntity,
|
||||||
|
Model as ProgressEntryModel,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
use chrono::Local;
|
||||||
|
use sea_orm::entity::*;
|
||||||
|
use progress_pile_migration::{ClientMigrator, MigratorTrait};
|
||||||
|
use uuid::Uuid;
|
||||||
|
use crate::database_connection::DATABASE_CONNECTION;
|
||||||
|
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn check_insert_entity() {
|
||||||
|
let db = DATABASE_CONNECTION.get_or_init("sqlite::memory:").await;
|
||||||
|
ClientMigrator::up(db, None).await.unwrap();
|
||||||
|
let local_date_time = Local::now();
|
||||||
|
let offset_date_time = local_date_time.with_timezone(local_date_time.offset());
|
||||||
|
|
||||||
|
let category = ProgressCategoryActiveModel{
|
||||||
|
name: Set("test_category".to_owned()),
|
||||||
|
..ProgressCategoryActiveModel::new()
|
||||||
|
}.insert(db).await.unwrap();
|
||||||
|
|
||||||
|
let entry1= ProgressEntryActiveModel {
|
||||||
|
progress_category_id: Set(category.id),
|
||||||
|
..ProgressEntryActiveModel::new()
|
||||||
|
}.insert(db).await.unwrap();
|
||||||
|
|
||||||
|
ClientMigrator::reset(db).await.unwrap();
|
||||||
|
//db.clone().close().await.unwrap();
|
||||||
|
}
|
||||||
|
}
|
52
progress-pile-client/src/entity/progress_category.rs
Normal file
52
progress-pile-client/src/entity/progress_category.rs
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
use core::time;
|
||||||
|
|
||||||
|
use async_graphql::*;
|
||||||
|
use chrono::Local;
|
||||||
|
use sea_orm::entity::{
|
||||||
|
*,
|
||||||
|
prelude::*
|
||||||
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
|
||||||
|
#[sea_orm(table_name = "progress_category")]
|
||||||
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id: Uuid,
|
||||||
|
#[sea_orm(indexed)]
|
||||||
|
pub name: String,
|
||||||
|
#[sea_orm(indexed)]
|
||||||
|
pub created_at: DateTimeWithTimeZone,
|
||||||
|
#[sea_orm(indexed)]
|
||||||
|
pub updated_at: DateTimeWithTimeZone,
|
||||||
|
#[sea_orm(indexed)]
|
||||||
|
pub deleted_at: Option<DateTimeWithTimeZone>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, DeriveRelation, EnumIter)]
|
||||||
|
pub enum Relation {
|
||||||
|
|
||||||
|
#[sea_orm(has_many = "super::ProgressEntryEntity")]
|
||||||
|
ProgressEntry,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Related<super::ProgressEntryEntity> for Entity {
|
||||||
|
fn to() -> RelationDef {
|
||||||
|
Relation::ProgressEntry.def()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
|
||||||
|
impl ActiveModel {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let timestamp: DateTimeWithTimeZone = Local::now().fixed_offset();
|
||||||
|
Self{
|
||||||
|
id: Set(Uuid::new_v4()),
|
||||||
|
created_at: Set(timestamp),
|
||||||
|
updated_at: Set(timestamp),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
62
progress-pile-client/src/entity/progress_entry.rs
Normal file
62
progress-pile-client/src/entity/progress_entry.rs
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
use async_graphql::*;
|
||||||
|
use chrono::Local;
|
||||||
|
use sea_orm::entity::{
|
||||||
|
*,
|
||||||
|
prelude::*
|
||||||
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize,)]
|
||||||
|
#[sea_orm(table_name = "progress_entry")]
|
||||||
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id: Uuid,
|
||||||
|
#[sea_orm(indexed)]
|
||||||
|
pub progress_category_id: Uuid,
|
||||||
|
#[sea_orm(indexed)]
|
||||||
|
pub created_at: DateTimeWithTimeZone,
|
||||||
|
#[sea_orm(indexed)]
|
||||||
|
pub updated_at: DateTimeWithTimeZone,
|
||||||
|
#[sea_orm(indexed)]
|
||||||
|
pub deleted_at: Option<DateTimeWithTimeZone>,
|
||||||
|
#[sea_orm(indexed)]
|
||||||
|
pub progressed_at: DateTimeWithTimeZone,
|
||||||
|
pub quantity: i32,
|
||||||
|
pub note: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, DeriveRelation, EnumIter)]
|
||||||
|
pub enum Relation {
|
||||||
|
|
||||||
|
#[sea_orm(
|
||||||
|
belongs_to = "super::ProgressCategoryEntity",
|
||||||
|
from = "Column::ProgressCategoryId",
|
||||||
|
to = "super::ProgressCategoryColumn::Id"
|
||||||
|
)]
|
||||||
|
ProgressCategory,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Related<super::progress_category::Entity> for Entity {
|
||||||
|
fn to() -> RelationDef {
|
||||||
|
Relation::ProgressCategory.def()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
|
||||||
|
impl ActiveModel {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let timestamp: DateTimeWithTimeZone = Local::now().fixed_offset();
|
||||||
|
Self{
|
||||||
|
id: Set(Uuid::new_v4()),
|
||||||
|
created_at: Set(timestamp),
|
||||||
|
updated_at: Set(timestamp),
|
||||||
|
progressed_at: Set(timestamp),
|
||||||
|
quantity: Set(1),
|
||||||
|
note: Set("".to_string()),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,8 @@
|
||||||
pub mod auth;
|
pub mod auth;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
|
pub mod entity;
|
||||||
|
|
||||||
pub use progress_pile_core::error;
|
pub use progress_pile_core::*;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,6 @@ clap = { workspace = true, optional = true }
|
||||||
csv = "1.3.1"
|
csv = "1.3.1"
|
||||||
cynic = "3.10.0"
|
cynic = "3.10.0"
|
||||||
dotenv = {workspace = true}
|
dotenv = {workspace = true}
|
||||||
progress-pile-migration-server.workspace = true
|
|
||||||
iana-time-zone = "0.1.63"
|
iana-time-zone = "0.1.63"
|
||||||
log = "0.4.27"
|
log = "0.4.27"
|
||||||
sea-orm.workspace = true
|
sea-orm.workspace = true
|
||||||
|
|
|
@ -6,7 +6,7 @@ use sea_orm::ConnectOptions;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use tokio::sync::OnceCell;
|
use tokio::sync::OnceCell;
|
||||||
|
|
||||||
use crate::Error;
|
use crate::error::Error;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Deserialize, PartialEq)]
|
||||||
pub struct DatabaseConfig {
|
pub struct DatabaseConfig {
|
||||||
|
|
|
@ -4,7 +4,7 @@ use clap::Args;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tokio::sync::OnceCell;
|
use tokio::sync::OnceCell;
|
||||||
|
|
||||||
use crate::Error;
|
use crate::error::Error;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
use chrono::{DateTime, NaiveDateTime};
|
use chrono::{DateTime, NaiveDateTime};
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
use crate::{
|
|
||||||
entity::RecordDetailModel,
|
|
||||||
error::Error,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||||
pub struct CsvRecord{
|
pub struct CsvRecord{
|
||||||
|
@ -12,10 +8,3 @@ pub struct CsvRecord{
|
||||||
pub tag: String,
|
pub tag: String,
|
||||||
pub count: i32,
|
pub count: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<RecordDetailModel> for CsvRecord{
|
|
||||||
type Error = Error;
|
|
||||||
fn try_from(model: RecordDetailModel) -> Result<Self, Self::Error> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,7 +4,6 @@ use crate::config::{
|
||||||
};
|
};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use sea_orm::{entity::*, query::*, ConnectOptions, Database, DatabaseConnection};
|
use sea_orm::{entity::*, query::*, ConnectOptions, Database, DatabaseConnection};
|
||||||
use progress_pile_migration_server::{Migrator, MigratorTrait};
|
|
||||||
|
|
||||||
use tokio::sync::OnceCell;
|
use tokio::sync::OnceCell;
|
||||||
|
|
||||||
|
@ -21,44 +20,14 @@ impl OnceDatabaseConnection {
|
||||||
pub fn get(&self) -> Option<&DatabaseConnection> {
|
pub fn get(&self) -> Option<&DatabaseConnection> {
|
||||||
self.inner.get()
|
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
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn get_or_init_with_server_config(&self, c: &DatabaseConfig) -> &DatabaseConnection {
|
pub async fn get_or_init<T>(&self, c: T) -> &DatabaseConnection where
|
||||||
self.get_or_init( || async {
|
T: Into<ConnectOptions>
|
||||||
let db = Database::connect(c).await.unwrap();
|
{
|
||||||
Migrator::fresh(&db).await.unwrap();
|
self.inner.get_or_init(|| async {
|
||||||
db
|
Database::connect(c).await.unwrap()
|
||||||
}).await
|
}).await
|
||||||
}
|
}
|
||||||
pub async fn get_or_init_with_static_server_config(&self) -> &DatabaseConnection {
|
|
||||||
self.get_or_init_with_server_config(DATABASE_CONFIG.get().unwrap()).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;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -68,71 +37,10 @@ pub static DATABASE_CONNECTION: OnceDatabaseConnection = OnceDatabaseConnection:
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use std::time::Duration;
|
//#[tokio::test]
|
||||||
use chrono::{offset, FixedOffset, Local, TimeZone};
|
|
||||||
use sea_orm::{entity::*, query::*, ConnectOptions, Database};
|
|
||||||
use progress_pile_migration_server::{Migrator, MigratorTrait};
|
|
||||||
use crate::entity::*;
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn check_database_connection() {
|
async fn check_database_connection() {
|
||||||
DATABASE_CONNECTION.init_test().await;
|
DATABASE_CONNECTION.get_or_init("sqlite::memory:").await;
|
||||||
let db = DATABASE_CONNECTION.get().unwrap();
|
let db = DATABASE_CONNECTION.get().unwrap();
|
||||||
assert!(db.ping().await.is_ok());
|
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
progress-pile-core/src/entity.rs
Normal file
7
progress-pile-core/src/entity.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
pub trait ProgressCategoryModelTrait {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ProgressEntityModelTrait {
|
||||||
|
|
||||||
|
}
|
|
@ -1,29 +0,0 @@
|
||||||
mod record_detail;
|
|
||||||
mod record_header;
|
|
||||||
mod record_tag;
|
|
||||||
mod user;
|
|
||||||
|
|
||||||
pub use user::{
|
|
||||||
ActiveModel as UserActiveModel,
|
|
||||||
Column as UserColumn,
|
|
||||||
Entity as UserEntity,
|
|
||||||
Model as UserModel,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub use record_detail::{
|
|
||||||
ActiveModel as RecordDetailActiveModel,
|
|
||||||
Entity as RecordDetailEntity,
|
|
||||||
Model as RecordDetailModel,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub use record_header::{
|
|
||||||
ActiveModel as RecordHeaderActiveModel,
|
|
||||||
Entity as RecordHeaderEntity,
|
|
||||||
Model as RecordHeaderModel,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub use record_tag::{
|
|
||||||
ActiveModel as RecordTagActiveModel,
|
|
||||||
Entity as RecordTagEntity,
|
|
||||||
Model as RecordTagModel,
|
|
||||||
};
|
|
|
@ -1,46 +0,0 @@
|
||||||
use async_graphql::*;
|
|
||||||
use sea_orm::entity::prelude::*;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize, SimpleObject)]
|
|
||||||
#[sea_orm(table_name = "record_detail")]
|
|
||||||
#[graphql(concrete(name = "RecordDetail", params()))]
|
|
||||||
pub struct Model {
|
|
||||||
#[sea_orm(primary_key)]
|
|
||||||
#[serde(skip_deserializing)]
|
|
||||||
pub record_header_id: i32,
|
|
||||||
#[sea_orm(primary_key)]
|
|
||||||
#[serde(skip_deserializing)]
|
|
||||||
pub record_tag_id: i32,
|
|
||||||
pub count: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, DeriveRelation, EnumIter)]
|
|
||||||
pub enum Relation {
|
|
||||||
#[sea_orm(
|
|
||||||
belongs_to = "super::record_header::Entity",
|
|
||||||
from = "Column::RecordHeaderId",
|
|
||||||
to = "super::record_header::Column::Id"
|
|
||||||
)]
|
|
||||||
RecordHeader,
|
|
||||||
#[sea_orm(
|
|
||||||
belongs_to = "super::record_tag::Entity",
|
|
||||||
from = "Column::RecordTagId",
|
|
||||||
to = "super::record_tag::Column::Id"
|
|
||||||
)]
|
|
||||||
RecordTag,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Related<super::record_header::Entity> for Entity {
|
|
||||||
fn to() -> RelationDef {
|
|
||||||
Relation::RecordHeader.def()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Related<super::record_tag::Entity> for Entity {
|
|
||||||
fn to() -> RelationDef {
|
|
||||||
Relation::RecordTag.def()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ActiveModelBehavior for ActiveModel {}
|
|
|
@ -1,46 +0,0 @@
|
||||||
use async_graphql::*;
|
|
||||||
use sea_orm::entity::prelude::*;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize, SimpleObject)]
|
|
||||||
#[sea_orm(table_name = "record_header")]
|
|
||||||
#[graphql(concrete(name = "RecordHeader", params()))]
|
|
||||||
pub struct Model {
|
|
||||||
#[sea_orm(primary_key)]
|
|
||||||
#[serde(skip_deserializing)]
|
|
||||||
pub id: i32,
|
|
||||||
#[sea_orm(indexed)]
|
|
||||||
#[serde(skip_deserializing)]
|
|
||||||
pub user_id: i32,
|
|
||||||
pub comment: String,
|
|
||||||
pub created_at: DateTimeWithTimeZone,
|
|
||||||
pub updated_at: DateTimeWithTimeZone,
|
|
||||||
#[sea_orm(indexed)]
|
|
||||||
pub recorded_at: DateTimeWithTimeZone,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, DeriveRelation, EnumIter)]
|
|
||||||
pub enum Relation {
|
|
||||||
#[sea_orm(has_many = "super::record_detail::Entity")]
|
|
||||||
RecordDetail,
|
|
||||||
#[sea_orm(
|
|
||||||
belongs_to = "super::user::Entity",
|
|
||||||
from = "Column::UserId",
|
|
||||||
to = "super::user::Column::Id"
|
|
||||||
)]
|
|
||||||
User,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Related<super::record_detail::Entity> for Entity {
|
|
||||||
fn to() -> RelationDef {
|
|
||||||
Relation::RecordDetail.def()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Related<super::user::Entity> for Entity {
|
|
||||||
fn to() -> RelationDef {
|
|
||||||
Relation::User.def()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ActiveModelBehavior for ActiveModel {}
|
|
|
@ -1,43 +0,0 @@
|
||||||
use async_graphql::*;
|
|
||||||
use sea_orm::entity::prelude::*;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize, SimpleObject)]
|
|
||||||
#[sea_orm(table_name = "record_tag")]
|
|
||||||
#[graphql(concrete(name = "RecordTag", params()))]
|
|
||||||
pub struct Model {
|
|
||||||
#[sea_orm(primary_key)]
|
|
||||||
#[serde(skip_deserializing)]
|
|
||||||
pub id: i32,
|
|
||||||
#[sea_orm(indexed)]
|
|
||||||
#[serde(skip_deserializing)]
|
|
||||||
pub user_id: i32,
|
|
||||||
#[sea_orm(indexed)]
|
|
||||||
pub name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, DeriveRelation, EnumIter)]
|
|
||||||
pub enum Relation {
|
|
||||||
#[sea_orm(has_many = "super::record_detail::Entity")]
|
|
||||||
RecordDetail,
|
|
||||||
#[sea_orm(
|
|
||||||
belongs_to = "super::user::Entity",
|
|
||||||
from = "Column::UserId",
|
|
||||||
to = "super::user::Column::Id"
|
|
||||||
)]
|
|
||||||
User,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Related<super::record_detail::Entity> for Entity {
|
|
||||||
fn to() -> RelationDef {
|
|
||||||
Relation::RecordDetail.def()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Related<super::user::Entity> for Entity {
|
|
||||||
fn to() -> RelationDef {
|
|
||||||
Relation::User.def()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ActiveModelBehavior for ActiveModel {}
|
|
|
@ -1,64 +0,0 @@
|
||||||
use async_graphql::SimpleObject;
|
|
||||||
use chrono::{DateTime, FixedOffset,};
|
|
||||||
use sea_orm::entity::prelude::*;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use crate::error::Error;
|
|
||||||
|
|
||||||
use crate::DATABASE_CONNECTION;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, SimpleObject, Deserialize)]
|
|
||||||
#[sea_orm(table_name = "user")]
|
|
||||||
#[graphql(concrete(name = "User", params()))]
|
|
||||||
pub struct Model {
|
|
||||||
#[sea_orm(primary_key)]
|
|
||||||
#[serde(skip_deserializing)]
|
|
||||||
pub id: i32,
|
|
||||||
#[sea_orm(unique, indexed)]
|
|
||||||
pub login_name: String,
|
|
||||||
pub password_hash: String,
|
|
||||||
pub created_at: DateTimeWithTimeZone,
|
|
||||||
pub updated_at: DateTimeWithTimeZone,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Entity {
|
|
||||||
pub async fn find_by_name(user_name: &str) -> Result<Option<Model>, Error> {
|
|
||||||
Ok(Entity::find()
|
|
||||||
.filter(Column::LoginName.contains(user_name))
|
|
||||||
.one(DATABASE_CONNECTION.get().unwrap())
|
|
||||||
.await?
|
|
||||||
)
|
|
||||||
}
|
|
||||||
pub async fn find_all() -> Result<Vec<Model>, Error> {
|
|
||||||
Ok(Entity::find()
|
|
||||||
.all(DATABASE_CONNECTION.get().unwrap())
|
|
||||||
.await?
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, DeriveRelation, EnumIter)]
|
|
||||||
pub enum Relation {
|
|
||||||
#[sea_orm(has_many = "super::record_header::Entity")]
|
|
||||||
RecordHeader,
|
|
||||||
#[sea_orm(has_many = "super::record_tag::Entity")]
|
|
||||||
RecordTag,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Related<super::record_header::Entity> for Model {
|
|
||||||
fn to() -> RelationDef {
|
|
||||||
Relation::RecordHeader.def()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Related<super::record_tag::Entity> for Model {
|
|
||||||
fn to() -> RelationDef {
|
|
||||||
Relation::RecordTag.def()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl ActiveModel {
|
|
||||||
pub async fn create_user(login_name: &str, password: &str) -> Result<Model, Error>{
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl ActiveModelBehavior for ActiveModel {}
|
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
use async_graphql::*;
|
use async_graphql::*;
|
||||||
use chrono::{DateTime, FixedOffset};
|
use chrono::{DateTime, FixedOffset};
|
||||||
|
|
||||||
use crate::entity::UserModel;
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(SimpleObject)]
|
#[derive(SimpleObject)]
|
||||||
pub struct PartialUser {
|
pub struct PartialUser {
|
||||||
pub id: Option<i32>,
|
pub id: Option<i32>,
|
||||||
|
@ -12,11 +9,6 @@ pub struct PartialUser {
|
||||||
pub updated_at: Option<DateTime<FixedOffset>>,
|
pub updated_at: Option<DateTime<FixedOffset>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(SimpleObject)]
|
|
||||||
pub struct Users{
|
|
||||||
users: Vec<UserModel>
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CreateUser {
|
pub struct CreateUser {
|
||||||
login_name: String,
|
login_name: String,
|
||||||
password: String,
|
password: String,
|
||||||
|
|
|
@ -5,9 +5,6 @@ pub mod entity;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod graphql;
|
pub mod graphql;
|
||||||
|
|
||||||
pub use database_connection::*;
|
|
||||||
pub use error::Error;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
}
|
}
|
|
@ -1,8 +1,10 @@
|
||||||
use sea_orm_migration::{prelude::*, schema::*};
|
use sea_orm_migration::{prelude::*, schema::*};
|
||||||
|
|
||||||
|
#[cfg(feature="client")]
|
||||||
#[derive(DeriveMigrationName)]
|
#[derive(DeriveMigrationName)]
|
||||||
pub struct ClientMigration;
|
pub struct ClientMigration;
|
||||||
|
|
||||||
|
#[cfg(feature="client")]
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl MigrationTrait for ClientMigration {
|
impl MigrationTrait for ClientMigration {
|
||||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
@ -290,7 +292,6 @@ impl MigrationTableDefault for ProgressCategory {
|
||||||
Table::create()
|
Table::create()
|
||||||
.table(Self::Table)
|
.table(Self::Table)
|
||||||
.if_not_exists()
|
.if_not_exists()
|
||||||
.col(uuid(Self::Id))
|
|
||||||
.col(string(Self::Name))
|
.col(string(Self::Name))
|
||||||
.col(timestamp_with_time_zone(Self::CreatedAt))
|
.col(timestamp_with_time_zone(Self::CreatedAt))
|
||||||
.col(timestamp_with_time_zone(Self::UpdatedAt))
|
.col(timestamp_with_time_zone(Self::UpdatedAt))
|
||||||
|
@ -326,7 +327,7 @@ impl MigrationTableDefault for ProgressCategory {
|
||||||
impl MigrationTableClient for ProgressCategory {
|
impl MigrationTableClient for ProgressCategory {
|
||||||
fn table_create_statement_client() -> TableCreateStatement{
|
fn table_create_statement_client() -> TableCreateStatement{
|
||||||
let mut tcs = Self::table_create_statement_default();
|
let mut tcs = Self::table_create_statement_default();
|
||||||
tcs.primary_key(Index::create().name(PK_PROGRESS_CATEGORY).col(Self::Id));
|
tcs.col(pk_uuid(Self::Id));
|
||||||
tcs
|
tcs
|
||||||
}
|
}
|
||||||
fn index_create_statements_client() -> Vec<IndexCreateStatement> {
|
fn index_create_statements_client() -> Vec<IndexCreateStatement> {
|
||||||
|
@ -342,6 +343,8 @@ impl MigrationTableServer for ProgressCategory {
|
||||||
|
|
||||||
fn table_create_statement_server() -> TableCreateStatement{
|
fn table_create_statement_server() -> TableCreateStatement{
|
||||||
let mut tcs = Self::table_create_statement_default();
|
let mut tcs = Self::table_create_statement_default();
|
||||||
|
tcs.col(uuid(Self::Id));
|
||||||
|
|
||||||
tcs.col(integer(Self::UserId));
|
tcs.col(integer(Self::UserId));
|
||||||
tcs.foreign_key(ForeignKey::create().name(FK_PROGRESS_CATEGORY_USER).from(Self::Table, Self::UserId)
|
tcs.foreign_key(ForeignKey::create().name(FK_PROGRESS_CATEGORY_USER).from(Self::Table, Self::UserId)
|
||||||
.to(User::Table, User::Id));
|
.to(User::Table, User::Id));
|
||||||
|
|
Loading…
Add table
Reference in a new issue