Comments (6)
In addition to just flat out fixing this problem, I'd also like to decouple the table name from the struct name, and allow a #[table_name="foo"]
annotation.
from diesel.
The decoupling would probably help a lot, as it looks like it has trouble with any edge case pluralization as well
from diesel.
Yeah, it literally is .to_lowercase + s right now. We can make it
slightly better, but I don't want to try and handle actual pluralization
for every word
On Mon, Jan 11, 2016, 5:46 PM Matt Casper [email protected] wrote:
The decoupling would probably help a lot, as it looks like it has trouble
with any edge case pluralization as well—
Reply to this email directly or view it on GitHub
#86 (comment).
from diesel.
👍 for #[table_name="foo"]
from diesel.
Also I didn't mention it earlier, but also keep in mind that I've left associations out of the public API of the released crate, as I'm not happy with the current design and it may change further (it also likely requires the lattice rule coming w/ specialization to implement properly)
from diesel.
So I've been starting to think more heavily about this, and specifically how to avoid duplicating a lot of information when dealing with non-standard tables and primary keys. An interesting thing about the #[table_name]
annotation is that I can't actually access it from annotations on other items (which makes sense, especially when considering the associated struct might be coming from another crate).
Just spitballing some thoughts here. Scoping to belongs_to
only to simplify. We might be able to work this into assuming the other side implements a trait, rather than how we operate today. If we do #[belongs_to(bar)] Struct Foo;
, then the code that'll get generated is:
impl ::diesel::BelongingToDsl<Bar> for Foo {
type Output = ::diesel::helper_types::FindBy<
foos::table,
foos::bar_id,
i32,
>;
fn belonging_to(model: &Bar) -> Self::Output {
foos::table.filter(foos::bar_id.eq(model.id.clone()))
}
}
impl ::diesel::JoinTo<bars::table> for foos::table {
fn join_sql(&self, out: &mut ::diesel::query_builder::QueryBuilder)
-> ::diesel::query_builder::BuildQueryResult
{
try!(bars::table.from_clause(out));
out.push_sql(" ON ");
foos::bar_id.eq(bars::table.primary_key()).to_sql(out)
}
}
So I guess really all we need is something like
trait Identifiable {
type Table: Table;
type Pk: AsExpression<Self::Table::PrimaryKey::SqlType>;
fn table() -> Self::Table;
fn primary_key(&self) -> Self::Pk;
}
Now the question is where do we actually generate this. Are we fine with just requiring a #derive(Identifiable)
on the other side? I could just tack it onto something common like Queriable
, but that would imply that you don't have models which aren't associated with a single row of a single table.
It's worth noting that all of this is focusing around the idea that these structs will represent a single row on a single table. While that's counter to the design of the framework overall, I think that more or less has to be a given when we start talking about associations (unless we want to explore the idea that you'd have a single struct to represent both sides, but I don't think that'll work well with one-to-many, and would inhibit code re-use).
It's also worth noting that we never actually use the argument to belongs_to
, other than to generate the foreign key and infer the struct name.
With all of this in mind, I'm thinking that we should change the API to #[belongs_to(User)]
, with the ability to specify the foreign key: #[belongs_to(User, foreign_key="author_id")]
. With this change, the generated code would become:
impl ::diesel::BelongingToDsl<Bar> for Foo {
type Output = ::diesel::helper_types::FindBy<
foos::table,
foos::bar_id,
i32,
>;
fn belonging_to(model: &Bar) -> Self::Output {
foos::table.filter(foos::bar_id.eq(<Bar as Identifiable>::primary_key(model)))
}
}
impl ::diesel::JoinTo<<Bar as Identifiable>::Table> for foos::table {
fn join_sql(&self, out: &mut ::diesel::query_builder::QueryBuilder)
-> ::diesel::query_builder::BuildQueryResult
{
try!(<Bar as Identifiable>::table().from_clause(out));
out.push_sql(" ON ");
foos::bar_id.eq(<Bar as Identifiable>::table().primary_key()).to_sql(out)
}
}
This does mean that you can't have an association using a primary key other than that of the table. I think that's fine, as the point is that we're equating with a single row, and I've never seen a good use case for changing the primary key of an association in Rails.
This will be a little bit more murky when it comes to has_many
, as that means the API becomes the slightly awkward #[has_many(Post)]
or #[has_many(Post, foreign_key="post_id")]
. It's worth noting that has_many
as it is today is effectively worthless (other than enabling joining).
At some point it will also be the thing that makes you able to get Vec<(User, Vec<Post>)>
out of a query, but I'm not sure that needs to care about the struct as much as it is a property of how you're performing the join. I was writing some examples of what I mean but as I wrote them I realized there's some flaws involving how it gets mixed with select
. I'd have to implement to figure that out. But what I'm getting at is that unlike belongs_to
, which does deal with a specific struct, has_many
doesn't necessarily need to know about it, and in fact it is more about the table, implying that #[has_many(posts)]
is in fact the right thing to do.
Perhaps at the heart of this is figuring out exactly what associations are meant to do. I do like Post::belonging_to(user)
as a helpful piece of sugar over the common posts.filter(user_id.eq(user.id))
(I also just realized that could totally be posts::belonging_to(user)
since the Post
struct has nothing to do with belonging_to
, but I'm struggling to come up with any cases where we need to involve structs.
If that's the case, maybe we need to separate out the relationships between tables from the relationships between structs. The biggest problem there is that we no longer have a place for you to actually annotate a table. I need to spike some more on what I want to be able to do with has_many
to figure out the right place to solve this...
from diesel.
Related Issues (20)
- Failed to save array of enums HOT 3
- Nullable<diesel::sqlite::sql_types::Timestamptz> throws trait not implement errors
- Segmentation Fault in R2D2 postgres (interrupted by signal 11: SIGSEGV) HOT 10
- `joinable!` is not generated for two foreign keys referencing the same table HOT 1
- Diesel-cli Can't connect to local MySQL server through socket '/tmp/mysql.sock' HOT 1
- Deserialization layer seems too permissive with regards to checking the actual types received HOT 1
- Can't use `into_boxed` after union HOT 1
- table have more than one primary_key can not use on_conflict(diesel::dsl::DuplicatedKeys) HOT 7
- No intellisense when using query dsl HOT 6
- `overflow evaluating the requirement` when writing generic diesel code HOT 1
- Pagination guide doesn't work on entity represented by joined tables HOT 2
- losing type information when adding WHERE (filter) clause to query HOT 2
- Diesel not generate joinable when there are 2 foreign keys reference same field HOT 1
- `#[derive(AsExpression, FromSqlRow)]` won't compile when generic bounds have a default implementation. HOT 2
- Serials keep incrementing despite begin_test_transaction HOT 3
- Source code for diesel_derives 2.1.2 not available on GitHub HOT 1
- Cannot use multiple table_name for Insertable when also deriving Queryable HOT 1
- SSL_MODE option not behaving correctly with Mysql 5.7 HOT 3
- Derive Queryable deserialize_as attribute doesn't support tuples HOT 4
- msvc+rust1.75 compile error HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from diesel.