graphql-compose / graphql-compose-mongoose

Mongoose model converter to GraphQL types with resolvers for graphql-compose https://github.com/nodkz/graphql-compose
MIT License
708 stars 94 forks source link

`filter` Arguments cannot be used if `filter` in used in addRelation `prepareArgs` #292

Open hanzal opened 3 years ago

hanzal commented 3 years ago

I added a relation as below on Item

ItemTC.addRelation(
    'category',
    {
        resolver: () => CategoryTC.mongooseResolvers.findOne(),
        prepareArgs: {
            filter: (source) => ({
                _id: source.categoryId,
            }),
        },
        projection: { categoryId: 1 }, // point fields in source object, which should be fetched from DB
    }
);

When i try to make a query as below

query getHotelAndTableMappings($uniqueId: String) {
    itemOne {
      category(filter: (name:"test")){
        name
        _id
        icon_url
      }
      name
      tags
  }

It throws an error for filter argument.

filter can be used if I dont pass the prepareArg field while creating a relation. Is this the expected behaviour? Is the a way to fetch category related to item and also apply filters on it?

balonsom commented 3 years ago

@hanzal It's an expected behaviour as described in the docs:

filter: (source) => value - hide filter arg form schema and at runtime evaluate its value

A way to achieve what you are looking for is by creating the relation via FieldConfig instead of using addRelation method.

You can follow the example in the docs or use something like this to replicate the default findOne resolver filter args:

ItemTC.addFields({
  category: {
    type: CategoryTC,
    description: 'Category for this item.',
    args: {
      filter: CategoryTC.mongooseResolvers.findOne().getArg('filter'),
    },
    resolve: (source, args) => {
      const prepareArgs = { _id: source.categoryId };
      const criteria = args.filter
        ? Object.keys(args.filter).reduce(
            (accumulated, key) => ({
              ...accumulated,
              [key]: args.filter[key],
            }),
            prepareArgs,
          )
        : prepareArgs;
      return DB.Categories.findOne(criteria); // Replace it with your own Category model.
    },
    projection: { categoryId: true },
  },
});

Have not tested it so it may fail, but can give you an idea of how to add a relation and be able to pass arguments.

nodkz commented 3 years ago

Yep, @balonsom provided I right solution 👍

addRelation under the hood creates a regular fieldConfig. And it provides a little bit of code sugar which helps to modify args (remove them).

@hanzal for your case better to create fieldConfig manually like above. But if you have any suggestions how addRelation can be improved - please let me know.

For now, I don't know what kind of configuration options should be provided to addRelation which