Compare commits
4 commits
master
...
moz-pr/798
Author | SHA1 | Date | |
---|---|---|---|
|
85f0497cf5 | ||
|
131398758b | ||
|
0fa466dd6b | ||
|
b838259a8b |
44 changed files with 3260 additions and 302 deletions
|
@ -19,11 +19,11 @@ use edn::types::Value;
|
||||||
/// Declare a lazy static `ident` of type `Value::Keyword` with the given `namespace` and
|
/// Declare a lazy static `ident` of type `Value::Keyword` with the given `namespace` and
|
||||||
/// `name`.
|
/// `name`.
|
||||||
///
|
///
|
||||||
/// It may look surprising that we declare a new `lazy_static!` block rather than including
|
/// It may look surprising to declare a new `lazy_static!` block rather than including
|
||||||
/// invocations inside an existing `lazy_static!` block. The latter cannot be done, since macros
|
/// invocations inside an existing `lazy_static!` block. The latter cannot be done, since macros
|
||||||
/// are expanded outside-in. Looking at the `lazy_static!` source suggests that there is no harm in
|
/// will be expanded outside-in. Looking at the `lazy_static!` source suggests that there is no
|
||||||
/// repeating that macro, since internally a multi-`static` block is expanded into many
|
/// harm in repeating that macro, since internally a multi-`static` block will be expanded into
|
||||||
/// single-`static` blocks.
|
/// many single-`static` blocks.
|
||||||
///
|
///
|
||||||
/// TODO: take just ":db.part/db" and define DB_PART_DB using "db.part" and "db".
|
/// TODO: take just ":db.part/db" and define DB_PART_DB using "db.part" and "db".
|
||||||
macro_rules! lazy_static_namespaced_keyword_value (
|
macro_rules! lazy_static_namespaced_keyword_value (
|
||||||
|
|
|
@ -662,7 +662,7 @@ pub struct AttributeCaches {
|
||||||
non_unique_reverse: BTreeMap<Entid, NonUniqueReverseAttributeCache>,
|
non_unique_reverse: BTreeMap<Entid, NonUniqueReverseAttributeCache>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: if an entity or attribute is ever renumbered, the cache will need to be rebuilt.
|
// TODO: if an entity or attribute is ever re-numbered, the cache will need to be rebuilt.
|
||||||
impl AttributeCaches {
|
impl AttributeCaches {
|
||||||
//
|
//
|
||||||
// These function names are brief and local.
|
// These function names are brief and local.
|
||||||
|
|
177
docs/tutorial.md
Normal file
177
docs/tutorial.md
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
# Introduction
|
||||||
|
|
||||||
|
Mentat is a transactional, relational storage system built on top of SQLite. The abstractions it offers allow you to easily tackle some things that are tricky in other storage systems:
|
||||||
|
|
||||||
|
- Have multiple components share storage and collaborate.
|
||||||
|
- Evolve schema.
|
||||||
|
- Track change over time.
|
||||||
|
- Synchronize data correctly.
|
||||||
|
- Store data with rich, checked types.
|
||||||
|
|
||||||
|
Mentat offers a programmatic Rust API for managing stores, retrieving data, and _transacting_ new data. It offers a Datalog-based query engine, with queries expressed in EDN, a rich textual data format similar to JSON. And it offers an EDN data format for transacting new data.
|
||||||
|
|
||||||
|
This tutorial covers all of these APIs, along with defining vocabulary.
|
||||||
|
|
||||||
|
We'll begin by introducing some concepts, and then we'll walk through some examples.
|
||||||
|
|
||||||
|
|
||||||
|
## What does Mentat store?
|
||||||
|
|
||||||
|
Depending on your perspective, Mentat looks like a relational store, a graph store, or a tuple store.
|
||||||
|
|
||||||
|
Mentat stores relationships between _entities_ and other entities or _values_. An entity is related to other things by an _attribute_.
|
||||||
|
|
||||||
|
All entities have an _entity ID_ (abbreviated to _entid_).
|
||||||
|
|
||||||
|
Some entities additionally have an identifier called an _ident_, which is a keyword. That looks something like `:bookmark/title`.
|
||||||
|
|
||||||
|
A value is a primitive piece of data. Mentat supports the following:
|
||||||
|
|
||||||
|
* Strings
|
||||||
|
* Long integers
|
||||||
|
* Double-precision floating point numbers
|
||||||
|
* Millisecond-precision timestamps
|
||||||
|
* UUIDs
|
||||||
|
* Booleans
|
||||||
|
* Keywords (a special kind of string that we use for idents).
|
||||||
|
|
||||||
|
There are two special kinds of entities: _attributes_ and _transactions_.
|
||||||
|
|
||||||
|
Attributes are themselves entities with a particular set of properties that define their meaning. They have identifiers, so you can refer to them easily. They have a _value type_, which is the type of value Mentat expects to be on the right hand side of the relationship. And they have a _cardinality_ (whether one or many values can exist for a particular entity), whether values are _unique_, a documentation string, and some indexing options.
|
||||||
|
|
||||||
|
An attribute looks something like this:
|
||||||
|
|
||||||
|
```edn
|
||||||
|
{:db/ident :bookmark/title
|
||||||
|
:db/cardinality :db.cardinality/one
|
||||||
|
:db/valueType :db.type/string
|
||||||
|
:db/fulltext true
|
||||||
|
:db/doc "The title of a bookmark."}
|
||||||
|
```
|
||||||
|
|
||||||
|
Transactions are special entities that can be described however you wish. By default they track the timestamp at which they were written.
|
||||||
|
|
||||||
|
The relationship between an entity, an attribute, and a value, occurring in a _transaction_ (which is just another kind of entity!) — a tuple of five values — is called a _datom_.
|
||||||
|
|
||||||
|
A single datom might look something like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
[:db/add 65536 :bookmark/title "mozilla.org" 268435456]
|
||||||
|
^ ^ ^ ^ ^
|
||||||
|
\ Add or retract. | | | |
|
||||||
|
\ The entity. | | |
|
||||||
|
\ The attribute. | |
|
||||||
|
\ The value, a string. |
|
||||||
|
\ The transaction ID.
|
||||||
|
```
|
||||||
|
|
||||||
|
which is equivalent to saying "in transaction 268435456 we assert that entity 65536 is a bookmark with the title 'mozilla.org'".
|
||||||
|
|
||||||
|
When we transact that — which means to add it as a fact to the store — Mentat also describes the transaction itself on our behalf:
|
||||||
|
|
||||||
|
```edn
|
||||||
|
[:db/add 268435456 :db/txInstant "2018-01-25 20:07:04.408358 UTC" 268435456]
|
||||||
|
```
|
||||||
|
|
||||||
|
# A simple app
|
||||||
|
|
||||||
|
Let's get started with some Rust code.
|
||||||
|
|
||||||
|
First, the imports we'll need. The comments here briefly explain what each thing is.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// So you can define keywords with neater syntax.
|
||||||
|
#[macro_use(kw)]
|
||||||
|
extern crate mentat;
|
||||||
|
|
||||||
|
use mentat::{
|
||||||
|
Store, // A single database connection and in-memory metadata.
|
||||||
|
}
|
||||||
|
|
||||||
|
use mentat::vocabulary::attribute; // Properties of attributes.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Defining a simple vocabulary
|
||||||
|
|
||||||
|
All data in Mentat — even the terms we used above, like `:db/cardinality` — are defined in the store itself. So that's where we start. In Rust, we define a _vocabulary definition_, and ask the store to ensure that it exists.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
|
||||||
|
fn set_up(mut store: Store) -> Result<()> {
|
||||||
|
// Start a write transaction.
|
||||||
|
let mut in_progress = store.begin_transaction()?;
|
||||||
|
|
||||||
|
// Make sure the core vocabulary exists. This is good practice if a user,
|
||||||
|
// an external tool, or another component might have touched the file
|
||||||
|
// since you last wrote it.
|
||||||
|
in_progress.verify_core_schema()?;
|
||||||
|
|
||||||
|
// Make sure our vocabulary is installed, and install if necessary.
|
||||||
|
// This defines some attributes that we can use to describe people.
|
||||||
|
in_progress.ensure_vocabulary(&Definition {
|
||||||
|
name: kw!(:example/people),
|
||||||
|
version: 1,
|
||||||
|
attributes: vec![
|
||||||
|
(kw!(:person/name),
|
||||||
|
vocabulary::AttributeBuilder::default()
|
||||||
|
.value_type(ValueType::String)
|
||||||
|
.multival(true)
|
||||||
|
.build()),
|
||||||
|
(kw!(:person/age),
|
||||||
|
vocabulary::AttributeBuilder::default()
|
||||||
|
.value_type(ValueType::Long)
|
||||||
|
.multival(false)
|
||||||
|
.build()),
|
||||||
|
(kw!(:person/email),
|
||||||
|
vocabulary::AttributeBuilder::default()
|
||||||
|
.value_type(ValueType::String)
|
||||||
|
.multival(true)
|
||||||
|
.unique(attribute::Unique::Identity)
|
||||||
|
.build()),
|
||||||
|
],
|
||||||
|
})?;
|
||||||
|
|
||||||
|
in_progress.commit()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
We open a store and configure its vocabulary like this:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let path = "/path/to/file.db";
|
||||||
|
let store = Store::open(path)?;
|
||||||
|
set_up(store)?;
|
||||||
|
```
|
||||||
|
|
||||||
|
If this code returns successfully, we're good to go.
|
||||||
|
|
||||||
|
## Transactions
|
||||||
|
|
||||||
|
You'll see in our `set_up` function that we begin and end a transaction, which we call `in_progress`. A read-only transaction is begun via `begin_read`. The resulting objects — `InProgress` and `InProgressRead` support various kinds of read and write operations. Transactions are automatically rolled back when dropped, so remember to call `commit`!
|
||||||
|
|
||||||
|
## Adding some data
|
||||||
|
|
||||||
|
There are two ways to add data to Mentat: programmatically or textually.
|
||||||
|
|
||||||
|
The textual form accepts EDN, a simple relative of JSON that supports richer types and more flexible syntax. You saw this in the introduction. Here's an example:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
in_progress.transact(r#"[
|
||||||
|
{:person/name "Alice"
|
||||||
|
:person/age 32
|
||||||
|
:person/email "alice@example.org"}
|
||||||
|
]"#)?;
|
||||||
|
```
|
||||||
|
|
||||||
|
You can implicitly _upsert_ data when you have a unique attribute to use:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// Alice's age is now 33. Note that we don't need to find out an entid,
|
||||||
|
// nor explicitly INSERT OR REPLACE or UPDATE OR INSERT or similar.
|
||||||
|
in_progress.transact(r#"[
|
||||||
|
{:person/age 33
|
||||||
|
:person/email "alice@example.org"}
|
||||||
|
]"#)?;
|
||||||
|
```
|
||||||
|
|
|
@ -12,8 +12,8 @@ extern crate chrono;
|
||||||
extern crate itertools;
|
extern crate itertools;
|
||||||
extern crate num;
|
extern crate num;
|
||||||
extern crate ordered_float;
|
extern crate ordered_float;
|
||||||
extern crate pretty;
|
|
||||||
extern crate peg;
|
extern crate peg;
|
||||||
|
extern crate pretty;
|
||||||
extern crate uuid;
|
extern crate uuid;
|
||||||
|
|
||||||
#[cfg(feature = "serde_support")]
|
#[cfg(feature = "serde_support")]
|
||||||
|
@ -50,13 +50,11 @@ pub use types::{
|
||||||
|
|
||||||
pub use symbols::{Keyword, NamespacedSymbol, PlainSymbol};
|
pub use symbols::{Keyword, NamespacedSymbol, PlainSymbol};
|
||||||
|
|
||||||
use std::collections::{BTreeSet, BTreeMap, LinkedList};
|
use std::collections::{BTreeMap, BTreeSet, LinkedList};
|
||||||
|
use std::f64::{INFINITY, NAN, NEG_INFINITY};
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
use std::f64::{NAN, INFINITY, NEG_INFINITY};
|
|
||||||
|
|
||||||
use chrono::{
|
use chrono::TimeZone;
|
||||||
TimeZone,
|
|
||||||
};
|
|
||||||
|
|
||||||
use entities::*;
|
use entities::*;
|
||||||
use query::FromValue;
|
use query::FromValue;
|
||||||
|
@ -70,7 +68,7 @@ use query::FromValue;
|
||||||
// TODO: Support tagged elements
|
// TODO: Support tagged elements
|
||||||
// TODO: Support discard
|
// TODO: Support discard
|
||||||
|
|
||||||
pub type ParseError = peg::error::ParseError<peg::str::LineCol>;
|
pub type ParseErrorKind = peg::error::ParseError<peg::str::LineCol>;
|
||||||
|
|
||||||
peg::parser!(pub grammar parse() for str {
|
peg::parser!(pub grammar parse() for str {
|
||||||
|
|
||||||
|
@ -525,4 +523,3 @@ peg::parser!(pub grammar parse() for str {
|
||||||
/ v:variable() { query::Binding::BindScalar(v) }
|
/ v:variable() { query::Binding::BindScalar(v) }
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,11 @@ use num::traits::{One, Zero};
|
||||||
use ordered_float::OrderedFloat;
|
use ordered_float::OrderedFloat;
|
||||||
|
|
||||||
use chrono::{TimeZone, Utc};
|
use chrono::{TimeZone, Utc};
|
||||||
use edn::{parse, symbols, types::{Span, SpannedValue, Value, ValueAndSpan}, utils, ParseError};
|
use edn::{
|
||||||
|
parse, symbols,
|
||||||
|
types::{Span, SpannedValue, Value, ValueAndSpan},
|
||||||
|
utils, ParseErrorKind,
|
||||||
|
};
|
||||||
|
|
||||||
// Helper for making wrapped keywords with a namespace.
|
// Helper for making wrapped keywords with a namespace.
|
||||||
fn k_ns(ns: &str, name: &str) -> Value {
|
fn k_ns(ns: &str, name: &str) -> Value {
|
||||||
|
|
|
@ -16,6 +16,12 @@ use std::collections::BTreeSet;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
use rusqlite;
|
use rusqlite;
|
||||||
|
use failure::{
|
||||||
|
Backtrace,
|
||||||
|
Context,
|
||||||
|
Fail,
|
||||||
|
};
|
||||||
|
+use std::fmt;
|
||||||
use uuid;
|
use uuid;
|
||||||
|
|
||||||
use edn;
|
use edn;
|
||||||
|
@ -39,8 +45,51 @@ use serde_json;
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, MentatError>;
|
pub type Result<T> = std::result::Result<T, MentatError>;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct MentatError(Box<Context<MentatErrorKind>>);
|
||||||
|
|
||||||
|
impl Fail for MentatError {
|
||||||
|
#[inline]
|
||||||
|
fn cause(&self) -> Option<&Fail> {
|
||||||
|
self.0.cause()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn backtrace(&self) -> Option<&Backtrace> {
|
||||||
|
self.0.backtrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for MentatError {
|
||||||
|
#[inline]
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
fmt::Display::fmt(&*self.0, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MentatError {
|
||||||
|
#[inline]
|
||||||
|
pub fn kind(&self) -> &MentatErrorKind {
|
||||||
|
&*self.0.get_context()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<MentatErrorKind> for MentatError {
|
||||||
|
#[inline]
|
||||||
|
fn from(kind: MentatErrorKind) -> MentatError {
|
||||||
|
MentatError(Box::new(Context::new(kind)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Context<MentatErrorKind>> for MentatError {
|
||||||
|
#[inline]
|
||||||
|
fn from(inner: Context<MentatErrorKind>) -> MentatError {
|
||||||
|
MentatError(Box::new(inner))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Fail)]
|
#[derive(Debug, Fail)]
|
||||||
pub enum MentatError {
|
pub enum MentatErrorKind {
|
||||||
#[fail(display = "bad uuid {}", _0)]
|
#[fail(display = "bad uuid {}", _0)]
|
||||||
BadUuid(String),
|
BadUuid(String),
|
||||||
|
|
||||||
|
@ -140,9 +189,67 @@ pub enum MentatError {
|
||||||
SerializationError(#[cause] serde_json::Error),
|
SerializationError(#[cause] serde_json::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<std::io::Error> for MentatErrorKind {
|
||||||
|
fn from(error: std::io::Error) -> MentatErrorKind {
|
||||||
|
MentatErrorKind::IoError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<rusqlite::Error> for MentatErrorKind {
|
||||||
|
fn from(error: rusqlite::Error) -> MentatErrorKind {
|
||||||
|
MentatErrorKind::RusqliteError(error.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<edn::ParseError> for MentatErrorKind {
|
||||||
|
fn from(error: edn::ParseError) -> MentatErrorKind {
|
||||||
|
MentatErrorKind::EdnParseError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<mentat_db::DbError> for MentatErrorKind {
|
||||||
|
fn from(error: mentat_db::DbError) -> MentatErrorKind {
|
||||||
|
MentatErrorKind::DbError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<mentat_query_algebrizer::AlgebrizerError> for MentatErrorKind {
|
||||||
|
fn from(error: mentat_query_algebrizer::AlgebrizerError) -> MentatErrorKind {
|
||||||
|
MentatErrorKind::AlgebrizerError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<mentat_query_projector::ProjectorError> for MentatErrorKind {
|
||||||
|
fn from(error: mentat_query_projector::ProjectorError) -> MentatErrorKind {
|
||||||
|
MentatErrorKind::ProjectorError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<mentat_query_pull::PullError> for MentatErrorKind {
|
||||||
|
fn from(error: mentat_query_pull::PullError) -> MentatErrorKind {
|
||||||
|
MentatErrorKind::PullError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<mentat_sql::SQLError> for MentatErrorKind {
|
||||||
|
fn from(error: mentat_sql::SQLError) -> MentatErrorKind {
|
||||||
|
MentatErrorKind::SQLError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "syncable")]
|
||||||
|
impl From<mentat_tolstoy::TolstoyError> for MentatErrorKind {
|
||||||
|
fn from(error: mentat_tolstoy::TolstoyError) -> MentatErrorKind {
|
||||||
|
MentatErrorKind::TolstoyError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX reduce dupe if this isn't completely throwaway
|
||||||
|
|
||||||
|
|
||||||
impl From<std::io::Error> for MentatError {
|
impl From<std::io::Error> for MentatError {
|
||||||
fn from(error: std::io::Error) -> Self {
|
fn from(error: std::io::Error) -> Self {
|
||||||
MentatError::IoError(error)
|
MentatError::from(error).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,76 +259,76 @@ impl From<rusqlite::Error> for MentatError {
|
||||||
Some(e) => e.to_string(),
|
Some(e) => e.to_string(),
|
||||||
None => "".to_string(),
|
None => "".to_string(),
|
||||||
};
|
};
|
||||||
MentatError::RusqliteError(error.to_string(), cause)
|
MentatError::from(error).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<uuid::Error> for MentatError {
|
impl From<uuid::Error> for MentatError {
|
||||||
fn from(error: uuid::Error) -> Self {
|
fn from(error: uuid::Error) -> Self {
|
||||||
MentatError::UuidError(error)
|
MentatError::from(error).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<edn::ParseError> for MentatError {
|
impl From<edn::ParseError> for MentatError {
|
||||||
fn from(error: edn::ParseError) -> Self {
|
fn from(error: edn::ParseError) -> Self {
|
||||||
MentatError::EdnParseError(error)
|
MentatError:from(error).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<DbError> for MentatError {
|
impl From<DbError> for MentatError {
|
||||||
fn from(error: DbError) -> Self {
|
fn from(error: DbError) -> Self {
|
||||||
MentatError::DbError(error)
|
MentatError::from(error).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<AlgebrizerError> for MentatError {
|
impl From<AlgebrizerError> for MentatError {
|
||||||
fn from(error: AlgebrizerError) -> Self {
|
fn from(error: AlgebrizerError) -> Self {
|
||||||
MentatError::AlgebrizerError(error)
|
MentatError::from(error).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ProjectorError> for MentatError {
|
impl From<ProjectorError> for MentatError {
|
||||||
fn from(error: ProjectorError) -> Self {
|
fn from(error: ProjectorError) -> Self {
|
||||||
MentatError::ProjectorError(error)
|
MentatError::from(error).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<PullError> for MentatError {
|
impl From<PullError> for MentatError {
|
||||||
fn from(error: PullError) -> Self {
|
fn from(error: PullError) -> Self {
|
||||||
MentatError::PullError(error)
|
MentatError::from(error).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<SQLError> for MentatError {
|
impl From<SQLError> for MentatError {
|
||||||
fn from(error: SQLError) -> Self {
|
fn from(error: SQLError) -> Self {
|
||||||
MentatError::SQLError(error)
|
MentatError::from(error).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "syncable")]
|
#[cfg(feature = "syncable")]
|
||||||
impl From<TolstoyError> for MentatError {
|
impl From<TolstoyError> for MentatError {
|
||||||
fn from(error: TolstoyError) -> Self {
|
fn from(error: TolstoyError) -> Self {
|
||||||
MentatError::TolstoyError(error)
|
MentatError::from(error).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "syncable")]
|
#[cfg(feature = "syncable")]
|
||||||
impl From<serde_json::Error> for MentatError {
|
impl From<serde_json::Error> for MentatError {
|
||||||
fn from(error: serde_json::Error) -> Self {
|
fn from(error: serde_json::Error) -> Self {
|
||||||
MentatError::SerializationError(error)
|
MentatError::from(error).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "syncable")]
|
#[cfg(feature = "syncable")]
|
||||||
impl From<hyper::Error> for MentatError {
|
impl From<hyper::Error> for MentatError {
|
||||||
fn from(error: hyper::Error) -> Self {
|
fn from(error: hyper::Error) -> Self {
|
||||||
MentatError::NetworkError(error)
|
MentatError::from(error).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "syncable")]
|
#[cfg(feature = "syncable")]
|
||||||
impl From<http::uri::InvalidUri> for MentatError {
|
impl From<http::uri::InvalidUri> for MentatError {
|
||||||
fn from(error: http::uri::InvalidUri) -> Self {
|
fn from(error: http::uri::InvalidUri) -> Self {
|
||||||
MentatError::UriError(error)
|
MentatError::from(error).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,60 @@ use std; // To refer to std::result::Result.
|
||||||
|
|
||||||
use core_traits::{ValueType, ValueTypeSet};
|
use core_traits::{ValueType, ValueTypeSet};
|
||||||
|
|
||||||
use edn::{ ParseError, query::PlainSymbol };
|
use std::fmt;
|
||||||
|
use failure::{
|
||||||
|
Backtrace,
|
||||||
|
Context,
|
||||||
|
Fail,
|
||||||
|
};
|
||||||
|
|
||||||
|
use edn::{query::PlainSymbol, ParseErrorKind};
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, AlgebrizerError>;
|
pub type Result<T> = std::result::Result<T, AlgebrizerError>;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct AlgebrizerError(Box<Context<AlgebrizerErrorKind>>);
|
||||||
|
|
||||||
|
impl Fail for AlgebrizerError {
|
||||||
|
#[inline]
|
||||||
|
fn cause(&self) -> Option<&dyn Fail> {
|
||||||
|
self.0.cause()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn backtrace(&self) -> Option<&Backtrace> {
|
||||||
|
self.0.backtrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for AlgebrizerError {
|
||||||
|
#[inline]
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
fmt::Display::fmt(&*self.0, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AlgebrizerError {
|
||||||
|
#[inline]
|
||||||
|
pub fn kind(&self) -> &AlgebrizerErrorKind {
|
||||||
|
&*self.0.get_context()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<AlgebrizerErrorKind> for AlgebrizerError {
|
||||||
|
#[inline]
|
||||||
|
fn from(kind: AlgebrizerErrorKind) -> AlgebrizerError {
|
||||||
|
AlgebrizerError(Box::new(Context::new(kind)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Context<AlgebrizerErrorKind>> for AlgebrizerError {
|
||||||
|
#[inline]
|
||||||
|
fn from(inner: Context<AlgebrizerErrorKind>) -> AlgebrizerError {
|
||||||
|
AlgebrizerError(Box::new(inner))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum BindingError {
|
pub enum BindingError {
|
||||||
NoBoundVariable,
|
NoBoundVariable,
|
||||||
|
@ -40,7 +90,7 @@ pub enum BindingError {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, Fail, PartialEq)]
|
#[derive(Clone, Debug, Eq, Fail, PartialEq)]
|
||||||
pub enum AlgebrizerError {
|
pub enum AlgebrizerErrorKind {
|
||||||
#[fail(display = "{} var {} is duplicated", _0, _1)]
|
#[fail(display = "{} var {} is duplicated", _0, _1)]
|
||||||
DuplicateVariableError(PlainSymbol, &'static str),
|
DuplicateVariableError(PlainSymbol, &'static str),
|
||||||
|
|
||||||
|
@ -107,11 +157,11 @@ pub enum AlgebrizerError {
|
||||||
InvalidBinding(PlainSymbol, BindingError),
|
InvalidBinding(PlainSymbol, BindingError),
|
||||||
|
|
||||||
#[fail(display = "{}", _0)]
|
#[fail(display = "{}", _0)]
|
||||||
EdnParseError(#[cause] ParseError),
|
EdnParseError(#[cause] ParseErrorKind),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ParseError> for AlgebrizerError {
|
impl From<ParseErrorKind> for AlgebrizerError {
|
||||||
fn from(error: ParseError) -> AlgebrizerError {
|
fn from(error: ParseErrorKind) -> AlgebrizerError {
|
||||||
AlgebrizerError::EdnParseError(error)
|
AlgebrizerError::from(error).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,9 +9,6 @@
|
||||||
// specific language governing permissions and limitations under the License.
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
extern crate failure;
|
extern crate failure;
|
||||||
#[macro_use]
|
|
||||||
extern crate failure_derive;
|
|
||||||
|
|
||||||
extern crate core_traits;
|
extern crate core_traits;
|
||||||
extern crate edn;
|
extern crate edn;
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ use edn::query::{FnArg, NonIntegerConstant, Variable};
|
||||||
|
|
||||||
use clauses::ConjoiningClauses;
|
use clauses::ConjoiningClauses;
|
||||||
|
|
||||||
use query_algebrizer_traits::errors::{AlgebrizerError, Result};
|
use query_algebrizer_traits::errors::{AlgebrizerErrorKind, Result};
|
||||||
|
|
||||||
use types::EmptyBecause;
|
use types::EmptyBecause;
|
||||||
|
|
||||||
|
@ -62,11 +62,11 @@ impl ValueTypes for FnArg {
|
||||||
|
|
||||||
&FnArg::Constant(NonIntegerConstant::BigInteger(_)) => {
|
&FnArg::Constant(NonIntegerConstant::BigInteger(_)) => {
|
||||||
// Not yet implemented.
|
// Not yet implemented.
|
||||||
bail!(AlgebrizerError::UnsupportedArgument)
|
bail!(AlgebrizerErrorKind::UnsupportedArgument)
|
||||||
}
|
}
|
||||||
|
|
||||||
// These don't make sense here. TODO: split FnArg into scalar and non-scalar…
|
// These don't make sense here. TODO: split FnArg into scalar and non-scalar…
|
||||||
&FnArg::Vector(_) | &FnArg::SrcVar(_) => bail!(AlgebrizerError::UnsupportedArgument),
|
&FnArg::Vector(_) | &FnArg::SrcVar(_) => bail!(AlgebrizerErrorKind::UnsupportedArgument),
|
||||||
|
|
||||||
// These are all straightforward.
|
// These are all straightforward.
|
||||||
&FnArg::Constant(NonIntegerConstant::Boolean(_)) => {
|
&FnArg::Constant(NonIntegerConstant::Boolean(_)) => {
|
||||||
|
@ -191,7 +191,7 @@ impl ConjoiningClauses {
|
||||||
FnArg::Variable(in_var) => {
|
FnArg::Variable(in_var) => {
|
||||||
// TODO: technically you could ground an existing variable inside the query….
|
// TODO: technically you could ground an existing variable inside the query….
|
||||||
if !self.input_variables.contains(&in_var) {
|
if !self.input_variables.contains(&in_var) {
|
||||||
bail!(AlgebrizerError::UnboundVariable((*in_var.0).clone()))
|
bail!(AlgebrizerErrorKind::UnboundVariable((*in_var.0).clone()))
|
||||||
}
|
}
|
||||||
match self.bound_value(&in_var) {
|
match self.bound_value(&in_var) {
|
||||||
// The type is already known if it's a bound variable….
|
// The type is already known if it's a bound variable….
|
||||||
|
@ -200,7 +200,7 @@ impl ConjoiningClauses {
|
||||||
// The variable is present in `:in`, but it hasn't yet been provided.
|
// The variable is present in `:in`, but it hasn't yet been provided.
|
||||||
// This is a restriction we will eventually relax: we don't yet have a way
|
// This is a restriction we will eventually relax: we don't yet have a way
|
||||||
// to collect variables as part of a computed table or substitution.
|
// to collect variables as part of a computed table or substitution.
|
||||||
bail!(AlgebrizerError::UnboundVariable((*in_var.0).clone()))
|
bail!(AlgebrizerErrorKind::UnboundVariable((*in_var.0).clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -209,7 +209,7 @@ impl ConjoiningClauses {
|
||||||
FnArg::Constant(NonIntegerConstant::BigInteger(_)) => unimplemented!(),
|
FnArg::Constant(NonIntegerConstant::BigInteger(_)) => unimplemented!(),
|
||||||
|
|
||||||
// These don't make sense here.
|
// These don't make sense here.
|
||||||
FnArg::Vector(_) | FnArg::SrcVar(_) => bail!(AlgebrizerError::InvalidGroundConstant),
|
FnArg::Vector(_) | FnArg::SrcVar(_) => bail!(AlgebrizerErrorKind::InvalidGroundConstant),
|
||||||
|
|
||||||
// These are all straightforward.
|
// These are all straightforward.
|
||||||
FnArg::Constant(NonIntegerConstant::Boolean(x)) => {
|
FnArg::Constant(NonIntegerConstant::Boolean(x)) => {
|
||||||
|
|
|
@ -18,7 +18,7 @@ use edn::query::{Binding, FnArg, NonIntegerConstant, SrcVar, VariableOrPlacehold
|
||||||
|
|
||||||
use clauses::ConjoiningClauses;
|
use clauses::ConjoiningClauses;
|
||||||
|
|
||||||
use query_algebrizer_traits::errors::{AlgebrizerError, BindingError, Result};
|
use query_algebrizer_traits::errors::{AlgebrizerErrorKind, BindingError, Result};
|
||||||
|
|
||||||
use types::{
|
use types::{
|
||||||
Column, ColumnConstraint, DatomsColumn, DatomsTable, EmptyBecause, FulltextColumn,
|
Column, ColumnConstraint, DatomsColumn, DatomsTable, EmptyBecause, FulltextColumn,
|
||||||
|
@ -31,7 +31,7 @@ impl ConjoiningClauses {
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub(crate) fn apply_fulltext(&mut self, known: Known, where_fn: WhereFn) -> Result<()> {
|
pub(crate) fn apply_fulltext(&mut self, known: Known, where_fn: WhereFn) -> Result<()> {
|
||||||
if where_fn.args.len() != 3 {
|
if where_fn.args.len() != 3 {
|
||||||
bail!(AlgebrizerError::InvalidNumberOfArguments(
|
bail!(AlgebrizerErrorKind::InvalidNumberOfArguments(
|
||||||
where_fn.operator.clone(),
|
where_fn.operator.clone(),
|
||||||
where_fn.args.len(),
|
where_fn.args.len(),
|
||||||
3
|
3
|
||||||
|
@ -40,7 +40,7 @@ impl ConjoiningClauses {
|
||||||
|
|
||||||
if where_fn.binding.is_empty() {
|
if where_fn.binding.is_empty() {
|
||||||
// The binding must introduce at least one bound variable.
|
// The binding must introduce at least one bound variable.
|
||||||
bail!(AlgebrizerError::InvalidBinding(
|
bail!(AlgebrizerErrorKind::InvalidBinding(
|
||||||
where_fn.operator.clone(),
|
where_fn.operator.clone(),
|
||||||
BindingError::NoBoundVariable
|
BindingError::NoBoundVariable
|
||||||
));
|
));
|
||||||
|
@ -48,7 +48,7 @@ impl ConjoiningClauses {
|
||||||
|
|
||||||
if !where_fn.binding.is_valid() {
|
if !where_fn.binding.is_valid() {
|
||||||
// The binding must not duplicate bound variables.
|
// The binding must not duplicate bound variables.
|
||||||
bail!(AlgebrizerError::InvalidBinding(
|
bail!(AlgebrizerErrorKind::InvalidBinding(
|
||||||
where_fn.operator.clone(),
|
where_fn.operator.clone(),
|
||||||
BindingError::RepeatedBoundVariable
|
BindingError::RepeatedBoundVariable
|
||||||
));
|
));
|
||||||
|
@ -59,7 +59,7 @@ impl ConjoiningClauses {
|
||||||
Binding::BindRel(bindings) => {
|
Binding::BindRel(bindings) => {
|
||||||
let bindings_count = bindings.len();
|
let bindings_count = bindings.len();
|
||||||
if bindings_count < 1 || bindings_count > 4 {
|
if bindings_count < 1 || bindings_count > 4 {
|
||||||
bail!(AlgebrizerError::InvalidBinding(
|
bail!(AlgebrizerErrorKind::InvalidBinding(
|
||||||
where_fn.operator.clone(),
|
where_fn.operator.clone(),
|
||||||
BindingError::InvalidNumberOfBindings {
|
BindingError::InvalidNumberOfBindings {
|
||||||
number: bindings.len(),
|
number: bindings.len(),
|
||||||
|
@ -70,7 +70,7 @@ impl ConjoiningClauses {
|
||||||
bindings
|
bindings
|
||||||
}
|
}
|
||||||
Binding::BindScalar(_) | Binding::BindTuple(_) | Binding::BindColl(_) => {
|
Binding::BindScalar(_) | Binding::BindTuple(_) | Binding::BindColl(_) => {
|
||||||
bail!(AlgebrizerError::InvalidBinding(
|
bail!(AlgebrizerErrorKind::InvalidBinding(
|
||||||
where_fn.operator.clone(),
|
where_fn.operator.clone(),
|
||||||
BindingError::ExpectedBindRel
|
BindingError::ExpectedBindRel
|
||||||
))
|
))
|
||||||
|
@ -93,7 +93,7 @@ impl ConjoiningClauses {
|
||||||
// TODO: process source variables.
|
// TODO: process source variables.
|
||||||
match args.next().unwrap() {
|
match args.next().unwrap() {
|
||||||
FnArg::SrcVar(SrcVar::DefaultSrc) => {}
|
FnArg::SrcVar(SrcVar::DefaultSrc) => {}
|
||||||
_ => bail!(AlgebrizerError::InvalidArgument(
|
_ => bail!(AlgebrizerErrorKind::InvalidArgument(
|
||||||
where_fn.operator.clone(),
|
where_fn.operator.clone(),
|
||||||
"source variable",
|
"source variable",
|
||||||
0
|
0
|
||||||
|
@ -116,12 +116,12 @@ impl ConjoiningClauses {
|
||||||
// TODO: allow non-constant attributes.
|
// TODO: allow non-constant attributes.
|
||||||
match self.bound_value(&v) {
|
match self.bound_value(&v) {
|
||||||
Some(TypedValue::Ref(entid)) => Some(entid),
|
Some(TypedValue::Ref(entid)) => Some(entid),
|
||||||
Some(tv) => bail!(AlgebrizerError::InputTypeDisagreement(
|
Some(tv) => bail!(AlgebrizerErrorKind::InputTypeDisagreement(
|
||||||
v.name().clone(),
|
v.name().clone(),
|
||||||
ValueType::Ref,
|
ValueType::Ref,
|
||||||
tv.value_type()
|
tv.value_type()
|
||||||
)),
|
)),
|
||||||
None => bail!(AlgebrizerError::UnboundVariable((*v.0).clone())),
|
None => bail!(AlgebrizerErrorKind::UnboundVariable((*v.0).clone())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
|
@ -130,7 +130,7 @@ impl ConjoiningClauses {
|
||||||
// An unknown ident, or an entity that isn't present in the store, or isn't a fulltext
|
// An unknown ident, or an entity that isn't present in the store, or isn't a fulltext
|
||||||
// attribute, is likely enough to be a coding error that we choose to bail instead of
|
// attribute, is likely enough to be a coding error that we choose to bail instead of
|
||||||
// marking the pattern as known-empty.
|
// marking the pattern as known-empty.
|
||||||
let a = a.ok_or(AlgebrizerError::InvalidArgument(
|
let a = a.ok_or(AlgebrizerErrorKind::InvalidArgument(
|
||||||
where_fn.operator.clone(),
|
where_fn.operator.clone(),
|
||||||
"attribute",
|
"attribute",
|
||||||
1,
|
1,
|
||||||
|
@ -139,7 +139,7 @@ impl ConjoiningClauses {
|
||||||
schema
|
schema
|
||||||
.attribute_for_entid(a)
|
.attribute_for_entid(a)
|
||||||
.cloned()
|
.cloned()
|
||||||
.ok_or(AlgebrizerError::InvalidArgument(
|
.ok_or(AlgebrizerErrorKind::InvalidArgument(
|
||||||
where_fn.operator.clone(),
|
where_fn.operator.clone(),
|
||||||
"attribute",
|
"attribute",
|
||||||
1,
|
1,
|
||||||
|
@ -190,7 +190,7 @@ impl ConjoiningClauses {
|
||||||
FnArg::Variable(in_var) => {
|
FnArg::Variable(in_var) => {
|
||||||
match self.bound_value(&in_var) {
|
match self.bound_value(&in_var) {
|
||||||
Some(t @ TypedValue::String(_)) => Either::Left(t),
|
Some(t @ TypedValue::String(_)) => Either::Left(t),
|
||||||
Some(_) => bail!(AlgebrizerError::InvalidArgument(
|
Some(_) => bail!(AlgebrizerErrorKind::InvalidArgument(
|
||||||
where_fn.operator.clone(),
|
where_fn.operator.clone(),
|
||||||
"string",
|
"string",
|
||||||
2
|
2
|
||||||
|
@ -199,7 +199,7 @@ impl ConjoiningClauses {
|
||||||
// Regardless of whether we'll be providing a string later, or the value
|
// Regardless of whether we'll be providing a string later, or the value
|
||||||
// comes from a column, it must be a string.
|
// comes from a column, it must be a string.
|
||||||
if self.known_type(&in_var) != Some(ValueType::String) {
|
if self.known_type(&in_var) != Some(ValueType::String) {
|
||||||
bail!(AlgebrizerError::InvalidArgument(
|
bail!(AlgebrizerErrorKind::InvalidArgument(
|
||||||
where_fn.operator.clone(),
|
where_fn.operator.clone(),
|
||||||
"string",
|
"string",
|
||||||
2
|
2
|
||||||
|
@ -209,7 +209,7 @@ impl ConjoiningClauses {
|
||||||
if self.input_variables.contains(&in_var) {
|
if self.input_variables.contains(&in_var) {
|
||||||
// Sorry, we haven't implemented late binding.
|
// Sorry, we haven't implemented late binding.
|
||||||
// TODO: implement this.
|
// TODO: implement this.
|
||||||
bail!(AlgebrizerError::UnboundVariable((*in_var.0).clone()))
|
bail!(AlgebrizerErrorKind::UnboundVariable((*in_var.0).clone()))
|
||||||
} else {
|
} else {
|
||||||
// It must be bound earlier in the query. We already established that
|
// It must be bound earlier in the query. We already established that
|
||||||
// it must be a string column.
|
// it must be a string column.
|
||||||
|
@ -220,13 +220,13 @@ impl ConjoiningClauses {
|
||||||
{
|
{
|
||||||
Either::Right(binding)
|
Either::Right(binding)
|
||||||
} else {
|
} else {
|
||||||
bail!(AlgebrizerError::UnboundVariable((*in_var.0).clone()))
|
bail!(AlgebrizerErrorKind::UnboundVariable((*in_var.0).clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => bail!(AlgebrizerError::InvalidArgument(
|
_ => bail!(AlgebrizerErrorKind::InvalidArgument(
|
||||||
where_fn.operator.clone(),
|
where_fn.operator.clone(),
|
||||||
"string",
|
"string",
|
||||||
2
|
2
|
||||||
|
@ -298,7 +298,7 @@ impl ConjoiningClauses {
|
||||||
|
|
||||||
// We do not allow the score to be bound.
|
// We do not allow the score to be bound.
|
||||||
if self.value_bindings.contains_key(var) || self.input_variables.contains(var) {
|
if self.value_bindings.contains_key(var) || self.input_variables.contains(var) {
|
||||||
bail!(AlgebrizerError::InvalidBinding(
|
bail!(AlgebrizerErrorKind::InvalidBinding(
|
||||||
var.name(),
|
var.name(),
|
||||||
BindingError::UnexpectedBinding
|
BindingError::UnexpectedBinding
|
||||||
));
|
));
|
||||||
|
|
|
@ -18,7 +18,7 @@ use clauses::{ConjoiningClauses, PushComputed};
|
||||||
|
|
||||||
use clauses::convert::ValueConversion;
|
use clauses::convert::ValueConversion;
|
||||||
|
|
||||||
use query_algebrizer_traits::errors::{AlgebrizerError, BindingError, Result};
|
use query_algebrizer_traits::errors::{AlgebrizerErrorKind, BindingError, Result};
|
||||||
|
|
||||||
use types::{ComputedTable, EmptyBecause, SourceAlias, VariableColumn};
|
use types::{ComputedTable, EmptyBecause, SourceAlias, VariableColumn};
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ impl ConjoiningClauses {
|
||||||
|
|
||||||
pub(crate) fn apply_ground(&mut self, known: Known, where_fn: WhereFn) -> Result<()> {
|
pub(crate) fn apply_ground(&mut self, known: Known, where_fn: WhereFn) -> Result<()> {
|
||||||
if where_fn.args.len() != 1 {
|
if where_fn.args.len() != 1 {
|
||||||
bail!(AlgebrizerError::InvalidNumberOfArguments(
|
bail!(AlgebrizerErrorKind::InvalidNumberOfArguments(
|
||||||
where_fn.operator.clone(),
|
where_fn.operator.clone(),
|
||||||
where_fn.args.len(),
|
where_fn.args.len(),
|
||||||
1
|
1
|
||||||
|
@ -128,7 +128,7 @@ impl ConjoiningClauses {
|
||||||
|
|
||||||
if where_fn.binding.is_empty() {
|
if where_fn.binding.is_empty() {
|
||||||
// The binding must introduce at least one bound variable.
|
// The binding must introduce at least one bound variable.
|
||||||
bail!(AlgebrizerError::InvalidBinding(
|
bail!(AlgebrizerErrorKind::InvalidBinding(
|
||||||
where_fn.operator.clone(),
|
where_fn.operator.clone(),
|
||||||
BindingError::NoBoundVariable
|
BindingError::NoBoundVariable
|
||||||
));
|
));
|
||||||
|
@ -136,7 +136,7 @@ impl ConjoiningClauses {
|
||||||
|
|
||||||
if !where_fn.binding.is_valid() {
|
if !where_fn.binding.is_valid() {
|
||||||
// The binding must not duplicate bound variables.
|
// The binding must not duplicate bound variables.
|
||||||
bail!(AlgebrizerError::InvalidBinding(
|
bail!(AlgebrizerErrorKind::InvalidBinding(
|
||||||
where_fn.operator.clone(),
|
where_fn.operator.clone(),
|
||||||
BindingError::RepeatedBoundVariable
|
BindingError::RepeatedBoundVariable
|
||||||
));
|
));
|
||||||
|
@ -154,7 +154,7 @@ impl ConjoiningClauses {
|
||||||
// Just the same, but we bind more than one column at a time.
|
// Just the same, but we bind more than one column at a time.
|
||||||
if children.len() != places.len() {
|
if children.len() != places.len() {
|
||||||
// Number of arguments don't match the number of values. TODO: better error message.
|
// Number of arguments don't match the number of values. TODO: better error message.
|
||||||
bail!(AlgebrizerError::GroundBindingsMismatch)
|
bail!(AlgebrizerErrorKind::GroundBindingsMismatch)
|
||||||
}
|
}
|
||||||
for (place, arg) in places.into_iter().zip(children.into_iter()) {
|
for (place, arg) in places.into_iter().zip(children.into_iter()) {
|
||||||
self.apply_ground_place(schema, place, arg)? // TODO: short-circuit on impossible.
|
self.apply_ground_place(schema, place, arg)? // TODO: short-circuit on impossible.
|
||||||
|
@ -168,7 +168,7 @@ impl ConjoiningClauses {
|
||||||
// are all in a single structure. That makes it substantially simpler!
|
// are all in a single structure. That makes it substantially simpler!
|
||||||
(Binding::BindColl(var), FnArg::Vector(children)) => {
|
(Binding::BindColl(var), FnArg::Vector(children)) => {
|
||||||
if children.is_empty() {
|
if children.is_empty() {
|
||||||
bail!(AlgebrizerError::InvalidGroundConstant)
|
bail!(AlgebrizerErrorKind::InvalidGroundConstant)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Turn a collection of arguments into a Vec of `TypedValue`s of the same type.
|
// Turn a collection of arguments into a Vec of `TypedValue`s of the same type.
|
||||||
|
@ -188,7 +188,7 @@ impl ConjoiningClauses {
|
||||||
&& !accumulated_types.is_unit()
|
&& !accumulated_types.is_unit()
|
||||||
{
|
{
|
||||||
// Values not all of the same type.
|
// Values not all of the same type.
|
||||||
Some(Err(AlgebrizerError::InvalidGroundConstant.into()))
|
Some(Err(AlgebrizerErrorKind::InvalidGroundConstant.into()))
|
||||||
} else {
|
} else {
|
||||||
Some(Ok(tv))
|
Some(Ok(tv))
|
||||||
}
|
}
|
||||||
|
@ -219,7 +219,7 @@ impl ConjoiningClauses {
|
||||||
|
|
||||||
(Binding::BindRel(places), FnArg::Vector(rows)) => {
|
(Binding::BindRel(places), FnArg::Vector(rows)) => {
|
||||||
if rows.is_empty() {
|
if rows.is_empty() {
|
||||||
bail!(AlgebrizerError::InvalidGroundConstant)
|
bail!(AlgebrizerErrorKind::InvalidGroundConstant)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grab the known types to which these args must conform, and track
|
// Grab the known types to which these args must conform, and track
|
||||||
|
@ -243,7 +243,7 @@ impl ConjoiningClauses {
|
||||||
|
|
||||||
if expected_width == 0 {
|
if expected_width == 0 {
|
||||||
// They can't all be placeholders.
|
// They can't all be placeholders.
|
||||||
bail!(AlgebrizerError::InvalidGroundConstant)
|
bail!(AlgebrizerErrorKind::InvalidGroundConstant)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accumulate values into `matrix` and types into `a_t_f_c`.
|
// Accumulate values into `matrix` and types into `a_t_f_c`.
|
||||||
|
@ -259,7 +259,7 @@ impl ConjoiningClauses {
|
||||||
FnArg::Vector(cols) => {
|
FnArg::Vector(cols) => {
|
||||||
// Make sure that every row is the same length.
|
// Make sure that every row is the same length.
|
||||||
if cols.len() != full_width {
|
if cols.len() != full_width {
|
||||||
bail!(AlgebrizerError::InvalidGroundConstant)
|
bail!(AlgebrizerErrorKind::InvalidGroundConstant)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: don't accumulate twice.
|
// TODO: don't accumulate twice.
|
||||||
|
@ -297,12 +297,12 @@ impl ConjoiningClauses {
|
||||||
let inserted = acc.insert(val.value_type());
|
let inserted = acc.insert(val.value_type());
|
||||||
if inserted && !acc.is_unit() {
|
if inserted && !acc.is_unit() {
|
||||||
// Heterogeneous types.
|
// Heterogeneous types.
|
||||||
bail!(AlgebrizerError::InvalidGroundConstant)
|
bail!(AlgebrizerErrorKind::InvalidGroundConstant)
|
||||||
}
|
}
|
||||||
matrix.push(val);
|
matrix.push(val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => bail!(AlgebrizerError::InvalidGroundConstant),
|
_ => bail!(AlgebrizerErrorKind::InvalidGroundConstant),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,7 +329,7 @@ impl ConjoiningClauses {
|
||||||
self.collect_named_bindings(schema, names, types, matrix);
|
self.collect_named_bindings(schema, names, types, matrix);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
(_, _) => bail!(AlgebrizerError::InvalidGroundConstant),
|
(_, _) => bail!(AlgebrizerErrorKind::InvalidGroundConstant),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ use core_traits::{TypedValue, ValueType};
|
||||||
|
|
||||||
use edn::query::Variable;
|
use edn::query::Variable;
|
||||||
|
|
||||||
use query_algebrizer_traits::errors::{AlgebrizerError, Result};
|
use query_algebrizer_traits::errors::{AlgebrizerErrorKind, Result};
|
||||||
|
|
||||||
/// Define the inputs to a query. This is in two parts: a set of values known now, and a set of
|
/// Define the inputs to a query. This is in two parts: a set of values known now, and a set of
|
||||||
/// types known now.
|
/// types known now.
|
||||||
|
@ -69,7 +69,7 @@ impl QueryInputs {
|
||||||
let old = types.insert(var.clone(), t);
|
let old = types.insert(var.clone(), t);
|
||||||
if let Some(old) = old {
|
if let Some(old) = old {
|
||||||
if old != t {
|
if old != t {
|
||||||
bail!(AlgebrizerError::InputTypeDisagreement(var.name(), old, t));
|
bail!(AlgebrizerErrorKind::InputTypeDisagreement(var.name(), old, t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ use mentat_core::counter::RcCounter;
|
||||||
|
|
||||||
use edn::query::{Element, FindSpec, Keyword, PatternNonValuePlace, Pull, Variable, WhereClause};
|
use edn::query::{Element, FindSpec, Keyword, PatternNonValuePlace, Pull, Variable, WhereClause};
|
||||||
|
|
||||||
use query_algebrizer_traits::errors::{AlgebrizerError, Result};
|
use query_algebrizer_traits::errors::{AlgebrizerErrorKind, Result};
|
||||||
|
|
||||||
use types::{
|
use types::{
|
||||||
Column, ColumnConstraint, ColumnIntersection, ComputedTable, DatomsColumn, DatomsTable,
|
Column, ColumnConstraint, ColumnIntersection, ComputedTable, DatomsColumn, DatomsTable,
|
||||||
|
@ -1071,7 +1071,7 @@ impl ConjoiningClauses {
|
||||||
let qa = self
|
let qa = self
|
||||||
.extracted_types
|
.extracted_types
|
||||||
.get(&var)
|
.get(&var)
|
||||||
.ok_or_else(|| AlgebrizerError::UnboundVariable(var.name()))?;
|
.ok_or_else(|| AlgebrizerErrorKind::UnboundVariable(var.name()))?;
|
||||||
self.wheres.add_intersection(ColumnConstraint::HasTypes {
|
self.wheres.add_intersection(ColumnConstraint::HasTypes {
|
||||||
value: qa.0.clone(),
|
value: qa.0.clone(),
|
||||||
value_types: types,
|
value_types: types,
|
||||||
|
|
|
@ -12,7 +12,7 @@ use edn::query::{ContainsVariables, NotJoin, UnifyVars};
|
||||||
|
|
||||||
use clauses::ConjoiningClauses;
|
use clauses::ConjoiningClauses;
|
||||||
|
|
||||||
use query_algebrizer_traits::errors::{AlgebrizerError, Result};
|
use query_algebrizer_traits::errors::{AlgebrizerErrorKind, Result};
|
||||||
|
|
||||||
use types::{ColumnConstraint, ComputedTable};
|
use types::{ColumnConstraint, ComputedTable};
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ impl ConjoiningClauses {
|
||||||
let col = self.column_bindings.get(&v).unwrap()[0].clone();
|
let col = self.column_bindings.get(&v).unwrap()[0].clone();
|
||||||
template.column_bindings.insert(v.clone(), vec![col]);
|
template.column_bindings.insert(v.clone(), vec![col]);
|
||||||
} else {
|
} else {
|
||||||
bail!(AlgebrizerError::UnboundVariable(v.name()));
|
bail!(AlgebrizerErrorKind::UnboundVariable(v.name()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ mod testing {
|
||||||
|
|
||||||
use clauses::{add_attribute, associate_ident, QueryInputs};
|
use clauses::{add_attribute, associate_ident, QueryInputs};
|
||||||
|
|
||||||
use query_algebrizer_traits::errors::AlgebrizerError;
|
use query_algebrizer_traits::errors::AlgebrizerErrorKind;
|
||||||
|
|
||||||
use types::{
|
use types::{
|
||||||
ColumnAlternation, ColumnConstraint, ColumnConstraintOrAlternation, ColumnIntersection,
|
ColumnAlternation, ColumnConstraint, ColumnConstraintOrAlternation, ColumnIntersection,
|
||||||
|
@ -714,7 +714,7 @@ mod testing {
|
||||||
let parsed = parse_find_string(query).expect("parse failed");
|
let parsed = parse_find_string(query).expect("parse failed");
|
||||||
let err = algebrize(known, parsed).expect_err("algebrization should have failed");
|
let err = algebrize(known, parsed).expect_err("algebrization should have failed");
|
||||||
match err {
|
match err {
|
||||||
AlgebrizerError::UnboundVariable(var) => {
|
AlgebrizerErrorKind::UnboundVariable(var) => {
|
||||||
assert_eq!(var, PlainSymbol("?x".to_string()));
|
assert_eq!(var, PlainSymbol("?x".to_string()));
|
||||||
}
|
}
|
||||||
x => panic!("expected Unbound Variable error, got {:?}", x),
|
x => panic!("expected Unbound Variable error, got {:?}", x),
|
||||||
|
|
|
@ -18,7 +18,7 @@ use clauses::ConjoiningClauses;
|
||||||
|
|
||||||
use clauses::convert::ValueTypes;
|
use clauses::convert::ValueTypes;
|
||||||
|
|
||||||
use query_algebrizer_traits::errors::{AlgebrizerError, Result};
|
use query_algebrizer_traits::errors::{AlgebrizerErrorKind, Result};
|
||||||
|
|
||||||
use types::{ColumnConstraint, EmptyBecause, Inequality, QueryValue};
|
use types::{ColumnConstraint, EmptyBecause, Inequality, QueryValue};
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ impl ConjoiningClauses {
|
||||||
if let Some(op) = Inequality::from_datalog_operator(predicate.operator.0.as_str()) {
|
if let Some(op) = Inequality::from_datalog_operator(predicate.operator.0.as_str()) {
|
||||||
self.apply_inequality(known, op, predicate)
|
self.apply_inequality(known, op, predicate)
|
||||||
} else {
|
} else {
|
||||||
bail!(AlgebrizerError::UnknownFunction(predicate.operator.clone()))
|
bail!(AlgebrizerErrorKind::UnknownFunction(predicate.operator.clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ impl ConjoiningClauses {
|
||||||
Some(value_type) => {
|
Some(value_type) => {
|
||||||
self.add_type_requirement(anno.variable.clone(), ValueTypeSet::of_one(value_type))
|
self.add_type_requirement(anno.variable.clone(), ValueTypeSet::of_one(value_type))
|
||||||
}
|
}
|
||||||
None => bail!(AlgebrizerError::InvalidArgumentType(
|
None => bail!(AlgebrizerErrorKind::InvalidArgumentType(
|
||||||
PlainSymbol::plain("type"),
|
PlainSymbol::plain("type"),
|
||||||
ValueTypeSet::any(),
|
ValueTypeSet::any(),
|
||||||
2
|
2
|
||||||
|
@ -76,7 +76,7 @@ impl ConjoiningClauses {
|
||||||
predicate: Predicate,
|
predicate: Predicate,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
if predicate.args.len() != 2 {
|
if predicate.args.len() != 2 {
|
||||||
bail!(AlgebrizerError::InvalidNumberOfArguments(
|
bail!(AlgebrizerErrorKind::InvalidNumberOfArguments(
|
||||||
predicate.operator.clone(),
|
predicate.operator.clone(),
|
||||||
predicate.args.len(),
|
predicate.args.len(),
|
||||||
2
|
2
|
||||||
|
@ -97,7 +97,7 @@ impl ConjoiningClauses {
|
||||||
.potential_types(known.schema, &left)?
|
.potential_types(known.schema, &left)?
|
||||||
.intersection(&supported_types);
|
.intersection(&supported_types);
|
||||||
if left_types.is_empty() {
|
if left_types.is_empty() {
|
||||||
bail!(AlgebrizerError::InvalidArgumentType(
|
bail!(AlgebrizerErrorKind::InvalidArgumentType(
|
||||||
predicate.operator.clone(),
|
predicate.operator.clone(),
|
||||||
supported_types,
|
supported_types,
|
||||||
0
|
0
|
||||||
|
@ -108,7 +108,7 @@ impl ConjoiningClauses {
|
||||||
.potential_types(known.schema, &right)?
|
.potential_types(known.schema, &right)?
|
||||||
.intersection(&supported_types);
|
.intersection(&supported_types);
|
||||||
if right_types.is_empty() {
|
if right_types.is_empty() {
|
||||||
bail!(AlgebrizerError::InvalidArgumentType(
|
bail!(AlgebrizerErrorKind::InvalidArgumentType(
|
||||||
predicate.operator.clone(),
|
predicate.operator.clone(),
|
||||||
supported_types,
|
supported_types,
|
||||||
1
|
1
|
||||||
|
@ -160,7 +160,7 @@ impl ConjoiningClauses {
|
||||||
left_v = self.resolve_ref_argument(known.schema, &predicate.operator, 0, left)?;
|
left_v = self.resolve_ref_argument(known.schema, &predicate.operator, 0, left)?;
|
||||||
right_v = self.resolve_ref_argument(known.schema, &predicate.operator, 1, right)?;
|
right_v = self.resolve_ref_argument(known.schema, &predicate.operator, 1, right)?;
|
||||||
} else {
|
} else {
|
||||||
bail!(AlgebrizerError::InvalidArgumentType(
|
bail!(AlgebrizerErrorKind::InvalidArgumentType(
|
||||||
predicate.operator.clone(),
|
predicate.operator.clone(),
|
||||||
supported_types,
|
supported_types,
|
||||||
0
|
0
|
||||||
|
|
|
@ -16,7 +16,7 @@ use edn::query::{FnArg, NonIntegerConstant, PlainSymbol};
|
||||||
|
|
||||||
use clauses::ConjoiningClauses;
|
use clauses::ConjoiningClauses;
|
||||||
|
|
||||||
use query_algebrizer_traits::errors::{AlgebrizerError, Result};
|
use query_algebrizer_traits::errors::{AlgebrizerErrorKind, Result};
|
||||||
|
|
||||||
use types::{EmptyBecause, QueryValue};
|
use types::{EmptyBecause, QueryValue};
|
||||||
|
|
||||||
|
@ -41,14 +41,14 @@ impl ConjoiningClauses {
|
||||||
if v.value_type().is_numeric() {
|
if v.value_type().is_numeric() {
|
||||||
Ok(QueryValue::TypedValue(v))
|
Ok(QueryValue::TypedValue(v))
|
||||||
} else {
|
} else {
|
||||||
bail!(AlgebrizerError::InputTypeDisagreement(var.name().clone(), ValueType::Long, v.value_type()))
|
bail!(AlgebrizerErrorKind::InputTypeDisagreement(var.name().clone(), ValueType::Long, v.value_type()))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.constrain_var_to_numeric(var.clone());
|
self.constrain_var_to_numeric(var.clone());
|
||||||
self.column_bindings
|
self.column_bindings
|
||||||
.get(&var)
|
.get(&var)
|
||||||
.and_then(|cols| cols.first().map(|col| QueryValue::Column(col.clone())))
|
.and_then(|cols| cols.first().map(|col| QueryValue::Column(col.clone())))
|
||||||
.ok_or_else(|| AlgebrizerError::UnboundVariable(var.name()).into())
|
.ok_or_else(|| AlgebrizerErrorKind::UnboundVariable(var.name()).into())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// Can't be an entid.
|
// Can't be an entid.
|
||||||
|
@ -62,7 +62,7 @@ impl ConjoiningClauses {
|
||||||
Constant(NonIntegerConstant::BigInteger(_)) |
|
Constant(NonIntegerConstant::BigInteger(_)) |
|
||||||
Vector(_) => {
|
Vector(_) => {
|
||||||
self.mark_known_empty(EmptyBecause::NonNumericArgument);
|
self.mark_known_empty(EmptyBecause::NonNumericArgument);
|
||||||
bail!(AlgebrizerError::InvalidArgument(function.clone(), "numeric", position))
|
bail!(AlgebrizerErrorKind::InvalidArgument(function.clone(), "numeric", position))
|
||||||
},
|
},
|
||||||
Constant(NonIntegerConstant::Float(f)) => Ok(QueryValue::TypedValue(TypedValue::Double(f))),
|
Constant(NonIntegerConstant::Float(f)) => Ok(QueryValue::TypedValue(TypedValue::Double(f))),
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,7 @@ impl ConjoiningClauses {
|
||||||
match arg {
|
match arg {
|
||||||
FnArg::Variable(var) => match self.bound_value(&var) {
|
FnArg::Variable(var) => match self.bound_value(&var) {
|
||||||
Some(TypedValue::Instant(v)) => Ok(QueryValue::TypedValue(TypedValue::Instant(v))),
|
Some(TypedValue::Instant(v)) => Ok(QueryValue::TypedValue(TypedValue::Instant(v))),
|
||||||
Some(v) => bail!(AlgebrizerError::InputTypeDisagreement(
|
Some(v) => bail!(AlgebrizerErrorKind::InputTypeDisagreement(
|
||||||
var.name().clone(),
|
var.name().clone(),
|
||||||
ValueType::Instant,
|
ValueType::Instant,
|
||||||
v.value_type()
|
v.value_type()
|
||||||
|
@ -89,7 +89,7 @@ impl ConjoiningClauses {
|
||||||
self.column_bindings
|
self.column_bindings
|
||||||
.get(&var)
|
.get(&var)
|
||||||
.and_then(|cols| cols.first().map(|col| QueryValue::Column(col.clone())))
|
.and_then(|cols| cols.first().map(|col| QueryValue::Column(col.clone())))
|
||||||
.ok_or_else(|| AlgebrizerError::UnboundVariable(var.name()).into())
|
.ok_or_else(|| AlgebrizerErrorKind::UnboundVariable(var.name()).into())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Constant(NonIntegerConstant::Instant(v)) => {
|
Constant(NonIntegerConstant::Instant(v)) => {
|
||||||
|
@ -107,7 +107,7 @@ impl ConjoiningClauses {
|
||||||
| Constant(NonIntegerConstant::BigInteger(_))
|
| Constant(NonIntegerConstant::BigInteger(_))
|
||||||
| Vector(_) => {
|
| Vector(_) => {
|
||||||
self.mark_known_empty(EmptyBecause::NonInstantArgument);
|
self.mark_known_empty(EmptyBecause::NonInstantArgument);
|
||||||
bail!(AlgebrizerError::InvalidArgumentType(
|
bail!(AlgebrizerErrorKind::InvalidArgumentType(
|
||||||
function.clone(),
|
function.clone(),
|
||||||
ValueType::Instant.into(),
|
ValueType::Instant.into(),
|
||||||
position
|
position
|
||||||
|
@ -136,14 +136,14 @@ impl ConjoiningClauses {
|
||||||
self.column_bindings
|
self.column_bindings
|
||||||
.get(&var)
|
.get(&var)
|
||||||
.and_then(|cols| cols.first().map(|col| QueryValue::Column(col.clone())))
|
.and_then(|cols| cols.first().map(|col| QueryValue::Column(col.clone())))
|
||||||
.ok_or_else(|| AlgebrizerError::UnboundVariable(var.name()).into())
|
.ok_or_else(|| AlgebrizerErrorKind::UnboundVariable(var.name()).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EntidOrInteger(i) => Ok(QueryValue::TypedValue(TypedValue::Ref(i))),
|
EntidOrInteger(i) => Ok(QueryValue::TypedValue(TypedValue::Ref(i))),
|
||||||
IdentOrKeyword(i) => schema
|
IdentOrKeyword(i) => schema
|
||||||
.get_entid(&i)
|
.get_entid(&i)
|
||||||
.map(|known_entid| QueryValue::Entid(known_entid.into()))
|
.map(|known_entid| QueryValue::Entid(known_entid.into()))
|
||||||
.ok_or_else(|| AlgebrizerError::UnrecognizedIdent(i.to_string()).into()),
|
.ok_or_else(|| AlgebrizerErrorKind::UnrecognizedIdent(i.to_string()).into()),
|
||||||
Constant(NonIntegerConstant::Boolean(_))
|
Constant(NonIntegerConstant::Boolean(_))
|
||||||
| Constant(NonIntegerConstant::Float(_))
|
| Constant(NonIntegerConstant::Float(_))
|
||||||
| Constant(NonIntegerConstant::Text(_))
|
| Constant(NonIntegerConstant::Text(_))
|
||||||
|
@ -153,7 +153,7 @@ impl ConjoiningClauses {
|
||||||
| SrcVar(_)
|
| SrcVar(_)
|
||||||
| Vector(_) => {
|
| Vector(_) => {
|
||||||
self.mark_known_empty(EmptyBecause::NonEntityArgument);
|
self.mark_known_empty(EmptyBecause::NonEntityArgument);
|
||||||
bail!(AlgebrizerError::InvalidArgumentType(
|
bail!(AlgebrizerErrorKind::InvalidArgumentType(
|
||||||
function.clone(),
|
function.clone(),
|
||||||
ValueType::Ref.into(),
|
ValueType::Ref.into(),
|
||||||
position
|
position
|
||||||
|
@ -188,7 +188,7 @@ impl ConjoiningClauses {
|
||||||
.column_bindings
|
.column_bindings
|
||||||
.get(&var)
|
.get(&var)
|
||||||
.and_then(|cols| cols.first().map(|col| QueryValue::Column(col.clone())))
|
.and_then(|cols| cols.first().map(|col| QueryValue::Column(col.clone())))
|
||||||
.ok_or_else(|| AlgebrizerError::UnboundVariable(var.name()).into()),
|
.ok_or_else(|| AlgebrizerErrorKind::UnboundVariable(var.name()).into()),
|
||||||
},
|
},
|
||||||
EntidOrInteger(i) => Ok(QueryValue::PrimitiveLong(i)),
|
EntidOrInteger(i) => Ok(QueryValue::PrimitiveLong(i)),
|
||||||
IdentOrKeyword(_) => unimplemented!(), // TODO
|
IdentOrKeyword(_) => unimplemented!(), // TODO
|
||||||
|
|
|
@ -14,7 +14,7 @@ use edn::query::{Binding, FnArg, SrcVar, VariableOrPlaceholder, WhereFn};
|
||||||
|
|
||||||
use clauses::ConjoiningClauses;
|
use clauses::ConjoiningClauses;
|
||||||
|
|
||||||
use query_algebrizer_traits::errors::{AlgebrizerError, BindingError, Result};
|
use query_algebrizer_traits::errors::{AlgebrizerErrorKind, BindingError, Result};
|
||||||
|
|
||||||
use types::{
|
use types::{
|
||||||
Column, ColumnConstraint, DatomsTable, Inequality, QualifiedAlias, QueryValue, SourceAlias,
|
Column, ColumnConstraint, DatomsTable, Inequality, QualifiedAlias, QueryValue, SourceAlias,
|
||||||
|
@ -40,7 +40,7 @@ impl ConjoiningClauses {
|
||||||
// transactions that impact one of the given attributes.
|
// transactions that impact one of the given attributes.
|
||||||
pub(crate) fn apply_tx_ids(&mut self, known: Known, where_fn: WhereFn) -> Result<()> {
|
pub(crate) fn apply_tx_ids(&mut self, known: Known, where_fn: WhereFn) -> Result<()> {
|
||||||
if where_fn.args.len() != 3 {
|
if where_fn.args.len() != 3 {
|
||||||
bail!(AlgebrizerError::InvalidNumberOfArguments(
|
bail!(AlgebrizerErrorKind::InvalidNumberOfArguments(
|
||||||
where_fn.operator.clone(),
|
where_fn.operator.clone(),
|
||||||
where_fn.args.len(),
|
where_fn.args.len(),
|
||||||
3
|
3
|
||||||
|
@ -49,7 +49,7 @@ impl ConjoiningClauses {
|
||||||
|
|
||||||
if where_fn.binding.is_empty() {
|
if where_fn.binding.is_empty() {
|
||||||
// The binding must introduce at least one bound variable.
|
// The binding must introduce at least one bound variable.
|
||||||
bail!(AlgebrizerError::InvalidBinding(
|
bail!(AlgebrizerErrorKind::InvalidBinding(
|
||||||
where_fn.operator.clone(),
|
where_fn.operator.clone(),
|
||||||
BindingError::NoBoundVariable
|
BindingError::NoBoundVariable
|
||||||
));
|
));
|
||||||
|
@ -57,7 +57,7 @@ impl ConjoiningClauses {
|
||||||
|
|
||||||
if !where_fn.binding.is_valid() {
|
if !where_fn.binding.is_valid() {
|
||||||
// The binding must not duplicate bound variables.
|
// The binding must not duplicate bound variables.
|
||||||
bail!(AlgebrizerError::InvalidBinding(
|
bail!(AlgebrizerErrorKind::InvalidBinding(
|
||||||
where_fn.operator.clone(),
|
where_fn.operator.clone(),
|
||||||
BindingError::RepeatedBoundVariable
|
BindingError::RepeatedBoundVariable
|
||||||
));
|
));
|
||||||
|
@ -68,7 +68,7 @@ impl ConjoiningClauses {
|
||||||
Binding::BindRel(bindings) => {
|
Binding::BindRel(bindings) => {
|
||||||
let bindings_count = bindings.len();
|
let bindings_count = bindings.len();
|
||||||
if bindings_count != 1 {
|
if bindings_count != 1 {
|
||||||
bail!(AlgebrizerError::InvalidBinding(
|
bail!(AlgebrizerErrorKind::InvalidBinding(
|
||||||
where_fn.operator.clone(),
|
where_fn.operator.clone(),
|
||||||
BindingError::InvalidNumberOfBindings {
|
BindingError::InvalidNumberOfBindings {
|
||||||
number: bindings_count,
|
number: bindings_count,
|
||||||
|
@ -83,7 +83,7 @@ impl ConjoiningClauses {
|
||||||
}
|
}
|
||||||
Binding::BindColl(v) => v,
|
Binding::BindColl(v) => v,
|
||||||
Binding::BindScalar(_) | Binding::BindTuple(_) => {
|
Binding::BindScalar(_) | Binding::BindTuple(_) => {
|
||||||
bail!(AlgebrizerError::InvalidBinding(
|
bail!(AlgebrizerErrorKind::InvalidBinding(
|
||||||
where_fn.operator.clone(),
|
where_fn.operator.clone(),
|
||||||
BindingError::ExpectedBindRelOrBindColl
|
BindingError::ExpectedBindRelOrBindColl
|
||||||
))
|
))
|
||||||
|
@ -95,7 +95,7 @@ impl ConjoiningClauses {
|
||||||
// TODO: process source variables.
|
// TODO: process source variables.
|
||||||
match args.next().unwrap() {
|
match args.next().unwrap() {
|
||||||
FnArg::SrcVar(SrcVar::DefaultSrc) => {}
|
FnArg::SrcVar(SrcVar::DefaultSrc) => {}
|
||||||
_ => bail!(AlgebrizerError::InvalidArgument(
|
_ => bail!(AlgebrizerErrorKind::InvalidArgument(
|
||||||
where_fn.operator.clone(),
|
where_fn.operator.clone(),
|
||||||
"source variable",
|
"source variable",
|
||||||
0
|
0
|
||||||
|
@ -150,7 +150,7 @@ impl ConjoiningClauses {
|
||||||
|
|
||||||
pub(crate) fn apply_tx_data(&mut self, known: Known, where_fn: WhereFn) -> Result<()> {
|
pub(crate) fn apply_tx_data(&mut self, known: Known, where_fn: WhereFn) -> Result<()> {
|
||||||
if where_fn.args.len() != 2 {
|
if where_fn.args.len() != 2 {
|
||||||
bail!(AlgebrizerError::InvalidNumberOfArguments(
|
bail!(AlgebrizerErrorKind::InvalidNumberOfArguments(
|
||||||
where_fn.operator.clone(),
|
where_fn.operator.clone(),
|
||||||
where_fn.args.len(),
|
where_fn.args.len(),
|
||||||
2
|
2
|
||||||
|
@ -159,7 +159,7 @@ impl ConjoiningClauses {
|
||||||
|
|
||||||
if where_fn.binding.is_empty() {
|
if where_fn.binding.is_empty() {
|
||||||
// The binding must introduce at least one bound variable.
|
// The binding must introduce at least one bound variable.
|
||||||
bail!(AlgebrizerError::InvalidBinding(
|
bail!(AlgebrizerErrorKind::InvalidBinding(
|
||||||
where_fn.operator.clone(),
|
where_fn.operator.clone(),
|
||||||
BindingError::NoBoundVariable
|
BindingError::NoBoundVariable
|
||||||
));
|
));
|
||||||
|
@ -167,7 +167,7 @@ impl ConjoiningClauses {
|
||||||
|
|
||||||
if !where_fn.binding.is_valid() {
|
if !where_fn.binding.is_valid() {
|
||||||
// The binding must not duplicate bound variables.
|
// The binding must not duplicate bound variables.
|
||||||
bail!(AlgebrizerError::InvalidBinding(
|
bail!(AlgebrizerErrorKind::InvalidBinding(
|
||||||
where_fn.operator.clone(),
|
where_fn.operator.clone(),
|
||||||
BindingError::RepeatedBoundVariable
|
BindingError::RepeatedBoundVariable
|
||||||
));
|
));
|
||||||
|
@ -178,7 +178,7 @@ impl ConjoiningClauses {
|
||||||
Binding::BindRel(bindings) => {
|
Binding::BindRel(bindings) => {
|
||||||
let bindings_count = bindings.len();
|
let bindings_count = bindings.len();
|
||||||
if bindings_count < 1 || bindings_count > 5 {
|
if bindings_count < 1 || bindings_count > 5 {
|
||||||
bail!(AlgebrizerError::InvalidBinding(
|
bail!(AlgebrizerErrorKind::InvalidBinding(
|
||||||
where_fn.operator.clone(),
|
where_fn.operator.clone(),
|
||||||
BindingError::InvalidNumberOfBindings {
|
BindingError::InvalidNumberOfBindings {
|
||||||
number: bindings.len(),
|
number: bindings.len(),
|
||||||
|
@ -189,7 +189,7 @@ impl ConjoiningClauses {
|
||||||
bindings
|
bindings
|
||||||
}
|
}
|
||||||
Binding::BindScalar(_) | Binding::BindTuple(_) | Binding::BindColl(_) => {
|
Binding::BindScalar(_) | Binding::BindTuple(_) | Binding::BindColl(_) => {
|
||||||
bail!(AlgebrizerError::InvalidBinding(
|
bail!(AlgebrizerErrorKind::InvalidBinding(
|
||||||
where_fn.operator.clone(),
|
where_fn.operator.clone(),
|
||||||
BindingError::ExpectedBindRel
|
BindingError::ExpectedBindRel
|
||||||
))
|
))
|
||||||
|
@ -217,7 +217,7 @@ impl ConjoiningClauses {
|
||||||
// TODO: process source variables.
|
// TODO: process source variables.
|
||||||
match args.next().unwrap() {
|
match args.next().unwrap() {
|
||||||
FnArg::SrcVar(SrcVar::DefaultSrc) => {}
|
FnArg::SrcVar(SrcVar::DefaultSrc) => {}
|
||||||
_ => bail!(AlgebrizerError::InvalidArgument(
|
_ => bail!(AlgebrizerErrorKind::InvalidArgument(
|
||||||
where_fn.operator.clone(),
|
where_fn.operator.clone(),
|
||||||
"source variable",
|
"source variable",
|
||||||
0
|
0
|
||||||
|
|
|
@ -12,7 +12,7 @@ use edn::query::WhereFn;
|
||||||
|
|
||||||
use clauses::ConjoiningClauses;
|
use clauses::ConjoiningClauses;
|
||||||
|
|
||||||
use query_algebrizer_traits::errors::{AlgebrizerError, Result};
|
use query_algebrizer_traits::errors::{AlgebrizerErrorKind, Result};
|
||||||
|
|
||||||
use Known;
|
use Known;
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ impl ConjoiningClauses {
|
||||||
"ground" => self.apply_ground(known, where_fn),
|
"ground" => self.apply_ground(known, where_fn),
|
||||||
"tx-data" => self.apply_tx_data(known, where_fn),
|
"tx-data" => self.apply_tx_data(known, where_fn),
|
||||||
"tx-ids" => self.apply_tx_ids(known, where_fn),
|
"tx-ids" => self.apply_tx_ids(known, where_fn),
|
||||||
_ => bail!(AlgebrizerError::UnknownFunction(where_fn.operator.clone())),
|
_ => bail!(AlgebrizerErrorKind::UnknownFunction(where_fn.operator.clone())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ use mentat_core::counter::RcCounter;
|
||||||
|
|
||||||
use edn::query::{Element, FindSpec, Limit, Order, ParsedQuery, SrcVar, Variable, WhereClause};
|
use edn::query::{Element, FindSpec, Limit, Order, ParsedQuery, SrcVar, Variable, WhereClause};
|
||||||
|
|
||||||
use query_algebrizer_traits::errors::{AlgebrizerError, Result};
|
use query_algebrizer_traits::errors::{AlgebrizerErrorKind, Result};
|
||||||
|
|
||||||
pub use clauses::{QueryInputs, VariableBindings};
|
pub use clauses::{QueryInputs, VariableBindings};
|
||||||
|
|
||||||
|
@ -229,7 +229,7 @@ fn validate_and_simplify_order(
|
||||||
|
|
||||||
// Fail if the var isn't bound by the query.
|
// Fail if the var isn't bound by the query.
|
||||||
if !cc.column_bindings.contains_key(&var) {
|
if !cc.column_bindings.contains_key(&var) {
|
||||||
bail!(AlgebrizerError::UnboundVariable(var.name()))
|
bail!(AlgebrizerErrorKind::UnboundVariable(var.name()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, determine if we also need to order by type…
|
// Otherwise, determine if we also need to order by type…
|
||||||
|
@ -263,7 +263,7 @@ fn simplify_limit(mut query: AlgebraicQuery) -> Result<AlgebraicQuery> {
|
||||||
Some(TypedValue::Long(n)) => {
|
Some(TypedValue::Long(n)) => {
|
||||||
if n <= 0 {
|
if n <= 0 {
|
||||||
// User-specified limits should always be natural numbers (> 0).
|
// User-specified limits should always be natural numbers (> 0).
|
||||||
bail!(AlgebrizerError::InvalidLimit(
|
bail!(AlgebrizerErrorKind::InvalidLimit(
|
||||||
n.to_string(),
|
n.to_string(),
|
||||||
ValueType::Long
|
ValueType::Long
|
||||||
))
|
))
|
||||||
|
@ -273,7 +273,7 @@ fn simplify_limit(mut query: AlgebraicQuery) -> Result<AlgebraicQuery> {
|
||||||
}
|
}
|
||||||
Some(val) => {
|
Some(val) => {
|
||||||
// Same.
|
// Same.
|
||||||
bail!(AlgebrizerError::InvalidLimit(
|
bail!(AlgebrizerErrorKind::InvalidLimit(
|
||||||
format!("{:?}", val),
|
format!("{:?}", val),
|
||||||
val.value_type()
|
val.value_type()
|
||||||
))
|
))
|
||||||
|
@ -375,7 +375,7 @@ impl FindQuery {
|
||||||
|
|
||||||
for var in parsed.in_vars.into_iter() {
|
for var in parsed.in_vars.into_iter() {
|
||||||
if !set.insert(var.clone()) {
|
if !set.insert(var.clone()) {
|
||||||
bail!(AlgebrizerError::DuplicateVariableError(var.name(), ":in"));
|
bail!(AlgebrizerErrorKind::DuplicateVariableError(var.name(), ":in"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -387,7 +387,7 @@ impl FindQuery {
|
||||||
|
|
||||||
for var in parsed.with.into_iter() {
|
for var in parsed.with.into_iter() {
|
||||||
if !set.insert(var.clone()) {
|
if !set.insert(var.clone()) {
|
||||||
bail!(AlgebrizerError::DuplicateVariableError(var.name(), ":with"));
|
bail!(AlgebrizerErrorKind::DuplicateVariableError(var.name(), ":with"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -397,7 +397,7 @@ impl FindQuery {
|
||||||
// Make sure that if we have `:limit ?x`, `?x` appears in `:in`.
|
// Make sure that if we have `:limit ?x`, `?x` appears in `:in`.
|
||||||
if let Limit::Variable(ref v) = parsed.limit {
|
if let Limit::Variable(ref v) = parsed.limit {
|
||||||
if !in_vars.contains(v) {
|
if !in_vars.contains(v) {
|
||||||
bail!(AlgebrizerError::UnknownLimitVar(v.name()));
|
bail!(AlgebrizerErrorKind::UnknownLimitVar(v.name()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ use std::collections::BTreeSet;
|
||||||
|
|
||||||
use edn::query::{ContainsVariables, NotJoin, OrJoin, UnifyVars, Variable};
|
use edn::query::{ContainsVariables, NotJoin, OrJoin, UnifyVars, Variable};
|
||||||
|
|
||||||
use query_algebrizer_traits::errors::{AlgebrizerError, Result};
|
use query_algebrizer_traits::errors::{AlgebrizerErrorKind, Result};
|
||||||
|
|
||||||
/// In an `or` expression, every mentioned var is considered 'free'.
|
/// In an `or` expression, every mentioned var is considered 'free'.
|
||||||
/// In an `or-join` expression, every var in the var list is 'required'.
|
/// In an `or-join` expression, every var in the var list is 'required'.
|
||||||
|
@ -47,7 +47,7 @@ pub(crate) fn validate_or_join(or_join: &OrJoin) -> Result<()> {
|
||||||
let template = clauses.next().unwrap().collect_mentioned_variables();
|
let template = clauses.next().unwrap().collect_mentioned_variables();
|
||||||
for clause in clauses {
|
for clause in clauses {
|
||||||
if template != clause.collect_mentioned_variables() {
|
if template != clause.collect_mentioned_variables() {
|
||||||
bail!(AlgebrizerError::NonMatchingVariablesInOrClause)
|
bail!(AlgebrizerErrorKind::NonMatchingVariablesInOrClause)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -58,7 +58,7 @@ pub(crate) fn validate_or_join(or_join: &OrJoin) -> Result<()> {
|
||||||
let var_set: BTreeSet<Variable> = vars.iter().cloned().collect();
|
let var_set: BTreeSet<Variable> = vars.iter().cloned().collect();
|
||||||
for clause in &or_join.clauses {
|
for clause in &or_join.clauses {
|
||||||
if !var_set.is_subset(&clause.collect_mentioned_variables()) {
|
if !var_set.is_subset(&clause.collect_mentioned_variables()) {
|
||||||
bail!(AlgebrizerError::NonMatchingVariablesInOrClause)
|
bail!(AlgebrizerErrorKind::NonMatchingVariablesInOrClause)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -74,7 +74,7 @@ pub(crate) fn validate_not_join(not_join: &NotJoin) -> Result<()> {
|
||||||
// The joined vars must each appear somewhere in the clause's mentioned variables.
|
// The joined vars must each appear somewhere in the clause's mentioned variables.
|
||||||
let var_set: BTreeSet<Variable> = vars.iter().cloned().collect();
|
let var_set: BTreeSet<Variable> = vars.iter().cloned().collect();
|
||||||
if !var_set.is_subset(¬_join.collect_mentioned_variables()) {
|
if !var_set.is_subset(¬_join.collect_mentioned_variables()) {
|
||||||
bail!(AlgebrizerError::NonMatchingVariablesInNotClause)
|
bail!(AlgebrizerErrorKind::NonMatchingVariablesInNotClause)
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ use mentat_core::Schema;
|
||||||
|
|
||||||
use edn::query::{Keyword, PlainSymbol, Variable};
|
use edn::query::{Keyword, PlainSymbol, Variable};
|
||||||
|
|
||||||
use query_algebrizer_traits::errors::{AlgebrizerError, BindingError};
|
use query_algebrizer_traits::errors::{AlgebrizerErrorKind, BindingError};
|
||||||
|
|
||||||
use mentat_query_algebrizer::{ComputedTable, Known, QueryInputs};
|
use mentat_query_algebrizer::{ComputedTable, Known, QueryInputs};
|
||||||
|
|
||||||
|
@ -297,7 +297,7 @@ fn test_ground_coll_heterogeneous_types() {
|
||||||
let q = r#"[:find ?x :where [?x _ ?v] [(ground [false 8.5]) [?v ...]]]"#;
|
let q = r#"[:find ?x :where [?x _ ?v] [(ground [false 8.5]) [?v ...]]]"#;
|
||||||
let schema = prepopulated_schema();
|
let schema = prepopulated_schema();
|
||||||
let known = Known::for_schema(&schema);
|
let known = Known::for_schema(&schema);
|
||||||
assert_eq!(bails(known, &q), AlgebrizerError::InvalidGroundConstant);
|
assert_eq!(bails(known, &q), AlgebrizerErrorKind::InvalidGroundConstant);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -305,7 +305,7 @@ fn test_ground_rel_heterogeneous_types() {
|
||||||
let q = r#"[:find ?x :where [?x _ ?v] [(ground [[false] [5]]) [[?v]]]]"#;
|
let q = r#"[:find ?x :where [?x _ ?v] [(ground [[false] [5]]) [[?v]]]]"#;
|
||||||
let schema = prepopulated_schema();
|
let schema = prepopulated_schema();
|
||||||
let known = Known::for_schema(&schema);
|
let known = Known::for_schema(&schema);
|
||||||
assert_eq!(bails(known, &q), AlgebrizerError::InvalidGroundConstant);
|
assert_eq!(bails(known, &q), AlgebrizerErrorKind::InvalidGroundConstant);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -315,7 +315,7 @@ fn test_ground_tuple_duplicate_vars() {
|
||||||
let known = Known::for_schema(&schema);
|
let known = Known::for_schema(&schema);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bails(known, &q),
|
bails(known, &q),
|
||||||
AlgebrizerError::InvalidBinding(
|
AlgebrizerErrorKind::InvalidBinding(
|
||||||
PlainSymbol::plain("ground"),
|
PlainSymbol::plain("ground"),
|
||||||
BindingError::RepeatedBoundVariable
|
BindingError::RepeatedBoundVariable
|
||||||
)
|
)
|
||||||
|
@ -329,7 +329,7 @@ fn test_ground_rel_duplicate_vars() {
|
||||||
let known = Known::for_schema(&schema);
|
let known = Known::for_schema(&schema);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bails(known, &q),
|
bails(known, &q),
|
||||||
AlgebrizerError::InvalidBinding(
|
AlgebrizerErrorKind::InvalidBinding(
|
||||||
PlainSymbol::plain("ground"),
|
PlainSymbol::plain("ground"),
|
||||||
BindingError::RepeatedBoundVariable
|
BindingError::RepeatedBoundVariable
|
||||||
)
|
)
|
||||||
|
@ -343,7 +343,7 @@ fn test_ground_nonexistent_variable_invalid() {
|
||||||
let known = Known::for_schema(&schema);
|
let known = Known::for_schema(&schema);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bails(known, &q),
|
bails(known, &q),
|
||||||
AlgebrizerError::UnboundVariable(PlainSymbol::plain("?v"))
|
AlgebrizerErrorKind::UnboundVariable(PlainSymbol::plain("?v"))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -362,6 +362,6 @@ fn test_unbound_input_variable_invalid() {
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bails_with_inputs(known, &q, i),
|
bails_with_inputs(known, &q, i),
|
||||||
AlgebrizerError::UnboundVariable(PlainSymbol::plain("?x"))
|
AlgebrizerErrorKind::UnboundVariable(PlainSymbol::plain("?x"))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ use mentat_core::{DateTime, Schema, Utc};
|
||||||
|
|
||||||
use edn::query::{Keyword, PlainSymbol, Variable};
|
use edn::query::{Keyword, PlainSymbol, Variable};
|
||||||
|
|
||||||
use query_algebrizer_traits::errors::AlgebrizerError;
|
use query_algebrizer_traits::errors::AlgebrizerErrorKind;
|
||||||
|
|
||||||
use mentat_query_algebrizer::{EmptyBecause, Known, QueryInputs};
|
use mentat_query_algebrizer::{EmptyBecause, Known, QueryInputs};
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ fn test_instant_predicates_require_instants() {
|
||||||
[(> ?t "2017-06-16T00:56:41.257Z")]]"#;
|
[(> ?t "2017-06-16T00:56:41.257Z")]]"#;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bails(known, query),
|
bails(known, query),
|
||||||
AlgebrizerError::InvalidArgumentType(
|
AlgebrizerErrorKind::InvalidArgumentType(
|
||||||
PlainSymbol::plain(">"),
|
PlainSymbol::plain(">"),
|
||||||
ValueTypeSet::of_numeric_and_instant_types(),
|
ValueTypeSet::of_numeric_and_instant_types(),
|
||||||
1
|
1
|
||||||
|
@ -88,7 +88,7 @@ fn test_instant_predicates_require_instants() {
|
||||||
[(> "2017-06-16T00:56:41.257Z", ?t)]]"#;
|
[(> "2017-06-16T00:56:41.257Z", ?t)]]"#;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bails(known, query),
|
bails(known, query),
|
||||||
AlgebrizerError::InvalidArgumentType(
|
AlgebrizerErrorKind::InvalidArgumentType(
|
||||||
PlainSymbol::plain(">"),
|
PlainSymbol::plain(">"),
|
||||||
ValueTypeSet::of_numeric_and_instant_types(),
|
ValueTypeSet::of_numeric_and_instant_types(),
|
||||||
0
|
0
|
||||||
|
|
|
@ -16,7 +16,7 @@ use mentat_query_algebrizer::{ColumnName, ConjoiningClauses, VariableColumn};
|
||||||
|
|
||||||
use mentat_query_sql::{ColumnOrExpression, Expression, Name, ProjectedColumn};
|
use mentat_query_sql::{ColumnOrExpression, Expression, Name, ProjectedColumn};
|
||||||
|
|
||||||
use errors::{ProjectorError, Result};
|
use errors::{ProjectorErrorKind, Result};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
pub enum SimpleAggregationOp {
|
pub enum SimpleAggregationOp {
|
||||||
|
@ -60,7 +60,7 @@ impl SimpleAggregationOp {
|
||||||
pub fn is_applicable_to_types(&self, possibilities: ValueTypeSet) -> Result<ValueType> {
|
pub fn is_applicable_to_types(&self, possibilities: ValueTypeSet) -> Result<ValueType> {
|
||||||
use self::SimpleAggregationOp::*;
|
use self::SimpleAggregationOp::*;
|
||||||
if possibilities.is_empty() {
|
if possibilities.is_empty() {
|
||||||
bail!(ProjectorError::CannotProjectImpossibleBinding(*self))
|
bail!(ProjectorErrorKind::CannotProjectImpossibleBinding(*self))
|
||||||
}
|
}
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
|
@ -73,7 +73,7 @@ impl SimpleAggregationOp {
|
||||||
// The mean of a set of numeric values will always, for our purposes, be a double.
|
// The mean of a set of numeric values will always, for our purposes, be a double.
|
||||||
Ok(ValueType::Double)
|
Ok(ValueType::Double)
|
||||||
} else {
|
} else {
|
||||||
bail!(ProjectorError::CannotApplyAggregateOperationToTypes(
|
bail!(ProjectorErrorKind::CannotApplyAggregateOperationToTypes(
|
||||||
*self,
|
*self,
|
||||||
possibilities
|
possibilities
|
||||||
))
|
))
|
||||||
|
@ -88,7 +88,7 @@ impl SimpleAggregationOp {
|
||||||
Ok(ValueType::Long)
|
Ok(ValueType::Long)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bail!(ProjectorError::CannotApplyAggregateOperationToTypes(
|
bail!(ProjectorErrorKind::CannotApplyAggregateOperationToTypes(
|
||||||
*self,
|
*self,
|
||||||
possibilities
|
possibilities
|
||||||
))
|
))
|
||||||
|
@ -111,7 +111,7 @@ impl SimpleAggregationOp {
|
||||||
|
|
||||||
// These types are unordered.
|
// These types are unordered.
|
||||||
Keyword | Ref | Uuid => {
|
Keyword | Ref | Uuid => {
|
||||||
bail!(ProjectorError::CannotApplyAggregateOperationToTypes(
|
bail!(ProjectorErrorKind::CannotApplyAggregateOperationToTypes(
|
||||||
*self,
|
*self,
|
||||||
possibilities
|
possibilities
|
||||||
))
|
))
|
||||||
|
@ -129,7 +129,7 @@ impl SimpleAggregationOp {
|
||||||
Ok(ValueType::Long)
|
Ok(ValueType::Long)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bail!(ProjectorError::CannotApplyAggregateOperationToTypes(
|
bail!(ProjectorErrorKind::CannotApplyAggregateOperationToTypes(
|
||||||
*self,
|
*self,
|
||||||
possibilities
|
possibilities
|
||||||
))
|
))
|
||||||
|
|
|
@ -15,14 +15,60 @@ use rusqlite;
|
||||||
use core_traits::ValueTypeSet;
|
use core_traits::ValueTypeSet;
|
||||||
use db_traits::errors::DbError;
|
use db_traits::errors::DbError;
|
||||||
use edn::query::PlainSymbol;
|
use edn::query::PlainSymbol;
|
||||||
|
use failure::{ Backtrace, Context, Fail, };
|
||||||
|
use std::fmt;
|
||||||
use query_pull_traits::errors::PullError;
|
use query_pull_traits::errors::PullError;
|
||||||
|
|
||||||
use aggregates::SimpleAggregationOp;
|
use aggregates::SimpleAggregationOp;
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, ProjectorError>;
|
pub type Result<T> = std::result::Result<T, ProjectorError>;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ProjectorError(Box<Context<ProjectorErrorKind>>);
|
||||||
|
|
||||||
|
impl Fail for ProjectorError {
|
||||||
|
#[inline]
|
||||||
|
fn cause(&self) -> Option<&Fail> {
|
||||||
|
self.0.cause()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn backtrace(&self) -> Option<&Backtrace> {
|
||||||
|
self.0.backtrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ProjectorError {
|
||||||
|
#[inline]
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
fmt::Display::fmt(&*self.0, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProjectorError {
|
||||||
|
#[inline]
|
||||||
|
pub fn kind(&self) -> &ProjectorErrorKind {
|
||||||
|
&*self.0.get_context()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ProjectorErrorKind> for ProjectorError {
|
||||||
|
#[inline]
|
||||||
|
fn from(kind: ProjectorErrorKind) -> ProjectorError {
|
||||||
|
ProjectorError(Box::new(Context::new(kind)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Context<ProjectorErrorKind>> for ProjectorError {
|
||||||
|
#[inline]
|
||||||
|
fn from(inner: Context<ProjectorErrorKind>) -> ProjectorError {
|
||||||
|
ProjectorError(Box::new(inner))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Fail)]
|
#[derive(Debug, Fail)]
|
||||||
pub enum ProjectorError {
|
pub enum ProjectorErrorKind {
|
||||||
/// We're just not done yet. Message that the feature is recognized but not yet
|
/// We're just not done yet. Message that the feature is recognized but not yet
|
||||||
/// implemented.
|
/// implemented.
|
||||||
#[fail(display = "not yet implemented: {}", _0)]
|
#[fail(display = "not yet implemented: {}", _0)]
|
||||||
|
@ -70,6 +116,24 @@ pub enum ProjectorError {
|
||||||
PullError(#[cause] PullError),
|
PullError(#[cause] PullError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<rusqlite::Error> for ProjectorErrorKind {
|
||||||
|
fn from(error: rusqlite::Error) -> ProjectorErrorKind {
|
||||||
|
ProjectorErrorKind::from(error).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<mentat_db::DbError> for ProjectorErrorKind {
|
||||||
|
fn from(error: mentat_db::DbError) -> ProjectorErrorKind {
|
||||||
|
ProjectorErrorKind::from(error).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<mentat_query_pull::PullError> for ProjectorErrorKind {
|
||||||
|
fn from(error: mentat_query_pull::PullError) -> ProjectorErrorKind {
|
||||||
|
ProjectorErrorKind::from(error).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<rusqlite::Error> for ProjectorError {
|
impl From<rusqlite::Error> for ProjectorError {
|
||||||
fn from(error: rusqlite::Error) -> ProjectorError {
|
fn from(error: rusqlite::Error) -> ProjectorError {
|
||||||
ProjectorError::RusqliteError(error.to_string())
|
ProjectorError::RusqliteError(error.to_string())
|
||||||
|
|
|
@ -101,9 +101,9 @@ fn test_the_without_max_or_min() {
|
||||||
// … when we look at the projection list, we cannot reconcile the types.
|
// … when we look at the projection list, we cannot reconcile the types.
|
||||||
let projection = query_projection(&schema, &algebrized);
|
let projection = query_projection(&schema, &algebrized);
|
||||||
assert!(projection.is_err());
|
assert!(projection.is_err());
|
||||||
use query_projector_traits::errors::ProjectorError;
|
use query_projector_traits::errors::ProjectorErrorKind;
|
||||||
match projection.err().expect("expected failure") {
|
match projection.err().expect("expected failure") {
|
||||||
ProjectorError::InvalidProjection(s) => {
|
ProjectorErrorKind::InvalidProjection(s) => {
|
||||||
assert_eq!(s.as_str(), "Warning: used `the` without `min` or `max`.");
|
assert_eq!(s.as_str(), "Warning: used `the` without `min` or `max`.");
|
||||||
}
|
}
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
use core_traits::Binding;
|
use core_traits::Binding;
|
||||||
|
|
||||||
use query_projector_traits::errors::{ProjectorError, Result};
|
use query_projector_traits::errors::{ProjectorErrorKind, Result};
|
||||||
|
|
||||||
/// A `BindingTuple` is any type that can accommodate a Mentat tuple query result of fixed length.
|
/// A `BindingTuple` is any type that can accommodate a Mentat tuple query result of fixed length.
|
||||||
///
|
///
|
||||||
|
@ -27,7 +27,7 @@ impl BindingTuple for Vec<Binding> {
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
Some(vec) => {
|
Some(vec) => {
|
||||||
if expected != vec.len() {
|
if expected != vec.len() {
|
||||||
Err(ProjectorError::UnexpectedResultsTupleLength(
|
Err(ProjectorErrorKind::UnexpectedResultsTupleLength(
|
||||||
expected,
|
expected,
|
||||||
vec.len(),
|
vec.len(),
|
||||||
))
|
))
|
||||||
|
@ -43,13 +43,13 @@ impl BindingTuple for Vec<Binding> {
|
||||||
impl BindingTuple for (Binding,) {
|
impl BindingTuple for (Binding,) {
|
||||||
fn from_binding_vec(expected: usize, vec: Option<Vec<Binding>>) -> Result<Option<Self>> {
|
fn from_binding_vec(expected: usize, vec: Option<Vec<Binding>>) -> Result<Option<Self>> {
|
||||||
if expected != 1 {
|
if expected != 1 {
|
||||||
return Err(ProjectorError::UnexpectedResultsTupleLength(1, expected));
|
return Err(ProjectorErrorKind::UnexpectedResultsTupleLength(1, expected));
|
||||||
}
|
}
|
||||||
match vec {
|
match vec {
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
Some(vec) => {
|
Some(vec) => {
|
||||||
if expected != vec.len() {
|
if expected != vec.len() {
|
||||||
Err(ProjectorError::UnexpectedResultsTupleLength(
|
Err(ProjectorErrorKind::UnexpectedResultsTupleLength(
|
||||||
expected,
|
expected,
|
||||||
vec.len(),
|
vec.len(),
|
||||||
))
|
))
|
||||||
|
@ -65,13 +65,13 @@ impl BindingTuple for (Binding,) {
|
||||||
impl BindingTuple for (Binding, Binding) {
|
impl BindingTuple for (Binding, Binding) {
|
||||||
fn from_binding_vec(expected: usize, vec: Option<Vec<Binding>>) -> Result<Option<Self>> {
|
fn from_binding_vec(expected: usize, vec: Option<Vec<Binding>>) -> Result<Option<Self>> {
|
||||||
if expected != 2 {
|
if expected != 2 {
|
||||||
return Err(ProjectorError::UnexpectedResultsTupleLength(2, expected));
|
return Err(ProjectorErrorKind::UnexpectedResultsTupleLength(2, expected));
|
||||||
}
|
}
|
||||||
match vec {
|
match vec {
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
Some(vec) => {
|
Some(vec) => {
|
||||||
if expected != vec.len() {
|
if expected != vec.len() {
|
||||||
Err(ProjectorError::UnexpectedResultsTupleLength(
|
Err(ProjectorErrorKind::UnexpectedResultsTupleLength(
|
||||||
expected,
|
expected,
|
||||||
vec.len(),
|
vec.len(),
|
||||||
))
|
))
|
||||||
|
@ -87,13 +87,13 @@ impl BindingTuple for (Binding, Binding) {
|
||||||
impl BindingTuple for (Binding, Binding, Binding) {
|
impl BindingTuple for (Binding, Binding, Binding) {
|
||||||
fn from_binding_vec(expected: usize, vec: Option<Vec<Binding>>) -> Result<Option<Self>> {
|
fn from_binding_vec(expected: usize, vec: Option<Vec<Binding>>) -> Result<Option<Self>> {
|
||||||
if expected != 3 {
|
if expected != 3 {
|
||||||
return Err(ProjectorError::UnexpectedResultsTupleLength(3, expected));
|
return Err(ProjectorErrorKind::UnexpectedResultsTupleLength(3, expected));
|
||||||
}
|
}
|
||||||
match vec {
|
match vec {
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
Some(vec) => {
|
Some(vec) => {
|
||||||
if expected != vec.len() {
|
if expected != vec.len() {
|
||||||
Err(ProjectorError::UnexpectedResultsTupleLength(
|
Err(ProjectorErrorKind::UnexpectedResultsTupleLength(
|
||||||
expected,
|
expected,
|
||||||
vec.len(),
|
vec.len(),
|
||||||
))
|
))
|
||||||
|
@ -113,13 +113,13 @@ impl BindingTuple for (Binding, Binding, Binding) {
|
||||||
impl BindingTuple for (Binding, Binding, Binding, Binding) {
|
impl BindingTuple for (Binding, Binding, Binding, Binding) {
|
||||||
fn from_binding_vec(expected: usize, vec: Option<Vec<Binding>>) -> Result<Option<Self>> {
|
fn from_binding_vec(expected: usize, vec: Option<Vec<Binding>>) -> Result<Option<Self>> {
|
||||||
if expected != 4 {
|
if expected != 4 {
|
||||||
return Err(ProjectorError::UnexpectedResultsTupleLength(4, expected));
|
return Err(ProjectorErrorKind::UnexpectedResultsTupleLength(4, expected));
|
||||||
}
|
}
|
||||||
match vec {
|
match vec {
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
Some(vec) => {
|
Some(vec) => {
|
||||||
if expected != vec.len() {
|
if expected != vec.len() {
|
||||||
Err(ProjectorError::UnexpectedResultsTupleLength(
|
Err(ProjectorErrorKind::UnexpectedResultsTupleLength(
|
||||||
expected,
|
expected,
|
||||||
vec.len(),
|
vec.len(),
|
||||||
))
|
))
|
||||||
|
@ -140,13 +140,13 @@ impl BindingTuple for (Binding, Binding, Binding, Binding) {
|
||||||
impl BindingTuple for (Binding, Binding, Binding, Binding, Binding) {
|
impl BindingTuple for (Binding, Binding, Binding, Binding, Binding) {
|
||||||
fn from_binding_vec(expected: usize, vec: Option<Vec<Binding>>) -> Result<Option<Self>> {
|
fn from_binding_vec(expected: usize, vec: Option<Vec<Binding>>) -> Result<Option<Self>> {
|
||||||
if expected != 5 {
|
if expected != 5 {
|
||||||
return Err(ProjectorError::UnexpectedResultsTupleLength(5, expected));
|
return Err(ProjectorErrorKind::UnexpectedResultsTupleLength(5, expected));
|
||||||
}
|
}
|
||||||
match vec {
|
match vec {
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
Some(vec) => {
|
Some(vec) => {
|
||||||
if expected != vec.len() {
|
if expected != vec.len() {
|
||||||
Err(ProjectorError::UnexpectedResultsTupleLength(
|
Err(ProjectorErrorKind::UnexpectedResultsTupleLength(
|
||||||
expected,
|
expected,
|
||||||
vec.len(),
|
vec.len(),
|
||||||
))
|
))
|
||||||
|
@ -170,13 +170,13 @@ impl BindingTuple for (Binding, Binding, Binding, Binding, Binding) {
|
||||||
impl BindingTuple for (Binding, Binding, Binding, Binding, Binding, Binding) {
|
impl BindingTuple for (Binding, Binding, Binding, Binding, Binding, Binding) {
|
||||||
fn from_binding_vec(expected: usize, vec: Option<Vec<Binding>>) -> Result<Option<Self>> {
|
fn from_binding_vec(expected: usize, vec: Option<Vec<Binding>>) -> Result<Option<Self>> {
|
||||||
if expected != 6 {
|
if expected != 6 {
|
||||||
return Err(ProjectorError::UnexpectedResultsTupleLength(6, expected));
|
return Err(ProjectorErrorKind::UnexpectedResultsTupleLength(6, expected));
|
||||||
}
|
}
|
||||||
match vec {
|
match vec {
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
Some(vec) => {
|
Some(vec) => {
|
||||||
if expected != vec.len() {
|
if expected != vec.len() {
|
||||||
Err(ProjectorError::UnexpectedResultsTupleLength(
|
Err(ProjectorErrorKind::UnexpectedResultsTupleLength(
|
||||||
expected,
|
expected,
|
||||||
vec.len(),
|
vec.len(),
|
||||||
))
|
))
|
||||||
|
|
|
@ -69,7 +69,7 @@ use projectors::{
|
||||||
|
|
||||||
pub use relresult::{RelResult, StructuredRelResult};
|
pub use relresult::{RelResult, StructuredRelResult};
|
||||||
|
|
||||||
use query_projector_traits::errors::{ProjectorError, Result};
|
use query_projector_traits::errors::{ProjectorErrorKind, Result};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct QueryOutput {
|
pub struct QueryOutput {
|
||||||
|
@ -275,43 +275,43 @@ impl QueryResults {
|
||||||
pub fn into_scalar(self) -> Result<Option<Binding>> {
|
pub fn into_scalar(self) -> Result<Option<Binding>> {
|
||||||
match self {
|
match self {
|
||||||
QueryResults::Scalar(o) => Ok(o),
|
QueryResults::Scalar(o) => Ok(o),
|
||||||
QueryResults::Coll(_) => bail!(ProjectorError::UnexpectedResultsType("coll", "scalar")),
|
QueryResults::Coll(_) => bail!(ProjectorErrorKind::UnexpectedResultsType("coll", "scalar")),
|
||||||
QueryResults::Tuple(_) => {
|
QueryResults::Tuple(_) => {
|
||||||
bail!(ProjectorError::UnexpectedResultsType("tuple", "scalar"))
|
bail!(ProjectorErrorKind::UnexpectedResultsType("tuple", "scalar"))
|
||||||
}
|
}
|
||||||
QueryResults::Rel(_) => bail!(ProjectorError::UnexpectedResultsType("rel", "scalar")),
|
QueryResults::Rel(_) => bail!(ProjectorErrorKind::UnexpectedResultsType("rel", "scalar")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_coll(self) -> Result<Vec<Binding>> {
|
pub fn into_coll(self) -> Result<Vec<Binding>> {
|
||||||
match self {
|
match self {
|
||||||
QueryResults::Scalar(_) => {
|
QueryResults::Scalar(_) => {
|
||||||
bail!(ProjectorError::UnexpectedResultsType("scalar", "coll"))
|
bail!(ProjectorErrorKind::UnexpectedResultsType("scalar", "coll"))
|
||||||
}
|
}
|
||||||
QueryResults::Coll(c) => Ok(c),
|
QueryResults::Coll(c) => Ok(c),
|
||||||
QueryResults::Tuple(_) => bail!(ProjectorError::UnexpectedResultsType("tuple", "coll")),
|
QueryResults::Tuple(_) => bail!(ProjectorErrorKind::UnexpectedResultsType("tuple", "coll")),
|
||||||
QueryResults::Rel(_) => bail!(ProjectorError::UnexpectedResultsType("rel", "coll")),
|
QueryResults::Rel(_) => bail!(ProjectorErrorKind::UnexpectedResultsType("rel", "coll")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_tuple(self) -> Result<Option<Vec<Binding>>> {
|
pub fn into_tuple(self) -> Result<Option<Vec<Binding>>> {
|
||||||
match self {
|
match self {
|
||||||
QueryResults::Scalar(_) => {
|
QueryResults::Scalar(_) => {
|
||||||
bail!(ProjectorError::UnexpectedResultsType("scalar", "tuple"))
|
bail!(ProjectorErrorKind::UnexpectedResultsType("scalar", "tuple"))
|
||||||
}
|
}
|
||||||
QueryResults::Coll(_) => bail!(ProjectorError::UnexpectedResultsType("coll", "tuple")),
|
QueryResults::Coll(_) => bail!(ProjectorErrorKind::UnexpectedResultsType("coll", "tuple")),
|
||||||
QueryResults::Tuple(t) => Ok(t),
|
QueryResults::Tuple(t) => Ok(t),
|
||||||
QueryResults::Rel(_) => bail!(ProjectorError::UnexpectedResultsType("rel", "tuple")),
|
QueryResults::Rel(_) => bail!(ProjectorErrorKind::UnexpectedResultsType("rel", "tuple")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_rel(self) -> Result<RelResult<Binding>> {
|
pub fn into_rel(self) -> Result<RelResult<Binding>> {
|
||||||
match self {
|
match self {
|
||||||
QueryResults::Scalar(_) => {
|
QueryResults::Scalar(_) => {
|
||||||
bail!(ProjectorError::UnexpectedResultsType("scalar", "rel"))
|
bail!(ProjectorErrorKind::UnexpectedResultsType("scalar", "rel"))
|
||||||
}
|
}
|
||||||
QueryResults::Coll(_) => bail!(ProjectorError::UnexpectedResultsType("coll", "rel")),
|
QueryResults::Coll(_) => bail!(ProjectorErrorKind::UnexpectedResultsType("coll", "rel")),
|
||||||
QueryResults::Tuple(_) => bail!(ProjectorError::UnexpectedResultsType("tuple", "rel")),
|
QueryResults::Tuple(_) => bail!(ProjectorErrorKind::UnexpectedResultsType("tuple", "rel")),
|
||||||
QueryResults::Rel(r) => Ok(r),
|
QueryResults::Rel(r) => Ok(r),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -526,7 +526,7 @@ fn test_into_tuple() {
|
||||||
);
|
);
|
||||||
|
|
||||||
match query_output.clone().into_tuple() {
|
match query_output.clone().into_tuple() {
|
||||||
Err(ProjectorError::UnexpectedResultsTupleLength(expected, got)) => {
|
Err(ProjectorErrorKind::UnexpectedResultsTupleLength(expected, got)) => {
|
||||||
assert_eq!((expected, got), (3, 2));
|
assert_eq!((expected, got), (3, 2));
|
||||||
}
|
}
|
||||||
// This forces the result type.
|
// This forces the result type.
|
||||||
|
@ -548,7 +548,7 @@ fn test_into_tuple() {
|
||||||
}
|
}
|
||||||
|
|
||||||
match query_output.clone().into_tuple() {
|
match query_output.clone().into_tuple() {
|
||||||
Err(ProjectorError::UnexpectedResultsTupleLength(expected, got)) => {
|
Err(ProjectorErrorKind::UnexpectedResultsTupleLength(expected, got)) => {
|
||||||
assert_eq!((expected, got), (3, 2));
|
assert_eq!((expected, got), (3, 2));
|
||||||
}
|
}
|
||||||
// This forces the result type.
|
// This forces the result type.
|
||||||
|
|
|
@ -30,7 +30,7 @@ use query_projector_traits::aggregates::{
|
||||||
projected_column_for_simple_aggregate, SimpleAggregation,
|
projected_column_for_simple_aggregate, SimpleAggregation,
|
||||||
};
|
};
|
||||||
|
|
||||||
use query_projector_traits::errors::{ProjectorError, Result};
|
use query_projector_traits::errors::{ProjectorErrorKind, Result};
|
||||||
|
|
||||||
use projectors::Projector;
|
use projectors::Projector;
|
||||||
|
|
||||||
|
@ -98,14 +98,14 @@ fn candidate_type_column(
|
||||||
let type_name = VariableColumn::VariableTypeTag(var.clone()).column_name();
|
let type_name = VariableColumn::VariableTypeTag(var.clone()).column_name();
|
||||||
(ColumnOrExpression::Column(alias), type_name)
|
(ColumnOrExpression::Column(alias), type_name)
|
||||||
})
|
})
|
||||||
.ok_or_else(|| ProjectorError::UnboundVariable(var.name()).into())
|
.ok_or_else(|| ProjectorErrorKind::UnboundVariable(var.name()).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cc_column(cc: &ConjoiningClauses, var: &Variable) -> Result<QualifiedAlias> {
|
fn cc_column(cc: &ConjoiningClauses, var: &Variable) -> Result<QualifiedAlias> {
|
||||||
cc.column_bindings
|
cc.column_bindings
|
||||||
.get(var)
|
.get(var)
|
||||||
.and_then(|cols| cols.get(0).cloned())
|
.and_then(|cols| cols.get(0).cloned())
|
||||||
.ok_or_else(|| ProjectorError::UnboundVariable(var.name()).into())
|
.ok_or_else(|| ProjectorErrorKind::UnboundVariable(var.name()).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn candidate_column(cc: &ConjoiningClauses, var: &Variable) -> Result<(ColumnOrExpression, Name)> {
|
fn candidate_column(cc: &ConjoiningClauses, var: &Variable) -> Result<(ColumnOrExpression, Name)> {
|
||||||
|
@ -187,13 +187,13 @@ pub(crate) fn project_elements<'a, I: IntoIterator<Item = &'a Element>>(
|
||||||
match e {
|
match e {
|
||||||
&Element::Variable(ref var) => {
|
&Element::Variable(ref var) => {
|
||||||
if outer_variables.contains(var) {
|
if outer_variables.contains(var) {
|
||||||
bail!(ProjectorError::InvalidProjection(format!(
|
bail!(ProjectorErrorKind::InvalidProjection(format!(
|
||||||
"Duplicate variable {} in query.",
|
"Duplicate variable {} in query.",
|
||||||
var
|
var
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
if corresponded_variables.contains(var) {
|
if corresponded_variables.contains(var) {
|
||||||
bail!(ProjectorError::InvalidProjection(format!(
|
bail!(ProjectorErrorKind::InvalidProjection(format!(
|
||||||
"Can't project both {} and `(the {})` from a query.",
|
"Can't project both {} and `(the {})` from a query.",
|
||||||
var, var
|
var, var
|
||||||
)));
|
)));
|
||||||
|
@ -201,13 +201,13 @@ pub(crate) fn project_elements<'a, I: IntoIterator<Item = &'a Element>>(
|
||||||
}
|
}
|
||||||
&Element::Corresponding(ref var) => {
|
&Element::Corresponding(ref var) => {
|
||||||
if outer_variables.contains(var) {
|
if outer_variables.contains(var) {
|
||||||
bail!(ProjectorError::InvalidProjection(format!(
|
bail!(ProjectorErrorKind::InvalidProjection(format!(
|
||||||
"Can't project both {} and `(the {})` from a query.",
|
"Can't project both {} and `(the {})` from a query.",
|
||||||
var, var
|
var, var
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
if corresponded_variables.contains(var) {
|
if corresponded_variables.contains(var) {
|
||||||
bail!(ProjectorError::InvalidProjection(format!(
|
bail!(ProjectorErrorKind::InvalidProjection(format!(
|
||||||
"`(the {})` appears twice in query.",
|
"`(the {})` appears twice in query.",
|
||||||
var
|
var
|
||||||
)));
|
)));
|
||||||
|
@ -344,7 +344,7 @@ pub(crate) fn project_elements<'a, I: IntoIterator<Item = &'a Element>>(
|
||||||
i += 1;
|
i += 1;
|
||||||
} else {
|
} else {
|
||||||
// TODO: complex aggregates.
|
// TODO: complex aggregates.
|
||||||
bail!(ProjectorError::NotYetImplemented(
|
bail!(ProjectorErrorKind::NotYetImplemented(
|
||||||
"complex aggregates".into()
|
"complex aggregates".into()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -355,7 +355,7 @@ pub(crate) fn project_elements<'a, I: IntoIterator<Item = &'a Element>>(
|
||||||
match (min_max_count, corresponded_variables.len()) {
|
match (min_max_count, corresponded_variables.len()) {
|
||||||
(0, 0) | (_, 0) => {}
|
(0, 0) | (_, 0) => {}
|
||||||
(0, _) => {
|
(0, _) => {
|
||||||
bail!(ProjectorError::InvalidProjection(
|
bail!(ProjectorErrorKind::InvalidProjection(
|
||||||
"Warning: used `the` without `min` or `max`.".to_string()
|
"Warning: used `the` without `min` or `max`.".to_string()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -363,7 +363,7 @@ pub(crate) fn project_elements<'a, I: IntoIterator<Item = &'a Element>>(
|
||||||
// This is the success case!
|
// This is the success case!
|
||||||
}
|
}
|
||||||
(n, c) => {
|
(n, c) => {
|
||||||
bail!(ProjectorError::AmbiguousAggregates(n, c));
|
bail!(ProjectorErrorKind::AmbiguousAggregates(n, c));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -466,7 +466,7 @@ pub(crate) fn project_elements<'a, I: IntoIterator<Item = &'a Element>>(
|
||||||
let type_name = VariableColumn::VariableTypeTag(var.clone()).column_name();
|
let type_name = VariableColumn::VariableTypeTag(var.clone()).column_name();
|
||||||
if !already_inner {
|
if !already_inner {
|
||||||
let type_col = query.cc.extracted_types.get(&var).cloned().ok_or_else(|| {
|
let type_col = query.cc.extracted_types.get(&var).cloned().ok_or_else(|| {
|
||||||
ProjectorError::NoTypeAvailableForVariable(var.name().clone())
|
ProjectorErrorKind::NoTypeAvailableForVariable(var.name().clone())
|
||||||
})?;
|
})?;
|
||||||
inner_projection.push(ProjectedColumn(
|
inner_projection.push(ProjectedColumn(
|
||||||
ColumnOrExpression::Column(type_col),
|
ColumnOrExpression::Column(type_col),
|
||||||
|
|
|
@ -12,10 +12,50 @@ use std; // To refer to std::result::Result.
|
||||||
|
|
||||||
use db_traits::errors::DbError;
|
use db_traits::errors::DbError;
|
||||||
|
|
||||||
|
use failure::{ Backtrace, Context, Fail, };
|
||||||
|
|
||||||
use core_traits::Entid;
|
use core_traits::Entid;
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, PullError>;
|
pub type Result<T> = std::result::Result<T, PullError>;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PullErrorKind(Box<Context<PullErrorKind>>);
|
||||||
|
|
||||||
|
impl Fail for PullError {
|
||||||
|
#[inline]
|
||||||
|
fn cause(&self) -> Option<&dyn Fail> {
|
||||||
|
self.0.cause()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn backtrace(&self) -> Option<&Backtrace> {
|
||||||
|
self.0.backtrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for PullError {
|
||||||
|
#[inline]
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
fmt::Display::fmt(&*self.0, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PullError {
|
||||||
|
#[inline]
|
||||||
|
pub fn kind(&self) -> &PullErrorKind {
|
||||||
|
&*self.0.get_context()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PullErrorKind> for PullError {
|
||||||
|
#[inline]
|
||||||
|
fn from(kind: PullErrorKind) -> PullError {
|
||||||
|
PullErrorKind(Box::new(Context::new(kind)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Fail)]
|
#[derive(Debug, Fail)]
|
||||||
pub enum PullError {
|
pub enum PullError {
|
||||||
#[fail(display = "attribute {:?} has no name", _0)]
|
#[fail(display = "attribute {:?} has no name", _0)]
|
||||||
|
@ -28,8 +68,13 @@ pub enum PullError {
|
||||||
DbError(#[cause] DbError),
|
DbError(#[cause] DbError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<DbError> for PullErrorKind {
|
||||||
|
fn from(error: DbError) -> PullErrorKind {
|
||||||
|
PullErrorKind::DbError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
impl From<DbError> for PullError {
|
impl From<DbError> for PullError {
|
||||||
fn from(error: DbError) -> PullError {
|
fn from(error: DbError) -> PullError {
|
||||||
PullError::DbError(error)
|
PullErrorKind::from(error).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,6 @@
|
||||||
// specific language governing permissions and limitations under the License.
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
extern crate failure;
|
extern crate failure;
|
||||||
#[macro_use]
|
|
||||||
extern crate failure_derive;
|
|
||||||
|
|
||||||
extern crate core_traits;
|
extern crate core_traits;
|
||||||
extern crate db_traits;
|
extern crate db_traits;
|
||||||
|
|
|
@ -77,7 +77,7 @@ use mentat_db::cache;
|
||||||
|
|
||||||
use edn::query::{NamedPullAttribute, PullAttributeSpec, PullConcreteAttribute};
|
use edn::query::{NamedPullAttribute, PullAttributeSpec, PullConcreteAttribute};
|
||||||
|
|
||||||
use query_pull_traits::errors::{PullError, Result};
|
use query_pull_traits::errors::{PullErrorKind, Result};
|
||||||
|
|
||||||
type PullResults = BTreeMap<Entid, ValueRc<StructuredMap>>;
|
type PullResults = BTreeMap<Entid, ValueRc<StructuredMap>>;
|
||||||
|
|
||||||
|
@ -149,7 +149,7 @@ impl Puller {
|
||||||
schema
|
schema
|
||||||
.get_ident(*i)
|
.get_ident(*i)
|
||||||
.map(|ident| ValueRc::new(ident.clone()))
|
.map(|ident| ValueRc::new(ident.clone()))
|
||||||
.ok_or_else(|| PullError::UnnamedAttribute(*i))
|
.ok_or_else(|| PullErrorKind::UnnamedAttribute(*i))
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut names: BTreeMap<Entid, ValueRc<Keyword>> = Default::default();
|
let mut names: BTreeMap<Entid, ValueRc<Keyword>> = Default::default();
|
||||||
|
@ -177,7 +177,7 @@ impl Puller {
|
||||||
&PullConcreteAttribute::Ident(ref i) if i.as_ref() == db_id.as_ref() => {
|
&PullConcreteAttribute::Ident(ref i) if i.as_ref() == db_id.as_ref() => {
|
||||||
// We only allow :db/id once.
|
// We only allow :db/id once.
|
||||||
if db_id_alias.is_some() {
|
if db_id_alias.is_some() {
|
||||||
Err(PullError::RepeatedDbId)?
|
Err(PullErrorKind::RepeatedDbId)?
|
||||||
}
|
}
|
||||||
db_id_alias = Some(alias.unwrap_or_else(|| db_id.to_value_rc()));
|
db_id_alias = Some(alias.unwrap_or_else(|| db_id.to_value_rc()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,54 @@
|
||||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
// specific language governing permissions and limitations under the License.
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
use failure::{ Backtrace, Context, Fail, };
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct SQLError(Box<Context<SQLErrorKind>>);
|
||||||
|
|
||||||
|
impl Fail for SQLError {
|
||||||
|
#[inline]
|
||||||
|
fn cause(&self) -> Option<&dyn Fail> {
|
||||||
|
self.0.cause()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn backtrace(&self) -> Option<&Backtrace> {
|
||||||
|
self.0.backtrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for SQLError {
|
||||||
|
#[inline]
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
fmt::Display::fmt(&*self.0, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SQLError {
|
||||||
|
#[inline]
|
||||||
|
pub fn kind(&self) -> &SQLErrorKind {
|
||||||
|
&*self.0.get_context()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SQLErrorKind> for SQLError {
|
||||||
|
#[inline]
|
||||||
|
fn from(kind: SQLErrorKind) -> SQLError {
|
||||||
|
SQLError(Box::new(Context::new(kind)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Context<SQLErrorKind>> for SQLError {
|
||||||
|
#[inline]
|
||||||
|
fn from(inner: Context<SQLErrorKind>) -> SQLError {
|
||||||
|
SQLError(Box::new(inner))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Fail)]
|
#[derive(Debug, Fail)]
|
||||||
pub enum SQLError {
|
pub enum SQLErrorKind {
|
||||||
#[fail(display = "invalid parameter name: {}", _0)]
|
#[fail(display = "invalid parameter name: {}", _0)]
|
||||||
InvalidParameterName(String),
|
InvalidParameterName(String),
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,5 @@
|
||||||
// specific language governing permissions and limitations under the License.
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
extern crate failure;
|
extern crate failure;
|
||||||
#[macro_use]
|
|
||||||
extern crate failure_derive;
|
|
||||||
|
|
||||||
pub mod errors;
|
pub mod errors;
|
||||||
|
|
|
@ -18,14 +18,13 @@ extern crate mentat_core;
|
||||||
extern crate sql_traits;
|
extern crate sql_traits;
|
||||||
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use ordered_float::OrderedFloat;
|
use ordered_float::OrderedFloat;
|
||||||
|
|
||||||
use core_traits::TypedValue;
|
use core_traits::TypedValue;
|
||||||
|
|
||||||
use sql_traits::errors::{BuildQueryResult, SQLError};
|
use sql_traits::errors::{BuildQueryResult, SQLErrorKind};
|
||||||
|
|
||||||
use mentat_core::{ToMicros, ValueRc};
|
use mentat_core::{ToMicros, ValueRc};
|
||||||
|
|
||||||
|
@ -194,7 +193,7 @@ impl QueryBuilder for SQLiteQueryBuilder {
|
||||||
// Do some validation first.
|
// Do some validation first.
|
||||||
// This is not free, but it's probably worth it for now.
|
// This is not free, but it's probably worth it for now.
|
||||||
if !name.chars().all(|c| char::is_alphanumeric(c) || c == '_') {
|
if !name.chars().all(|c| char::is_alphanumeric(c) || c == '_') {
|
||||||
return Err(SQLError::InvalidParameterName(name.to_string()));
|
return Err(SQLErrorKind::InvalidParameterName(name.to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if name.starts_with(self.arg_prefix.as_str())
|
if name.starts_with(self.arg_prefix.as_str())
|
||||||
|
@ -203,7 +202,7 @@ impl QueryBuilder for SQLiteQueryBuilder {
|
||||||
.skip(self.arg_prefix.len())
|
.skip(self.arg_prefix.len())
|
||||||
.all(char::is_numeric)
|
.all(char::is_numeric)
|
||||||
{
|
{
|
||||||
return Err(SQLError::BindParamCouldBeGenerated(name.to_string()));
|
return Err(SQLErrorKind::BindParamCouldBeGenerated(name.to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.push_sql("$");
|
self.push_sql("$");
|
||||||
|
|
55
src/conn.rs
55
src/conn.rs
|
@ -36,7 +36,7 @@ use mentat_query_pull::{pull_attributes_for_entities, pull_attributes_for_entity
|
||||||
|
|
||||||
use mentat_transaction::{CacheAction, CacheDirection, InProgress, InProgressRead, Metadata};
|
use mentat_transaction::{CacheAction, CacheDirection, InProgress, InProgressRead, Metadata};
|
||||||
|
|
||||||
use public_traits::errors::{MentatError, Result};
|
use public_traits::errors::{MentatErrorKind, Result};
|
||||||
|
|
||||||
use mentat_transaction::query::{
|
use mentat_transaction::query::{
|
||||||
lookup_value_for_attribute, lookup_values_for_attribute, q_explain, q_once, q_prepare,
|
lookup_value_for_attribute, lookup_values_for_attribute, q_explain, q_once, q_prepare,
|
||||||
|
@ -340,7 +340,7 @@ impl Conn {
|
||||||
attribute_entid = metadata
|
attribute_entid = metadata
|
||||||
.schema
|
.schema
|
||||||
.attribute_for_ident(&attribute)
|
.attribute_for_ident(&attribute)
|
||||||
.ok_or_else(|| MentatError::UnknownAttribute(attribute.to_string()))?
|
.ok_or_else(|| MentatErrorKind::UnknownAttribute(attribute.to_string()))?
|
||||||
.1
|
.1
|
||||||
.into();
|
.into();
|
||||||
}
|
}
|
||||||
|
@ -404,12 +404,16 @@ mod tests {
|
||||||
let t = format!("[[:db/add {} :db.schema/attribute \"tempid\"]]", next + 1);
|
let t = format!("[[:db/add {} :db.schema/attribute \"tempid\"]]", next + 1);
|
||||||
|
|
||||||
match conn.transact(&mut sqlite, t.as_str()) {
|
match conn.transact(&mut sqlite, t.as_str()) {
|
||||||
Err(MentatError::DbError(e)) => {
|
Err(e) => {
|
||||||
assert_eq!(
|
match e.kind() {
|
||||||
e.kind(),
|
&MentatErrorKind::DbError(ref e) => {
|
||||||
::db_traits::errors::DbErrorKind::UnallocatedEntid(next + 1)
|
assert_eq!(e.kind(), ::mentat_db::DbErrorKind::UnallocatedEntid(next + 1));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
x => {
|
||||||
|
panic!("expected db error, got {:?}", x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
x => panic!("expected db error, got {:?}", x),
|
x => panic!("expected db error, got {:?}", x),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,12 +438,15 @@ mod tests {
|
||||||
let t = format!("[[:db/add {} :db.schema/attribute \"tempid\"]]", next);
|
let t = format!("[[:db/add {} :db.schema/attribute \"tempid\"]]", next);
|
||||||
|
|
||||||
match conn.transact(&mut sqlite, t.as_str()) {
|
match conn.transact(&mut sqlite, t.as_str()) {
|
||||||
Err(MentatError::DbError(e)) => {
|
Err(e) => {
|
||||||
// All this, despite this being the ID we were about to allocate!
|
match e.kind() {
|
||||||
assert_eq!(
|
&MentatErrorKind::DbError(ref e) => {
|
||||||
e.kind(),
|
assert_eq!(e.kind(), ::mentat_db::DbErrorKind::UnallocatedEntid(next + 1));
|
||||||
::db_traits::errors::DbErrorKind::UnallocatedEntid(next)
|
}
|
||||||
);
|
x => {
|
||||||
|
panic!("expected db error, got {:?}", x);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
x => panic!("expected db error, got {:?}", x),
|
x => panic!("expected db error, got {:?}", x),
|
||||||
}
|
}
|
||||||
|
@ -642,8 +649,8 @@ mod tests {
|
||||||
|
|
||||||
// Bad EDN: missing closing ']'.
|
// Bad EDN: missing closing ']'.
|
||||||
let report = conn.transact(&mut sqlite, "[[:db/add \"t\" :db/ident :a/keyword]");
|
let report = conn.transact(&mut sqlite, "[[:db/add \"t\" :db/ident :a/keyword]");
|
||||||
match report.expect_err("expected transact to fail for bad edn") {
|
match report.expect_err("expected transact to fail for bad edn").kind() {
|
||||||
MentatError::EdnParseError(_) => {}
|
&MentatErrorKind::EdnParseError(_) => { }
|
||||||
x => panic!("expected EDN parse error, got {:?}", x),
|
x => panic!("expected EDN parse error, got {:?}", x),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -655,8 +662,8 @@ mod tests {
|
||||||
|
|
||||||
// Bad transaction data: missing leading :db/add.
|
// Bad transaction data: missing leading :db/add.
|
||||||
let report = conn.transact(&mut sqlite, "[[\"t\" :db/ident :b/keyword]]");
|
let report = conn.transact(&mut sqlite, "[[\"t\" :db/ident :b/keyword]]");
|
||||||
match report.expect_err("expected transact error") {
|
match report.expect_err("expected transact error").kind() {
|
||||||
MentatError::EdnParseError(_) => {}
|
&MentatErrorKind::EdnParseError(_) => { }
|
||||||
x => panic!("expected EDN parse error, got {:?}", x),
|
x => panic!("expected EDN parse error, got {:?}", x),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -668,12 +675,10 @@ mod tests {
|
||||||
|
|
||||||
// Bad transaction based on state of store: conflicting upsert.
|
// Bad transaction based on state of store: conflicting upsert.
|
||||||
let report = conn.transact(
|
let report = conn.transact(
|
||||||
&mut sqlite,
|
&mut sqlite, "[[:db/add \"u\" :db/ident :a/keyword]
|
||||||
"[[:db/add \"u\" :db/ident :a/keyword]
|
[:db/add \"u\" :db/ident :b/keyword]]");
|
||||||
[:db/add \"u\" :db/ident :b/keyword]]",
|
match report.expect_err("expected transact error").kind() {
|
||||||
);
|
&MentatErrorKind::DbError(ref e) => {
|
||||||
match report.expect_err("expected transact error") {
|
|
||||||
MentatError::DbError(e) => match e.kind() {
|
|
||||||
::db_traits::errors::DbErrorKind::SchemaConstraintViolation(_) => {}
|
::db_traits::errors::DbErrorKind::SchemaConstraintViolation(_) => {}
|
||||||
_ => panic!("expected SchemaConstraintViolation"),
|
_ => panic!("expected SchemaConstraintViolation"),
|
||||||
},
|
},
|
||||||
|
@ -705,8 +710,8 @@ mod tests {
|
||||||
CacheDirection::Forward,
|
CacheDirection::Forward,
|
||||||
CacheAction::Register,
|
CacheAction::Register,
|
||||||
);
|
);
|
||||||
match res.expect_err("expected cache to fail") {
|
match res.expect_err("expected cache to fail").kind() {
|
||||||
MentatError::UnknownAttribute(msg) => assert_eq!(msg, ":foo/bat"),
|
&MentatErrorKind::UnknownAttribute(ref msg) => assert_eq!(msg, ":foo/bat")
|
||||||
x => panic!("expected UnknownAttribute error, got {:?}", x),
|
x => panic!("expected UnknownAttribute error, got {:?}", x),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,7 @@ macro_rules! kw {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use public_traits::errors;
|
pub use public_traits::errors;
|
||||||
pub use public_traits::errors::{MentatError, Result};
|
pub use public_traits::errors::{MentatErrorKind, Result};
|
||||||
|
|
||||||
pub use edn::{FromMicros, FromMillis, ParseError, ToMicros, ToMillis};
|
pub use edn::{FromMicros, FromMillis, ParseError, ToMicros, ToMillis};
|
||||||
pub use mentat_query_projector::BindingTuple;
|
pub use mentat_query_projector::BindingTuple;
|
||||||
|
|
|
@ -17,7 +17,7 @@ use mentat_core::{DateTime, Keyword, Utc};
|
||||||
|
|
||||||
use super::{HasSchema, QueryInputs, QueryOutput, Queryable, RelResult, Store, Variable};
|
use super::{HasSchema, QueryInputs, QueryOutput, Queryable, RelResult, Store, Variable};
|
||||||
|
|
||||||
use public_traits::errors::{MentatError, Result};
|
use public_traits::errors::{MentatErrorKind, Result};
|
||||||
|
|
||||||
pub struct QueryBuilder<'a> {
|
pub struct QueryBuilder<'a> {
|
||||||
query: String,
|
query: String,
|
||||||
|
@ -49,12 +49,8 @@ impl<'a> QueryBuilder<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bind_ref_from_kw(&mut self, var: &str, value: Keyword) -> Result<&mut Self> {
|
pub fn bind_ref_from_kw(&mut self, var: &str, value: Keyword) -> Result<&mut Self> {
|
||||||
let entid = self
|
let entid = self.store.conn().current_schema().get_entid(&value).ok_or_else(||
|
||||||
.store
|
MentatError::from(MentatErrorKind::UnknownAttribute(value.to_string())))?;
|
||||||
.conn()
|
|
||||||
.current_schema()
|
|
||||||
.get_entid(&value)
|
|
||||||
.ok_or(MentatError::UnknownAttribute(value.to_string()))?;
|
|
||||||
self.values.insert(
|
self.values.insert(
|
||||||
Variable::from_valid_name(var),
|
Variable::from_valid_name(var),
|
||||||
TypedValue::Ref(entid.into()),
|
TypedValue::Ref(entid.into()),
|
||||||
|
|
29
src/store.rs.rej
Normal file
29
src/store.rs.rej
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
--- src/store.rs
|
||||||
|
+++ src/store.rs
|
||||||
|
@@ -85,7 +85,7 @@ impl Store {
|
||||||
|
pub fn open_empty(path: &str) -> Result<Store> {
|
||||||
|
if !path.is_empty() {
|
||||||
|
if Path::new(path).exists() {
|
||||||
|
- bail!(MentatError::PathAlreadyExists(path.to_string()));
|
||||||
|
+ bail!(MentatErrorKind::PathAlreadyExists(path.to_string()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -125,7 +125,7 @@ impl Store {
|
||||||
|
pub fn open_empty_with_key(path: &str, encryption_key: &str) -> Result<Store> {
|
||||||
|
if !path.is_empty() {
|
||||||
|
if Path::new(path).exists() {
|
||||||
|
- bail!(MentatError::PathAlreadyExists(path.to_string()));
|
||||||
|
+ bail!(MentatErrorKind::PathAlreadyExists(path.to_string()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -241,7 +241,7 @@ impl Pullable for Store {
|
||||||
|
#[cfg(feature = "syncable")]
|
||||||
|
impl Syncable for Store {
|
||||||
|
fn sync(&mut self, server_uri: &String, user_uuid: &String) -> Result<()> {
|
||||||
|
- let uuid = Uuid::parse_str(&user_uuid).map_err(|_| MentatError::BadUuid(user_uuid.clone()))?;
|
||||||
|
+ let uuid = Uuid::parse_str(&user_uuid).map_err(|_| MentatErrorKind::BadUuid(user_uuid.clone()))?;
|
||||||
|
Ok(Syncer::flow(&mut self.sqlite, server_uri, &uuid)?)
|
||||||
|
}
|
||||||
|
}
|
|
@ -101,7 +101,7 @@ use super::{
|
||||||
CORE_SCHEMA_VERSION,
|
CORE_SCHEMA_VERSION,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::errors::{MentatError, Result};
|
use super::errors::{MentatErrorKind, Result};
|
||||||
|
|
||||||
use mentat_transaction::{InProgress, Queryable};
|
use mentat_transaction::{InProgress, Queryable};
|
||||||
|
|
||||||
|
@ -325,17 +325,17 @@ where
|
||||||
{
|
{
|
||||||
fn core_type(&self, t: ValueType) -> Result<KnownEntid> {
|
fn core_type(&self, t: ValueType) -> Result<KnownEntid> {
|
||||||
self.entid_for_type(t)
|
self.entid_for_type(t)
|
||||||
.ok_or_else(|| MentatError::MissingCoreVocabulary(DB_SCHEMA_VERSION.clone()).into())
|
.ok_or_else(|| MentatErrorKind::MissingCoreVocabulary(DB_SCHEMA_VERSION.clone()).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn core_entid(&self, ident: &Keyword) -> Result<KnownEntid> {
|
fn core_entid(&self, ident: &Keyword) -> Result<KnownEntid> {
|
||||||
self.get_entid(ident)
|
self.get_entid(ident)
|
||||||
.ok_or_else(|| MentatError::MissingCoreVocabulary(DB_SCHEMA_VERSION.clone()).into())
|
.ok_or_else(|| MentatErrorKind::MissingCoreVocabulary(DB_SCHEMA_VERSION.clone()).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn core_attribute(&self, ident: &Keyword) -> Result<KnownEntid> {
|
fn core_attribute(&self, ident: &Keyword) -> Result<KnownEntid> {
|
||||||
self.attribute_for_ident(ident)
|
self.attribute_for_ident(ident)
|
||||||
.ok_or_else(|| MentatError::MissingCoreVocabulary(DB_SCHEMA_VERSION.clone()).into())
|
.ok_or_else(|| MentatErrorKind::MissingCoreVocabulary(DB_SCHEMA_VERSION.clone()).into())
|
||||||
.map(|(_, e)| e)
|
.map(|(_, e)| e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -548,7 +548,7 @@ pub trait VersionedStore: HasVocabularies + HasSchema {
|
||||||
// We have two vocabularies with the same name, same version, and
|
// We have two vocabularies with the same name, same version, and
|
||||||
// different definitions for an attribute. That's a coding error.
|
// different definitions for an attribute. That's a coding error.
|
||||||
// We can't accept this vocabulary.
|
// We can't accept this vocabulary.
|
||||||
bail!(MentatError::ConflictingAttributeDefinitions(
|
bail!(MentatErrorKind::ConflictingAttributeDefinitions(
|
||||||
definition.name.to_string(),
|
definition.name.to_string(),
|
||||||
definition.version,
|
definition.version,
|
||||||
pair.0.to_string(),
|
pair.0.to_string(),
|
||||||
|
@ -604,7 +604,7 @@ pub trait VersionedStore: HasVocabularies + HasSchema {
|
||||||
fn verify_core_schema(&self) -> Result<()> {
|
fn verify_core_schema(&self) -> Result<()> {
|
||||||
if let Some(core) = self.read_vocabulary_named(&DB_SCHEMA_CORE)? {
|
if let Some(core) = self.read_vocabulary_named(&DB_SCHEMA_CORE)? {
|
||||||
if core.version != CORE_SCHEMA_VERSION {
|
if core.version != CORE_SCHEMA_VERSION {
|
||||||
bail!(MentatError::UnexpectedCoreSchema(
|
bail!(MentatErrorKind::UnexpectedCoreSchema(
|
||||||
CORE_SCHEMA_VERSION,
|
CORE_SCHEMA_VERSION,
|
||||||
Some(core.version)
|
Some(core.version)
|
||||||
));
|
));
|
||||||
|
@ -613,7 +613,7 @@ pub trait VersionedStore: HasVocabularies + HasSchema {
|
||||||
// TODO: check things other than the version.
|
// TODO: check things other than the version.
|
||||||
} else {
|
} else {
|
||||||
// This would be seriously messed up.
|
// This would be seriously messed up.
|
||||||
bail!(MentatError::UnexpectedCoreSchema(CORE_SCHEMA_VERSION, None));
|
bail!(MentatErrorKind::UnexpectedCoreSchema(CORE_SCHEMA_VERSION, None));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -694,7 +694,7 @@ impl<'a, 'c> VersionedStore for InProgress<'a, 'c> {
|
||||||
self.install_attributes_for(definition, attributes)
|
self.install_attributes_for(definition, attributes)
|
||||||
}
|
}
|
||||||
VocabularyCheck::PresentButTooNew { newer_version } => {
|
VocabularyCheck::PresentButTooNew { newer_version } => {
|
||||||
Err(MentatError::ExistingVocabularyTooNew(
|
Err(MentatErrorKind::ExistingVocabularyTooNew(
|
||||||
definition.name.to_string(),
|
definition.name.to_string(),
|
||||||
newer_version.version,
|
newer_version.version,
|
||||||
definition.version,
|
definition.version,
|
||||||
|
@ -722,7 +722,7 @@ impl<'a, 'c> VersionedStore for InProgress<'a, 'c> {
|
||||||
out.insert(definition.name.clone(), VocabularyOutcome::Existed);
|
out.insert(definition.name.clone(), VocabularyOutcome::Existed);
|
||||||
}
|
}
|
||||||
VocabularyCheck::PresentButTooNew { newer_version } => {
|
VocabularyCheck::PresentButTooNew { newer_version } => {
|
||||||
bail!(MentatError::ExistingVocabularyTooNew(
|
bail!(MentatErrorKind::ExistingVocabularyTooNew(
|
||||||
definition.name.to_string(),
|
definition.name.to_string(),
|
||||||
newer_version.version,
|
newer_version.version,
|
||||||
definition.version
|
definition.version
|
||||||
|
@ -914,7 +914,7 @@ where
|
||||||
attributes: attributes,
|
attributes: attributes,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
Some(_) => bail!(MentatError::InvalidVocabularyVersion),
|
Some(_) => bail!(MentatErrorKind::InvalidVocabularyVersion),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
|
|
|
@ -37,7 +37,7 @@ use mentat::query::q_uncached;
|
||||||
|
|
||||||
use mentat::conn::Conn;
|
use mentat::conn::Conn;
|
||||||
|
|
||||||
use public_traits::errors::MentatError;
|
use public_traits::errors::MentatErrorKind;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_rel() {
|
fn test_rel() {
|
||||||
|
@ -243,10 +243,9 @@ fn test_unbound_inputs() {
|
||||||
inputs,
|
inputs,
|
||||||
);
|
);
|
||||||
|
|
||||||
match results.expect_err("expected unbound variables") {
|
match results.expect_err("expected unbound variables").kind() {
|
||||||
MentatError::UnboundVariables(vars) => {
|
&MentatErrorKind::UnboundVariables(ref vars) => {
|
||||||
assert_eq!(vars, vec!["?e".to_string()].into_iter().collect());
|
assert_eq!(vars, &vec!["?e".to_string()].into_iter().collect());
|
||||||
}
|
|
||||||
_ => panic!("Expected UnboundVariables variant."),
|
_ => panic!("Expected UnboundVariables variant."),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -495,17 +494,15 @@ fn test_fulltext() {
|
||||||
[?a :foo/term ?term]
|
[?a :foo/term ?term]
|
||||||
]"#;
|
]"#;
|
||||||
let r = conn.q_once(&mut c, query, None);
|
let r = conn.q_once(&mut c, query, None);
|
||||||
match r.expect_err("expected query to fail") {
|
match r.expect_err("expected query to fail").kind() {
|
||||||
MentatError::AlgebrizerError(
|
&MentatErrorKind::AlgebrizerError(ref e) => {
|
||||||
query_algebrizer_traits::errors::AlgebrizerError::InvalidArgument(
|
if let &mentat_query_algebrizer::AlgebrizerErrorKind::InvalidArgument(PlainSymbol(ref s), ref ty, ref i) = e.kind() {
|
||||||
PlainSymbol(s),
|
assert_eq!(*s, "fulltext");
|
||||||
ty,
|
assert_eq!(*ty, "string");
|
||||||
i,
|
assert_eq!(*i, 2);
|
||||||
),
|
} else {
|
||||||
) => {
|
panic!("Expected invalid argument");
|
||||||
assert_eq!(s, "fulltext");
|
}
|
||||||
assert_eq!(ty, "string");
|
|
||||||
assert_eq!(i, 2);
|
|
||||||
}
|
}
|
||||||
_ => panic!("Expected query to fail."),
|
_ => panic!("Expected query to fail."),
|
||||||
}
|
}
|
||||||
|
@ -516,17 +513,15 @@ fn test_fulltext() {
|
||||||
[?a :foo/term ?term]
|
[?a :foo/term ?term]
|
||||||
[(fulltext $ :foo/fts ?a) [[?x ?val]]]]"#;
|
[(fulltext $ :foo/fts ?a) [[?x ?val]]]]"#;
|
||||||
let r = conn.q_once(&mut c, query, None);
|
let r = conn.q_once(&mut c, query, None);
|
||||||
match r.expect_err("expected query to fail") {
|
match r.expect_err("expected query to fail").kind() {
|
||||||
MentatError::AlgebrizerError(
|
&MentatErrorKind::AlgebrizerError(ref e) => {
|
||||||
query_algebrizer_traits::errors::AlgebrizerError::InvalidArgument(
|
if let &mentat_query_algebrizer::AlgebrizerErrorKind::InvalidArgument(PlainSymbol(ref s), ref ty, ref i) = e.kind() {
|
||||||
PlainSymbol(s),
|
assert_eq!(*s, "fulltext");
|
||||||
ty,
|
assert_eq!(*ty, "string");
|
||||||
i,
|
assert_eq!(*i, 2);
|
||||||
),
|
} else {
|
||||||
) => {
|
panic!("expected AlgebrizerError::InvalidArgument");
|
||||||
assert_eq!(s, "fulltext");
|
}
|
||||||
assert_eq!(ty, "string");
|
|
||||||
assert_eq!(i, 2);
|
|
||||||
}
|
}
|
||||||
_ => panic!("Expected query to fail."),
|
_ => panic!("Expected query to fail."),
|
||||||
}
|
}
|
||||||
|
@ -732,14 +727,15 @@ fn test_aggregates_type_handling() {
|
||||||
// No type limits => can't do it.
|
// No type limits => can't do it.
|
||||||
let r = store.q_once(r#"[:find (sum ?v) . :where [_ _ ?v]]"#, None);
|
let r = store.q_once(r#"[:find (sum ?v) . :where [_ _ ?v]]"#, None);
|
||||||
let all_types = ValueTypeSet::any();
|
let all_types = ValueTypeSet::any();
|
||||||
match r.expect_err("expected query to fail") {
|
use mentat_query_projector::errors::ProjectorErrorKind;
|
||||||
MentatError::ProjectorError(
|
match r.expect_err("expected query to fail").kind() {
|
||||||
::query_projector_traits::errors::ProjectorError::CannotApplyAggregateOperationToTypes(
|
&MentatErrorKind::ProjectorError(ref e) => {
|
||||||
SimpleAggregationOp::Sum,
|
if let &ProjectorErrorKind::CannotApplyAggregateOperationToTypes(
|
||||||
types,
|
SimpleAggregationOp::Sum, ref types) = e.kind() {
|
||||||
),
|
assert_eq!(types, &all_types);
|
||||||
) => {
|
} else {
|
||||||
assert_eq!(types, all_types);
|
panic!("Unexpected error type {:?}", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
e => panic!("Unexpected error type {:?}", e),
|
e => panic!("Unexpected error type {:?}", e),
|
||||||
}
|
}
|
||||||
|
@ -750,14 +746,14 @@ fn test_aggregates_type_handling() {
|
||||||
:where [_ _ ?v] [(type ?v :db.type/instant)]]"#,
|
:where [_ _ ?v] [(type ?v :db.type/instant)]]"#,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
match r.expect_err("expected query to fail") {
|
match r.expect_err("expected query to fail").kind() {
|
||||||
MentatError::ProjectorError(
|
&MentatErrorKind::ProjectorError(ref e) => {
|
||||||
::query_projector_traits::errors::ProjectorError::CannotApplyAggregateOperationToTypes(
|
if let &ProjectorErrorKind::CannotApplyAggregateOperationToTypes(
|
||||||
SimpleAggregationOp::Sum,
|
SimpleAggregationOp::Sum, ref types) = e.kind() {
|
||||||
types,
|
assert_eq!(types, &ValueTypeSet::of_one(ValueType::Instant));
|
||||||
),
|
} else {
|
||||||
) => {
|
panic!("Unexpected error type {:?}", e);
|
||||||
assert_eq!(types, ValueTypeSet::of_one(ValueType::Instant));
|
}
|
||||||
}
|
}
|
||||||
e => panic!("Unexpected error type {:?}", e),
|
e => panic!("Unexpected error type {:?}", e),
|
||||||
}
|
}
|
||||||
|
@ -1705,12 +1701,15 @@ fn test_aggregation_implicit_grouping() {
|
||||||
[?person :foo/name ?name]]"#,
|
[?person :foo/name ?name]]"#,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
match res.expect_err("expected query to fail") {
|
use mentat_query_projector::errors::ProjectorErrorKind;
|
||||||
MentatError::ProjectorError(
|
match res.expect_err("expected query to fail").kind() {
|
||||||
::query_projector_traits::errors::ProjectorError::AmbiguousAggregates(mmc, cc),
|
&MentatErrorKind::ProjectorError(ref e) => {
|
||||||
) => {
|
if let &ProjectorErrorKind::AmbiguousAggregates(mmc, cc) = e.kind() {
|
||||||
assert_eq!(mmc, 2);
|
assert_eq!(mmc, 2);
|
||||||
assert_eq!(cc, 1);
|
assert_eq!(cc, 1);
|
||||||
|
} else {
|
||||||
|
panic!("Unexpected error type {:?}.", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
e => {
|
e => {
|
||||||
panic!("Unexpected error type {:?}.", e);
|
panic!("Unexpected error type {:?}.", e);
|
||||||
|
|
|
@ -40,7 +40,7 @@ use mentat::{
|
||||||
|
|
||||||
use mentat::entity_builder::{BuildTerms, TermBuilder};
|
use mentat::entity_builder::{BuildTerms, TermBuilder};
|
||||||
|
|
||||||
use mentat::errors::MentatError;
|
use mentat::errors::MentatErrorKind;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref FOO_NAME: Keyword = { kw!(:foo/name) };
|
static ref FOO_NAME: Keyword = { kw!(:foo/name) };
|
||||||
|
@ -327,12 +327,12 @@ fn test_add_vocab() {
|
||||||
.ensure_vocabulary(&foo_v1_malformed)
|
.ensure_vocabulary(&foo_v1_malformed)
|
||||||
.expect_err("expected vocabulary to fail")
|
.expect_err("expected vocabulary to fail")
|
||||||
{
|
{
|
||||||
MentatError::ConflictingAttributeDefinitions(vocab, version, attr, theirs, ours) => {
|
&MentatErrorKind::ConflictingAttributeDefinitions(vocab, version, attr, theirs, ours) => {
|
||||||
assert_eq!(vocab.as_str(), ":org.mozilla/foo");
|
assert_eq!(vocab.as_str(), ":org.mozilla/foo");
|
||||||
assert_eq!(attr.as_str(), ":foo/baz");
|
assert_eq!(attr.as_str(), ":foo/baz");
|
||||||
assert_eq!(version, 1);
|
assert_eq!(*version, 1);
|
||||||
assert_eq!(&theirs, &baz);
|
assert_eq!(theirs, &baz);
|
||||||
assert_eq!(&ours, &malformed_baz);
|
assert_eq!(ours, &malformed_baz);
|
||||||
}
|
}
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -376,7 +376,7 @@ impl Repl {
|
||||||
let next = match encryption_key {
|
let next = match encryption_key {
|
||||||
#[cfg(not(feature = "sqlcipher"))]
|
#[cfg(not(feature = "sqlcipher"))]
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
return Err(::mentat::MentatError::RusqliteError(
|
return Err(::mentat::MentatErrorKind::RusqliteError(
|
||||||
".open_encrypted requires the sqlcipher Mentat feature".into(),
|
".open_encrypted requires the sqlcipher Mentat feature".into(),
|
||||||
"".into(),
|
"".into(),
|
||||||
))
|
))
|
||||||
|
|
|
@ -43,7 +43,7 @@ pub use mentat_query_projector::{
|
||||||
RelResult,
|
RelResult,
|
||||||
};
|
};
|
||||||
|
|
||||||
use public_traits::errors::{MentatError, Result};
|
use public_traits::errors::{MentatErrorKind, Result};
|
||||||
|
|
||||||
pub type QueryExecutionResult = Result<QueryOutput>;
|
pub type QueryExecutionResult = Result<QueryOutput>;
|
||||||
pub type PreparedResult<'sqlite> = Result<PreparedQuery<'sqlite>>;
|
pub type PreparedResult<'sqlite> = Result<PreparedQuery<'sqlite>>;
|
||||||
|
@ -156,7 +156,7 @@ where
|
||||||
// If they aren't, the user has made an error -- perhaps writing the wrong variable in `:in`, or
|
// If they aren't, the user has made an error -- perhaps writing the wrong variable in `:in`, or
|
||||||
// not binding in the `QueryInput`.
|
// not binding in the `QueryInput`.
|
||||||
if !unbound.is_empty() {
|
if !unbound.is_empty() {
|
||||||
bail!(MentatError::UnboundVariables(
|
bail!(MentatErrorKind::UnboundVariables(
|
||||||
unbound.into_iter().map(|v| v.to_string()).collect()
|
unbound.into_iter().map(|v| v.to_string()).collect()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -198,7 +198,7 @@ fn fetch_values<'sqlite>(
|
||||||
fn lookup_attribute(schema: &Schema, attribute: &Keyword) -> Result<KnownEntid> {
|
fn lookup_attribute(schema: &Schema, attribute: &Keyword) -> Result<KnownEntid> {
|
||||||
schema
|
schema
|
||||||
.get_entid(attribute)
|
.get_entid(attribute)
|
||||||
.ok_or_else(|| MentatError::UnknownAttribute(attribute.name().into()).into())
|
.ok_or_else(|| MentatErrorKind::UnknownAttribute(attribute.name().into()).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a single value for the provided entity and attribute.
|
/// Return a single value for the provided entity and attribute.
|
||||||
|
@ -415,7 +415,7 @@ where
|
||||||
if !unbound.is_empty() {
|
if !unbound.is_empty() {
|
||||||
// TODO: Allow binding variables at execution time, not just
|
// TODO: Allow binding variables at execution time, not just
|
||||||
// preparation time.
|
// preparation time.
|
||||||
bail!(MentatError::UnboundVariables(
|
bail!(MentatErrorKind::UnboundVariables(
|
||||||
unbound.into_iter().map(|v| v.to_string()).collect()
|
unbound.into_iter().map(|v| v.to_string()).collect()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue