Skip to content

Commit 80e594a

Browse files
authored
Allow enum types in schema (aws#95)
Fix schema generation with enums such that they are not interpreted as edges and can be used for query and mutation input.
1 parent 28eb315 commit 80e594a

File tree

5 files changed

+41
-5
lines changed

5 files changed

+41
-5
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ This release contains new support for Apollo Server integration.
2626
* Fixed bug with ID argument type conversion and added Apollo arguments to help menu (#74)
2727
* Upgraded axios and babel versions to fix security warnings (#90)
2828
* Fixed failing integration test by excluding `node_modules` from Apollo zip (#94)
29+
* Fixed enum types in schema to be included in input types (#95)
2930

3031
### Features
3132

src/schemaModelValidator.js

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@ import {gql} from 'graphql-tag'
1616
import { loggerInfo, yellow } from "./logger.js";
1717

1818
let quiet = false;
19+
// TODO change variables to local scope instead of global so this module can be used against multiple schemas
1920
const typesToAdd = [];
2021
const queriesToAdd = [];
2122
const mutationsToAdd = [];
23+
const enumTypes = [];
2224

2325
function lowercaseFirstCharacter(inputString) {
2426
if (inputString.length === 0) {
@@ -238,7 +240,7 @@ function idFieldToInputValue({ name, type }) {
238240

239241

240242
function getInputFields(objTypeDef) {
241-
return objTypeDef.fields.filter(field => isScalar(nullable(field.type)));
243+
return objTypeDef.fields.filter(field => isScalarOrEnum(nullable(field.type)));
242244
}
243245

244246

@@ -247,9 +249,9 @@ function nullable(type) {
247249
}
248250

249251

250-
function isScalar(type) {
251-
const scalarTypes = ['String', 'Int', 'Float', 'Boolean', 'ID'];
252-
return type.kind === 'NamedType' && scalarTypes.includes(type.name.value);
252+
function isScalarOrEnum(type) {
253+
const scalarOrEnumTypes = ['String', 'Int', 'Float', 'Boolean', 'ID', ...enumTypes];
254+
return type.kind === 'NamedType' && scalarOrEnumTypes.includes(type.name.value);
253255
}
254256

255257

@@ -259,6 +261,10 @@ function inferGraphDatabaseDirectives(schemaModel) {
259261
let referencedType = '';
260262
let edgeName = '';
261263

264+
schemaModel.definitions
265+
.filter(definition => definition.kind === 'EnumTypeDefinition')
266+
.forEach(definition => enumTypes.push(definition.name.value));
267+
262268
schemaModel.definitions.forEach(def => {
263269
if (def.kind == 'ObjectTypeDefinition') {
264270
if (!(def.name.value == 'Query' || def.name.value == 'Mutation')) {
@@ -296,7 +302,8 @@ function inferGraphDatabaseDirectives(schemaModel) {
296302
} else if (field.type.name.value !== 'String' &&
297303
field.type.name.value !== 'Int' &&
298304
field.type.name.value !== 'Float' &&
299-
field.type.name.value !== 'Boolean') {
305+
field.type.name.value !== 'Boolean' &&
306+
!enumTypes.includes(field.type.name.value)) {
300307

301308
referencedType = field.type.name.value;
302309
edgeName = referencedType + 'Edge';

src/test/directive-id.graphql

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,15 @@ type User {
22
userId: ID! @id
33
firstName: String
44
lastName: String
5+
role: Role
56
}
67

78
type Group {
89
name: String
910
}
11+
12+
enum Role {
13+
ADMIN
14+
USER
15+
GUEST
16+
}

src/test/schemaModelValidator.test.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,15 @@ describe('validatedSchemaModel', () => {
1313
model = validatedSchemaModel(schemaParser(schema));
1414
});
1515

16+
test('types definitions should be as expected', () => {
17+
const objectTypes = model.definitions.filter(def => def.kind === 'ObjectTypeDefinition').map(def => def.name.value);
18+
expect(objectTypes).toEqual(expect.arrayContaining(['User','Group','Query', 'Mutation']));
19+
const inputTypes = model.definitions.filter(def => def.kind === 'InputObjectTypeDefinition').map(def => def.name.value);
20+
expect(inputTypes).toEqual(expect.arrayContaining(['UserInput','GroupInput','Options']));
21+
const enumTypes = model.definitions.filter(def => def.kind === 'EnumTypeDefinition').map(def => def.name.value);
22+
expect(enumTypes).toEqual(expect.arrayContaining(['Role']));
23+
});
24+
1625
test('should only add _id field to object types without ID fields', () => {
1726
const objTypeDefs = model.definitions.filter(def => def.kind === 'ObjectTypeDefinition');
1827
const userType = objTypeDefs.find(def => def.name.value === 'User');
@@ -49,6 +58,15 @@ describe('validatedSchemaModel', () => {
4958
});
5059
});
5160

61+
test('should allow enum types as input fields', () => {
62+
const roleEnumType = model.definitions.find(def => def.kind === 'EnumTypeDefinition' && def.name.value === 'Role');
63+
expect(roleEnumType.values.map(value => value.name.value)).toEqual(expect.arrayContaining(['USER','ADMIN','GUEST']));
64+
65+
const userInput = model.definitions.find(def => def.kind === 'InputObjectTypeDefinition' && def.name.value === 'UserInput');
66+
const userRoleField = userInput.fields.find(field => field.name.value === 'role');
67+
expect(userRoleField.type.name.value).toEqual('Role');
68+
});
69+
5270
function getIdFields(objTypeDef) {
5371
return objTypeDef.fields.filter(
5472
field =>

templates/queryHttpNeptune.mjs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ export async function queryNeptune(neptuneUrl, resolvedQuery, options = {logging
3333
};
3434

3535
let response;
36+
if (loggingEnabled) {
37+
console.log("Query: ", JSON.stringify(resolvedQuery, null, 2));
38+
}
3639
if (resolvedQuery.language === 'opencypher') {
3740
response = await axios.post(`${neptuneUrl}/opencypher`, {
3841
query: resolvedQuery.query, parameters: JSON.stringify(resolvedQuery.parameters)

0 commit comments

Comments
 (0)