Browse Source

WIP: refactor

develop-refactor
chodak166 4 months ago
parent
commit
c8c6cfd57f
  1. 3
      app/src/app.rs
  2. 5
      app/src/cli.rs
  3. 168
      app/src/cli/args.rs
  4. 4
      app/src/cli/commands.rs
  5. 22
      app/src/cli/commands/decode.rs
  6. 36
      app/src/cli/commands/encode.rs
  7. 12
      app/src/cli/commands/import_dict.rs
  8. 6
      app/src/cli/commands/server.rs
  9. 81
      app/src/cli/handlers.rs
  10. 14
      app/src/cli/traits.rs
  11. 81
      app/src/commands.rs
  12. 64
      app/src/commands/decode.rs
  13. 83
      app/src/commands/encode.rs
  14. 57
      app/src/commands/import_dict.rs
  15. 60
      app/src/commands/server.rs
  16. 6
      app/src/config.rs
  17. 0
      app/src/defaults.rs
  18. 3
      app/src/main.rs
  19. 2
      lib/src/core/sys_major/encoder.rs
  20. 54
      lib/src/core/sys_major/lvmap.rs
  21. 2
      lib/src/infrastructure/sqlite_dict_repository.rs
  22. 8612
      resources/dsr1ll70_pl_demo.json
  23. 12
      resources/example_dict.json

3
app/src/app.rs

@ -1,5 +1,4 @@
use crate::cli::args::{CliArgs, Command};
use crate::cli::handlers::resolve_command;
use crate::commands::{CliArgs, Command, resolve_command};
use crate::config::AppConfig;
use crate::container::Container;
use anyhow::Result;

5
app/src/cli.rs

@ -1,5 +0,0 @@
pub mod args;
pub mod commands;
pub mod defaults;
pub mod handlers;
pub mod traits;

168
app/src/cli/args.rs

@ -1,168 +0,0 @@
use crate::cli::defaults;
use crate::cli::traits::ConfigurableCommand;
use anyhow::Result;
use clap::{Args as ClapArgs, Parser, Subcommand};
use config::ConfigBuilder;
use config::builder::DefaultState;
use std::path::PathBuf;
#[derive(Parser, Debug)]
#[command(author, version, about)]
pub struct CliArgs {
#[command(flatten)]
pub global: GlobalArgs,
#[command(subcommand)]
pub command: Command,
}
#[derive(ClapArgs, Debug)]
pub struct GlobalArgs {
/// Path to config file
#[arg(short, long, default_value = "config.toml")]
pub config: PathBuf,
#[arg(long, help = defaults::HELP_LOG)]
pub log_level: Option<String>,
}
#[derive(Subcommand, Debug, Clone)]
pub enum Command {
/// Start the application server
Server(ServerArgs),
/// Decode a word using given system
Decode(DecodeArgs),
/// Encode a number using given system
Encode(EncodeArgs),
/// Import dictionary
ImportDict(ImportDictArgs),
}
#[derive(ClapArgs, Debug, Clone)]
pub struct ServerArgs {
#[arg(short, long, help = defaults::HELP_PORT)]
pub port: Option<u16>,
}
impl ConfigurableCommand for ServerArgs {
fn apply_defaults(
&self,
builder: ConfigBuilder<DefaultState>,
) -> Result<ConfigBuilder<DefaultState>> {
builder
.set_default("server.host", defaults::HOST)?
.set_default("server.port", defaults::PORT)
.map_err(Into::into)
}
fn apply_overrides(
&self,
builder: ConfigBuilder<DefaultState>,
) -> Result<ConfigBuilder<DefaultState>> {
let mut builder = builder;
if let Some(port) = self.port {
builder = builder.set_override("server.port", port)?;
}
Ok(builder)
}
}
#[derive(ClapArgs, Debug, Clone)]
pub struct DecodeArgs {
#[arg(long, help = defaults::HELP_DEC_SYSTEM)]
pub system: Option<String>,
#[arg(long, help = defaults::HELP_DEC_INPUT)]
pub input: String,
}
impl ConfigurableCommand for DecodeArgs {
fn apply_defaults(
&self,
builder: ConfigBuilder<DefaultState>,
) -> Result<ConfigBuilder<DefaultState>> {
builder
.set_default("decoder.system", defaults::SYSTEM_NAME)?
.set_default("decoder.input", "")
.map_err(Into::into)
}
fn apply_overrides(
&self,
builder: ConfigBuilder<DefaultState>,
) -> Result<ConfigBuilder<DefaultState>> {
let mut builder = builder;
if let Some(ref system) = self.system {
builder = builder.set_override("decoder.system", system.clone())?;
}
builder = builder.set_override("decoder.input", self.input.clone())?;
Ok(builder)
}
}
#[derive(ClapArgs, Debug, Clone)]
pub struct EncodeArgs {
#[arg(long, help = defaults::HELP_ENC_SYSTEM)]
pub system: Option<String>,
#[arg(long, help = defaults::HELP_ENC_INPUT)]
pub input: String,
}
impl ConfigurableCommand for EncodeArgs {
fn apply_defaults(
&self,
builder: ConfigBuilder<DefaultState>,
) -> Result<ConfigBuilder<DefaultState>> {
builder
.set_default("encoder.system", defaults::SYSTEM_NAME)?
.set_default("encoder.input", "")
.map_err(Into::into)
}
fn apply_overrides(
&self,
builder: ConfigBuilder<DefaultState>,
) -> Result<ConfigBuilder<DefaultState>> {
let mut builder = builder;
if let Some(ref system) = self.system {
builder = builder.set_override("encoder.system", system.clone())?;
}
builder = builder.set_override("encoder.input", self.input.clone())?;
Ok(builder)
}
}
#[derive(ClapArgs, Debug, Clone)]
pub struct ImportDictArgs {
#[arg(long, help = defaults::HELP_IMPORT_DICT_NAME)]
pub name: String,
#[arg(long, help = defaults::HELP_IMPORT_DICT_INPUT)]
pub path: String,
}
impl ConfigurableCommand for ImportDictArgs {
fn apply_defaults(
&self,
builder: ConfigBuilder<DefaultState>,
) -> Result<ConfigBuilder<DefaultState>> {
builder
.set_default("import_dict.name", defaults::IMPORT_DICT_NAME)?
.set_default("import_dict.path", defaults::IMPORT_DICT_PATH)
.map_err(Into::into)
}
fn apply_overrides(
&self,
builder: ConfigBuilder<DefaultState>,
) -> Result<ConfigBuilder<DefaultState>> {
builder
.set_override("import_dict.name", self.name.clone())?
.set_override("import_dict.path", self.path.clone())
.map_err(Into::into)
}
}

4
app/src/cli/commands.rs

@ -1,4 +0,0 @@
pub mod decode;
pub mod encode;
pub mod import_dict;
pub mod server;

22
app/src/cli/commands/decode.rs

@ -1,22 +0,0 @@
use applib::application::config::DecoderConfig;
use applib::core::sys_major::decoder::Decoder;
use applib::core::sys_major::{self as major, LenValueMap};
use applib::core::traits::SystemDecoder;
use applib::system::System;
use std::sync::Arc;
pub async fn run(config: DecoderConfig) {
let decoder: Box<dyn SystemDecoder> = match config.system {
System::MajorPl => Box::new(Decoder::new(major::rules_pl::get_rules())),
System::MajorEn => Box::new(Decoder::new(major::rules_en::get_rules())),
// _ => {
// eprintln!("Unknown system: {:?}", config.system);
// return;
// }
};
match decoder.decode(&config.input) {
Ok(result) => println!("{:?}", result),
Err(e) => eprintln!("Error: {}", e),
}
}

36
app/src/cli/commands/encode.rs

@ -1,36 +0,0 @@
use applib::application::config::EncoderConfig;
use applib::core::sys_major::encoder::Encoder;
use applib::core::sys_major::{self as major, LenValueMap};
use applib::core::traits::{DictRepository, SystemEncoder};
use applib::system::System;
use tracing::debug;
pub async fn run(config: EncoderConfig, dict: &dyn DictRepository) {
debug!("Running encoder with config {:?}", config);
let system_encoder: Box<dyn SystemEncoder> = match config.system {
System::MajorPl | System::MajorEn => {
let decoder = major::Decoder::new(match config.system {
System::MajorPl => major::rules_pl::get_rules(),
System::MajorEn => major::rules_en::get_rules(),
// _ => unreachable!(),
});
let stream = dict.stream_batches(100).await.unwrap();
let lvmap = LenValueMap::from_stream(stream, &decoder).await.unwrap();
Box::new(Encoder::new(lvmap))
} // _ => {
// eprintln!("Unknown system: {:?}", config.system);
// return;
// }
};
let result = system_encoder.encode(&config.input);
match result {
Ok(res) => {
let json = serde_json::to_string_pretty(&res).expect("JSON serialization failed");
println!("{}", json);
}
Err(e) => eprintln!("Error encoding: {:?}", e),
}
}

12
app/src/cli/commands/import_dict.rs

@ -1,12 +0,0 @@
use anyhow::Result;
use applib::DictImporter;
use applib::application::config::ImportDictConfig;
pub async fn run(config: ImportDictConfig, importer: DictImporter) -> Result<()> {
// Importer expects an impl DictSource
// We need to create a DictSource from the path
use applib::infrastructure::json_file_dict_source::JsonFileDictSource;
let source = JsonFileDictSource::new(&config.path)?;
importer.import(source).await?;
Ok(())
}

6
app/src/cli/commands/server.rs

@ -1,6 +0,0 @@
use applib::application::config::ServerConfig;
use std::future::Future;
pub async fn run(config: ServerConfig, signal: impl Future<Output = ()> + Send + 'static) {
applib::presentation::server::run(config, signal).await;
}

81
app/src/cli/handlers.rs

@ -1,81 +0,0 @@
use crate::cli::args::{Command, DecodeArgs, EncodeArgs, ImportDictArgs, ServerArgs};
use crate::cli::commands;
use crate::cli::traits::ConfigurableCommand;
use crate::config::AppConfig;
use crate::container::Container;
use anyhow::Result;
use async_trait::async_trait;
use tokio::signal;
use tracing::{info, warn};
#[async_trait]
pub trait CommandExecutor {
async fn execute(&self, config: &AppConfig, container: &Container) -> Result<()>;
}
// AppCommand must be dyn-compatible. ConfigurableCommand is already dyn-compatible.
// CommandExecutor is dyn-compatible because of #[async_trait].
pub trait AppCommand: ConfigurableCommand + CommandExecutor {}
impl<T: ConfigurableCommand + CommandExecutor> AppCommand for T {}
pub fn resolve_command(command: &Command) -> &dyn AppCommand {
match command {
Command::Server(args) => args,
Command::Decode(args) => args,
Command::Encode(args) => args,
Command::ImportDict(args) => args,
}
}
#[async_trait]
impl CommandExecutor for ServerArgs {
async fn execute(&self, config: &AppConfig, _container: &Container) -> Result<()> {
let config = config.server.as_ref().expect("Server config not set");
commands::server::run(config.clone(), wait_for_shutdown_signal()).await;
Ok(())
}
}
#[async_trait]
impl CommandExecutor for DecodeArgs {
async fn execute(&self, config: &AppConfig, _container: &Container) -> Result<()> {
let config = config.decoder.as_ref().expect("Decoder config not set");
commands::decode::run(config.clone()).await;
Ok(())
}
}
#[async_trait]
impl CommandExecutor for EncodeArgs {
async fn execute(&self, config: &AppConfig, container: &Container) -> Result<()> {
let config = config.encoder.as_ref().expect("Encoder config not set");
let repo = container.create_dict_repo("demo_pl").await?;
commands::encode::run(config.clone(), repo.as_ref()).await;
Ok(())
}
}
#[async_trait]
impl CommandExecutor for ImportDictArgs {
async fn execute(&self, config: &AppConfig, container: &Container) -> Result<()> {
let config = config
.import_dict
.as_ref()
.expect("ImportDict config not set");
let importer = container.create_dict_importer(&config.name).await?;
commands::import_dict::run(config.clone(), importer).await?;
Ok(())
}
}
async fn wait_for_shutdown_signal() {
match signal::ctrl_c().await {
Ok(()) => {
info!("Received shutdown signal (SIGINT/SIGTERM)");
}
Err(err) => {
warn!("Failed to listen for shutdown signal: {}", err);
}
}
}

