use std::collections::BTreeSet;
use nodedb_sql::types::SqlValue;
use nodedb_sql::types::filter::Filter;
use nodedb_types::result::QueryResult;
use nodedb_types::value::Value;
use crate::error::LiteError;
use crate::nodedb::convert::loro_value_to_document;
use crate::query::engine::{LiteQueryEngine, sql_value_to_string};
use crate::query::visitor::scan_post::filter_mask;
use crate::storage::engine::StorageEngine;
pub(crate) fn document_targets<S: StorageEngine>(
engine: &LiteQueryEngine<S>,
collection: &str,
filters: &[Filter],
target_keys: &[SqlValue],
) -> Result<Vec<String>, LiteError> {
if !target_keys.is_empty() {
return Ok(target_keys.iter().map(sql_value_to_string).collect());
}
let docs: Vec<(String, std::collections::HashMap<String, Value>)> = {
let crdt = engine.crdt.lock().map_err(|_| LiteError::LockPoisoned)?;
crdt.list_ids(collection)
.into_iter()
.filter_map(|id| {
let value = crdt.read(collection, &id)?;
let fields = loro_value_to_document(&id, &value).fields;
Some((id, fields))
})
.collect()
};
let columns: Vec<String> = docs
.iter()
.flat_map(|(_, fields)| fields.keys().cloned())
.collect::<BTreeSet<_>>()
.into_iter()
.collect();
let rows: Vec<Vec<Value>> = docs
.iter()
.map(|(_, fields)| {
columns
.iter()
.map(|c| fields.get(c).cloned().unwrap_or(Value::Null))
.collect()
})
.collect();
let keep = filter_mask(
&QueryResult {
columns,
rows,
rows_affected: 0,
command: None,
},
filters,
)?;
Ok(docs
.into_iter()
.zip(keep)
.filter_map(|((id, _), keep)| keep.then_some(id))
.collect())
}
pub(crate) async fn strict_targets<S: StorageEngine>(
engine: &LiteQueryEngine<S>,
collection: &str,
filters: &[Filter],
named_keys: Vec<Value>,
pk_idx: usize,
) -> Result<Vec<Value>, LiteError> {
if !named_keys.is_empty() {
return Ok(named_keys);
}
let Some(schema) = engine.strict.schema(collection) else {
return Ok(Vec::new());
};
let rows = engine.strict.list_rows(collection).await?;
let keep = filter_mask(
&QueryResult {
columns: schema.columns.iter().map(|c| c.name.clone()).collect(),
rows: rows.clone(),
rows_affected: 0,
command: None,
},
filters,
)?;
Ok(rows
.into_iter()
.zip(keep)
.filter_map(|(row, keep)| if keep { row.get(pk_idx).cloned() } else { None })
.collect())
}