Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/feature/load_returns_a_iterator'…
Browse files Browse the repository at this point in the history
… into feature/load_returns_a_iterator
  • Loading branch information
weiznich committed Jul 1, 2021
2 parents 2ff17b4 + 96d463a commit ec31ccb
Show file tree
Hide file tree
Showing 41 changed files with 831 additions and 75 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ for Rust libraries in [RFC #1105](https://github.com/rust-lang/rfcs/blob/master/

* Add support for HAVING clauses.

* Added support for SQL functions without arguments for SQLite.

* Diesel CLI will now generate SQL type definitions for SQL types that are not supported by diesel out of the box. It's possible to disable this behavior via the `generate_missing_sql_type_definitions` config option.

### Removed

* All previously deprecated items have been removed.
Expand Down
10 changes: 6 additions & 4 deletions diesel/src/connection/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,14 @@ where
/// If the transaction fails to commit due to a `SerializationFailure` or a
/// `ReadOnlyTransaction` a rollback will be attempted. If the rollback succeeds,
/// the original error will be returned, otherwise the error generated by the rollback
/// will be returned. In the second case the connection should be considered broken
/// as it contains a uncommitted unabortable open transaction.
/// will be wrapped into an `Error::RollbackError` and returned. In the second case
/// the connection should be considered broken as it contains a uncommitted unabortable
/// open transaction.
///
/// If a nested transaction fails to release the corresponding savepoint
/// a rollback will be attempted. If the rollback succeeds,
/// the original error will be returned, otherwise the error generated by the rollback
/// will be returned.
/// will be wrapped into an `Error::RollbackError` and returned.
///
/// # Example
///
Expand Down Expand Up @@ -127,7 +128,8 @@ where
Ok(value)
}
Err(e) => {
Self::TransactionManager::rollback_transaction(self)?;
Self::TransactionManager::rollback_transaction(self)
.map_err(|e| Error::RollbackError(Box::new(e)))?;
Err(e)
}
}
Expand Down
7 changes: 4 additions & 3 deletions diesel/src/expression/array_comparison.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ pub trait MaybeEmpty {
fn is_empty(&self) -> bool;
}

impl<ST, S, F, W, O, L, Of, G, LC> AsInExpression<ST> for SelectStatement<S, F, W, O, L, Of, G, LC>
impl<ST, F, S, D, W, O, LOf, G, H, LC> AsInExpression<ST>
for SelectStatement<F, S, D, W, O, LOf, G, H, LC>
where
ST: SqlType + TypedExpressionType,
Subselect<Self, ST>: Expression<SqlType = ST>,
Expand All @@ -133,10 +134,10 @@ where
}
}

impl<'a, ST, QS, DB> AsInExpression<ST> for BoxedSelectStatement<'a, ST, QS, DB>
impl<'a, ST, QS, DB, GB> AsInExpression<ST> for BoxedSelectStatement<'a, ST, QS, DB, GB>
where
ST: SqlType + TypedExpressionType,
Subselect<BoxedSelectStatement<'a, ST, QS, DB>, ST>: Expression<SqlType = ST>,
Subselect<BoxedSelectStatement<'a, ST, QS, DB, GB>, ST>: Expression<SqlType = ST>,
{
type InExpression = Subselect<Self, ST>;

Expand Down
22 changes: 19 additions & 3 deletions diesel/src/macros/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,22 @@ pub(crate) mod prelude {
};
}

#[macro_export]
#[doc(hidden)]
macro_rules! __diesel_fix_sql_type_import {
($(use $($import:tt)::+;)*) => {
$(
$crate::__diesel_fix_sql_type_import!(@expand_import: $($import)::+);
)*
};
(@expand_import: super:: $($Type:tt)+) => {
use super::super::$($Type)+;
};
(@expand_import: $($Type:tt)+) => {
use $($Type)+;
}
}