14
app/src/cli/traits.rs

@ -1,14 +0,0 @@
use anyhow::Result;
pub use config::ConfigBuilder;
pub use config::builder::DefaultState;
pub trait ConfigurableCommand {
fn apply_defaults(
&self,
builder: ConfigBuilder<DefaultState>,
) -> Result<ConfigBuilder<DefaultState>>;
fn apply_overrides(
&self,
builder: ConfigBuilder<DefaultState>,
) -> Result<ConfigBuilder<DefaultState>>;
}

81
app/src/commands.rs

@ -0,0 +1,81 @@
pub mod decode;
pub mod encode;
pub mod import_dict;
pub mod server;
use crate::config::AppConfig;
use crate::container::Container;
use crate::defaults;
use anyhow::Result;
use async_trait::async_trait;
use clap::Subcommand;
use clap::{Args as ClapArgs, Parser};
use config::ConfigBuilder;
use config::builder::DefaultState;
use std::path::PathBuf;
#[derive(Subcommand, Debug, Clone)]
pub enum Command {
/// Start the application server
Server(server::ServerArgs),
/// Decode a word using given system
Decode(decode::DecodeArgs),
/// Encode a number using given system
Encode(encode::EncodeArgs),
/// Import dictionary
ImportDict(import_dict::ImportDictArgs),
}
pub fn resolve_command(command: &Command) -> &dyn AppCommand {
match command {
Command::Server(args) => args,
Command::Decode(args) => args,
Command::Encode(args) => args,
Command::ImportDict(args) => args,
}
}
#[derive(Parser, Debug)]
#[command(author, version, about)]
pub struct CliArgs {
#[command(flatten)]
pub global: GlobalArgs,
#[command(subcommand)]
pub command: Command,
}
#[derive(ClapArgs, Debug)]
pub struct GlobalArgs {
/// Path to config file
#[arg(short, long, default_value = "config.toml")]
pub config: PathBuf,
#[arg(long, help = defaults::HELP_LOG)]
pub log_level: Option<String>,
}
pub trait ConfigurableCommand {
fn apply_defaults(
&self,
builder: ConfigBuilder<DefaultState>,
) -> Result<ConfigBuilder<DefaultState>>;
fn apply_overrides(
&self,
builder: ConfigBuilder<DefaultState>,
) -> Result<ConfigBuilder<DefaultState>>;
}
#[async_trait]
pub trait CommandExecutor {
async fn execute(&self, config: &AppConfig, container: &Container) -> Result<()>;
}
// AppCommand must be dyn-compatible. ConfigurableCommand is already dyn-compatible.
// CommandExecutor is dyn-compatible because of #[async_trait].
pub trait AppCommand: ConfigurableCommand + CommandExecutor {}
impl<T: ConfigurableCommand + CommandExecutor> AppCommand for T {}

64
app/src/commands/decode.rs

@ -0,0 +1,64 @@
use crate::commands::{ClapArgs, CommandExecutor, ConfigurableCommand};
use crate::config::AppConfig;
use crate::container::Container;
use crate::defaults;
use anyhow::Result;
use applib::core::sys_major::decoder::Decoder;
use applib::core::sys_major::{self as major};
use applib::core::traits::SystemDecoder;
use applib::system::System;
use async_trait::async_trait;
use config::ConfigBuilder;
use config::builder::DefaultState;
#[derive(ClapArgs, Debug, Clone)]
pub struct DecodeArgs {
#[arg(long, help = defaults::HELP_DEC_SYSTEM)]
pub system: Option<String>,
#[arg(long, help = defaults::HELP_DEC_INPUT)]
pub input: String,
}
impl ConfigurableCommand for DecodeArgs {
fn apply_defaults(
&self,
builder: ConfigBuilder<DefaultState>,
) -> Result<ConfigBuilder<DefaultState>> {
builder
.set_default("decoder.system", defaults::SYSTEM_NAME)?
.set_default("decoder.input", "")
.map_err(Into::into)
}
fn apply_overrides(
&self,
builder: ConfigBuilder<DefaultState>,
) -> Result<ConfigBuilder<DefaultState>> {
let mut builder = builder;
if let Some(ref system) = self.system {
builder = builder.set_override("decoder.system", system.clone())?;
}
builder = builder.set_override("decoder.input", self.input.clone())?;
Ok(builder)
}
}
#[async_trait]
impl CommandExecutor for DecodeArgs {
async fn execute(&self, config: &AppConfig, _container: &Container) -> Result<()> {
let config = config.decoder.as_ref().expect("Decoder config not set");
let decoder: Box<dyn SystemDecoder> = match config.system {
System::MajorPl => Box::new(Decoder::new(major::rules_pl::get_rules())),
System::MajorEn => Box::new(Decoder::new(major::rules_en::get_rules())),
};
match decoder.decode(&config.input) {
Ok(result) => println!("{:?}", result),
Err(e) => eprintln!("Error: {}", e),
}
Ok(()) // TODO: Map decode result
}
}

