Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(code-first): Use capitalized case for enums in code-first #1852

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
2 changes: 2 additions & 0 deletions packages/apollo/tests/code-first/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ import { Module } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';
import { ApolloDriverConfig } from '../../lib';
import { ApolloDriver } from '../../lib/drivers';
import { CatsModule } from './cats/cats.module';
import { DirectionsModule } from './directions/directions.module';
import { RecipesModule } from './recipes/recipes.module';

@Module({
imports: [
RecipesModule,
DirectionsModule,
CatsModule,
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
debug: false,
Expand Down
11 changes: 10 additions & 1 deletion packages/apollo/tests/code-first/cats/cats.resolver.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
import { Query, Resolver } from '@nestjs/graphql';
import { Args, Query, Resolver } from '@nestjs/graphql';
import { CatType } from '../enums/cat-type.enum';

@Resolver()
export class CatsResolver {
@Query((returns) => String)
getAnimalName(): string {
return 'cat';
}

@Query((returns) => CatType)
catType(
@Args({ name: 'catType', type: () => CatType })
catType: CatType,
): CatType {
return catType;
}
}
16 changes: 16 additions & 0 deletions packages/apollo/tests/code-first/enums/cat-type.enum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { registerEnumType } from '@nestjs/graphql';

export enum CatType {
PersianCat = 'persian-cat',
MaineCoon = 'maine-coon',
Ragdoll = 'ragdoll',
SomeNewAwesomeCat = 'some-new-awesome-cat',
SomeWEIRDCat = 'some-weird-cat',
anotherAwesomeCat = 'another-awesome-cat',
}

registerEnumType(CatType, {
name: 'CatType',
description: 'Distinguish cats',
mapToUppercase: true,
});
59 changes: 57 additions & 2 deletions packages/apollo/tests/e2e/code-first-schema.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { SampleOrphanedType } from '../code-first/other/sample-orphaned.type';
import { IRecipesResolver } from '../code-first/recipes/irecipes.resolver';
import { Recipe } from '../code-first/recipes/models/recipe';
import { RecipesResolver } from '../code-first/recipes/recipes.resolver';
import { CatsResolver } from '../code-first/cats/cats.resolver';
import {
getMutation,
getMutationByName,
Expand Down Expand Up @@ -50,6 +51,7 @@ describe('Code-first - schema factory', () => {
[
RecipesResolver,
DirectionsResolver,
CatsResolver,
AbstractResolver,
IRecipesResolver,
],
Expand All @@ -68,17 +70,18 @@ describe('Code-first - schema factory', () => {
printedSchemaSnapshot,
);
});
it('should define 5 queries', async () => {
it('should define 7 queries', async () => {
const type = getQuery(introspectionSchema);

expect(type.fields.length).toEqual(5);
expect(type.fields.length).toEqual(7);
expect(type.fields.map((item) => item.name)).toEqual(
expect.arrayContaining([
'recipes',
'search',
'categories',
'move',
'recipe',
'catType',
]),
);
});
Expand Down Expand Up @@ -154,6 +157,58 @@ describe('Code-first - schema factory', () => {
);
});

it('should define "CatType" enum to use CAPITALIZED_UNDERSCORE', () => {
const type = introspectionSchema.types.find(
({ name }) => name === 'CatType',
);

expect(type).toEqual(
expect.objectContaining({
kind: TypeKind.ENUM,
name: 'CatType',
description: 'Distinguish cats',
enumValues: [
{
deprecationReason: null,
description: null,
isDeprecated: false,
name: 'PERSIAN_CAT',
},
{
deprecationReason: null,
description: null,
isDeprecated: false,
name: 'MAINE_COON',
},
{
deprecationReason: null,
description: null,
isDeprecated: false,
name: 'RAGDOLL',
},
{
deprecationReason: null,
description: null,
isDeprecated: false,
name: 'SOME_NEW_AWESOME_CAT',
},
{
deprecationReason: null,
description: null,
isDeprecated: false,
name: 'SOME_WEIRD_CAT',
},
{
deprecationReason: null,
description: null,
isDeprecated: false,
name: 'ANOTHER_AWESOME_CAT',
},
],
}),
);
});

it('should define "SearchResultUnion" union', () => {
const type = introspectionSchema.types.find(
({ name }) => name === 'SearchResultUnion',
Expand Down
2 changes: 2 additions & 0 deletions packages/apollo/tests/graphql/sort-auto-schema.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import { GraphQLModule } from '@nestjs/graphql';
import { ApolloDriver } from '../../lib/drivers';
import { DirectionsModule } from '../code-first/directions/directions.module';
import { RecipesModule } from '../code-first/recipes/recipes.module';
import { CatsModule } from '../code-first/cats/cats.module';

@Module({
imports: [
RecipesModule,
DirectionsModule,
CatsModule.register('useClass'),
GraphQLModule.forRoot({
driver: ApolloDriver,
autoSchemaFile: 'schema.graphql',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import { GraphQLSchema, lexicographicSortSchema } from 'graphql';
import { ApolloDriver } from '../../lib/drivers';
import { DirectionsModule } from '../code-first/directions/directions.module';
import { RecipesModule } from '../code-first/recipes/recipes.module';
import { CatsModule } from '../code-first/cats/cats.module';

@Module({
imports: [
RecipesModule,
DirectionsModule,
CatsModule.register('useClass'),
GraphQLModule.forRoot({
driver: ApolloDriver,
autoSchemaFile: 'schema.graphql',
Expand Down
24 changes: 24 additions & 0 deletions packages/apollo/tests/utils/printed-schema.snapshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ type Query {
take: Int = 25
): [Recipe!]!
move(direction: Direction!): Direction!
getAnimalName: String!
catType(catType: CatType!): CatType!
}

"""Search result description"""
Expand All @@ -90,6 +92,16 @@ enum Direction {
Sideways @deprecated(reason: "Replaced with Left or Right")
}

"""Distinguish cats"""
enum CatType {
PERSIAN_CAT
MAINE_COON
RAGDOLL
SOME_NEW_AWESOME_CAT
SOME_WEIRD_CAT
ANOTHER_AWESOME_CAT
}

type Mutation {
addRecipe(newRecipeData: NewRecipeInput!): Recipe!
removeRecipe(id: String!): Boolean!
Expand All @@ -113,6 +125,16 @@ export const sortedPrintedSchemaSnapshot = `# ----------------------------------
# THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)
# ------------------------------------------------------

"""Distinguish cats"""
enum CatType {
ANOTHER_AWESOME_CAT
MAINE_COON
PERSIAN_CAT
RAGDOLL
SOME_NEW_AWESOME_CAT
SOME_WEIRD_CAT
}

type Category {
description: String!
name: String!
Expand Down Expand Up @@ -162,7 +184,9 @@ input NewRecipeInput {
}

type Query {
catType(catType: CatType!): CatType!
categories: [Category!]!
getAnimalName: String!
move(direction: Direction!): Direction!

"""get recipe by id"""
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { upperCase } from 'lodash';
import { Injectable } from '@nestjs/common';
import { GraphQLEnumType } from 'graphql';
import { EnumMetadata } from '../metadata';

export const mapToUppercase = (value: string): string =>
upperCase(value).replaceAll(' ', '_');

export interface EnumDefinition {
enumRef: object;
type: GraphQLEnumType;
Expand All @@ -19,7 +23,13 @@ export class EnumDefinitionFactory {
description: metadata.description,
values: Object.keys(enumValues).reduce((prevValue, key) => {
const valueMap = metadata.valuesMap[key];
prevValue[key] = {

let enumKey = key;
if (metadata.mapToUppercase) {
enumKey = mapToUppercase(key);
}

prevValue[enumKey] = {
value: enumValues[key],
description: valueMap?.description,
deprecationReason: valueMap?.deprecationReason,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ export interface EnumMetadata<T extends object = any> {
name: string;
description?: string;
valuesMap?: EnumMetadataValuesMap<T>;
mapToUppercase?: boolean;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kasvith this option seems to be a single purpose one. Would it be better to take a key transform function so that people can use any function they want for the enum keys? toUppercase could then become the default and the feature would become a lot more useful.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @mareksuscak

By convention GraphQL enums are UPPER_CASE literals, i dont see a usecase to have a transformer function and make this much more complicated than it is now

https://www.apollographql.com/tutorials/side-quest-intermediate-schema-design/02-the-enum-type

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ export interface EnumOptions<T extends object = any> {
* A map of options for the values of the enum.
*/
valuesMap?: EnumMetadataValuesMap<T>;

/**
* Automatically map enum to UPPER_CASE in the schema.
* Defaults to `false`
*/
mapToUppercase?: boolean;
}

/**
Expand All @@ -41,6 +47,7 @@ export function registerEnumType<T extends object = any>(
name: options.name,
description: options.description,
valuesMap: options.valuesMap || {},
mapToUppercase: options.mapToUppercase || false,
}),
);
}