Skip to content

Commit 31b69e1

Browse files
committed
Allow self referencing relationships
1 parent f07157f commit 31b69e1

File tree

6 files changed

+147
-5
lines changed

6 files changed

+147
-5
lines changed

dist/vuex-orm-graphql.esm.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25390,7 +25390,7 @@ var DataStore = /** @class */ (function () {
2539025390
return DataStore;
2539125391
}());
2539225392

25393-
var version_1 = "2.3.1";
25393+
var version_1 = "2.3.5";
2539425394

2539525395
var __assign$7 = (undefined && undefined.__assign) || Object.assign || function(t) {
2539625396
for (var s, i = 1, n = arguments.length; i < n; i++) {
@@ -28324,7 +28324,12 @@ var QueryBuilder = /** @class */ (function () {
2832428324
relatedModel = context.getModel(name);
2832528325
context.logger.log('WARNING: field has neither parent nor related property. Fallback to attribute name', field);
2832628326
}
28327-
var ignore = path.includes(relatedModel.singularName);
28327+
// We will ignore the field, when it's already in the path. Means: When it's already queried. However there are
28328+
// cases where the model will have a relationship to itself. For example a nested category strucure where the
28329+
// category model has a parent: belongsTo(Category). So we also check if the model references itself. If this is
28330+
// the case, we allow the nesting up to 5 times.
28331+
var referencesItSelf = takeWhile(path.slice(0).reverse(), function (p) { return p === relatedModel.singularName; }).length;
28332+
var ignore = referencesItSelf ? referencesItSelf > 5 : path.includes(relatedModel.singularName);
2832828333
// console.log(`-----> Will ${ignore ? '' : 'not'} ignore ${model.singularName}.${name}, path: ${path.join('.')}`);
2832928334
if (model.shouldEagerLoadRelation(name, field, relatedModel) && !ignore) {
2833028335
var newPath = path.slice(0);

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@vuex-orm/plugin-graphql",
3-
"version": "1.0.0-rc.14",
3+
"version": "1.0.0-rc.15",
44
"description": "Vuex-ORM Plugin to sync the data against a GraphQL API.",
55
"main": "dist/vuex-orm-graphql.common.js",
66
"module": "dist/vuex-orm-graphql.esm.js",

src/graphql/query-builder.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,12 @@ export default class QueryBuilder {
317317
context.logger.log('WARNING: field has neither parent nor related property. Fallback to attribute name', field);
318318
}
319319

320-
const ignore = path.includes(relatedModel.singularName);
320+
// We will ignore the field, when it's already in the path. Means: When it's already queried. However there are
321+
// cases where the model will have a relationship to itself. For example a nested category strucure where the
322+
// category model has a parent: belongsTo(Category). So we also check if the model references itself. If this is
323+
// the case, we allow the nesting up to 5 times.
324+
const referencesItSelf = _.takeWhile(path.slice(0).reverse(), p => p === relatedModel.singularName).length;
325+
const ignore = referencesItSelf ? referencesItSelf > 5 : path.includes(relatedModel.singularName);
321326

322327
// console.log(`-----> Will ${ignore ? '' : 'not'} ignore ${model.singularName}.${name}, path: ${path.join('.')}`);
323328

test/support/mock-data.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,19 @@ export class TariffOption extends ORMModel {
132132
}
133133
}
134134

135+
export class Category extends ORMModel {
136+
static entity = 'categories';
137+
138+
static fields () {
139+
return {
140+
id: this.increment(),
141+
name: this.string(''),
142+
143+
parentId: this.number(0),
144+
parent: this.belongsTo(Category, 'parentId'),
145+
}
146+
}
147+
}
135148

136149
export async function setupMockData() {
137150
let store, vuexOrmGraphQL;
@@ -144,7 +157,8 @@ export async function setupMockData() {
144157
{ model: Comment },
145158
{ model: TariffOption },
146159
{ model: Tariff },
147-
{ model: TariffTariffOption }
160+
{ model: TariffTariffOption },
161+
{ model: Category }
148162
]);
149163

150164
return [store, vuexOrmGraphQL];

test/support/mock-schema.js

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { User, Profile, Video, Post, Comment, Tariff, TariffOption } from 'test/support/mock-data'
22
import inflection from 'inflection';
33
import * as _ from 'lodash';
4+
import {Category} from "./mock-data";
45

56

67
export const typeDefs = `
@@ -21,6 +22,8 @@ export const typeDefs = `
2122
tariffs(filter: TariffFilter): TariffTypeConnection!
2223
tariffTariffOption(id: ID!): TariffTariffOption!
2324
tariffTariffOptions(filter: TariffTariffOptionFilter): TariffTariffOptionTypeConnection!
25+
category(id: ID!): Category!
26+
categories(filter: CategoryFilter): CategoryTypeConnection!
2427
2528
unpublishedPosts(authorId: ID!): PostTypeConnection
2629
status: Status
@@ -320,6 +323,34 @@ export const typeDefs = `
320323
type TariffTariffOptionTypeConnection {
321324
nodes: [TariffTariffOption!]!
322325
}
326+
327+
type Category {
328+
id: ID
329+
name: String
330+
parentId: ID
331+
parent: Category
332+
}
333+
334+
335+
input CategoryFilter {
336+
id: ID
337+
name: String
338+
parentId: ID
339+
parent: CategoryInput
340+
}
341+
342+
343+
input CategoryInput {
344+
id: ID
345+
name: String
346+
parentId: ID
347+
parent: CategoryInput
348+
}
349+
350+
351+
type CategoryTypeConnection {
352+
nodes: [Category!]!
353+
}
323354
`;
324355

325356

@@ -493,6 +524,56 @@ const tariffOptions = [
493524
}
494525
];
495526

527+
const categories = [
528+
{
529+
id: 1,
530+
name: 'Programming',
531+
parentId: 0,
532+
},
533+
534+
{
535+
id: 2,
536+
name: 'Frameworks',
537+
parentId: 1,
538+
},
539+
540+
{
541+
id: 3,
542+
name: 'Languages',
543+
parentId: 1,
544+
},
545+
546+
{
547+
id: 4,
548+
name: 'Patterns',
549+
parentId: 1,
550+
},
551+
552+
{
553+
id: 5,
554+
name: 'Ruby',
555+
parentId: 3,
556+
},
557+
558+
{
559+
id: 6,
560+
name: 'JavaScript',
561+
parentId: 3,
562+
},
563+
564+
{
565+
id: 7,
566+
name: 'PHP',
567+
parentId: 3,
568+
},
569+
570+
{
571+
id: 8,
572+
name: 'RSpec',
573+
parentId: 5,
574+
},
575+
];
576+
496577

497578
function addRelations(model, record, path = []) {
498579
if (!record) return record;
@@ -530,6 +611,10 @@ function addRelations(model, record, path = []) {
530611
if (!ignoreRelation(Tariff, path)) record.tariffs = findMany(Tariff, tariffs, () => true, path);
531612
break;
532613

614+
case Category:
615+
if (record.parentId) record.parent = findOne(Category, categories, record.parentId);
616+
break;
617+
533618
}
534619

535620
return record;
@@ -600,6 +685,8 @@ export const resolvers = {
600685
tariffs: (parent, { filter }) => findMany(Tariff, tariffs, filter),
601686
tariffOption: (parent, { id }) => findOne(TariffOption, tariffOptions, id),
602687
tariffOptions: (parent, { filter }) => findMany(TariffOption, tariffOptions, filter),
688+
category: (parent, { id }) => findOne(Category, categories, id),
689+
categories: (parent, { filter }) => findMany(Category, categories, filter),
603690

604691
unpublishedPosts: (parent, { authorId }) => findMany(Post, posts, { authorId }),
605692
status: (parent, args) => ({

test/unit/QueryBuilder.spec.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,37 @@ query test {
114114
}
115115
`.trim());
116116
});
117+
118+
119+
it('respects nested categories', () => {
120+
const fields = QueryBuilder.buildRelationsQuery(context.getModel('category'), ['category']);
121+
const query = prettify(`query test { ${fields} }`).trim();
122+
123+
expect(query).toEqual(`
124+
query test {
125+
parent {
126+
id
127+
name
128+
parent {
129+
id
130+
name
131+
parent {
132+
id
133+
name
134+
parent {
135+
id
136+
name
137+
parent {
138+
id
139+
name
140+
}
141+
}
142+
}
143+
}
144+
}
145+
}
146+
`.trim());
147+
});
117148
});
118149

119150

0 commit comments

Comments
 (0)