Git Product home page Git Product logo

quaint's Introduction

quaint's People

Contributors

aknuds1 avatar atouchet avatar cprieto avatar cryslith avatar dbussink avatar do4gr avatar dpetrick avatar drewlloyd avatar ejoebstl avatar endor avatar garrensmith avatar grandchaman avatar jannikkeye avatar jkomyno avatar jolg42 avatar kyleu avatar lanny avatar mavilein avatar miguelff avatar pantharshit00 avatar pimeys avatar sevinf avatar spacekookie avatar sytten avatar tomhoule avatar weakky avatar yoshuawuyts avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

quaint's Issues

Some tests are failing on MySQL8 and MariaDB

Overview

Since we added MySQL8 and MariaDB to the tested databases (#315), a couple of tests are now failing. Namely:

  • newdecimal_conversion_is_handled_correctly
  • filtering_by_json_values_does_not_work_but_does_not_crash
  • text_columns_with_non_utf8_encodings_can_be_queried
  • json_array_contains_fun (fixed by #319)
  • json_array_begins_with_fun (fixed by #319)
  • json_array_not_begins_with_fun (fixed by #319)
  • json_array_ends_into_fun (fixed by #319)
  • json_array_not_ends_into_fun (fixed by #319)

These all need to be fixed.

MySQL Date value not supported in current configuration (with features = "chrono")

First of all, thanks for this great library! Really appreciate all the effort you are putting in it.

I am encountering a panic Value of type Date("\'2019-08-07 10:04:50\'") is not supported with the current configuration when reading from a table that has a date value. I have the 'chrono' feature enabled. Cargo.toml excerpt:

quaint = {version = "^0.1.0", features = ["sqlite", "mysql", "chrono"]}

Actual version in use is 0.1.13.

Looking at the code it appears that while the my::Value::Date(year, month, day, hour, min, sec, micro) case is covered, there apparently also is a `my::Value::Date(String)' that should probably be added.

Table looks like this in MySQL:

 CREATE TABLE `urls` (
  `url_id` int(11) NOT NULL AUTO_INCREMENT,
  `url_unit` varchar(64) DEFAULT NULL,
  `url_url` text,
  `url_value` text,
  `url_found` datetime DEFAULT NULL,
  PRIMARY KEY (`url_id`)
) ENGINE=InnoDB AUTO_INCREMENT=51204 DEFAULT CHARSET=utf8mb4
thread 'tokio-runtime-worker' panicked at 'Value of type Date("\'2019-08-07 10:04:50\'") is not supported with the current configuration', <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/quaint-0.1.13/src/connector/mysql/conversion.rs:59:24
stack backtrace:
   0: rust_begin_unwind
             at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/std/src/panicking.rs:493:5
   1: std::panicking::begin_panic_fmt
             at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/std/src/panicking.rs:435:5
   2: quaint::connector::mysql::conversion::<impl quaint::connector::queryable::TakeRow for mysql_common::row::Row>::take_result_row::convert
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/quaint-0.1.13/src/connector/mysql/conversion.rs:59:24
   3: quaint::connector::mysql::conversion::<impl quaint::connector::queryable::TakeRow for mysql_common::row::Row>::take_result_row
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/quaint-0.1.13/src/connector/mysql/conversion.rs:71:22
   4: <quaint::connector::mysql::Mysql as quaint::connector::queryable::Queryable>::query_raw::{{closure}}::{{closure}}::{{closure}}
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/quaint-0.1.13/src/connector/mysql.rs:293:77
   5: mysql_async::queryable::query_result::QueryResult<T,P>::map::{{closure}}
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/mysql_async-0.21.1/src/queryable/query_result/mod.rs:328:31
   6: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
             at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/core/src/future/mod.rs:80:19
   7: mysql_async::queryable::query_result::QueryResult<T,P>::map_and_drop::{{closure}}
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/mysql_async-0.21.1/src/queryable/query_result/mod.rs:342:28
   8: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
             at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/core/src/future/mod.rs:80:19
   9: quaint::connector::mysql::Mysql::timeout::{{closure}}
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/quaint-0.1.13/src/connector/mysql.rs:243:27
  10: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
             at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/core/src/future/mod.rs:80:19
  11: <quaint::connector::mysql::Mysql as quaint::connector::queryable::Queryable>::query_raw::{{closure}}::{{closure}}
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/quaint-0.1.13/src/connector/mysql.rs:293:33
  12: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
             at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/core/src/future/mod.rs:80:19
  13: quaint::connector::metrics::query::{{closure}}
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/quaint-0.1.13/src/connector/metrics.rs:19:19
  14: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
             at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/core/src/future/mod.rs:80:19
  15: <quaint::connector::dbio::DBIO<T> as core::future::future::Future>::poll
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/quaint-0.1.13/src/connector/dbio.rs:25:9
  16: <quaint::connector::mysql::Mysql as quaint::connector::queryable::Queryable>::query::{{closure}}
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/quaint-0.1.13/src/connector/mysql.rs:275:13
  17: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
             at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/core/src/future/mod.rs:80:19
  18: <quaint::connector::dbio::DBIO<T> as core::future::future::Future>::poll
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/quaint-0.1.13/src/connector/dbio.rs:25:9
  19: <quaint::single::Quaint as quaint::connector::queryable::Queryable>::query::{{closure}}
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/quaint-0.1.13/src/single.rs:146:32
  20: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
             at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/core/src/future/mod.rs:80:19
  21: <quaint::connector::dbio::DBIO<T> as core::future::future::Future>::poll
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/quaint-0.1.13/src/connector/dbio.rs:25:9
  22: esplanade::db::database::Database::query::{{closure}}
             at ./src/db/database.rs:142:13
  23: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
             at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/core/src/future/mod.rs:80:19
  24: esplanade::api::query_with_query::{{closure}}
             at ./src/api.rs:248:19
  25: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
             at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/core/src/future/mod.rs:80:19
  26: <F as futures_core::future::TryFuture>::try_poll
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-core-0.3.13/src/future.rs:84:9
  27: <warp::filter::and_then::AndThenFuture<T,F> as core::future::future::Future>::poll
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/warp-0.2.5/src/filter/and_then.rs:82:44
  28: <F as futures_core::future::TryFuture>::try_poll
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-core-0.3.13/src/future.rs:84:9
  29: <warp::filter::recover::RecoverFuture<T,F> as core::future::future::Future>::poll
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/warp-0.2.5/src/filter/recover.rs:91:65
  30: <F as futures_core::future::TryFuture>::try_poll
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-core-0.3.13/src/future.rs:84:9
  31: <warp::filter::or::EitherFuture<T,U> as core::future::future::Future>::poll
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/warp-0.2.5/src/filter/or.rs:87:44
  32: <warp::filter::and::AndFuture<T,U> as core::future::future::Future>::poll
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/warp-0.2.5/src/filter/and.rs:71:44
  33: <F as futures_core::future::TryFuture>::try_poll
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-core-0.3.13/src/future.rs:84:9
  34: <warp::filter::or::EitherFuture<T,U> as core::future::future::Future>::poll
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/warp-0.2.5/src/filter/or.rs:77:65
  35: <F as futures_core::future::TryFuture>::try_poll
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-core-0.3.13/src/future.rs:84:9
  36: <warp::filter::recover::RecoverFuture<T,F> as core::future::future::Future>::poll
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/warp-0.2.5/src/filter/recover.rs:91:65
  37: <F as futures_core::future::TryFuture>::try_poll
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-core-0.3.13/src/future.rs:84:9
  38: <warp::filters::cors::internal::WrappedFuture<F> as core::future::future::Future>::poll
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/warp-0.2.5/src/filters/cors.rs:573:26
  39: <futures_util::future::either::Either<A,B> as core::future::future::Future>::poll
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.13/src/future/either.rs:73:33
  40: <F as futures_core::future::TryFuture>::try_poll
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-core-0.3.13/src/future.rs:84:9
  41: <warp::filter::map::MapFuture<T,F> as core::future::future::Future>::poll
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/warp-0.2.5/src/filter/map.rs:51:22
  42: <F as futures_core::future::TryFuture>::try_poll
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-core-0.3.13/src/future.rs:84:9
  43: <warp::filters::log::internal::WithLogFuture<FN,F> as core::future::future::Future>::poll
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/warp-0.2.5/src/filters/log.rs:257:49
  44: <F as futures_core::future::TryFuture>::try_poll
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-core-0.3.13/src/future.rs:84:9
  45: <warp::filter::service::FilteredFuture<F> as core::future::future::Future>::poll::{{closure}}
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/warp-0.2.5/src/filter/service.rs:128:41
  46: scoped_tls::ScopedKey<T>::set
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/scoped-tls-1.0.0/src/lib.rs:137:9
  47: warp::route::set
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/warp-0.2.5/src/route.rs:17:5
  48: <warp::filter::service::FilteredFuture<F> as core::future::future::Future>::poll
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/warp-0.2.5/src/filter/service.rs:128:15
  49: <hyper::proto::h1::dispatch::Server<S,hyper::body::body::Body> as hyper::proto::h1::dispatch::Dispatch>::poll_msg
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/hyper-0.13.10/src/proto/h1/dispatch.rs:476:31
  50: hyper::proto::h1::dispatch::Dispatcher<D,Bs,I,T>::poll_write
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/hyper-0.13.10/src/proto/h1/dispatch.rs:284:43
  51: hyper::proto::h1::dispatch::Dispatcher<D,Bs,I,T>::poll_loop
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/hyper-0.13.10/src/proto/h1/dispatch.rs:151:21
  52: hyper::proto::h1::dispatch::Dispatcher<D,Bs,I,T>::poll_inner
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/hyper-0.13.10/src/proto/h1/dispatch.rs:127:16
  53: hyper::proto::h1::dispatch::Dispatcher<D,Bs,I,T>::poll_catch
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/hyper-0.13.10/src/proto/h1/dispatch.rs:110:28
  54: <hyper::proto::h1::dispatch::Dispatcher<D,Bs,I,T> as core::future::future::Future>::poll
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/hyper-0.13.10/src/proto/h1/dispatch.rs:411:9
  55: <hyper::server::conn::ProtoServer<T,B,S,E> as core::future::future::Future>::poll
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/hyper-0.13.10/src/server/conn.rs:884:39
  56: <hyper::server::conn::upgrades::UpgradeableConnection<I,S,E> as core::future::future::Future>::poll
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/hyper-0.13.10/src/server/conn.rs:1063:30
  57: <hyper::server::conn::spawn_all::NewSvcTask<I,N,S,E,W> as core::future::future::Future>::poll
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/hyper-0.13.10/src/server/conn.rs:1001:36
  58: tokio::runtime::task::core::Core<T,S>::poll::{{closure}}
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.25/src/runtime/task/core.rs:173:17
  59: tokio::loom::std::unsafe_cell::UnsafeCell<T>::with_mut
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.25/src/loom/std/unsafe_cell.rs:14:9
  60: tokio::runtime::task::core::Core<T,S>::poll
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.25/src/runtime/task/core.rs:158:13
  61: tokio::runtime::task::harness::Harness<T,S>::poll::{{closure}}
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.25/src/runtime/task/harness.rs:107:27
  62: core::ops::function::FnOnce::call_once
             at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/core/src/ops/function.rs:227:5
  63: <std::panic::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once
             at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/std/src/panic.rs:344:9
  64: std::panicking::try::do_call
             at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/std/src/panicking.rs:379:40
  65: __rust_try
  66: std::panicking::try
             at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/std/src/panicking.rs:343:19
  67: std::panic::catch_unwind
             at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/std/src/panic.rs:431:14
  68: tokio::runtime::task::harness::Harness<T,S>::poll
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.25/src/runtime/task/harness.rs:89:19
  69: tokio::runtime::task::raw::poll
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.25/src/runtime/task/raw.rs:104:5
  70: tokio::runtime::task::raw::RawTask::poll
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.25/src/runtime/task/raw.rs:66:18
  71: tokio::runtime::task::Notified<S>::run
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.25/src/runtime/task/mod.rs:169:9
  72: tokio::runtime::thread_pool::worker::Context::run_task::{{closure}}
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.25/src/runtime/thread_pool/worker.rs:349:13
  73: tokio::coop::with_budget::{{closure}}
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.25/src/coop.rs:127:9
  74: std::thread::local::LocalKey<T>::try_with
             at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/std/src/thread/local.rs:272:16
  75: std::thread::local::LocalKey<T>::with
             at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/std/src/thread/local.rs:248:9
  76: tokio::coop::with_budget
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.25/src/coop.rs:120:5
  77: tokio::coop::budget
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.25/src/coop.rs:96:5
  78: tokio::runtime::thread_pool::worker::Context::run_task
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.25/src/runtime/thread_pool/worker.rs:348:9
  79: tokio::runtime::thread_pool::worker::Context::run
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.25/src/runtime/thread_pool/worker.rs:320:24
  80: tokio::runtime::thread_pool::worker::run::{{closure}}
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.25/src/runtime/thread_pool/worker.rs:305:17
  81: tokio::macros::scoped_tls::ScopedKey<T>::set
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.25/src/macros/scoped_tls.rs:63:9
  82: tokio::runtime::thread_pool::worker::run
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.25/src/runtime/thread_pool/worker.rs:302:5
  83: tokio::runtime::thread_pool::worker::Launch::launch::{{closure}}
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.25/src/runtime/thread_pool/worker.rs:281:45
  84: <tokio::runtime::blocking::task::BlockingTask<T> as core::future::future::Future>::poll
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.25/src/runtime/blocking/task.rs:41:21
  85: tokio::runtime::task::core::Core<T,S>::poll::{{closure}}
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.25/src/runtime/task/core.rs:173:17
  86: tokio::loom::std::unsafe_cell::UnsafeCell<T>::with_mut
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.25/src/loom/std/unsafe_cell.rs:14:9
  87: tokio::runtime::task::core::Core<T,S>::poll
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.25/src/runtime/task/core.rs:158:13
  88: tokio::runtime::task::harness::Harness<T,S>::poll::{{closure}}
             at <omitted>/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.25/src/runtime/task/harness.rs:107:27
  89: core::ops::function::FnOnce::call_once
             at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/core/src/ops/function.rs:227:5
  90: <std::panic::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once
             at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/std/src/panic.rs:344:9
  91: std::panicking::try::do_call
             at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/std/src/panicking.rs:379:40
  92: __rust_try
  93: std::panicking::try
             at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/std/src/panicking.rs:343:19
  94: std::panic::catch_unwind
             at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/std/src/panic.rs:431:14
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

Cannot compile master

Hey awesome quaint maintainers :) I'm getting this error when attempting to compile quaint:

   Compiling quaint v0.2.0-alpha.13 (https://github.com/prisma/quaint.git#03a6d66d)
error[E0201]: duplicate definitions with name `visit_not_equals`:
   --> /Users/Max/.cargo/git/checkouts/quaint-9f01e008b9a89c14/03a6d66/src/visitor/postgres.rs:258:5
    |
230 | /     fn visit_not_equals(&mut self, left: Expression<'a>, right: Expression<'a>) -> visitor::Result {
231 | |         // LHS must be cast to json/xml-text if the right is a json/xml-text value and vice versa.
232 | |         let right_cast = match left {
233 | |             #[cfg(feature = "json-1")]
...   |
254 | |         Ok(())
255 | |     }
    | |_____- previous definition of `visit_not_equals` here
...
258 | /     fn visit_not_equals(&mut self, left: Expression<'a>, right: Expression<'a>) -> visitor::Result {
259 | |         self.visit_expression(left)?;
260 | |         self.write(" <> ")?;
261 | |         self.visit_expression(right)
262 | |     }
    | |_____^ duplicate definition

error: aborting due to previous error

In case it helps, here are my cargo dependencies:

[dependencies]
tokio = { version = "0.2", features = ["full"]}
quaint = { git = "https://github.com/prisma/quaint.git", features = ["full-mssql"]}

and here's my silly test main.rs:

use quaint::{prelude::*, pooled::Quaint};

// assuming a local mssql instance started via:
// docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=<YourStrong@Passw0rd>' -p 1433:1433 -d mcr.microsoft.com/mssql/server:2017-latest

#[tokio::main]
async fn main() -> Result<(), quaint::error::Error> {
    let dsn = "sqlserver://127.0.0.1:1433;database=master;user=SA;password=<YourStrong@Passw0rd>;trustServerCertificate=true;encrypt=DANGER_PLAINTEXT";
    let pool = Quaint::builder(dsn)?.build();
    let conn = pool.check_out().await?;
    let result = conn.select(Select::default().value(1)).await?;

    assert_eq!(
        Some(1),
        result.into_iter().nth(0).and_then(|row| row[0].as_i64()),
    );

    Ok(())
}

Clean-up of our feature flags

Our feature flags are a mess. We should clean them up and run more feature combinations on CI before merging anything.

Generic interface to obtain schema information

Loving quaint so far - we are using it to build an OData service in front of a database.

In our use case we are querying the database for schema information (list schemas, list tables, get column info). This can be done in both MySQL, SQLite and PostgreSQL using queries, but the interface slightly differs in each case (i.e. in SQLite you need to query the sqlite_master schema and use PRAGMA table_info(table_name), whereas in MySQL and PostgreSQL you would query the information_schema).

Having methods in quaint that list schemas/tables would be very convenient and not at all difficult to implement. Having a way to obtain column information would be even better (but would require that quaint 'understands' the type names returned by the database and map them to some common set of types to be actually useful).

`connector` module is unavailable with default features.

Hi,

The connector module is not available without activating at least one backend feature. This makes it impossible to build a backend-independent crate that only uses the traits defined in this module. Is there a reason for that? Why can't I have access to the connector::Queryable trait?

Bigdecimal conversion in Postgres is limited to u128

What the title says. The lib doesn't currently support the variable numeric type: https://www.postgresql.org/docs/9.1/datatype-numeric.html which says up to 131072 digits before the decimal point; up to 16383 digits after the decimal point. It crashes if it's used with a numeric type beyond 2^128 because of the code in this function: https://github.com/prisma/quaint/blob/main/src/connector/postgres/conversion/decimal.rs#L81

Opinions on the best way to fix it? I can try submitting a PR if I get some time this week.

I realised that the PR #344 only stops the crash but the underlying issue is that large numeric types aren't supported

PostgreSQL: Support `options` connection string parameter

PostgreSQL supports an options parameter for connection strings:

Specifies command-line options to send to the server at connection start. For example, setting this to -c geqo=off sets the session's value of the geqo parameter to off. Spaces within this string are considered to separate command-line arguments, unless escaped with a backslash (); write \ to represent a literal backslash.

https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-OPTIONS

Cockroach Cloud for example uses that to submit the cluster name when a connection is created: ...?options=--cluster%3D{{CLUSTER_NAME}}

Our PostgreSQL driver Tokio-Postgres also support this parameter:

options - Command line options used to configure the server.

https://docs.rs/tokio-postgres/latest/tokio_postgres/config/struct.Config.html

Right now it seems we are filtering this value out of the connection string, or at least not forwarding it to Tokio-Postgres: https://prisma.github.io/quaint/src/quaint/connector/postgres.rs.html#267

It would be great if we could enable Prisma to use the options parameter in PostgreSQL connection strings.

Discard Connection after aborted Transaction

Here we introduced a transaction around DDL operations in order to abort invalid enum migrations. prisma/prisma-engines#1016

When the transaction fails without an explicit rollback being submitted next, the following statement will reuse the same connection and error. See here: https://stackoverflow.com/questions/10399727/psqlexception-current-transaction-is-aborted-commands-ignored-until-end-of-tra

We should look into how Quaint could handle this case.

Change default postgres settings

Write-up of the issue: prisma/specs#325

We discussed it with Matt and Jan, and decided that for now, we should align on what all other clients are doing, i.e. accept invalid (=not trusted) ssl certificates by default.

SQLx now supports MSSQL.

If you'd like to pull more of the connector responsibility out of quaint, SQLx's MSSQL support might be a way to do that. I know this is an odd call-out since you guys maintain tiberius :) Perhaps the SQLx devs could leverage the awesome work that's gone in to tiberius.

Sqlite connector's use of schema-names doesn't work properly

The sqlite connector opens a new in-memory database connection, then executes a command like ATTACH /path/to/database AS quaint;. This results in the main schema being the in-memory one, and the quaint schema being the actual database. This is a problem for the following reasons:

  • The default schema for queries is main, and this cannot be changed. Thus, unqualified queries like SELECT * FROM my_table are executed against the in-memory database.
  • You can use an alternate schema by prepending the schema name to the table name, as in SELECT * FROM quaint.my_table. However, there are a couple problems with that.
    • quaint's visitor implementation (correctly, imo) surrounds table names with quotes, making it impossible to write the above query (you get SELECT * FROM "quaint.my_table" instead).
    • Doing this would require the code to know the schema name in advance, which defeats the purpose of dynamically specifying it in the database URL.

The net result of this situation is that all queries get executed against the in-memory database, rather than the database on disk. I think the simplest way to resolve this would be to drop the db_name functionality and avoid using schema-names other than main entirely, since sqlite doesn't have any way to select a default schema to use, unlike e.g. Postgres's \connect or MySQL's use statements.

I couldn't find any way around this issue to execute commands against the database on disk, but please let me know if I missed something obvious.

Assign an alias to a value column

First, thank you, the library is awesome.

Second, I'm having difficulty understanding how to add an alias to an aggregate column. Specifically when using the aggregate_to_string function (as seen below).

    Select::from_table("employee")
        .column(("employee", "id"))
        .column(("employee", "created"))
        .column(("employee", "updated"))
        .column(("employee", "deleted"))
        .column(("employee", "casino_id"))
        .column(("employee", "uuid"))
        .column(("employee", "name_first"))
        .column(("employee", "name_last"))
        .column(("employee", "title"))
        .value(aggregate_to_string(Column::from(("role", "display"))))
        .inner_join(join_credential)
        .inner_join(join_credential_role)
        .inner_join(join_role)
        .group_by(Column::from(("employee", "id")))

Is it possible to assign an alias to the .value(aggregate_to_string(Column::from(("role", "display"))))?

Reuse arguments on building

Hi !

Some database specific features are missing from this library. Rather than implementing everyone of them. It would be nice to be able to reuse an argument vectors, so that when concatenating queries, the arguments will be correctly numbered.

Something like (pseudo-code) :

let main_insert = Insert::single_into("my_table")
	.value("foo", 10)
	.build()
	.returning("id");
let following_insert = Insert::single_into("my_dep_table")
	.value("foo", 10)
	.value("main_id", Select::from_table("main_insert").column("id"))
	.build()
	.returning("id");
let final_select = Select::from_table("main_insert")
	.and_from("following_insert")
	.column(Column::from(("main_insert", "id")).alias("main_insert_id"))
	.column(Column::from(("following_insert", "id")).alias("following_insert_id"));
let params: Vec<Value<'_>> = Vec::with_capacity(128);
let (main_insert_query, params) = Postgres::build_with_params(main_insert, params);
let (following_insert_query, params) = Postgres::build_with_params(following_insert, params);
let (final_select_query, params) = Postgres::build_with_params(final_select, params);
let query = format!("WITH 'main_insert' AS ({}), 'following_insert' AS ({}) {};",
	main_insert_query, following_insert_query, final_select_query);

The `Sqlite` connector always create in-memory databases.

This is something I had to discover the hard way, since it is not documented.

Even while it takes a file path as parameter, Sqlite::new does not open the file but creates an in-memory database. The method attach_database seems to used to attach the file afterward? This is quite weird to be honest.

If Sqlite::new takes a file name, then it should use the given file as main schema. If you want to keep new to create in-memory database, I would advocate removing its input parameter and add a new Sqlite::open method to open an on-disk file.

Also the method attach_database should comply to the sqlite semantics: take a file name and a schema name, and bind them together.

ExpressionKind members have large size differences

Function(Function<'a>),
and
Query(Select<'a>),
are marked by clippy as 500 bytes, with the second-largest member being 40 bytes. Adding an intermediate box will likely help improve allocations / performance.

You can get this output by running:

$ cargo +nightly clippy

Thanks!

Output

warning: large size difference between variants
   --> src\ast\expression.rs:170:5
    |
170 |     Function(Function<'a>),
    |     ^^^^^^^^^^^^^^^^^^^^^^ this variant is 536 bytes
    |
    = note: `#[warn(clippy::large_enum_variant)]` on by default
note: and the second-largest variant is 40 bytes:
   --> src\ast\expression.rs:162:5
    |
162 |     RawValue(Raw<'a>),
    |     ^^^^^^^^^^^^^^^^^
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant
help: consider boxing the large fields to reduce the total size of the enum
    |
170 |     Function(Box<Function<'a>>),
    |              ^^^^^^^^^^^^^^^^^

warning: large size difference between variants
  --> src\ast\table.rs:22:5
   |
22 |     Query(Select<'a>),
   |     ^^^^^^^^^^^^^^^^^ this variant is 296 bytes
   |
note: and the second-largest variant is 32 bytes:
  --> src\ast\table.rs:21:5
   |
21 |     Table(Cow<'a, str>),
   |     ^^^^^^^^^^^^^^^^^^^
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant
help: consider boxing the large fields to reduce the total size of the enum
   |
22 |     Query(Box<Select<'a>>),
   |           ^^^^^^^^^^^^^^^

Quaint seqfaults with empty SQLite commands

Reproducer:

use quaint::pooled::Quaint;
use quaint::prelude::*;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    let q = Quaint::new("sqlite:test.db").await?;
    let c  = q.check_out().await?;
    c.execute_raw("", &[]).await?;
    Result::Ok(())
}

Backtrace:

  * frame #0: 0x00005555557bc69c quaint-test`sqlite3_clear_bindings(pStmt=0x0000000000000000) at sqlite3.c:81610:40
    frame #1: 0x000055555576df82 quaint-test`rusqlite::raw_statement::RawStatement::clear_bindings::h343c364d834a7c75(self=0x00007fffffff9d50) at raw_statement.rs:95:18
    frame #2: 0x00005555557717d5 quaint-test`rusqlite::cache::StatementCache::cache_stmt::h7a92c872dee251b7(self=0x0000555555a99250, stmt=(__0 = 0x0000000000000000)) at cache.rs:139:9
    frame #3: 0x000055555577137e quaint-test`_$LT$rusqlite..cache..CachedStatement$u20$as$u20$core..ops..drop..Drop$GT$::drop::h36e26cdc88cefec4(self=0x00007fffffff9f10) at cache.rs:86:13
    frame #4: 0x0000555555763977 quaint-test`core::ptr::drop_in_place::h920545ed40fe7c7a((null)=0x00007fffffff9f10) at mod.rs:177:1
    frame #5: 0x000055555562fd81 quaint-test`_$LT$quaint..connector..sqlite..Sqlite$u20$as$u20$quaint..connector..queryable..Queryable$GT$::execute_raw::_$u7b$$u7b$closure$u7d$$u7d$::_$u7b$$u7b$closure$u7d$$u7d$::h2fd5e94fff290f82 at sqlite.rs:205:13
    frame #6: 0x000055555562fea1 quaint-test`_$LT$quaint..connector..sqlite..Sqlite$u20$as$u20$quaint..connector..queryable..Queryable$GT$::execute_raw::_$u7b$$u7b$closure$u7d$$u7d$::h88ce23e985472900 at sqlite.rs:207:19
    frame #7: 0x00005555556108ae quaint-test`quaint::connector::metrics::query::_$u7b$$u7b$closure$u7d$$u7d$::h1fb49f99e7b8e4ec((null)=<unavailable>) at metrics.rs:19:19
    frame #8: 0x0000555555615cdf quaint-test`_$LT$std..future..GenFuture$LT$T$GT$$u20$as$u20$core..future..future..Future$GT$::poll::h9f2b432ea5ca4614(self=Pin<&mut std::future::GenFuture<generator-0>> @ 0x00007fffffffa720, cx=0x00007fffffffb5f0) at future.rs:44:15
    frame #9: 0x000055555563deb9 quaint-test`_$LT$quaint..connector..dbio..DBIO$LT$T$GT$$u20$as$u20$core..future..future..Future$GT$::poll::he066444a35b3d1db(self=Pin<&mut quaint::connector::dbio::DBIO<u64>> @ 0x00007fffffffa780, ctx=0x00007fffffffb5f0) at dbio.rs:25:9
    frame #10: 0x000055555561486d quaint-test`std::future::poll_with_tls_context::h64437bc63477017d(f=Pin<&mut quaint::connector::dbio::DBIO<u64>> @ 0x00007fffffffa818) at future.rs:99:14
    frame #11: 0x00005555555e59fe quaint-test`quaint_test::main::_$u7b$$u7b$closure$u7d$$u7d$::h17c3c46f3093e878((null)=<unavailable>) at main.rs:8:5
    frame #12: 0x00005555555e4702 quaint-test`_$LT$std..future..GenFuture$LT$T$GT$$u20$as$u20$core..future..future..Future$GT$::poll::h71fdd89390940c42(self=Pin<&mut std::future::GenFuture<generator-0>> @ 0x00007fffffffb390, cx=0x00007fffffffb5f0) at future.rs:44:15
    frame #13: 0x00005555555fc6b6 quaint-test`tokio::runtime::enter::Enter::block_on::_$u7b$$u7b$closure$u7d$$u7d$::h3e459cfe52175f05 at enter.rs:101:58
    frame #14: 0x00005555555bd6da quaint-test`tokio::coop::budget::_$u7b$$u7b$closure$u7d$$u7d$::h89bc075f7eb66002(hits=0x00007ffff7c0a2d8) at coop.rs:97:9
    frame #15: 0x00005555555d1d82 quaint-test`std::thread::local::LocalKey$LT$T$GT$::try_with::h3668363ab3b1f608(self=0x0000555555a27c38, f=closure-0 @ 0x00007fffffffb4f0) at local.rs:262:16
    frame #16: 0x00005555555d14fd quaint-test`std::thread::local::LocalKey$LT$T$GT$::with::hc82aeb690e204b0f(self=0x0000555555a27c38, f=closure-0 @ 0x00007fffffffb568) at local.rs:239:9
    frame #17: 0x00005555555fc543 quaint-test`tokio::runtime::enter::Enter::block_on::h7890a791e1399f56 [inlined] tokio::coop::budget::h28f55ca60abb5d42(f=closure-0 @ 0x00007fffffffb698) at coop.rs:79:5
    frame #18: 0x00005555555fc50f quaint-test`tokio::runtime::enter::Enter::block_on::h7890a791e1399f56(self=0x00007fffffffb6f0, f=(__0 = quaint_test::main::generator-0 @ 0x00007fffffffb710)) at enter.rs:101
    frame #19: 0x00005555555fec5f quaint-test`tokio::runtime::thread_pool::ThreadPool::block_on::h392433f9e3cb7450(self=0x00007fffffffd2e0, future=(__0 = quaint_test::main::generator-0 @ 0x00007fffffffc298)) at mod.rs:82:9
    frame #20: 0x00005555555bf699 quaint-test`tokio::runtime::Runtime::block_on::_$u7b$$u7b$closure$u7d$$u7d$::he2e7354750fff41d at mod.rs:420:39
    frame #21: 0x00005555555caa1e quaint-test`tokio::runtime::context::enter::hb24868dd9b9fc1a5(new=<unavailable>, f=closure-0 @ 0x00007fffffffcaf8) at context.rs:72:5
    frame #22: 0x00005555555d575b quaint-test`tokio::runtime::handle::Handle::enter::h6817f5ac891ddcb7(self=0x00007fffffffd380, f=closure-0 @ 0x00007fffffffcef0) at handle.rs:39:9
    frame #23: 0x00005555555bf5cd quaint-test`tokio::runtime::Runtime::block_on::h4a50a777093425e4(self=0x00007fffffffd2d8, future=<unavailable>) at mod.rs:415:9
    frame #24: 0x00005555555fca6f quaint-test`quaint_test::main::hc13577d9a723c273 at main.rs:4:1
    frame #25: 0x00005555555ce97b quaint-test`std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::h1951a0cef2c0ae64 at rt.rs:67:34
    frame #26: 0x00005555558f3f2f quaint-test`std::rt::lang_start_internal::h0962c0aa989e5c64 [inlined] std::rt::lang_start_internal::_$u7b$$u7b$closure$u7d$$u7d$::he55e3739ea41259e at rt.rs:52:13
    frame #27: 0x00005555558f3f24 quaint-test`std::rt::lang_start_internal::h0962c0aa989e5c64 [inlined] std::panicking::try::do_call::h73e24f9817ae57df at panicking.rs:331
    frame #28: 0x00005555558f3f24 quaint-test`std::rt::lang_start_internal::h0962c0aa989e5c64 [inlined] std::panicking::try::hd08eb281999526b6 at panicking.rs:274
    frame #29: 0x00005555558f3f24 quaint-test`std::rt::lang_start_internal::h0962c0aa989e5c64 [inlined] std::panic::catch_unwind::hc981e5be87497715 at panic.rs:394
    frame #30: 0x00005555558f3f24 quaint-test`std::rt::lang_start_internal::h0962c0aa989e5c64 at rt.rs:51
    frame #31: 0x00005555555ce957 quaint-test`std::rt::lang_start::h252a346e8020a484(main=(quaint-test`quaint_test::main::hc13577d9a723c273 at main.rs:4), argc=1, argv=0x00007fffffffdf18) at rt.rs:67:5
    frame #32: 0x00005555555fcb1a quaint-test`main + 42
    frame #33: 0x00007ffff7d78023 libc.so.6`__libc_start_main + 243
    frame #34: 0x00005555555bd30e quaint-test`_start + 46

Union on queries

Hi !

Would'nt it be nice to be able to UNION together more than just SELECT ? Like the returning data from INSERT, UPDATE and DELETE (Postgres only)

Would it mean that the Visitor::visit_union should'nt be provided anymore and implemented at the visitor level ?

SQLx

While I've been considering our shift from separate SQL crates to SQLx, our recent move to a different runtime (async-std) adds another reason to consider it as the interface to the open source databases in Quaint.

What is SQLx?

  • A standardized interface to several SQL databases.
  • Connectors for PostgreSQL, MySQL and SQLite
  • Parameter conversion to the underlying databases
  • Written in Rust, no unsafe code

Points to consider for using it:

  • Would allow us to use async-std without running a separate tokio runtime in Prisma (speed, simplicity)
  • Would give us statement caching (configurable) for all three databases
  • Would reduce the amount of code in Quaint (no need to maintain separate conversion and connection setup)
  • Would give us an easy access to new databases when SQLx gets support

Prisma is anyhow stuck now with old version of Tokio due to their latest runtime performing really bad with MySQL. QE is also now ran on top of async-std so we could benefit from the Tide HTTP server and to get Unix pipe and Windows named pipe support in the near future. Due to our database crates being based on Tokio, this means we still need an extra Tokio runtime for database actions, which adds to our memory usage and which might cause trouble in the future (more moving parts).

It also helps to have one of the async-std authors in the house (yay).

What would be the work items to get this done?

  • Replace tokio-postgres in Quaint with SQLx (#149)
  • Replace mysql_async in Quaint with SQLx (#150)
  • And replace rusqlite with SQLx (#151)

With the upcoming change to support SQL Server, and the upcoming change on Tiberius to be runtime-independent, we could then make Quaint to support both: Tokio and async-std with a feature flag (#152).

No condition is translated as 1=1 for OR

The visitor always translates a ConditionTree::NoCondition as 1=1, which leads to the unexpected outcome that for an OR filter, the entire expression becomes truthy.

After a cursory inspection of the visitor, I believe a fix would require the visitor to have context about the parent, which it isn't designed to have at the moment (as far as I can tell).

Removal of panics

With the upcoming changes for mssql, we get result types in the visitors and don't need to panic anymore in cases where user wants to use types such as Array in databases that do not support them (everything else except PostgreSQL).

Remove all places of panic!, unimplemented! etc. and replace them with proper error types.

Run CI on GitHub Actions

Now we can't run tests from 3rd party pull requests. We could move our test runs to GitHub actions, which would make it easier for people to write pull requests. And, additionally, we could run the tests on platforms such as Windows and macOS.

Mobc 0.7.2 will introduce retry

I wanted to create the issue so we don't forget it.
Basically due to this PR importcjj/mobc#54, if the health check fails it will retry to get a connection.
This is a good behaviour in general, but prisma decided to fail on all broken connections and defer to the client what to do.
This will break this consistent behaviour since sometimes it will retry broken connections (mobc health check) and sometimes it won't (failed perform_io).
A quick fix is to set the max_bad_conn_retries to 0 (currently we use the default of two)

Support set variables

Support set variables for certain SQL dialects.

  • MySQL, SET [GLOBAL | SESSION] [@]variable = value;
  • PostgreSQL, SET [LOCAL | SESSION] variable [=|TO] value

SQL Server cannot set a variable without declaring it first:

DECLARE @variable INT;
SET @variable = 1;

In MySQL, the prefix @ is optional while in SQL Server is required.

SQLite does not support setting variables.

Compile error for 0.2.0-alpha.13

Features enabled: "sqlite", "mysql", "chrono"

   Compiling quaint v0.2.0-alpha.13
error[E0599]: no variant or associated item named `DateTime` found for enum `values::Value<'_>` in the current scope
  --> /Users/work/.cargo/registry/src/github.com-1ecc6299db9ec823/quaint-0.2.0-alpha.13/src/connector/sqlite/conversion.rs:40:63
   |
40 |                     Some("DATE") | Some("DATETIME") => Value::DateTime(None),
   |                                                               ^^^^^^^^ variant or associated item not found in `values::Value<'_>`
   | 
  ::: /Users/work/.cargo/registry/src/github.com-1ecc6299db9ec823/quaint-0.2.0-alpha.13/src/ast/values.rs:44:1
   |
44 | pub enum Value<'a> {
   | ------------------ variant or associated item `DateTime` not found here

Getting started with postgres

Issue

I'm trying to use quaint with postgres, and I'm having trouble building/using quaint.

Context

rustup 1.24.3 (ce5817a94 2021-05-31)
rustc 1.57.0-nightly (308dffd25 2021-09-22)
cargo 1.57.0-nightly (9a28ac83c 2021-09-18)

Cargo.toml

[package]
name = "my-quaint-example"
version = "0.1.0"
edition = "2021"

[dependencies]
quaint = { version = "0.1.13", features = ["pooled"] }
tokio = { version = "1.12.0", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
async-trait = "0.1.51"

Import errors

I get errors when I try to import pooled or single, as outlined here.
I've tried using a bunch of different combinations of the following features in Cargo.toml, but I can't get the imports to resolve:

  • pooled
  • single
  • full
  • full-postgresql
  • full-mysql
use async_trait::async_trait;
use quaint::{pooled::Quaint, prelude::*};
// use quaint::{prelude::*, single::Quaint};
use serde::{Deserialize, Serialize};
unresolved imports `quaint::pooled`, `quaint::single`
could not find `pooled` in `quaint`

Build errors

When I try to use any of the postgres features (ie full-postgresql), I get build errors:

Compiling rust_decimal v1.16.0
error[E0432]: unresolved import `byteorder`
   --> /Users/me/.cargo/registry/src/github.com-1ecc6299db9ec823/rust_decimal-1.16.0/src/db.rs:466:9
    |
466 |     use byteorder::{BigEndian, ReadBytesExt};
    |         ^^^^^^^^^ use of undeclared crate or module `byteorder`

error[E0432]: unresolved import `bytes`
   --> /Users/me/.cargo/registry/src/github.com-1ecc6299db9ec823/rust_decimal-1.16.0/src/db.rs:467:9
    |
467 |     use bytes::{BufMut, BytesMut};
    |         ^^^^^ use of undeclared crate or module `bytes`

error[E0599]: no method named `read_u16` found for struct `std::io::Cursor` in the current scope
   --> /Users/me/.cargo/registry/src/github.com-1ecc6299db9ec823/rust_decimal-1.16.0/src/db.rs:526:34
    |
526 |             let num_groups = raw.read_u16::<BigEndian>()?;
    |                                  ^^^^^^^^ method not found in `std::io::Cursor<&[u8]>`
    |
   ::: /Users/me/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.12.0/src/io/util/async_read_ext.rs:424:16
    |
424 |             fn read_u16(&mut self) -> ReadU16;
    |                -------- the method is available for `Pin<&mut std::io::Cursor<&[u8]>>` here
    |
    = help: items from traits can only be used if the trait is in scope
help: consider wrapping the receiver expression with the appropriate type
    |
526 |             let num_groups = Pin::new(&mut raw).read_u16::<BigEndian>()?;
    |                              +++++++++++++    +
help: the following traits are implemented but not in scope; perhaps add a `use` for one of them:
    |
464 |     use gimli::endianity::Endianity;
    |
464 |     use gimli::read::reader::Reader;
    |
464 |     use object::endian::Endian;
    |
464 |     use byteorder::io::ReadBytesExt;
    |
      and 1 other candidate

error[E0599]: no method named `read_i16` found for struct `std::io::Cursor` in the current scope
   --> /Users/me/.cargo/registry/src/github.com-1ecc6299db9ec823/rust_decimal-1.16.0/src/db.rs:527:30
    |
527 |             let weight = raw.read_i16::<BigEndian>()?; // 10000^weight
    |                              ^^^^^^^^ method not found in `std::io::Cursor<&[u8]>`
    |
   ::: /Users/jlymecargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.12.0/src/io/util/async_read_ext.rs:462:16
    |
462 |             fn read_i16(&mut self) -> ReadI16;
    |                -------- the method is available for `Pin<&mut std::io::Cursor<&[u8]>>` here
    |
    = help: items from traits can only be used if the trait is in scope
help: consider wrapping the receiver expression with the appropriate type
    |
527 |             let weight = Pin::new(&mut raw).read_i16::<BigEndian>()?; // 10000^weight
    |                          +++++++++++++    +
help: the following traits are implemented but not in scope; perhaps add a `use` for one of them:
    |
464 |     use gimli::endianity::Endianity;
    |
464 |     use gimli::read::reader::Reader;
    |
464 |     use object::endian::Endian;
    |
464 |     use byteorder::io::ReadBytesExt;
    |
      and 1 other candidate

error[E0599]: no method named `read_u16` found for struct `std::io::Cursor` in the current scope
   --> /Users/me/.cargo/registry/src/github.com-1ecc6299db9ec823/rust_decimal-1.16.0/src/db.rs:529:28
    |
529 |             let sign = raw.read_u16::<BigEndian>()?;
    |                            ^^^^^^^^ method not found in `std::io::Cursor<&[u8]>`
    |
   ::: /Users/me/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.12.0/src/io/util/async_read_ext.rs:424:16
    |
424 |             fn read_u16(&mut self) -> ReadU16;
    |                -------- the method is available for `Pin<&mut std::io::Cursor<&[u8]>>` here
    |
    = help: items from traits can only be used if the trait is in scope
help: consider wrapping the receiver expression with the appropriate type
    |
529 |             let sign = Pin::new(&mut raw).read_u16::<BigEndian>()?;
    |                        +++++++++++++    +
help: the following traits are implemented but not in scope; perhaps add a `use` for one of them:
    |
464 |     use gimli::endianity::Endianity;
    |
464 |     use gimli::read::reader::Reader;
    |
464 |     use object::endian::Endian;
    |
464 |     use byteorder::io::ReadBytesExt;
    |
      and 1 other candidate

error[E0599]: no method named `read_u16` found for struct `std::io::Cursor` in the current scope
   --> /Users/me/.cargo/registry/src/github.com-1ecc6299db9ec823/rust_decimal-1.16.0/src/db.rs:531:29
    |
531 |             let scale = raw.read_u16::<BigEndian>()?;
    |                             ^^^^^^^^ method not found in `std::io::Cursor<&[u8]>`
    |
   ::: /Users/me/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.12.0/src/io/util/async_read_ext.rs:424:16
    |
424 |             fn read_u16(&mut self) -> ReadU16;
    |                -------- the method is available for `Pin<&mut std::io::Cursor<&[u8]>>` here
    |
    = help: items from traits can only be used if the trait is in scope
help: consider wrapping the receiver expression with the appropriate type
    |
531 |             let scale = Pin::new(&mut raw).read_u16::<BigEndian>()?;
    |                         +++++++++++++    +
help: the following traits are implemented but not in scope; perhaps add a `use` for one of them:
    |
464 |     use gimli::endianity::Endianity;
    |
464 |     use gimli::read::reader::Reader;
    |
464 |     use object::endian::Endian;
    |
464 |     use byteorder::io::ReadBytesExt;
    |
      and 1 other candidate

error[E0599]: no method named `read_u16` found for struct `std::io::Cursor` in the current scope
   --> /Users/me/.cargo/registry/src/github.com-1ecc6299db9ec823/rust_decimal-1.16.0/src/db.rs:536:33
    |
536 |                 groups.push(raw.read_u16::<BigEndian>()?);
    |                                 ^^^^^^^^ method not found in `std::io::Cursor<&[u8]>`
    |
   ::: /Users/me/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.12.0/src/io/util/async_read_ext.rs:424:16
    |
424 |             fn read_u16(&mut self) -> ReadU16;
    |                -------- the method is available for `Pin<&mut std::io::Cursor<&[u8]>>` here
    |
    = help: items from traits can only be used if the trait is in scope
help: consider wrapping the receiver expression with the appropriate type
    |
536 |                 groups.push(Pin::new(&mut raw).read_u16::<BigEndian>()?);
    |                             +++++++++++++    +
help: the following traits are implemented but not in scope; perhaps add a `use` for one of them:
    |
464 |     use gimli::endianity::Endianity;
    |
464 |     use gimli::read::reader::Reader;
    |
464 |     use object::endian::Endian;
    |
464 |     use byteorder::io::ReadBytesExt;
    |
      and 1 other candidate

Some errors have detailed explanations: E0432, E0599.
For more information about an error, try `rustc --explain E0432`.
error: could not compile `rust_decimal` due to 7 previous errors

Examples

Are there code examples I can use to figure out what I'm missing in my Cargo.toml & code?

Clone connection pool

I really like quaint so far however I would like to use it in a web but I'm not able to currently as the connection pool looks like clone isn't implemented or it is private. Here's an example with actix-web:

let pool = Quaint::new("postgres:////user:password@host/database").await?;

actix_web::HttpServer::new(move || {
        actix_web::App::new()
            .data(pool.clone())
            .service(routes::routes())
    })
    .bind(format!("0.0.0.0:{}", port))?
    .run()
    .await?;

Bad connection reused between health checks

Consider the following path:

  1. Client ask Quaint for a connection
  2. Quaint ask mobc for a connectio
  3. If connection was checked recently (15s timeout in engine), return it directly
  4. Client tries to use connection, but it is broken
  5. Client drops the object and return an error
  6. The connection is returned to the pool

So in between health checks, a connection is always returned to the pool even if it is broken.
There is a mechanism in place in mobc to prevent a connection from re-entering the pool:
https://github.com/importcjj/mobc/blob/master/src/lib.rs#L648

Currently the manager always return true (https://github.com/importcjj/mobc/blob/master/src/lib.rs#L187) since it doesn't override the method validate from the Manager trait (https://github.com/prisma/quaint/blob/master/src/pooled/manager.rs#L74).
This means we needs to store information in the connection that the manager can read to deny re-entry. Unfortunately the current Queryable interface doesn't take a mutable reference to self so we would need to change that first for all methods (https://github.com/prisma/quaint/blob/master/src/connector/queryable.rs#L19) and then we could add a method is_dead or in_error to that the validate function would call.

I can do the changes, but I wanted to check with the team before since it is significant.

Release 0.2 to crates.io

Sigh, this is kind of a tough one. But it would be great to be able to finally cut a release to crates.io. What's stopping us?

Now, we could fork tokio_postgres to our own set of crates, release them to crates.io and cut a release. But that would kind of be horrible idea for maintaining.

The other idea is to complete the SQLx transition (#138) and related tasks that triggered bugs with certain Postgres types in our quite dynamic setup. This needs some work on their side too.

MySQL Error: column() vs. columns()

Hi guys,

First, thanks for releasing this project. The flexibility it provides is exactly what I was looking for and I appreciate you opening it up to the community.

That said, I was trying to use the package and having a heck of a time (I almost gave up on it) because I kept running into an error, even when I was practically copy-pasting examples from the documentation. After further digging I've narrowed the issue down to the columns() method in the query builder which doesn't seem to play nice with MySQL 5.6 which I was testing on. I don't know if the same issue persists on all versions of MySQL, but I figured I'd inform you guys. (Or maybe I'm doing something wrong and need to be educated?).

In the code below I attempt to run the same query and get the results, first using multiple column() calls, and the second with a single columns() call. Here's the code, then I'll post the results I get after:

CODE

#[derive(Debug, PartialEq, Eq)]
pub struct User {
  pub user_id: Option<i64>,
  pub first_name: Option<String>,
  pub last_name: Option<String>,
}

// Setup
let pool = Quaint::new("mysql://root:[email protected]:3306/some_database").await?;
let conn = pool.check_out().await?;

// ///////////////////////////////////////////////////////////
// First query with each column specified individually - WORKS
// ///////////////////////////////////////////////////////////
println!("\r\n\r\n#################  FIRST QUERY  #################\r\n");

// Build query
let query1 = Select::from_table("users")
  .column("user_id")
  .column("first_name") 
  .column("last_name")
  .limit(5);

// Output the SQL generated
let (sql_str1, params) = Mysql::build(query1.clone());
println!("{}", sql_str1);

// Run the query and print the number of returned results
let results = conn.query(Query::from(query1)).await.unwrap();
println!("Number of results: {}", results.len());

// Try grabbing and printing the first result
if let Some(row) = results.get(0) {
  println!("{:#?}", row);

  let user = User {
    user_id: row["user_id"].as_i64(),
    first_name: row["first_name"].to_string(),
    last_name: row["last_name"].to_string(),
  };
  println!("{:#?}", user);
};


// ///////////////////////////////////////////////////////////
// Second query with columns specified in array - BROKEN
// ///////////////////////////////////////////////////////////
println!("\r\n\r\n#################  SECOND QUERY  #################\r\n");

// Build query
let query2 = Select::from_table("users")
  .columns(vec!["user_id", "first_name", "last_name"])
  .limit(5);

// Output the SQL generated
let (sql_str2, params) = Mysql::build(query2.clone());
println!("{}", sql_str2);

// Run the query and print the number of returned results
let results = conn.query(Query::from(query2)).await.unwrap();
println!("Number of results: {}", results.len());

// Try grabbing and printing the first result
if let Some(row) = results.get(0) {
  println!("{:#?}", row);

  let user = User {
    user_id: row["user_id"].as_i64(),
    first_name: row["first_name"].to_string(),
    last_name: row["last_name"].to_string(),
  };
  println!("{:#?}", user);
};

RESULTS:

#################  FIRST QUERY  #################

SELECT `user_id`, `first_name`, `last_name` FROM `users` LIMIT ?
Number of results: 5
ResultRowRef {
    name_to_index: {
        "first_name": 1,
        "last_name": 2,
        "user_id": 0,
    },
    values: [
        Integer(
            1,
        ),
        Text(
            "John",
        ),
        Text(
            "Doe",
        ),
    ],
}
User {
    user_id: Some(
        1,
    ),
    first_name: Some(
        "John",
    ),
    last_name: Some(
        "Doe",
    ),
}


#################  SECOND QUERY  #################

SELECT ?, ?, ? FROM `users` LIMIT ?
Number of results: 5
ResultRowRef {
    name_to_index: {
        "?": 2,
    },
    values: [
        Text(
            "user_id",
        ),
        Text(
            "first_name",
        ),
        Text(
            "last_name",
        ),
    ],
}
thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', src/libcore/option.rs:378:21

Things to note

Notice that in both cases the number of rows returned is correct at 5, however the results are messed up in the second scenario as they are just the column names and the program obviously panics when trying to unwrap.


SNIP (I think this was wrong, see my next comment)

The documentation on prepared queries for MySQL 5.6 seem to indicate that placeholders for column names should work (https://dev.mysql.com/doc/refman/5.6/en/sql-prepared-statements.html)


So I'm not positive where the error is coming from, but it's obviously by the difference in the generated query between column() and columns(), so for the moment I'm just going to avoid columns().

Hope I explained that well. I realize the error could be in the version of MySQL I tested on, or the Rust MySQL library, but I figured I'd submit a report and let you take a look at it. Cheers guys, thanks again and sorry about throwing a bug report your way!

Can't deserialize some Postgres types

When querying certain postgres types, quaint throws Error querying the database: error deserializing column N: cannot convert between the Rust type `core::option::Option<alloc::string::String>` and the Postgres type `XXX` , where XXX is one of:

  • money
  • date
  • time
  • timetz*
  • timestamptz
  • interval*
  • xml*
  • bytea
  • bit varying
  • cidr*
  • inet*
  • macaddr
  • point
  • box*
  • circle*
  • path*
  • polygon*
  • tsquery*
  • tsvector*

*: not fully supported by tokio-postgres

Some of these types are pretty obscure (though I do use them all), but some like "timestamptz" are fairly common. The type json is an odd one, since you've already got a variant for Json in ParameterizedValue, but it doesn't seem to work

It would be fine if values of unsupported types were returned as a string, users can transform them to the proper types in client code

Release 0.1

This is a ticket for functionality needed before releasing version 0.1 of the crate.

  • Support async/await (#18)
  • Have parity in features and usability compared to other AST:s, such as https://pypika.readthedocs.io/en/latest/ (#45)
  • Make the visitors to allocate less, maybe allocating one slab for the whole query and mutating it while visiting. (#23)
  • One interface to all databases. (#30)
  • When converting rows to ResultRow, check if we could copy less and move instead
  • Results should be available as a Stream in addition to a fully allocated Vec
  • Get needed changes merged to rust-decimal (paupino/rust-decimal#203)
  • Get needed changes merged to num_cpus (seanmonstar/num_cpus#86)
  • Switch to a connection pool that works on stable. (mobc)
  • Follow crates.io releases of mysql-async
  • Write examples
  • Get a fancy and "hip" name for the crate (decided: quaint)
  • Replace failure with something implementing std::error::Error

bonus:

  • Support async-std!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.