Browse Source

Added PL major system rules

develop-refactor
chodak166 5 months ago
parent
commit
b86a375b1c
  1. 38
      lib/src/application/errors.rs
  2. 2
      lib/src/application/services.rs
  3. 46
      lib/src/application/traits.rs
  4. 9
      lib/src/core/entities.rs
  5. 24
      lib/src/core/errors.rs
  6. 219
      lib/src/core/sys_major/rules_pl.rs
  7. 41
      lib/src/core/traits.rs
  8. 2
      lib/src/infrastructure/json_file_dict_source.rs
  9. 8
      lib/src/infrastructure/sqlite_dict_repository.rs
  10. 2
      lib/src/presentation/cli/commands/import_dict.rs

38
lib/src/application/errors.rs

@ -1,39 +1 @@
// #[derive(Debug)]
// pub enum RepositoryError {
// NotFound,
// ConnectionFailed,
// InvalidData(String),
// Unexpected(String),
// }
// impl std::fmt::Display for RepositoryError {
// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// write!(f, "{:?}", self)
// }
// }
// impl std::error::Error for RepositoryError {}
use thiserror::Error;
// #[derive(Error, Debug)]
// pub enum RepositoryError {
// #[error("Database connection failed")]
// ConnectionFailed(#[source] sqlx::Error),
// #[error("Database query failed: {0}")]
// QueryFailed(#[source] sqlx::Error), //TODO: sqlx id infrastructure
// #[error("Dictionary '{0}' not found")]
// NotFound(String),
// #[error("Invalid data encountered")]
// InvalidData,
// }
#[derive(Error, Debug)]
pub enum RepositoryError {
#[error("Database connection failed")]
ConnectionFailed,
#[error("Dictionary '{0}' not found")]
NotFound(String),
#[error("Storage error: {0}")]
StorageError(String),
}

2
lib/src/application/services.rs

@ -1,4 +1,4 @@
use crate::application::traits::{DictRepository, DictSource}; use crate::core::traits::{DictRepository, DictSource};
pub struct DictImporter<'a, R> { pub struct DictImporter<'a, R> {
repo: &'a R, repo: &'a R,

46
lib/src/application/traits.rs

@ -1,47 +1 @@
use crate::{
application::errors::RepositoryError,
core::entities::{Dict, DictEntry},
};
// pub trait DictRepository {
// fn create(&self, name: &str) -> Result<(), RepositoryError>;
// // Batch saving is usually much faster than 1-by-1 for SQL
// fn save_entries(&self, dict_name: &str, entries: &[DictEntry]) -> Result<(), RepositoryError>;
// fn fetch_many(
// &self,
// name: &str,
// limit: Option<u32>,
// offset: Option<u32>,
// ) -> Result<Dict, RepositoryError>;
// // Get the next available ID for a dictionary
// fn get_next_id(&self, dict_name: &str) -> Result<u32, RepositoryError>;
// }
#[async_trait::async_trait]
pub trait DictRepository: Send + Sync {
async fn create(&self, name: &str) -> Result<(), RepositoryError>;
/// "Upsert" logic:
/// - If entry exists (by text), update metadata.
/// - If not, insert new.
/// - IDs are handled by the Database.
async fn save_entries(
&self,
dict_name: &str,
entries: &[DictEntry],
) -> Result<(), RepositoryError>;
/// Fetch a page of entries.
async fn fetch_many(
&self,
name: &str,
limit: Option<u32>,
offset: Option<u32>,
) -> Result<Dict, RepositoryError>;
}
pub trait DictSource {
fn next_entry(&mut self) -> Option<Result<DictEntry, anyhow::Error>>;
}

9
lib/src/core/entities.rs

@ -36,3 +36,12 @@ impl Dict {
self.entries.insert(entry.id.unwrap(), entry); self.entries.insert(entry.id.unwrap(), entry);
} }
} }
// pub struct DecodedItem {
// pub value: String,
// }
// pub struct DecodedResult {
// pub input: String,
// pub output: Vec<DecodedItem>,
// }

24
lib/src/core/errors.rs

@ -1,15 +1,11 @@
// use std::fmt; use thiserror::Error;
// #[derive(Debug)] #[derive(Error, Debug)]
// pub enum RepositoryError { pub enum RepositoryError {
// NotFound, #[error("Data source connection failed")]
// ConnectionFailed, ConnectionFailed,
// InvalidData(String), #[error("Dictionary '{0}' not found")]
// Unexpected(String), NotFound(String),
// } #[error("Storage error: {0}")]
StorageError(String),
// impl fmt::Display for RepositoryError { }
// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// write!(f, "{:?}", self)
// }
// }

219
lib/src/core/sys_major/rules_pl.rs

