diff --git a/src/transact/pull.rs b/src/transact/pull.rs index 10244f98..7e880f78 100644 --- a/src/transact/pull.rs +++ b/src/transact/pull.rs @@ -1,4 +1,4 @@ -use crate::data::attr::{Attribute, AttributeCardinality}; +use crate::data::attr::{Attribute, AttributeCardinality, AttributeTyping}; use crate::data::encode::{ decode_ea_key, decode_value_from_key, decode_value_from_val, encode_eav_key, StorageTag, }; @@ -6,17 +6,15 @@ use crate::data::id::{AttrId, EntityId, Validity}; use crate::data::json::JsonValue; use crate::data::keyword::Keyword; use crate::data::triple::StoreOp; -use crate::data::value::Value; +use crate::data::value::{StaticValue, Value}; use crate::runtime::transact::SessionTx; use anyhow::Result; -use serde_json::json; +use serde_json::{json, Map}; pub(crate) type PullSpecs = Vec; pub(crate) enum PullSpec { - None, PullAll, - Recurse(Keyword), Attr(AttrPullSpec), } @@ -35,12 +33,139 @@ pub(crate) struct RecursePullSpec { } impl SessionTx { - pub fn pull_all(&mut self, eid: EntityId, vld: Validity) -> Result { + pub(crate) fn pull( + &mut self, + eid: EntityId, + vld: Validity, + spec: &PullSpec, + collector: &mut Map, + ) -> Result<()> { + match spec { + PullSpec::PullAll => self.pull_all(eid, vld, collector), + PullSpec::Attr(a_spec) => { + if a_spec.reverse { + self.pull_attr_rev(eid, vld, a_spec, collector) + } else { + self.pull_attr(eid, vld, a_spec, collector) + } + } + } + } + pub(crate) fn pull_attr( + &mut self, + eid: EntityId, + vld: Validity, + spec: &AttrPullSpec, + collector: &mut Map, + ) -> Result<()> { + if spec.cardinality.is_one() { + if let Some(found) = self.triple_ea_before_scan(eid, spec.attr.id, vld).next() { + let (_, _, value) = found?; + self.pull_attr_collect(spec, value, vld, collector)?; + } else { + self.pull_attr_collect(spec, Value::Null, vld, collector)?; + } + } else { + let mut collection: Vec = vec![]; + let iter = self.triple_ea_before_scan(eid, spec.attr.id, vld); + for found in iter { + let (_, _, value) = found?; + collection.push(value); + if let Some(n) = spec.take { + if n <= collection.len() { + break; + } + } + } + self.pull_attr_collect_many(spec, collection, vld, collector)?; + } + Ok(()) + } + fn pull_attr_collect( + &mut self, + spec: &AttrPullSpec, + value: StaticValue, + vld: Validity, + collector: &mut Map, + ) -> Result<()> { + if spec.nested.is_empty() { + collector.insert(spec.name.to_string_no_prefix(), value.into()); + } else { + let eid = value.get_entity_id()?; + let mut sub_collector = Map::default(); + for sub_spec in &spec.nested { + self.pull(eid, vld, sub_spec, &mut sub_collector)?; + } + collector.insert(spec.name.to_string_no_prefix(), sub_collector.into()); + } + Ok(()) + } + fn pull_attr_collect_many( + &mut self, + spec: &AttrPullSpec, + values: Vec, + vld: Validity, + collector: &mut Map, + ) -> Result<()> { + if spec.nested.is_empty() { + collector.insert(spec.name.to_string_no_prefix(), values.into()); + } else { + let mut sub_collectors = vec![]; + for value in values { + let eid = value.get_entity_id()?; + let mut sub_collector = Map::default(); + for sub_spec in &spec.nested { + self.pull(eid, vld, sub_spec, &mut sub_collector)?; + } + sub_collectors.push(sub_collector); + } + collector.insert(spec.name.to_string_no_prefix(), sub_collectors.into()); + } + Ok(()) + } + pub(crate) fn pull_attr_rev( + &mut self, + eid: EntityId, + vld: Validity, + spec: &AttrPullSpec, + collector: &mut Map, + ) -> Result<()> { + if spec.cardinality.is_one() { + if let Some(found) = self + .triple_vref_a_before_scan(eid, spec.attr.id, vld) + .next() + { + let (_, _, value) = found?; + self.pull_attr_collect(spec, Value::EnId(value), vld, collector)?; + } else { + self.pull_attr_collect(spec, Value::Null, vld, collector)?; + } + } else { + let mut collection: Vec = vec![]; + let iter = self.triple_vref_a_before_scan(eid, spec.attr.id, vld); + for found in iter { + let (_, _, value) = found?; + collection.push(Value::EnId(value)); + if let Some(n) = spec.take { + if n <= collection.len() { + break; + } + } + } + self.pull_attr_collect_many(spec, collection.into(), vld, collector)?; + } + Ok(()) + } + pub(crate) fn pull_all( + &mut self, + eid: EntityId, + vld: Validity, + collector: &mut Map, + ) -> Result<()> { let mut current = encode_eav_key(eid, AttrId::MIN_PERM, &Value::Null, Validity::MAX); let upper_bound = encode_eav_key(eid, AttrId::MAX_PERM, &Value::Bottom, Validity::MIN); let mut it = self.tx.iterator().upper_bound(&upper_bound).start(); - let mut collected = json!({}); it.seek(¤t); while let Some((k_slice, v_slice)) = it.pair()? { debug_assert_eq!( @@ -73,20 +198,38 @@ impl SessionTx { } else { decode_value_from_key(k_slice)? }; - let map_for_entry = collected.as_object_mut().unwrap(); - map_for_entry.insert("_id".to_string(), eid.0.into()); + collector.insert("_id".to_string(), eid.0.into()); if attr.cardinality.is_many() { - let arr = map_for_entry - .entry(attr.keyword.to_string_no_prefix()) - .or_insert_with(|| json!([])); - let arr = arr.as_array_mut().unwrap(); - arr.push(value.into()); + if attr.val_type == AttributeTyping::Component { + let val_id = value.get_entity_id()?; + let mut subcollector = Map::default(); + self.pull_all(val_id, vld, &mut subcollector)?; + + let arr = collector + .entry(attr.keyword.to_string_no_prefix()) + .or_insert_with(|| json!([])); + let arr = arr.as_array_mut().unwrap(); + arr.push(subcollector.into()); + } else { + let arr = collector + .entry(attr.keyword.to_string_no_prefix()) + .or_insert_with(|| json!([])); + let arr = arr.as_array_mut().unwrap(); + arr.push(value.into()); + } } else { - map_for_entry.insert(attr.keyword.to_string_no_prefix(), value.into()); + if attr.val_type == AttributeTyping::Component { + let val_id = value.get_entity_id()?; + let mut subcollector = Map::default(); + self.pull_all(val_id, vld, &mut subcollector)?; + collector.insert(attr.keyword.to_string_no_prefix(), subcollector.into()); + } else { + collector.insert(attr.keyword.to_string_no_prefix(), value.into()); + } } current.encoded_entity_amend_validity_to_inf_past(); it.seek(¤t); } - Ok(json!(collected)) + Ok(()) } } diff --git a/src/transact/triple.rs b/src/transact/triple.rs index 4c9ceea9..8aa9bc52 100644 --- a/src/transact/triple.rs +++ b/src/transact/triple.rs @@ -690,7 +690,10 @@ impl TripleEntityAttrBeforeIter { self.current.encoded_entity_amend_validity(self.before); continue; } - let v = decode_value_from_key(k_slice)?; + let mut v = decode_value_from_key(k_slice)?; + if v == Value::Bottom { + v = decode_value_from_val(v_slice)?; + } self.current.copy_from_slice(k_slice); self.current.encoded_entity_amend_validity_to_inf_past(); let op = StoreOp::try_from(v_slice[0])?;