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

Allow promises to be returned in a field in the resolver of connection #853

Open
shreyas44 opened this issue Mar 6, 2021 · 4 comments · May be fixed by #906
Open

Allow promises to be returned in a field in the resolver of connection #853

shreyas44 opened this issue Mar 6, 2021 · 4 comments · May be fixed by #906
Labels
scope/types Having to do with types type/bug Something is not working the way it should

Comments

@shreyas44
Copy link
Contributor

shreyas44 commented Mar 6, 2021

The below example would return a type error because the return type of the edges field is expected to be {cursor: string, node: Bar} and Promise<{cursor: string, node: Bar}> is not allowed. However, a query that requests for those edges will resolve without any error.

Why return a Promise in the getter of edges in the first place?

Say, we need to get a list of items from a database and parse that through a utility function that creates a cursor for that record. If we directly await the query to get the list of items, then we lose the ability to batch the requests using something like dataloader, or Prismas Fluent API (which uses the dataloader pattern). Instead, we can return a promise for the edges field that waits for the response from the database, parse that through our utility function to get the cursor, and resolve the promise.

An alternative is to just use the nodes() function, but then implementing a resolver for the entire connection wouldn't be possible in this scenario.

import { ApolloServer } from "apollo-server"
import { connectionPlugin, makeSchema, objectType, queryField } from "nexus"

const bars = [
  {
    cursor: "cursor1",
    node: {
      id: "1",
      barField1: "abcd",
      barField2: "abcdef",
    }
  },
  {
    cursor: "cursor2",
    node: {
      id: "2",
      barField1: "asdf",
      barField2: "asdfasdf",
    }
  }
]

const Foo = objectType({
  name: "Foo",
  definition(t) {
    t.nonNull.id("id")
    t.nonNull.string("fooField1")
    t.nonNull.string("fooField2")
   
   // --- Error in this part ---
    t.connectionField("bars", {
      type: "Bar",
      resolve() {
        return {
          get edges() {
            return new Promise(resolve => {
              resolve(bars)
            })
          }
        }
      }
    })
  }
})

const Bar = objectType({
  name: "Bar",
  definition(t) {
    t.nonNull.id("id")
    t.nonNull.string("barField1")
    t.nonNull.string("barField2")
  }
})

const fooQuery = queryField("foo", {
  type: "Foo",
  resolve() {
    return {
      id: "12345",
      fooField1: "qwrew",
      fooField2: "14123"
    }
  }
})

const schema = makeSchema({
  types: [Foo, Bar, fooQuery],
  plugins: [connectionPlugin()]
})

I'm sorry for the bad example, let me know if you'd like a better one 🙂

@gianluca1606
Copy link

I am also getting the same Errors on multiple resolvers and I don't understand what I am doing wrong.. but the queries and mutations are working

@shreyas44
Copy link
Contributor Author

shreyas44 commented Mar 8, 2021

I am also getting the same Errors on multiple resolvers and I don't understand what I am doing wrong.. but the queries and mutations are working

It depends on the situation. In my case, the property getters return promises. But the generated types don't allow promises to be returned and expect the value itself. If it's the same scenario for you, adding a @ts-ignore as a temporary fix to avoid your IDE screaming at you would probably work for now.

I could probably get into fixing this issue later this week as well.

@tgriesser
Copy link
Member

I could probably get into fixing this issue later this week as well.

Yeah, if you want to see if there’s a reasonable fix for this one, that’d be great.

I remember trying to do this genetically at one point early on (making all obj properties T | Promise<T>, recursively) but it made the typings way more complicated and it didn’t seem to be worth the trouble.

Might try and think about this a bit more sometime soon and see if there’s a good middle ground.

@shreyas44 shreyas44 linked a pull request May 15, 2021 that will close this issue
@Sytten Sytten added scope/types Having to do with types type/bug Something is not working the way it should labels Jul 26, 2021
@GuessWhatBBQ
Copy link

I've been facing the exact issue described in the initial comment. Trying to use the prisma fluent api results is a type error if the relation is one-to-many, meaning an array is returned instead of a single object.

So for example the following works fine with no errors:

export const Link = objectType({
    name: "Link",
    definition(t) {
        t.nonNull.int("id");
        t.field("postedBy", {
            type: "User",
            resolve(parent, args, context) {
                return context.prisma.link
                    .findUnique({ where: { id: parent.id } })
                    .postedBy();
            },
        });
    },
});

This on the other hand won't compile unless I provide the @ts-ignore directive but will execute fine at runtime:

export const User = objectType({
    name: "User",
    definition(t) {
        t.nonNull.int("id");
        t.nonNull.list.nonNull.field("links", {
            type: "Link",
            resolve(parent, args, context) {
                return context.prisma.user
                    .findUnique({ where: { id: parent.id } })
                    .links();
            },
        });
    },
});

If I'm doing something wrong I would really appreciate being pointed in the right direction for a fix

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
scope/types Having to do with types type/bug Something is not working the way it should
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants