Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enums not working with nestjs and graphql

I have recently moved from using typegraphql and typeorm directly to using them with nestjs. Mostly this has been a straightforward experience. I however have one issue with respect to enums.

I have a set of custom decorators that I have combined together so that I can easily decorate up my models without having both typeorm, typegraphql and class validator decorators. This worked great before and works fine now in all cases other than enums.

As an example here is an @OptionalDecimal decorator:

import { IsNumber } from 'class-validator'
import { Field, Float } from 'type-graphql'
import { Column } from 'typeorm'

export function OptionalDecimal() {
    const typeDecorator = IsNumber()
    const fieldDecorator = Field(type => Float, { nullable: true })
    const columnDecorator = Column('decimal', { nullable: true })

    return (target: any, key: string) => {
        typeDecorator(target, key)
        fieldDecorator(target, key)
        columnDecorator(target, key)
    }
}

My @Enum decorator is as so:

import { IsEnum } from 'class-validator'
import { Field } from 'type-graphql'
import { Column } from 'typeorm'
import { IEnumOptions } from './IEnumOptions'

export function Enum(
    typeFunction: (type?: any) => object,
    options: IEnumOptions = {}
) {
    const isEnumDecorator = IsEnum(typeFunction())
    const fieldDecorator = Field(typeFunction)
    const columnDecorator = Column({
        default: options.default,
        enum: typeFunction(),
        type: 'enum',
    })

    return (target: any, key: string) => {
        isEnumDecorator(target, key)
        fieldDecorator(target, key)
        columnDecorator(target, key)
    }
}

I define my enums in separate files like so:

import { registerEnumType } from 'type-graphql'

export enum AccountState {
  ACTIVE,
  SUSPENDED,
  CLOSED,
}

registerEnumType(AccountState, { name: 'AccountState' })

And is used thusly:

@EntityType()
export class Member extends VersionedEntity {
  @IdentifierNewGuid()
  public readonly id: string

  @Enum(type => AccountState, { default: AccountState.ACTIVE })
  public accountState: AccountState
...

My database is returning numeric ids for the enumerations and the field type in the database (mysql) is enum. As an example where my database is returning 1 for accountState which should be SUSPENDED I receive a graphql error:

  "errors": [
    {
      "message": "Expected a value of type \"AccountState\" but received: 1",
      "locations": [
        {
          "line": 3,
          "column": 5
        }
      ],
      "path": [
        "searchMembers",
        0,
        "accountState"
      ],
      "extensions": {
        "code": "INTERNAL_SERVER_ERROR",
        "exception": {
          "stacktrace": [
            "Error: Expected a value of type \"AccountState\" but received: 1",
            "    at completeLeafValue

So to recap this approach worked fine with typeorm and typegraphql directly but sadly fails to work now. All the other decorators I have appear to work fine (50+) so it's just something that's up specifically with enums.

This is a major blocker for me and any help would be greatly appreciated as I am currently out of ideas.

Edit - In response to Shusson, when I add the decorators manually it also does not work actually:

@Column({
    default: AccountState.ACTIVE,
    enum: AccountState,
    type: 'enum',
  })
@Field(type => AccountState)
public accountState: AccountState

Cheers, Mark

like image 865
TreeMan360 Avatar asked Apr 09 '19 17:04

TreeMan360


1 Answers

In the end I fixed this by making the enums equal their string equivalents rather than default numerical values when defining them like so:

export enum AccountState {
  ACTIVE='ACTIVE',
  SUSPENDED='SUSPENDED',
  CLOSED='CLOSED',
}

This results in storing the string value in the database instead which plays well with graphql. This definitely worked before, I am not sure how :) I would prefer to use numeric values from a db design perspective, so any ideas would still be appreciated.

like image 106
TreeMan360 Avatar answered Oct 12 '22 13:10

TreeMan360