Crudely parse or
and or-join
. (#388) r=nalexander
This commit is contained in:
parent
4b874deae1
commit
0d15381e11
3 changed files with 378 additions and 22 deletions
|
@ -27,12 +27,15 @@ use self::mentat_query::{
|
||||||
FindSpec,
|
FindSpec,
|
||||||
FnArg,
|
FnArg,
|
||||||
FromValue,
|
FromValue,
|
||||||
|
OrJoin,
|
||||||
|
OrWhereClause,
|
||||||
Pattern,
|
Pattern,
|
||||||
PatternNonValuePlace,
|
PatternNonValuePlace,
|
||||||
PatternValuePlace,
|
PatternValuePlace,
|
||||||
Predicate,
|
Predicate,
|
||||||
PredicateFn,
|
PredicateFn,
|
||||||
SrcVar,
|
SrcVar,
|
||||||
|
UnifyVars,
|
||||||
Variable,
|
Variable,
|
||||||
WhereClause,
|
WhereClause,
|
||||||
};
|
};
|
||||||
|
@ -110,28 +113,114 @@ def_value_satisfy_parser_fn!(Where,
|
||||||
PatternNonValuePlace,
|
PatternNonValuePlace,
|
||||||
PatternNonValuePlace::from_value);
|
PatternNonValuePlace::from_value);
|
||||||
|
|
||||||
/// Take a vector Value containing one vector Value, and return the `Vec` inside the inner vector.
|
fn seq<T: Into<Option<edn::Value>>>(x: T) -> Option<Vec<edn::Value>> {
|
||||||
/// Also accepts an inner list, returning it as a `Vec`.
|
match x.into() {
|
||||||
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::List(items)) => Some(items.into_iter().collect()),
|
||||||
Some(edn::Value::Vector(items)) => Some(items),
|
Some(edn::Value::Vector(items)) => Some(items),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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) => {
|
||||||
|
seq(v.pop())
|
||||||
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def_value_parser_fn!(Where, and, (), input, {
|
||||||
|
matches_plain_symbol!("and", input)
|
||||||
|
});
|
||||||
|
|
||||||
|
def_value_parser_fn!(Where, or, (), input, {
|
||||||
|
matches_plain_symbol!("or", input)
|
||||||
|
});
|
||||||
|
|
||||||
|
def_value_parser_fn!(Where, or_join, (), input, {
|
||||||
|
matches_plain_symbol!("or-join", input)
|
||||||
|
});
|
||||||
|
|
||||||
|
def_value_parser_fn!(Where, rule_vars, Vec<Variable>, input, {
|
||||||
|
satisfy_map(|x: edn::Value| {
|
||||||
|
seq(x).and_then(|items| {
|
||||||
|
let mut p = many1(Query::variable()).skip(eof());
|
||||||
|
Query::to_parsed_value(p.parse_lazy(&items[..]).into())
|
||||||
|
})}).parse_stream(input)
|
||||||
|
});
|
||||||
|
|
||||||
|
def_value_parser_fn!(Where, or_pattern_clause, OrWhereClause, input, {
|
||||||
|
Where::clause().map(|clause| OrWhereClause::Clause(clause)).parse_stream(input)
|
||||||
|
});
|
||||||
|
|
||||||
|
def_value_parser_fn!(Where, or_and_clause, OrWhereClause, input, {
|
||||||
|
satisfy_map(|x: edn::Value| {
|
||||||
|
seq(x).and_then(|items| {
|
||||||
|
let mut p = Where::and()
|
||||||
|
.with(many1(Where::clause()))
|
||||||
|
.skip(eof())
|
||||||
|
.map(OrWhereClause::And);
|
||||||
|
let r: ParseResult<OrWhereClause, _> = p.parse_lazy(&items[..]).into();
|
||||||
|
Query::to_parsed_value(r)
|
||||||
|
})
|
||||||
|
}).parse_stream(input)
|
||||||
|
});
|
||||||
|
|
||||||
|
def_value_parser_fn!(Where, or_where_clause, OrWhereClause, input, {
|
||||||
|
choice([Where::or_pattern_clause(), Where::or_and_clause()]).parse_stream(input)
|
||||||
|
});
|
||||||
|
|
||||||
|
def_value_parser_fn!(Where, or_clause, WhereClause, input, {
|
||||||
|
satisfy_map(|x: edn::Value| {
|
||||||
|
seq(x).and_then(|items| {
|
||||||
|
let mut p = Where::or()
|
||||||
|
.with(many1(Where::or_where_clause()))
|
||||||
|
.skip(eof())
|
||||||
|
.map(|clauses| {
|
||||||
|
WhereClause::OrJoin(
|
||||||
|
OrJoin {
|
||||||
|
unify_vars: UnifyVars::Implicit,
|
||||||
|
clauses: clauses,
|
||||||
|
})
|
||||||
|
});
|
||||||
|
let r: ParseResult<WhereClause, _> = p.parse_lazy(&items[..]).into();
|
||||||
|
Query::to_parsed_value(r)
|
||||||
|
})
|
||||||
|
}).parse_stream(input)
|
||||||
|
});
|
||||||
|
|
||||||
|
def_value_parser_fn!(Where, or_join_clause, WhereClause, input, {
|
||||||
|
satisfy_map(|x: edn::Value| {
|
||||||
|
seq(x).and_then(|items| {
|
||||||
|
let mut p = Where::or_join()
|
||||||
|
.with(Where::rule_vars())
|
||||||
|
.and(many1(Where::or_where_clause()))
|
||||||
|
.skip(eof())
|
||||||
|
.map(|(vars, clauses)| {
|
||||||
|
WhereClause::OrJoin(
|
||||||
|
OrJoin {
|
||||||
|
unify_vars: UnifyVars::Explicit(vars),
|
||||||
|
clauses: clauses,
|
||||||
|
})
|
||||||
|
});
|
||||||
|
let r: ParseResult<WhereClause, _> = p.parse_lazy(&items[..]).into();
|
||||||
|
Query::to_parsed_value(r)
|
||||||
|
})
|
||||||
|
}).parse_stream(input)
|
||||||
|
});
|
||||||
|
|
||||||
/// A vector containing just a parenthesized filter expression.
|
/// A vector containing just a parenthesized filter expression.
|
||||||
def_value_parser_fn!(Where, pred, WhereClause, input, {
|
def_value_parser_fn!(Where, pred, WhereClause, input, {
|
||||||
satisfy_map(|x: edn::Value| {
|
satisfy_map(|x: edn::Value| {
|
||||||
// Accept either a list or a vector here:
|
// Accept either a list or a vector here:
|
||||||
// `[(foo ?x ?y)]` or `[[foo ?x ?y]]`
|
// `[(foo ?x ?y)]` or `[[foo ?x ?y]]`
|
||||||
unwrap_nested(x).and_then(|items| {
|
unwrap_nested(x).and_then(|items| {
|
||||||
let mut p = (Query::predicate_fn(), Query::arguments(), eof()).map(|(f, args, _)| {
|
let mut p = (Query::predicate_fn(), Query::arguments())
|
||||||
|
.skip(eof())
|
||||||
|
.map(|(f, args)| {
|
||||||
WhereClause::Pred(
|
WhereClause::Pred(
|
||||||
Predicate {
|
Predicate {
|
||||||
operator: f.0,
|
operator: f.0,
|
||||||
|
@ -154,9 +243,9 @@ def_value_parser_fn!(Where, pattern, WhereClause, input, {
|
||||||
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
|
||||||
optional(Where::pattern_non_value_place()), // tx
|
optional(Where::pattern_non_value_place())) // tx
|
||||||
eof())
|
.skip(eof())
|
||||||
.map(|(src, e, a, v, tx, _)| {
|
.map(|(src, e, a, v, tx)| {
|
||||||
let v = v.unwrap_or(PatternValuePlace::Placeholder);
|
let v = v.unwrap_or(PatternValuePlace::Placeholder);
|
||||||
let tx = tx.unwrap_or(PatternNonValuePlace::Placeholder);
|
let tx = tx.unwrap_or(PatternNonValuePlace::Placeholder);
|
||||||
|
|
||||||
|
@ -190,15 +279,28 @@ def_value_parser_fn!(Where, pattern, WhereClause, input, {
|
||||||
});
|
});
|
||||||
|
|
||||||
def_value_parser_fn!(Query, arguments, Vec<FnArg>, input, {
|
def_value_parser_fn!(Query, arguments, Vec<FnArg>, input, {
|
||||||
(many::<Vec<FnArg>, _>(Query::fn_arg()), eof())
|
(many::<Vec<FnArg>, _>(Query::fn_arg()))
|
||||||
.map(|(args, _)| { args })
|
.skip(eof())
|
||||||
.parse_stream(input)
|
.parse_stream(input)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
def_value_parser_fn!(Where, clause, WhereClause, input, {
|
||||||
|
choice([Where::pattern(),
|
||||||
|
Where::pred(),
|
||||||
|
// It's either
|
||||||
|
// (or-join [vars] clauses…)
|
||||||
|
// or
|
||||||
|
// (or clauses…)
|
||||||
|
// We don't yet handle source vars.
|
||||||
|
Where::or_join_clause(),
|
||||||
|
Where::or_clause(),
|
||||||
|
]).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 and predicates. See #239 for more.
|
// Right now we only support patterns and predicates. See #239 for more.
|
||||||
(many1::<Vec<WhereClause>, _>(choice([Where::pattern(), Where::pred()])), eof())
|
(many1::<Vec<WhereClause>, _>(Where::clause()))
|
||||||
.map(|(patterns, _)| { patterns })
|
.skip(eof())
|
||||||
.parse_stream(input)
|
.parse_stream(input)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -213,15 +315,19 @@ def_value_parser_fn!(Find, ellipsis, (), input, {
|
||||||
});
|
});
|
||||||
|
|
||||||
def_value_parser_fn!(Find, find_scalar, FindSpec, input, {
|
def_value_parser_fn!(Find, find_scalar, FindSpec, input, {
|
||||||
(Query::variable(), Find::period(), eof())
|
Query::variable()
|
||||||
.map(|(var, _, _)| FindSpec::FindScalar(Element::Variable(var)))
|
.skip(Find::period())
|
||||||
|
.skip(eof())
|
||||||
|
.map(|var| FindSpec::FindScalar(Element::Variable(var)))
|
||||||
.parse_stream(input)
|
.parse_stream(input)
|
||||||
});
|
});
|
||||||
|
|
||||||
def_value_parser_fn!(Find, find_coll, FindSpec, input, {
|
def_value_parser_fn!(Find, find_coll, FindSpec, input, {
|
||||||
satisfy_unwrap!(edn::Value::Vector, y, {
|
satisfy_unwrap!(edn::Value::Vector, y, {
|
||||||
let mut p = (Query::variable(), Find::ellipsis(), eof())
|
let mut p = Query::variable()
|
||||||
.map(|(var, _, _)| FindSpec::FindColl(Element::Variable(var)));
|
.skip(Find::ellipsis())
|
||||||
|
.skip(eof())
|
||||||
|
.map(|var| FindSpec::FindColl(Element::Variable(var)));
|
||||||
let r: ParseResult<FindSpec, _> = p.parse_lazy(&y[..]).into();
|
let r: ParseResult<FindSpec, _> = p.parse_lazy(&y[..]).into();
|
||||||
Query::to_parsed_value(r)
|
Query::to_parsed_value(r)
|
||||||
})
|
})
|
||||||
|
@ -229,8 +335,8 @@ def_value_parser_fn!(Find, find_coll, FindSpec, input, {
|
||||||
});
|
});
|
||||||
|
|
||||||
def_value_parser_fn!(Find, elements, Vec<Element>, input, {
|
def_value_parser_fn!(Find, elements, Vec<Element>, input, {
|
||||||
(many1::<Vec<Variable>, _>(Query::variable()), eof())
|
many1::<Vec<Variable>, _>(Query::variable()).skip(eof())
|
||||||
.map(|(vars, _)| {
|
.map(|vars| {
|
||||||
vars.into_iter()
|
vars.into_iter()
|
||||||
.map(Element::Variable)
|
.map(Element::Variable)
|
||||||
.collect()
|
.collect()
|
||||||
|
@ -392,6 +498,67 @@ mod test {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rule_vars() {
|
||||||
|
let e = edn::PlainSymbol::new("?e");
|
||||||
|
let input = [edn::Value::Vector(vec![edn::Value::PlainSymbol(e.clone())])];
|
||||||
|
assert_parses_to!(Where::rule_vars, input,
|
||||||
|
vec![Variable(e.clone())]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_or() {
|
||||||
|
let oj = edn::PlainSymbol::new("or");
|
||||||
|
let e = edn::PlainSymbol::new("?e");
|
||||||
|
let a = edn::PlainSymbol::new("?a");
|
||||||
|
let v = edn::PlainSymbol::new("?v");
|
||||||
|
let input = [edn::Value::List(
|
||||||
|
vec![edn::Value::PlainSymbol(oj),
|
||||||
|
edn::Value::Vector(vec![edn::Value::PlainSymbol(e.clone()),
|
||||||
|
edn::Value::PlainSymbol(a.clone()),
|
||||||
|
edn::Value::PlainSymbol(v.clone())])].into_iter().collect())];
|
||||||
|
assert_parses_to!(Where::or_clause, input,
|
||||||
|
WhereClause::OrJoin(
|
||||||
|
OrJoin {
|
||||||
|
unify_vars: UnifyVars::Implicit,
|
||||||
|
clauses: vec![OrWhereClause::Clause(
|
||||||
|
WhereClause::Pattern(Pattern {
|
||||||
|
source: None,
|
||||||
|
entity: PatternNonValuePlace::Variable(Variable(e)),
|
||||||
|
attribute: PatternNonValuePlace::Variable(Variable(a)),
|
||||||
|
value: PatternValuePlace::Variable(Variable(v)),
|
||||||
|
tx: PatternNonValuePlace::Placeholder,
|
||||||
|
}))],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_or_join() {
|
||||||
|
let oj = edn::PlainSymbol::new("or-join");
|
||||||
|
let e = edn::PlainSymbol::new("?e");
|
||||||
|
let a = edn::PlainSymbol::new("?a");
|
||||||
|
let v = edn::PlainSymbol::new("?v");
|
||||||
|
let input = [edn::Value::List(
|
||||||
|
vec![edn::Value::PlainSymbol(oj),
|
||||||
|
edn::Value::Vector(vec![edn::Value::PlainSymbol(e.clone())]),
|
||||||
|
edn::Value::Vector(vec![edn::Value::PlainSymbol(e.clone()),
|
||||||
|
edn::Value::PlainSymbol(a.clone()),
|
||||||
|
edn::Value::PlainSymbol(v.clone())])].into_iter().collect())];
|
||||||
|
assert_parses_to!(Where::or_join_clause, input,
|
||||||
|
WhereClause::OrJoin(
|
||||||
|
OrJoin {
|
||||||
|
unify_vars: UnifyVars::Explicit(vec![Variable(e.clone())]),
|
||||||
|
clauses: vec![OrWhereClause::Clause(
|
||||||
|
WhereClause::Pattern(Pattern {
|
||||||
|
source: None,
|
||||||
|
entity: PatternNonValuePlace::Variable(Variable(e)),
|
||||||
|
attribute: PatternNonValuePlace::Variable(Variable(a)),
|
||||||
|
value: PatternValuePlace::Variable(Variable(v)),
|
||||||
|
tx: PatternNonValuePlace::Placeholder,
|
||||||
|
}))],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_find_sp_variable() {
|
fn test_find_sp_variable() {
|
||||||
let sym = edn::PlainSymbol::new("?x");
|
let sym = edn::PlainSymbol::new("?x");
|
||||||
|
|
|
@ -12,16 +12,22 @@ extern crate mentat_query_parser;
|
||||||
extern crate mentat_query;
|
extern crate mentat_query;
|
||||||
extern crate edn;
|
extern crate edn;
|
||||||
|
|
||||||
use edn::PlainSymbol;
|
use edn::{
|
||||||
|
NamespacedKeyword,
|
||||||
|
PlainSymbol,
|
||||||
|
};
|
||||||
|
|
||||||
use mentat_query::{
|
use mentat_query::{
|
||||||
Element,
|
Element,
|
||||||
FindSpec,
|
FindSpec,
|
||||||
FnArg,
|
FnArg,
|
||||||
|
OrJoin,
|
||||||
|
OrWhereClause,
|
||||||
Pattern,
|
Pattern,
|
||||||
PatternNonValuePlace,
|
PatternNonValuePlace,
|
||||||
PatternValuePlace,
|
PatternValuePlace,
|
||||||
Predicate,
|
Predicate,
|
||||||
|
UnifyVars,
|
||||||
Variable,
|
Variable,
|
||||||
WhereClause,
|
WhereClause,
|
||||||
};
|
};
|
||||||
|
@ -54,3 +60,146 @@ fn can_parse_predicates() {
|
||||||
]}),
|
]}),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_parse_simple_or() {
|
||||||
|
let s = "[:find ?x . :where (or [?x _ 10] [?x _ 15])]";
|
||||||
|
let p = parse_find_string(s).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(p.find_spec,
|
||||||
|
FindSpec::FindScalar(Element::Variable(Variable(PlainSymbol::new("?x")))));
|
||||||
|
assert_eq!(p.where_clauses,
|
||||||
|
vec![
|
||||||
|
WhereClause::OrJoin(OrJoin {
|
||||||
|
unify_vars: UnifyVars::Implicit,
|
||||||
|
clauses: vec![
|
||||||
|
OrWhereClause::Clause(
|
||||||
|
WhereClause::Pattern(Pattern {
|
||||||
|
source: None,
|
||||||
|
entity: PatternNonValuePlace::Variable(Variable(PlainSymbol::new("?x"))),
|
||||||
|
attribute: PatternNonValuePlace::Placeholder,
|
||||||
|
value: PatternValuePlace::EntidOrInteger(10),
|
||||||
|
tx: PatternNonValuePlace::Placeholder,
|
||||||
|
})),
|
||||||
|
OrWhereClause::Clause(
|
||||||
|
WhereClause::Pattern(Pattern {
|
||||||
|
source: None,
|
||||||
|
entity: PatternNonValuePlace::Variable(Variable(PlainSymbol::new("?x"))),
|
||||||
|
attribute: PatternNonValuePlace::Placeholder,
|
||||||
|
value: PatternValuePlace::EntidOrInteger(15),
|
||||||
|
tx: PatternNonValuePlace::Placeholder,
|
||||||
|
})),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_parse_unit_or_join() {
|
||||||
|
let s = "[:find ?x . :where (or-join [?x] [?x _ 15])]";
|
||||||
|
let p = parse_find_string(s).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(p.find_spec,
|
||||||
|
FindSpec::FindScalar(Element::Variable(Variable(PlainSymbol::new("?x")))));
|
||||||
|
assert_eq!(p.where_clauses,
|
||||||
|
vec![
|
||||||
|
WhereClause::OrJoin(OrJoin {
|
||||||
|
unify_vars: UnifyVars::Explicit(vec![Variable(PlainSymbol::new("?x"))]),
|
||||||
|
clauses: vec![
|
||||||
|
OrWhereClause::Clause(
|
||||||
|
WhereClause::Pattern(Pattern {
|
||||||
|
source: None,
|
||||||
|
entity: PatternNonValuePlace::Variable(Variable(PlainSymbol::new("?x"))),
|
||||||
|
attribute: PatternNonValuePlace::Placeholder,
|
||||||
|
value: PatternValuePlace::EntidOrInteger(15),
|
||||||
|
tx: PatternNonValuePlace::Placeholder,
|
||||||
|
})),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_parse_simple_or_join() {
|
||||||
|
let s = "[:find ?x . :where (or-join [?x] [?x _ 10] [?x _ 15])]";
|
||||||
|
let p = parse_find_string(s).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(p.find_spec,
|
||||||
|
FindSpec::FindScalar(Element::Variable(Variable(PlainSymbol::new("?x")))));
|
||||||
|
assert_eq!(p.where_clauses,
|
||||||
|
vec![
|
||||||
|
WhereClause::OrJoin(OrJoin {
|
||||||
|
unify_vars: UnifyVars::Explicit(vec![Variable(PlainSymbol::new("?x"))]),
|
||||||
|
clauses: vec![
|
||||||
|
OrWhereClause::Clause(
|
||||||
|
WhereClause::Pattern(Pattern {
|
||||||
|
source: None,
|
||||||
|
entity: PatternNonValuePlace::Variable(Variable(PlainSymbol::new("?x"))),
|
||||||
|
attribute: PatternNonValuePlace::Placeholder,
|
||||||
|
value: PatternValuePlace::EntidOrInteger(10),
|
||||||
|
tx: PatternNonValuePlace::Placeholder,
|
||||||
|
})),
|
||||||
|
OrWhereClause::Clause(
|
||||||
|
WhereClause::Pattern(Pattern {
|
||||||
|
source: None,
|
||||||
|
entity: PatternNonValuePlace::Variable(Variable(PlainSymbol::new("?x"))),
|
||||||
|
attribute: PatternNonValuePlace::Placeholder,
|
||||||
|
value: PatternValuePlace::EntidOrInteger(15),
|
||||||
|
tx: PatternNonValuePlace::Placeholder,
|
||||||
|
})),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_parse_simple_or_and_join() {
|
||||||
|
let s = "[:find ?x . :where (or [?x _ 10] (and (or [?x :foo/bar ?y] [?x :foo/baz ?y]) [(< ?y 1)]))]";
|
||||||
|
let p = parse_find_string(s).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(p.find_spec,
|
||||||
|
FindSpec::FindScalar(Element::Variable(Variable(PlainSymbol::new("?x")))));
|
||||||
|
assert_eq!(p.where_clauses,
|
||||||
|
vec![
|
||||||
|
WhereClause::OrJoin(OrJoin {
|
||||||
|
unify_vars: UnifyVars::Implicit,
|
||||||
|
clauses: vec![
|
||||||
|
OrWhereClause::Clause(
|
||||||
|
WhereClause::Pattern(Pattern {
|
||||||
|
source: None,
|
||||||
|
entity: PatternNonValuePlace::Variable(Variable(PlainSymbol::new("?x"))),
|
||||||
|
attribute: PatternNonValuePlace::Placeholder,
|
||||||
|
value: PatternValuePlace::EntidOrInteger(10),
|
||||||
|
tx: PatternNonValuePlace::Placeholder,
|
||||||
|
})),
|
||||||
|
OrWhereClause::And(
|
||||||
|
vec![
|
||||||
|
WhereClause::OrJoin(OrJoin {
|
||||||
|
unify_vars: UnifyVars::Implicit,
|
||||||
|
clauses: vec![
|
||||||
|
OrWhereClause::Clause(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,
|
||||||
|
})),
|
||||||
|
OrWhereClause::Clause(WhereClause::Pattern(Pattern {
|
||||||
|
source: None,
|
||||||
|
entity: PatternNonValuePlace::Variable(Variable(PlainSymbol::new("?x"))),
|
||||||
|
attribute: PatternNonValuePlace::Ident(NamespacedKeyword::new("foo", "baz")),
|
||||||
|
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(1),
|
||||||
|
]}),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
}
|
|
@ -474,13 +474,53 @@ pub struct Predicate {
|
||||||
pub args: Vec<FnArg>,
|
pub args: Vec<FnArg>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub enum UnifyVars {
|
||||||
|
/// `Implicit` means the variables in an `or` or `not` are derived from the enclosed pattern.
|
||||||
|
/// DataScript regards these vars as 'free': these variables don't need to be bound by the
|
||||||
|
/// enclosing environment.
|
||||||
|
///
|
||||||
|
/// Datomic's documentation implies that all implicit variables are required:
|
||||||
|
///
|
||||||
|
/// > Datomic will attempt to push the or clause down until all necessary variables are bound,
|
||||||
|
/// > and will throw an exception if that is not possible.
|
||||||
|
///
|
||||||
|
/// but that would render top-level `or` expressions (as used in Datomic's own examples!)
|
||||||
|
/// impossible, so we assume that this is an error in the documentation.
|
||||||
|
///
|
||||||
|
/// All contained 'arms' in an `or` with implicit variables must bind the same vars.
|
||||||
|
Implicit,
|
||||||
|
|
||||||
|
/// `Explicit` means the variables in an `or-join` or `not-join` are explicitly listed,
|
||||||
|
/// specified with `required-vars` syntax.
|
||||||
|
///
|
||||||
|
/// DataScript parses these as free, but allows (incorrectly) the use of more complicated
|
||||||
|
/// `rule-vars` syntax.
|
||||||
|
///
|
||||||
|
/// Only the named variables will be unified with the enclosing query.
|
||||||
|
///
|
||||||
|
/// Every 'arm' in an `or-join` must mention the entire set of explicit vars.
|
||||||
|
Explicit(Vec<Variable>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub enum OrWhereClause {
|
||||||
|
Clause(WhereClause),
|
||||||
|
And(Vec<WhereClause>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub struct OrJoin {
|
||||||
|
pub unify_vars: UnifyVars,
|
||||||
|
pub clauses: Vec<OrWhereClause>,
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum WhereClause {
|
pub enum WhereClause {
|
||||||
Not,
|
Not,
|
||||||
NotJoin,
|
NotJoin,
|
||||||
Or,
|
OrJoin(OrJoin),
|
||||||
OrJoin,
|
|
||||||
Pred(Predicate),
|
Pred(Predicate),
|
||||||
WhereFn,
|
WhereFn,
|
||||||
RuleExpr,
|
RuleExpr,
|
||||||
|
|
Loading…
Reference in a new issue