83
app/src/commands/encode.rs

@ -0,0 +1,83 @@
use applib::core::sys_major::encoder::Encoder;
use applib::core::sys_major::{self as major, LenValueMap};
use applib::core::traits::SystemEncoder;
use applib::system::System;
use tracing::debug;
use crate::commands::{ClapArgs, CommandExecutor, ConfigurableCommand};
use crate::config::AppConfig;
use crate::container::Container;
use crate::defaults;
use anyhow::Result;
use async_trait::async_trait;
use config::ConfigBuilder;
use config::builder::DefaultState;
#[derive(ClapArgs, Debug, Clone)]
pub struct EncodeArgs {
#[arg(long, help = defaults::HELP_ENC_SYSTEM)]
pub system: Option<String>,
#[arg(long, help = defaults::HELP_ENC_INPUT)]
pub input: String,
}
impl ConfigurableCommand for EncodeArgs {
fn apply_defaults(
&self,
builder: ConfigBuilder<DefaultState>,
) -> Result<ConfigBuilder<DefaultState>> {
builder
.set_default("encoder.system", defaults::SYSTEM_NAME)?
.set_default("encoder.input", "")
.map_err(Into::into)
}
fn apply_overrides(
&self,
builder: ConfigBuilder<DefaultState>,
) -> Result<ConfigBuilder<DefaultState>> {
let mut builder = builder;
if let Some(ref system) = self.system {
builder = builder.set_override("encoder.system", system.clone())?;
}
builder = builder.set_override("encoder.input", self.input.clone())?;
Ok(builder)
}
}
#[async_trait]
impl CommandExecutor for EncodeArgs {
async fn execute(&self, config: &AppConfig, container: &Container) -> Result<()> {
let config = config.encoder.as_ref().expect("Encoder config not set");
let repo = container.create_dict_repo("demo_pl").await?;
debug!("Running encoder with config {:?}", config);
let system_encoder: Box<dyn SystemEncoder> = match config.system {
System::MajorPl | System::MajorEn => {
let decoder = major::Decoder::new(match config.system {
System::MajorPl => major::rules_pl::get_rules(),
System::MajorEn => major::rules_en::get_rules(),
// _ => unreachable!(),
});
let stream = repo.stream_batches(100).await.unwrap();
let lvmap = LenValueMap::from_stream(stream, &decoder).await.unwrap();
Box::new(Encoder::new(lvmap))
}
};
let result = system_encoder.encode(&config.input);
match result {
Ok(res) => {
let json = serde_json::to_string_pretty(&res).expect("JSON serialization failed");
println!("{}", json);
}
Err(e) => eprintln!("Error encoding: {:?}", e),
}
Ok(())
}
}

57
app/src/commands/import_dict.rs