#[macro_export]
#[doc(hidden)]
macro_rules! __diesel_column {
Expand Down Expand Up @@ -616,10 +632,10 @@ macro_rules! __diesel_table_impl {
},)+],
) => {
$($meta)*
#[allow(unused_imports, dead_code)]
pub mod $table_name {
#![allow(dead_code)]
$($imports)*
pub use self::columns::*;
$($imports)*

/// Re-exports all of the columns of this table, as well as the
/// table struct renamed to the module name. This is meant to be
Expand Down Expand Up @@ -797,7 +813,7 @@ macro_rules! __diesel_table_impl {
/// Contains all of the columns of this table
pub mod columns {
use super::table;
$($imports)*
$crate::__diesel_fix_sql_type_import!($($imports)*);

#[allow(non_camel_case_types, dead_code)]
#[derive(Debug, Clone, Copy, $crate::query_builder::QueryId)]
Expand Down
6 changes: 3 additions & 3 deletions diesel/src/pg/expression/array_comparison.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,8 @@ where
}
}

impl<ST, S, F, W, O, L, Of, G, FU> AsArrayExpression<ST>
for SelectStatement<S, F, W, O, L, Of, G, FU>
impl<ST, F, S, D, W, O, LOf, G, H, LC> AsArrayExpression<ST>
for SelectStatement<F, S, D, W, O, LOf, G, H, LC>
where
Self: SelectQuery<SqlType = ST>,
{
Expand All @@ -157,7 +157,7 @@ where
}
}

impl<'a, ST, QS, DB> AsArrayExpression<ST> for BoxedSelectStatement<'a, ST, QS, DB>
impl<'a, ST, QS, DB, GB> AsArrayExpression<ST> for BoxedSelectStatement<'a, ST, QS, DB, GB>
where
Self: SelectQuery<SqlType = ST>,
{
Expand Down
1 change: 0 additions & 1 deletion diesel/src/pg/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,6 @@ pub mod sql_types {
pub type BigSerial = crate::sql_types::BigInt;

/// The `UUID` SQL type. This type can only be used with `feature = "uuid"`
/// (uuid <=0.6) or `feature = "uuidv07"` (uuid = 0.7)
///
/// ### [`ToSql`] impls
///
Expand Down
2 changes: 1 addition & 1 deletion diesel/src/query_builder/select_statement/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ where
}
}

impl<'a, ST, QS, DB> CombineDsl for BoxedSelectStatement<'a, ST, QS, DB>
impl<'a, ST, QS, DB, GB> CombineDsl for BoxedSelectStatement<'a, ST, QS, DB, GB>
where
Self: Query,
{
Expand Down
30 changes: 17 additions & 13 deletions diesel/src/query_builder/upsert/into_conflict_clause.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,23 @@ where
// The corresponding impl for`NoWhereClause` is missing because of
// https://www.sqlite.org/lang_UPSERT.html (Parsing Ambiguity)
#[cfg(feature = "sqlite")]
impl<F, S, D, W, O, LOf, G, LC> QueryFragment<crate::sqlite::Sqlite>
for OnConflictSelectWrapper<SelectStatement<F, S, D, WhereClause<W>, O, LOf, G, LC>>
impl<F, S, D, W, O, LOf, G, H, LC> QueryFragment<crate::sqlite::Sqlite>
for OnConflictSelectWrapper<SelectStatement<F, S, D, WhereClause<W>, O, LOf, G, H, LC>>
where
SelectStatement<F, S, D, WhereClause<W>, O, LOf, G, LC>: QueryFragment<crate::sqlite::Sqlite>,
SelectStatement<F, S, D, WhereClause<W>, O, LOf, G, H, LC>:
QueryFragment<crate::sqlite::Sqlite>,
{
fn walk_ast(&self, out: AstPass<crate::sqlite::Sqlite>) -> QueryResult<()> {
self.0.walk_ast(out)
}
}

#[cfg(feature = "sqlite")]
impl<'a, ST, QS> QueryFragment<crate::sqlite::Sqlite>
for OnConflictSelectWrapper<BoxedSelectStatement<'a, ST, QS, crate::sqlite::Sqlite>>
impl<'a, ST, QS, GB> QueryFragment<crate::sqlite::Sqlite>
for OnConflictSelectWrapper<BoxedSelectStatement<'a, ST, QS, crate::sqlite::Sqlite, GB>>
where
BoxedSelectStatement<'a, ST, QS, crate::sqlite::Sqlite>: QueryFragment<crate::sqlite::Sqlite>,
BoxedSelectStatement<'a, ST, QS, crate::sqlite::Sqlite, GB>:
QueryFragment<crate::sqlite::Sqlite>,
QS: crate::query_source::QuerySource,
QS::FromClause: QueryFragment<crate::sqlite::Sqlite>,
{
Expand Down Expand Up @@ -91,11 +93,11 @@ impl<Inner, Tab> IntoConflictValueClause for OwnedBatchInsert<Inner, Tab> {
}
}

impl<F, S, D, W, O, LOf, G, LC, Columns> IntoConflictValueClause
for InsertFromSelect<SelectStatement<F, S, D, W, O, LOf, G, LC>, Columns>
impl<F, S, D, W, O, LOf, G, H, LC, Columns> IntoConflictValueClause
for InsertFromSelect<SelectStatement<F, S, D, W, O, LOf, G, H, LC>, Columns>
{
type ValueClause = InsertFromSelect<
OnConflictSelectWrapper<SelectStatement<F, S, D, W, O, LOf, G, LC>>,
OnConflictSelectWrapper<SelectStatement<F, S, D, W, O, LOf, G, H, LC>>,
Columns,
>;

Expand All @@ -108,11 +110,13 @@ impl<F, S, D, W, O, LOf, G, LC, Columns> IntoConflictValueClause
}
}

impl<'a, ST, QS, DB, Columns> IntoConflictValueClause
for InsertFromSelect<BoxedSelectStatement<'a, ST, QS, DB>, Columns>
impl<'a, ST, QS, DB, GB, Columns> IntoConflictValueClause
for InsertFromSelect<BoxedSelectStatement<'a, ST, QS, DB, GB>, Columns>
{
type ValueClause =
InsertFromSelect<OnConflictSelectWrapper<BoxedSelectStatement<'a, ST, QS, DB>>, Columns>;
type ValueClause = InsertFromSelect<
OnConflictSelectWrapper<BoxedSelectStatement<'a, ST, QS, DB, GB>>,
Columns,
>;

fn into_value_clause(self) -> Self::ValueClause {
let InsertFromSelect { columns, query } = self;
Expand Down
7 changes: 7 additions & 0 deletions diesel/src/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ pub enum Error {
/// by PostgreSQL.
SerializationError(Box<dyn StdError + Send + Sync>),

/// An error occurred during the rollback of a transaction.
///
/// An example of when this error would be returned is if a rollback has
/// already be called on the current transaction.
RollbackError(Box<Error>),

/// Roll back the current transaction.
///
/// You can return this variant inside of a transaction when you want to
Expand Down Expand Up @@ -283,6 +289,7 @@ impl Display for Error {
Error::QueryBuilderError(ref e) => e.fmt(f),
Error::DeserializationError(ref e) => e.fmt(f),
Error::SerializationError(ref e) => e.fmt(f),
Error::RollbackError(ref e) => e.fmt(f),
Error::RollbackTransaction => write!(f, "The current transaction was aborted"),
Error::AlreadyInTransaction => write!(
f,
Expand Down
18 changes: 18 additions & 0 deletions diesel/src/sqlite/connection/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,24 @@ where
Ok(())
}

pub fn register_noargs<RetSqlType, Ret, F>(
conn: &RawConnection,
fn_name: &str,
deterministic: bool,
mut f: F,
) -> QueryResult<()>
where
F: FnMut() -> Ret + std::panic::UnwindSafe + Send + 'static,
Ret: ToSql<RetSqlType, Sqlite>,
Sqlite: HasSqlType<RetSqlType>,
{
conn.register_sql_function(fn_name, 0, deterministic, move |_, _| {
let result = f();
process_sql_function_result::<RetSqlType, Ret>(result)
})?;
Ok(())
}

pub fn register_aggregate<ArgsSqlType, RetSqlType, Args, Ret, A>(
conn: &RawConnection,
fn_name: &str,
Expand Down
35 changes: 35 additions & 0 deletions diesel/src/sqlite/connection/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,21 @@ impl SqliteConnection {
)
}

#[doc(hidden)]
pub fn register_noarg_sql_function<RetSqlType, Ret, F>(
&self,
fn_name: &str,
deterministic: bool,
f: F,
) -> QueryResult<()>
where
F: FnMut() -> Ret + std::panic::UnwindSafe + Send + 'static,
Ret: ToSql<RetSqlType, Sqlite>,
Sqlite: HasSqlType<RetSqlType>,
{
functions::register_noargs(&self.raw_connection, fn_name, deterministic, f)
}

#[doc(hidden)]
pub fn register_aggregate_function<ArgsSqlType, RetSqlType, Args, Ret, A>(
&mut self,
Expand Down Expand Up @@ -432,6 +447,26 @@ mod tests {
assert_eq!(Ok(3), added);
}

sql_function!(fn answer() -> Integer);

#[test]
fn register_noarg_function() {
let connection = &mut SqliteConnection::establish(":memory:").unwrap();
answer::register_impl(&connection, || 42).unwrap();

let answer = crate::select(answer()).get_result::<i32>(connection);
assert_eq!(Ok(42), answer);
}

#[test]
fn register_nondeterministic_noarg_function() {
let connection = &mut SqliteConnection::establish(":memory:").unwrap();
answer::register_nondeterministic_impl(&connection, || 42).unwrap();

let answer = crate::select(answer()).get_result::<i32>(connection);
assert_eq!(Ok(42), answer);
}

sql_function!(fn add_counter(x: Integer) -> Integer);

#[test]
Expand Down
4 changes: 1 addition & 3 deletions diesel_bench/benches/diesel_benches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,8 +199,7 @@ pub fn bench_medium_complex_query(b: &mut Bencher, size: usize) {
use self::users::dsl::*;
let target = users
.left_outer_join(posts::table)
.filter(hair_color.eq("black"))
.order(name.desc());
.filter(hair_color.eq("black"));
target.load::<(User, Option<Post>)>(&mut conn).unwrap()
})
}
Expand All @@ -216,7 +215,6 @@ pub fn bench_medium_complex_query_boxed(b: &mut Bencher, size: usize) {
let target = users
.left_outer_join(posts::table)
.filter(hair_color.eq("black"))
.order(name.desc())
.into_boxed();
target.load::<(User, Option<Post>)>(&mut conn).unwrap()
})
Expand Down
5 changes: 5 additions & 0 deletions diesel_cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,11 @@ pub fn build_cli() -> App<'static, 'static> {
.multiple(true)
.number_of_values(1)
.help("A list of types to import for every table, separated by commas."),
)
.arg(
Arg::with_name("generate-custom-type-definitions")
.long("no-generate-missing-sql-type-definitions")
.help("Generate SQL type definitions for types not provided by diesel"),
);

let config_arg = Arg::with_name("CONFIG_FILE")
Expand Down
6 changes: 6 additions & 0 deletions diesel_cli/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,15 @@ pub struct PrintSchema {
pub patch_file: Option<PathBuf>,
#[serde(default)]
pub import_types: Option<Vec<String>>,
#[serde(default)]
pub generate_missing_sql_type_definitions: Option<bool>,
}

impl PrintSchema {
pub fn generate_missing_sql_type_definitions(&self) -> bool {
self.generate_missing_sql_type_definitions.unwrap_or(true)
}

pub fn schema_name(&self) -> Option<&str> {
self.schema.as_deref()
}
Expand Down
4 changes: 2 additions & 2 deletions diesel_cli/src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use std::fs::{self, File};
use std::io::Write;
use std::path::Path;

enum Backend {
pub enum Backend {
#[cfg(feature = "postgres")]
Pg,
#[cfg(feature = "sqlite")]
Expand All @@ -26,7 +26,7 @@ enum Backend {
}

impl Backend {
fn for_url(database_url: &str) -> Self {
pub fn for_url(database_url: &str) -> Self {
match database_url {
_ if database_url.starts_with("postgres://")
|| database_url.starts_with("postgresql://") =>
Expand Down
Loading

0 comments on commit ec31ccb

Please sign in to comment.