Skip to main content

edn/
query.rs

1// Copyright 2016-2018 Mozilla
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
4// this file except in compliance with the License. You may obtain a copy of the
5// License at http://www.apache.org/licenses/LICENSE-2.0
6// Unless required by applicable law or agreed to in writing, software distributed
7// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
8// CONDITIONS OF ANY KIND, either express or implied. See the License for the
9// specific language governing permissions and limitations under the License.
10
11//! This module defines some core types that support find expressions: sources,
12//! variables, expressions, etc.
13//! These are produced as 'fuel' by the query parser, consumed by the query
14//! translator and executor.
15//!
16//! Many of these types are defined as simple structs that are little more than
17//! a richer type alias: a variable, for example, is really just a fancy kind
18//! of string.
19//!
20//! At some point in the future, we might consider reducing copying and memory
21//! usage by recasting all of these string-holding structs and enums in terms
22//! of string references, with those references being slices of some parsed
23//! input query string, and valid for the lifetime of that string.
24//!
25//! For now, for the sake of simplicity, all of these strings are heap-allocated.
26//!
27//! Furthermore, we might cut out some of the chaff here: each time a 'tagged'
28//! type is used within an enum, we have an opportunity to simplify and use the
29//! inner type directly in conjunction with matching on the enum. Before diving
30//! deeply into this it's worth recognizing that this loss of 'sovereignty' is
31//! a tradeoff against well-typed function signatures and other such boundaries.
32use std::collections::{BTreeSet, HashSet};
33
34use std;
35use std::fmt;
36use std::rc::Rc;
37
38use crate::{BigInt, DateTime, OrderedFloat, Utc, Uuid};
39
40use crate::value_rc::{FromRc, ValueRc};
41
42pub use crate::{Keyword, PlainSymbol};
43
44pub type SrcVarName = String; // Do not include the required syntactic '$'.
45
46#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
47pub struct Variable(pub Rc<PlainSymbol>);
48
49impl Variable {
50    pub fn as_str(&self) -> &str {
51        self.0.as_ref().0.as_str()
52    }
53
54    pub fn name(&self) -> PlainSymbol {
55        self.0.as_ref().clone()
56    }
57
58    /// Return a new `Variable`, assuming that the provided string is a valid name.
59    pub fn from_valid_name(name: &str) -> Variable {
60        let s = PlainSymbol::plain(name);
61        assert!(s.is_var_symbol());
62        Variable(Rc::new(s))
63    }
64}
65
66pub trait FromValue<T> {
67    fn from_value(v: &crate::ValueAndSpan) -> Option<T>;
68}
69
70/// If the provided EDN value is a PlainSymbol beginning with '?', return
71/// it wrapped in a Variable. If not, return None.
72/// TODO: intern strings. #398.
73impl FromValue<Variable> for Variable {
74    fn from_value(v: &crate::ValueAndSpan) -> Option<Variable> {
75        if let crate::SpannedValue::PlainSymbol(ref s) = v.inner {
76            Variable::from_symbol(s)
77        } else {
78            None
79        }
80    }
81}
82
83impl Variable {
84    pub fn from_rc(sym: Rc<PlainSymbol>) -> Option<Variable> {
85        if sym.is_var_symbol() {
86            Some(Variable(sym))
87        } else {
88            None
89        }
90    }
91
92    /// TODO: intern strings. #398.
93    pub fn from_symbol(sym: &PlainSymbol) -> Option<Variable> {
94        if sym.is_var_symbol() {
95            Some(Variable(Rc::new(sym.clone())))
96        } else {
97            None
98        }
99    }
100}
101
102impl fmt::Debug for Variable {
103    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
104        write!(f, "var({})", self.0)
105    }
106}
107
108impl std::fmt::Display for Variable {
109    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
110        write!(f, "{}", self.0)
111    }
112}
113
114#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
115pub struct QueryFunction(pub PlainSymbol);
116
117impl FromValue<QueryFunction> for QueryFunction {
118    fn from_value(v: &crate::ValueAndSpan) -> Option<QueryFunction> {
119        if let crate::SpannedValue::PlainSymbol(ref s) = v.inner {
120            QueryFunction::from_symbol(s)
121        } else {
122            None
123        }
124    }
125}
126
127impl QueryFunction {
128    pub fn from_symbol(sym: &PlainSymbol) -> Option<QueryFunction> {
129        // TODO: validate the acceptable set of function names.
130        Some(QueryFunction(sym.clone()))
131    }
132}
133
134impl std::fmt::Display for QueryFunction {
135    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
136        write!(f, "{}", self.0)
137    }
138}
139
140#[derive(Clone, Debug, Eq, PartialEq)]
141pub enum Direction {
142    Ascending,
143    Descending,
144}
145
146/// An abstract declaration of ordering: direction and variable.
147#[derive(Clone, Debug, Eq, PartialEq)]
148pub struct Order(pub Direction, pub Variable); // Future: Element instead of Variable?
149
150#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
151pub enum SrcVar {
152    DefaultSrc,
153    NamedSrc(SrcVarName),
154}
155
156impl FromValue<SrcVar> for SrcVar {
157    fn from_value(v: &crate::ValueAndSpan) -> Option<SrcVar> {
158        if let crate::SpannedValue::PlainSymbol(ref s) = v.inner {
159            SrcVar::from_symbol(s)
160        } else {
161            None
162        }
163    }
164}
165
166impl SrcVar {
167    pub fn from_symbol(sym: &PlainSymbol) -> Option<SrcVar> {
168        if sym.is_src_symbol() {
169            if sym.0 == "$" {
170                Some(SrcVar::DefaultSrc)
171            } else {
172                Some(SrcVar::NamedSrc(sym.name().to_string()))
173            }
174        } else {
175            None
176        }
177    }
178}
179
180/// These are the scalar values representable in EDN.
181#[derive(Clone, Debug, Eq, PartialEq)]
182pub enum NonIntegerConstant {
183    Boolean(bool),
184    BigInteger(BigInt),
185    Float(OrderedFloat<f64>),
186    Text(ValueRc<String>),
187    Instant(DateTime<Utc>),
188    Uuid(Uuid),
189}
190
191impl<'a> From<&'a str> for NonIntegerConstant {
192    fn from(val: &'a str) -> NonIntegerConstant {
193        NonIntegerConstant::Text(ValueRc::new(val.to_string()))
194    }
195}
196
197impl From<String> for NonIntegerConstant {
198    fn from(val: String) -> NonIntegerConstant {
199        NonIntegerConstant::Text(ValueRc::new(val))
200    }
201}
202
203#[derive(Clone, Debug, Eq, PartialEq)]
204pub enum FnArg {
205    Variable(Variable),
206    SrcVar(SrcVar),
207    EntidOrInteger(i64),
208    IdentOrKeyword(Keyword),
209    Constant(NonIntegerConstant),
210    // The collection values representable in EDN.  There's no advantage to destructuring up front,
211    // since consumers will need to handle arbitrarily nested EDN themselves anyway.
212    Vector(Vec<FnArg>),
213}
214
215impl FromValue<FnArg> for FnArg {
216    fn from_value(v: &crate::ValueAndSpan) -> Option<FnArg> {
217        use crate::SpannedValue::*;
218        match v.inner {
219            Integer(x) => Some(FnArg::EntidOrInteger(x)),
220            PlainSymbol(ref x) if x.is_src_symbol() => SrcVar::from_symbol(x).map(FnArg::SrcVar),
221            PlainSymbol(ref x) if x.is_var_symbol() => {
222                Variable::from_symbol(x).map(FnArg::Variable)
223            }
224            PlainSymbol(_) => None,
225            Keyword(ref x) => Some(FnArg::IdentOrKeyword(x.clone())),
226            Instant(x) => Some(FnArg::Constant(NonIntegerConstant::Instant(x))),
227            Uuid(x) => Some(FnArg::Constant(NonIntegerConstant::Uuid(x))),
228            Boolean(x) => Some(FnArg::Constant(NonIntegerConstant::Boolean(x))),
229            Float(x) => Some(FnArg::Constant(NonIntegerConstant::Float(x))),
230            BigInteger(ref x) => Some(FnArg::Constant(NonIntegerConstant::BigInteger(x.clone()))),
231            Text(ref x) =>
232            // TODO: intern strings. #398.
233            {
234                Some(FnArg::Constant(x.clone().into()))
235            }
236            Nil | NamespacedSymbol(_) | Vector(_) | List(_) | Set(_) | Map(_) | Bytes(_) => None,
237        }
238    }
239}
240
241// For display in column headings in the repl.
242impl std::fmt::Display for FnArg {
243    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
244        match self {
245            FnArg::Variable(ref var) => write!(f, "{}", var),
246            FnArg::SrcVar(ref var) => {
247                if var == &SrcVar::DefaultSrc {
248                    write!(f, "$")
249                } else {
250                    write!(f, "{:?}", var)
251                }
252            }
253            FnArg::EntidOrInteger(entid) => write!(f, "{}", entid),
254            FnArg::IdentOrKeyword(ref kw) => write!(f, "{}", kw),
255            FnArg::Constant(ref constant) => write!(f, "{:?}", constant),
256            FnArg::Vector(ref vec) => write!(f, "{:?}", vec),
257        }
258    }
259}
260
261impl FnArg {
262    pub fn as_variable(&self) -> Option<&Variable> {
263        match self {
264            FnArg::Variable(ref v) => Some(v),
265            _ => None,
266        }
267    }
268}
269
270/// e, a, tx can't be values -- no strings, no floats -- and so
271/// they can only be variables, entity IDs, ident keywords, or
272/// placeholders.
273/// This encoding allows us to represent integers that aren't
274/// entity IDs. That'll get filtered out in the context of the
275/// database.
276#[derive(Clone, Debug, Eq, PartialEq)]
277pub enum PatternNonValuePlace {
278    Placeholder,
279    Variable(Variable),
280    Entid(i64), // Will always be +ve. See #190.
281    Ident(ValueRc<Keyword>),
282}
283
284impl From<Rc<Keyword>> for PatternNonValuePlace {
285    fn from(value: Rc<Keyword>) -> Self {
286        PatternNonValuePlace::Ident(ValueRc::from_rc(value))
287    }
288}
289
290impl From<Keyword> for PatternNonValuePlace {
291    fn from(value: Keyword) -> Self {
292        PatternNonValuePlace::Ident(ValueRc::new(value))
293    }
294}
295
296impl PatternNonValuePlace {
297    // I think we'll want move variants, so let's leave these here for now.
298    #[allow(dead_code)]
299    fn into_pattern_value_place(self) -> PatternValuePlace {
300        match self {
301            PatternNonValuePlace::Placeholder => PatternValuePlace::Placeholder,
302            PatternNonValuePlace::Variable(x) => PatternValuePlace::Variable(x),
303            PatternNonValuePlace::Entid(x) => PatternValuePlace::EntidOrInteger(x),
304            PatternNonValuePlace::Ident(x) => PatternValuePlace::IdentOrKeyword(x),
305        }
306    }
307
308    fn to_pattern_value_place(&self) -> PatternValuePlace {
309        match *self {
310            PatternNonValuePlace::Placeholder => PatternValuePlace::Placeholder,
311            PatternNonValuePlace::Variable(ref x) => PatternValuePlace::Variable(x.clone()),
312            PatternNonValuePlace::Entid(x) => PatternValuePlace::EntidOrInteger(x),
313            PatternNonValuePlace::Ident(ref x) => PatternValuePlace::IdentOrKeyword(x.clone()),
314        }
315    }
316}
317
318impl FromValue<PatternNonValuePlace> for PatternNonValuePlace {
319    fn from_value(v: &crate::ValueAndSpan) -> Option<PatternNonValuePlace> {
320        match v.inner {
321            crate::SpannedValue::Integer(x) => {
322                if x >= 0 {
323                    Some(PatternNonValuePlace::Entid(x))
324                } else {
325                    None
326                }
327            }
328            crate::SpannedValue::PlainSymbol(ref x) => {
329                if x.0.as_str() == "_" {
330                    Some(PatternNonValuePlace::Placeholder)
331                } else {
332                    Variable::from_symbol(x).map(PatternNonValuePlace::Variable)
333                }
334            }
335            crate::SpannedValue::Keyword(ref x) => Some(x.clone().into()),
336            _ => None,
337        }
338    }
339}
340
341#[derive(Clone, Debug, Eq, PartialEq)]
342pub enum IdentOrEntid {
343    Ident(Keyword),
344    Entid(i64),
345}
346
347/// The `v` part of a pattern can be much broader: it can represent
348/// integers that aren't entity IDs (particularly negative integers),
349/// strings, and all the rest. We group those under `Constant`.
350#[derive(Clone, Debug, Eq, PartialEq)]
351pub enum PatternValuePlace {
352    Placeholder,
353    Variable(Variable),
354    EntidOrInteger(i64),
355    IdentOrKeyword(ValueRc<Keyword>),
356    Constant(NonIntegerConstant),
357}
358
359impl From<Rc<Keyword>> for PatternValuePlace {
360    fn from(value: Rc<Keyword>) -> Self {
361        PatternValuePlace::IdentOrKeyword(ValueRc::from_rc(value))
362    }
363}
364
365impl From<Keyword> for PatternValuePlace {
366    fn from(value: Keyword) -> Self {
367        PatternValuePlace::IdentOrKeyword(ValueRc::new(value))
368    }
369}
370
371impl FromValue<PatternValuePlace> for PatternValuePlace {
372    fn from_value(v: &crate::ValueAndSpan) -> Option<PatternValuePlace> {
373        match v.inner {
374            crate::SpannedValue::Integer(x) => Some(PatternValuePlace::EntidOrInteger(x)),
375            crate::SpannedValue::PlainSymbol(ref x) if x.0.as_str() == "_" => {
376                Some(PatternValuePlace::Placeholder)
377            }
378            crate::SpannedValue::PlainSymbol(ref x) => {
379                Variable::from_symbol(x).map(PatternValuePlace::Variable)
380            }
381            crate::SpannedValue::Keyword(ref x) => Some(x.clone().into()),
382            crate::SpannedValue::Boolean(x) => {
383                Some(PatternValuePlace::Constant(NonIntegerConstant::Boolean(x)))
384            }
385            crate::SpannedValue::Float(x) => {
386                Some(PatternValuePlace::Constant(NonIntegerConstant::Float(x)))
387            }
388            crate::SpannedValue::BigInteger(ref x) => Some(PatternValuePlace::Constant(
389                NonIntegerConstant::BigInteger(x.clone()),
390            )),
391            crate::SpannedValue::Instant(x) => {
392                Some(PatternValuePlace::Constant(NonIntegerConstant::Instant(x)))
393            }
394            crate::SpannedValue::Text(ref x) =>
395            // TODO: intern strings. #398.
396            {
397                Some(PatternValuePlace::Constant(x.clone().into()))
398            }
399            crate::SpannedValue::Uuid(ref u) => {
400                Some(PatternValuePlace::Constant(NonIntegerConstant::Uuid(*u)))
401            }
402
403            // These don't appear in queries.
404            crate::SpannedValue::Nil => None,
405            crate::SpannedValue::NamespacedSymbol(_) => None,
406            crate::SpannedValue::Map(_) => None,
407            crate::SpannedValue::List(_) => None,
408            crate::SpannedValue::Set(_) => None,
409            crate::SpannedValue::Vector(_) => None,
410            crate::SpannedValue::Bytes(_) => None,
411        }
412    }
413}
414
415impl PatternValuePlace {
416    // I think we'll want move variants, so let's leave these here for now.
417    #[allow(dead_code)]
418    fn into_pattern_non_value_place(self) -> Option<PatternNonValuePlace> {
419        match self {
420            PatternValuePlace::Placeholder => Some(PatternNonValuePlace::Placeholder),
421            PatternValuePlace::Variable(x) => Some(PatternNonValuePlace::Variable(x)),
422            PatternValuePlace::EntidOrInteger(x) => {
423                if x >= 0 {
424                    Some(PatternNonValuePlace::Entid(x))
425                } else {
426                    None
427                }
428            }
429            PatternValuePlace::IdentOrKeyword(x) => Some(PatternNonValuePlace::Ident(x)),
430            PatternValuePlace::Constant(_) => None,
431        }
432    }
433
434    fn to_pattern_non_value_place(&self) -> Option<PatternNonValuePlace> {
435        match *self {
436            PatternValuePlace::Placeholder => Some(PatternNonValuePlace::Placeholder),
437            PatternValuePlace::Variable(ref x) => Some(PatternNonValuePlace::Variable(x.clone())),
438            PatternValuePlace::EntidOrInteger(x) => {
439                if x >= 0 {
440                    Some(PatternNonValuePlace::Entid(x))
441                } else {
442                    None
443                }
444            }
445            PatternValuePlace::IdentOrKeyword(ref x) => {
446                Some(PatternNonValuePlace::Ident(x.clone()))
447            }
448            PatternValuePlace::Constant(_) => None,
449        }
450    }
451}
452
453// Not yet used.
454// pub enum PullDefaultValue {
455//     EntidOrInteger(i64),
456//     IdentOrKeyword(Rc<Keyword>),
457//     Constant(NonIntegerConstant),
458// }
459
460#[derive(Clone, Debug, Eq, PartialEq)]
461pub enum PullConcreteAttribute {
462    Ident(Rc<Keyword>),
463    Entid(i64),
464}
465
466#[derive(Clone, Debug, Eq, PartialEq)]
467pub struct NamedPullAttribute {
468    pub attribute: PullConcreteAttribute,
469    pub alias: Option<Rc<Keyword>>,
470    /// True for a reverse-reference pull like `:person/_friends`. When set,
471    /// `attribute` holds the *forward* ident (used for schema lookup) and the
472    /// pull walks the VAET index to find entities that refer to each pulled
473    /// entity via that attribute. Ported from pg_mentat's reverse pull.
474    pub reverse: bool,
475}
476
477impl From<PullConcreteAttribute> for NamedPullAttribute {
478    fn from(a: PullConcreteAttribute) -> Self {
479        NamedPullAttribute {
480            attribute: a,
481            alias: None,
482            reverse: false,
483        }
484    }
485}
486
487#[derive(Clone, Debug, Eq, PartialEq)]
488pub enum PullAttributeSpec {
489    Wildcard,
490    Attribute(NamedPullAttribute),
491    // PullMapSpec(Vec<…>),
492    // LimitedAttribute(NamedPullAttribute, u64),  // Limit nil => Attribute instead.
493    // DefaultedAttribute(NamedPullAttribute, PullDefaultValue),
494}
495
496impl std::fmt::Display for PullConcreteAttribute {
497    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
498        match self {
499            PullConcreteAttribute::Ident(ref k) => write!(f, "{}", k),
500            PullConcreteAttribute::Entid(i) => write!(f, "{}", i),
501        }
502    }
503}
504
505impl std::fmt::Display for NamedPullAttribute {
506    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
507        let attr = &self.attribute;
508        if let Some(ref alias) = self.alias {
509            if self.reverse {
510                write!(f, "_{} :as {}", attr, alias)
511            } else {
512                write!(f, "{} :as {}", attr, alias)
513            }
514        } else if self.reverse {
515            write!(f, "_{}", attr)
516        } else {
517            write!(f, "{}", attr)
518        }
519    }
520}
521
522impl std::fmt::Display for PullAttributeSpec {
523    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
524        match self {
525            PullAttributeSpec::Wildcard => write!(f, "*"),
526            PullAttributeSpec::Attribute(ref attr) => write!(f, "{}", attr),
527        }
528    }
529}
530
531#[derive(Clone, Debug, Eq, PartialEq)]
532pub struct Pull {
533    pub var: Variable,
534    pub patterns: Vec<PullAttributeSpec>,
535}
536
537#[derive(Clone, Debug, Eq, PartialEq)]
538pub struct Aggregate {
539    pub func: QueryFunction,
540    pub args: Vec<FnArg>,
541}
542
543#[derive(Clone, Debug, Eq, PartialEq)]
544pub enum Element {
545    Variable(Variable),
546    Aggregate(Aggregate),
547
548    /// In a query with a `max` or `min` aggregate, a corresponding variable
549    /// (indicated in the query with `(the ?var)`, is guaranteed to come from
550    /// the row that provided the max or min value. Queries with more than one
551    /// `max` or `min` cannot yield predictable behavior, and will err during
552    /// algebrizing.
553    Corresponding(Variable),
554    Pull(Pull),
555}
556
557impl Element {
558    /// Returns true if the element must yield only one value.
559    pub fn is_unit(&self) -> bool {
560        match self {
561            Element::Variable(_) => false,
562            Element::Pull(_) => false,
563            Element::Aggregate(_) => true,
564            Element::Corresponding(_) => true,
565        }
566    }
567}
568
569impl From<Variable> for Element {
570    fn from(x: Variable) -> Element {
571        Element::Variable(x)
572    }
573}
574
575impl std::fmt::Display for Element {
576    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
577        match self {
578            Element::Variable(ref var) => write!(f, "{}", var),
579            Element::Pull(Pull {
580                ref var,
581                ref patterns,
582            }) => {
583                write!(f, "(pull {} [ ", var)?;
584                for p in patterns.iter() {
585                    write!(f, "{} ", p)?;
586                }
587                write!(f, "])")
588            }
589            Element::Aggregate(ref agg) => match agg.args.len() {
590                0 => write!(f, "({})", agg.func),
591                1 => write!(f, "({} {})", agg.func, agg.args[0]),
592                _ => write!(f, "({} {:?})", agg.func, agg.args),
593            },
594            Element::Corresponding(ref var) => write!(f, "(the {})", var),
595        }
596    }
597}
598
599#[derive(Clone, Debug, Eq, PartialEq)]
600pub enum Limit {
601    Unlimited,
602    Fixed(u64),
603    Variable(Variable),
604}
605
606/// The `:offset` clause of a find query: skip N leading results.
607/// Ported from pg_mentat for pagination support.
608#[derive(Clone, Debug, Eq, PartialEq)]
609pub enum Offset {
610    /// No offset: start from the first result.
611    Unlimited,
612    Fixed(u64),
613    Variable(Variable),
614}
615
616/// A definition of the first part of a find query: the
617/// `[:find ?foo ?bar…]` bit.
618///
619/// There are four different kinds of find specs, allowing you to query for
620/// a single value, a collection of values from different entities, a single
621/// tuple (relation), or a collection of tuples.
622///
623/// Examples:
624///
625/// ```rust
626/// # use edn::query::{Element, FindSpec, Variable};
627/// let elements = vec![
628///   Element::Variable(Variable::from_valid_name("?foo")),
629///   Element::Variable(Variable::from_valid_name("?bar")),
630/// ];
631/// let rel = FindSpec::FindRel(elements);
632///
633/// if let FindSpec::FindRel(elements) = rel {
634///   assert_eq!(2, elements.len());
635/// }
636/// ```
637///
638#[derive(Clone, Debug, Eq, PartialEq)]
639pub enum FindSpec {
640    /// Returns an array of arrays, represented as a single array with length a multiple of width.
641    FindRel(Vec<Element>),
642
643    /// Returns an array of scalars, usually homogeneous.
644    /// This is equivalent to mapping over the results of a `FindRel`,
645    /// returning the first value of each.
646    FindColl(Element),
647
648    /// Returns a single tuple: a heterogeneous array of scalars. Equivalent to
649    /// taking the first result from a `FindRel`.
650    FindTuple(Vec<Element>),
651
652    /// Returns a single scalar value. Equivalent to taking the first result
653    /// from a `FindColl`.
654    FindScalar(Element),
655}
656
657/// Returns true if the provided `FindSpec` returns at most one result.
658impl FindSpec {
659    pub fn is_unit_limited(&self) -> bool {
660        use self::FindSpec::*;
661        match self {
662            FindScalar(..) => true,
663            FindTuple(..) => true,
664            FindRel(..) => false,
665            FindColl(..) => false,
666        }
667    }
668
669    pub fn expected_column_count(&self) -> usize {
670        use self::FindSpec::*;
671        match self {
672            FindScalar(..) => 1,
673            FindColl(..) => 1,
674            FindTuple(ref elems) | &FindRel(ref elems) => elems.len(),
675        }
676    }
677
678    /// Returns true if the provided `FindSpec` cares about distinct results.
679    ///
680    /// I use the words "cares about" because find is generally defined in terms of producing distinct
681    /// results at the Datalog level.
682    ///
683    /// Two of the find specs (scalar and tuple) produce only a single result. Those don't need to be
684    /// run with `SELECT DISTINCT`, because we're only consuming a single result. Those queries will be
685    /// run with `LIMIT 1`.
686    ///
687    /// Additionally, some projections cannot produce duplicate results: `[:find (max ?x) …]`, for
688    /// example.
689    ///
690    /// This function gives us the hook to add that logic when we're ready.
691    ///
692    /// Beyond this, `DISTINCT` is not always needed. For example, in some kinds of accumulation or
693    /// sampling projections we might not need to do it at the SQL level because we're consuming into
694    /// a dupe-eliminating data structure like a Set, or we know that a particular query cannot produce
695    /// duplicate results.
696    pub fn requires_distinct(&self) -> bool {
697        !self.is_unit_limited()
698    }
699
700    pub fn columns<'s>(&'s self) -> Box<dyn Iterator<Item = &'s Element> + 's> {
701        use self::FindSpec::*;
702        match self {
703            FindScalar(ref e) => Box::new(std::iter::once(e)),
704            FindColl(ref e) => Box::new(std::iter::once(e)),
705            FindTuple(ref v) => Box::new(v.iter()),
706            FindRel(ref v) => Box::new(v.iter()),
707        }
708    }
709}
710
711// Datomic accepts variable or placeholder.  DataScript accepts recursive bindings.  Mentat sticks
712// to the non-recursive form Datomic accepts, which is much simpler to process.
713#[derive(Clone, Debug, Eq, Hash, PartialEq)]
714pub enum VariableOrPlaceholder {
715    Placeholder,
716    Variable(Variable),
717}
718
719impl VariableOrPlaceholder {
720    pub fn into_var(self) -> Option<Variable> {
721        match self {
722            VariableOrPlaceholder::Placeholder => None,
723            VariableOrPlaceholder::Variable(var) => Some(var),
724        }
725    }
726
727    pub fn var(&self) -> Option<&Variable> {
728        match self {
729            VariableOrPlaceholder::Placeholder => None,
730            VariableOrPlaceholder::Variable(ref var) => Some(var),
731        }
732    }
733}
734
735#[derive(Clone, Debug, Eq, PartialEq)]
736pub enum Binding {
737    BindScalar(Variable),
738    BindColl(Variable),
739    BindRel(Vec<VariableOrPlaceholder>),
740    BindTuple(Vec<VariableOrPlaceholder>),
741}
742
743impl Binding {
744    /// Return each variable or `None`, in order.
745    pub fn variables(&self) -> Vec<Option<Variable>> {
746        match self {
747            &Binding::BindScalar(ref var) | &Binding::BindColl(ref var) => vec![Some(var.clone())],
748            &Binding::BindRel(ref vars) | &Binding::BindTuple(ref vars) => {
749                vars.iter().map(|x| x.var().cloned()).collect()
750            }
751        }
752    }
753
754    /// Return `true` if no variables are bound, i.e., all binding entries are placeholders.
755    pub fn is_empty(&self) -> bool {
756        match self {
757            &Binding::BindScalar(_) | &Binding::BindColl(_) => false,
758            &Binding::BindRel(ref vars) | &Binding::BindTuple(ref vars) => {
759                vars.iter().all(|x| x.var().is_none())
760            }
761        }
762    }
763
764    /// Return `true` if no variable is bound twice, i.e., each binding entry is either a
765    /// placeholder or unique.
766    ///
767    /// ```
768    /// use edn::query::{Binding,Variable,VariableOrPlaceholder};
769    /// use std::rc::Rc;
770    ///
771    /// let v = Variable::from_valid_name("?foo");
772    /// let vv = VariableOrPlaceholder::Variable(v);
773    /// let p = VariableOrPlaceholder::Placeholder;
774    ///
775    /// let e = Binding::BindTuple(vec![p.clone()]);
776    /// let b = Binding::BindTuple(vec![p.clone(), vv.clone()]);
777    /// let d = Binding::BindTuple(vec![vv.clone(), p, vv]);
778    /// assert!(b.is_valid());          // One var, one placeholder: OK.
779    /// assert!(!e.is_valid());         // Empty: not OK.
780    /// assert!(!d.is_valid());         // Duplicate var: not OK.
781    /// ```
782    pub fn is_valid(&self) -> bool {
783        match self {
784            Binding::BindScalar(_) | &Binding::BindColl(_) => true,
785            Binding::BindRel(ref vars) | &Binding::BindTuple(ref vars) => {
786                let mut acc = HashSet::<Variable>::new();
787                for var in vars {
788                    if let VariableOrPlaceholder::Variable(ref var) = *var {
789                        if !acc.insert(var.clone()) {
790                            // It's invalid if there was an equal var already present in the set --
791                            // i.e., we have a duplicate var.
792                            return false;
793                        }
794                    }
795                }
796                // We're not valid if every place is a placeholder!
797                !acc.is_empty()
798            }
799        }
800    }
801}
802
803// Note that the "implicit blank" rule applies.
804// A pattern with a reversed attribute — :foo/_bar — is reversed
805// at the point of parsing. These `Pattern` instances only represent
806// one direction.
807#[derive(Clone, Debug, Eq, PartialEq)]
808pub struct Pattern {
809    pub source: Option<SrcVar>,
810    pub entity: PatternNonValuePlace,
811    pub attribute: PatternNonValuePlace,
812    pub value: PatternValuePlace,
813    pub tx: PatternNonValuePlace,
814    /// The `added` flag, a 5th pattern place for history queries:
815    /// `[?e ?a ?v ?tx ?added]`. Placeholder in an ordinary 4-place pattern.
816    pub added: PatternNonValuePlace,
817}
818
819impl Pattern {
820    pub fn simple(
821        e: PatternNonValuePlace,
822        a: PatternNonValuePlace,
823        v: PatternValuePlace,
824    ) -> Option<Pattern> {
825        Pattern::new(
826            None,
827            e,
828            a,
829            v,
830            PatternNonValuePlace::Placeholder,
831            PatternNonValuePlace::Placeholder,
832        )
833    }
834
835    pub fn new(
836        src: Option<SrcVar>,
837        e: PatternNonValuePlace,
838        a: PatternNonValuePlace,
839        v: PatternValuePlace,
840        tx: PatternNonValuePlace,
841        added: PatternNonValuePlace,
842    ) -> Option<Pattern> {
843        let aa = a.clone(); // Too tired of fighting borrow scope for now.
844        if let PatternNonValuePlace::Ident(ref k) = aa {
845            if k.is_backward() {
846                // e and v have different types; we must convert them.
847                // Not every parseable value is suitable for the entity field!
848                // As such, this is a failable constructor.
849                let e_v = e.to_pattern_value_place();
850                if let Some(v_e) = v.to_pattern_non_value_place() {
851                    return Some(Pattern {
852                        source: src,
853                        entity: v_e,
854                        attribute: k.to_reversed().into(),
855                        value: e_v,
856                        tx,
857                        added,
858                    });
859                } else {
860                    return None;
861                }
862            }
863        }
864        Some(Pattern {
865            source: src,
866            entity: e,
867            attribute: a,
868            value: v,
869            tx,
870            added,
871        })
872    }
873}
874
875#[derive(Clone, Debug, Eq, PartialEq)]
876pub struct Predicate {
877    pub operator: PlainSymbol,
878    pub args: Vec<FnArg>,
879}
880
881#[derive(Clone, Debug, Eq, PartialEq)]
882pub struct WhereFn {
883    pub operator: PlainSymbol,
884    pub args: Vec<FnArg>,
885    pub binding: Binding,
886}
887
888#[derive(Clone, Debug, Eq, PartialEq)]
889pub enum UnifyVars {
890    /// `Implicit` means the variables in an `or` or `not` are derived from the enclosed pattern.
891    /// DataScript regards these vars as 'free': these variables don't need to be bound by the
892    /// enclosing environment.
893    ///
894    /// Datomic's documentation implies that all implicit variables are required:
895    ///
896    /// > Datomic will attempt to push the or clause down until all necessary variables are bound,
897    /// > and will throw an exception if that is not possible.
898    ///
899    /// but that would render top-level `or` expressions (as used in Datomic's own examples!)
900    /// impossible, so we assume that this is an error in the documentation.
901    ///
902    /// All contained 'arms' in an `or` with implicit variables must bind the same vars.
903    Implicit,
904
905    /// `Explicit` means the variables in an `or-join` or `not-join` are explicitly listed,
906    /// specified with `required-vars` syntax.
907    ///
908    /// DataScript parses these as free, but allows (incorrectly) the use of more complicated
909    /// `rule-vars` syntax.
910    ///
911    /// Only the named variables will be unified with the enclosing query.
912    ///
913    /// Every 'arm' in an `or-join` must mention the entire set of explicit vars.
914    Explicit(BTreeSet<Variable>),
915}
916
917impl WhereClause {
918    pub fn is_pattern(&self) -> bool {
919        matches!(self, WhereClause::Pattern(_))
920    }
921}
922
923#[derive(Clone, Debug, Eq, PartialEq)]
924pub enum OrWhereClause {
925    Clause(WhereClause),
926    And(Vec<WhereClause>),
927}
928
929impl OrWhereClause {
930    pub fn is_pattern_or_patterns(&self) -> bool {
931        match self {
932            OrWhereClause::Clause(WhereClause::Pattern(_)) => true,
933            OrWhereClause::And(ref clauses) => clauses.iter().all(|clause| clause.is_pattern()),
934            _ => false,
935        }
936    }
937}
938
939#[derive(Clone, Debug, Eq, PartialEq)]
940pub struct OrJoin {
941    pub unify_vars: UnifyVars,
942    pub clauses: Vec<OrWhereClause>,
943
944    /// Caches the result of `collect_mentioned_variables`.
945    mentioned_vars: Option<BTreeSet<Variable>>,
946}
947
948#[derive(Clone, Debug, Eq, PartialEq)]
949pub struct NotJoin {
950    pub unify_vars: UnifyVars,
951    pub clauses: Vec<WhereClause>,
952}
953
954impl NotJoin {
955    pub fn new(unify_vars: UnifyVars, clauses: Vec<WhereClause>) -> NotJoin {
956        NotJoin {
957            unify_vars,
958            clauses,
959        }
960    }
961}
962
963#[derive(Clone, Debug, Eq, PartialEq)]
964pub struct TypeAnnotation {
965    pub value_type: Keyword,
966    pub variable: Variable,
967}
968
969#[allow(dead_code)]
970/// A rule invocation in a query, e.g., `(ancestor ?person ?ancestor)`.
971/// Ported from pg_mentat to support named and recursive rules.
972#[derive(Clone, Debug, Eq, PartialEq)]
973pub struct RuleInvocation {
974    pub name: PlainSymbol,
975    pub args: Vec<FnArg>,
976}
977
978/// A single rule clause: head + body.
979/// Example: `[(ancestor ?p ?a) [?p :parent ?a]]`
980/// Or recursive: `[(ancestor ?p ?a) [?p :parent ?x] (ancestor ?x ?a)]`
981#[derive(Clone, Debug, Eq, PartialEq)]
982pub struct RuleClause {
983    pub head: RuleInvocation,
984    pub body: Vec<WhereClause>,
985}
986
987/// A named rule with one or more clauses.
988/// Rules with multiple clauses represent alternatives (like OR).
989#[derive(Clone, Debug, Eq, PartialEq)]
990pub struct Rule {
991    pub name: PlainSymbol,
992    pub clauses: Vec<RuleClause>,
993}
994
995#[derive(Clone, Debug, Eq, PartialEq)]
996pub enum WhereClause {
997    NotJoin(NotJoin),
998    OrJoin(OrJoin),
999    Pred(Predicate),
1000    WhereFn(WhereFn),
1001    RuleExpr(RuleInvocation),
1002    Pattern(Pattern),
1003    TypeAnnotation(TypeAnnotation),
1004}
1005
1006#[allow(dead_code)]
1007#[derive(Debug, Eq, PartialEq)]
1008pub struct ParsedQuery {
1009    pub find_spec: FindSpec,
1010    pub default_source: SrcVar,
1011    pub with: Vec<Variable>,
1012    pub in_vars: Vec<Variable>,
1013    pub in_bindings: Vec<Binding>,
1014    pub in_sources: BTreeSet<SrcVar>,
1015    pub limit: Limit,
1016    pub offset: Offset,
1017    pub where_clauses: Vec<WhereClause>,
1018    pub order: Option<Vec<Order>>,
1019    pub distinct: bool,
1020    pub rules: Vec<Rule>,
1021}
1022
1023pub(crate) enum QueryPart {
1024    FindSpec(FindSpec),
1025    WithVars(Vec<Variable>),
1026    #[allow(dead_code)]
1027    InVars(Vec<Variable>),
1028    InBindings(Vec<Binding>),
1029    // `$` / `$named` source vars from `:in`. Previously nothing populated
1030    // ParsedQuery.in_sources; the grammar now routes source vars here so a
1031    // `:in $ [?a ...]` binding list is not polluted with `$` (which is not a
1032    // Variable and would shift positional inputs).
1033    InSources(Vec<SrcVar>),
1034    Limit(Limit),
1035    Offset(Offset),
1036    WhereClauses(Vec<WhereClause>),
1037    Order(Vec<Order>),
1038    Distinct,
1039    Rules(Vec<Rule>),
1040}
1041/// A `ParsedQuery` represents a parsed but potentially invalid query to the query algebrizer.
1042/// Such a query is syntactically valid but might be semantically invalid, for example because
1043/// constraints on the set of variables are not respected.
1044///
1045/// We split `ParsedQuery` from `FindQuery` because it's not easy to generalize over containers
1046/// (here, `Vec` and `BTreeSet`) in Rust.
1047impl ParsedQuery {
1048    pub(crate) fn from_parts(
1049        parts: Vec<QueryPart>,
1050    ) -> std::result::Result<ParsedQuery, &'static str> {
1051        let mut find_spec: Option<FindSpec> = None;
1052        let mut with: Option<Vec<Variable>> = None;
1053        let mut in_vars: Option<Vec<Variable>> = None;
1054        let mut in_bindings: Option<Vec<Binding>> = None;
1055        let mut in_sources: Option<Vec<SrcVar>> = None;
1056        let mut limit: Option<Limit> = None;
1057        let mut offset: Option<Offset> = None;
1058        let mut where_clauses: Option<Vec<WhereClause>> = None;
1059        let mut order: Option<Vec<Order>> = None;
1060        let mut distinct = false;
1061        let mut rules: Option<Vec<Rule>> = None;
1062
1063        for part in parts.into_iter() {
1064            match part {
1065                QueryPart::FindSpec(x) => {
1066                    if find_spec.is_some() {
1067                        return Err("find query has repeated :find");
1068                    }
1069                    find_spec = Some(x)
1070                }
1071                QueryPart::WithVars(x) => {
1072                    if with.is_some() {
1073                        return Err("find query has repeated :with");
1074                    }
1075                    with = Some(x)
1076                }
1077                QueryPart::InVars(x) => {
1078                    if in_vars.is_some() {
1079                        return Err("find query has repeated :in");
1080                    }
1081                    in_vars = Some(x)
1082                }
1083                QueryPart::InBindings(x) => {
1084                    if in_bindings.is_some() {
1085                        return Err("find query has repeated :in");
1086                    }
1087                    in_bindings = Some(x)
1088                }
1089                QueryPart::InSources(x) => {
1090                    if in_sources.is_some() {
1091                        return Err("find query has repeated :in");
1092                    }
1093                    in_sources = Some(x)
1094                }
1095                QueryPart::Limit(x) => {
1096                    if limit.is_some() {
1097                        return Err("find query has repeated :limit");
1098                    }
1099                    limit = Some(x)
1100                }
1101                QueryPart::Offset(x) => {
1102                    if offset.is_some() {
1103                        return Err("find query has repeated :offset");
1104                    }
1105                    offset = Some(x)
1106                }
1107                QueryPart::WhereClauses(x) => {
1108                    if where_clauses.is_some() {
1109                        return Err("find query has repeated :where");
1110                    }
1111                    where_clauses = Some(x)
1112                }
1113                QueryPart::Order(x) => {
1114                    if order.is_some() {
1115                        return Err("find query has repeated :order");
1116                    }
1117                    order = Some(x)
1118                }
1119                QueryPart::Distinct => {
1120                    distinct = true;
1121                }
1122                QueryPart::Rules(x) => {
1123                    if rules.is_some() {
1124                        return Err("find query has repeated :rules");
1125                    }
1126                    rules = Some(x)
1127                }
1128            }
1129        }
1130
1131        // If we got InBindings, derive in_vars from the scalar bindings
1132        // for backward compatibility with existing code that uses in_vars.
1133        let final_in_bindings = in_bindings.unwrap_or_default();
1134        let final_in_vars = if let Some(v) = in_vars {
1135            v
1136        } else {
1137            final_in_bindings
1138                .iter()
1139                .filter_map(|b| match b {
1140                    Binding::BindScalar(v) => Some(v.clone()),
1141                    _ => None,
1142                })
1143                .collect()
1144        };
1145
1146        Ok(ParsedQuery {
1147            find_spec: find_spec.ok_or("expected :find")?,
1148            default_source: SrcVar::DefaultSrc,
1149            with: with.unwrap_or_default(),
1150            in_vars: final_in_vars,
1151            in_bindings: final_in_bindings,
1152            in_sources: in_sources.unwrap_or_default().into_iter().collect(),
1153            limit: limit.unwrap_or(Limit::Unlimited),
1154            offset: offset.unwrap_or(Offset::Unlimited),
1155            where_clauses: where_clauses.ok_or("expected :where")?,
1156            order,
1157            distinct,
1158            rules: rules.unwrap_or_default(),
1159        })
1160    }
1161}
1162
1163impl OrJoin {
1164    pub fn new(unify_vars: UnifyVars, clauses: Vec<OrWhereClause>) -> OrJoin {
1165        OrJoin {
1166            unify_vars,
1167            clauses,
1168            mentioned_vars: None,
1169        }
1170    }
1171
1172    /// Return true if either the `OrJoin` is `UnifyVars::Implicit`, or if
1173    /// every variable mentioned inside the join is also mentioned in the `UnifyVars` list.
1174    pub fn is_fully_unified(&self) -> bool {
1175        match &self.unify_vars {
1176            UnifyVars::Implicit => true,
1177            UnifyVars::Explicit(ref vars) => {
1178                // We know that the join list must be a subset of the vars in the pattern, or
1179                // it would have failed validation. That allows us to simply compare counts here.
1180                // TODO: in debug mode, do a full intersection, and verify that our count check
1181                // returns the same results.
1182                // Use the cached list if we have one.
1183                if let Some(ref mentioned) = self.mentioned_vars {
1184                    vars.len() == mentioned.len()
1185                } else {
1186                    vars.len() == self.collect_mentioned_variables().len()
1187                }
1188            }
1189        }
1190    }
1191}
1192
1193pub trait ContainsVariables {
1194    fn accumulate_mentioned_variables(&self, acc: &mut BTreeSet<Variable>);
1195    fn collect_mentioned_variables(&self) -> BTreeSet<Variable> {
1196        let mut out = BTreeSet::new();
1197        self.accumulate_mentioned_variables(&mut out);
1198        out
1199    }
1200}
1201
1202impl ContainsVariables for WhereClause {
1203    fn accumulate_mentioned_variables(&self, acc: &mut BTreeSet<Variable>) {
1204        use self::WhereClause::*;
1205        match self {
1206            OrJoin(ref o) => o.accumulate_mentioned_variables(acc),
1207            Pred(ref p) => p.accumulate_mentioned_variables(acc),
1208            Pattern(ref p) => p.accumulate_mentioned_variables(acc),
1209            NotJoin(ref n) => n.accumulate_mentioned_variables(acc),
1210            WhereFn(ref f) => f.accumulate_mentioned_variables(acc),
1211            TypeAnnotation(ref a) => a.accumulate_mentioned_variables(acc),
1212            RuleExpr(ref invocation) => {
1213                for arg in &invocation.args {
1214                    if let FnArg::Variable(ref var) = arg {
1215                        acc.insert(var.clone());
1216                    }
1217                }
1218            }
1219        }
1220    }
1221}
1222
1223impl ContainsVariables for OrWhereClause {
1224    fn accumulate_mentioned_variables(&self, acc: &mut BTreeSet<Variable>) {
1225        use self::OrWhereClause::*;
1226        match self {
1227            And(ref clauses) => {
1228                for clause in clauses {
1229                    clause.accumulate_mentioned_variables(acc)
1230                }
1231            }
1232            Clause(ref clause) => clause.accumulate_mentioned_variables(acc),
1233        }
1234    }
1235}
1236
1237impl ContainsVariables for OrJoin {
1238    fn accumulate_mentioned_variables(&self, acc: &mut BTreeSet<Variable>) {
1239        for clause in &self.clauses {
1240            clause.accumulate_mentioned_variables(acc);
1241        }
1242    }
1243}
1244
1245impl OrJoin {
1246    pub fn dismember(self) -> (Vec<OrWhereClause>, UnifyVars, BTreeSet<Variable>) {
1247        let vars = match self.mentioned_vars {
1248            Some(m) => m,
1249            None => self.collect_mentioned_variables(),
1250        };
1251        (self.clauses, self.unify_vars, vars)
1252    }
1253
1254    pub fn mentioned_variables(&mut self) -> &BTreeSet<Variable> {
1255        if self.mentioned_vars.is_none() {
1256            let m = self.collect_mentioned_variables();
1257            self.mentioned_vars = Some(m);
1258        }
1259
1260        if let Some(ref mentioned) = self.mentioned_vars {
1261            mentioned
1262        } else {
1263            unreachable!()
1264        }
1265    }
1266}
1267
1268impl ContainsVariables for NotJoin {
1269    fn accumulate_mentioned_variables(&self, acc: &mut BTreeSet<Variable>) {
1270        for clause in &self.clauses {
1271            clause.accumulate_mentioned_variables(acc);
1272        }
1273    }
1274}
1275
1276impl ContainsVariables for Predicate {
1277    fn accumulate_mentioned_variables(&self, acc: &mut BTreeSet<Variable>) {
1278        for arg in &self.args {
1279            if let FnArg::Variable(ref v) = *arg {
1280                acc_ref(acc, v)
1281            }
1282        }
1283    }
1284}
1285
1286impl ContainsVariables for TypeAnnotation {
1287    fn accumulate_mentioned_variables(&self, acc: &mut BTreeSet<Variable>) {
1288        acc_ref(acc, &self.variable);
1289    }
1290}
1291
1292impl ContainsVariables for Binding {
1293    fn accumulate_mentioned_variables(&self, acc: &mut BTreeSet<Variable>) {
1294        match self {
1295            Binding::BindScalar(ref v) | &Binding::BindColl(ref v) => acc_ref(acc, v),
1296            Binding::BindRel(ref vs) | &Binding::BindTuple(ref vs) => {
1297                for v in vs {
1298                    if let VariableOrPlaceholder::Variable(ref v) = *v {
1299                        acc_ref(acc, v);
1300                    }
1301                }
1302            }
1303        }
1304    }
1305}
1306
1307impl ContainsVariables for WhereFn {
1308    fn accumulate_mentioned_variables(&self, acc: &mut BTreeSet<Variable>) {
1309        for arg in &self.args {
1310            if let FnArg::Variable(ref v) = *arg {
1311                acc_ref(acc, v)
1312            }
1313        }
1314        self.binding.accumulate_mentioned_variables(acc);
1315    }
1316}
1317
1318fn acc_ref<T: Clone + Ord>(acc: &mut BTreeSet<T>, v: &T) {
1319    // Roll on, reference entries!
1320    if !acc.contains(v) {
1321        acc.insert(v.clone());
1322    }
1323}
1324
1325impl ContainsVariables for Pattern {
1326    fn accumulate_mentioned_variables(&self, acc: &mut BTreeSet<Variable>) {
1327        if let PatternNonValuePlace::Variable(ref v) = self.entity {
1328            acc_ref(acc, v)
1329        }
1330        if let PatternNonValuePlace::Variable(ref v) = self.attribute {
1331            acc_ref(acc, v)
1332        }
1333        if let PatternValuePlace::Variable(ref v) = self.value {
1334            acc_ref(acc, v)
1335        }
1336        if let PatternNonValuePlace::Variable(ref v) = self.tx {
1337            acc_ref(acc, v)
1338        }
1339        if let PatternNonValuePlace::Variable(ref v) = self.added {
1340            acc_ref(acc, v)
1341        }
1342    }
1343}