WIP: nested pull.
This commit is contained in:
parent
dc608319b0
commit
2b12c41095
4 changed files with 63 additions and 4 deletions
|
@ -366,7 +366,11 @@ fn validate_attributes<'a, I>(attrs: I) -> std::result::Result<(), &'static str>
|
|||
return Err("wildcard with specified attributes");
|
||||
}
|
||||
},
|
||||
// TODO: map form.
|
||||
&PullAttributeSpec::Nested(ref _attr, ref patterns) => {
|
||||
if patterns.is_empty() {
|
||||
return Err("empty nested pull map");
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
@ -27,6 +27,11 @@ error_chain! {
|
|||
description(":db/id repeated")
|
||||
display(":db/id repeated")
|
||||
}
|
||||
|
||||
NonRefNestedPullAttribute {
|
||||
description("nested pull attribute is non-ref")
|
||||
display("nested pull attribute is non-ref")
|
||||
}
|
||||
}
|
||||
|
||||
links {
|
||||
|
|
|
@ -88,6 +88,7 @@ use mentat_core::{
|
|||
StructuredMap,
|
||||
TypedValue,
|
||||
ValueRc,
|
||||
ValueType,
|
||||
};
|
||||
|
||||
use mentat_db::cache;
|
||||
|
@ -144,8 +145,18 @@ pub struct Puller {
|
|||
// The domain of this map is the set of attributes to fetch.
|
||||
// The range is the set of aliases to use in the output.
|
||||
attributes: BTreeMap<Entid, ValueRc<NamespacedKeyword>>,
|
||||
|
||||
// The original spec for this puller.
|
||||
attribute_spec: cache::AttributeSpec,
|
||||
|
||||
// If :db/id is mentioned in the attribute list, its alias is this.
|
||||
db_id_alias: Option<ValueRc<NamespacedKeyword>>,
|
||||
|
||||
// A pull expression can be arbitrarily nested. We represent this both
|
||||
// within the `attribute_spec` itself and also as a nested set of `Puller`s.
|
||||
// When an attribute in the list above returns an entity -- and it should! --
|
||||
// it is accumulated and we recurse down into these nested layers.
|
||||
nested: BTreeMap<Entid, Puller>,
|
||||
}
|
||||
|
||||
impl Puller {
|
||||
|
@ -156,8 +167,8 @@ impl Puller {
|
|||
let lookup_name = |i: &Entid| {
|
||||
// In the unlikely event that we have an attribute with no name, we bail.
|
||||
schema.get_ident(*i)
|
||||
.map(|ident| ValueRc::new(ident.clone()))
|
||||
.ok_or_else(|| ErrorKind::UnnamedAttribute(*i))
|
||||
.map(|ident| ValueRc::new(ident.clone()))
|
||||
.ok_or_else(|| ErrorKind::UnnamedAttribute(*i))
|
||||
};
|
||||
|
||||
let mut names: BTreeMap<Entid, ValueRc<NamespacedKeyword>> = Default::default();
|
||||
|
@ -204,6 +215,20 @@ impl Puller {
|
|||
},
|
||||
}
|
||||
},
|
||||
|
||||
// An attribute that nests must be ref-typed.
|
||||
&PullAttributeSpec::Nested(ref attribute, ref patterns) => {
|
||||
let value_type = attribute.get_attribute(schema)
|
||||
.map(|(a, _e)| a.value_type);
|
||||
let is_ref_typed = value_type.map(|v| v == ValueType::Ref)
|
||||
.unwrap_or(false);
|
||||
if !is_ref_typed {
|
||||
bail!(ErrorKind::NonRefNestedPullAttribute);
|
||||
}
|
||||
|
||||
// TODO
|
||||
unimplemented!();
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -211,6 +236,7 @@ impl Puller {
|
|||
attributes: names,
|
||||
attribute_spec: cache::AttributeSpec::specified(&attrs, schema),
|
||||
db_id_alias,
|
||||
nested: Default::default(),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -55,7 +55,11 @@ pub use edn::{
|
|||
};
|
||||
|
||||
use mentat_core::{
|
||||
Attribute,
|
||||
FromRc,
|
||||
HasSchema,
|
||||
KnownEntid,
|
||||
Schema,
|
||||
TypedValue,
|
||||
ValueRc,
|
||||
ValueType,
|
||||
|
@ -499,6 +503,19 @@ pub enum PullConcreteAttribute {
|
|||
Entid(i64),
|
||||
}
|
||||
|
||||
impl PullConcreteAttribute {
|
||||
pub fn get_attribute<'s>(&self, schema: &'s Schema) -> Option<(&'s Attribute, KnownEntid)> {
|
||||
match self {
|
||||
&PullConcreteAttribute::Ident(ref rc) => {
|
||||
schema.attribute_for_ident(rc.as_ref())
|
||||
},
|
||||
&PullConcreteAttribute::Entid(e) => {
|
||||
schema.attribute_for_entid(e).map(|a| (a, KnownEntid(e)))
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct NamedPullAttribute {
|
||||
pub attribute: PullConcreteAttribute,
|
||||
|
@ -518,7 +535,7 @@ impl From<PullConcreteAttribute> for NamedPullAttribute {
|
|||
pub enum PullAttributeSpec {
|
||||
Wildcard,
|
||||
Attribute(NamedPullAttribute),
|
||||
// PullMapSpec(Vec<…>),
|
||||
Nested(PullConcreteAttribute, Vec<PullAttributeSpec>),
|
||||
// LimitedAttribute(PullConcreteAttribute, u64), // Limit nil => Attribute instead.
|
||||
// DefaultedAttribute(PullConcreteAttribute, PullDefaultValue),
|
||||
}
|
||||
|
@ -556,6 +573,13 @@ impl std::fmt::Display for PullAttributeSpec {
|
|||
&PullAttributeSpec::Attribute(ref attr) => {
|
||||
write!(f, "{}", attr)
|
||||
},
|
||||
&PullAttributeSpec::Nested(ref attr, ref patterns) => {
|
||||
write!(f, "{{{} [", attr)?;
|
||||
for p in patterns {
|
||||
write!(f, " {}", p)?;
|
||||
}
|
||||
write!(f, "]}}")
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue