Skip to content

Commit a54db9f

Browse files
authored
feat: generate searchable aggregateItems 2 additional levels (#268)
1 parent 2f1456d commit a54db9f

File tree

2 files changed

+93
-2
lines changed

2 files changed

+93
-2
lines changed

packages/graphql-docs-generator/__tests__/generator/getFields.test.ts

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLInt, GraphQLInterfaceType, GraphQLUnionType } from 'graphql';
1+
import { GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLInt, GraphQLInterfaceType, GraphQLUnionType, GraphQLFloat } from 'graphql';
22

33
import getFields from '../../src/generator/getFields';
44
import getFragment from '../../src/generator/getFragment';
@@ -185,4 +185,73 @@ describe('getField', () => {
185185
expect(getFragment.mock.calls[1][3]).toEqual(commonField);
186186
});
187187
});
188+
189+
describe('aggregateItems should generate two additional levels', () => {
190+
beforeEach(() => {
191+
jest.resetAllMocks();
192+
});
193+
const aggregateScalarResult = new GraphQLObjectType({
194+
name: 'SearchableAggregateScalarResult',
195+
fields: {
196+
value: { type: GraphQLFloat },
197+
},
198+
});
199+
200+
const aggregateBucketResultItem = new GraphQLObjectType({
201+
name: 'SearchableAggregateBucketResultItem',
202+
fields: {
203+
key: { type: GraphQLString },
204+
doc_count: { type: GraphQLInt },
205+
},
206+
});
207+
208+
const aggregateBucketResult = new GraphQLObjectType({
209+
name: 'SearchableAggregateBucketResult',
210+
fields: {
211+
buckets: { type: aggregateBucketResultItem },
212+
},
213+
});
214+
215+
const aggregateResult = new GraphQLUnionType({
216+
name: 'SearchableAggregateGenericResult',
217+
types: [aggregateScalarResult, aggregateBucketResult],
218+
});
219+
220+
const aggregateItemsObject = new GraphQLObjectType({
221+
name: 'SearchableAggregateResult',
222+
fields: {
223+
name: { type: GraphQLString },
224+
result: { type: aggregateResult },
225+
},
226+
});
227+
228+
const schema = new GraphQLSchema({
229+
query: new GraphQLObjectType({
230+
name: 'Query',
231+
fields: {
232+
aggregateItems: { type: aggregateItemsObject },
233+
},
234+
}),
235+
});
236+
237+
it('aggregateItems property should traverse two additional levels to generate required fields with default depth 2', () => {
238+
const maxDepth = 2;
239+
const getPossibleTypeSpy = jest.spyOn(schema, 'getPossibleTypes');
240+
getFields(schema.getQueryType().getFields().aggregateItems, schema, maxDepth, { useExternalFragmentForS3Object: false });
241+
expect(getPossibleTypeSpy).toHaveBeenCalled();
242+
expect(getFragment).toHaveBeenCalled();
243+
244+
const commonField = []; // unions don't have to have common field
245+
246+
expect(getFragment.mock.calls[0][0]).toEqual(aggregateScalarResult);
247+
expect(getFragment.mock.calls[0][1]).toEqual(schema);
248+
expect(getFragment.mock.calls[0][2]).toEqual(maxDepth - 1);
249+
expect(getFragment.mock.calls[0][3]).toEqual(commonField);
250+
251+
expect(getFragment.mock.calls[1][0]).toEqual(aggregateBucketResult);
252+
expect(getFragment.mock.calls[1][1]).toEqual(schema);
253+
expect(getFragment.mock.calls[1][2]).toEqual(maxDepth - 1);
254+
expect(getFragment.mock.calls[1][3]).toEqual(commonField);
255+
});
256+
});
188257
});

packages/graphql-docs-generator/src/generator/getFields.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
isUnionType,
1212
isEnumType,
1313
isScalarType,
14+
isListType,
1415
} from 'graphql';
1516
import getFragment from './getFragment';
1617
import { GQLConcreteType, GQLTemplateField, GQLTemplateFragment, GQLDocsGenOptions } from './types';
@@ -36,7 +37,7 @@ export default function getFields(
3637
const fields: Array<GQLTemplateField> = Object.keys(subFields)
3738
.map(fieldName => {
3839
const subField = subFields[fieldName];
39-
return getFields(subField, schema, depth - 1, options);
40+
return getFields(subField, schema, adjustDepth(subField, depth), options);
4041
})
4142
.filter(f => f);
4243
const fragments: Array<GQLTemplateFragment> = Object.keys(subFragments)
@@ -61,3 +62,24 @@ export default function getFields(
6162
hasBody: !!(fields.length || fragments.length),
6263
};
6364
}
65+
66+
function adjustDepth(field, depth) {
67+
const maxDepth = 100;
68+
if (isGraphQLAggregateField(field) && depth < maxDepth) {
69+
return depth + 1;
70+
} else if (depth >= maxDepth) {
71+
throw new Error('Statement generation depth exceeded the maximum allowed limit');
72+
}
73+
return depth - 1;
74+
}
75+
76+
function isGraphQLAggregateField(field) {
77+
if (
78+
field &&
79+
field.name == 'aggregateItems' &&
80+
field.type?.ofType?.name == 'SearchableAggregateResult'
81+
) {
82+
return true;
83+
}
84+
return false;
85+
}

0 commit comments

Comments
 (0)