Skip to content

Commit dfa0271

Browse files
committed
Fix recursion detection
1 parent 42ed771 commit dfa0271

File tree

4 files changed

+83
-32
lines changed

4 files changed

+83
-32
lines changed

dist/vuex-orm-apollo.esm.js

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9857,7 +9857,7 @@ var QueryBuilder = /** @class */ (function () {
98579857
* @param {Model|string} model The model to use
98589858
* @param {boolean} multiple Determines whether plural/nodes syntax or singular syntax is used.
98599859
* @param {Arguments} args The args that will be passed to the query field ( user(role: $role) )
9860-
* @param {Array<Model>} ignoreModels The models in this list are ignored (while traversing relations).
9860+
* @param {Array<Model>} ignoreRelations The models in this list are ignored (while traversing relations).
98619861
* Mainly for recursion
98629862
* @param {string} name Optional name of the field. If not provided, this will be the model name
98639863
* @param {boolean} allowIdFields Optional. Determines if id fields will be ignored for the argument generation.
@@ -9866,16 +9866,15 @@ var QueryBuilder = /** @class */ (function () {
98669866
*
98679867
* @todo Do we need the allowIdFields param?
98689868
*/
9869-
QueryBuilder.buildField = function (model, multiple, args, ignoreModels, name, filter, allowIdFields) {
9869+
QueryBuilder.buildField = function (model, multiple, args, ignoreRelations, name, filter, allowIdFields) {
98709870
if (multiple === void 0) { multiple = true; }
9871-
if (ignoreModels === void 0) { ignoreModels = []; }
9871+
if (ignoreRelations === void 0) { ignoreRelations = []; }
98729872
if (filter === void 0) { filter = false; }
98739873
if (allowIdFields === void 0) { allowIdFields = false; }
98749874
var context = Context.getInstance();
98759875
model = context.getModel(model);
9876-
ignoreModels.push(model);
98779876
var params = this.buildArguments(model, args, false, filter, allowIdFields);
9878-
var fields = "\n " + model.getQueryFields().join(' ') + "\n " + this.buildRelationsQuery(model, ignoreModels) + "\n ";
9877+
var fields = "\n " + model.getQueryFields().join(' ') + "\n " + this.buildRelationsQuery(model, ignoreRelations) + "\n ";
98799878
if (multiple) {
98809879
return "\n " + (name ? name : model.pluralName) + params + " {\n nodes {\n " + fields + "\n }\n }\n ";
98819880
}
@@ -10026,14 +10025,12 @@ var QueryBuilder = /** @class */ (function () {
1002610025
* Generates the fields for all related models.
1002710026
*
1002810027
* @param {Model} model
10029-
* @param {Array<Model>} ignoreModels The models in this list are ignored (while traversing relations).
10028+
* @param {Array<Model>} ignoreRelations The models in this list are ignored (while traversing relations).
1003010029
* @returns {string}
10031-
*
10032-
* @todo https://github.com/vuex-orm/vuex-orm-apollo/issues/13
1003310030
*/
10034-
QueryBuilder.buildRelationsQuery = function (model, ignoreModels) {
10031+
QueryBuilder.buildRelationsQuery = function (model, ignoreRelations) {
1003510032
var _this = this;
10036-
if (ignoreModels === void 0) { ignoreModels = []; }
10033+
if (ignoreRelations === void 0) { ignoreRelations = []; }
1003710034
if (model === null)
1003810035
return '';
1003910036
var context = Context.getInstance();
@@ -10051,22 +10048,25 @@ var QueryBuilder = /** @class */ (function () {
1005110048
context.logger.log('WARNING: field has neither parent nor related property. Fallback to attribute name', field);
1005210049
}
1005310050
if (model.shouldEagerLoadRelation(field, relatedModel) &&
10054-
!_this.shouldModelBeIgnored(relatedModel, ignoreModels)) {
10051+
!_this.shouldRelationBeIgnored(model, relatedModel, ignoreRelations)) {
1005510052
var multiple = !(field instanceof context.components.BelongsTo ||
1005610053
field instanceof context.components.HasOne);
10057-
relationQueries.push(_this.buildField(relatedModel, multiple, undefined, ignoreModels, name, false));
10054+
relationQueries.push(_this.buildField(relatedModel, multiple, undefined, ignoreRelations, name, false));
10055+
ignoreRelations.push(model.singularName + "." + relatedModel.singularName);
1005810056
}
1005910057
});
1006010058
return relationQueries.join('\n');
1006110059
};
1006210060
/**
10063-
* Tells if a model should be ignored because it's included in the ignoreModels array.
10061+
* Tells if a relation should be ignored because it's included in the ignoreRelations array.
1006410062
* @param {Model} model
10065-
* @param {Array<Model>} ignoreModels
10063+
* @param {Model} relatedModel
10064+
* @param {Array<string>} ignoreRelations
1006610065
* @returns {boolean}
1006710066
*/
10068-
QueryBuilder.shouldModelBeIgnored = function (model, ignoreModels) {
10069-
return ignoreModels.find(function (m) { return m.singularName === model.singularName; }) !== undefined;
10067+
QueryBuilder.shouldRelationBeIgnored = function (model, relatedModel, ignoreRelations) {
10068+
var relevantRelation = model.singularName + "." + relatedModel.singularName;
10069+
return ignoreRelations.find(function (r) { return r === relevantRelation; }) !== undefined;
1007010070
};
1007110071
return QueryBuilder;
1007210072
}());

src/graphql/query-builder.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export default class QueryBuilder {
1414
* @param {Model|string} model The model to use
1515
* @param {boolean} multiple Determines whether plural/nodes syntax or singular syntax is used.
1616
* @param {Arguments} args The args that will be passed to the query field ( user(role: $role) )
17-
* @param {Array<Model>} ignoreModels The models in this list are ignored (while traversing relations).
17+
* @param {Array<Model>} ignoreRelations The models in this list are ignored (while traversing relations).
1818
* Mainly for recursion
1919
* @param {string} name Optional name of the field. If not provided, this will be the model name
2020
* @param {boolean} allowIdFields Optional. Determines if id fields will be ignored for the argument generation.
@@ -26,20 +26,19 @@ export default class QueryBuilder {
2626
public static buildField (model: Model | string,
2727
multiple: boolean = true,
2828
args?: Arguments,
29-
ignoreModels: Array<Model> = [],
29+
ignoreRelations: Array<string> = [],
3030
name?: string,
3131
filter: boolean = false,
3232
allowIdFields: boolean = false): string {
3333

3434
const context = Context.getInstance();
3535
model = context.getModel(model);
36-
ignoreModels.push(model);
3736

3837
let params: string = this.buildArguments(model, args, false, filter, allowIdFields);
3938

4039
const fields = `
4140
${model.getQueryFields().join(' ')}
42-
${this.buildRelationsQuery(model, ignoreModels)}
41+
${this.buildRelationsQuery(model, ignoreRelations)}
4342
`;
4443

4544
if (multiple) {
@@ -208,12 +207,10 @@ export default class QueryBuilder {
208207
* Generates the fields for all related models.
209208
*
210209
* @param {Model} model
211-
* @param {Array<Model>} ignoreModels The models in this list are ignored (while traversing relations).
210+
* @param {Array<Model>} ignoreRelations The models in this list are ignored (while traversing relations).
212211
* @returns {string}
213-
*
214-
* @todo https://github.com/vuex-orm/vuex-orm-apollo/issues/13
215212
*/
216-
private static buildRelationsQuery (model: (null | Model), ignoreModels: Array<Model> = []): string {
213+
private static buildRelationsQuery (model: (null | Model), ignoreRelations: Array<string> = []): string {
217214
if (model === null) return '';
218215

219216
const context = Context.getInstance();
@@ -232,25 +229,28 @@ export default class QueryBuilder {
232229
}
233230

234231
if (model.shouldEagerLoadRelation(field, relatedModel) &&
235-
!this.shouldModelBeIgnored(relatedModel, ignoreModels)) {
232+
!this.shouldRelationBeIgnored(model, relatedModel, ignoreRelations)) {
236233

237234
const multiple: boolean = !(field instanceof context.components.BelongsTo ||
238235
field instanceof context.components.HasOne);
239236

240-
relationQueries.push(this.buildField(relatedModel, multiple, undefined, ignoreModels, name, false));
237+
relationQueries.push(this.buildField(relatedModel, multiple, undefined, ignoreRelations, name, false));
238+
ignoreRelations.push(`${model.singularName}.${relatedModel.singularName}`);
241239
}
242240
});
243241

244242
return relationQueries.join('\n');
245243
}
246244

247245
/**
248-
* Tells if a model should be ignored because it's included in the ignoreModels array.
246+
* Tells if a relation should be ignored because it's included in the ignoreRelations array.
249247
* @param {Model} model
250-
* @param {Array<Model>} ignoreModels
248+
* @param {Model} relatedModel
249+
* @param {Array<string>} ignoreRelations
251250
* @returns {boolean}
252251
*/
253-
private static shouldModelBeIgnored (model: Model, ignoreModels: Array<Model>): boolean {
254-
return ignoreModels.find((m) => m.singularName === model.singularName) !== undefined;
252+
private static shouldRelationBeIgnored (model: Model, relatedModel: Model, ignoreRelations: Array<string>): boolean {
253+
const relevantRelation = `${model.singularName}.${relatedModel.singularName}`;
254+
return ignoreRelations.find((r) => r === relevantRelation) !== undefined;
255255
}
256256
}

test/integration/VuexORMApollo.spec.js

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,12 @@ describe('VuexORMApollo', () => {
2727
id: 15,
2828
content: 'Works!',
2929
subjectId: 42,
30-
subjectType: 'Post'
30+
subjectType: 'Post',
31+
user: {
32+
__typename: 'user',
33+
id: 2,
34+
name: 'Charly Brown'
35+
}
3136
}]
3237
},
3338
user: {
@@ -63,6 +68,11 @@ query Post($id: ID!) {
6368
content
6469
subjectId
6570
subjectType
71+
user {
72+
id
73+
name
74+
__typename
75+
}
6676
__typename
6777
}
6878
__typename
@@ -229,7 +239,12 @@ query Users {
229239
id: 15,
230240
content: 'Works!',
231241
subjectId: 42,
232-
subjectType: 'Post'
242+
subjectType: 'Post',
243+
user: {
244+
__typename: 'user',
245+
id: 2,
246+
name: 'Charly Brown'
247+
}
233248
}]
234249
},
235250
user: {
@@ -281,6 +296,11 @@ mutation CreatePost($post: PostInput!) {
281296
content
282297
subjectId
283298
subjectType
299+
user {
300+
id
301+
name
302+
__typename
303+
}
284304
__typename
285305
}
286306
__typename
@@ -411,6 +431,11 @@ query UnpublishedPosts($userId: ID!) {
411431
content
412432
subjectId
413433
subjectType
434+
user {
435+
id
436+
name
437+
__typename
438+
}
414439
__typename
415440
}
416441
__typename
@@ -472,6 +497,11 @@ query Example($userId: ID!, $id: ID!) {
472497
content
473498
subjectId
474499
subjectType
500+
user {
501+
id
502+
name
503+
__typename
504+
}
475505
__typename
476506
}
477507
__typename
@@ -534,6 +564,11 @@ mutation UpvotePost($captchaToken: String!, $id: ID!) {
534564
content
535565
subjectId
536566
subjectType
567+
user {
568+
id
569+
name
570+
__typename
571+
}
537572
__typename
538573
}
539574
__typename

test/unit/QueryBuilder.spec.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ query test {
7474
content
7575
subjectId
7676
subjectType
77+
user {
78+
id
79+
name
80+
}
7781
}
7882
}
7983
}
@@ -128,6 +132,10 @@ query Posts($title: String!) {
128132
content
129133
subjectId
130134
subjectType
135+
user {
136+
id
137+
name
138+
}
131139
}
132140
}
133141
}
@@ -161,6 +169,10 @@ mutation CreatePost($post: PostInput!) {
161169
content
162170
subjectId
163171
subjectType
172+
user {
173+
id
174+
name
175+
}
164176
}
165177
}
166178
}
@@ -193,6 +205,10 @@ mutation UpdatePost($id: ID!, $post: PostInput!) {
193205
content
194206
subjectId
195207
subjectType
208+
user {
209+
id
210+
name
211+
}
196212
}
197213
}
198214
}

0 commit comments

Comments
 (0)