diesel-rs / diesel Goto Github PK
View Code? Open in Web Editor NEWA safe, extensible ORM and Query Builder for Rust
Home Page: https://diesel.rs
License: Apache License 2.0
A safe, extensible ORM and Query Builder for Rust
Home Page: https://diesel.rs
License: Apache License 2.0
I'm not pushing to crates.io without a name
@sgrif I am setting up a simple server with yaqb and I am running into a problem with insert that I cannot get past. I ultimately keep running into this error when trying to use insert with a NewUser struct.
src/models/user.rs:41:10: 41:49 error: unable to infer enough type information about `_`; type annotations or generic parameter binding required [E0282]
src/models/user.rs:41 conn.insert(&self::users::table, &new_users);
If I switch to insert_returning_count it works fine.
Here is the line causing the error:
https://github.com/mfpiccolo/yaqb_test/blob/master/src/models/user.rs#L40
It's a terrible habit, and I agree that we shouldn't have it in our docs. I've gotten rid of a decent number recently, but I'd like to eliminate the rest in favor of try!
(this will take some annoying boilerplate in our doctests, but it's probably worth it).
I've read you are going to add support of other databases only after 1.0, but differences between Postgre and MySQL are not so big, so please consider to support MySQL in 0.x. Then it will be well-tested for 1.0 :)
It would be really great if you could debug sql commands at compile time. Something like:
debug_sql!(users.filter(id.eq(1));
would output:
SELECT * FROM users WHERE id = 1
Or:
debug_sql!(update(users::table.filter(id.eq(id))).set(changed_user));
prints to console:
UPDATE "users" SET "name" = $1, "email" = $2 WHERE "users"."id" = $3 RETURNING "users"."id", "users"."name", "users"."email"
This is my biggest call to action for anybody interested. While I will absolutely write all the docs if needed, I do strongly believe that the best flow for this is to have people who didn't implement something ask questions, and find usage that way, as it forces an explanation targeted at people not familiar with the framework.
This is by far the biggest blocker for 0.1, and probably the easiest way to get started. If you're interested in helping, comment here, or shoot me an email (it's on my profile). I will take as much time as is needed to explain usage.
Currently in codegen, when we're attempting to figure out the NativeSqlType
to map to for a table, we do the following:
_
? If so ::diesel::types::Array<{next step}>
::diesel::types::{type name with capitalized first letter}
This was a wart that was the "absolute minimum that could possibly work" to get 0.1 out the door, but it's time for it to go. (And it'll be nice to get rid of ugly little hacks like https://github.com/sgrif/diesel/blob/3ab23f6d20b4405a8361726fd9212e332b599061/diesel/src/types/mod.rs#L47).
The main constraint here is that the system we replace this with is something that third party crates can hook into. I also do not want to require that the type be in scope, so we need to get the full path (::diesel::types::*
is rarely in scope, and I don't want it to be).
In an ideal world, third party crates could just do something like #[diesel_type_lookup(oid = "1234")] pub struct PostGisOrSomething
, but I don't think that's possible (especially with the added constraint that I want to potentially take an arbitrary function), as I don't believe that we can have mutable state as part of a compilation unit that crosses crate boundaries.
So I think the best way we can actually do this is to have a database table. This means that other crates will have to actually populate it, but we can have a macro required or a function call required from build.rs
. In the simplest case this can be a table that maps oid -> path to type
, and we continue to special case arrays (though based on pg_type.typcategory
instead of the name). If we don't want to special case arrays, I think we end up with a metadata entry that is an array of SQL function names. Each of these functions would take a pg_type
row, and return the path to the modifier and another oid if it matches, or null if it doesn't.
In either case, all of Diesel's lookups should go through this same machinery. It should not be special cased.
Using #[has_many(posts)]
on a User struct throws this error:
src/models/user.rs:12:19: 12:19 error: multiple applicable items in scope [E0034]
src/models/user.rs:12 #[has_many(posts)]
^
src/models/user.rs:12:1: 12:19 note: in this expansion of #[has_many] (defined in src/models/user.rs)
src/models/user.rs:12:19: 12:19 help: run `rustc --explain E0034` to see a detailed explanation
src/models/user.rs:12:19: 12:19 note: candidate #1 is defined in an impl of the trait `diesel::expression::Expression` for the type `diesel::expression::predicates::Eq<_, _>`
src/models/user.rs:12 #[has_many(posts)]
^
src/models/user.rs:12:1: 12:19 note: in this expansion of #[has_many] (defined in src/models/user.rs)
src/models/user.rs:12:19: 12:19 note: candidate #2 is defined in an impl of the trait `diesel::query_builder::update_statement::changeset::Changeset` for the type `diesel::expression::predicates::Eq<_, _>`
src/models/user.rs:12 #[has_many(posts)]
^
src/models/user.rs:12:1: 12:19 note: in this expansion of #[has_many] (defined in src/models/user.rs)
src/models/user.rs:12:19: 12:19 note: candidate #3 is defined in an impl of the trait `diesel::expression::Expression` for the type `&_`
src/models/user.rs:12 #[has_many(posts)]
^
src/models/user.rs:12:1: 12:19 note: in this expansion of #[has_many] (defined in src/models/user.rs)
src/models/user.rs:12:19: 12:19 note: candidate #4 is defined in an impl of the trait `diesel::query_builder::QueryFragment` for the type `_`
src/models/user.rs:12 #[has_many(posts)]
^
src/models/user.rs:12:1: 12:19 note: in this expansion of #[has_many] (defined in src/models/user.rs)
error: aborting due to previous error
We have max
. We don't have min
. Or avg
, sum
, etc. We should add these. They should not use the sql_function!
macro, as they need to accept more than one argument type. min
should have the same bounds as max
. Others might need new bounds. I'm fine with just naming the trait something like CanBePassedToAvg
or something, if there's not a good generic name. If you ever need to find the types which can be passed to a function in postgres, just open up psql and run this query:
select typname from pg_type where oid in (select proargtypes::text::oid from pg_proc where proname = 'sum');
Note: All items should be implemented in a way that works on stable rust, unless otherwise specified. Compiler plugins are probably the most preferable for codegen, but we'll see what's possible.
LIKE
)IN
statements, since we have = ANY
filter(json_col["foo"].eq("bar"))
, might be hard to support arbitrary data types.IS NULL
(does this need to be separate from equality?)
thing.eq("foo")
, not thing.eq(Some("foo"))
, which means the pattern for AR style equality will look like:match value {
Some(x) => thing.eq(x),
None => thing.is_null(),
}
Documenting in case anyone out there happens to want to get involved, these should be easy to add. We need a trivial test case for this. "users"."hair_color"
is nullable in our normal schema.
This issue was automatically generated. Feel free to close without ceremony if
you do not agree with re-licensing or if it is not possible for other reasons.
Respond to @cmr with any questions or concerns, or pop over to
#rust-offtopic
on IRC to discuss.
You're receiving this because someone (perhaps the project maintainer)
published a crates.io package with the license as "MIT" xor "Apache-2.0" and
the repository field pointing here.
TL;DR the Rust ecosystem is largely Apache-2.0. Being available under that
license is good for interoperation. The MIT license as an add-on can be nice
for GPLv2 projects to use your code.
The MIT license requires reproducing countless copies of the same copyright
header with different names in the copyright field, for every MIT library in
use. The Apache license does not have this drawback. However, this is not the
primary motivation for me creating these issues. The Apache license also has
protections from patent trolls and an explicit contribution licensing clause.
However, the Apache license is incompatible with GPLv2. This is why Rust is
dual-licensed as MIT/Apache (the "primary" license being Apache, MIT only for
GPLv2 compat), and doing so would be wise for this project. This also makes
this crate suitable for inclusion and unrestricted sharing in the Rust
standard distribution and other projects using dual MIT/Apache, such as my
personal ulterior motive, the Robigalia project.
Some ask, "Does this really apply to binary redistributions? Does MIT really
require reproducing the whole thing?" I'm not a lawyer, and I can't give legal
advice, but some Google Android apps include open source attributions using
this interpretation. Others also agree with
it.
But, again, the copyright notice redistribution is not the primary motivation
for the dual-licensing. It's stronger protections to licensees and better
interoperation with the wider Rust ecosystem.
To do this, get explicit approval from each contributor of copyrightable work
(as not all contributions qualify for copyright, due to not being a "creative
work", e.g. a typo fix) and then add the following to your README:
## License
Licensed under either of
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
additional terms or conditions.
and in your license headers, if you have them, use the following boilerplate
(based on that used in Rust):
// Copyright 2016 diesel Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
It's commonly asked whether license headers are required. I'm not comfortable
making an official recommendation either way, but the Apache license
recommends it in their appendix on how to use the license.
Be sure to add the relevant LICENSE-{MIT,APACHE}
files. You can copy these
from the Rust repo for a plain-text
version.
And don't forget to update the license
metadata in your Cargo.toml
to:
license = "MIT OR Apache-2.0"
I'll be going through projects which agree to be relicensed and have approval
by the necessary contributors and doing this changes, so feel free to leave
the heavy lifting to me!
To agree to relicensing, comment with :
I license past and future contributions under the dual MIT/Apache-2.0 license, allowing licensees to chose either at their option.
Or, if you're a contributor, you can check the box in this repo next to your
name. My scripts will pick this exact phrase up and check your checkbox, but
I'll come through and manually review this issue later as well.
It used to be the case that everything had to go through Connection#query_all
and Connection#query_one
. I found it was annoying, and added too many parenthesis, which is why load
and first
were added. (connection.query_all(users.filter(name.eq("Sean")))
vs users.filter(name.eq("Sean")).load(&connection)
.
I want to give the same treatment to these (technically load
actually works fine, but I think that update(users.filter(id.eq(1))).set(name.eq("Sean")).load(&connection)
reads really strangely). We should add some new methods (the names are up for debate):
run(&connection)
: We often know that we will return exactly one row. The should return QueryResult<T>
, and will basically be load(&connection).map(|mut r| r.nth(0).unwrap())
.run_all(&connection)
: Alias for load
. Probably a better name for this, but I want it to imply that we're doing a command that happens to return.execute(&connection)
: Alias for Connection#execute_returning_count
This does not include the codegen or integration test crates. This issue is tracking the fact that core only builds on nightly. This is due to the fact that the way I implemented the interval DSL requires From<i32>
. I've implemented the interval dsl for i64
and f64
, which only implement From<i32>
on nightly. We just need to copy paste the defaulted methods. Should be straight forward.
The litmus test for this issue is the yaqb
directory passing cargo test
on stable. codegen and yaqb_tests
do not need to pass on stable.
What's the recommended way of dealing with the infer_*
macros and CIs? Say if you have
infer_table_from_schema!(dotenv!("DATABASE_URL"), "users");
You can create the database in a before_script
with Travis, but the table still won't exist at compile time. You could obviously also create the table in the before_script
section, but that feels like it would get onerous as your number of tables grows.
I realize there may be no easy way of dealing with this since it is a convenience compile-time check, just wanted to see if you had a nice way.
I'm debating whether or not to have foo.eq(None)
result in foo IS NULL
or not. Either way, for ergonomics, we should allow foo.eq("bar")
in addition to foo.eq(Some("bar"))
. At the moment, attempting to write this ToSql
implementation results in overlap both with the impl for Option<T>
, and for &'a T
. I think we need specialization for this to work.
error: the trait `diesel::expression::Expression` is not implemented for the type `u64`
I got this error.
I solved it with this:
let game = games.filter(id.eq(params.find("id").unwrap().as_u64().unwrap() as i32 )).first(&connection);
This is a bit ugly. Could there be more types supported than just i32?
Any other suggestion than moving this cast to a function?
I had hoped that this would just involve adding an Aggregate
marker trait, and modifying the tuple impls to allow if all members are aggregate. This causes overlap since any type could implement both NonAggregate
and Aggregate
. I do not think there is a way to express this currently in the type system currently, without negative bounds (or maybe specialization)
This is just an artifact of the fact that I implemented this before everything other than the most basic forms of select. This should be changed to match update
and delete
. This is the API I'm imagining:
insert_into(table).values(records)
This would return a command that can be used in the same way the return values of update
and delete
, which will be less painful with #29.
Since this represents a breaking change in one of the most common APIs, we should do this sooner rather than later.
I'd like to make this refactoring to clean up parts of our type system. However, I can't seem to figure out how to express tuples with that refactoring, as right now a tuple of (A, B, C)
can be expressed in two ways if all 3 of the inner types are nullable, it can be Nullable<(SA, SB, SC)>
or (Nullable<SA>, Nullable<SB>, Nullable<SC>)
.
This is important for the ergonomics of left outer joins. I'd be fine with dropping the second case for joins, but we definitely cannot drop it more generally.
So far update
is the hardest to wrap my head around, and I was hoping for some clarification/guidance.
In the context of an HTTP API, with a users table that looks like:
table! {
users {
id -> Serial,
first_name -> VarChar,
last_name -> VarChar,
email -> VarChar,
}
}
how would you go about implementing a Users#update action?
My first instinct is to have something like:
#[changeset_for(users)]
pub struct UserChanges {
id: i32,
first_name: Option<String>,
last_name: Option<String>,
email: Option<String>,
}
fn update(req: SomeHTTPReq) -> SomeHTTPRes {
let changeset = UserChanges {
first_name: req.body.get("first_name"),
// etc
}
changeset.save_changes(&connection)
}
Such that you end up updating whatever valid params the user sends, but that requires having Nullable
columns in the table macro, when the columns aren't actually nullable.
Keep up all the great work!
While I can do this:
table! {
foo {
id -> Serial,
bar -> Array<Integer>,
}
}
#[derive(Queriable)]
struct Foo {
bar: Vec<i32>,
}
I can't do that:
#[changeset_for(foo)]
struct Foo {
bar: Vec<i32>,
}
Is there a way to achieve this?
These are both blockers in my mind. As with rails, the schema file should be auto generated, but I would like to have a usage story that doesn't require a DSL for every possible database feature. In my mind this was going to be Schema.toml
, but I think this might just end up being structure.sql
from Rails. The main benefit of schema.rb
over structure.sql
in the Rails world is that the former is often easier to solve merge conflicts for. This is not an issue for 0.1, or really 0.x, as it's easy to work around, but we need to figure out our story for this
I have several questions/propositions regarding the current implementation:
Row
trait: to me, looking at DbRow
(only struct implementing it) it looks more like a Value
than an entire row ... I am not familiar with postgresql so it might be an implementation detail (to manage tuples?)is_null
: IMHO rust traits should not have is_null
functions. Some implementations could be 100% rust and as a result can't be null. What do you think?Looks like a breaking change upstream. We should at minimum update for this, and perhaps start using Syntex_syntax over libsyntax on nightly
I was trying to set up another repo to play around with yaqb in another crate but I was unable to build the crate because of a cargo issue rust-lang/cargo#2064.
The error I am getting I think is due to conflicting libc's.
Compiling yaqb v0.1.0 (file:///Users/mfpiccolo/code/mfpiccolo/yaqb_test)
/Users/mfpiccolo/code/mfpiccolo/yaqb/src/connection/mod.rs:320:23: 320:55 error: mismatched types:
expected `*mut libc::types::common::c95::c_void`,
found `*mut connection::libc::c_void`
(expected enum `libc::types::common::c95::c_void`,
found enum `connection::libc::c_void`) [E0308]
/Users/mfpiccolo/code/mfpiccolo/yaqb/src/connection/mod.rs:320 PQfreemem(self.pg_str as *mut libc::c_void)
Are you able to use the crate as a dependency?
How to reproduce the bug:
#[changeset_for(foo)]
struct Foo {
field1: i64,
field2: Option<i16>,
field3: i16,
}
/* ... */
update(
foo::table.filter(foo::id.eq(&1))
).set(&Foo {
field1: 0,
field2: None,
field3: 0,
}).execute(&conn).unwrap();
This yields the following error:
ERROR: syntax error at or near "field3"
LINE 1: UPDATE "foo" SET "field1" = $1"field3" = $2
It seems that there is a comma missing in the SQL output with patterns like (Something, None, ..., None, Something)
We need to test for this. For example, if we have
table! {
users {
id -> Serial,
name -> VarChar,
email -> VarChar,
}
}
There's nothing to prevent
let source = users.select((id, email, name));
connection.query_all::<User>(&source)
which would read the fields into the wrong pieces of the struct. The obvious solution is to access by the name of the fields, but then we have to figure out more concrete aliasing behavior and couple to it which I don't want. Needs further investigation.
Do we need one? @derekprior you might have opinions on this. I was just thinking about this, and it might be cool (if we go the DSL migration route) to allow using the query builder DSL for constructing views, and then when the migration is run store the previous version in the schema_migrations
table, to get down
for free.
As we start to get into things like schema inference and migrations, which mean we want a persistent schema for our tests, we need to stop assuming the ids 1 and 2. Even though our tests will still run in isolated transactions, inserting rows in a transaction will bump the PK counter, regardless of whether or not the transaction is committed. This is fine, but we need to make sure our suite still passes.
I am trying to build using the latest master but a bunch of unimplemented errors now. It was working on master and when I pointed to the newest master on yaqb there was a serde compatibility issue because of quasi. I removed serde and now I am trying to get the same functionality but I am unable to compile.
I can post the code in the issue but it may just be easier to link.
Here are the two files from my try-compile branch:
https://github.com/mfpiccolo/yaqb_test/blob/try-compile/src/models/post.rs
https://github.com/mfpiccolo/yaqb_test/blob/try-compile/src/models/user.rs
Any idea why I would be getting the errors like:
error: the trait `yaqb::query_source::Queriable<(yaqb::types::Integer, yaqb::types::VarChar, yaqb::types::Nullable<yaqb::types::VarChar>)>` is not implemented for the type `models::user::User
The README shows it as the return type for insert but the source shows Result
as the return type. Is the end goal to use DbResult
over Result
?
I believe this should be straightforward. There's a couple of things to consider
Edit: The thoughts in this comment are super outdated, and likely no longer relevant.
Table::PrimaryKey
has the constraint Column<Table=Self>
. Unsure if we want to relax that to SelectableExpression
, or if we want to introduce the Columns
trait. We could even implement Column
for tuples now if we really want to, as there's no longer any automatically added behaviors.conn.find(&posts_tags, &(1, 1))
would be more likely to generate SELECT * FROM posts_tags WHERE (post_id, tag_id) = $1
, instead of SELECT * FROM posts_tags WHERE post_id = $1 AND tag_id = $2
. Might be fine for an initial implementation, but we do eventually need to solve this to support other databases.http://www.postgresql.org/docs/current/static/queries-union.html
These are quite useful for set-like queries.
This code works:
table! {
hello {
id -> Serial,
hello_a -> Integer,
hello_b -> Integer,
hello_c -> Integer,
hello_d -> Integer,
hello_e -> Integer,
hello_f -> Integer,
hello_g -> Integer,
hello_h -> Integer,
hello_i -> Integer,
hello_j -> Integer,
hello_k -> Integer,
hello_l -> Integer,
hello_m -> Integer,
hello_n -> Integer,
hello_o -> Integer,
}
}
This code doesn't work:
table! {
hello {
id -> Serial,
hello_a -> Integer,
hello_b -> Integer,
hello_c -> Integer,
hello_d -> Integer,
hello_e -> Integer,
hello_f -> Integer,
hello_g -> Integer,
hello_h -> Integer,
hello_i -> Integer,
hello_j -> Integer,
hello_k -> Integer,
hello_l -> Integer,
hello_m -> Integer,
hello_n -> Integer,
hello_o -> Integer,
hello_p -> Integer,
}
}
It gives this error:
<diesel macros>:16:54: 19:52 error: the trait `diesel::types::NativeSqlType` is not implemented for the type `(diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer)` [E0277]
<diesel macros>:16 out . push_identifier ( stringify ! ( $ name ) ) } } impl AsQuery for table {
<diesel macros>:17 type SqlType = SqlType ; type Query = SelectStatement < SqlType , (
<diesel macros>:18 $ ( $ column_name ) , + ) , Self > ; fn as_query ( self ) -> Self:: Query {
<diesel macros>:19 SelectStatement:: simple ( all_columns , self ) } } impl Table for table {
<diesel macros>:15:1: 17:58 note: in this expansion of table_body! (defined in <diesel macros>)
<diesel macros>:5:1: 6:2 note: in this expansion of table! (defined in <diesel macros>)
<diesel macros>:2:1: 2:64 note: in this expansion of table! (defined in <diesel macros>)
src/main.rs:50:1: 70:2 note: in this expansion of table! (defined in <diesel macros>)
<diesel macros>:16:54: 19:52 help: run `rustc --explain E0277` to see a detailed explanation
<diesel macros>:16:54: 19:52 note: required by `diesel::query_builder::AsQuery`
<diesel macros>:16:54: 19:52 error: the trait `diesel::expression::SelectableExpression<hello::table, (diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer)>` is not implemented for the type `(hello::columns::id, hello::columns::hello_a, hello::columns::hello_b, hello::columns::hello_c, hello::columns::hello_d, hello::columns::hello_e, hello::columns::hello_f, hello::columns::hello_g, hello::columns::hello_h, hello::columns::hello_i, hello::columns::hello_j, hello::columns::hello_k, hello::columns::hello_l, hello::columns::hello_m, hello::columns::hello_n, hello::columns::hello_o, hello::columns::hello_p)` [E0277]
<diesel macros>:16 out . push_identifier ( stringify ! ( $ name ) ) } } impl AsQuery for table {
<diesel macros>:17 type SqlType = SqlType ; type Query = SelectStatement < SqlType , (
<diesel macros>:18 $ ( $ column_name ) , + ) , Self > ; fn as_query ( self ) -> Self:: Query {
<diesel macros>:19 SelectStatement:: simple ( all_columns , self ) } } impl Table for table {
<diesel macros>:15:1: 17:58 note: in this expansion of table_body! (defined in <diesel macros>)
<diesel macros>:5:1: 6:2 note: in this expansion of table! (defined in <diesel macros>)
<diesel macros>:2:1: 2:64 note: in this expansion of table! (defined in <diesel macros>)
src/main.rs:50:1: 70:2 note: in this expansion of table! (defined in <diesel macros>)
<diesel macros>:16:54: 19:52 help: run `rustc --explain E0277` to see a detailed explanation
<diesel macros>:16:54: 19:52 note: required by `diesel::query_builder::AsQuery`
<diesel macros>:19:53: 23:45 error: the trait `diesel::expression::Expression` is not implemented for the type `(hello::columns::id, hello::columns::hello_a, hello::columns::hello_b, hello::columns::hello_c, hello::columns::hello_d, hello::columns::hello_e, hello::columns::hello_f, hello::columns::hello_g, hello::columns::hello_h, hello::columns::hello_i, hello::columns::hello_j, hello::columns::hello_k, hello::columns::hello_l, hello::columns::hello_m, hello::columns::hello_n, hello::columns::hello_o, hello::columns::hello_p)` [E0277]
<diesel macros>:19 SelectStatement:: simple ( all_columns , self ) } } impl Table for table {
<diesel macros>:20 type PrimaryKey = columns:: $ pk ; type AllColumns = ( $ ( $ column_name ) , +
<diesel macros>:21 ) ; fn name ( ) -> & 'static str { stringify ! ( $ name ) } fn primary_key (
<diesel macros>:22 & self ) -> Self:: PrimaryKey { columns:: $ pk } fn all_columns ( ) -> Self::
<diesel macros>:23 AllColumns { ( $ ( $ column_name ) , + ) } } pub mod columns {
<diesel macros>:15:1: 17:58 note: in this expansion of table_body! (defined in <diesel macros>)
<diesel macros>:5:1: 6:2 note: in this expansion of table! (defined in <diesel macros>)
<diesel macros>:2:1: 2:64 note: in this expansion of table! (defined in <diesel macros>)
src/main.rs:50:1: 70:2 note: in this expansion of table! (defined in <diesel macros>)
<diesel macros>:19:53: 23:45 help: run `rustc --explain E0277` to see a detailed explanation
error: aborting due to 3 previous errors
What is wrong? I'm pretty new on rust. ๐ถ
YAQB has no license, which means you currently reserve all rights.
The TL;DR of this is add support for syntex. I hope to have a better story for stable on 1.0.
In issue #36 I was trying to get example with #[derive(Queriable)]
to work and one of the things that confused me is that you still have to make a table!
call and hand-write all the column types.
Here I'm proposing to make Queriable
smart enough to generate appropriate table stuff or even table!
call so you won't have to do it manually. For some cases you might want to manually set the type of the column, e.g
#[derive(Queriable, Debug)]
pub struct User {
#[column_type = Serial]
id: i32,
#[column_type = VarChar]
name: String,
}
P.S @sgrif thanks for all the great work you've done! I'm very excited about query builder/ORM in Rust.
I'm trying this example from the README (added some imports from previous one with table!
macro):
#![feature(custom_derive)]
#[macro_use]
extern crate diesel;
use diesel::*;
#[derive(Queriable, Debug)]
pub struct User {
id: i32,
name: String,
favorite_color: Option<String>,
}
fn main() {
let connection = Connection::establish(env!("DATABASE_URL"))
.unwrap();
let users: Vec<User> = users::table.load(&connection)
.unwrap().collect();
println!("Here are all the users in our database: {:?}", users);
}
Here's my error msg:
Compiling try_diesel v0.1.0 (file:///home/user/rust/try_diesel)
src/main.rs:18:28: 18:40 error: failed to resolve. Use of undeclared type or module `users` [E0433]
src/main.rs:18 let users: Vec<User> = users::table.load(&connection)
^~~~~~~~~~~~
src/main.rs:18:28: 18:40 help: run `rustc --explain E0433` to see a detailed explanation
src/main.rs:18:28: 18:40 error: unresolved name `users::table` [E0425]
src/main.rs:18 let users: Vec<User> = users::table.load(&connection)
^~~~~~~~~~~~
src/main.rs:18:28: 18:40 help: run `rustc --explain E0425` to see a detailed explanation
error: aborting due to 2 previous errors
Could not compile `try_diesel`.
rustc:
rustc 1.6.0-nightly (b7845f93b 2015-11-15)
binary: rustc
commit-hash: b7845f93b54d3e45fcac94e7d7f3111aad90142f
commit-date: 2015-11-15
host: x86_64-unknown-linux-gnu
release: 1.6.0-nightly
The has_many/belongs_to codegen annotations don't seem to be able to handle a table name consisting of multiple words and underscores, as it smashes all the words together when searching for the module name. The following code fails to compile:
#![feature(plugin, custom_derive)]
#![plugin(diesel_codegen)]
#[macro_use]
extern crate diesel;
fn main() {}
#[has_many(soccer_balls)]
pub struct User {
id: i32
}
#[belongs_to(user)]
pub struct SoccerBall {
id: i32,
user_id: i32
}
table! {
users {
id -> Serial,
}
}
table! {
soccer_balls {
id -> Serial,
user_id -> Integer,
}
}
Giving the following error:
src/main.rs:1:1: 1:1 error: failed to resolve. Use of undeclared type or module `soccerballs` [E0433]
src/main.rs:1 #![feature(plugin, custom_derive)]
^
src/main.rs:14:1: 14:20 note: in this expansion of #[belongs_to] (defined in src/main.rs)
src/main.rs:1:1: 1:1 help: run `rustc --explain E0433` to see a detailed explanation
src/main.rs:1:1: 1:1 error: use of undeclared type name `soccerballs::table` [E0412]
src/main.rs:1 #![feature(plugin, custom_derive)]
^
src/main.rs:14:1: 14:20 note: in this expansion of #[belongs_to] (defined in src/main.rs)
src/main.rs:1:1: 1:1 help: run `rustc --explain E0412` to see a detailed explanation
src/main.rs:1:1: 1:1 error: failed to resolve. Use of undeclared type or module `soccerballs` [E0433]
src/main.rs:1 #![feature(plugin, custom_derive)]
^
src/main.rs:14:1: 14:20 note: in this expansion of #[belongs_to] (defined in src/main.rs)
src/main.rs:1:1: 1:1 help: run `rustc --explain E0433` to see a detailed explanation
src/main.rs:1:1: 1:1 error: use of undeclared type name `soccerballs::user_id` [E0412]
src/main.rs:1 #![feature(plugin, custom_derive)]
^
src/main.rs:14:1: 14:20 note: in this expansion of #[belongs_to] (defined in src/main.rs)
src/main.rs:1:1: 1:1 help: run `rustc --explain E0412` to see a detailed explanation
src/main.rs:1:1: 1:1 error: failed to resolve. Use of undeclared type or module `soccerballs` [E0433]
src/main.rs:1 #![feature(plugin, custom_derive)]
^
src/main.rs:14:1: 14:20 note: in this expansion of #[belongs_to] (defined in src/main.rs)
src/main.rs:1:1: 1:1 help: run `rustc --explain E0433` to see a detailed explanation
src/main.rs:1:1: 1:1 error: unresolved name `soccerballs::table` [E0425]
src/main.rs:1 #![feature(plugin, custom_derive)]
^
src/main.rs:14:1: 14:20 note: in this expansion of #[belongs_to] (defined in src/main.rs)
src/main.rs:1:1: 1:1 help: run `rustc --explain E0425` to see a detailed explanation
src/main.rs:1:1: 1:1 error: failed to resolve. Use of undeclared type or module `soccerballs` [E0433]
src/main.rs:1 #![feature(plugin, custom_derive)]
^
src/main.rs:14:1: 14:20 note: in this expansion of #[belongs_to] (defined in src/main.rs)
src/main.rs:1:1: 1:1 help: run `rustc --explain E0433` to see a detailed explanation
src/main.rs:1:1: 1:1 error: unresolved name `soccerballs::user_id`. Did you mean `self.soccerballs::user_id`? [E0425]
src/main.rs:1 #![feature(plugin, custom_derive)]
// Lots more of those...
src/main.rs:14:1: 14:20 note: in this expansion of #[belongs_to] (defined in src/main.rs)
src/main.rs:1:1: 1:1 help: run `rustc --explain E0412` to see a detailed explanation
error: internal compiler error: ty_is_local invoked on unexpected type: [type error]
note: the compiler unexpectedly panicked. this is a bug.
note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports
note: run with `RUST_BACKTRACE=1` for a backtrace
thread 'rustc' panicked at 'Box<Any>', ../src/libsyntax/errors/mod.rs:469
The expansion is looking for soccerballs::table
and friends, when it should be looking for soccer_balls::table
and friends.
Deriving Queriable
for structs with explicit lifetimes blows up with the error message:
Compiling diesel_test v0.1.0 (file:///Users/mattcasper/code/diesel_test)
src/main.rs:28:18: 28:20 error: use of undeclared lifetime name `'a` [E0261]
src/main.rs:28 first_name: &'a str,
^~
src/main.rs:25:10: 25:19 note: in this expansion of #[derive_Queriable] (defined in src/main.rs)
src/main.rs:28:18: 28:20 help: run `rustc --explain E0261` to see a detailed explanation
src/main.rs:28:18: 28:20 error: use of undeclared lifetime name `'a` [E0261]
src/main.rs:28 first_name: &'a str,
^~
src/main.rs:25:10: 25:19 note: in this expansion of #[derive_Queriable] (defined in src/main.rs)
src/main.rs:28:18: 28:20 help: run `rustc --explain E0261` to see a detailed explanation
error: aborting due to 2 previous errors
for the struct
#[derive(Queriable)]
pub struct User<'a> {
id: i32,
first_name: &'a str,
last_name: String,
email: String
}
And trying to implement the trait by hand got tricky, I got stuck on what $row_type
evaluates to.
To make this useful for more than web-applications that are backed by a database server, for example a dektop application that needs to save some data, it would be nice to have support for at least one embedded database like sqlite, which happens to be following pgs design decisions if in doubt.
https://github.com/sgrif/diesel#delete
deleted_rows
is referenced but not defined anywhere
So let's talk borderline absurd features. I'm trying to figure out how we can support this type, while still being useful. I feel like this is harder to do than in dynamic languages where we're just an arbitrary map or array. However, I think we can do something moderately useful with serde integration (I am unsure if this should be in core, or a separate trait)
However, I am fairly convinced that we can do impl<T> ToSql<Json> for T where T: serde::ser::Serialize
and impl<T> FromSql<Json> for T where T: serde::de::Deserialize
(note: As written, those two almost certainly require specialization. We can work around this with boilerplate macros to implement for individual types in the short term).
The following operators exist for the JSON data types:
->
: Query DSL should just implement Index
for Json
expressions. Output should be Expression<SqlType=Json>
. We might need to do some hackery since Index
requires returning a reference. A Copy
constraint will likely be involved as well. Might need to be a method if we really can't work with Index
, but boy it would be amazing to write filter(json_column["foo"].eq("bar"))
->>
: Unsure if we should support. If so, will need to be a method. Unclear on the right name.#>
: Unsupported#>>
: Unsupported@>
: Implemented as method contains
. Argument should be AsExpression<Json>
, return type is Bool`<@
: Unsupported?
: Implemented as method has_key
. Argument should be AsExpression<VarChar>
, return type is Bool
?|
and ?&
: Same as above. Don't have an opinion on the method names.We should also support as many functions as possible from http://www.postgresql.org/docs/9.4/static/functions-json.html. As I write this, I'm fairly convinced this should be a separate crate. If anyone wants to tackle this, let me know and I'll add a new repo for it. I do want this to be supported under the general Diesel umbrella though, even if it's not in the core crate.
Documenting in case anyone wants to get involved. This is the last macro being invoked from our integration tests that needs to go away for 0.1 I intend for this to be #[can_update="users"]
. This annotation should basically do what the macro does today, including all columns, but should specifically exclude the primary key of the table from the changeset.
As part of this, I think we should group all our non-derive annotations into a single namespace with each just being a key/value pair. e.g. #[yaqb(inserable_into("users"), can_update("users"))]
. That change should affect #[column_name]
as well. That can be a separate PR that pre-dates this change, part of this change, or just not done at all. It's not a 0.1 blocker.
The correct name would be Queryable.
Once https://github.com/slapresta/rust-dotenv/pull/27 is merged switch back to https://github.com/slapresta/rust-dotenv
This is due to the (very naive) type lookup that we do right now. The name of a string array in Postgres is _varchar
. We need to be much more sophisticated.
Trying to use #[changeset_for]
for the struct:
#[changeset_for(users)]
pub struct UserChanges {
id: i32,
first_name: Option<String>,
last_name: Option<String>,
email: Option<String>,
}
Produces the error:
src/main.rs:33:24: 33:24 error: the trait `diesel::query_source::Queriable<(diesel::types::Integer, diesel::types::VarChar, diesel::types::VarChar, diesel::types::VarChar)>` is not implemented for the type `UserChanges` [E0277]
src/main.rs:33 #[changeset_for(users)]
^
src/main.rs:33:1: 33:24 note: in this expansion of try! (defined in <std macros>)
src/main.rs:33:24: 33:24 help: run `rustc --explain E0277` to see a detailed explanation
error: aborting due to previous error
However, adding #[derive(Queriable)]
to the struct annotation raises the error:
src/main.rs:34:24: 34:24 error: the trait `diesel::types::FromSqlRow<(diesel::types::Integer, diesel::types::VarChar, diesel::types::VarChar, diesel::types::VarChar)>` is not implemented for the type `(i32, core::option::Option<collections::string::String>, core::option::Option<collections::string::String>, core::option::Option<collections::string::String>)` [E0277]
src/main.rs:34 #[changeset_for(users)]
^
src/main.rs:34:1: 34:24 note: in this expansion of try! (defined in <std macros>)
src/main.rs:34:24: 34:24 help: run `rustc --explain E0277` to see a detailed explanation
error: aborting due to previous error
Halp
Codegen continues to try to create a tuple, and we don't implement any of our traits for tuples with a single element. This should not create a tuple if there's only one field.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.