Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Develop global config #28

Merged
merged 7 commits into from
Mar 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src-tauri/src/core/cfgmanager/dto.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use serde::{Deserialize, Serialize};

#[derive(Debug, Deserialize, Serialize)]
pub struct ChangeConfigDto {
pub lang: Option<String>,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct ConfigDto {
pub lang: String
}
102 changes: 102 additions & 0 deletions src-tauri/src/core/cfgmanager/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
use std::path::Path;
use std::fs::{self, File};
use std::io::{Read, Write};
use std::sync::{Arc, Mutex, MutexGuard};

use once_cell::sync::OnceCell;
use serde::{Deserialize, Serialize};

mod dto;
pub use dto::*;
mod tauri_command;
pub use tauri_command::*;

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct MakuConfig {
lang: String,
}

impl Default for MakuConfig {
fn default() -> Self {
Self { lang: "enUS".to_string() }
}
}

impl MakuConfig {
pub fn set_lang(&mut self, lang: String) {
if lang == "enUS" || lang == "zhTW" {
self.lang = lang;
}
}
}

static MAKU_CONFIG: OnceCell<Mutex<MakuConfigManager>> = OnceCell::new();

#[derive(Debug)]
pub struct MakuConfigManager {
config: MakuConfig,

path: String,
}

impl MakuConfigManager {

pub fn init(config_path: String) -> Result<(), String> {
fs::create_dir_all(&config_path)
.expect("config directory should be writable");

let path = Path::new(&config_path).join("config.json");

let mut manager = Self {
config: MakuConfig::default(),
path: path.to_str().unwrap().to_string(),
};
manager.load();

MAKU_CONFIG.set(Mutex::new(manager))
.expect("config manager is initialize failed");
Ok(())
}


pub fn save(&self) {
let data = serde_json::to_string(&self.config)
.unwrap();

let mut writer = File::create(&self.path)
.expect("cannot create the file writer");

writer
.write_all(data.as_bytes())
.expect("config should be writable");
}

pub fn load(&mut self) {
let path = Path::new(&self.path);

if path.exists() == false {
self.config = MakuConfig::default();
self.save();
return;
}

let reader = File::open(path);
let mut buffer = String::new();

match reader {
Ok(mut file) => {
file.read_to_string(&mut buffer)
.expect("config should be readable");
},
Err(e) => {
buffer = serde_json::to_string(&MakuConfig::default()).unwrap();
}
}

self.config = serde_json::from_str(&buffer).unwrap();
}

pub fn access() -> MutexGuard<'static, MakuConfigManager> {
MAKU_CONFIG.get().unwrap().lock().unwrap()
}
}
22 changes: 22 additions & 0 deletions src-tauri/src/core/cfgmanager/tauri_command.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use super::{ChangeConfigDto, ConfigDto, MakuConfigManager};


#[tauri::command(rename_all = "snake_case")]
pub fn update_config(data: ChangeConfigDto) -> String {
let mut manager = MakuConfigManager::access();

if let Some(lang) = data.lang {
manager.config.set_lang(lang);
}

manager.save();

"Success".to_string()
}

#[tauri::command(rename_all = "snake_case")]
pub fn get_config() -> Result<ConfigDto, String> {
let config = MakuConfigManager::access().config.clone();

Ok(ConfigDto { lang: config.lang })
}
1 change: 1 addition & 0 deletions src-tauri/src/core/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pub mod dbmanager;
pub mod cfgmanager;
13 changes: 13 additions & 0 deletions src-tauri/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
use core::dbmanager::DatabaseManagerStatus;
use core::cfgmanager::{self, MakuConfigManager};
use std::path::PathBuf;

use pretty_env_logger;
use modules::common::repository;
Expand Down Expand Up @@ -43,6 +45,15 @@ fn main() {
.lock()
.unwrap()
.start_db();

// config
let config_path = app.app_handle()
.path_resolver()
.app_local_data_dir()
.unwrap_or(PathBuf::new());
let config_path = config_path.to_str().unwrap().to_string();
MakuConfigManager::init(config_path)?;

match result {
Ok(_) => { Ok(()) },
Err(err) => panic!("{}", err.to_string()),
Expand All @@ -65,6 +76,8 @@ fn main() {
})
.invoke_handler(tauri::generate_handler![
connect_db,
core::cfgmanager::update_config,
core::cfgmanager::get_config,
category::application::create_category,
category::application::update_category,
category::application::update_mapper_rule_category,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,16 @@ impl ICommandHandler<CreateCategoryCommand> for CreateCategoryHandler<'_> {
root_path,
} = command;

// check name already existed
let duplicated = self.categroy_repo
.is_duplicate_name(&name)
.await
.or(Err(CategoryGenericError::DBInternalError()))?;

if duplicated {
return Err(CategoryGenericError::NameIsDuplicated { current_name: name }.into());
}

// create new category
let new_category = CategoryFactory::create(name, description, root_path)?;

Expand Down
45 changes: 41 additions & 4 deletions src-tauri/src/modules/category/repository/repository.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ use surrealdb::Surreal;
use surrealdb::engine::remote::ws::Client;
use surrealdb::sql::{Thing, Datetime, thing};

use crate::modules::category::infrastructure::CategoryQueryBuilder;
use crate::modules::common::infrastructure::{QueryBuilder, QueryBuilderResult};
use crate::modules::common::domain::DomainModelMapper;
use crate::modules::common::repository::{env, tablens};
use crate::modules::common::repository::{env, tablens, CommonRepository, COMMON_REPOSITORY};
use crate::modules::category::domain::{Category, CategoryFactory};

pub static CATEGORY_REPOSITORY: CategoryRepository<'_> = CategoryRepository::init(&env::DB);
pub static CATEGORY_REPOSITORY: CategoryRepository<'_> = CategoryRepository::init(&env::DB, &COMMON_REPOSITORY);

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct CategoryMapperRuleItemDO {
Expand All @@ -34,11 +36,34 @@ pub struct CategoryDO {
* Repository */
pub struct CategoryRepository<'a> {
db: &'a Lazy<Surreal<Client>>,
common_repo: &'a CommonRepository<'a>,
}

impl<'a> CategoryRepository<'a> {
pub const fn init(db: &'a Lazy<Surreal<Client>>) -> Self {
CategoryRepository { db: db }
pub const fn init(db: &'a Lazy<Surreal<Client>>, common_repo: &'a CommonRepository) -> Self {
CategoryRepository {
db: db,
common_repo: common_repo,
}
}

pub async fn get_by(&self, builder_result: QueryBuilderResult) -> surrealdb::Result<Vec<Category>> {
let sql = format!(r#"
SELECT
*
FROM type::table($table) WHERE {}"#,
builder_result.to_string());

let result: Vec<Category> = self.db
.query(sql)
.bind(("table", tablens::CATEGORY))
.await?
.take::<Vec<CategoryDO>>(0)?
.into_iter()
.map(|val| Self::model_to_entity(val))
.collect();

Ok(result)
}

pub async fn is_exist(&self, id: &String) -> bool {
Expand All @@ -54,6 +79,18 @@ impl<'a> CategoryRepository<'a> {
}
}

pub async fn is_duplicate_name(&self, name: &String) -> surrealdb::Result<bool> {
let buildres = CategoryQueryBuilder::new()
.set_name(name)
.build()
.unwrap();

let result = self.common_repo.is_duplicated(tablens::CATEGORY, buildres)
.await?;

Ok(result)
}

pub async fn find_by_id(&self, id: &String) -> surrealdb::Result<Option<Category>> {
let thing_id = thing(id).unwrap();
let result: Option<CategoryDO> = self.db
Expand Down
21 changes: 21 additions & 0 deletions src-tauri/src/modules/common/repository/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@ use surrealdb::sql::thing;
use surrealdb::engine::remote::ws::Client;

use crate::modules::category::domain::CategoryID;
use crate::modules::common::infrastructure::QueryBuilderResult;
use crate::modules::common::repository::env;
use crate::modules::resource::domain::ResourceID;
use crate::modules::subject::domain::SubjectID;
use crate::modules::tag::domain::TagID;

use super::CountDO;

pub static COMMON_REPOSITORY: CommonRepository<'_> = CommonRepository::init(&env::DB);

/**
Expand Down Expand Up @@ -64,5 +67,23 @@ impl<'a> CommonRepository<'a> {
).await?;
Ok(())
}

pub async fn is_duplicated(&self, ns: &str, builder_result: QueryBuilderResult) -> surrealdb::Result<bool> {
let sql = format!(r#"
SELECT
COUNT()
FROM type::table($table)
WHERE {}"#,
builder_result.to_string());

let result = self.db
.query(sql)
.bind(("table", ns))
.await?
.take::<Vec<CountDO>>(0)?
.pop();

Ok(result.is_some() && (result.unwrap().count > 0))
}
}

3 changes: 3 additions & 0 deletions src-tauri/src/modules/common/repository/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ pub use common::CommonRepository;

mod predef;
pub use predef::*;

mod obj;
pub use obj::*;
9 changes: 9 additions & 0 deletions src-tauri/src/modules/common/repository/obj.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use serde::{Deserialize, Serialize};


/**
* counting Data Object */
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct CountDO {
pub count: i64,
}
4 changes: 2 additions & 2 deletions src-tauri/src/modules/resource/repository/query-repository.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ impl<'a> ResourceQueryRepository<'a> {
(SELECT
*,
(->belong->subject.name)[0] AS subject_name,
(->tagging.added_at)[0] AS added_at,
(->tagging.attrval)[0] AS attrval,
->tagging[WHERE out == $parent.id][0].added_at as added_at,
->tagging[WHERE out == $parent.id][0].attrval as attrval,
array::len(->tagging.out) as tagged_count
FROM tag
WHERE ->tagging->resource.id CONTAINS $parent.id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@ impl ICommandHandler<CreateSubjectCommand> for CreateSubjectHandler<'_> {
belong_category,
} = command;

// check name existed
let duplicated = self.subject_repo
.is_duplicate_name(&belong_category, &name)
.await
.or(Err(SubjectGenericError::DBInternalError()))?;

if duplicated {
return Err(SubjectGenericError::NameIsDuplicated { current_name: name }.into());
}

// get CategoryID
let category_id = self.category_repo
.is_exist(&belong_category)
Expand Down
18 changes: 16 additions & 2 deletions src-tauri/src/modules/subject/repository/repository.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ use surrealdb::sql::{Datetime, Thing, thing};
use surrealdb::engine::remote::ws::Client;

use crate::modules::common::domain::DomainModelMapper;
use crate::modules::common::infrastructure::QueryBuilderResult;
use crate::modules::common::repository::{env, tablens, CommonRepository, COMMON_REPOSITORY};
use crate::modules::common::infrastructure::{QueryBuilder, QueryBuilderResult};
use crate::modules::common::repository::{env, tablens, CommonRepository, CountDO, COMMON_REPOSITORY};
use crate::modules::subject::domain::{Subject, SubjectFactory, SubjectID};
use crate::modules::subject::infrastructure::SubjectQueryBuilder;

pub static SUBJECT_REPOSITORY: SubjectRepository<'_> = SubjectRepository::init(&env::DB, &COMMON_REPOSITORY);

Expand Down Expand Up @@ -89,6 +90,19 @@ impl<'a> SubjectRepository<'a> {
}
}

pub async fn is_duplicate_name(&self, belong_category: &String, name: &String) -> surrealdb::Result<bool> {
let buildres = SubjectQueryBuilder::new()
.set_name(name)
.set_belong_category(belong_category)
.build()
.unwrap();

let result = self.common_repo.is_duplicated(tablens::SUBJECT, buildres)
.await?;

Ok(result)
}

pub async fn find_by_id(&self, id: &String) -> surrealdb::Result<Option<Subject>> {
let result = self.return_aggregate_by_id(id)
.await?;
Expand Down
10 changes: 10 additions & 0 deletions src-tauri/src/modules/tag/application/command/create_tag/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,16 @@ impl ICommandHandler<CreateTagCommand> for CreateTagHandler<'_> {
attrval,
} = command;

// check name duplicated
let duplicated = self.tag_repo
.is_duplicate_name(&belong_category, &belong_subject, &name)
.await
.or(Err(TagGenericError::DBInternalError()))?;

if duplicated {
return Err(TagGenericError::NameIsDuplicated { current_name: name }.into());
}

// get CategoryID
let category_id = self.category_repo
.is_exist(&belong_category)
Expand Down
Loading
Loading