Part 2: define a type to encapsulate query inputs.
This is for two reasons. Firstly, we need to track the types of inputs, their values, and also the input variables; adding a struct gives us a little more clarity. Secondly, when we come to implement prepared statements, we'll be algebrizing queries without having the values available. We'll be able to do a better job of algebrizing, and also do more validating, if we allow callers to specify the types of variables in advance, even if the values aren't known.
This commit is contained in:
parent
a9a82ea1a7
commit
651308f721
1 changed files with 72 additions and 0 deletions
72
query-algebrizer/src/clauses/inputs.rs
Normal file
72
query-algebrizer/src/clauses/inputs.rs
Normal file
|
@ -0,0 +1,72 @@
|
|||
// Copyright 2016 Mozilla
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
// License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use mentat_core::{
|
||||
TypedValue,
|
||||
ValueType,
|
||||
};
|
||||
|
||||
use mentat_query::{
|
||||
Variable,
|
||||
};
|
||||
|
||||
pub use errors::{
|
||||
Error,
|
||||
ErrorKind,
|
||||
Result,
|
||||
};
|
||||
|
||||
/// Define the inputs to a query. This is in two parts: a set of values known now, and a set of
|
||||
/// types known now.
|
||||
/// The separate map of types is to allow queries to be algebrized without full knowledge of
|
||||
/// the bindings that will be used at execution time.
|
||||
/// When built correctly, `types` is guaranteed to contain the types of `values` -- use
|
||||
/// `QueryInputs::new` or `QueryInputs::with_values` to construct an instance.
|
||||
pub struct QueryInputs {
|
||||
pub types: BTreeMap<Variable, ValueType>,
|
||||
pub values: BTreeMap<Variable, TypedValue>,
|
||||
}
|
||||
|
||||
impl Default for QueryInputs {
|
||||
fn default() -> Self {
|
||||
QueryInputs { types: BTreeMap::default(), values: BTreeMap::default() }
|
||||
}
|
||||
}
|
||||
|
||||
impl QueryInputs {
|
||||
pub fn with_value_sequence(vals: Vec<(Variable, TypedValue)>) -> QueryInputs {
|
||||
let values: BTreeMap<Variable, TypedValue> = vals.into_iter().collect();
|
||||
QueryInputs::with_values(values)
|
||||
}
|
||||
|
||||
pub fn with_values(values: BTreeMap<Variable, TypedValue>) -> QueryInputs {
|
||||
QueryInputs {
|
||||
types: values.iter().map(|(var, val)| (var.clone(), val.value_type())).collect(),
|
||||
values: values,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(mut types: BTreeMap<Variable, ValueType>,
|
||||
values: BTreeMap<Variable, TypedValue>) -> Result<QueryInputs> {
|
||||
// Make sure that the types of the values agree with those in types, and collect.
|
||||
for (var, v) in values.iter() {
|
||||
let t = v.value_type();
|
||||
let old = types.insert(var.clone(), t);
|
||||
if let Some(old) = old {
|
||||
if old != t {
|
||||
bail!(ErrorKind::InputTypeDisagreement(var.name(), old, t));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(QueryInputs { types: types, values: values })
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue