Rocket icon indicating copy to clipboard operation
Rocket copied to clipboard

`sqlx::query_*` not working when imported from `rocket_db_pools`

Open edpft opened this issue 3 years ago • 4 comments

Description

I want to use the sqlx::query_* macros as demonstrated in your database example but with Postgres instead of Sqlite. However, when I tried to adapt the example to my use case:

// src/models.rs
use rocket::form::FromForm;
use rocket::serde::{Deserialize, Serialize};
use rocket_db_pools::{sqlx, sqlx::Row, Connection};

use crate::db::Db;

#[derive(Debug, FromForm, Clone, Deserialize, Serialize)]
#[serde(crate = "rocket::serde")]
pub struct NewClient<'v> {
    #[field(validate = len(1..).or_else(msg!("Enter the client's first name")))]
    pub first_name: &'v str,
    #[field(validate = len(1..).or_else(msg!("Enter the client's last name")))]
    pub last_name: &'v str,
    #[field(validate = contains('@').or_else(msg!("Enter a valid email address")))]
    pub email_address: &'v str,
    pub telephone_number: &'v str,
}

pub struct NewClientId{
    id: i64
}

impl NewClient<'_> {
    pub async fn add(&self, mut db: Connection<Db>) -> Result<i64, sqlx::Error> {
        let new_client_id = sqlx::query_file_as!(
            NewClientId,
            "queries/add_client.sql",
            self.first_name,
            self.last_name,
            self.email_address,
            self.telephone_number
        )
        .fetch_one(&mut *db)
        .await?;

        Ok(new_client_id.id)
    }
}

I got the following error message:

error[E0034]: multiple applicable items in scope
   --> src/models.rs:25:29
    |
25  |           let new_client_id = sqlx::query_file_as!(
    |  _____________________________^
26  | |             NewClientId,
27  | |             "queries/add_client.sql",
28  | |             self.first_name,
...   |
31  | |             self.telephone_number
32  | |         )
    | |_________^ multiple `default` found
    |
note: candidate #1 is defined in the trait `std::default::Default`
   --> /home/ed/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/default.rs:133:5
    |
133 |     fn default() -> Self;
    |     ^^^^^^^^^^^^^^^^^^^^^
note: candidate #2 is defined in the trait `FromForm`
   --> /home/ed/.cargo/registry/src/github.com-1ecc6299db9ec823/rocket-0.5.0-rc.2/src/form/from_form.rs:551:5
    |
551 |     fn default(opts: Options) -> Option<Self> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: this error originates in the macro `$crate::sqlx_macros::expand_query` (in Nightly builds, run with -Z macro-backtrace for more info)
help: disambiguate the associated function for candidate #1
    |
598 |         <_ as std::default::Default>::$crate::sqlx_macros::expand_query!(record = $out_struct, source_file = $path, args = [$($args)*])
    |         ++++++++++++++++++++++++++++++
help: disambiguate the associated function for candidate #2
    |
598 |         <_ as FromForm>::$crate::sqlx_macros::expand_query!(record = $out_struct, source_file = $path, args = [$($args)*])
    |         +++++++++++++++++

error[E0277]: the trait bound `rocket_db_pools::sqlx::Postgres: sqlx::database::HasArguments<'_>` is not satisfied
  --> src/models.rs:25:29
   |
25 |           let new_client_id = sqlx::query_file_as!(
   |  _____________________________^
26 | |             NewClientId,
27 | |             "queries/add_client.sql",
28 | |             self.first_name,
...  |
31 | |             self.telephone_number
32 | |         )
   | |_________^ the trait `sqlx::database::HasArguments<'_>` is not implemented for `rocket_db_pools::sqlx::Postgres`
   |
   = help: the trait `sqlx::database::HasArguments<'_>` is implemented for `sqlx::Postgres`
   = note: this error originates in the macro `$crate::sqlx_macros::expand_query` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `rocket_db_pools::sqlx::Postgres: sqlx::Database` is not satisfied
  --> src/models.rs:25:29
   |
25 |           let new_client_id = sqlx::query_file_as!(
   |  _____________________________^
26 | |             NewClientId,
27 | |             "queries/add_client.sql",
28 | |             self.first_name,
...  |
31 | |             self.telephone_number
32 | |         )
   | |_________^ the trait `sqlx::Database` is not implemented for `rocket_db_pools::sqlx::Postgres`
   |
   = help: the trait `sqlx::Database` is implemented for `sqlx::Postgres`
note: required by a bound in `sqlx::Encode::size_hint`
  --> /home/ed/.cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-core-0.6.0/src/encode.rs:19:26
   |
19 | pub trait Encode<'q, DB: Database> {
   |                          ^^^^^^^^ required by this bound in `sqlx::Encode::size_hint`
   = note: this error originates in the macro `$crate::sqlx_macros::expand_query` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the size for values of type `str` cannot be known at compilation time
  --> src/models.rs:25:29
   |
25 |           let new_client_id = sqlx::query_file_as!(
   |  _____________________________^
26 | |             NewClientId,
27 | |             "queries/add_client.sql",
28 | |             self.first_name,
...  |
31 | |             self.telephone_number
32 | |         )
   | |_________^ doesn't have a size known at compile-time
   |
   = help: the trait `Sized` is not implemented for `str`
   = help: the following other types implement trait `sqlx::Encode<'q, DB>`:
             &str
             std::string::String
   = note: required because of the requirements on the impl of `sqlx::Encode<'_, rocket_db_pools::sqlx::Postgres>` for `&str`
   = note: this error originates in the macro `$crate::sqlx_macros::expand_query` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `str: sqlx::Encode<'_, rocket_db_pools::sqlx::Postgres>` is not satisfied
  --> src/models.rs:25:29
   |
25 |           let new_client_id = sqlx::query_file_as!(
   |  _____________________________^
26 | |             NewClientId,
27 | |             "queries/add_client.sql",
28 | |             self.first_name,
...  |
31 | |             self.telephone_number
32 | |         )
   | |_________^ the trait `sqlx::Encode<'_, rocket_db_pools::sqlx::Postgres>` is not implemented for `str`
   |
   = help: the following other types implement trait `sqlx::Encode<'q, DB>`:
             &str
             std::string::String
   = note: required because of the requirements on the impl of `sqlx::Encode<'_, rocket_db_pools::sqlx::Postgres>` for `&str`
   = note: this error originates in the macro `$crate::sqlx_macros::expand_query` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0599]: the method `try_map` exists for struct `sqlx::query::Query<'_, rocket_db_pools::sqlx::Postgres, _>`, but its trait bounds were not satisfied
  --> src/models.rs:25:29
   |
25 |           let new_client_id = sqlx::query_file_as!(
   |  _____________________________^
26 | |             NewClientId,
27 | |             "queries/add_client.sql",
28 | |             self.first_name,
...  |
31 | |             self.telephone_number
32 | |         )
   | |_________^ method cannot be called on `sqlx::query::Query<'_, rocket_db_pools::sqlx::Postgres, _>` due to unsatisfied trait bounds
   |
  ::: /home/ed/.cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-core-0.5.13/src/postgres/database.rs:11:1
   |
11 |   pub struct Postgres;
   |   -------------------- doesn't satisfy `rocket_db_pools::sqlx::Postgres: sqlx::Database`
   |
   = note: the following trait bounds were not satisfied:
           `rocket_db_pools::sqlx::Postgres: sqlx::Database`
   = note: this error originates in the macro `$crate::sqlx_macros::expand_query` (in Nightly builds, run with -Z macro-backtrace for more info)

Now, obviously, I could have made a mistake when adapting, but the code works fine if I import sqlx::query_* macros from sqlx instead.

// src/models.rs
use rocket::form::FromForm;
use rocket::serde::{Deserialize, Serialize};
use sqlx::{self, postgres::PgPool};

#[derive(Debug, FromForm, Clone, Deserialize, Serialize)]
#[serde(crate = "rocket::serde")]
pub struct NewClient<'v> {
    #[field(validate = len(1..).or_else(msg!("Enter the client's first name")))]
    pub first_name: &'v str,
    #[field(validate = len(1..).or_else(msg!("Enter the client's last name")))]
    pub last_name: &'v str,
    #[field(validate = contains('@').or_else(msg!("Enter a valid email address")))]
    pub email_address: &'v str,
    pub telephone_number: &'v str,
}

pub struct NewClientId{
    id: i64
}

impl NewClient<'_> {
    pub async fn add(&self, pool: &PgPool) -> Result<i64, sqlx::Error> {
        let new_client_id = sqlx::query_file_as!(
            NewClientId,
            "queries/add_client.sql",
            self.first_name,
            self.last_name,
            self.email_address,
            self.telephone_number
        )
        .fetch_one(pool)
        .await?;

        Ok(new_client_id.id)
    }
}

This wouldn't be so bad if I could still use the launch pattern in the example, but instead I need to manage the Postgres db as demonstrated in this gist.

To Reproduce

// src/db.rs
use rocket_db_pools::Database;
use rocket_db_pools::sqlx::PgPool;

#[derive(Database)]
#[database("rust-backend")]
pub struct Db(PgPool);
-- queries/add_client.sql
INSERT INTO clients (first_name, last_name, email_address, telephone_number) VALUES ($1, $2, $3, $4) RETURNING id;

Expected Behavior

sqlx::query_* macros imported from rocket_db_pools will work if their sqlx equivalents will.

Environment:

  • OS Distribution and Kernel: KDE neon User - 5.25
  • Rocket Version: 0.5.0-rc.2

edpft avatar Jul 18 '22 19:07 edpft

Can you check what version of sqlx you're using? I would assume that the macros re-exported from Rocket may be from a different version of sqlx.

Otherwise, it's quite possible that the re-export is messing with the $crate value in the macros. It's been a hot minute since I've worked with these kinds of macros, so I'm probably missing something.

the10thWiz avatar Jul 19 '22 16:07 the10thWiz

I'm using:

sqlx = { version = "0.6.0", features = ["macros", "runtime-tokio-rustls", "postgres", "uuid", "chrono", "migrate", "offline"] }

edpft avatar Jul 19 '22 18:07 edpft

It looks like rocket_db_pools depends on 0.5. Does downgrading to 0.5.0 break it?

You may be best off setting the version to *, since it should then select the version rocket depends on.

the10thWiz avatar Jul 19 '22 19:07 the10thWiz

No, it compiles with sqlx set to 0.5.0 or *. It's using the sqlx macros from rocket_db_pools that's the problem.

edpft avatar Jul 19 '22 20:07 edpft

yeah they will probably never work, you need sqlx as dependency

griffi-gh avatar Sep 16 '22 17:09 griffi-gh

No, it compiles with sqlx set to 0.5.0 or *. It's using the sqlx macros from rocket_db_pools that's the problem.

This is just a version mismatch. You need to be using the same version as rocket_db_pools uses.

SergioBenitez avatar Sep 18 '22 08:09 SergioBenitez