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");
|
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(())
|
Ok(())
|
||||||
|
|
|
@ -27,6 +27,11 @@ error_chain! {
|
||||||
description(":db/id repeated")
|
description(":db/id repeated")
|
||||||
display(":db/id repeated")
|
display(":db/id repeated")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NonRefNestedPullAttribute {
|
||||||
|
description("nested pull attribute is non-ref")
|
||||||
|
display("nested pull attribute is non-ref")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
links {
|
links {
|
||||||
|
|
|
@ -88,6 +88,7 @@ use mentat_core::{
|
||||||
StructuredMap,
|
StructuredMap,
|
||||||
TypedValue,
|
TypedValue,
|
||||||
ValueRc,
|
ValueRc,
|
||||||
|
ValueType,
|
||||||
};
|
};
|
||||||
|
|
||||||
use mentat_db::cache;
|
use mentat_db::cache;
|
||||||
|
@ -144,8 +145,18 @@ pub struct Puller {
|
||||||
// The domain of this map is the set of attributes to fetch.
|
// The domain of this map is the set of attributes to fetch.
|
||||||
// The range is the set of aliases to use in the output.
|
// The range is the set of aliases to use in the output.
|
||||||
attributes: BTreeMap<Entid, ValueRc<NamespacedKeyword>>,
|
attributes: BTreeMap<Entid, ValueRc<NamespacedKeyword>>,
|
||||||
|
|
||||||
|
// The original spec for this puller.
|
||||||
attribute_spec: cache::AttributeSpec,
|
attribute_spec: cache::AttributeSpec,
|
||||||
|
|
||||||
|
// If :db/id is mentioned in the attribute list, its alias is this.
|
||||||
db_id_alias: Option<ValueRc<NamespacedKeyword>>,
|
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 {
|
impl Puller {
|
||||||
|
@ -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,
|
attributes: names,
|
||||||
attribute_spec: cache::AttributeSpec::specified(&attrs, schema),
|
attribute_spec: cache::AttributeSpec::specified(&attrs, schema),
|
||||||
db_id_alias,
|
db_id_alias,
|
||||||
|
nested: Default::default(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,11 @@ pub use edn::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use mentat_core::{
|
use mentat_core::{
|
||||||
|
Attribute,
|
||||||
FromRc,
|
FromRc,
|
||||||
|
HasSchema,
|
||||||
|
KnownEntid,
|
||||||
|
Schema,
|
||||||
TypedValue,
|
TypedValue,
|
||||||
ValueRc,
|
ValueRc,
|
||||||
ValueType,
|
ValueType,
|
||||||
|
@ -499,6 +503,19 @@ pub enum PullConcreteAttribute {
|
||||||
Entid(i64),
|
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)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct NamedPullAttribute {
|
pub struct NamedPullAttribute {
|
||||||
pub attribute: PullConcreteAttribute,
|
pub attribute: PullConcreteAttribute,
|
||||||
|
@ -518,7 +535,7 @@ impl From<PullConcreteAttribute> for NamedPullAttribute {
|
||||||
pub enum PullAttributeSpec {
|
pub enum PullAttributeSpec {
|
||||||
Wildcard,
|
Wildcard,
|
||||||
Attribute(NamedPullAttribute),
|
Attribute(NamedPullAttribute),
|
||||||
// PullMapSpec(Vec<…>),
|
Nested(PullConcreteAttribute, Vec<PullAttributeSpec>),
|
||||||
// LimitedAttribute(PullConcreteAttribute, u64), // Limit nil => Attribute instead.
|
// LimitedAttribute(PullConcreteAttribute, u64), // Limit nil => Attribute instead.
|
||||||
// DefaultedAttribute(PullConcreteAttribute, PullDefaultValue),
|
// DefaultedAttribute(PullConcreteAttribute, PullDefaultValue),
|
||||||
}
|
}
|
||||||
|
@ -556,6 +573,13 @@ impl std::fmt::Display for PullAttributeSpec {
|
||||||
&PullAttributeSpec::Attribute(ref attr) => {
|
&PullAttributeSpec::Attribute(ref attr) => {
|
||||||
write!(f, "{}", 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