diesel cratediesel-clidiesel-migrationdiesel-full-text-searchdiesel-dynamic-schemadiesel-asyncdiesel_clitable! Macrotable! Macromod users {
pub struct table;
mod columns {
pub struct id;
pub struct name;
}
pub use columns::*;
pub mod dsl {
pub use super::table as users;
pub use super::columns::*;
}
}users::idcargo doc to see what’s generatedusers::table.select(users::id) maps to
SELECT id FROM usersQueryDsl traitRunQueryDsl:
load::<U>/get_results::<U>:
Returns a list of U as Vec<U>get_result::<U>: Returns the first U
ignores the restfirst::<U>: Returns the first U,
implicitly attaches a LIMIT 1 clause to the executed queryexecute: Returns the number of affected columnQueryablethe trait bound `(diesel::sql_types::Integer, diesel::sql_types::Text, diesel::sql_types::Integer): load_dsl::private::CompatibleType<User, Sqlite>` is not satisfied
--> src/main.rs:19:31
|
19 | users::table.load::<User>(conn);
| ---- ^^^^ the trait `load_dsl::private::CompatibleType<User, Sqlite>` is not implemented for `(diesel::sql_types::Integer, diesel::sql_types::Text, diesel::sql_types::Integer)`, which is required by `table: LoadQuery<'_, _, User>`
| |
| required by a bound introduced by this call
|
= note: this is a mismatch between what your query returns and what your type expects the query to return
= note: the fields in your struct need to match the fields returned by your query in count, order and type
= note: consider using `#[derive(Selectable)]` or #[derive(QueryableByName)] + `#[diesel(check_for_backend(Sqlite))]`
on your struct `User` and in your query `.select(User::as_select())` to get a better error message
→ Diesel provides a
#[derive(Selectable)] which allows to generate a matching
select clause from your struct
error[E0277]: cannot deserialize a value of the database type `diesel::sql_types::Integer` as `*const str`
--> src/main.rs:16:9
|
16 | id: String,
| ^^^^^^ the trait `FromSql<diesel::sql_types::Integer, Sqlite>` is not implemented for `*const str`, which is required by `String: FromSqlRow<diesel::sql_types::Integer, Sqlite>`
|
= note: double check your type mappings via the documentation of `diesel::sql_types::Integer`
= help: the trait `FromSql<diesel::sql_types::Text, Sqlite>` is implemented for `*const str`
= help: for that trait implementation, expected `diesel::sql_types::Text`, found `diesel::sql_types::Integer`
= note: required for `String` to implement `FromSql<diesel::sql_types::Integer, Sqlite>`
= note: required for `String` to implement `diesel::Queryable<diesel::sql_types::Integer, Sqlite>`
= note: required for `String` to implement `FromSqlRow<diesel::sql_types::Integer, Sqlite>`
users::table.select((
users::id, // select a column,
// select clause part based on selectable
UserWithName::as_select(),
users::id + users::id, // arbitary expressions
diesel::dsl::date(diesel::dsl::now), // SQL function calls
"abc".into_sql::<Text>((), // constants
))users::table
.filter(users::id.eq(42))
.filter(users::name.like("%John%"))
.or_filter(users::name.is_null())AND operatorExpressionMethods for possible
expressionsASCQueryDsl methods for other clausesGROUP BY is special, as it adds additional
requirements+-*/) so that
they can be used to combine expressionsusers::table
.filter(users::my_boolean_column) // plain columns
.filter(users::id.eq(42)) // function call
.filter(users::id.eq(users::age + users::age)) // operators
.filter(42.into_sql::<Integer>().eq(users::id)) // constants
// chaining function calls
.filter(users::id.eq(users::id + 5).eq(false))
// sub queries
.filter(users::id.eq_any(
posts::table
.filter(posts::name.eq("My fancy post"))
.select(posts::user_id)
))*ExpressionMethod traits for all provided
methodsdiesel::insert_into(users::table)
.values((
users::name.eq("John"),
users::age.eq(42),
)).execute(&mut conn)?;INSERT INTO table
statement#[derive(Insertable)]
#[diesel(table_name = users)]
struct NewUser {
name: String,
age: i32,
}
let values: Vec<NewUser> = /* … */;
diesel::insert_into(users::table)
.values(values)
.returning(User::as_returning())
.get_results(&mut conn)?;diesel::update(users::table.find(42))
.set((
users::name.eq("Jane"),
users::age.eq(users::age + 5.into_sql::<Integer>())
)).execute(&mut conn)?;UPDATE table statementfind is a shorthand for
.filter(users::id.eq(42))#[derive(AsChangeset, Identifiable)]
#[diesel(table_name = users)]
struct UserChangeset {
id: i32,
name: String,
age: i32,
}
let value = UserChangeset { /*…*/ };
diesel::update(&value)
.set(&value)
.returning(users::id)
.get_result::<i32>(&mut conn)?;IdentifiableDELETE FROM table statement#[derive(QueryableByName)]
#[diesel(table_name = users)]
struct User {
id: i32,
name: String,
}
diesel::sql_query("SELECT id, name FROM users WHERE name = $1")
.bind::<Text, _>("Jane")
.load::<User>(&mut conn)?;format!()let users = users::table.load::<User>(&mut conn)?;
let users_with_posts = users.into_iter()
.map(|u| {
let posts = posts::table.filter(posts::user_id.eq(u.id))
.load::<Post>(&mtu conn)?;
Ok((u, posts))
}).collect()?;users::table.inner_join(posts::table)
.load::<(User, Post)>(&mut conn)?;
users::table
.inner_join(posts::table)
.group_by(users::id)
.select((User::as_select(), dsl::count(posts::id)))
.load::<(User, i64)>(&mut conn)?;QueryDsllet user = users::table.filter(users::name.eq("Jane"))
.get_result::<User>(&mut conn)?;
let following_user = Followers::belonging_to(&user)
.inner_join(users::table)
.select(User::as_select())
.load(&mut conn);belonging_to just constructs a query targeting the
followers tablelet last_inserted_user = my_connection.transaction(|conn| {
diesel::insert_into(users::table)
.values(data)
.execute(conn)?;
users::table
.order_by(users::id.desc())
.first::<User>(conn)
})?;Connection::transaction
cargo run -- --insert-test-data once to initialize
the databasecargo run again to start the applicationcompetition_overview.rs)registration_list.rs)registration.rs)RunQueryDsl and Connection traitsDiesel
use diesel::prelude::*;
let mut connection = PgConnection::establish(url)?;
let users = users::table.load::<User>(&mut conn)?;Diesel-Async
Use diesel:
Use Diesel-Async:
lib.rs and a
main.rs filelib.rs have a function that constructs your state
and your routerConnection::begin_test_transaction() on creating a
new connection#[tokio::test]
async fn my_test() {
let (router, state) = race_timing::setup(test_config(true));
let resp = router.oneshot(
Request::get("/index.html")
.body(Body::empty())
.unwrap()
).await
.unwrap();
assert_eq!(res.status(), StatusCode::Ok);
// possibly interact with the database via state here
// to check that the database contains the relevant details
}admin/users.rs that also needs to be testedBackendRawValue<'a> describes how values are represented
at the protocol valuesdiesel::pg::Pgdiesel::sqlite::Sqlitediesel::mysql::MysqlQueryFragmentpub trait QueryFragment<DB: Backend, SP = NotSpecialized> {
fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>)
-> QueryResult<()>;
}QueryFragmentQueryIdtrait QueryId {
type QueryId: Any;
const HAS_STATIC_QUERY_ID: bool;
fn query_id() -> Option<TypeId> {/**/}
}
impl<L, R> QueryId for Eq<L, R>
where L: QueryId, R: QueryId
{
type QueryId = Self;
const HAS_STATIC_QUERY_ID: bool =
L::HAS_STATIC_QUERY_ID && R::HAS_STATIC_QUERY_ID;
}TypeId of the composite type, use that as
static prepared statement cache keyExpressionSELECT clausesFROM clausesGROUP BY clausesFromSqlA is the SQL side type
(i.e. TEXT)Self is the Rust side typeDBFromSqlRow if you implement this
traitToSqlpub trait ToSql<A, DB: Backend>: Debug {
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>)
-> Result;
}A is the SQL side typeSelf is the Rust side typeDBAsExpression if you implement this
traitFromSql and
ToSqlConnectionBackend +
Connectiondiesel::sql_types::Integeri32FromSql + ToSqlFromSqlRow and
AsExpressiondefine_sql_function!() to setup a new “bindings”
for a SQL functioninfix_operator! / prefix_operator! /
postfix_operator! to setup bindings for a SQL operatorQueryFragment, Expression
and QueryId for your typedefine_sql_function!()define_sql_function! {
fn lower(x: Text) -> Text;
}
/// use it like
diesel::select(lower("TEST")).get_result::<String>(&mut conn)?;
/// for sqlite
lower_utils::register_impl(connection, |x: String| {
x.to_lowercase()
})?;infix_operator!()diesel::MultiConnection)upserts
or COPY TO statements
Comments
son your keyboard