S) for additional informationtable! {
students {
id -> Integer,
name -> Text,
}
}
#[derive(Queryable)]
struct Student {
id: i32,
name: String,
}
let students: Vec<Student> =
students::table
.filter(students::id.eq(42))
.load::<Student>(&conn)?;
diesel::insert_into(students::table)
.values((
students::id.eq(43),
students::name.eq("weiznich"),
)).execute(&conn)?;General design assumptions for diesel:
diesel_cli (A tool to manage migrations/your schema)table! marcoQueryDsl traita_table::table.select((
a_table::column_a, // just select a column
a_table::column_b + a_table::column_b, // an expression
"abc".into_sql::<Text>() // or a constant
))table! macroa_table::table
.filter(a_table::column_a.eq(foo)
.and(a_table::column_b.like(baz)))
.or_filter(a_table::column_c.is_null()).filter twice appends the new where clause with an AND to the old one*ExpressionMethods traits for methods useful to construct inner expressionsASCQueryable)load::<U>/get_results::<U>: Returns a list of Uget_result::<U>: Returns the first U ignores the restfirst::<U>: Returns the first U, attaches a LIMIT 1 clause to the executed queryexecute: Returns the number of affected columnsdiesel::insert_into(a_table::table)
.values((
a_table::column_a.eq(value),
a_table::column_b.eq(other_value)
)).execute(&conn);INSERT INTO statement.diesel::update(a_table::table.filter(a_table::id.eq(1)))
.set((
a_table::column_a.eq(some_value),
a_table::column_b.eq(a_table::column_b + 5.into_sql::<Integer>())
)).execute(&conn);UPDATE statementDROP FROM a_table statement#[derive(QueryableByName)]
#[table_name = "students"]
struct Student {
id: i32,
name: String
}
diesel::sql_query("SELECT id, name FROM students WHERE name = $1")
.bind::<Text, _>("weiznich")
.load(&conn);#[derive(Identifiable, Queryable)]
#[table_name = "teachers"]
struct Teacher {
id: i32,
name: String,
}
#[derive(Identifiable, Queryable, Associations)]
#[belongs_to(Teacher, foreign_key = "supervisor")]
#[table_name = "students"]
struct Student {
id: i32,
name: String,
supervisor: i32
}
let teachers = teachers::table.load::<Teacher>(&conn)?;
let students = Student::belonging_to(&teachers)
.load::<Student>(&conn)?
.grouped_by(&teachers);
let teachers_with_students = teachers.into_iter()
.zip(students)
.collect::<Vec<(Teacher, Vec<Student>)>>();error[E0277]: the trait bound `teachers::columns::name: diesel::SelectableExpression<students::table>` is not satisfied
--> src/main.rs:30:21
|
30 | students::table.select(teachers::name).load::<Student>(&conn);
| ^^^^^^ the trait `diesel::SelectableExpression<students::table>` is not implemented for `teachers::columns::name`
|
= help: the following implementations were found:
#[derive(Queryable)]
struct Student {
id: i32,
name: String
}
let s: Vec<Student> = students::table
.select(students::id)
.load(conn);error[E0277]: the trait bound `(std::string::String, i32): diesel::Queryable<diesel::sql_types::Integer, diesel::pg::Pg>` is not satisfied
--> src/main.rs:34:64
|
34 | let s: Vec<Student> = students::table.select(students::id).load(&conn)?;
| ^^^^ the trait `diesel::Queryable<diesel::sql_types::Integer, diesel::pg::Pg>` is not implemented for `(std::string::String, i32)`
error[E0277]: the trait bound `*const str: diesel::deserialize::FromSql<diesel::sql_types::Integer, diesel::pg::Pg>` is not satisfied
--> src/main.rs:34:63
|
34 | let s: Vec<String> = students::table.select(students::id).load(&conn)?;
| ^^^^ the trait `diesel::deserialize::FromSql<diesel::sql_types::Integer, diesel::pg::Pg>` is not implemented for `*const str`
= help: the following implementations were found:
<*const [u8] as diesel::deserialize::FromSql<diesel::sql_types::Binary, DB>>
<*const str as diesel::deserialize::FromSql<diesel::sql_types::Text, DB>>
= note: required because of the requirements on the impl of `diesel::deserialize::FromSql<diesel::sql_types::Integer, diesel::pg::Pg>` for `std::string::String`
GROUP BY clauses and mixing aggregating and non aggregating expressionsSELECT statements at compile time:
userspostscommentsBootstrap a simple REST API for the given database schema:
diesel_cliimpl FromSql<ColorType, Pg> for Color {
fn from_sql(bytes: Option<&[u8]>) -> Result<Self> {
match bytes {
Some(b"red") => Ok(Color::Red),
Some(b"green") => Ok(Color::Green),
Some(b"blue") => Ok(Color::Blue),
_ => Err("Unrecognized enum variant".into())
}
}
}
impl ToSql<ColorType, Pg> Color {
fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> Result<IsNull> {
match *self {
Color::Red => out.write_all(b"red")?;,
Color::Green => out.write_all(b"green")?;
Color::Blue => out.write_all(b"blue")?;
}
Ok(IsNull::No)
}
}RawValue says which how data are represented at protocol levelstruct Eq<L, R>{
left: L,
right: R,
}
impl<L, R> QueryFragment<Pg> for Eq<L, R>
where
L: QueryFragment<Pg>,
R: QueryFragment<Pg>,
{
fn walk_ast(&self, mut pass: AstPass<DB>) -> QueryResult<()> {
self.left.walk_ast(pass.reborrow())?;
pass.push_sql(" = ");
self.right.walk_ast(pass.reborrow())?;
Ok(())
}
}trait 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 key
let mut query = students::table.select(students::name);
if let Some(id) = filter_by_id {
query = query.filter(students::id.eq(id));
}let mut query = students::table.select(students::name)
.into_boxed();
if let Some(id) = filter_by_id {
query = query.filter(students::id.eq(id));
}.into_boxed creates a boxed select statement that erases all generic arguments beside of the table name and target backend for the given select statementpost table indicating the state of the post.
Draft, Published, Deletedhttp://localhost/posts?name="foo"&order="id"post table
http://localhost/posts/page/$page_number?post_count=$postcount to return the number of total pages and the posts of the requested page.{
Teachers {
teacherName: name
students {
name
}
}
}
#[derive(GraphQLObject)]
struct Student {
id: i32,
name: String,
}
struct Query;
juniper::graphql_object!(Query: Context |&self| {
field apiVersion() -> &str {
"1.0"
}
field student(&executor, id: i32) -> FieldResult<Student> {
let context = executor.context();
context.load_student_with_id(id)
}
});#[derive(GraphQLObject, Queryable)]
struct Student {
id: i32,
name: String,
}
#[derive(Queryable)]
struct Teacher {
id: i32,
name: String,
}
juniper::graphql_object!(Teacher: Context |&self| {
field id() -> i32 {
self.id
}
field name() -> &str {
&self.name
}
field students(&executor) -> FieldResult<Vec<Student>> {
let conn = executor.context().pool.get_connection()?;
let students = students::table
.filter(students::supervisor.eq(self.id))
.load::<Student>(&conn)?;
Ok(students)
}
})#[derive(Identifiable, WundergraphEntity)]
#[table_name = "students"]
struct Student {
id: i32,
name: String,
supervisor: HasOne<i32, Teacher>,
}
#[derive(Identifiable, WundergraphEntity)]
#[table_name = "teachers"]
struct Teacher {
id: i32,
name: String,
students: HasMany<Student, students::supervisor>,
}
wundergraph::query_object! {
Query {
Student,
Teacher
}
}WundergraphEntity#[derive(WundergraphEntity, Identifiable)]
#[table_name = "student"]
#[primary_key(id)]
/// GraphQL type description
struct Student {
/// GraphQL field description
id: i32,
#[wundergraph(graphql_name = "name")]
#[column_name = "name"]
name: String,
supervisor: HasOne<i32, Teacher>,
papers: HasMany<Paper, papers::student>,
}query_object!mutation CreateStudent {
createStudent(name: "weiznich", supervisor: 42) {
id
name
}
}
Insertable are automatically usable as insert mutationAsChangeset are automatically usable as update mutationwundergraph::query_builder::mutationsmutation_object!WundergraphContext as juniper context typeConnection traittrait QueryModifier<L, DB> {
fn modify_query(
&self,
select: &LookAheadSelection<WundergraphScalarValue>,
query: BoxedQuery<L, DB, Self>,
) -> Result<BoxedQuery<L, DB, Self>>;
}table! macro callNULL instead of removing the fieldAssociations approach involving a fixed number of queries insteadBoxedSelectStatement helps there, but writing generic code also requiredpub trait LoadingHandler<DB, Ctx> : HasTable + Sized
where DB: Backend
{
type Columns;
type FieldList;
type PrimaryKeyIndex;
type Filter;
const FIELD_NAMES: &[&str];
const TYPE_NAME: &str;
}pub trait WundergraphBelongsTo<Other, DB, Ctx, FK>: LoadingHandler<DB, Ctx> {
type Key;
fn resolve(
glob_args: &[LookAheadArgument<WundergraphScalarValue>],
look_ahead: &[LookAheadSelection<WundergraphScalarValue>],
selection: Option<&[Selection<WundergraphScalarValue>],
keys: &[Option<Self::Key>],
executor: Executor<Ctx, WundergraphScalarValue>,
) -> Result<
HashMap<
Option<Self::Key>,
Vec<Value<WundergraphScalarValue>>
>>;
}LoadingHandlertrait ExtractTableFields {
type Out;
}
impl<T1, T2> ExtractTableFields for (T1, T2)
where T1: WundergraphValue, (T2,): ExtractTableFields
<(T2,) as ExtractTableFields>::Out: AppendToTuple<T1>
{
type Out = <<(T2,) as ExtractTableFields>::Out
as AppendToTuple<T1>>::Out;
}
impl<C, FK, T2> ExtractTableFields for (HasMany<C, FK>, T2)
where (T2,): ExtractTableFields
{
type Out = <(T2,) as ExtractTableFields>::Out;
}SELECT * FROM post_at_version(5);