@ -0,0 +1,57 @@
use crate::commands::{ClapArgs, CommandExecutor, ConfigurableCommand};
use crate::config::AppConfig;
use crate::container::Container;
use crate::defaults;
use anyhow::Result;
use async_trait::async_trait;
use config::ConfigBuilder;
use config::builder::DefaultState;
#[derive(ClapArgs, Debug, Clone)]
pub struct ImportDictArgs {
#[arg(long, help = defaults::HELP_IMPORT_DICT_NAME)]
pub name: String,
#[arg(long, help = defaults::HELP_IMPORT_DICT_INPUT)]
pub path: String,
}
impl ConfigurableCommand for ImportDictArgs {
fn apply_defaults(
&self,
builder: ConfigBuilder<DefaultState>,
) -> Result<ConfigBuilder<DefaultState>> {
builder
.set_default("import_dict.name", defaults::IMPORT_DICT_NAME)?
.set_default("import_dict.path", defaults::IMPORT_DICT_PATH)
.map_err(Into::into)
}
fn apply_overrides(
&self,
builder: ConfigBuilder<DefaultState>,
) -> Result<ConfigBuilder<DefaultState>> {
builder
.set_override("import_dict.name", self.name.clone())?
.set_override("import_dict.path", self.path.clone())
.map_err(Into::into)
}
}
#[async_trait]
impl CommandExecutor for ImportDictArgs {
async fn execute(&self, config: &AppConfig, container: &Container) -> Result<()> {
let config = config
.import_dict
.as_ref()
.expect("ImportDict config not set");
let importer = container.create_dict_importer(&config.name).await?;
// Importer expects an impl DictSource
// We need to create a DictSource from the path
use applib::infrastructure::json_file_dict_source::JsonFileDictSource;
let source = JsonFileDictSource::new(&config.path)?;
importer.import(source).await?;
Ok(())
}
}

60
app/src/commands/server.rs

@ -0,0 +1,60 @@
use crate::commands::{ClapArgs, CommandExecutor, ConfigurableCommand};
use crate::config::AppConfig;
use crate::container::Container;
use crate::defaults;
use anyhow::Result;
use async_trait::async_trait;
use config::ConfigBuilder;
use config::builder::DefaultState;
use tokio::signal;
use tracing::{info, warn};
#[derive(ClapArgs, Debug, Clone)]
pub struct ServerArgs {
#[arg(short, long, help = defaults::HELP_PORT)]
pub port: Option<u16>,
}
impl ConfigurableCommand for ServerArgs {
fn apply_defaults(
&self,
builder: ConfigBuilder<DefaultState>,
) -> Result<ConfigBuilder<DefaultState>> {
builder
.set_default("server.host", defaults::HOST)?
.set_default("server.port", defaults::PORT)
.map_err(Into::into)
}
fn apply_overrides(
&self,
builder: ConfigBuilder<DefaultState>,
) -> Result<ConfigBuilder<DefaultState>> {
let mut builder = builder;
if let Some(port) = self.port {
builder = builder.set_override("server.port", port)?;
}
Ok(builder)
}
}
#[async_trait]
impl CommandExecutor for ServerArgs {
async fn execute(&self, config: &AppConfig, _container: &Container) -> Result<()> {
let config = config.server.as_ref().expect("Server config not set");
applib::presentation::server::run(config.clone(), wait_for_shutdown_signal()).await;
Ok(())
}
}
async fn wait_for_shutdown_signal() {
match signal::ctrl_c().await {
Ok(()) => {
info!("Received shutdown signal (SIGINT/SIGTERM)");
}
Err(err) => {
warn!("Failed to listen for shutdown signal: {}", err);
}
}
}

6
app/src/config.rs

