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:
Richard Newman 2017-04-17 21:09:18 -07:00
parent a9a82ea1a7
commit 651308f721

View 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 })
}
}