Prisma1: Prisma Client: Support selection of non-scalar fields

Created on 15 Oct 2018  路  8Comments  路  Source: prisma/prisma1

If you have this schema:

type Query {
  user: User!
}

type User {
  house: House!
}

type House {
  id: String!
}

and do this client call:

client.user() - what should happen?
Right now an error is thrown, that the query contains an empty selection set.
This is the case, because we only expand on scalar fields for now.
However, with types like the User type as in our example, that don't have scalar fields, this approach breaks.

An opinionated, non-trivial solution is needed here.

Here are possible solutions for the problem:

  1. Expand the first single relation, if that is not possible, expand the first list relation
  2. Expand every field

Let's discuss in this issue, which behavior makes more sense and potentially other solutions.

One thing is clear: We at least need better error handling for this case.

bu2-confirmed rf2-accepted areclient

Most helpful comment

My suggestion: always query __typename automatically for every selection set. This way, there is no error thrown. Don't query any relations automatically.

If the user wants to query a relation, they should be able to easily do so however. I think this would be client.user().house().

Could you please provide an example?

All 8 comments

My suggestion: always query __typename automatically for every selection set. This way, there is no error thrown. Don't query any relations automatically.

If the user wants to query a relation, they should be able to easily do so however. I think this would be client.user().house().

Just a side not: Currently, this behaviour breaks xsConnection queries.

If you run

ctx.prisma.usersConnection()

this error is thrown

Field 'usersConnection' of type 'UserConnection' must have a sub selection.

I like @marktani's suggestion to query for __typename. I'm currently leaning towards only querying it if no other scalar fields are available. Are there any reasons why it should be queried in all cases?

Note that this is both important for Connection types and Subscription types.

My suggestion: always query __typename automatically for every selection set. This way, there is no error thrown. Don't query any relations automatically.

If the user wants to query a relation, they should be able to easily do so however. I think this would be client.user().house().

Could you please provide an example?

Until this issue is resolved, you can try connection queries like :-

async productsConnection(parent, args, ctx: Context, info) {
    //getUserId(ctx);
    const query = `
    query($orderBy: ProductOrderByInput, $where: ProductWhereInput) {
      productsConnection(orderBy: $orderBy, where: $where) {
        __typename
        pageInfo {
          hasNextPage
          hasPreviousPage
        }
        edges {
          node {
            id
            name
            price
            pictureUrl
            seller {
              id
            }
          }
          cursor
        }
      }
    }
    `;
    const variables = { ...args};
    const { productsConnection } = await ctx.prisma.$graphql(query, variables);
    return productsConnection;
  },

In the above code I made a request to prisma's endpoint from my server.

We just discussed the concrete implementation and it should look like this:
Only for types that don't have scalar fields, we'll add the __typename in the query.
The actual return type won't change - it's an empty object.

This PR https://github.com/prisma/prisma/pull/3892 implements it for top level types. Resulting in the following behavior:

prisma.users() yields the following query now

query ($where: UserWhereInput) {
  users(where: $where) {
    __typename
  }
}

However, as a result of this opinionated API https://github.com/prisma/prisma/issues/3629 the generated connection API for a type with no scalars breaks currently, generating the following query:-

{
  usersConnection {
    pageInfo {
      hasNextPage
      hasPreviousPage
      startCursor
      endCursor
    }
    edges {
      node
      cursor
    }
  }
}

This fails at node selection with: UnhandledPromiseRejectionWarning: Error: Field 'node' of type 'User' must have a sub selection.

This needs further spec of the behavior when we encounter a connection operation from client for a type without scalars. Following solutions (not exhaustive) are possible:-

  1. Do not expand connection query as per https://github.com/prisma/prisma/issues/3629 when the type has no scalars, resulting in the following query:-

Cons:

  • Different types for relay connection API for types that have scalars vs types that have no scalars.

  • This will be a breaking change in terms of types.

Resulting query:

{
  usersConnection {
    __typename
  }
}
  1. Expand nested fields without scalars to query __typename

Cons:

  • Generated query is not very useful.
  • Big performance penalty as we need to iterate over resulted data to pluck out __typename from the result.
  • Complicated codepath, do we hardcode this for field name node (as done in the opinionated API ) or handle it via a generic solution i.e. expand every type without scalars ?

Resulting query:

{
  usersConnection {
    pageInfo {
      hasNextPage
      hasPreviousPage
      startCursor
      endCursor
    }
    edges {
      node {
        __typename
      }
      cursor
    }
  }
}
Was this page helpful?
0 / 5 - 0 ratings