Skip to content
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

Limit a queries select to the model's table #1214

Open
JasonTheAdams opened this issue Feb 28, 2020 · 6 comments
Open

Limit a queries select to the model's table #1214

JasonTheAdams opened this issue Feb 28, 2020 · 6 comments
Labels
bug An error within Lighthouse

Comments

@JasonTheAdams
Copy link
Contributor

Describe the bug

I have the following type:

type User @modelClass(class: "App\\Models\\User") {
    id: ID!
    donations(
        type: String = "charge" @where(key: "donations.type")
        status: String = "complete" @where(key: "donations.status")
        teamId: ID @scope(name: "byTeam")
    ): [Donation!]
        @hasMany(type: "connection")
}

User.donations is a hasManyThrough relationship. So in order to limit by teamId an additional join is applied during the scope:

    public function scopeByTeam(Builder $query, int $teamId): Builder
    {
        $table = $this->getTable();

        $query
            ->join('campaigns', "$table.campaign_id", '=', 'campaigns.id')
            ->where('campaigns.team_id', '=', $teamId);

        return $query;
    }

This is where things break. The resulting donations have much of the correct data but the wrong ID. The reason for this is actually pretty simple. By default selects in Laravel are *, which means that all columns including the joined table columns are included. Since the joined table also has an ID column and it comes later in the results the ID of the joined table item is returned instead of the correct table's ID.

Expected behavior/Solution

Since Lighthouse has the model and is building the query, all we should really need to do here is to apply the table to the query select. Something like $query->select("{$model->getTable()}.*").

I don't believe this would cause backwards-incompatibility as the GraphQL object is expecting to only be a single model, anyway. The only scenarios I'm not sure of is how Lighthouse handles sub-models and eager loading.


Environment

Lighthouse Version: 5.9
Laravel Version: 6.x

@JasonTheAdams
Copy link
Contributor Author

If anyone else runs into this scenario I ended up working around it by using a sub-query and applying an alias to the joined table's ID:

    public function scopeByTeam(Builder $query, int $teamId): Builder
    {
        $subQuery = Campaign::query()->select('id as campaignId')->where('team_id', '=', $teamId);

        $query->joinSub(
            $subQuery,
            'team_campaigns',
            function (JoinClause $join) {
                $join->on('donations.campaign_id', '=', 'team_campaigns.campaignId');
            }
        );

        return $query;
    }

@spawnia
Copy link
Collaborator

spawnia commented Mar 4, 2020

Thanks for the detailed report. Can you add a PR with a failing test case?

@spawnia spawnia added the bug An error within Lighthouse label Mar 4, 2020
omacranger added a commit to omacranger/lighthouse that referenced this issue Mar 24, 2020
@omacranger
Copy link
Contributor

I've been running into this issue quite a bit too, so placed together a failing test in PR #1253. In the instance of attempting to select users with ID 1 & 2, joining the team table (with ID 1) will change all users in the query to id => 1 since they share that column unless specifying the table in the select or performing a sub join like Jason did above.

@JasonTheAdams
Copy link
Contributor Author

Thanks for putting that together, @omacranger! I hadn't quite found the time, yet.

@spawnia
Copy link
Collaborator

spawnia commented Mar 29, 2020

This issue is caused by Eloquent, Lighthouse does not do anything extraordinary with the query builder. See laravel/framework#4962 for more information.

The proposed fix/workaround can only be done if the user is able to control the select() call. Since Lighthouse takes care of that, we could fix it there.

@spawnia
Copy link
Collaborator

spawnia commented Mar 29, 2020

I did try my hand at fixing this within Eloquent itself, not quite there yet: https://github.com/spawnia/laravel-framework/tree/prefer-original-table-columns-on-join

Fixing this within Lighthouse seems to have it's own set of problems. Subqueries for relationships seem to not work correctly yet, see #1253

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug An error within Lighthouse
Projects
None yet
Development

No branches or pull requests

3 participants