From fccba79c118082be6d8c40ba5322ff82f02aaa56 Mon Sep 17 00:00:00 2001 From: David Richolm Date: Wed, 18 Oct 2023 18:45:45 +0000 Subject: [PATCH 1/3] fix(ra-data-graphql-simple): Handle nested types - Handle nested lists and non-null types. --- .../src/buildGqlQuery.test.ts | 44 +------ .../src/buildGqlQuery.ts | 29 +---- .../src/getGqlType.test.ts | 109 ++++++++++++++++++ .../ra-data-graphql-simple/src/getGqlType.ts | 23 ++++ .../src/isRequired.test.ts | 37 ------ .../ra-data-graphql-simple/src/isRequired.ts | 18 --- 6 files changed, 139 insertions(+), 121 deletions(-) create mode 100644 packages/ra-data-graphql-simple/src/getGqlType.test.ts create mode 100644 packages/ra-data-graphql-simple/src/getGqlType.ts delete mode 100644 packages/ra-data-graphql-simple/src/isRequired.test.ts delete mode 100644 packages/ra-data-graphql-simple/src/isRequired.ts diff --git a/packages/ra-data-graphql-simple/src/buildGqlQuery.test.ts b/packages/ra-data-graphql-simple/src/buildGqlQuery.test.ts index d37fdff5d14..27d2550ea34 100644 --- a/packages/ra-data-graphql-simple/src/buildGqlQuery.test.ts +++ b/packages/ra-data-graphql-simple/src/buildGqlQuery.test.ts @@ -8,6 +8,7 @@ import { CREATE, DELETE, } from 'ra-core'; + import buildGqlQuery, { buildApolloArgs, buildArgs, @@ -17,51 +18,14 @@ import buildGqlQuery, { describe('getArgType', () => { it('returns the arg type', () => { - expect( - print(getArgType({ type: { kind: TypeKind.SCALAR, name: 'foo' } })) - ).toEqual('foo'); - }); - it('returns the arg type for NON_NULL types', () => { - expect( - print( - getArgType({ - type: { - kind: TypeKind.NON_NULL, - ofType: { name: 'ID', kind: TypeKind.SCALAR }, - }, - }) - ) - ).toEqual('ID!'); - }); - it('returns the arg type for LIST types', () => { expect( print( getArgType({ - type: { - kind: TypeKind.LIST, - ofType: { name: 'ID', kind: TypeKind.SCALAR }, - }, + name: 'arg', + type: { kind: TypeKind.SCALAR, name: 'foo' }, }) ) - ).toEqual('[ID]'); - }); - it('returns the arg type for LIST types of NON_NULL type', () => { - expect( - print( - getArgType({ - type: { - kind: TypeKind.LIST, - ofType: { - kind: TypeKind.NON_NULL, - ofType: { - kind: TypeKind.SCALAR, - name: 'ID', - }, - }, - }, - }) - ) - ).toEqual('[ID!]'); + ).toEqual('foo'); }); }); diff --git a/packages/ra-data-graphql-simple/src/buildGqlQuery.ts b/packages/ra-data-graphql-simple/src/buildGqlQuery.ts index 59190f175b1..0d3ec039ade 100644 --- a/packages/ra-data-graphql-simple/src/buildGqlQuery.ts +++ b/packages/ra-data-graphql-simple/src/buildGqlQuery.ts @@ -18,8 +18,7 @@ import { import * as gqlTypes from 'graphql-ast-types-browser'; import getFinalType from './getFinalType'; -import isList from './isList'; -import isRequired from './isRequired'; +import { getGqlType } from './getGqlType'; export default (introspectionResults: IntrospectionResult) => ( resource: IntrospectedResource, @@ -241,27 +240,5 @@ export const buildApolloArgs = ( return args; }; -export const getArgType = (arg: IntrospectionInputValue): TypeNode => { - const type = getFinalType(arg.type); - const required = isRequired(arg.type); - const list = isList(arg.type); - - if (list) { - if (required) { - return gqlTypes.listType( - gqlTypes.nonNullType( - gqlTypes.namedType(gqlTypes.name(type.name)) - ) - ); - } - return gqlTypes.listType(gqlTypes.namedType(gqlTypes.name(type.name))); - } - - if (required) { - return gqlTypes.nonNullType( - gqlTypes.namedType(gqlTypes.name(type.name)) - ); - } - - return gqlTypes.namedType(gqlTypes.name(type.name)); -}; +export const getArgType = (arg: IntrospectionInputValue): TypeNode => + getGqlType(arg.type); diff --git a/packages/ra-data-graphql-simple/src/getGqlType.test.ts b/packages/ra-data-graphql-simple/src/getGqlType.test.ts new file mode 100644 index 00000000000..a65847104ae --- /dev/null +++ b/packages/ra-data-graphql-simple/src/getGqlType.test.ts @@ -0,0 +1,109 @@ +import { TypeKind, print } from 'graphql'; +import { getGqlType } from './getGqlType'; + +describe('getGqlType', () => { + it('returns the arg type', () => { + expect( + print(getGqlType({ kind: TypeKind.SCALAR, name: 'foo' })) + ).toEqual('foo'); + }); + + it('returns the arg type for NON_NULL types', () => { + expect( + print( + getGqlType({ + kind: TypeKind.NON_NULL, + ofType: { name: 'ID', kind: TypeKind.SCALAR }, + }) + ) + ).toEqual('ID!'); + }); + + it('returns the arg type for LIST types', () => { + expect( + print( + getGqlType({ + kind: TypeKind.LIST, + ofType: { name: 'ID', kind: TypeKind.SCALAR }, + }) + ) + ).toEqual('[ID]'); + }); + + it('returns the arg type for LIST with NON_NULL item types', () => { + expect( + print( + getGqlType({ + kind: TypeKind.LIST, + ofType: { + kind: TypeKind.NON_NULL, + ofType: { + kind: TypeKind.SCALAR, + name: 'ID', + }, + }, + }) + ) + ).toEqual('[ID!]'); + }); + + it('returns the arg type for NON_NULL LIST with nullable item type', () => { + expect( + print( + getGqlType({ + kind: TypeKind.NON_NULL, + ofType: { + kind: TypeKind.LIST, + ofType: { + kind: TypeKind.SCALAR, + name: 'ID', + }, + }, + }) + ) + ).toEqual('[ID]!'); + }); + + it('returns the arg type for NON_NULL LIST with NON_NULL items', () => { + expect( + print( + getGqlType({ + kind: TypeKind.NON_NULL, + ofType: { + kind: TypeKind.LIST, + ofType: { + kind: TypeKind.NON_NULL, + ofType: { + kind: TypeKind.SCALAR, + name: 'ID', + }, + }, + }, + }) + ) + ).toEqual('[ID!]!'); + }); + + it('returns the arg type for nested LIST and NON_NULL items', () => { + expect( + print( + getGqlType({ + kind: TypeKind.NON_NULL, + ofType: { + kind: TypeKind.LIST, + ofType: { + kind: TypeKind.LIST, + ofType: { + kind: TypeKind.NON_NULL, + ofType: { + kind: TypeKind.SCALAR, + name: 'ID', + }, + }, + }, + }, + }) + ) + ).toEqual('[[ID!]]!'); + }); +}); diff --git a/packages/ra-data-graphql-simple/src/getGqlType.ts b/packages/ra-data-graphql-simple/src/getGqlType.ts new file mode 100644 index 00000000000..b827c7189a9 --- /dev/null +++ b/packages/ra-data-graphql-simple/src/getGqlType.ts @@ -0,0 +1,23 @@ +import { + IntrospectionListTypeRef, + IntrospectionType, + IntrospectionTypeRef, + TypeKind, + TypeNode, +} from 'graphql'; +import * as gqlTypes from 'graphql-ast-types-browser'; + +export const getGqlType = ( + type: IntrospectionType | IntrospectionListTypeRef | IntrospectionTypeRef +): TypeNode => { + switch (type.kind) { + case TypeKind.LIST: + return gqlTypes.listType(getGqlType(type.ofType)); + + case TypeKind.NON_NULL: + return gqlTypes.nonNullType(getGqlType(type.ofType)); + + default: + return gqlTypes.namedType(gqlTypes.name(type.name)); + } +}; diff --git a/packages/ra-data-graphql-simple/src/isRequired.test.ts b/packages/ra-data-graphql-simple/src/isRequired.test.ts deleted file mode 100644 index aa626dc9178..00000000000 --- a/packages/ra-data-graphql-simple/src/isRequired.test.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { TypeKind } from 'graphql'; -import isRequired from './isRequired'; - -describe('isRequired', () => { - it('returns the correct type for SCALAR types', () => { - expect(isRequired({ name: 'foo', kind: TypeKind.SCALAR })).toEqual( - false - ); - }); - it('returns the correct type for NON_NULL types', () => { - expect( - isRequired({ - kind: TypeKind.NON_NULL, - ofType: { name: 'foo', kind: TypeKind.SCALAR }, - }) - ).toEqual(true); - }); - it('returns the correct type for LIST types', () => { - expect( - isRequired({ - kind: TypeKind.LIST, - ofType: { name: 'foo', kind: TypeKind.SCALAR }, - }) - ).toEqual(false); - }); - it('returns the correct type for NON_NULL LIST types', () => { - expect( - isRequired({ - kind: TypeKind.NON_NULL, - ofType: { - kind: TypeKind.LIST, - ofType: { name: 'foo', kind: TypeKind.SCALAR }, - }, - }) - ).toEqual(true); - }); -}); diff --git a/packages/ra-data-graphql-simple/src/isRequired.ts b/packages/ra-data-graphql-simple/src/isRequired.ts deleted file mode 100644 index 11e2dd8843c..00000000000 --- a/packages/ra-data-graphql-simple/src/isRequired.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { - IntrospectionType, - IntrospectionListTypeRef, - IntrospectionTypeRef, - TypeKind, -} from 'graphql'; - -const isRequired = ( - type: IntrospectionType | IntrospectionListTypeRef | IntrospectionTypeRef -) => { - if (type.kind === TypeKind.LIST) { - return isRequired(type.ofType); - } - - return type.kind === TypeKind.NON_NULL; -}; - -export default isRequired; From 8998608db2c96bce64ff8fba4060a5fd72784db0 Mon Sep 17 00:00:00 2001 From: David Richolm Date: Fri, 20 Oct 2023 15:30:15 +0000 Subject: [PATCH 2/3] refactor: Remove wrapper function in buildGqlQuery --- .../src/buildGqlQuery.test.ts | 14 -------------- .../ra-data-graphql-simple/src/buildGqlQuery.ts | 5 +---- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/packages/ra-data-graphql-simple/src/buildGqlQuery.test.ts b/packages/ra-data-graphql-simple/src/buildGqlQuery.test.ts index 27d2550ea34..ee49d64101f 100644 --- a/packages/ra-data-graphql-simple/src/buildGqlQuery.test.ts +++ b/packages/ra-data-graphql-simple/src/buildGqlQuery.test.ts @@ -13,22 +13,8 @@ import buildGqlQuery, { buildApolloArgs, buildArgs, buildFields, - getArgType, } from './buildGqlQuery'; -describe('getArgType', () => { - it('returns the arg type', () => { - expect( - print( - getArgType({ - name: 'arg', - type: { kind: TypeKind.SCALAR, name: 'foo' }, - }) - ) - ).toEqual('foo'); - }); -}); - describe('buildArgs', () => { it('returns an empty array when query does not have any arguments', () => { expect(buildArgs({ args: [] }, {})).toEqual([]); diff --git a/packages/ra-data-graphql-simple/src/buildGqlQuery.ts b/packages/ra-data-graphql-simple/src/buildGqlQuery.ts index 0d3ec039ade..abcf71ad737 100644 --- a/packages/ra-data-graphql-simple/src/buildGqlQuery.ts +++ b/packages/ra-data-graphql-simple/src/buildGqlQuery.ts @@ -232,13 +232,10 @@ export const buildApolloArgs = ( ...acc, gqlTypes.variableDefinition( gqlTypes.variable(gqlTypes.name(arg.name)), - getArgType(arg) + getGqlType(arg.type) ), ]; }, []); return args; }; - -export const getArgType = (arg: IntrospectionInputValue): TypeNode => - getGqlType(arg.type); From 692226a238aa192690933586f35bcf31489ae149 Mon Sep 17 00:00:00 2001 From: David Richolm Date: Mon, 23 Oct 2023 17:18:06 +0000 Subject: [PATCH 3/3] fix(buildGqlQuery): Remove unused imports --- packages/ra-data-graphql-simple/src/buildGqlQuery.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/ra-data-graphql-simple/src/buildGqlQuery.ts b/packages/ra-data-graphql-simple/src/buildGqlQuery.ts index abcf71ad737..a3ff4129e74 100644 --- a/packages/ra-data-graphql-simple/src/buildGqlQuery.ts +++ b/packages/ra-data-graphql-simple/src/buildGqlQuery.ts @@ -7,12 +7,10 @@ import { import { ArgumentNode, IntrospectionField, - IntrospectionInputValue, IntrospectionNamedTypeRef, IntrospectionObjectType, IntrospectionUnionType, TypeKind, - TypeNode, VariableDefinitionNode, } from 'graphql'; import * as gqlTypes from 'graphql-ast-types-browser';