Skip to content

Commit 361e1bf

Browse files
committed
Added the following support:
Converts a JavaScript object into a valid query, including single directives with args, so long as any variables used are enclosed in a string with '$' included.
1 parent 5bc1208 commit 361e1bf

File tree

2 files changed

+52
-18
lines changed

2 files changed

+52
-18
lines changed

src/__tests__/jsonToGraphQLQuery.tests.ts

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ describe('jsonToGraphQL()', () => {
146146
}`);
147147
});
148148

149-
it('Converts a JavaScript object into a valid Apollo query, including single directives with no arguments.', () => {
149+
it('Converts a JavaScript object into a valid query, including a single directive w/ no arguments.', () => {
150150
interface ILooseObject { [key: string]: any; }
151151
let input: ILooseObject = {
152152
__typename: 'everyday-health-focuses',
@@ -197,14 +197,42 @@ describe('jsonToGraphQL()', () => {
197197
input[key]['__directives'] = { client: true, };
198198
});
199199
input = {query: input};
200-
// Do I want to add some keysToStrip functionality separately?
201-
// - const input = jsonToGraphqlQuery(preInput, { keysToStrip: ['__typename'] });
202200
const expected = 'query { diet @client { id options { calorie-count { category ' +
203201
'icon id text } mood { category icon id text } weight { category icon id text } } ' +
204202
'title } someOtherAbritraryKey @client { arb1 arb2 } }';
205203
expect(jsonToGraphQLQuery(input)).to.equal(expected);
206204
});
207205

206+
it('Converts a JavaScript object into a valid query, including single directives ' +
207+
'with args, so long as any variables used are enclosed in a string with "$" included.', () => {
208+
interface ILooseObject { [key: string]: any; }
209+
let input: ILooseObject = {
210+
someOtherAbritraryKey: {
211+
__typename: 'someArbitraryObjType',
212+
arb1: 'arbitrary value',
213+
arb2: 'some other arbitrary value'
214+
}
215+
};
216+
Object.keys(input)
217+
.filter(filterNonConfigFields)
218+
.forEach((key) => {
219+
input[key]['__directives'] = { include: {if: '$isAwesome'}, };
220+
});
221+
input = {query: input};
222+
const expected = 'query { someOtherAbritraryKey @include(if: $isAwesome) { arb1 arb2 } }';
223+
expect(jsonToGraphQLQuery(input)).to.equal(expected);
224+
});
225+
226+
// TODO
227+
// it('Converts a JavaScript object into a valid query, including *multiple* directives ' +
228+
// 'with args, so long as any variables used are enclosed in a string with "$" included.', () => {
229+
// });
230+
231+
// TODO
232+
// it('Creates a query, stripping/ignoring certain, specified keys.', () => {
233+
// // Example usage: jsonToGraphqlQuery(preInput, { keysToStrip: ['__typename'] });
234+
// });
235+
208236
it('converts a query with nested objects', () => {
209237
const query = {
210238
query: {

src/jsonToGraphQLQuery.ts

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,23 @@ function buildVariables(varsObj: any): string {
4646
}
4747

4848
function buildDirectives(dirsObj: any): string {
49-
const numDirectives = Object.keys(dirsObj).length;
50-
if (numDirectives > 1) {
51-
throw new Error(numDirectives.toString());
49+
const directiveName = Object.keys(dirsObj)[0];
50+
const directiveValue = dirsObj[directiveName];
51+
if (typeof directiveValue === 'boolean') {
52+
return directiveName;
53+
}
54+
else if (typeof directiveValue === 'object') {
55+
const args = [];
56+
for (const argName in directiveValue) {
57+
const argVal = stringify(directiveValue[argName]).replace(/"/g, '');
58+
args.push(`${argName}: ${argVal}`);
59+
}
60+
return `${directiveName}(${args.join(', ')})`;
61+
}
62+
else {
63+
throw new Error(`Unsupported type for directive: ${typeof directiveValue}. Types allowed: object, boolean.\n` +
64+
`Offending object: ${JSON.stringify(dirsObj)}`);
5265
}
53-
// const args = [];
54-
// for (const varName in dirsObj) {
55-
// args.push(`@${varName}: ${dirsObj[varName]}`);
56-
// }
57-
// return args.join(', ');
58-
return '@' + Object.keys(dirsObj)[0];
5966
}
6067

6168
function getIndent(level: number): string {
@@ -83,15 +90,14 @@ function convertQuery(node: any, level: number, output: Array<[ string, number ]
8390
token = `${key} (${buildVariables(node[key].__variables)})`;
8491
}
8592
else if (typeof node[key].__directives === 'object') {
86-
// TODO: Add support for multiple directives on one node, if that's a thing.
87-
try {
88-
token = `${key} ${buildDirectives(node[key].__directives)}`;
89-
} catch (e) {
90-
e = e.toString().replace(/Error: /, '');
93+
// TODO: Add support for multiple directives on one node.
94+
const numDirectives = Object.keys(node[key].__directives).length;
95+
if (numDirectives > 1) {
9196
throw new Error(`Too many directives. The object/key ` +
92-
`'${Object.keys(node[key])[0]}' had ${e} directives, ` +
97+
`'${Object.keys(node[key])[0]}' had ${numDirectives} directives, ` +
9398
`but only 1 directive per object/key is supported at this time.`);
9499
}
100+
token = `${key} @${buildDirectives(node[key].__directives)}`;
95101
}
96102
else {
97103
token = `${key}`;

0 commit comments

Comments
 (0)