Skip to content

Commit 935b913

Browse files
committed
Bugfix & filter syntax
1 parent 355103b commit 935b913

File tree

5 files changed

+111
-18
lines changed

5 files changed

+111
-18
lines changed

Diff for: README.md

+1
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ This plugin has an opinion how the GraphQL API schema should look like:
118118
- The create mutation expects the new record as argument
119119
- The update mutation expects two arguments: The ID and the new record
120120
- The delete mutation expects the record ID to delete
121+
- Multiple records are within a `nodes` object and filtered by a `filter` argument.
121122

122123
You can see query examples in the [project wiki](https://github.com/vuex-orm/vuex-orm-apollo/wiki/Example-Queries).
123124

Diff for: dist/vuex-orm-apollo.esm.js

+20-7
Original file line numberDiff line numberDiff line change
@@ -7754,7 +7754,7 @@ var QueryBuilder = /** @class */ (function () {
77547754
if (allowIdFields === void 0) { allowIdFields = false; }
77557755
model = this.getModel(model);
77567756
ignoreModels.push(model);
7757-
var params = this.buildArguments(args, false, allowIdFields);
7757+
var params = this.buildArguments(args, false, multiple, allowIdFields);
77587758
var fields = "\n " + model.getQueryFields().join(' ') + "\n " + this.buildRelationsQuery(model, ignoreModels) + "\n ";
77597759
if (multiple) {
77607760
return "\n " + (name ? name : model.pluralName) + params + " {\n nodes {\n " + fields + "\n }\n }\n ";
@@ -7791,7 +7791,7 @@ var QueryBuilder = /** @class */ (function () {
77917791
if (!name)
77927792
name = (multiple ? model.pluralName : model.singularName);
77937793
// build query
7794-
var query = type + " " + upcaseFirstLetter(name) + this.buildArguments(args, true) + " {\n" +
7794+
var query = type + " " + upcaseFirstLetter(name) + this.buildArguments(args, true, false) + " {\n" +
77957795
(" " + this.buildField(model, multiple, args, [], name, true) + "\n") +
77967796
"}";
77977797
return src(query);
@@ -7881,13 +7881,17 @@ var QueryBuilder = /** @class */ (function () {
78817881
* 3) Fields with variables (signature = false)
78827882
* query user(id: $id)
78837883
*
7884+
* 4) Filter fields with variables (signature = false, filter = true)
7885+
* query users(filter: { active: $active })
7886+
*
78847887
* @param {Arguments | undefined} args
78857888
* @param {boolean} signature When true, then this method generates a query signature instead of key/value pairs
78867889
* @param {boolean} allowIdFields If true, ID fields will be included in the arguments list
78877890
* @returns {String}
78887891
*/
7889-
QueryBuilder.prototype.buildArguments = function (args, signature, allowIdFields) {
7892+
QueryBuilder.prototype.buildArguments = function (args, signature, filter, allowIdFields) {
78907893
if (signature === void 0) { signature = false; }
7894+
if (filter === void 0) { filter = false; }
78917895
if (allowIdFields === void 0) { allowIdFields = true; }
78927896
if (args === undefined)
78937897
return '';
@@ -7904,25 +7908,34 @@ var QueryBuilder = /** @class */ (function () {
79047908
// Case 2 (User!)
79057909
typeOrValue = value.__type + 'Input!';
79067910
}
7907-
else if (key === 'id') {
7911+
else if (key === 'id' || key.endsWith('Id')) {
79087912
// Case 1 (ID!)
79097913
typeOrValue = 'ID!';
79107914
}
79117915
else {
79127916
// Case 1 (String!)
7913-
typeOrValue = typeof value === 'number' ? 'Number!' : 'String!';
7917+
if (typeof value === 'number')
7918+
typeOrValue = 'Int';
7919+
if (typeof value === 'string')
7920+
typeOrValue = 'String';
7921+
if (typeof value === 'boolean')
7922+
typeOrValue = 'Boolean';
7923+
typeOrValue = typeOrValue + '!';
79147924
}
79157925
}
79167926
else {
7917-
// Case 3 (user: $user)
7927+
// Case 3 or 4
79187928
typeOrValue = "$" + key;
79197929
}
79207930
returnValue = "" + returnValue + (first ? '' : ', ') + ((signature ? '$' : '') + key) + ": " + typeOrValue;
79217931
first = false;
79227932
}
79237933
});
7924-
if (!first)
7934+
if (!first) {
7935+
if (filter)
7936+
returnValue = "filter: { " + returnValue + " }";
79257937
returnValue = "(" + returnValue + ")";
7938+
}
79267939
}
79277940
return returnValue;
79287941
};

Diff for: src/queryBuilder.ts

+19-7
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ export default class QueryBuilder {
6161
model = this.getModel(model);
6262
ignoreModels.push(model);
6363

64-
let params: string = this.buildArguments(args, false, allowIdFields);
64+
let params: string = this.buildArguments(args, false, multiple, allowIdFields);
6565

6666
const fields = `
6767
${model.getQueryFields().join(' ')}
@@ -116,7 +116,7 @@ export default class QueryBuilder {
116116

117117
// build query
118118
const query: string =
119-
`${type} ${upcaseFirstLetter(name)}${this.buildArguments(args, true)} {\n` +
119+
`${type} ${upcaseFirstLetter(name)}${this.buildArguments(args, true, false)} {\n` +
120120
` ${this.buildField(model, multiple, args, [], name, true)}\n` +
121121
`}`;
122122

@@ -212,12 +212,16 @@ export default class QueryBuilder {
212212
* 3) Fields with variables (signature = false)
213213
* query user(id: $id)
214214
*
215+
* 4) Filter fields with variables (signature = false, filter = true)
216+
* query users(filter: { active: $active })
217+
*
215218
* @param {Arguments | undefined} args
216219
* @param {boolean} signature When true, then this method generates a query signature instead of key/value pairs
217220
* @param {boolean} allowIdFields If true, ID fields will be included in the arguments list
218221
* @returns {String}
219222
*/
220-
private buildArguments (args?: Arguments, signature: boolean = false, allowIdFields: boolean = true): string {
223+
private buildArguments (args?: Arguments, signature: boolean = false, filter: boolean = false,
224+
allowIdFields: boolean = true): string {
221225
if (args === undefined) return '';
222226

223227
let returnValue: string = '';
@@ -235,24 +239,32 @@ export default class QueryBuilder {
235239
if (typeof value === 'object' && value.__type) {
236240
// Case 2 (User!)
237241
typeOrValue = value.__type + 'Input!';
238-
} else if (key === 'id') {
242+
} else if (key === 'id' || key.endsWith('Id')) {
239243
// Case 1 (ID!)
240244
typeOrValue = 'ID!';
241245
} else {
242246
// Case 1 (String!)
243-
typeOrValue = typeof value === 'number' ? 'Number!' : 'String!';
247+
if (typeof value === 'number') typeOrValue = 'Int';
248+
if (typeof value === 'string') typeOrValue = 'String';
249+
if (typeof value === 'boolean') typeOrValue = 'Boolean';
250+
251+
typeOrValue = typeOrValue + '!';
244252
}
245253
} else {
246-
// Case 3 (user: $user)
254+
// Case 3 or 4
247255
typeOrValue = `$${key}`;
248256
}
249257

250258
returnValue = `${returnValue}${first ? '' : ', '}${(signature ? '$' : '') + key}: ${typeOrValue}`;
259+
251260
first = false;
252261
}
253262
});
254263

255-
if (!first) returnValue = `(${returnValue})`;
264+
if (!first) {
265+
if (filter) returnValue = `filter: { ${returnValue} }`;
266+
returnValue = `(${returnValue})`;
267+
}
256268
}
257269

258270
return returnValue;

Diff for: test/integration/VuexORMApollo.spec.js

+57-1
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,63 @@ query User($id: ID!) {
158158
});
159159
});
160160

161-
describe('without ID', () => {
161+
describe('without ID but with filter', () => {
162+
it('sends the correct query to the API', async () => {
163+
const response = {
164+
data: {
165+
users: {
166+
__typename: 'user',
167+
nodes: [
168+
{
169+
__typename: 'user',
170+
id: 1,
171+
name: 'Charlie Brown',
172+
posts: {
173+
__typename: 'post',
174+
nodes: [
175+
{
176+
__typename: 'post',
177+
id: 1,
178+
userId: 1,
179+
title: 'Example Post 1',
180+
content: 'Foo'
181+
},
182+
{
183+
__typename: 'post',
184+
id: 2,
185+
userId: 1,
186+
title: 'Example Post 2',
187+
content: 'Bar'
188+
}
189+
]
190+
}
191+
}
192+
]
193+
}
194+
}
195+
};
196+
197+
const request = await sendWithMockFetch(response, async () => {
198+
await store.dispatch('entities/users/fetch', { filter: { active: true } });
199+
});
200+
201+
expect(request.variables).toEqual({ active: true });
202+
expect(request.query).toEqual(`
203+
query Users($active: Boolean!) {
204+
users(filter: {active: $active}) {
205+
nodes {
206+
id
207+
name
208+
__typename
209+
}
210+
__typename
211+
}
212+
}
213+
`.trim() + "\n");
214+
});
215+
});
216+
217+
describe('without ID or filter', () => {
162218
it('sends the correct query to the API', async () => {
163219
const response = {
164220
data: {

Diff for: test/unit/QueryBuilder.spec.js

+14-3
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ describe('QueryBuilder', () => {
7676
user: { __type: 'User' }
7777
}, true);
7878

79-
expect(args).toEqual('($name: String!, $email: String!, $age: Number!, $user: UserInput!)');
79+
expect(args).toEqual('($name: String!, $email: String!, $age: Int!, $user: UserInput!)');
8080
});
8181

8282
it('can generate fields with variables', () => {
@@ -85,10 +85,21 @@ describe('QueryBuilder', () => {
8585
8686
age: 32,
8787
user: { __type: 'User' }
88-
}, false, true);
88+
}, false, false, true);
8989

9090
expect(args).toEqual('(name: $name, email: $email, age: $age, user: $user)');
9191
});
92+
93+
it('can generate filter field with variables', () => {
94+
let args = queryBuilder.buildArguments({
95+
name: 'Foo Bar',
96+
97+
age: 32,
98+
user: { __type: 'User' }
99+
}, false, true, true);
100+
101+
expect(args).toEqual('(filter: { name: $name, email: $email, age: $age, user: $user })');
102+
});
92103
});
93104

94105

@@ -295,7 +306,7 @@ query test {
295306

296307
expect(query).toEqual(`
297308
query users {
298-
users(age: $age) {
309+
users(filter: {age: $age}) {
299310
nodes {
300311
id
301312
name

0 commit comments

Comments
 (0)