197 lines
7.1 KiB
Rust
197 lines
7.1 KiB
Rust
// Sonic
|
|
//
|
|
// Fast, lightweight and schema-less search backend
|
|
// Copyright: 2026, Rémi Bardon <remi@remibardon.name>
|
|
// License: Mozilla Public License v2.0 (MPL v2.0)
|
|
|
|
#![allow(unused)]
|
|
|
|
pub mod config;
|
|
mod executor;
|
|
mod logging;
|
|
mod meta_tests;
|
|
pub mod util;
|
|
|
|
pub use self::executor::*;
|
|
pub(crate) use self::item_ref::*;
|
|
pub use self::logging::*;
|
|
pub(crate) use self::meta_tests::*;
|
|
pub(crate) use self::util::assert_contains;
|
|
|
|
// NOTE: Using macros instead of functions so `unwrap`s point to the call site
|
|
// (helps debugging).
|
|
pub(crate) mod item_ref {
|
|
macro_rules! collection_ref {
|
|
($collection:expr) => {
|
|
sonic::store::StoreItemBuilder::from_depth_1($collection).unwrap()
|
|
};
|
|
}
|
|
pub(crate) use collection_ref;
|
|
|
|
macro_rules! bucket_ref {
|
|
($collection:expr, $bucket:expr) => {
|
|
sonic::store::StoreItemBuilder::from_depth_2($collection, $bucket).unwrap()
|
|
};
|
|
}
|
|
pub(crate) use bucket_ref;
|
|
|
|
macro_rules! object_ref {
|
|
($collection:expr, $bucket:expr, $object:expr) => {
|
|
sonic::store::StoreItemBuilder::from_depth_3($collection, $bucket, $object).unwrap()
|
|
};
|
|
}
|
|
pub(crate) use object_ref;
|
|
}
|
|
|
|
macro_rules! exec {
|
|
($executor:ident -> PUSH $collection:tt $bucket:tt $oid:tt $text:tt $(LANG($lang:expr))? NEW) => {
|
|
exec!(internal_ $executor -> PUSH $collection $bucket $oid $text true $(LANG($lang))?)
|
|
};
|
|
($executor:ident -> PUSH $collection:tt $bucket:tt $oid:tt $text:tt $(LANG($lang:expr))?) => {
|
|
exec!(internal_ $executor -> PUSH $collection $bucket $oid $text false $(LANG($lang))?)
|
|
};
|
|
(internal_ $executor:ident -> PUSH $collection:tt $bucket:tt $oid:tt $text:tt $assume_new:ident $(LANG($lang:expr))?) => {{
|
|
#[rustfmt::skip]
|
|
$executor.log(format!(
|
|
"PUSH {:?} {:?} {:?} {:?}{}{}",
|
|
$collection, $bucket, $oid, $text, exec!(internal_ lang_txt $($lang)?), if $assume_new { " NEW" } else { "" }
|
|
));
|
|
let (c, b, o) = crate::common::object_ref!($collection, $bucket, $oid);
|
|
let preprocessor = sonic::lexer::preprocessor::Preprocessor::new(
|
|
$executor.app_conf.tokenization,
|
|
$executor.app_conf.normalization,
|
|
$executor.app_conf.stopwords.clone(),
|
|
true,
|
|
true,
|
|
);
|
|
$executor
|
|
.push(
|
|
c, b, o,
|
|
preprocessor.preprocess($text, exec!(internal_ lang $($lang)?)),
|
|
$assume_new,
|
|
)
|
|
.unwrap()
|
|
}};
|
|
|
|
($executor:ident -> TRIGGER consolidate) => {{
|
|
$executor.log(format!("TRIGGER consolidate"));
|
|
$executor.fst_pool.consolidate(true, |_| true)
|
|
}};
|
|
|
|
($executor:ident -> COUNT $collection:tt) => {{
|
|
$executor.log(format!("COUNT {:?}", $collection));
|
|
let c = collection_ref!($collection);
|
|
$executor.countc(c)
|
|
}};
|
|
|
|
($executor:ident -> COUNT $collection:tt $bucket:tt) => {{
|
|
$executor.log(format!("COUNT {:?} {:?}", $collection, $bucket));
|
|
let (c, b) = bucket_ref!($collection, $bucket);
|
|
$executor.legacy_countb(c, b)
|
|
}};
|
|
|
|
($executor:ident -> COUNTB $collection:tt $bucket:tt) => {{
|
|
$executor.log(format!("COUNTB {:?} {:?}", $collection, $bucket));
|
|
let (c, b) = bucket_ref!($collection, $bucket);
|
|
$executor.countb(c, b)
|
|
}};
|
|
|
|
($executor:ident -> COUNT $collection:tt $bucket:tt $oid:tt) => {{
|
|
$executor.log(format!("COUNT {:?} {:?} {:?}", $collection, $bucket, $oid));
|
|
let (c, b, o) = object_ref!($collection, $bucket, $oid);
|
|
$executor.counto(c, b, o)
|
|
}};
|
|
|
|
($executor:ident -> QUERY $collection:tt $bucket:tt $term:tt $(LANG($lang:expr))? $(LIMIT($limit:expr))?) => {{
|
|
#[rustfmt::skip]
|
|
$executor.log(format!(
|
|
"QUERY {:?} {:?} {:?}{}{}",
|
|
$collection, $bucket, $term, exec!(internal_ lang_txt $($lang)?), exec!(internal_ limit_txt $($limit)?)
|
|
));
|
|
let (c, b) = crate::common::bucket_ref!($collection, $bucket);
|
|
let preprocessor = sonic::lexer::preprocessor::Preprocessor::new(
|
|
$executor.app_conf.tokenization,
|
|
$executor.app_conf.normalization,
|
|
$executor.app_conf.stopwords.clone(),
|
|
true,
|
|
true,
|
|
);
|
|
$executor
|
|
.search(
|
|
c, b,
|
|
preprocessor.preprocess($term, exec!(internal_ lang $($lang)?)),
|
|
exec!(internal_ limit $($limit)?),
|
|
0,
|
|
)
|
|
.expect("QUERY should succeed")
|
|
}};
|
|
|
|
($executor:ident -> SUGGEST $collection:tt $bucket:tt $word:tt $(LANG($lang:expr))?) => {{
|
|
#[rustfmt::skip]
|
|
$executor.log(format!(
|
|
"SUGGEST {:?} {:?} {:?}{}",
|
|
$collection, $bucket, $word, exec!(internal_ lang_txt $($lang)?)
|
|
));
|
|
let (c, b) = crate::common::bucket_ref!($collection, $bucket);
|
|
let preprocessor = sonic::lexer::preprocessor::Preprocessor::new(
|
|
$executor.app_conf.tokenization,
|
|
$executor.app_conf.normalization,
|
|
$executor.app_conf.stopwords.clone(),
|
|
false,
|
|
false,
|
|
);
|
|
$executor
|
|
.suggest(
|
|
c, b,
|
|
preprocessor.preprocess($word, exec!(internal_ lang $($lang)?)),
|
|
$executor.app_conf.search.suggest_limit_default,
|
|
)
|
|
.expect("SUGGEST should succeed")
|
|
.map(|words| words.collect::<Vec<String>>())
|
|
.unwrap_or_default()
|
|
}};
|
|
|
|
($executor:ident -> LIST $collection:tt $bucket:tt $(LIMIT($limit:expr))?) => {{
|
|
$executor.log(format!("LIST {:?} {:?}", $collection, $bucket));
|
|
let (c, b) = crate::common::bucket_ref!($collection, $bucket);
|
|
$executor
|
|
.list(
|
|
c, b,
|
|
exec!(internal_ limit $($limit)?),
|
|
0,
|
|
)
|
|
.expect("LIST should succeed")
|
|
}};
|
|
|
|
($executor:ident -> FLUSHC $collection:tt) => {{
|
|
$executor.log(format!("FLUSHC {:?}", $collection));
|
|
let c = crate::common::collection_ref!($collection);
|
|
$executor.flushc(c).unwrap()
|
|
}};
|
|
|
|
($executor:ident -> FLUSHB $collection:tt $bucket:tt) => {{
|
|
$executor.log(format!("FLUSHB {:?} {:?}", $collection, $bucket));
|
|
let (c, b) = crate::common::bucket_ref!($collection, $bucket);
|
|
$executor.flushb(c, b).unwrap()
|
|
}};
|
|
|
|
($executor:ident -> FLUSHO $collection:tt $bucket:tt $oid:tt) => {{
|
|
$executor.log(format!("FLUSHO {:?} {:?} {:?}", $collection, $bucket, $oid));
|
|
let (c, b, o) = crate::common::object_ref!($collection, $bucket, $oid);
|
|
$executor.flusho(c, b, o).unwrap()
|
|
}};
|
|
|
|
(internal_ lang) => { None };
|
|
(internal_ lang $lang:expr) => { whatlang::Lang::from_code($lang) };
|
|
|
|
(internal_ lang_txt) => { "" };
|
|
(internal_ lang_txt $lang:expr) => { format!(" LANG({})", $lang) };
|
|
|
|
(internal_ limit) => { sonic::executor::QuerySearchLimit::MAX };
|
|
(internal_ limit $limit:expr) => { $limit };
|
|
|
|
(internal_ limit_txt) => { "" };
|
|
(internal_ limit_txt $limit:expr) => { format!(" LLIMIT({})", $limit) };
|
|
}
|
|
pub(crate) use exec;
|