Nested Fragments not functioning as expected


#1

I have a schema with an array of another type (here’s a simplified version):

type Parent {
    name: String!
    id: ID!
    children: [Child!]!
}

type Child {
    id: ID!
    nickname: String!
    grade: Int!
 }

I have a resolver for children that requires both the id of the parent and the nickname of each of the children to perform it’s function. Since the query may come in without those fields, I would like to require it with a fragment:

fragment: 'fragment pub on Parent { id children { nickname } }'

but if I do that it fails ugly (“JavaScript heap out of memory”). Having a fragment only looking for { id } is working fine.

I have tried putting a resolver with a fragment on Child.nickname, but that resolver is not being called unless the query is one that returns that type.

Please advise me what I’m doing wrong. How can I be sure to get each children[xx].nickname without doing a second, costly fetch?


#2

Taking a guess here: are you resolving the parent with prisma client?

Prisma client by default functions pretty much like SELECT * FROM <table-name>, so you get all fields but no relations.

Prisma bindings does resolve as deep as possible.

Anyways please share your resolver function.


#3

Thanks for the quick response. Actually it’s a prisma binding. A simplified version of the resolver is:

children: {
//  fragment: 'fragment userId on Parent { id children { nickname } }',
//  fragment: 'fragment pub on Child { nickname }',
  resolve(parent, args, { prisma }, info) {
    return parent.children.filter((child) => (child.nickname === 'Jack'))
  }
}

The first commented fragment is what I think I should be able to do. The second version doesn’t seem to do anything.


#4

The second version is correct. But please show me the Parent resolver. By the time we get to this children resolver, the fragment data should already be available


#5

What I reproduced above is a field resolver on the Parent type resolver object. There is nothing else on it except another field resolver…

const Parent = {

// another field resolver

// the children resolver shown above

}

Everything else is left to the defaults.


#6

Yes. What I want to see is the parent resolver itself, probably on the Query type, or whatever type you have it on.


#7

Not much to it…

  parents(parent, args, { prisma }, info) {

    const opArgs = {
      first: args.first,
      skip: args.skip,
      after: args.after
    }

    if (args.query) {
      opArgs.where = {
        name_contains: args.query
      }
    }

    return prisma.query.parents(opArgs, info)
  },

#8

Looks ok… You are adding your fragment replacements to your bindings instance right?

Edit:

Example:

Extract fragmentReplacements:

Use them when creating prisma bindings class instance:


#9

Yes. Almost verbatim to your examples.

To me, the biggest mystery is why the field resolver on Child.nickname doesn’t get called when it is supposed to be deep-resolving Parent.children (if I knew that, I think it would be clear why the fragment isn’t working). I know the field resolver was configured OK, because it does get called when resolving a query that returns a Child.


#10

What is the result of this:

children: {
  fragment: 'fragment ChildrenNicknames on Parent { id children { id nickname } }',
  resolve(parent, args, { prisma }, info) {
    console.log(parent)
    return parent.children.filter((child) => (child.nickname === 'Jack'))
  }
}


#11

Well, I tried it. It crashed ugly:

Security context: 0x018b0051e549 <JSObject>
    0: builtin exit frame: concat(this=0x01d238a26559 <JSArray[0]>,0x012899d6af11 <JSArray[2]>,0x01d238a26559 <JS
Array[0]>)

    1: SelectionSet [000001DFAFDE5DD1] [C:\Users\eric\Dropbox\Programming\graphql-course\graphql-prisma\node_modu
les\graphql-tools\dist\transforms\ReplaceFieldWithFragment.js:~42] [pc=0000001D33110DFE](this=0x00199063d039 <Obj
ect map = 000003DA1C1D8999>,node=0x02fd266ae321...

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory

#12

After a bit more experimentation, I have found that the Child field resolvers (including the associated fragments) fire if that field is explicitly listed on the query. So, I worked around my problem by adding a nickname fragment for every Child field other than nickname. This works, but is clearly suboptimal.

My findings:

  1. Putting a fragment that references a different type does nothing.

  2. Putting a structured fragment (i.e., a nested fragment) causes a bad crash.

  3. A field resolver is fired if and only if the field is explicitly on the query (a cross reference does not do the trick).

Am I missing anything here? I do think the structured fragments should work.


#13

I am having the same issue, tried to add a fragment to a nested resolver, it crashes if I try to do a nested fragment, and I have no other way to get the field I want…


#14

Well, the only solution I found was to put a fragment on every field (except the field you need) on that type. And, you still need SOMETHING on that type to be on the query.


#15

This topic was automatically closed 45 days after the last reply. New replies are no longer allowed.