@ -1,11 +1,9 @@
use crate::commands::{ConfigurableCommand, GlobalArgs};
use anyhow::{Context, Result};
use applib::application::config::*;
use config::{Config, Environment, File};
use serde::Deserialize;
use crate::cli::args::GlobalArgs;
use crate::cli::traits::ConfigurableCommand;
use applib::application::config::*;
#[derive(Debug, Deserialize, Clone)]
pub struct AppConfig {
#[serde(default)]

0
app/src/cli/defaults.rs → app/src/defaults.rs

3
app/src/main.rs

@ -1,7 +1,8 @@
mod app;
pub mod cli;
mod commands;
mod config;
mod container;
mod defaults;
use anyhow::Result;
use app::Application;

2
lib/src/core/sys_major/encoder.rs

@ -1,5 +1,3 @@
use core::num;
use crate::core::{
entities::{EncodedPart, EncodedSplit, EncodedValue},
errors::CodecError,

54
lib/src/core/sys_major/lvmap.rs

@ -1,10 +1,10 @@
use crate::core::{
DictRepository, SystemDecoder,
SystemDecoder,
entities::DecodedLength,
errors::{CodecError, RepositoryError},
};
use futures::{Stream, StreamExt, TryStreamExt};
use std::{collections::HashMap, hash::Hash, num::ParseIntError};
use futures::{Stream, StreamExt};
use std::{collections::HashMap, num::ParseIntError};
use thiserror::Error;
// We store words by encoded number length, then encoded value
@ -20,9 +20,6 @@ use thiserror::Error;
// - 45:
// - word: oral
// Words are fetched from DictRepository in batches
const DEFAULT_DICT_BATCH_SIZE: usize = 100;
#[derive(Error, Debug)]
pub enum LenValueMapError {
#[error("value parsing error: {0}")]
@ -137,12 +134,10 @@ impl LenValueMap {
mod tests {
use super::*;
use crate::core::{entities::*, errors::*};
use async_trait::async_trait;
use futures::stream;
use std::collections::HashMap;
use mockall::{Sequence, automock};
use mockall::{mock, predicate::*};
const TEST_WORD_1: &str = "test_word_1";
@ -293,16 +288,6 @@ mod tests {
// --- build ---
fn dict_with_words(words: &[&str]) -> Dict {
let mut dict = Dict::new("default".into());
for (i, word) in words.iter().enumerate() {
dict.add_entry(DictEntry::new(Some(i as u64), word.to_string()));
}
dict
}
#[tokio::test]
async fn test_from_stream_success() {
// 1. Setup Mocks (Same as before)
@ -362,37 +347,4 @@ mod tests {
),
}
}
// #[tokio::test]
// async fn test_build_multiple_batches() {
// let mut repo = MockRepo::new();
// let mut decoder = MockDecoder::new();
// let mut seq = Sequence::new();
// decoder
// .expect_decode()
// .returning(|word| mock_decoding(word));
// repo.expect_fetch_many()
// .times(1) // Explicitly expect 1 call
// .in_sequence(&mut seq) // Enforce order
// .returning(|_, _| Ok(dict_with_words(&[TEST_WORD_1])));
// repo.expect_fetch_many()
// .times(1) // Explicitly expect 1 call
// .in_sequence(&mut seq) // Enforce order
// .returning(|_, _| Ok(dict_with_words(&[TEST_WORD_3]))); // word with different decoded length
// repo.expect_fetch_many()
// .times(1)
// .in_sequence(&mut seq)
// .returning(|_, _| Ok(Dict::new("default_dict".into())));
// let data = LenValueMap::build(&decoder, &repo, 1)
// .await
// .unwrap()
// .into_data();
// assert_eq!(data.len(), 2);
// }
}

2
lib/src/infrastructure/sqlite_dict_repository.rs

@ -1,8 +1,8 @@
use crate::core::entities::{Dict, DictEntry};
use crate::core::errors::RepositoryError;
use crate::core::traits::DictRepository;
use futures::TryStreamExt;
use futures::stream::BoxStream;
use futures::{StreamExt, TryStreamExt};
use sqlx::{Row, SqlitePool, sqlite::SqliteConnectOptions};
use std::collections::HashMap;

8612
resources/dsr1ll70_pl_demo.json

File diff suppressed because it is too large Load Diff

12
resources/example_dict.json

@ -0,0 +1,12 @@
[
{"word": "hello", "metadata": {"type": "greeting", "language": "english"}},
{"word": "world", "metadata": {"type": "noun", "language": "english"}},
{"word": "rust", "metadata": {"type": "programming_language", "paradigm": "systems"}},
{"word": "programming", "metadata": {"type": "verb", "context": "computing"}},
{"word": "database", "metadata": {"type": "noun", "context": "data_storage"}},
{"word": "sqlite", "metadata": {"type": "database_engine", "features": ["embedded", "sql"]}},
{"word": "json", "metadata": {"type": "data_format", "standard": "RFC 8259"}},
{"word": "import", "metadata": {"type": "verb", "context": "data_operations"}},
{"word": "dictionary", "metadata": {"type": "noun", "context": "reference"}},
{"word": "example", "metadata": {"type": "noun", "usage": "demonstration"}}
]
Loading…
Cancel
Save