use std::error::Error;
use std::sync::Arc;
use mindb::db::{Database, DatabaseOptions, SecondaryIndexConfig};
use mindb::query::FilterRequest;
use serde_json::{Value, json};
#[test]
fn database_facade_query_helpers() -> Result<(), Box<dyn Error>> {
let tempdir = tempfile::tempdir()?;
let mut options = DatabaseOptions::new(tempdir.path());
options.wal_direct_io = false;
options.secondary_indexes = SecondaryIndexConfig {
slug: Some(Arc::new(|_, value: &[u8]| {
serde_json::from_slice::<Value>(value).ok().and_then(|doc| {
doc.get("slug")
.and_then(|slug| slug.as_str().map(|s| s.to_string()))
})
})),
timestamp: Some(Arc::new(|_, value: &[u8]| {
serde_json::from_slice::<Value>(value)
.ok()
.and_then(|doc| doc.get("timestamp").and_then(|ts| ts.as_i64()))
})),
roaring_tags: Some(Arc::new(|_, value: &[u8]| {
serde_json::from_slice::<Value>(value)
.ok()
.and_then(|doc| {
doc.get("tags").and_then(|tags| {
tags.as_array().map(|entries| {
entries
.iter()
.filter_map(|entry| entry.as_str().map(|s| s.to_string()))
.collect::<Vec<_>>()
})
})
})
.unwrap_or_default()
})),
json_paths: Some(Arc::new(|_, value: &[u8]| {
let mut fields = Vec::new();
if let Ok(doc) = serde_json::from_slice::<Value>(value) {
if let Some(kind) = doc.get("kind") {
fields.push(("kind".to_string(), kind.clone()));
}
if let Some(active) = doc.get("active") {
fields.push(("active".to_string(), active.clone()));
}
}
fields
})),
full_text: Some(Arc::new(|_, value: &[u8]| {
serde_json::from_slice::<Value>(value).ok().and_then(|doc| {
doc.get("content")
.and_then(|text| text.as_str().map(|s| s.to_string()))
})
})),
};
let db = Database::open(options)?;
let doc_one = json!({
"slug": "doc-1",
"timestamp": 10,
"tags": ["red", "shared"],
"kind": "alpha",
"active": true,
"content": "alpha document body",
});
let doc_two = json!({
"slug": "doc-2",
"timestamp": 20,
"tags": ["blue"],
"kind": "beta",
"active": false,
"content": "beta entry",
});
let doc_one_bytes = serde_json::to_vec(&doc_one)?;
let doc_two_bytes = serde_json::to_vec(&doc_two)?;
db.put(b"doc-1".to_vec(), doc_one_bytes.clone())?;
db.put(b"doc-2".to_vec(), doc_two_bytes.clone())?;
let slug_lookup = db.get_by_slug("doc-2")?;
assert_eq!(slug_lookup.as_deref(), Some(doc_two_bytes.as_slice()));
let mut prefix_results = db.scan_prefix(b"doc-")?.collect(&db)?;
prefix_results.sort_by(|a, b| a.0.cmp(&b.0));
assert_eq!(
prefix_results,
vec![
(b"doc-1".to_vec(), doc_one_bytes.clone()),
(b"doc-2".to_vec(), doc_two_bytes.clone()),
]
);
let time_results = db.scan_time(15, 25)?.collect(&db)?;
assert_eq!(
time_results,
vec![(b"doc-2".to_vec(), doc_two_bytes.clone())]
);
let required_tags = vec!["shared".to_string()];
let kind_alpha = json!("alpha");
let filter_request = FilterRequest {
bitmap_tags: &required_tags,
json_equals: &[("kind", &kind_alpha)],
};
let filter_results = db.filter(&filter_request)?.collect(&db)?;
assert_eq!(
filter_results,
vec![(b"doc-1".to_vec(), doc_one_bytes.clone())]
);
let search_results = db.search("beta")?.collect(&db)?;
assert_eq!(
search_results,
vec![(b"doc-2".to_vec(), doc_two_bytes.clone())]
);
Ok(())
}