-
Notifications
You must be signed in to change notification settings - Fork 11.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[10.x] Add JoinMany
and JoinOne
methods for joining Models to Builder
#46603
Conversation
JoinMany
and JoinOne
methods for directly adding modelsJoinMany
and JoinOne
methods for joining Models to Builder
|
||
return '('.substr($this->compileWheres($where['query']), $offset).')'; | ||
return '('.substr($whereSql, $offset).')'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this was actually a bug, nested inner where's would be cut off on 'whe' and still leave 're ' in the query
is_string($model) => (new $model())->newQuery(), | ||
$model instanceof Builder => $model, | ||
$model instanceof Model => $model->newQuery(), | ||
$model instanceof Relation => $model->getQuery(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Relations actually don't work very well yet (see PR description), i could remove this for now so it would just throw an exception instead?
This would be a huge win! I didn't look at the code too closely, but does this also hydrate the model & set the relation too? That would be 😗👌 edit: saw in your notes (Future Work) that this would require the |
hydration can better be done with the already existing |
Yes, it's possible currently using But regardless, this was just a thought I had. 👍 |
In future PR i would like to make this possible: class User extends Model {
public function manager(){
return $this->belongsToOne(User::class)->where('some_filter', true);
}
}
User::query()->joinRelations('manager')->toSql();
// select * from "users"
// inner join "users" as "manager" on "manager"."user_id" = "users"."id" and "manager"."some_filter" = 1 it includes added filters but not include 'default constraints' (based on model id). but adding this in this PR i fear it might be to big a refactor and might get a lot of push-back, and might need to wait when it brings breaking changes. |
see here an example of |
Not sure I want to maintain this code at this time. Thanks. |
@taylorotwell Can you please elaborate? This fits completely within the Relationship structure and default naming schemes Laravel already handles. It's a minimum addition of code with a huge increase to developer experience for those who follow the naming conventions Laravel follows. |
I suggest you take a look at kirschbaum-development/eloquent-power-joins to see what would be like if this was ever implemented. |
Ah I didn't know this existed. It's very similar indeed. |
How it works
With this Merge a Laravel developer can easily join models without needing to think every time how to join the columns names, as long as you use default laravel naming conventions. You can easily Join models on each other.
It also works with any scopes or where statements.
These will be added to the "on" part of the join to avoid having weird left or right joins. (otherwise if you left joins softdeletable models it would also remove also results that have a related soft deleted model and no other models connected. (in this case a blog with 1 deleted comment would not show up in the results). But that is not the case in this solution :)
Example with where statement
It also works when a relation is the base query:
Edge cases
Considerations & future work
Manually joining Relations
Joining relationships is much harder as it add would add the constraints automatically:
You might expect to just join all comments instead of only joining the comments for the Blog model that you just created.
But the problem is the "constraints" are added when making the Relationship, and this class has no control at this point.
To make this work Each relationship should either:
null
which happens when you instantiate the model yourself as i did in the example above. But i wonder if this might break anything.I would love to solve this with some help
Join relationships (future work)
In future work i would like to add a
joinRelation("name")
But there are many considerations here, perhaps ideally we would like to use a table aliases. to be able to join models of the same class. for example:
This would need some extra work and some more research on my side.
Database Builder (future work)
Technically joining a database
Qualify all column names when joining:
When joining a query Builder it could be the query builder has where statements without qualified table names. This could lead to ambiguous column names.
Consider example below:
it's unclear if "created_at" is from comments or Blog Table.
This problem also exists when you manually build your join query so i think this can be merged/used with keeping this limitation in mind. Ideas: