|
|
|
@ -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<PullSpec>;
|
|
|
|
|
|
|
|
|
|
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<JsonValue> {
|
|
|
|
|
pub(crate) fn pull(
|
|
|
|
|
&mut self,
|
|
|
|
|
eid: EntityId,
|
|
|
|
|
vld: Validity,
|
|
|
|
|
spec: &PullSpec,
|
|
|
|
|
collector: &mut Map<String, JsonValue>,
|
|
|
|
|
) -> 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<String, JsonValue>,
|
|
|
|
|
) -> 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<StaticValue> = 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<String, JsonValue>,
|
|
|
|
|
) -> 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<StaticValue>,
|
|
|
|
|
vld: Validity,
|
|
|
|
|
collector: &mut Map<String, JsonValue>,
|
|
|
|
|
) -> 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<String, JsonValue>,
|
|
|
|
|
) -> 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<StaticValue> = 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<String, JsonValue>,
|
|
|
|
|
) -> 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
|
|
|
|
|
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(())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|