Graphcool 1.0 - Add where clause in query


#1

Hey,
I have a mult-tenant application and want to use graphcool 1.0’s new server feature to add an additional where filter statemanet (for the tenant Id which I can get for authenticated users). This works fine if no filter statement is given in the original query:

export const Query = {

customers(parent, args, ctx: Context, info) {

return ctx.db.query.customers({ where: { tenant: { id: tenantId } } }, info)
}

But if there is a where statement in the query this is not working anymore. I can see, that there is something about the where clause in the args attribute. But there is something in the info atttribute, too. I think this causes the issue.
So, I tried somehting like this (two where statements concatenated with AND):

if (args.where.AND) {
args.where.AND.push(
{
tenant: {
id: tenantId
}
} as CustomerWhereInput
)
}

return ctx.db.query.customers(args, info)

But the Tenant filter is ignored. What is the correct way to add an additional where statement in a query by providing all other functionality like filtering, ordering and selecting fields?

Thank you in advance!


#2

I think something like this should work:

const tenantFilter = {  tenant: { id: tenantId } }
let where = {}

if (args.where) {
  where = {
    AND: [{
      ...args.where,
    }, {
      ...tenantFilter,
    }]
  }
} else {
  where = {
    ...tenantFilter,
  }
}

return ctx.db.query.customers({ where }, info)

#3

I think it should be

else {
        where = {
          ...tenantFilter,
        }
      }

Nevertheless, this is not working for a given where statement. The tenant filter is ignored, but the where object is correct:

{"where":{"AND":[{"name_contains":"Muster"},{"tenant":{"id":"cjc6bik40013c0120ffhyld2q"}}]}}

After investigating the info object, there are some parts of the filter, too.


#4

Oops, updated :slight_smile:


Can you share

  • the query you are sending
  • the resolver definition in src/schema.graphql

for which you observe the described behaviour?


#5

Thanks for your help :slight_smile:
Here is the query:

{
  customers(where: {name_contains: "Muster"}, orderBy: name_DESC) {
    name
    id
    tenant {
      name
      id
    }
  }
}

and the resolver definition:

#import Tenant from "./generated/database.graphql"
type Query {
  me: User
  customers(where: CustomerWhereInput, orderBy: CustomerOrderByInput): [Customer!]!
}
...
type Customer {
  id: ID!
  name: String!
  vorname: String!
  tenant: Tenant!
}

#6

One more thing that would be helpful to understand what’s going on. Please enable the debug option for the Graphcool binding in src/index.{js, ts}:

    db: new Graphcool({
      endpoint: process.env.GRAPHCOOL_ENDPOINT,
      secret: process.env.GRAPHCOOL_SECRET,
+      debug: true,
    }),

Then use the customers resolver, and share the complete query and variables from your debug output.


#7

Ok, here is the debug output of a query containing a where statement:

query:
query ($_skip: Int, $_after: String, $_before: String, $_first: Int, $_last: Int) {
  customers(where: {name_contains: "Muster"}, orderBy: name_DESC, skip: $_skip, after: $_after, before: $_before, first: $_first, last: $_last) {
    name
    id
    tenant{
      name
      id
    }
  }
}
operationName: null
variables:
{}
Response from http://localhost:60001/....
{
  "customers": [
    {
      "name": "Mustermann",
      "id": "cjc6dsrbj02sh0120qob1alt8",
      "tenant": {
        "name": "Company 2",
        "id": "cjc6bik40013c0120ffhyld2q"
      }
    },
    {
      "name": "Musterfrau",
      "id": "cjc6e1bif03ec0120gd9p1vt5",
      "tenant": {
        "name": "Company 1",
        "id": "cjc6b65fl00pm0120p7isu618"
      }
    }
  ]
}

and here is the output of a non-filtered query:

query:
query ($_where: CustomerWhereInput, $_skip: Int, $_after: String, $_before: String, $_first: Int, $_last: Int) {
  customers(orderBy: name_DESC, where: $_where, skip: $_skip, after: $_after, before: $_before, first: $_first, last: $_last) {
    name
    id
    tenant{
      name
      id
    }
  }
}
operationName: null
variables:
{
  "_where": {
    "tenant": {
      "id": "cjc6bik40013c0120ffhyld2q"
    }
  }
}
Response from http://localhost:60001/.....
{
  "customers": [
    {
      "name": "Mustermann",
      "id": "cjc6dsrbj02sh0120qob1alt8",
      "tenant": {
        "name": "Company 2",
        "id": "cjc6bik40013c0120ffhyld2q"
      }
    }
  ]
}

As you can see, the “variables” part of the first output is empty.


#8

I also have a multi tenant app. I haven’t migrated it to 1.0, so I don’t know if filter was deprecated / removed in 1.0. But my query to get all inventory from a tenant is…

 {
    allDealerships(filter: { name: $dealershipName }) {
      id
      ...
      vehicles {
        id
        year
        make
        model
      ...
     }
}

#9

Good news, I found a solution!

as mentioned the problem is the where statement information in the info object. You just have to remove it and all works as expected.

So, my code looks like this:

const tenantFilter = {  tenant: { id: tenantId } }
let where = {}

if (args.where) {

  _.set(info, 'fieldNodes[0].arguments', []);

  where = {
    AND: [{
      ...args.where,
    }, {
      ...tenantFilter,
    }]
  }
} else {
  where = {
    ...tenantFilter,
  }
}

return ctx.db.query.customers({ where }, info)

I use lodash to remove the filter information. This makes the query using the where clause in the args object instead.

Question @nilan: Bug or feature? :smiley: