diff --git a/query-projector/src/lib.rs b/query-projector/src/lib.rs index 0737cd80..fd59c5c2 100644 --- a/query-projector/src/lib.rs +++ b/query-projector/src/lib.rs @@ -69,6 +69,13 @@ error_chain! { links { DbError(mentat_db::Error, mentat_db::ErrorKind); } + + errors { + UnexpectedResultsType(actual: &'static str, expected: &'static str) { + description("unexpected query results type") + display("expected {}, got {}", expected, actual) + } + } } #[derive(Debug, PartialEq, Eq)] @@ -119,6 +126,42 @@ impl QueryResults { &FindRel(_) => Box::new(|| QueryResults::Rel(vec![])), } } + + pub fn into_scalar(self) -> Result> { + match self { + QueryResults::Scalar(o) => Ok(o), + QueryResults::Coll(_) => bail!(ErrorKind::UnexpectedResultsType("coll", "scalar")), + QueryResults::Tuple(_) => bail!(ErrorKind::UnexpectedResultsType("tuple", "scalar")), + QueryResults::Rel(_) => bail!(ErrorKind::UnexpectedResultsType("rel", "scalar")), + } + } + + pub fn into_coll(self) -> Result> { + match self { + QueryResults::Scalar(_) => bail!(ErrorKind::UnexpectedResultsType("scalar", "coll")), + QueryResults::Coll(c) => Ok(c), + QueryResults::Tuple(_) => bail!(ErrorKind::UnexpectedResultsType("tuple", "coll")), + QueryResults::Rel(_) => bail!(ErrorKind::UnexpectedResultsType("rel", "coll")), + } + } + + pub fn into_tuple(self) -> Result>> { + match self { + QueryResults::Scalar(_) => bail!(ErrorKind::UnexpectedResultsType("scalar", "tuple")), + QueryResults::Coll(_) => bail!(ErrorKind::UnexpectedResultsType("coll", "tuple")), + QueryResults::Tuple(t) => Ok(t), + QueryResults::Rel(_) => bail!(ErrorKind::UnexpectedResultsType("rel", "tuple")), + } + } + + pub fn into_rel(self) -> Result>> { + match self { + QueryResults::Scalar(_) => bail!(ErrorKind::UnexpectedResultsType("scalar", "rel")), + QueryResults::Coll(_) => bail!(ErrorKind::UnexpectedResultsType("coll", "rel")), + QueryResults::Tuple(_) => bail!(ErrorKind::UnexpectedResultsType("tuple", "rel")), + QueryResults::Rel(r) => Ok(r), + } + } } type Index = i32; // See rusqlite::RowIndex. diff --git a/src/query.rs b/src/query.rs index da12f601..256cbfea 100644 --- a/src/query.rs +++ b/src/query.rs @@ -13,6 +13,7 @@ use rusqlite::types::ToSql; use mentat_core::{ Schema, + TypedValue, }; use mentat_query_algebrizer::{ @@ -52,6 +53,31 @@ use errors::{ pub type QueryExecutionResult = Result; +pub trait IntoResult { + fn into_scalar_result(self) -> Result>; + fn into_coll_result(self) -> Result>; + fn into_tuple_result(self) -> Result>>; + fn into_rel_result(self) -> Result>>; +} + +impl IntoResult for QueryExecutionResult { + fn into_scalar_result(self) -> Result> { + self?.into_scalar().map_err(|e| e.into()) + } + + fn into_coll_result(self) -> Result> { + self?.into_coll().map_err(|e| e.into()) + } + + fn into_tuple_result(self) -> Result>> { + self?.into_tuple().map_err(|e| e.into()) + } + + fn into_rel_result(self) -> Result>> { + self?.into_rel().map_err(|e| e.into()) + } +} + /// Take an EDN query string, a reference to an open SQLite connection, a Mentat schema, and an /// optional collection of input bindings (which should be keyed by `"?varname"`), and execute the /// query immediately, blocking the current thread.