mirror of
https://github.com/patarapolw/cjdic2.git
synced 2026-11-09 17:39:35 +00:00
plan search db
This commit is contained in:
1 parent
ec14023c04
commit
a97da3fa1d
6 files changed
+61
-23
No files matched your search
+15
-12
@@ -7,16 +7,19 @@ use std::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{Ok, Result};
|
|
||||||
use enum_map::EnumMap;
|
use enum_map::EnumMap;
|
||||||
use rusqlite::Connection;
|
use rusqlite::Connection;
|
||||||
|
|
||||||
|
mod search;
|
||||||
|
|
||||||
mod yomitan;
|
mod yomitan;
|
||||||
pub use yomitan::YomitanRow;
|
pub use yomitan::YomitanRow;
|
||||||
|
|
||||||
mod yomitan_writer;
|
mod yomitan_writer;
|
||||||
pub use yomitan_writer::{YomitanProgress, YomitanWriter, YomitanZipImportResult, ZipSource};
|
pub use yomitan_writer::{YomitanProgress, YomitanWriter, YomitanZipImportResult, ZipSource};
|
||||||
|
|
||||||
|
use crate::CJDicError;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub(crate) struct Database {
|
pub(crate) struct Database {
|
||||||
pub(crate) conn: Arc<Mutex<Connection>>,
|
pub(crate) conn: Arc<Mutex<Connection>>,
|
||||||
@@ -28,28 +31,28 @@ pub(crate) struct Database {
|
|||||||
pub(crate) enum DbChild {
|
pub(crate) enum DbChild {
|
||||||
Yomitan,
|
Yomitan,
|
||||||
YomitanGlossary,
|
YomitanGlossary,
|
||||||
Reading,
|
Search,
|
||||||
}
|
}
|
||||||
|
|
||||||
const USER_DBFILE: &str = "user.db";
|
const USER_DBFILE: &str = "user.db";
|
||||||
|
|
||||||
pub(crate) const DBFILE: LazyLock<EnumMap<DbChild, &str>> = LazyLock::new(|| {
|
pub(crate) static DBFILE: LazyLock<EnumMap<DbChild, &str>> = LazyLock::new(|| {
|
||||||
enum_map! {
|
enum_map! {
|
||||||
DbChild::Yomitan => "yomitan.db",
|
DbChild::Yomitan => "yomitan.db",
|
||||||
DbChild::YomitanGlossary => "yomitan-glossary.db",
|
DbChild::YomitanGlossary => "yomitan-glossary.db",
|
||||||
DbChild::Reading => "reading.db"
|
DbChild::Search => "reading.db"
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
pub(crate) const DBSCHEMA: LazyLock<EnumMap<DbChild, &str>> = LazyLock::new(|| {
|
pub(crate) static DBSCHEMA: LazyLock<EnumMap<DbChild, &str>> = LazyLock::new(|| {
|
||||||
enum_map! {
|
enum_map! {
|
||||||
DbChild::Yomitan => "yomitan",
|
DbChild::Yomitan => "yomitan",
|
||||||
DbChild::YomitanGlossary => "glossary",
|
DbChild::YomitanGlossary => "glossary",
|
||||||
DbChild::Reading => "reading"
|
DbChild::Search => "reading"
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
impl Database {
|
impl Database {
|
||||||
pub fn new(db_dir: impl AsRef<Path>) -> Result<Self> {
|
pub fn new(db_dir: impl AsRef<Path>) -> Result<Self, CJDicError> {
|
||||||
let dir = db_dir.as_ref().to_path_buf();
|
let dir = db_dir.as_ref().to_path_buf();
|
||||||
let conn = Connection::open(dir.join(USER_DBFILE))?;
|
let conn = Connection::open(dir.join(USER_DBFILE))?;
|
||||||
|
|
||||||
@@ -68,24 +71,24 @@ impl Database {
|
|||||||
is_db_attached: enum_map! {
|
is_db_attached: enum_map! {
|
||||||
DbChild::Yomitan => Arc::new(AtomicBool::new(false)),
|
DbChild::Yomitan => Arc::new(AtomicBool::new(false)),
|
||||||
DbChild::YomitanGlossary => Arc::new(AtomicBool::new(false)),
|
DbChild::YomitanGlossary => Arc::new(AtomicBool::new(false)),
|
||||||
DbChild::Reading => Arc::new(AtomicBool::new(false)),
|
DbChild::Search => Arc::new(AtomicBool::new(false)),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn yomitan(&self) -> Result<yomitan::YomitanDatabase> {
|
pub fn yomitan(&self) -> Result<yomitan::YomitanDatabase, CJDicError> {
|
||||||
self.ensure_db_attached(DbChild::Yomitan)?;
|
self.ensure_db_attached(DbChild::Yomitan)?;
|
||||||
self.ensure_db_attached(DbChild::YomitanGlossary)?;
|
self.ensure_db_attached(DbChild::YomitanGlossary)?;
|
||||||
self.ensure_db_attached(DbChild::Reading)?;
|
self.ensure_db_attached(DbChild::Search)?;
|
||||||
Ok(yomitan::YomitanDatabase::new(self.clone()))
|
Ok(yomitan::YomitanDatabase::new(self.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ensure_db_attached(&self, db_child: DbChild) -> Result<()> {
|
fn ensure_db_attached(&self, db_child: DbChild) -> Result<(), CJDicError> {
|
||||||
if self.is_db_attached[db_child].load(Ordering::Acquire) {
|
if self.is_db_attached[db_child].load(Ordering::Acquire) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let conn = self.conn.lock().unwrap();
|
let conn = self.conn.lock()?;
|
||||||
let is_attached = self.is_db_attached[db_child].load(Ordering::Relaxed);
|
let is_attached = self.is_db_attached[db_child].load(Ordering::Relaxed);
|
||||||
|
|
||||||
if !is_attached {
|
if !is_attached {
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#[allow(unused)]
|
||||||
|
pub(super) fn normalize_reading(s: &str) -> String {
|
||||||
|
s.chars()
|
||||||
|
.map(|c| {
|
||||||
|
if c >= 'ア' && c <= 'ン' {
|
||||||
|
// Katakana range
|
||||||
|
if let Some(x) = char::from_u32(c as u32 - 0x60) {
|
||||||
|
x // Convert to Hiragana
|
||||||
|
} else {
|
||||||
|
c // Ensure it's a valid char
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c // Return the character as is if it's not in the range
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
@@ -31,7 +31,7 @@ impl YomitanDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn decompressor(&self) -> Result<Decompressor<'_>, CJDicError> {
|
fn decompressor(&self) -> Result<Decompressor<'_>, CJDicError> {
|
||||||
let conn = self.db.conn.lock().unwrap();
|
let conn = self.db.conn.lock()?;
|
||||||
|
|
||||||
let row = conn.query_row(
|
let row = conn.query_row(
|
||||||
"SELECT value FROM glossary.meta WHERE key = 'zstd_dict'",
|
"SELECT value FROM glossary.meta WHERE key = 'zstd_dict'",
|
||||||
@@ -79,7 +79,7 @@ impl YomitanDatabase {
|
|||||||
let eq1 = if q_term_norm.len() > 0 { "GLOB" } else { "=" };
|
let eq1 = if q_term_norm.len() > 0 { "GLOB" } else { "=" };
|
||||||
let eq2 = if q_reading.len() > 0 { "GLOB" } else { "=" };
|
let eq2 = if q_reading.len() > 0 { "GLOB" } else { "=" };
|
||||||
|
|
||||||
let conn = self.db.conn.lock().unwrap();
|
let conn = self.db.conn.lock()?;
|
||||||
conn.execute_batch(
|
conn.execute_batch(
|
||||||
"
|
"
|
||||||
CREATE TEMP TABLE IF NOT EXISTS yomitan_lookup_keys (
|
CREATE TEMP TABLE IF NOT EXISTS yomitan_lookup_keys (
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ use zip::ZipArchive;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
CJDicError, Timer,
|
CJDicError, Timer,
|
||||||
db::{DBFILE, DbChild},
|
db::{DBFILE, DBSCHEMA, DbChild},
|
||||||
};
|
};
|
||||||
|
|
||||||
fn blake3_hex(s: &str) -> String {
|
fn blake3_hex(s: &str) -> String {
|
||||||
@@ -174,7 +174,8 @@ impl YomitanWriter {
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
self.create_materialized_views()?;
|
self.create_materialized_views()?;
|
||||||
self.attach_glossary()?;
|
self.attach_db(DbChild::YomitanGlossary)?;
|
||||||
|
self.attach_db(DbChild::Search)?;
|
||||||
|
|
||||||
let schema_version = "2026-03-07";
|
let schema_version = "2026-03-07";
|
||||||
|
|
||||||
@@ -361,7 +362,7 @@ impl YomitanWriter {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn attach_glossary(&mut self) -> Result<(), CJDicError> {
|
fn attach_db(&mut self, db_child: DbChild) -> Result<(), CJDicError> {
|
||||||
let dir = self.dir.clone();
|
let dir = self.dir.clone();
|
||||||
let path = if self.dir.is_absolute() {
|
let path = if self.dir.is_absolute() {
|
||||||
dir
|
dir
|
||||||
@@ -369,8 +370,8 @@ impl YomitanWriter {
|
|||||||
current_dir()?.join(dir)
|
current_dir()?.join(dir)
|
||||||
};
|
};
|
||||||
|
|
||||||
let db_file = DBFILE[DbChild::YomitanGlossary];
|
let db_file = DBFILE[db_child];
|
||||||
let schema_name = "glossary";
|
let schema_name = DBSCHEMA[db_child];
|
||||||
|
|
||||||
let path = path.join(db_file).to_string_lossy().replace(r"\", r"/");
|
let path = path.join(db_file).to_string_lossy().replace(r"\", r"/");
|
||||||
|
|
||||||
@@ -392,7 +393,10 @@ impl YomitanWriter {
|
|||||||
schema_name
|
schema_name
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
self.create_schema_glossary()?;
|
match db_child {
|
||||||
|
DbChild::YomitanGlossary => self.create_schema_glossary()?,
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -529,7 +533,7 @@ impl YomitanWriter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.attach_glossary()?;
|
self.attach_db(DbChild::YomitanGlossary)?;
|
||||||
|
|
||||||
{
|
{
|
||||||
let tx = self.conn.transaction()?;
|
let tx = self.conn.transaction()?;
|
||||||
|
|||||||
+15
-1
@@ -1,5 +1,9 @@
|
|||||||
use std::string::FromUtf8Error;
|
use std::{
|
||||||
|
string::FromUtf8Error,
|
||||||
|
sync::{MutexGuard, PoisonError},
|
||||||
|
};
|
||||||
|
|
||||||
|
use rusqlite::Connection;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use vibrato::errors::VibratoError;
|
use vibrato::errors::VibratoError;
|
||||||
@@ -32,6 +36,9 @@ pub enum CJDicError {
|
|||||||
#[error("FromUtf8Error: {0}")]
|
#[error("FromUtf8Error: {0}")]
|
||||||
FromUtf8Error(String),
|
FromUtf8Error(String),
|
||||||
|
|
||||||
|
#[error("ConnectionMutexGuardError: {0}")]
|
||||||
|
ConnectionMutexGuardError(String),
|
||||||
|
|
||||||
#[error("Not found")]
|
#[error("Not found")]
|
||||||
NotFound,
|
NotFound,
|
||||||
|
|
||||||
@@ -87,3 +94,10 @@ impl From<FromUtf8Error> for CJDicError {
|
|||||||
CJDicError::FromUtf8Error(e.to_string())
|
CJDicError::FromUtf8Error(e.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<PoisonError<MutexGuard<'_, Connection>>> for CJDicError {
|
||||||
|
fn from(e: PoisonError<MutexGuard<'_, Connection>>) -> Self {
|
||||||
|
eprintln!("{e:#}");
|
||||||
|
CJDicError::ConnectionMutexGuardError(e.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -91,7 +91,7 @@ impl AppService {
|
|||||||
) -> Result<serde_json::Value, CJDicError> {
|
) -> Result<serde_json::Value, CJDicError> {
|
||||||
let _timer = Timer::new(sql.to_string());
|
let _timer = Timer::new(sql.to_string());
|
||||||
|
|
||||||
let conn = self.db.conn.lock().unwrap();
|
let conn = self.db.conn.lock()?;
|
||||||
let converted_params: Vec<_> = params
|
let converted_params: Vec<_> = params
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|p| match p {
|
.map(|p| match p {
|
||||||
|
|||||||
Reference in new issue
Block a user