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

defaultFields, set child defaultFields from parent type #333

Open
cyril94440 opened this issue May 29, 2024 · 6 comments
Open

defaultFields, set child defaultFields from parent type #333

cyril94440 opened this issue May 29, 2024 · 6 comments

Comments

@cyril94440
Copy link

Hi there,

Thanks for your awesome library, it is so great to optimize GraphQL queries!

Problem Description

I am trying to do the following:
I have a type Parent which contains an array of Child.

It is easy to define the defaultFields for the Parent, and also for the Child, but what I am trying to do is to add defaultFields to the Child if the Parent has some field in select.

Attempted Solution

I have tried this:

Parent: (select) => {
    if (select.fieldThatNeedsChild) {
        return {
            id: true,
            children: {
                select: {
                    fieldNeeded: true
                }
            }
        };
    }
};

But it only works if children is not requested in the GraphQL query. As soon as it is requested, the children.select is overridden.

Unfortunately, in the Child.select function, I don’t have the parent select fields, so I can’t add the fields there.

Desired Outcome

Is there any solution to this problem?

Basically, what I need to do is to add computed fields on the Parent which need info from Child, and I’d like to avoid an additional query as I could easily compute it if children are present.

Thanks for your help.

@AhmedElywa
Copy link
Collaborator

Hi,

Is this needed every time you query the parent type or in only some query
if you can do this at the query level we have a way

https://paljs.com/plugins/select#mergedeep

@cyril94440
Copy link
Author

cyril94440 commented May 31, 2024

Hi,

Is this needed every time you query the parent type or in only some query if you can do this at the query level we have a way

https://paljs.com/plugins/select#mergedeep

It looks like I can't do it at the query level easily because the "parent" is not always at the root of the query, sometimes there is a parent above it.

Why can't I return also a "mergeDeep" object in the defaultFields ?
because I don't have an as convenient way of checking a field in the query exists than with the (select) handler of the defaultFields object, and that is what I would need to enhance the prisma generated select with my new mergeDeep Object

@AhmedElywa
Copy link
Collaborator

AhmedElywa commented May 31, 2024

Look at this code and see how we can do this we are filtering the input fields to remove the fields not in the prisma model.
We add the default fields you send but after that, we overwrite them with the child-filtered fields you can check if you have any way

if (this.defaultFields && this.defaultFields[modelName]) {

Also, look at the line 284

@cyril94440
Copy link
Author

cyril94440 commented May 31, 2024

@ResolveField()
  exercises(@Args() args: FindManySportExerciseArgs, @Info() info) {
    const select = new PrismaSelect(info, {
      defaultFields,
    });

    const originalQuery = select.valueWithFilter('');

    let selectValue = select.value;

    if (originalQuery?.select?.title) {
      selectValue = PrismaSelect.mergeDeep(selectValue, {
        select: {
          simpleExercise: {
            select: {
              title: true,
            },
          },
        },
      });
    }

    return this.sportExercisesService.findMany(args, selectValue);
  }

I have done that, but it doesn't feel very efficient.

isn't there a way to do this like defaultFields, so that I don't have to add this piece of code on every CRUD resolvers .. ?

@AhmedElywa
Copy link
Collaborator

I am thinking on away to do the merge between default fields and the requested

But for now you can for easy way always query simpleExercise.title by adding it to default fields direct without any conditions

@cyril94440
Copy link
Author

Unfortunately, I am not querying simpleExercise, so even if I add title, it is not queried in my original request.
And even if I add simpleExercise: true to the parent type, I have another use case where I have one more nested level which is starting to make this really inefficient.

What I am think now, is to create an helper method that generate the PrismaSelect AND apply a given mergeDeep object based on some kind of logic similar to the defaultFields one. However, as of today, I am relying on this to determine if the computed field is requested :

 const originalQuery = select.valueWithFilter('');
 if (originalQuery?.select?.title) {
 }

which works only if the compute field is at the parent level.

What would be great, would be to be able to generate directly from the defaultFields object, not only a parent-level fields flat object but also a mergeDeep compatible one that would be applied automatically or manually. And then we could easily add general logic to query nested fields based on a parent field condition.

I am thinking of doing that manually but I don't think there is an easy way to check if a given field is present on a given GraphQL type with prisma-tools, you for sure do that already within the library but no method of this kind is exposed appart from the defaultFields which is not flexible enough. I am also thinking of doing that manually, but then we would be analyzing the graphQL twice (1 within prisma-tools and once more with my code).

I really think that there is some kind of easy fix to that, as it seems you already do everything, but I don't know the inside of prisma-tool enough to expose the appropriate method.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants