Add query sub-crate, implementing more of the beginnings of the query language.

This commit is contained in:
Richard Newman 2017-01-04 13:09:12 +00:00
parent 476f04e27b
commit daddfd3e0f
6 changed files with 161 additions and 0 deletions

View file

@ -9,6 +9,9 @@ rusqlite = "0.8.0"
[dependencies.edn] [dependencies.edn]
path = "edn" path = "edn"
[dependencies.mentat_query]
path = "query"
[dependencies.mentat_query_parser] [dependencies.mentat_query_parser]
path = "query-parser" path = "query-parser"

7
query/Cargo.toml Normal file
View file

@ -0,0 +1,7 @@
[package]
name = "mentat_query"
version = "0.0.1"
[dependencies]
[dependencies.edn]
path = "../edn"

4
query/README.md Normal file
View file

@ -0,0 +1,4 @@
This sub-crate implements the core types used by the query parser,
translator, and executor — variables, find specifications, etc.
The `edn` sub-crate implements some even lower-level types, such as `Keyword`.

135
query/src/find.rs Normal file
View file

@ -0,0 +1,135 @@
// Copyright 2016 Mozilla
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
// this file except in compliance with the License. You may obtain a copy of the
// License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
///! This module defines some core types that support find expressions: sources,
///! variables, expressions, etc.
///! These are produced as 'fuel' by the query parser, consumed by the query
///! translator and executor.
///!
///! Many of these types are defined as simple structs that are little more than
///! a richer type alias: a variable, for example, is really just a fancy kind
///! of string.
///!
///! At some point in the future, we might consider reducing copying and memory
///! usage by recasting all of these string-holding structs and enums in terms
///! of string references, with those references being slices of some parsed
///! input query string, and valid for the lifetime of that string.
///!
///! For now, for the sake of simplicity, all of these strings are heap-allocated.
///!
///! Furthermore, we might cut out some of the chaff here: each time a 'tagged'
///! type is used within an enum, we have an opportunity to simplify and use the
///! inner type directly in conjunction with matching on the enum. Before diving
///! deeply into this it's worth recognizing that this loss of 'sovereignty' is
///! a tradeoff against well-typed function signatures and other such boundaries.
// TODO: support other kinds of sources.
#[derive(Clone,Debug,Eq,PartialEq)]
pub enum SrcVar {
DefaultSrc,
}
pub enum Constant {} // This is essentially Box. TODO: flesh out.
#[derive(Clone,Debug,Eq,PartialEq)]
pub struct Variable {
pub name: String,
}
pub enum FnArg {
Constant { constant: Constant },
Variable { variable: Variable },
Src { src: SrcVar },
}
pub enum PullPattern {
Constant { constant: Constant },
Variable { variable: Variable },
}
pub struct Pull {
pub src: SrcVar,
pub var: Variable,
pub pattern: PullPattern, // Constant, variable, or plain variable.
}
pub struct Aggregate {
pub fn_name: String,
pub args: Vec<FnArg>,
}
// TODO: look up the idiomatic way to express these kinds of type
// combinations in Rust. It must be common in ASTs. Trait objects
// presumably aren't the answer…
pub enum Element {
Variable { variable: Variable },
Pull { expression: Pull },
Aggregate { expression: Aggregate },
}
/// A definition of the first part of a find query: the
/// `[:find ?foo ?bar…]` bit.
///
/// There are four different kinds of find specs, allowing you to query for
/// a single value, a collection of values from different entities, a single
/// tuple (relation), or a collection of tuples.
///
/// Examples:
///
/// ```rust
/// # use mentat_query::find::{FindSpec, Element, Variable};
///
/// // TODO: this feels clunky.
/// let foo = Variable { name: "foo".to_string() };
/// let bar = Variable { name: "bar".to_string() };
/// let elements = vec![
/// Element::Variable { variable: foo },
/// Element::Variable { variable: bar },
/// ];
/// let rel = FindSpec::FindRel { elements: elements };
///
/// if let FindSpec::FindRel { elements } = rel {
/// assert_eq!(2, elements.len());
/// }
/// ```
///
pub enum FindSpec {
/// Returns an array of arrays.
FindRel { elements: Vec<Element> },
/// Returns an array of scalars, usually homogeneous.
/// This is equivalent to mapping over the results of a `FindRel`,
/// returning the first value of each.
FindColl { element: Element },
/// Returns a single tuple: a heterogeneous array of scalars. Equivalent to
/// taking the first result from a `FindRel`.
FindTuple { elements: Vec<Element> },
/// Returns a single scalar value. Equivalent to taking the first result
/// from a `FindColl`.
FindScalar { element: Element },
}
/// Returns true if the provided `FindSpec` returns at most one result.
pub fn is_unit_limited(spec: &FindSpec) -> bool {
match spec {
&FindSpec::FindScalar { .. } => true,
&FindSpec::FindTuple { .. } => true,
&FindSpec::FindRel { .. } => false,
&FindSpec::FindColl { .. } => false,
}
}
/// Returns true if the provided `FindSpec` cares about distinct results.
pub fn requires_distinct(spec: &FindSpec) -> bool {
return !is_unit_limited(spec);
}

11
query/src/lib.rs Normal file
View file

@ -0,0 +1,11 @@
// Copyright 2016 Mozilla
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
// this file except in compliance with the License. You may obtain a copy of the
// License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
pub mod find;

View file

@ -9,6 +9,7 @@
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
extern crate edn; extern crate edn;
extern crate mentat_query;
extern crate mentat_query_parser; extern crate mentat_query_parser;
extern crate rusqlite; extern crate rusqlite;