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

Use `setRecordIdFn` to override default `_id` generation behavior? #364

Open dannydi12 opened 2 years ago

dannydi12 commented 2 years ago

Hi, thank you for building such a great framework!

I need to be able to generate mutations that will automatically create _id. This functionality already exists but it builds a Mongo ObjectId. I need the ID to be a string.

The behavior I want to achieve:

  1. client calls the createOne mutation without providing an ID
  2. server creates a new mongo document with a string ID ex: _id: 'some-UUID-234'

I think I can modify the default behavior by using setRecordIdFn on my object type composer but I can't get it to work.

Shouldn't this work considering this excerpt from payloadRecordId.ts in this repo:

export type PayloadRecordIdHelperOpts = {
  /** Custom function for id generation. By default: `doc._id`. */
  fn?: (doc: any, context: any) => any;
  /** Custom output type for returned recordId */
  type?: string | ComposeOutputTypeDefinition<any>;
};

export function payloadRecordId<TSource = any, TContext = any>(
  tc: ObjectTypeComposer<TSource, TContext> | InterfaceTypeComposer<TSource, TContext>,
  opts?: PayloadRecordIdHelperOpts | false
): ObjectTypeComposerFieldConfigMapDefinition<TSource, TContext> | null {
  if (opts === false) return null;

  return {
    recordId: {
      description: 'Document ID',
      type: opts?.type ? opts.type : tc.hasField('_id') ? tc.getFieldTC('_id') : 'MongoID',
      resolve: (source, _, context) => {
        const doc = (source as any)?.record;
        if (!doc) return;
        return opts?.fn ? opts.fn(doc, context) : doc?._id;
      },
    },
  };
}

Thank you for your time!

dannydi12 commented 2 years ago

I found a solution! I did the following:

import { composeWithMongoose } from 'graphql-compose-mongoose'
import { Schema, model } from 'mongoose'
import { v4 as uuid } from 'uuid'

export type TestType = {
  _id: string;
  text: string;
  type: 'captionLibrary' | 'dashboard';
}

export const TestSchema = new Schema<TestType>({
  _id: { type: String, default: uuid },
  text: { type: String, required: true },
  type: { type: String, required: true }
})

export const Test = model('Test', TestSchema)
export const TestTC = composeWithMongoose(Test)

Turns out you can just define a default function in your Mongoose schema. That did the trick for me. I now have string UUIDs being generated from all my createOne mutations!

Thank you!