Skip to content

Commit

Permalink
Merge pull request #35 from wayfair-incubator/mfaga-support-multiple-…
Browse files Browse the repository at this point in the history
…nodes-in-private-query
  • Loading branch information
mjfaga authored Dec 22, 2023
2 parents c50042b + 2576e03 commit 2afc498
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 19 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,17 @@ and this project adheres to

## [Unreleased]

## [v1.2.2] - 2023-12-21

### Fixed

- fix: support multiple nodes in private queries

## [v1.2.1] - 2023-12-15

### Fixed

- feat: support unions when building private queries
- fix: support unions when building private queries

## [v1.2.0] - 2023-11-01

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@wayfair/gqmock",
"version": "1.2.1",
"version": "1.2.2",
"description": "GQMock - GraphQL Mocking Service",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
19 changes: 19 additions & 0 deletions src/__fixtures__/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,25 @@ type Query {
item: Item
random: RandomThing
items(type: String): [Item]
itemConnection(type: String): ItemConnection
}

type ItemConnection {
totalCount: Int
edges: [ItemEdge]
pageInfo: PageInfo
}

type PageInfo {
hasNextPage: Boolean
hasPreviousPage: Boolean
startCursor: String
endCursor: String
}

type ItemEdge {
node: Item
cursor: String
}

enum SomeEnum {
Expand Down
110 changes: 108 additions & 2 deletions src/utilities/__tests__/buildPrivateTypeQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@ const schema = fs.readFileSync(
);

describe('buildPrivateTypeQuery', function () {
let apolloServerManager;
let apolloServerManager: ApolloServerManager;

beforeAll(() => {
apolloServerManager = new ApolloServerManager();
apolloServerManager.createApolloServer(schema, {});
apolloServerManager.createApolloServer(schema, {
subgraph: false,
fakerConfig: {},
});
});

it('should build a query for the correct interface inline fragment', () => {
Expand Down Expand Up @@ -334,4 +337,107 @@ describe('buildPrivateTypeQuery', function () {
})
).toBe(expectedQuery);
});

it('should select the deeply nested union of all fields in each selection set', () => {
const query = `
fragment randomFragment_itemConnection on ItemConnection {
totalCount
edges {
node {
id
type
}
}
}
fragment itemConnection_query on Query {
itemConnection {
edges {
cursor
node {
id
... on ItemOne {
id
someField1: String
}
}
}
...randomFragment_itemConnection
}
}
query itemsQuery {
...itemConnection_query
}`;

const expectedItemConnectionQuery = `query gqmock_privateQuery {
gqmock_ItemConnection {
edges {
cursor
node {
id
... on ItemOne {
id
someField1: String
__typename
}
__typename
}
__typename
}
totalCount
edges {
node {
id
type
__typename
}
__typename
}
__typename
}
__typename
}`;

expect(
buildPrivateTypeQuery({
query: apolloServerManager.expandFragments(query),
typeName: 'ItemConnection',
operationName: 'itemsQuery',
rollingKey: 'data.itemConnection',
apolloServerManager,
})
).toBe(expectedItemConnectionQuery);

const expectEdgesQuery = `query gqmock_privateQuery {
gqmock_ItemEdge {
cursor
node {
id
... on ItemOne {
id
someField1: String
__typename
}
__typename
}
node {
id
type
__typename
}
__typename
}
__typename
}`;
expect(
buildPrivateTypeQuery({
query: apolloServerManager.expandFragments(query),
typeName: 'ItemEdge',
operationName: 'itemsQuery',
rollingKey: 'data.itemConnection.edges',
apolloServerManager,
})
).toBe(expectEdgesQuery);
});
});
33 changes: 18 additions & 15 deletions src/utilities/buildPrivateTypeQuery.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
ASTNode,
FieldNode,
FragmentSpreadNode,
GraphQLSchema,
InlineFragmentNode,
Kind,
Expand Down Expand Up @@ -74,11 +75,14 @@ export default function ({
},
];

let isFound = false;
const nodesFound: (FieldNode | InlineFragmentNode | FragmentSpreadNode)[] =
[];

while (nodesToVisit.length) {
let {_node} = nodesToVisit[0];
const {currentKeys} = nodesToVisit[0];
const key = currentKeys[0];

if (_node && 'selectionSet' in _node) {
for (const selection of _node.selectionSet?.selections || []) {
if (keyMatchesFieldNode(selection, key)) {
Expand All @@ -92,11 +96,9 @@ export default function ({
});
} else if (currentKeys.length === 1) {
_node = selection;
isFound = true;
nodesFound.push(_node);
}
break;
} else if (selection.kind === Kind.INLINE_FRAGMENT) {
let isInlineFragmentSelectionFound = false;
for (const inlineFragmentSelection of selection.selectionSet
.selections) {
if (keyMatchesFieldNode(inlineFragmentSelection, key)) {
Expand All @@ -111,9 +113,8 @@ export default function ({
});
} else if (currentKeys.length === 1) {
_node = inlineFragmentSelection;
isFound = true;
nodesFound.push(_node);
}
isInlineFragmentSelectionFound = true;
} else if (
inlineFragmentSelection.kind !== Kind.FIELD &&
'selectionSet' in inlineFragmentSelection
Expand All @@ -123,21 +124,23 @@ export default function ({
currentKeys,
});
}

if (isInlineFragmentSelectionFound) {
break;
}
}
if (isInlineFragmentSelectionFound) {
break;
}
}
}
}
nodesToVisit.shift();

if (isFound) {
node = _node;
if (nodesFound.length > 0) {
node = nodesFound[0];

for (let i = 1; i < nodesFound.length; i++) {
// @ts-expect-error we don't care
node.selectionSet.selections.push(
// @ts-expect-error we don't care
...nodesFound[i].selectionSet.selections
);
}

break;
}
}
Expand Down

0 comments on commit 2afc498

Please sign in to comment.