@ -3,13 +3,220 @@ use super::encoder::{Rule, Rules};
pub fn get_rules() -> Rules { pub fn get_rules() -> Rules {
vec![ vec![
Rule { Rule {
phoneme_in: "PL".to_string(), not_after: vec![],
only_after: vec![],
phoneme_in: "S".to_string(),
phoneme_out: "0".to_string(),
not_before: vec!["I".to_string(), "Z".to_string()],
only_before: vec![],
},
Rule {
not_after: vec![
"C".to_string(),
"D".to_string(),
"R".to_string(),
"S".to_string(),
],
only_after: vec![],
phoneme_in: "Z".to_string(),
phoneme_out: "0".to_string(),
not_before: vec!["I".to_string()],
only_before: vec![],
},
Rule {
not_after: vec![],
only_after: vec![],
phoneme_in: "T".to_string(),
phoneme_out: "1".to_string(),
not_before: vec![],
only_before: vec![],
},
Rule {
only_after: vec![],
not_after: vec![],
phoneme_in: "D".to_string(),
phoneme_out: "1".to_string(),
not_before: vec!["Z".to_string(), "Ź".to_string(), "Ż".to_string()],
only_before: vec![],
},
Rule {
not_after: vec![],
only_after: vec![],
phoneme_in: "N".to_string(),
phoneme_out: "2".to_string(), phoneme_out: "2".to_string(),
not_after: vec!["Y".to_string()], not_before: vec!["I".to_string()],
not_before: vec!["X".to_string()], only_before: vec![],
only_after: vec!["A".to_string()], },
only_before: vec!["C".to_string()], Rule {
not_after: vec![],
only_after: vec![],
phoneme_in: "M".to_string(),
phoneme_out: "3".to_string(),
not_before: vec![],
only_before: vec![],
},
Rule {
not_after: vec![],
only_after: vec![],
phoneme_in: "R".to_string(),
phoneme_out: "4".to_string(),
not_before: vec!["Z".to_string()],
only_before: vec![],
},
Rule {
not_after: vec![],
only_after: vec![],
phoneme_in: "L".to_string(),
phoneme_out: "5".to_string(),
not_before: vec![],
only_before: vec![],
},
Rule {
not_after: vec![],
only_after: vec![],
phoneme_in: "J".to_string(),
phoneme_out: "6".to_string(),
not_before: vec![],
only_before: vec![],
},
Rule {
not_after: vec![],
only_after: vec![],
phoneme_in: "K".to_string(),
phoneme_out: "7".to_string(),
not_before: vec![],
only_before: vec![],
},
Rule {
not_after: vec![],
only_after: vec![],
phoneme_in: "G".to_string(),
phoneme_out: "7".to_string(),
not_before: vec![],
only_before: vec![],
},
Rule {
not_after: vec![],
only_after: vec![],
phoneme_in: "F".to_string(),
phoneme_out: "8".to_string(),
not_before: vec![],
only_before: vec![],
},
Rule {
not_after: vec![],
only_after: vec![],
phoneme_in: "W".to_string(),
phoneme_out: "8".to_string(),
not_before: vec![],
only_before: vec![],
},
Rule {
not_after: vec![],
only_after: vec![],
phoneme_in: "P".to_string(),
phoneme_out: "9".to_string(),
not_before: vec![],
only_before: vec![],
},
Rule {
not_after: vec![],
only_after: vec![],
phoneme_in: "B".to_string(),
phoneme_out: "9".to_string(),
not_before: vec![],
only_before: vec![],
}, },
// ...more entries...
] ]
} }
#[cfg(test)]
mod tests {
use super::*;
use crate::SystemEncoder;
use crate::core::sys_major::Encoder;
#[test]
fn test_major_dict_pl_encode_0_1() {
let encoder = Encoder::new(get_rules());
let output = encoder.encode("SZSCZ");
assert_eq!(output, "0")
}
#[test]
fn test_major_dict_pl_encode_0_2() {
let encoder = Encoder::new(get_rules());
let output = encoder.encode("SZSICZ");
assert_eq!(output, "")
}
#[test]
fn test_major_dict_pl_encode_0_3() {
let encoder = Encoder::new(get_rules());
let output = encoder.encode("SZCZRZZCZDZSZ");
assert_eq!(output, "0")
}
#[test]
fn test_major_dict_pl_encode_0_4() {
let encoder = Encoder::new(get_rules());
let output = encoder.encode("SZCZRZZICZDZSZ");
assert_eq!(output, "")
}
#[test]
fn test_major_dict_pl_encode_1_1() {
let encoder = Encoder::new(get_rules());
let output = encoder.encode("SZTCZ");
assert_eq!(output, "1")
}
#[test]
fn test_major_dict_pl_encode_1_2() {
let encoder = Encoder::new(get_rules());
let output = encoder.encode("DZDŻDŹDDZDŻDŹ");
assert_eq!(output, "1")
}
#[test]
fn test_major_dict_pl_encode_1_3() {
let encoder = Encoder::new(get_rules());
let output = encoder.encode("DZDŻDŹDZDZDŻDŹ");
assert_eq!(output, "")
}
#[test]
fn test_major_dict_pl_encode_2_1() {
let encoder = Encoder::new(get_rules());
let output = encoder.encode("NINNI");
assert_eq!(output, "2")
}
#[test]
fn test_major_dict_pl_encode_2_2() {
let encoder = Encoder::new(get_rules());
let output = encoder.encode("NININI");
assert_eq!(output, "")
}
#[test]
fn test_major_dict_pl_encode_4_1() {
let encoder = Encoder::new(get_rules());
let output = encoder.encode("RZRRZ");
assert_eq!(output, "4")
}
#[test]
fn test_major_dict_pl_encode_4_2() {
let encoder = Encoder::new(get_rules());
let output = encoder.encode("RZRZRZ");
assert_eq!(output, "")
}
#[test]
fn test_major_dict_pl_encode_full_1() {
let encoder = Encoder::new(get_rules());
let output = encoder.encode("ATADANAMARALAJAKAGAFAWAPABA");
assert_eq!(output, "1123456778899")
}
}

41
lib/src/core/traits.rs

@ -1,15 +1,38 @@
use super::entities::{Dict, DictEntry};
use super::errors::RepositoryError;
pub trait SystemEncoder { pub trait SystemEncoder {
fn encode(&self, word: &str) -> String; fn encode(&self, word: &str) -> String;
} }
// pub trait WordRepository { // pub trait SystenDecoder {
// fn save(word: &WordEntry) -> Result<WordEntryId, RepositoryError>; // fn initialize(&self) -> Result<(), anyhow::Error>;
// fn save_many(words: &Vec<WordEntry>) -> Result<(), RepositoryError>;
// fn fetch(id: WordEntryId) -> Result<WordEntry, RepositoryError>;
// fn fetch_many(ids: &Vec<WordEntryId>) -> Result<Vec<WordEntry>, RepositoryError>;
// }
// pub trait DictRepository {
// fn save(dict: &Dict) -> Result<(), RepositoryError>;
// fn fetch(name: &str) -> Result<Dict, RepositoryError>;
// } // }
#[async_trait::async_trait]
pub trait DictRepository: Send + Sync {
async fn create(&self, name: &str) -> Result<(), RepositoryError>;
/// "Upsert" logic:
/// - If entry exists (by text), update metadata.
/// - If not, insert new.
/// - IDs are handled by the Database.
async fn save_entries(
&self,
dict_name: &str,
entries: &[DictEntry],
) -> Result<(), RepositoryError>;
/// Fetch a page of entries.
async fn fetch_many(
&self,
name: &str,
limit: Option<u32>,
offset: Option<u32>,
) -> Result<Dict, RepositoryError>;
}
pub trait DictSource {
fn next_entry(&mut self) -> Option<Result<DictEntry, anyhow::Error>>;
}

2
lib/src/infrastructure/json_file_dict_source.rs

@ -1,5 +1,5 @@
use crate::application::traits::DictSource;
use crate::core::entities::DictEntry; use crate::core::entities::DictEntry;
use crate::core::traits::DictSource;
use serde::Deserialize; use serde::Deserialize;
use std::collections::HashMap; use std::collections::HashMap;
use std::fs::File; use std::fs::File;

8
lib/src/infrastructure/sqlite_dict_repository.rs

@ -1,12 +1,10 @@
use crate::application::errors::RepositoryError; use crate::core::entities::{Dict, DictEntry};
use crate::application::traits::DictRepository; use crate::core::errors::RepositoryError;
use crate::core::entities::{Dict, DictEntry, DictEntryId}; use crate::core::traits::DictRepository;
use sqlx::{Row, SqlitePool, sqlite::SqliteConnectOptions}; use sqlx::{Row, SqlitePool, sqlite::SqliteConnectOptions};
use std::collections::HashMap; use std::collections::HashMap;
use std::str::FromStr; use std::str::FromStr;
// --- DTO: Data Transfer Object ---
// This struct exists ONLY to talk to the database.
#[derive(sqlx::FromRow)] #[derive(sqlx::FromRow)]
struct SqliteEntryDto { struct SqliteEntryDto {
id: i64, id: i64,

2
lib/src/presentation/cli/commands/import_dict.rs

@ -1,5 +1,5 @@
use crate::application::traits::DictRepository;
use crate::application::{config::ImportDictConfig, services::DictImporter}; use crate::application::{config::ImportDictConfig, services::DictImporter};
use crate::core::traits::DictRepository;
use crate::infrastructure::json_file_dict_source::JsonFileDictSource; use crate::infrastructure::json_file_dict_source::JsonFileDictSource;
use tracing::{debug, error, info}; use tracing::{debug, error, info};

Loading…
Cancel
Save