Make GraphQL polymorphic relationships working with Bookshelf

This commit is contained in:
Aurelsicoko 2018-04-11 12:53:07 +02:00
parent c59ad9d958
commit 17c46b331d
4 changed files with 83 additions and 30 deletions

View File

@ -176,6 +176,7 @@ module.exports = function(strapi) {
attrs[association.alias] = attrs[association.alias].related; attrs[association.alias] = attrs[association.alias].related;
break; break;
case 'manyMorphToOne': case 'manyMorphToOne':
case 'manyMorphToMany':
attrs[association.alias] = attrs[association.alias].map(obj => obj.related); attrs[association.alias] = attrs[association.alias].map(obj => obj.related);
break; break;
default: default:
@ -226,7 +227,6 @@ module.exports = function(strapi) {
const association = definition.associations const association = definition.associations
.filter(association => association.nature.toLowerCase().indexOf('morph') !== -1) .filter(association => association.nature.toLowerCase().indexOf('morph') !== -1)
.filter(association => association.alias === path || association.via === path)[0]; .filter(association => association.alias === path || association.via === path)[0];
if (association) { if (association) {
// Override on polymorphic path only. // Override on polymorphic path only.
if (_.isString(path) && path === association.via) { if (_.isString(path) && path === association.via) {

View File

@ -29,16 +29,37 @@ module.exports = {
.count(); .count();
}, },
findOne: async function (params) { findOne: async function (params, populate, raw = true) {
const record = await this const record = await this
.forge({ .forge({
[this.primaryKey]: params[this.primaryKey] [this.primaryKey]: params[this.primaryKey]
}) })
.fetch({ .fetch({
withRelated: this.associations.map(x => x.alias) withRelated: populate || this.associations.map(x => x.alias)
}); });
return record ? record.toJSON() : record; const data = record ? record.toJSON() : record;
// Retrieve data manually.
if (_.isEmpty(populate)) {
const arrayOfPromises = this.associations
.filter(association => ['manyMorphToOne', 'manyMorphToMany'].includes(association.nature))
.map(association => {
return this.morph.forge()
.where({
[`${this.collectionName}_id`]: params[this.primaryKey]
})
.fetchAll()
});
const related = await Promise.all(arrayOfPromises);
related.forEach((value, index) => {
data[this.associations[index].alias] = value ? value.toJSON() : value;
});
}
return data;
}, },
create: async function (params) { create: async function (params) {

View File

@ -475,31 +475,38 @@ module.exports = {
acc.resolver[globalId] = {}; acc.resolver[globalId] = {};
} }
if (association.nature === 'manyMorphToMany') { switch (association.nature) {
return _.merge(acc.resolver[globalId], { case 'manyMorphToOne':
[association.alias]: async (obj, options, context) => { case 'manyMorphToMany':
const [ withRelated, withoutRelated ] = await Promise.all([ return _.merge(acc.resolver[globalId], {
resolvers.fetch({ [association.alias]: async (obj, options, context) => {
id: obj[model.primaryKey], const [ withRelated, withoutRelated ] = await Promise.all([
model: name resolvers.fetch({
}, plugin, [association.alias], false), id: obj[model.primaryKey],
resolvers.fetch({ model: name
id: obj[model.primaryKey], }, plugin, [association.alias], false),
model: name resolvers.fetch({
}, plugin, []) id: obj[model.primaryKey],
]); model: name
}, plugin, [])
]);
const entry = withRelated.toJSON ? withRelated.toJSON() : withRelated; const entry = withRelated.toJSON ? withRelated.toJSON() : withRelated;
entry[association.alias].map((entry, index) => { entry[association.alias].map((entry, index) => {
entry._type = withoutRelated[association.alias][index].kind; const type = withoutRelated[association.alias][index].kind ||
_.upperFirst(_.camelCase(withoutRelated[association.alias][index][`${association.alias}_type`]));
return entry; entry._type = type;
});
return entry[association.alias]; return entry;
} });
});
return entry[association.alias];
}
});
break;
default:
} }
// TODO: // TODO:
@ -520,13 +527,13 @@ module.exports = {
} else { } else {
// Get attribute. // Get attribute.
const attr = association.plugin ? const attr = association.plugin ?
strapi.plugins[association.plugin].models[association.collection].attributes[association.via]: strapi.plugins[association.plugin].models[params.model].attributes[association.via]:
strapi.models[association.collection].attributes[association.via]; strapi.models[params.model].attributes[association.via];
// Get refering model. // Get refering model.
const ref = attr.plugin ? const ref = attr.plugin ?
strapi.plugins[attr.plugin].models[attr.model || attr.collection]: strapi.plugins[attr.plugin].models[params.model]:
strapi.models[attr.model || attr.collection]; strapi.models[params.model];
// Apply optional arguments to make more precise nested request. // Apply optional arguments to make more precise nested request.
const convertedParams = strapi.utils.models.convertParams(name, this.convertToParams(options)); const convertedParams = strapi.utils.models.convertParams(name, this.convertToParams(options));
@ -668,7 +675,7 @@ module.exports = {
polymorphicDef: `union Morph = ${types.join(' | ')}`, polymorphicDef: `union Morph = ${types.join(' | ')}`,
polymorphicResolver: { polymorphicResolver: {
Morph: { Morph: {
__resolveType(obj, context, info){ __resolveType(obj, context, info) {
return obj.kind || obj._type; return obj.kind || obj._type;
} }
} }

View File

@ -0,0 +1,25 @@
module.exports = {
type: {
UsersPermissionsPermission: false // Make this type NOT queriable.
},
resolver: {
Query: {
role: {
resolverOf: 'UsersPermissions.getRole',
resolver: async (obj, options, ctx) => {
await strapi.plugins['users-permissions'].controllers.userspermissions.getRole(ctx);
return ctx.body.role;
}
},
roles: {
resolverOf: 'UsersPermissions.getRoles', // Apply the `getRoles` permissions on the resolver.
resolver: async (obj, options, ctx) => {
await strapi.plugins['users-permissions'].controllers.userspermissions.getRoles(ctx);
return ctx.body.roles;
}
}
}
}
};