1#![doc = include_str!("../README.md")]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![warn(missing_docs)]
4
5#[cfg(feature = "jieba")]
6use std::path::Path;
7
8use better_embedded::strategies::DefaultCheckStrategy;
9use rusqlite::ffi::{sqlite3_auto_extension, sqlite3_cancel_auto_extension};
10
11use crate::ffi::sqlite3_simple_init;
12
13pub mod ffi;
14
15pub fn enable_auto_extension() -> rusqlite::Result<()> {
17 let res = unsafe { sqlite3_auto_extension(Some(sqlite3_simple_init)) };
18 ffi::check_err(res)
19}
20
21pub fn disable_auto_extension() -> rusqlite::Result<()> {
23 let res = unsafe { sqlite3_cancel_auto_extension(Some(sqlite3_simple_init)) };
24 ffi::check_err(res)
25}
26
27#[cfg(feature = "jieba")]
32#[cfg_attr(docsrs, doc(cfg(feature = "jieba")))]
33pub fn release_dict(directory: impl AsRef<Path>) -> std::io::Result<()> {
34 let directory = directory.as_ref().to_path_buf();
35 if !directory.is_dir() { std::fs::create_dir_all(&directory)?; }
36
37 macro_rules! embedded_file {
38 ($target: ident, $source: expr) => {
39 let file = include_bytes!(concat!("../cppjieba/dict/", $source));
40 let target = $target.join($source);
41 better_embedded::release_file_with_check(file, &target, DefaultCheckStrategy::config())?;
42 };
43 }
44 embedded_file!(directory, "jieba.dict.utf8");
45 embedded_file!(directory, "user.dict.utf8");
46 embedded_file!(directory, "hmm_model.utf8");
47 embedded_file!(directory, "idf.utf8");
48 embedded_file!(directory, "stop_words.utf8");
49
50 Ok(())
51}
52
53#[cfg(feature = "jieba")]
58#[cfg_attr(docsrs, doc(cfg(feature = "jieba")))]
59pub fn set_dict(connection: &rusqlite::Connection, directory: impl AsRef<Path>) -> rusqlite::Result<()> {
60 let directory = directory.as_ref();
61 let directory = directory.to_str()
62 .ok_or_else(|| rusqlite::Error::InvalidPath(directory.to_path_buf()))?;
63 connection.query_row("SELECT jieba_dict(?)", rusqlite::params![directory], |_| Ok(()))
64}
65
66#[cfg(test)]
67mod tests {
68 #[test]
69 fn test() -> anyhow::Result<()> {
70 crate::enable_auto_extension()?;
71 let dir = tempfile::tempdir()?;
72 crate::release_dict(&dir)?;
73
74 let conn = rusqlite::Connection::open_in_memory()?;
75 crate::set_dict(&conn, &dir)?;
76 conn.execute_batch("
77 PRAGMA key = '123456';
78 CREATE TABLE singer (id INTEGER, name TEXT);
79 CREATE VIRTUAL TABLE d USING fts5(id, name, tokenize = 'simple');
80 CREATE TRIGGER dtrigger AFTER INSERT ON singer BEGIN
81 INSERT INTO d(id, name) VALUES (new.id, new.name);
82 END;
83 INSERT INTO singer (id, name) VALUES (1, '中华人民共和国国歌');
84 ")?;
85 assert_eq!(1, conn.query_row(
86 "SELECT id FROM d WHERE name MATCH jieba_query('中华国歌')",
87 [], |row| row.get::<_, i64>(0)
88 )?);
89 Ok(())
90 }
91}