graphql-to-mongodb icon indicating copy to clipboard operation
graphql-to-mongodb copied to clipboard

How to incorporate into NestJS?

Open yaser-ali-s opened this issue 5 years ago • 3 comments

I was wondering if there was a way to integrate this with NestJS? I found myself implementing the features manually until I ran into your project. I tried to translate your code into the way NestJS is implementing their code, but ran into issues. Would very much appreciate any pointers you have.

yaser-ali-s avatar Nov 19 '19 14:11 yaser-ali-s

I have posted a question on SO with the full details of my set up and why I need to implement this solution. I assume it is somewhat similar to the apollo example, but I'm not sure how to go about it.

yaser-ali-s avatar Nov 20 '19 08:11 yaser-ali-s

@yaser-ali-s

Hi, I did something like this for TypeOrm:

@InputType()
class GqlQueryFilter {}

export function GqlFilter<T>(classRef: Type<T>): Type<T> {
  const { fields, decoratorFactory } = getFieldsAndDecoratorForType(classRef);

  abstract class Filter {}

  decoratorFactory({ isAbstract: true })(GqlQueryFilter);

  Object.values(constantOptions) // this is an object with the operators like: EQ, NOT EQ, CONTAINS, NOT...
    .filter(prop => prop !== constantOptions.NOT)
    .forEach(prop => {
      Field(() => String, { nullable: true })(GqlQueryFilter.prototype, prop);
      Field(() => String, { nullable: true })(
        GqlQueryFilter.prototype,
        constantOptions.NOT + prop,
      );
    });

  decoratorFactory({ isAbstract: true })(Filter);
  fields.forEach(item => {
    if (isFunction(item.typeFn)) {
      /**
       * Execute type function eagarly to update the type options object (before "clone" operation)
       * when the passed function (e.g., @Field(() => Type)) lazily returns an array.
       */
      item.typeFn = () => GqlQueryFilter;
      item.typeFn();
    }

    Field(item.typeFn, { ...item.options, nullable: true })(
      Filter.prototype,
      item.name,
    );
  });
  return Filter as Type<T>;
}

export function GqlQueryObject<T>(classRef: Type<T>): Type<T> {
  const { fields, decoratorFactory } = getFieldsAndDecoratorForType(classRef);

  abstract class QueryObject {}
  decoratorFactory({ isAbstract: true })(QueryObject);

  Field(() => Int, { nullable: true })(QueryObject.prototype, 'limit');
  Field(() => Int, { nullable: true })(QueryObject.prototype, 'page');
  Field(() => [classRef], { nullable: true })(QueryObject.prototype, 'filter');

  return QueryObject as Type<T>;
}

and the usage is like that:

// define the query ObjectType for the gql schema 
@InputType()
class UsuarioFilter extends GqlFilter(Usuario) {}

@InputType()
export class UsuarioQuery extends GqlQueryObject(UsuarioFilter) {}

---
//on resolver we add the query as type
  @Query(returns => [Usuario])
  async usuarios(
    @Args('query', { nullable: true }) gqlQuery: UsuarioQuery,
  ): Promise<Usuario[]> {
    return this.usuarioApi.buscarUsuarios(gqlQuery);
  }

the query:

 usuarios(query: { name: { eq: "test" } }) {
    id
}

I'm doing it right now for mongo, In case u need I can share it.

fikani avatar Sep 15 '20 22:09 fikani

Hey @fikani Would love to get the MongoDB class

iamkhalidbashir avatar Jul 04 '22 08:07 iamkhalidbashir