use std::collections::{HashMap, HashSet};
use std::sync::Mutex;
use nodedb_query::scan_filter::ScanFilter;
use nodedb_types::value::Value;
use crate::engine::crdt::CrdtEngine;
use crate::error::LiteError;
use crate::nodedb::convert::loro_value_to_document;
use crate::nodedb::lock_ext::LockExt;
use crate::query::scan_filter_convert::decode_scan_filters;
pub(super) type TextRow = (String, HashMap<String, Value>);
pub(super) struct TextRowGate {
filters: Vec<ScanFilter>,
}
impl TextRowGate {
pub(super) fn new(filters: &[u8], rls_filters: &[u8]) -> Result<Self, LiteError> {
let mut all = decode_scan_filters(filters)?;
all.extend(decode_scan_filters(rls_filters)?);
Ok(Self { filters: all })
}
pub(super) fn is_open(&self) -> bool {
self.filters.is_empty()
}
pub(super) fn admits(&self, row: &Value) -> Result<bool, LiteError> {
Ok(ScanFilter::all_match_value(&self.filters, row)?)
}
}
pub(super) fn collection_ids(crdt: &Mutex<CrdtEngine>, collection: &str) -> Vec<String> {
crdt.lock_or_recover().list_ids(collection)
}
pub(super) fn collection_rows(crdt: &Mutex<CrdtEngine>, collection: &str) -> Vec<TextRow> {
let guard = crdt.lock_or_recover();
guard
.list_ids(collection)
.into_iter()
.filter_map(|id| {
let value = guard.read(collection, &id)?;
let fields = loro_value_to_document(&id, &value).fields;
Some((id, fields))
})
.collect()
}
pub(super) fn admitted_ids(
crdt: &Mutex<CrdtEngine>,
collection: &str,
gate: &TextRowGate,
) -> Result<Option<HashSet<String>>, LiteError> {
if gate.is_open() {
return Ok(None);
}
let mut admitted = HashSet::new();
for (id, fields) in collection_rows(crdt, collection) {
if gate.admits(&Value::Object(fields))? {
admitted.insert(id);
}
}
Ok(Some(admitted))
}
pub(super) fn is_eligible(admitted: Option<&HashSet<String>>, id: &str) -> bool {
admitted.is_none_or(|ids| ids.contains(id))
}