Skip to content

Refactor resolver creation #263

@nodkz

Description

@nodkz

This discussion was started here: graphql-compose/graphql-compose#281 (comment)

I was working under a new major version of graphql-compose-mongoose in my free time. And there was added 8 new resolvers and two old resolvers were changed with breaking changes. So according to these changes, I feel that storing resolvers in ObjectTypeComposer has the following disadvantages:

  • no static analysis for resolver names
  • no static analysis for available args when you are crating relations
  • quite awkward mechanics of creating new resolvers and wrapping them
  • no go-to support in IDE via ctrl+click for opening resolver definition

There is a long way but something already has done:

  • There were improved typescript definitions. Now generated Resolvers know source: Model<IDoc>
  • Created a new method composeMongoose which does not generate resolvers.
    • It adds mongooseResolvers property to TypeComposer with resolver generators. And when you need a resolver you may generate it in such way PostTC. mongooseResolvers.findMany() (before was PostTC.getResolver('findMany')).
    • Generating resolvers on demand allows you:
      • Modify TypeComposer in a programmatic way and only after that generate resolvers with customized fields
      • Safe memory and time on bootstrap server phase, because won't b generated unused resolvers
      • You may call resolver generators several times with different configurations.

And for now looks so:

import { schemaComposer, graphql } from 'graphql-compose';
import { composeMongoose } from 'graphql-compose-mongoose';
import mongoose, { Document } from 'mongoose';

const UserSchema = new mongoose.Schema({
  name: { type: String, required: true },
});

interface IUser extends Document {
  name: string;
}

const PostSchema = new mongoose.Schema({
  title: { type: String, required: true },
  authorId: { type: mongoose.Types.ObjectId },
  reviewerIds: { type: [mongoose.Types.ObjectId] },
});

interface IPost extends Document {
  title: string;
  authorId?: mongoose.Types.ObjectId;
  reviewerIds?: [mongoose.Types.ObjectId];
}

const UserModel = mongoose.model<IUser>('User', UserSchema);
const PostModel = mongoose.model<IPost>('Post', PostSchema);

const UserTC = composeMongoose(UserModel);
const PostTC = composeMongoose(PostModel);

PostTC.addRelation('author', {
  resolver: UserTC. mongooseResolvers.dataLoaderLean(), // <------ added `mongooseResolvers` with all resolvers
  prepareArgs: {
    _id: (s) => s.authorId,
  },
  projection: { authorId: true },
});

PostTC.addRelation('reviewers', {
  resolver: UserTC. mongooseResolvers.dataLoaderManyLean(), // <------ added `mongooseResolvers` with all resolvers
  prepareArgs: {
    _ids: (s) => s.reviewerIds,
  },
  projection: { reviewerIds: true },
});

schemaComposer.Query.addFields({
  posts: PostTC. mongooseResolvers.findMany(), // <------ added `mongooseResolvers` with all resolvers
});

const schema = schemaComposer.buildSchema();

UPD: in the code above generateResolver was renamed to mongooseResolvers.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions