nuwave / nuwave/lighthouse

Problem with table name on HAS condition with relationship on same table

Open
#1,794 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
PHP
Stars
3.5k
Forks
468
Avg merge
3h 9m
Merged PRs (30d)
2

Description

Describe the bug
I think there's a bug with WhereConditionsBaseDirective using HAS condition when the relation is between the same model.
The prefixConditionWithTableName method doesn't take in consideration possible renaming of the joined table/model.

For example, I have a Location model that can be represented by a tree, having a parent_id foreign key column and 2 relationships, parent and children, that allow to retrieve related nodes.
My schema is similar to the following:

type Location {
    id: ID!
    parent: Location @belongsTo
    children: [Location!] @hasMany
}

enum LocationColumn {
    ID @enum(value: "id")
}

extend type Query {
    locations(
        where: _ @whereConditions(columnsEnum: "LocationColumn"),
        hasParent: _ @whereHasConditions(columnsEnum: "LocationColumn"),
        hasChildren: _ @whereHasConditions(columnsEnum: "LocationColumn")
    ): [Location!]!
}

The models i currently have saved in the database are

[
  {
    "id": 1,
    "parent_id": null,
  },
  {
    "id": 2,
    "parent_id": 1,
  }
]

The actual query performed using this code

query locations($hasChildren: QueryLocationsHasChildrenWhereHasConditions) {
  locations(hasChildren: $hasChildren) {
    id
    parent {
      id
    }
    children {
      id
    }
  }
}

and these variables

{
  "hasChildren": {
    "column": "ID",
    "value": 2
  }
}

is

select *
from `locations`
where (exists(select *
              from `locations` as `laravel_reserved_0`
              where `locations`.`id` = `laravel_reserved_0`.`parent_id`
                and `locations`.`id` = 8))
limit 1000 offset 0;

I have the same problem the other way around, performing the query using the hasParent condition

Expected behavior/Solution

I'd expect the query to be like this

select *
from `locations`
where (exists(select *
              from `locations` as `laravel_reserved_0`
              where `locations`.`id` = `laravel_reserved_0`.`parent_id`
                and `laravel_reserved_0`.`id` = 8))
limit 1000 offset 0;

to notice last line of the inner select

Lighthouse Version

5.3.0

Opened PR #1795 with failing tests. I'll check later if I'm able to fix the issue

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with WhereConditionsBaseDirective and its prefixConditionWithTableName method, then inspect the failing tests mentioned in PR #1795. Reproduce the self-referential HAS query and compare the generated SQL with the expected alias-qualified condition; done means both hasParent and hasChildren conditions use the correct joined-table name.

Written by the indexing model from the issue text.

Assessment

Tech stack
graphql, laravel, php
Domain
api, backend, databases
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.