Skip to content
This repository was archived by the owner on Sep 12, 2018. It is now read-only.

Finish passing input parameters through to queries#418

Closed
rnewman wants to merge 9 commits intorustfrom
rnewman/inline-limit
Closed

Finish passing input parameters through to queries#418
rnewman wants to merge 9 commits intorustfrom
rnewman/inline-limit

Conversation

@rnewman
Copy link
Copy Markdown
Collaborator

@rnewman rnewman commented Apr 17, 2017

In the course of starting another feature, I realized this wasn't finished.

@rnewman rnewman self-assigned this Apr 17, 2017
@rnewman rnewman requested a review from ncalexan April 17, 2017 22:08
@rnewman rnewman force-pushed the rnewman/inline-limit branch from eb5a529 to 15d0f5d Compare April 17, 2017 22:09
@rnewman rnewman force-pushed the rnewman/inline-limit branch from 15d0f5d to 4955156 Compare April 17, 2017 22:10
@rnewman
Copy link
Copy Markdown
Collaborator Author

rnewman commented Apr 17, 2017

I just realized this uses inputs not named in :in. Fixing.

@rnewman
Copy link
Copy Markdown
Collaborator Author

rnewman commented Apr 17, 2017

Oh, and we don't parse :in yet. Heh.

@rnewman rnewman force-pushed the rnewman/inline-limit branch from 4955156 to 3297774 Compare April 18, 2017 04:32
rnewman added a commit that referenced this pull request Apr 18, 2017
This also adds a test that an `UnboundVariables` error is raised if a
variable mentioned in the `:in` clause isn't bound.
@rnewman
Copy link
Copy Markdown
Collaborator Author

rnewman commented Apr 18, 2017

@ncalexan: part 1 needs some advice from you on how to get things to compile when returning an error; I can't get it to work.

core/src/lib.rs Outdated
&ValueType::Double => values::DB_TYPE_DOUBLE.clone(),
&ValueType::String => values::DB_TYPE_STRING.clone(),
&ValueType::Keyword => values::DB_TYPE_KEYWORD.clone(),
match *self {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did this on the way, but I suspect it should actually be to_edn_value(self)ValueType is Copy, so avoiding references wherever possible is best.

None => ConjoiningClauses::with_alias_counter(alias_counter),
Some(QueryInputs { mut types, mut values }) => {
println!("Got inputs {:?}", values);
println!("Got input vars {:?}", in_variables);
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll remove these locally.

rnewman added 5 commits April 18, 2017 07:53
We also at this point switch from using `Vec<Variable>` to
`BTreeSet<Variable>`. This allows us to guarantee no duplicates later;
we'll reject duplicates at parse time.
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.
We'll use this to drop unneeded values from input maps, if lazy callers
reuse a general-purpose map for multiple queries.
This also adds a test that an `UnboundVariables` error is raised if a
variable mentioned in the `:in` clause isn't bound.
@rnewman rnewman force-pushed the rnewman/inline-limit branch from 3297774 to dbbfdb2 Compare April 18, 2017 14:53
Copy link
Copy Markdown
Member

@ncalexan ncalexan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few nits, some small requests. Rock on!

}

errors {
DuplicateVariableError {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth decorating with the variable, I think. (I see your TODO below.)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately it's a little tricky with the way I've implemented it; I hope this can be part of an ergonomics pass in a few months. It should be pretty obvious to users when there are duplicated variables.

pub struct Order(pub Direction, pub Variable); // Future: Element instead of Variable?

#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: prefer alphabetical order.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was copypasta'd from elsewhere, but sure.

Variable,
};

pub use errors::{
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pub?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I get your question. Yeah, probably unnecessary.

/// 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>,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do these need to be pub? You could make a stronger statement if they were hidden, and only exposed via accessors.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like them not to be, but there's no concept of crate-private in Rust. I could flatten inputs.rs into mod.rs


impl Default for QueryInputs {
fn default() -> Self {
QueryInputs { types: BTreeMap::default(), values: BTreeMap::default() }
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't we settle on

Name {
    x: X,
    y: Y,
    ...
}

(Here and below.)

/// Remove all keys from the map that are not present in `ks`.
/// This implementation is terrible because there's no mutable iterator for BTreeMap.
fn keep_intersected_keys(&mut self, ks: &BTreeSet<K>) {
let mut to_remove = Vec::with_capacity(self.len() - ks.len());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I expect this to panic when self.len() is less than ks.len(). That might be okay, but can you be safe about it?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch!


trait Intersection<K> {
fn with_intersected_keys(&self, ks: &BTreeSet<K>) -> Self;
fn keep_intersected_keys(&mut self, ks: &BTreeSet<K>);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have one mutating and one non-mutating method. Is there a compelling reason to have different API regimes?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, it means we can write:

            value_bindings: self.value_bindings.with_intersected_keys(&vars),

rather than

let new_value_bindings = self.value_bindings.clone();
new_value_bindings.keep_intersected_keys(&vars);
…
    value_bindings: new_value_bindings,

The reason for k_i_k is because we're already taking ownership of the inputs, so it's wasteful to clone into a new map.

match inputs.into() {
None => ConjoiningClauses::with_alias_counter(alias_counter),
Some(QueryInputs { mut types, mut values }) => {
// Discard any bindings not mentioned in our :in clause.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we test somewhere that all :in variables appear? I feel like Datomic probably doesn't care, but we should probably fail in this case, since it's likely to be an error.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do check that they're all bound. I don't think we check that they're a subset of the variables in the query. I'll file.


errors {
UnboundVariables(names: BTreeSet<String>) {
description("unbound variables at execution time")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: "query execution time"? There are many things being executed at many times.

// Because this is q_once, we can check that all of our `:in` variables are bound at this point.
// If they aren't, the user has made an error -- perhaps writing the wrong variable in `:in`, or
// not binding in the `QueryInput`.
let unbound = algebrized.unbound_variables();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah! I think this closes an open loop from earlier.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did this because I wrote a test that failed because I typoed the :in variable :)

rnewman added a commit that referenced this pull request Apr 18, 2017
This also adds a test that an `UnboundVariables` error is raised if a
variable mentioned in the `:in` clause isn't bound.
rnewman added a commit that referenced this pull request Apr 18, 2017
This commit downgrades error_chain to 0.8.1 in order to fix trait bounds
on errors.
@rnewman
Copy link
Copy Markdown
Collaborator Author

rnewman commented Apr 18, 2017

Thanks for the help, Nick!

aa14a71

@rnewman rnewman closed this Apr 18, 2017
@rnewman rnewman deleted the rnewman/inline-limit branch April 18, 2017 20:21
rnewman added a commit that referenced this pull request Apr 18, 2017
@rnewman
Copy link
Copy Markdown
Collaborator Author

rnewman commented Apr 18, 2017

Review comments addressed in bffefe7.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants