Skip to content

Commit c935646

Browse files
🐛 fix(merge.spec.js): fix formatting and indentation issues in merge.spec.js
✨ feat(merge.spec.js): add additional test cases for mergeQueries function 🐛 fix(merge.spec.js): fix formatting and indentation in mergeQueries test cases ✨ feat(merge.spec.js): add test case for handling subqueries in mergeQueries 🐛 fix(merge.spec.ts): handle subqueries in mergeQueries function ✨ feat(merge.ts): modify AST of request query based on allowed paths in mergeQueries function
1 parent 6da0f8b commit c935646

3 files changed

Lines changed: 194 additions & 97 deletions

File tree

dist/__tests__/merge.spec.js

Lines changed: 144 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,121 +1,143 @@
1-
"use strict";
2-
Object.defineProperty(exports, "__esModule", { value: true });
3-
const merge_1 = require("../merge");
1+
'use strict';
2+
Object.defineProperty(exports, '__esModule', { value: true });
3+
const merge_1 = require('../merge');
44
describe('mergeQueries', () => {
5-
test('should allow fields present in allowed queries', () => {
6-
const requestQuery = `{ user { id, name, email } }`;
7-
const allowedQueries = [`{ user { id, name } }`];
8-
const expected = `{
5+
test('should allow fields present in allowed queries', () => {
6+
const requestQuery = `{ user { id, name, email } }`;
7+
const allowedQueries = [`{ user { id, name } }`];
8+
const expected = `{
99
user {
1010
id
1111
name
1212
}
1313
}`;
14-
expect((0, merge_1.mergeQueries)(requestQuery, allowedQueries)).toBe(expected);
15-
});
16-
test('should exclude fields not present in allowed queries', () => {
17-
const requestQuery = `{ user { id, name, email } }`;
18-
const allowedQueries = [`{ user { id } }`];
19-
const expected = `{
14+
expect((0, merge_1.mergeQueries)(requestQuery, allowedQueries)).toBe(
15+
expected
16+
);
17+
});
18+
test('should exclude fields not present in allowed queries', () => {
19+
const requestQuery = `{ user { id, name, email } }`;
20+
const allowedQueries = [`{ user { id } }`];
21+
const expected = `{
2022
user {
2123
id
2224
}
2325
}`;
24-
expect((0, merge_1.mergeQueries)(requestQuery, allowedQueries)).toBe(expected);
25-
});
26-
test('should handle nested queries', () => {
27-
const requestQuery = `{ user { id, profile { name, age } } }`;
28-
const allowedQueries = [`{ user { profile { name } } }`];
29-
const expected = `{
26+
expect((0, merge_1.mergeQueries)(requestQuery, allowedQueries)).toBe(
27+
expected
28+
);
29+
});
30+
test('should handle nested queries', () => {
31+
const requestQuery = `{ user { id, profile { name, age } } }`;
32+
const allowedQueries = [`{ user { profile { name } } }`];
33+
const expected = `{
3034
user {
3135
profile {
3236
name
3337
}
3438
}
3539
}`;
36-
expect((0, merge_1.mergeQueries)(requestQuery, allowedQueries)).toBe(expected);
37-
});
38-
test('should handle queries with arguments', () => {
39-
const requestQuery = `{ users(age: 30) { id, name } }`;
40-
const allowedQueries = [`{ users { name } }`];
41-
const expected = `{
40+
expect((0, merge_1.mergeQueries)(requestQuery, allowedQueries)).toBe(
41+
expected
42+
);
43+
});
44+
test('should handle queries with arguments', () => {
45+
const requestQuery = `{ users(age: 30) { id, name } }`;
46+
const allowedQueries = [`{ users { name } }`];
47+
const expected = `{
4248
users(age: 30) {
4349
name
4450
}
4551
}`;
46-
expect((0, merge_1.mergeQueries)(requestQuery, allowedQueries)).toBe(expected);
47-
});
48-
test('should strictly follow allowed queries with aliases', () => {
49-
const requestQuery = `{ user: users { id, name } }`;
50-
const allowedQueries = [`{ user: users { name } }`];
51-
const expected = `{
52+
expect((0, merge_1.mergeQueries)(requestQuery, allowedQueries)).toBe(
53+
expected
54+
);
55+
});
56+
test('should strictly follow allowed queries with aliases', () => {
57+
const requestQuery = `{ user: users { id, name } }`;
58+
const allowedQueries = [`{ user: users { name } }`];
59+
const expected = `{
5260
user: users {
5361
name
5462
}
5563
}`;
56-
expect((0, merge_1.mergeQueries)(requestQuery, allowedQueries)).toBe(expected);
57-
});
58-
test('should strictly follow allowed queries without aliases', () => {
59-
const requestQuery = `{ users { id, name } }`;
60-
const allowedQueries = [`{ users { name } }`];
61-
const expected = `{
64+
expect((0, merge_1.mergeQueries)(requestQuery, allowedQueries)).toBe(
65+
expected
66+
);
67+
});
68+
test('should strictly follow allowed queries without aliases', () => {
69+
const requestQuery = `{ users { id, name } }`;
70+
const allowedQueries = [`{ users { name } }`];
71+
const expected = `{
6272
users {
6373
name
6474
}
6575
}`;
66-
expect((0, merge_1.mergeQueries)(requestQuery, allowedQueries)).toBe(expected);
67-
});
68-
test('should handle mutations', () => {
69-
const requestQuery = `mutation { updateUser(id: 1, data: { name: "New Name" }) { id, name } }`;
70-
const allowedQueries = [
71-
`mutation { updateUser(id: 1, data: { name: "New Name" }) { name } }`,
72-
];
73-
const expected = `mutation {
76+
expect((0, merge_1.mergeQueries)(requestQuery, allowedQueries)).toBe(
77+
expected
78+
);
79+
});
80+
test('should handle mutations', () => {
81+
const requestQuery = `mutation { updateUser(id: 1, data: { name: "New Name" }) { id, name } }`;
82+
const allowedQueries = [
83+
`mutation { updateUser(id: 1, data: { name: "New Name" }) { name } }`,
84+
];
85+
const expected = `mutation {
7486
updateUser(id: 1, data: {name: "New Name"}) {
7587
name
7688
}
7789
}`;
78-
expect((0, merge_1.mergeQueries)(requestQuery, allowedQueries)).toBe(expected);
79-
});
80-
test('should handle multiple allowed queries', () => {
81-
const requestQuery = `{ user { id, name, email } }`;
82-
const allowedQueries = [`{ user { id } }`, `{ user { name } }`];
83-
const expected = `{
90+
expect((0, merge_1.mergeQueries)(requestQuery, allowedQueries)).toBe(
91+
expected
92+
);
93+
});
94+
test('should handle multiple allowed queries', () => {
95+
const requestQuery = `{ user { id, name, email } }`;
96+
const allowedQueries = [`{ user { id } }`, `{ user { name } }`];
97+
const expected = `{
8498
user {
8599
id
86100
name
87101
}
88102
}`;
89-
expect((0, merge_1.mergeQueries)(requestQuery, allowedQueries)).toBe(expected);
90-
});
91-
test('should handle empty requestQuery', () => {
92-
const requestQuery = '';
93-
const allowedQueries = [`{ user { id, name } }`];
94-
const expected = '';
95-
expect((0, merge_1.mergeQueries)(requestQuery, allowedQueries)).toBe(expected);
96-
});
97-
test('should handle empty allowedQueries', () => {
98-
const requestQuery = `{ user { id, name, email } }`;
99-
const allowedQueries = [];
100-
const expected = '';
101-
expect((0, merge_1.mergeQueries)(requestQuery, allowedQueries)).toBe(expected);
102-
});
103-
test('should handle mutations', () => {
104-
const requestQuery = `mutation { updateUser(id: 1, data: { name: "New Name" }) { id, name } }`;
105-
const allowedQueries = [
106-
`mutation { updateUser(id: 1, data: { name: "New Name" }) { name } }`,
107-
];
108-
const expected = `mutation {
103+
expect((0, merge_1.mergeQueries)(requestQuery, allowedQueries)).toBe(
104+
expected
105+
);
106+
});
107+
test('should handle empty requestQuery', () => {
108+
const requestQuery = '';
109+
const allowedQueries = [`{ user { id, name } }`];
110+
const expected = '';
111+
expect((0, merge_1.mergeQueries)(requestQuery, allowedQueries)).toBe(
112+
expected
113+
);
114+
});
115+
test('should handle empty allowedQueries', () => {
116+
const requestQuery = `{ user { id, name, email } }`;
117+
const allowedQueries = [];
118+
const expected = '';
119+
expect((0, merge_1.mergeQueries)(requestQuery, allowedQueries)).toBe(
120+
expected
121+
);
122+
});
123+
test('should handle mutations', () => {
124+
const requestQuery = `mutation { updateUser(id: 1, data: { name: "New Name" }) { id, name } }`;
125+
const allowedQueries = [
126+
`mutation { updateUser(id: 1, data: { name: "New Name" }) { name } }`,
127+
];
128+
const expected = `mutation {
109129
updateUser(id: 1, data: {name: "New Name"}) {
110130
name
111131
}
112132
}`;
113-
expect((0, merge_1.mergeQueries)(requestQuery, allowedQueries)).toBe(expected);
114-
});
115-
test('should handle deeply nested queries', () => {
116-
const requestQuery = `{ user { id, profile { name, address { street, city } } } }`;
117-
const allowedQueries = [`{ user { profile { address { street } } } }`];
118-
const expected = `{
133+
expect((0, merge_1.mergeQueries)(requestQuery, allowedQueries)).toBe(
134+
expected
135+
);
136+
});
137+
test('should handle deeply nested queries', () => {
138+
const requestQuery = `{ user { id, profile { name, address { street, city } } } }`;
139+
const allowedQueries = [`{ user { profile { address { street } } } }`];
140+
const expected = `{
119141
user {
120142
profile {
121143
address {
@@ -124,18 +146,53 @@ describe('mergeQueries', () => {
124146
}
125147
}
126148
}`;
127-
expect((0, merge_1.mergeQueries)(requestQuery, allowedQueries)).toBe(expected);
128-
});
129-
test('should handle nested mutations', () => {
130-
const requestQuery = `mutation { updateUser(id: 1, data: { profile: { name: "New Name" } }) { id } }`;
131-
const allowedQueries = [
132-
`mutation { updateUser(id: 1, data: { profile: { name: "New Name" } }) { id } }`,
133-
];
134-
const expected = `mutation {
149+
expect((0, merge_1.mergeQueries)(requestQuery, allowedQueries)).toBe(
150+
expected
151+
);
152+
});
153+
test('should handle nested mutations', () => {
154+
const requestQuery = `mutation { updateUser(id: 1, data: { profile: { name: "New Name" } }) { id } }`;
155+
const allowedQueries = [
156+
`mutation { updateUser(id: 1, data: { profile: { name: "New Name" } }) { id } }`,
157+
];
158+
const expected = `mutation {
135159
updateUser(id: 1, data: {profile: {name: "New Name"}}) {
136160
id
137161
}
138162
}`;
139-
expect((0, merge_1.mergeQueries)(requestQuery, allowedQueries)).toBe(expected);
140-
});
163+
expect((0, merge_1.mergeQueries)(requestQuery, allowedQueries)).toBe(
164+
expected
165+
);
166+
});
167+
168+
test('should handle subqueries', () => {
169+
const requestQuery = `query {
170+
employees {
171+
salary {
172+
amount
173+
}
174+
name
175+
}
176+
}`;
177+
const allowedQueries = [
178+
`query {
179+
departments {
180+
id
181+
name
182+
employees {
183+
id
184+
name
185+
}
186+
}
187+
}`,
188+
];
189+
const expected = `mutation {
190+
updateUser(id: 1, data: {profile: {name: "New Name"}}) {
191+
id
192+
}
193+
}`;
194+
expect((0, merge_1.mergeQueries)(requestQuery, allowedQueries)).toBe(
195+
expected
196+
);
197+
});
141198
});

src/__tests__/merge.spec.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,4 +149,34 @@ describe('mergeQueries', () => {
149149
}`;
150150
expect(mergeQueries(requestQuery, allowedQueries)).toBe(expected);
151151
});
152+
153+
test('should handle subqueries', () => {
154+
const requestQuery = `query {
155+
employees {
156+
salary {
157+
amount
158+
}
159+
name
160+
}
161+
}`;
162+
const allowedQueries = [
163+
`query {
164+
departments {
165+
id
166+
name
167+
employees {
168+
id
169+
name
170+
}
171+
}
172+
}`,
173+
`query {
174+
salary {
175+
amount
176+
}
177+
}`,
178+
];
179+
const expected = ``;
180+
expect(mergeQueries(requestQuery, allowedQueries)).toBe(expected);
181+
});
152182
});

src/merge.ts

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,41 @@
1-
import { FieldNode, parse, print, visit } from 'graphql';
1+
import { ASTNode, FieldNode, parse, print, visit } from 'graphql';
2+
3+
function getPath(node: FieldNode, ancestors: ASTNode[]) {
4+
// Build the path from the ancestors and the current node
5+
const path = ancestors
6+
.map((ancestor) => (ancestor.kind === 'Field' ? ancestor.name.value : null))
7+
.filter(Boolean);
8+
path.push(node.name.value);
9+
return path.join('.');
10+
}
211

312
export function mergeQueries(
413
requestQuery: string,
514
allowedQueries: string[]
615
): string {
716
if (!requestQuery.trim()) {
8-
return ''; // Return an empty string for empty requestQuery
17+
return '';
918
}
1019

1120
const parsedRequestQuery = parse(requestQuery);
1221
const allowedQueryASTs = allowedQueries.map((query) => parse(query));
1322

14-
const allowedFields = new Set<string>();
15-
// Extract allowed fields from allowedQueryASTs
23+
const allowedPaths = new Set<string>();
24+
// Extract allowed paths from allowedQueryASTs
1625
allowedQueryASTs.forEach((ast) => {
1726
visit(ast, {
18-
Field(node) {
19-
allowedFields.add(node.name.value);
27+
Field(node, key, parent, path, ancestors) {
28+
allowedPaths.add(getPath(node, ancestors as ASTNode[]));
2029
},
2130
});
2231
});
2332

24-
// Modify the AST of the request query based on allowed fields
33+
// Modify the AST of the request query based on allowed paths
2534
const modifiedAST = visit(parsedRequestQuery, {
26-
Field(node: FieldNode) {
27-
if (!allowedFields.has(node.name.value)) {
28-
return null; // This removes the field from the AST
35+
Field(node, key, parent, path, ancestors) {
36+
const currentPath = getPath(node, ancestors as ASTNode[]);
37+
if (!allowedPaths.has(currentPath)) {
38+
return null; // Remove the field from the AST
2939
}
3040
return undefined; // Continue visiting child nodes
3141
},

0 commit comments

Comments
 (0)