Skip to content

Commit 5bc1208

Browse files
committed
1) Refactored Apollo Client's @client directive support into general support for directives. Initially, this supports a single directive with no additional arguments per key in an object.
2) In tandem with this refactor, moved code into core jsonToGraphQLQuery file and tests file, away from the extensions/apollo directory structure. 3) Refactor of filterNonConfigFields(), which now utilizes external array configFields, which has also been exported for use by other modules (i.e. tests).
1 parent 19626b2 commit 5bc1208

File tree

6 files changed

+89
-98
lines changed

6 files changed

+89
-98
lines changed

src/__tests__/jsonToGraphQLQuery.tests.ts

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

22
import { expect } from 'chai';
3-
import { jsonToGraphQLQuery } from '../';
3+
import { jsonToGraphQLQuery, filterNonConfigFields } from '../';
44

55
describe('jsonToGraphQL()', () => {
66

@@ -146,6 +146,65 @@ describe('jsonToGraphQL()', () => {
146146
}`);
147147
});
148148

149+
it('Converts a JavaScript object into a valid Apollo query, including single directives with no arguments.', () => {
150+
interface ILooseObject { [key: string]: any; }
151+
let input: ILooseObject = {
152+
__typename: 'everyday-health-focuses',
153+
diet: {
154+
__typename: 'diet',
155+
id: 'diet',
156+
options: {
157+
// tslint:disable-next-line:object-literal-key-quotes
158+
__typename: 'diet-options',
159+
'calorie-count': {
160+
__typename: 'calorie-count',
161+
category: 'Diet',
162+
icon: 'fa fa-question-circle',
163+
id: 'calorie-count',
164+
selected: false,
165+
text: 'Calorie Count'
166+
},
167+
// tslint:disable-next-line:object-literal-key-quotes
168+
mood: {
169+
__typename: 'mood',
170+
category: 'Diet',
171+
icon: 'fa fa-question-circle',
172+
id: 'mood',
173+
selected: false,
174+
text: 'Mood'
175+
},
176+
// tslint:disable-next-line:object-literal-key-quotes
177+
weight: {
178+
__typename: 'weight',
179+
category: 'Diet',
180+
icon: 'fa fa-question-circle',
181+
id: 'weight',
182+
selected: false,
183+
text: 'Weight'
184+
},
185+
},
186+
title: 'Diet'
187+
},
188+
someOtherAbritraryKey: {
189+
__typename: 'someArbitraryObjType',
190+
arb1: 'arbitrary value',
191+
arb2: 'some other arbitrary value'
192+
}
193+
};
194+
Object.keys(input)
195+
.filter(filterNonConfigFields)
196+
.forEach((key) => {
197+
input[key]['__directives'] = { client: true, };
198+
});
199+
input = {query: input};
200+
// Do I want to add some keysToStrip functionality separately?
201+
// - const input = jsonToGraphqlQuery(preInput, { keysToStrip: ['__typename'] });
202+
const expected = 'query { diet @client { id options { calorie-count { category ' +
203+
'icon id text } mood { category icon id text } weight { category icon id text } } ' +
204+
'title } someOtherAbritraryKey @client { arb1 arb2 } }';
205+
expect(jsonToGraphQLQuery(input)).to.equal(expected);
206+
});
207+
149208
it('converts a query with nested objects', () => {
150209
const query = {
151210
query: {

src/extensions/apollo/__tests__/apollo.tests.ts

Lines changed: 0 additions & 71 deletions
This file was deleted.

src/extensions/apollo/index.ts

Lines changed: 0 additions & 21 deletions
This file was deleted.

src/extensions/index.ts

Lines changed: 0 additions & 2 deletions
This file was deleted.

src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,3 @@
22
export * from './jsonToGraphQLQuery';
33
export {EnumType} from './types/EnumType';
44
export {VariableType} from './types/VariableType';
5-
export * from './extensions/index';

src/jsonToGraphQLQuery.ts

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { EnumType } from './types/EnumType';
22
import { VariableType } from './types/VariableType';
33

4+
export const configFields = ['__args', '__alias', '__variables', '__directives', '__typename'];
5+
46
function stringify(obj_from_json: any): string {
57
if (obj_from_json instanceof EnumType) {
68
return obj_from_json.value;
@@ -43,12 +45,26 @@ function buildVariables(varsObj: any): string {
4345
return args.join(', ');
4446
}
4547

48+
function buildDirectives(dirsObj: any): string {
49+
const numDirectives = Object.keys(dirsObj).length;
50+
if (numDirectives > 1) {
51+
throw new Error(numDirectives.toString());
52+
}
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];
59+
}
60+
4661
function getIndent(level: number): string {
4762
return Array((level * 4) + 1).join(' ');
4863
}
4964

50-
function filterNonConfigFields(fieldName: string) {
51-
return fieldName !== '__args' && fieldName !== '__alias' && fieldName !== '__variables';
65+
export function filterNonConfigFields(fieldName: string) {
66+
// Returns true if fieldName is not a 'configField'.
67+
return configFields.indexOf(fieldName) === -1; // Equivalent to: return !configFields.includes(fieldName);
5268
}
5369

5470
function convertQuery(node: any, level: number, output: Array<[ string, number ]>) {
@@ -66,6 +82,17 @@ function convertQuery(node: any, level: number, output: Array<[ string, number ]
6682
else if (typeof node[key].__variables === 'object') {
6783
token = `${key} (${buildVariables(node[key].__variables)})`;
6884
}
85+
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: /, '');
91+
throw new Error(`Too many directives. The object/key ` +
92+
`'${Object.keys(node[key])[0]}' had ${e} directives, ` +
93+
`but only 1 directive per object/key is supported at this time.`);
94+
}
95+
}
6996
else {
7097
token = `${key}`;
7198
}

0 commit comments

Comments
 (0)