Implement parsing of query predicates. (#380) r=nalexander
This commit is contained in:
parent
1c4e30a906
commit
d83c8620cd
4 changed files with 184 additions and 56 deletions
|
@ -41,16 +41,20 @@ use std::collections::BTreeMap;
|
||||||
|
|
||||||
use self::mentat_query::{
|
use self::mentat_query::{
|
||||||
FindQuery,
|
FindQuery,
|
||||||
|
FnArg,
|
||||||
FromValue,
|
FromValue,
|
||||||
|
Predicate,
|
||||||
|
PredicateFn,
|
||||||
SrcVar,
|
SrcVar,
|
||||||
Variable,
|
Variable,
|
||||||
};
|
};
|
||||||
|
|
||||||
use self::mentat_parser_utils::ValueParseError;
|
use self::mentat_parser_utils::ValueParseError;
|
||||||
|
|
||||||
use super::parse::{
|
use super::parse::{
|
||||||
Result,
|
|
||||||
ErrorKind,
|
ErrorKind,
|
||||||
QueryParseResult,
|
QueryParseResult,
|
||||||
|
Result,
|
||||||
clause_seq_to_patterns,
|
clause_seq_to_patterns,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -106,8 +110,8 @@ fn parse_find_parts(find: &[edn::Value],
|
||||||
find_spec: spec,
|
find_spec: spec,
|
||||||
default_source: source,
|
default_source: source,
|
||||||
with: with_vars,
|
with: with_vars,
|
||||||
in_vars: vec!(), // TODO
|
in_vars: vec![], // TODO
|
||||||
in_sources: vec!(), // TODO
|
in_sources: vec![], // TODO
|
||||||
where_clauses: where_clauses,
|
where_clauses: where_clauses,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -230,6 +234,26 @@ mod test_parse {
|
||||||
value: PatternValuePlace::Variable(Variable(PlainSymbol::new("?y"))),
|
value: PatternValuePlace::Variable(Variable(PlainSymbol::new("?y"))),
|
||||||
tx: PatternNonValuePlace::Placeholder,
|
tx: PatternNonValuePlace::Placeholder,
|
||||||
})]);
|
})]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_predicate() {
|
||||||
|
let input = "[:find ?x :where [?x :foo/bar ?y] [[< ?y 10]]]";
|
||||||
|
let parsed = parse_find_string(input).unwrap();
|
||||||
|
assert_eq!(parsed.where_clauses,
|
||||||
|
vec![
|
||||||
|
WhereClause::Pattern(Pattern {
|
||||||
|
source: None,
|
||||||
|
entity: PatternNonValuePlace::Variable(Variable(PlainSymbol::new("?x"))),
|
||||||
|
attribute: PatternNonValuePlace::Ident(NamespacedKeyword::new("foo", "bar")),
|
||||||
|
value: PatternValuePlace::Variable(Variable(PlainSymbol::new("?y"))),
|
||||||
|
tx: PatternNonValuePlace::Placeholder,
|
||||||
|
}),
|
||||||
|
WhereClause::Pred(Predicate {
|
||||||
|
operator: PlainSymbol::new("<"),
|
||||||
|
args: vec![FnArg::Variable(Variable(PlainSymbol::new("?y"))),
|
||||||
|
FnArg::EntidOrInteger(10)],
|
||||||
|
}),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ extern crate edn;
|
||||||
extern crate mentat_parser_utils;
|
extern crate mentat_parser_utils;
|
||||||
extern crate mentat_query;
|
extern crate mentat_query;
|
||||||
|
|
||||||
use self::combine::{eof, many1, optional, parser, satisfy_map, Parser, ParseResult, Stream};
|
use self::combine::{eof, many, many1, optional, parser, satisfy_map, Parser, ParseResult, Stream};
|
||||||
use self::combine::combinator::{choice, try};
|
use self::combine::combinator::{choice, try};
|
||||||
|
|
||||||
use self::mentat_parser_utils::{
|
use self::mentat_parser_utils::{
|
||||||
|
@ -25,10 +25,13 @@ use self::mentat_query::{
|
||||||
Element,
|
Element,
|
||||||
FindQuery,
|
FindQuery,
|
||||||
FindSpec,
|
FindSpec,
|
||||||
|
FnArg,
|
||||||
FromValue,
|
FromValue,
|
||||||
Pattern,
|
Pattern,
|
||||||
PatternNonValuePlace,
|
PatternNonValuePlace,
|
||||||
PatternValuePlace,
|
PatternValuePlace,
|
||||||
|
Predicate,
|
||||||
|
PredicateFn,
|
||||||
SrcVar,
|
SrcVar,
|
||||||
Variable,
|
Variable,
|
||||||
WhereClause,
|
WhereClause,
|
||||||
|
@ -93,20 +96,61 @@ impl<I> Query<I>
|
||||||
|
|
||||||
def_value_satisfy_parser_fn!(Query, variable, Variable, Variable::from_value);
|
def_value_satisfy_parser_fn!(Query, variable, Variable, Variable::from_value);
|
||||||
def_value_satisfy_parser_fn!(Query, source_var, SrcVar, SrcVar::from_value);
|
def_value_satisfy_parser_fn!(Query, source_var, SrcVar, SrcVar::from_value);
|
||||||
|
def_value_satisfy_parser_fn!(Query, predicate_fn, PredicateFn, PredicateFn::from_value);
|
||||||
|
def_value_satisfy_parser_fn!(Query, fn_arg, FnArg, FnArg::from_value);
|
||||||
|
|
||||||
pub struct Where<I>(::std::marker::PhantomData<fn(I) -> I>);
|
pub struct Where<I>(::std::marker::PhantomData<fn(I) -> I>);
|
||||||
|
|
||||||
def_value_satisfy_parser_fn!(Where, pattern_value_place, PatternValuePlace, PatternValuePlace::from_value);
|
def_value_satisfy_parser_fn!(Where,
|
||||||
def_value_satisfy_parser_fn!(Where, pattern_non_value_place, PatternNonValuePlace, PatternNonValuePlace::from_value);
|
pattern_value_place,
|
||||||
|
PatternValuePlace,
|
||||||
|
PatternValuePlace::from_value);
|
||||||
|
def_value_satisfy_parser_fn!(Where,
|
||||||
|
pattern_non_value_place,
|
||||||
|
PatternNonValuePlace,
|
||||||
|
PatternNonValuePlace::from_value);
|
||||||
|
|
||||||
def_value_parser_fn!(Where, pattern, Pattern, input, {
|
/// Take a vector Value containing one vector Value, and return the `Vec` inside the inner vector.
|
||||||
|
/// Also accepts an inner list, returning it as a `Vec`.
|
||||||
|
fn unwrap_nested(x: edn::Value) -> Option<Vec<edn::Value>> {
|
||||||
|
match x {
|
||||||
|
edn::Value::Vector(mut v) => {
|
||||||
|
match v.pop() {
|
||||||
|
Some(edn::Value::List(items)) => Some(items.into_iter().collect()),
|
||||||
|
Some(edn::Value::Vector(items)) => Some(items),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A vector containing just a parenthesized filter expression.
|
||||||
|
def_value_parser_fn!(Where, pred, WhereClause, input, {
|
||||||
|
satisfy_map(|x: edn::Value| {
|
||||||
|
// Accept either a list or a vector here:
|
||||||
|
// `[(foo ?x ?y)]` or `[[foo ?x ?y]]`
|
||||||
|
unwrap_nested(x).and_then(|items| {
|
||||||
|
let mut p = (Query::predicate_fn(), Query::arguments(), eof()).map(|(f, args, _)| {
|
||||||
|
WhereClause::Pred(
|
||||||
|
Predicate {
|
||||||
|
operator: f.0,
|
||||||
|
args: args,
|
||||||
|
})
|
||||||
|
});
|
||||||
|
let r: ParseResult<WhereClause, _> = p.parse_lazy(&items[..]).into();
|
||||||
|
Query::to_parsed_value(r)
|
||||||
|
})
|
||||||
|
}).parse_stream(input)
|
||||||
|
});
|
||||||
|
|
||||||
|
def_value_parser_fn!(Where, pattern, WhereClause, input, {
|
||||||
satisfy_map(|x: edn::Value| {
|
satisfy_map(|x: edn::Value| {
|
||||||
if let edn::Value::Vector(y) = x {
|
if let edn::Value::Vector(y) = x {
|
||||||
// While *technically* Datomic allows you to have a query like:
|
// While *technically* Datomic allows you to have a query like:
|
||||||
// [:find … :where [[?x]]]
|
// [:find … :where [[?x]]]
|
||||||
// We don't -- we require at list e, a.
|
// We don't -- we require at least e, a.
|
||||||
let mut p =
|
let mut p = (optional(Query::source_var()), // src
|
||||||
(optional(Query::source_var()), // src
|
|
||||||
Where::pattern_non_value_place(), // e
|
Where::pattern_non_value_place(), // e
|
||||||
Where::pattern_non_value_place(), // a
|
Where::pattern_non_value_place(), // a
|
||||||
optional(Where::pattern_value_place()), // v
|
optional(Where::pattern_value_place()), // v
|
||||||
|
@ -119,7 +163,7 @@ def_value_parser_fn!(Where, pattern, Pattern, input, {
|
||||||
// Pattern::new takes care of reversal of reversed
|
// Pattern::new takes care of reversal of reversed
|
||||||
// attributes: [?x :foo/_bar ?y] turns into
|
// attributes: [?x :foo/_bar ?y] turns into
|
||||||
// [?y :foo/bar ?x].
|
// [?y :foo/bar ?x].
|
||||||
Pattern::new(src, e, a, v, tx)
|
Pattern::new(src, e, a, v, tx).map(WhereClause::Pattern)
|
||||||
});
|
});
|
||||||
|
|
||||||
// This is a bit messy: the inner conversion to a Pattern can
|
// This is a bit messy: the inner conversion to a Pattern can
|
||||||
|
@ -136,8 +180,8 @@ def_value_parser_fn!(Where, pattern, Pattern, input, {
|
||||||
// ```
|
// ```
|
||||||
//
|
//
|
||||||
// is nonsense. That leaves us with nested optionals; we unwrap them here.
|
// is nonsense. That leaves us with nested optionals; we unwrap them here.
|
||||||
let r: ParseResult<Option<Pattern>, _> = p.parse_lazy(&y[..]).into();
|
let r: ParseResult<Option<WhereClause>, _> = p.parse_lazy(&y[..]).into();
|
||||||
let v: Option<Option<Pattern>> = r.ok().map(|x| x.0);
|
let v: Option<Option<WhereClause>> = Query::to_parsed_value(r);
|
||||||
v.unwrap_or(None)
|
v.unwrap_or(None)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -145,12 +189,16 @@ def_value_parser_fn!(Where, pattern, Pattern, input, {
|
||||||
}).parse_stream(input)
|
}).parse_stream(input)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
def_value_parser_fn!(Query, arguments, Vec<FnArg>, input, {
|
||||||
|
(many::<Vec<FnArg>, _>(Query::fn_arg()), eof())
|
||||||
|
.map(|(args, _)| { args })
|
||||||
|
.parse_stream(input)
|
||||||
|
});
|
||||||
|
|
||||||
def_value_parser_fn!(Where, clauses, Vec<WhereClause>, input, {
|
def_value_parser_fn!(Where, clauses, Vec<WhereClause>, input, {
|
||||||
// Right now we only support patterns. See #239 for more.
|
// Right now we only support patterns and predicates. See #239 for more.
|
||||||
(many1::<Vec<Pattern>, _>(Where::pattern()), eof())
|
(many1::<Vec<WhereClause>, _>(choice([Where::pattern(), Where::pred()])), eof())
|
||||||
.map(|(patterns, _)| {
|
.map(|(patterns, _)| { patterns })
|
||||||
patterns.into_iter().map(WhereClause::Pattern).collect()
|
|
||||||
})
|
|
||||||
.parse_stream(input)
|
.parse_stream(input)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -272,18 +320,17 @@ mod test {
|
||||||
let a = edn::NamespacedKeyword::new("foo", "bar");
|
let a = edn::NamespacedKeyword::new("foo", "bar");
|
||||||
let v = OrderedFloat(99.9);
|
let v = OrderedFloat(99.9);
|
||||||
let tx = edn::PlainSymbol::new("?tx");
|
let tx = edn::PlainSymbol::new("?tx");
|
||||||
let input = [edn::Value::Vector(
|
let input = [edn::Value::Vector(vec!(edn::Value::PlainSymbol(e.clone()),
|
||||||
vec!(edn::Value::PlainSymbol(e.clone()),
|
|
||||||
edn::Value::NamespacedKeyword(a.clone()),
|
edn::Value::NamespacedKeyword(a.clone()),
|
||||||
edn::Value::Float(v.clone()),
|
edn::Value::Float(v.clone()),
|
||||||
edn::Value::PlainSymbol(tx.clone())))];
|
edn::Value::PlainSymbol(tx.clone())))];
|
||||||
assert_parses_to!(Where::pattern, input, Pattern {
|
assert_parses_to!(Where::pattern, input, WhereClause::Pattern(Pattern {
|
||||||
source: None,
|
source: None,
|
||||||
entity: PatternNonValuePlace::Placeholder,
|
entity: PatternNonValuePlace::Placeholder,
|
||||||
attribute: PatternNonValuePlace::Ident(a),
|
attribute: PatternNonValuePlace::Ident(a),
|
||||||
value: PatternValuePlace::Constant(NonIntegerConstant::Float(v)),
|
value: PatternValuePlace::Constant(NonIntegerConstant::Float(v)),
|
||||||
tx: PatternNonValuePlace::Variable(Variable(tx)),
|
tx: PatternNonValuePlace::Variable(Variable(tx)),
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -293,19 +340,18 @@ mod test {
|
||||||
let a = edn::PlainSymbol::new("?a");
|
let a = edn::PlainSymbol::new("?a");
|
||||||
let v = edn::PlainSymbol::new("?v");
|
let v = edn::PlainSymbol::new("?v");
|
||||||
let tx = edn::PlainSymbol::new("?tx");
|
let tx = edn::PlainSymbol::new("?tx");
|
||||||
let input = [edn::Value::Vector(
|
let input = [edn::Value::Vector(vec!(edn::Value::PlainSymbol(s.clone()),
|
||||||
vec!(edn::Value::PlainSymbol(s.clone()),
|
|
||||||
edn::Value::PlainSymbol(e.clone()),
|
edn::Value::PlainSymbol(e.clone()),
|
||||||
edn::Value::PlainSymbol(a.clone()),
|
edn::Value::PlainSymbol(a.clone()),
|
||||||
edn::Value::PlainSymbol(v.clone()),
|
edn::Value::PlainSymbol(v.clone()),
|
||||||
edn::Value::PlainSymbol(tx.clone())))];
|
edn::Value::PlainSymbol(tx.clone())))];
|
||||||
assert_parses_to!(Where::pattern, input, Pattern {
|
assert_parses_to!(Where::pattern, input, WhereClause::Pattern(Pattern {
|
||||||
source: Some(SrcVar::NamedSrc("x".to_string())),
|
source: Some(SrcVar::NamedSrc("x".to_string())),
|
||||||
entity: PatternNonValuePlace::Variable(Variable(e)),
|
entity: PatternNonValuePlace::Variable(Variable(e)),
|
||||||
attribute: PatternNonValuePlace::Variable(Variable(a)),
|
attribute: PatternNonValuePlace::Variable(Variable(a)),
|
||||||
value: PatternValuePlace::Variable(Variable(v)),
|
value: PatternValuePlace::Variable(Variable(v)),
|
||||||
tx: PatternNonValuePlace::Variable(Variable(tx)),
|
tx: PatternNonValuePlace::Variable(Variable(tx)),
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -314,8 +360,7 @@ mod test {
|
||||||
let a = edn::NamespacedKeyword::new("foo", "_bar");
|
let a = edn::NamespacedKeyword::new("foo", "_bar");
|
||||||
let v = OrderedFloat(99.9);
|
let v = OrderedFloat(99.9);
|
||||||
let tx = edn::PlainSymbol::new("?tx");
|
let tx = edn::PlainSymbol::new("?tx");
|
||||||
let input = [edn::Value::Vector(
|
let input = [edn::Value::Vector(vec!(edn::Value::PlainSymbol(e.clone()),
|
||||||
vec!(edn::Value::PlainSymbol(e.clone()),
|
|
||||||
edn::Value::NamespacedKeyword(a.clone()),
|
edn::Value::NamespacedKeyword(a.clone()),
|
||||||
edn::Value::Float(v.clone()),
|
edn::Value::Float(v.clone()),
|
||||||
edn::Value::PlainSymbol(tx.clone())))];
|
edn::Value::PlainSymbol(tx.clone())))];
|
||||||
|
@ -331,21 +376,20 @@ mod test {
|
||||||
let a = edn::NamespacedKeyword::new("foo", "_bar");
|
let a = edn::NamespacedKeyword::new("foo", "_bar");
|
||||||
let v = edn::PlainSymbol::new("?v");
|
let v = edn::PlainSymbol::new("?v");
|
||||||
let tx = edn::PlainSymbol::new("?tx");
|
let tx = edn::PlainSymbol::new("?tx");
|
||||||
let input = [edn::Value::Vector(
|
let input = [edn::Value::Vector(vec!(edn::Value::PlainSymbol(e.clone()),
|
||||||
vec!(edn::Value::PlainSymbol(e.clone()),
|
|
||||||
edn::Value::NamespacedKeyword(a.clone()),
|
edn::Value::NamespacedKeyword(a.clone()),
|
||||||
edn::Value::PlainSymbol(v.clone()),
|
edn::Value::PlainSymbol(v.clone()),
|
||||||
edn::Value::PlainSymbol(tx.clone())))];
|
edn::Value::PlainSymbol(tx.clone())))];
|
||||||
|
|
||||||
// Note that the attribute is no longer reversed, and the entity and value have
|
// Note that the attribute is no longer reversed, and the entity and value have
|
||||||
// switched places.
|
// switched places.
|
||||||
assert_parses_to!(Where::pattern, input, Pattern {
|
assert_parses_to!(Where::pattern, input, WhereClause::Pattern(Pattern {
|
||||||
source: None,
|
source: None,
|
||||||
entity: PatternNonValuePlace::Variable(Variable(v)),
|
entity: PatternNonValuePlace::Variable(Variable(v)),
|
||||||
attribute: PatternNonValuePlace::Ident(edn::NamespacedKeyword::new("foo", "bar")),
|
attribute: PatternNonValuePlace::Ident(edn::NamespacedKeyword::new("foo", "bar")),
|
||||||
value: PatternValuePlace::Placeholder,
|
value: PatternValuePlace::Placeholder,
|
||||||
tx: PatternNonValuePlace::Variable(Variable(tx)),
|
tx: PatternNonValuePlace::Variable(Variable(tx)),
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -12,24 +12,45 @@ extern crate mentat_query_parser;
|
||||||
extern crate mentat_query;
|
extern crate mentat_query;
|
||||||
extern crate edn;
|
extern crate edn;
|
||||||
|
|
||||||
use mentat_query::FindSpec::FindScalar;
|
|
||||||
use mentat_query::Element;
|
|
||||||
use mentat_query::Variable;
|
|
||||||
use edn::PlainSymbol;
|
use edn::PlainSymbol;
|
||||||
|
|
||||||
|
use mentat_query::{
|
||||||
|
Element,
|
||||||
|
FindSpec,
|
||||||
|
FnArg,
|
||||||
|
Pattern,
|
||||||
|
PatternNonValuePlace,
|
||||||
|
PatternValuePlace,
|
||||||
|
Predicate,
|
||||||
|
Variable,
|
||||||
|
WhereClause,
|
||||||
|
};
|
||||||
|
|
||||||
|
use mentat_query_parser::parse_find_string;
|
||||||
|
|
||||||
///! N.B., parsing a query can be done without reference to a DB.
|
///! N.B., parsing a query can be done without reference to a DB.
|
||||||
///! Processing the parsed query into something we can work with
|
///! Processing the parsed query into something we can work with
|
||||||
///! for planning involves interrogating the schema and idents in
|
///! for planning involves interrogating the schema and idents in
|
||||||
///! the store.
|
///! the store.
|
||||||
///! See <https://github.com/mozilla/mentat/wiki/Querying> for more.
|
///! See <https://github.com/mozilla/mentat/wiki/Querying> for more.
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_parse_trivial_find() {
|
fn can_parse_predicates() {
|
||||||
let find = FindScalar(Element::Variable(Variable(PlainSymbol("?foo".to_string()))));
|
let s = "[:find [?x ...] :where [?x _ ?y] [(< ?y 10)]]";
|
||||||
|
let p = parse_find_string(s).unwrap();
|
||||||
|
|
||||||
if let FindScalar(Element::Variable(Variable(PlainSymbol(name)))) = find {
|
assert_eq!(p.find_spec,
|
||||||
assert_eq!("?foo", name);
|
FindSpec::FindColl(Element::Variable(Variable(PlainSymbol::new("?x")))));
|
||||||
} else {
|
assert_eq!(p.where_clauses,
|
||||||
panic!()
|
vec![
|
||||||
}
|
WhereClause::Pattern(Pattern {
|
||||||
|
source: None,
|
||||||
|
entity: PatternNonValuePlace::Variable(Variable(PlainSymbol::new("?x"))),
|
||||||
|
attribute: PatternNonValuePlace::Placeholder,
|
||||||
|
value: PatternValuePlace::Variable(Variable(PlainSymbol::new("?y"))),
|
||||||
|
tx: PatternNonValuePlace::Placeholder,
|
||||||
|
}),
|
||||||
|
WhereClause::Pred(Predicate { operator: PlainSymbol::new("<"), args: vec![
|
||||||
|
FnArg::Variable(Variable(PlainSymbol::new("?y"))), FnArg::EntidOrInteger(10),
|
||||||
|
]}),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,6 +75,26 @@ impl fmt::Debug for Variable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub struct PredicateFn(pub PlainSymbol);
|
||||||
|
|
||||||
|
impl FromValue<PredicateFn> for PredicateFn {
|
||||||
|
fn from_value(v: &edn::Value) -> Option<PredicateFn> {
|
||||||
|
if let edn::Value::PlainSymbol(ref s) = *v {
|
||||||
|
PredicateFn::from_symbol(s)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PredicateFn {
|
||||||
|
pub fn from_symbol(sym: &PlainSymbol) -> Option<PredicateFn> {
|
||||||
|
// TODO: validate the acceptable set of function names.
|
||||||
|
Some(PredicateFn(sym.clone()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum SrcVar {
|
pub enum SrcVar {
|
||||||
DefaultSrc,
|
DefaultSrc,
|
||||||
|
@ -121,6 +141,7 @@ impl NonIntegerConstant {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum FnArg {
|
pub enum FnArg {
|
||||||
Variable(Variable),
|
Variable(Variable),
|
||||||
SrcVar(SrcVar),
|
SrcVar(SrcVar),
|
||||||
|
@ -129,6 +150,19 @@ pub enum FnArg {
|
||||||
Constant(NonIntegerConstant),
|
Constant(NonIntegerConstant),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FromValue<FnArg> for FnArg {
|
||||||
|
fn from_value(v: &edn::Value) -> Option<FnArg> {
|
||||||
|
// TODO: support SrcVars.
|
||||||
|
Variable::from_value(v)
|
||||||
|
.and_then(|v| Some(FnArg::Variable(v)))
|
||||||
|
.or_else(||
|
||||||
|
match v {
|
||||||
|
&edn::Value::Integer(i) => Some(FnArg::EntidOrInteger(i)),
|
||||||
|
_ => unimplemented!(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// e, a, tx can't be values -- no strings, no floats -- and so
|
/// e, a, tx can't be values -- no strings, no floats -- and so
|
||||||
/// they can only be variables, entity IDs, ident keywords, or
|
/// they can only be variables, entity IDs, ident keywords, or
|
||||||
/// placeholders.
|
/// placeholders.
|
||||||
|
@ -433,6 +467,11 @@ impl Pattern {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub struct Predicate {
|
||||||
|
pub operator: PlainSymbol,
|
||||||
|
pub args: Vec<FnArg>,
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
@ -441,7 +480,7 @@ pub enum WhereClause {
|
||||||
NotJoin,
|
NotJoin,
|
||||||
Or,
|
Or,
|
||||||
OrJoin,
|
OrJoin,
|
||||||
Pred,
|
Pred(Predicate),
|
||||||
WhereFn,
|
WhereFn,
|
||||||
RuleExpr,
|
RuleExpr,
|
||||||
Pattern(Pattern),
|
Pattern(Pattern),
|
||||||
|
|
Loading…
Reference in a new issue