Skip to content

Commit

Permalink
Add get_result and get_results to SQL commands
Browse files Browse the repository at this point in the history
These are intended to be used in favor of `query_one` and `query_all`,
which are now hidden from the public API. I originally was going to name
these `run` and `run_all`, but I didn't like the name `run_all`, nor the
fact that `run` and `execute` are synonyms ("Do I call `memcpy` or
`memmov` here?")

Fixes #29
  • Loading branch information
sgrif committed Nov 30, 2015
1 parent 7c6d388 commit 3cb4ad2
Show file tree
Hide file tree
Showing 10 changed files with 55 additions and 34 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ for Rust libraries in [RFC #1105](https://github.com/rust-lang/rfcs/blob/master/
under the hood, but has been hidden from docs and is not considered public
API.

* Added `get_result` and `get_results`, which work similarly to `load` and
`first`, but are intended to make code read better when working with commands
like `create` and `update`. In the future, `get_result` may also check that
only a single row was affected.

### Changed

* Added a hidden `__Nonexhaustive` variant to `result::Error`. This is not
Expand Down
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,15 +157,15 @@ fn change_users_name(connection: &Connection, target: i32, new_name: &str) -> Qu
use diesel::query_builder::update;
use users::dsl::*;

let command = update(users.filter(id.eq(target))).set(name.eq(new_name));
connection.query_one(command)
update(users.filter(id.eq(target))).set(name.eq(new_name))
.get_result(&connection)
}
```

As with [`insert`][insert], we can return any type which implements
[`Queriable`][queriable] for the right types. If you do not want to use the
returned record(s), you should call [`execute`][execute] instead of
[`query_one`][query_one] or [`query_all`][query_all].
[`run`][run] or [`run_all`][run_all].

You can also use a struct to represent the changes, if it implements
[`AsChangeset`][as_changeset]. Again, `diesel_codegen` can generate this for us
Expand All @@ -179,8 +179,8 @@ pub struct UserChanges {
}

fn save_user(connection: &Connection, id: i32, changes: &UserChanges) -> QueryResult<User> {
let command = update(users::table.filter(users::id.eq(id))).set(changes);
connection.query_one(command)
update(users::table.filter(users::id.eq(id))).set(changes)
.get_result(&connection)
}
```

Expand Down Expand Up @@ -236,8 +236,8 @@ you can go about getting the data structures set up.
[insert]: http://sgrif.github.io/diesel/diesel/struct.Connection.html#method.insert
[insert_returning_count]: http://sgrif.github.io/diesel/diesel/struct.Connection.html#method.insert_returning_count
[execute]: http://sgrif.github.io/diesel/diesel/trait.ExecuteDsl.html#method.execute
[query_one]: http://sgrif.github.io/diesel/diesel/struct.Connection.html#method.query_one
[query_all]: http://sgrif.github.io/diesel/diesel/struct.Connection.html#method.query_all
[run]: http://sgrif.github.io/diesel/diesel/trait.LoadDsl.html#method.run
[run_all]: http://sgrif.github.io/diesel/diesel/trait.LoadDsl.html#method.run_all
[update]: http://sgrif.github.io/diesel/diesel/query_builder/fn.update.html
[delete]: http://sgrif.github.io/diesel/diesel/query_builder/fn.delete.html
[connection]: http://sgrif.github.io/diesel/diesel/struct.Connection.html
Expand Down
8 changes: 2 additions & 6 deletions diesel/src/connection/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,7 @@ impl Connection {
self.execute_inner(query).map(|res| res.rows_affected())
}

/// Executes the given query, returning a single value. Identical to
/// `source.first(&connection)`. See [the documentation for
/// `first`](trait.LoadDsl.html#method.first) for more.
#[doc(hidden)]
pub fn query_one<T, U>(&self, source: T) -> QueryResult<U> where
T: AsQuery,
U: Queriable<T::SqlType>,
Expand All @@ -115,9 +113,7 @@ impl Connection {
.and_then(|mut e| e.nth(0).map(Ok).unwrap_or(Err(Error::NotFound)))
}

/// Executes the given query, returning an `Iterator` over the returned
/// rows. Identical to `source.load(&connection)`. See [the documentation
/// for `load`](trait.LoadDsl.html#method.load) for more.
#[doc(hidden)]
pub fn query_all<T, U>(&self, source: T) -> QueryResult<Cursor<T::SqlType, U>> where
T: AsQuery,
U: Queriable<T::SqlType>,
Expand Down
26 changes: 23 additions & 3 deletions diesel/src/query_dsl/load_dsl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ use super::LimitDsl;

/// Methods to execute a query given a connection. These are automatically implemented for the
/// various query types.
pub trait LoadDsl: AsQuery + LimitDsl + Sized {
pub trait LoadDsl: AsQuery + Sized {
/// Executes the given query, returning an `Iterator` over the returned
/// rows.
fn load<U>(self, conn: &Connection) -> QueryResult<Cursor<Self::SqlType, U>> where
U: Queriable<Self::SqlType>
{
Expand All @@ -18,13 +20,31 @@ pub trait LoadDsl: AsQuery + LimitDsl + Sized {
/// optional, you can call `.optional()` on the result of this to get a
/// `Result<Option<U>>`.
fn first<U>(self, conn: &Connection) -> QueryResult<U> where
U: Queriable<<<Self as LimitDsl>::Output as Query>::SqlType>
U: Queriable<<<Self as LimitDsl>::Output as Query>::SqlType>,
Self: LimitDsl,
{
conn.query_one(self.limit(1))
}

/// Runs the command, and returns the affected row. `Err(NotFound)` will be
/// returned if the query affected 0 rows. You can call `.optional()` on the
/// result of this if the command was optional to get back a
/// `Result<Option<U>>`
fn get_result<U>(self, conn: &Connection) -> QueryResult<U> where
U: Queriable<Self::SqlType>,
{
conn.query_one(self)
}

/// Runs the command, returning an `Iterator` over the affected rows.
fn get_results<U>(self, conn: &Connection) -> QueryResult<Cursor<Self::SqlType, U>> where
U: Queriable<Self::SqlType>
{
self.load(conn)
}
}

impl<T: AsQuery + LimitDsl> LoadDsl for T {
impl<T: AsQuery> LoadDsl for T {
}

pub trait ExecuteDsl: QueryFragment + Sized {
Expand Down
6 changes: 3 additions & 3 deletions diesel_codegen/src/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,9 @@ fn save_changes_impl(
pub fn save_changes(&mut self, connection: &::diesel::Connection) -> ::diesel::QueryResult<()> {
use ::diesel::query_builder::update;
*self = {
let command = update($table.filter($table.primary_key().eq(&self.$pk_field)))
.set(&*self);
try!(connection.query_one(command))
try!(update($table.filter($table.primary_key().eq(&self.$pk_field)))
.set(&*self)
.get_result(&connection))
};
Ok(())
}
Expand Down
8 changes: 4 additions & 4 deletions diesel_tests/tests/bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ fn bench_selecting_0_rows_with_trivial_query(b: &mut Bencher) {
setup_users_table(&conn);

b.iter(|| {
conn.query_all(users::table).unwrap().collect::<Vec<User>>()
users::table.load(&conn).unwrap().collect::<Vec<User>>();
})
}

Expand All @@ -29,7 +29,7 @@ fn bench_selecting_10k_rows_with_trivial_query(b: &mut Bencher) {
conn.insert_returning_count(&users::table, &data).unwrap();

b.iter(|| {
conn.query_all(users::table).unwrap().collect::<Vec<User>>()
users::table.load(&conn).unwrap().collect::<Vec<User>>()
})
}

Expand All @@ -44,7 +44,7 @@ fn bench_selecting_0_rows_with_medium_complex_query(b: &mut Bencher) {
let target = users.left_outer_join(posts::table)
.filter(hair_color.eq("black"))
.order(name.desc());
conn.query_all(target).unwrap().collect::<Vec<(User, Option<Post>)>>()
target.load(&conn).unwrap().collect::<Vec<(User, Option<Post>)>>()
})
}

Expand All @@ -65,6 +65,6 @@ fn bench_selecting_10k_rows_with_medium_complex_query(b: &mut Bencher) {
let target = users.left_outer_join(posts::table)
.filter(hair_color.eq("black"))
.order(name.desc());
conn.query_all(target).unwrap().collect::<Vec<(User, Option<Post>)>>()
target.load(&conn).unwrap().collect::<Vec<(User, Option<Post>)>>()
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ fn main() {
let select_id = users.select(id);
let select_name = users.select(name);

let ids: Vec<i32> = connection.query_all(select_name).unwrap().collect();
let ids: Vec<i32> = select_name.load(&connection).unwrap().collect();
//~^ ERROR the trait `diesel::query_source::Queriable<diesel::types::VarChar>` is not implemented for the type `i32`
//~| ERROR E0277
let names: Vec<String> = connection.query_all(select_id).unwrap().collect();
let names: Vec<String> = select_id.load(&connection).unwrap().collect();
//~^ ERROR the trait `diesel::query_source::Queriable<diesel::types::Integer>` is not implemented
//~| ERROR E0277
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ table! {
fn main() {
let connection = Connection::establish("").unwrap();
let select_count = users::table.select_sql::<types::BigInt>("COUNT(*)");
let count = connection.query_one::<_, String>(select_count).unwrap();
let count = select_count.get_result::<String>(&connection).unwrap();
//~^ ERROR E0277
}
4 changes: 2 additions & 2 deletions diesel_tests/tests/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ fn with_select_sql() {
.unwrap();

let select_count = users::table.select_sql::<types::BigInt>("COUNT(*)");
let get_count = || connection.query_one::<_, i64>(select_count.clone());
let get_count = || select_count.clone().first::<i64>(&connection);

assert_eq!(Ok(2), get_count());

Expand Down Expand Up @@ -180,7 +180,7 @@ fn selecting_columns_with_different_definition_order() {
.unwrap();
let expected_user = User::with_hair_color(1, "Sean", "black");
let user_from_insert = connection.insert(&users::table, &NewUser::new("Sean", Some("black"))).unwrap().nth(0);
let user_from_select = connection.query_one(users::table);
let user_from_select = users::table.first(&connection);

assert_eq!(Some(expected_user.clone()), user_from_insert);
assert_eq!(Ok(expected_user), user_from_select);
Expand Down
12 changes: 6 additions & 6 deletions diesel_tests/tests/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ fn update_returning_struct() {
use schema::users::dsl::*;

let connection = connection_with_sean_and_tess_in_users_table();
let command = update(users.filter(id.eq(1))).set(hair_color.eq("black"));
let user = connection.query_one(command);
let user = update(users.filter(id.eq(1))).set(hair_color.eq("black"))
.get_result(&connection);
let expected_user = User::with_hair_color(1, "Sean", "black");

assert_eq!(Ok(expected_user), user);
Expand All @@ -91,9 +91,9 @@ fn update_with_struct_as_changes() {

let connection = connection_with_sean_and_tess_in_users_table();
let changes = NewUser::new("Jim", Some("blue"));
let command = update(users.filter(id.eq(1))).set(&changes);

let user = connection.query_one(command);
let user = update(users.filter(id.eq(1))).set(&changes)
.get_result(&connection);
let expected_user = User::with_hair_color(1, "Jim", "blue");

assert_eq!(Ok(expected_user), user);
Expand All @@ -105,9 +105,9 @@ fn update_with_struct_does_not_set_primary_key() {

let connection = connection_with_sean_and_tess_in_users_table();
let changes = User::with_hair_color(2, "Jim", "blue");
let command = update(users.filter(id.eq(1))).set(&changes);

let user = connection.query_one(command);
let user = update(users.filter(id.eq(1))).set(&changes)
.get_result(&connection);
let expected_user = User::with_hair_color(1, "Jim", "blue");

assert_eq!(Ok(expected_user), user);
Expand Down

1 comment on commit 3cb4ad2

@mfpiccolo
Copy link
Contributor

Choose a reason for hiding this comment

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

I like these much better than run and run_all. 🎉

Please sign in to comment.