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

Flexible client side querying through @whereConstraints directive #753

Merged
merged 15 commits into from
May 12, 2019
Merged

Flexible client side querying through @whereConstraints directive #753

merged 15 commits into from
May 12, 2019

Conversation

spawnia
Copy link
Collaborator

@spawnia spawnia commented Apr 25, 2019

@whereConstraints

Add a dynamically client-controlled where constraint to a fields query.

Setup

This is an experimental feature and not included in Lighthouse by default.

First, enable the service provider:

'providers' => [
    \Nuwave\Lighthouse\Defer\DeferServiceProvider::class,
],

It depends upon mll-lab/graphql-php-scalars:

composer require mll-lab/graphql-php-scalars

Finally, add an enum type Operator to your schema. Depending on your
database, you may want to allow different internal values. This default
should work for most databases:

enum Operator {
    EQ @enum(value: "=")
    NEQ @enum(value: "!=")
    GT @enum(value: ">")
    GTE @enum(value: ">=")
    LT @enum(value: "<")
    LTE @enum(value: "<=")
    LIKE @enum(value: "LIKE")
    NOT_LIKE @enum(value: "NOT_LIKE")
}

Usage

The argument it is defined on may have any name but must be
of the input type WhereConstraints.

type Query {
    people(where: WhereConstraints @whereConstraints): [Person!]!
}

This is how you can use it to construct a complex query
that gets actors over age 37 who either have red hair or are at least 150cm.

{
  people(
    filter: {
      where: [
        {
          AND: [
            { column: "age", operator: GT value: 37 }
            { column: "type", value: "Actor" }
            {
              OR: [
                { column: "haircolour", value: "red" }
                { column: "height", operator: GTE, value: 150 }
              ]
            }
          ]
        }
      ]
    }
  ) {
    name
  }
}

The definition for the WhereConstraints input is automatically included
within your schema.

input WhereConstraints {
    column: String
    operator: String = EQ
    value: Mixed
    AND: [WhereConstraints!]
    OR: [WhereConstraints!]
    NOT: [WhereConstraints!]
}

scalar Mixed @scalar(class: "MLL\\GraphQLScalars\\Mixed")

@spawnia spawnia changed the title Flexible where constraints Flexible client side querying through @whereConstraints directive Apr 25, 2019
@chrissm79
Copy link
Contributor

@spawnia looks pretty interesting! Not able to test at the moment but should get to this soon. Will this suffer from the same exploit mentioned here since the column names are dynamic and controlled by the client? Might be nice to have the operators as Enums as well, not sure if those suffer the same fate as the columns or not.

@spawnia spawnia changed the title Flexible client side querying through @whereConstraints directive WIP: Flexible client side querying through @whereConstraints directive Apr 27, 2019
@spawnia
Copy link
Collaborator Author

spawnia commented Apr 27, 2019

@chrissm79 good point, let's definitely fix the security issue before we merge this.

The article you linked was great, i think we can employ a similar security mechanism as in spatie/laravel-query-builder@3aa483b
We can just add a scalar ColumnName to make this constraint obvious to the client.

Having the operator as an Enum makes sense, but i am not too sure if we can define a generalized solution that works for all databases. Maybe we will have to leave that up to the user and make them add the enum Operator themselves, only providing suggestions or a default implementation.

@spawnia spawnia added the enhancement A feature or improvement label Apr 27, 2019
@spawnia spawnia requested a review from chrissm79 May 11, 2019 14:26
@spawnia spawnia changed the title WIP: Flexible client side querying through @whereConstraints directive Flexible client side querying through @whereConstraints directive May 11, 2019
@spawnia
Copy link
Collaborator Author

spawnia commented May 11, 2019

@chrissm79 fixed the security issue and made the user add an Operator enum themselves.

@chrissm79
Copy link
Contributor

Nice job @spawnia!

@chrissm79 chrissm79 merged commit 6bb99d5 into nuwave:master May 12, 2019
@spawnia spawnia deleted the flexible-where-constraints branch May 12, 2019 09:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement A feature or improvement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants