Fix bad conversion of id to _id in graphql and aggregations

This commit is contained in:
Alexandre Bodin 2019-09-16 22:53:54 +02:00
parent 0026819119
commit c1f818958a
3 changed files with 72 additions and 63 deletions

View File

@ -143,8 +143,8 @@ const extractType = function(_type, attributeType) {
return isPrimitiveType(_type) return isPrimitiveType(_type)
? _type.replace('!', '') ? _type.replace('!', '')
: isEnumType(attributeType) : isEnumType(attributeType)
? 'String' ? 'String'
: 'ID'; : 'ID';
}; };
/** /**
@ -169,11 +169,20 @@ const extractType = function(_type, attributeType) {
* age: function ageResolver() { .... } * age: function ageResolver() { .... }
* } * }
*/ */
const createAggregationFieldsResolver = function(model, fields, operation, typeCheck) { const createAggregationFieldsResolver = function(
model,
fields,
operation,
typeCheck
) {
return createFieldsResolver( return createFieldsResolver(
fields, fields,
async (filters, options, context, fieldResolver, fieldKey) => { async (obj, options, context, fieldResolver, fieldKey) => {
// eslint-disable-line no-unused-vars const filters = convertRestQueryParams({
...GraphQLQuery.convertToParams(_.omit(obj, 'where')),
...GraphQLQuery.convertToQuery(obj.where),
});
return buildQuery({ model, filters, aggregate: true }) return buildQuery({ model, filters, aggregate: true })
.group({ .group({
_id: null, _id: null,
@ -194,7 +203,16 @@ const preProcessGroupByData = function({ result, fieldKey, filters, model }) {
return _.map(_result, value => { return _.map(_result, value => {
return { return {
key: value._id, key: value._id,
connection: () => filters, connection: () => {
// filter by the grouped by value in next connection
return {
...filters,
where: {
...filters.where || {},
[fieldKey]: value._id
}
}
},
}; };
}); });
}; };
@ -219,7 +237,14 @@ const preProcessGroupByData = function({ result, fieldKey, filters, model }) {
* } * }
*/ */
const createGroupByFieldsResolver = function(model, fields, name) { const createGroupByFieldsResolver = function(model, fields, name) {
const resolver = async (filters, options, context, fieldResolver, fieldKey) => { const resolver = async (
filters,
options,
context,
fieldResolver,
fieldKey
) => {
const params = { const params = {
...GraphQLQuery.convertToParams(_.omit(filters, 'where')), ...GraphQLQuery.convertToParams(_.omit(filters, 'where')),
...GraphQLQuery.convertToQuery(filters.where), ...GraphQLQuery.convertToQuery(filters.where),
@ -233,6 +258,8 @@ const createGroupByFieldsResolver = function(model, fields, name) {
_id: `$${fieldKey}`, _id: `$${fieldKey}`,
}); });
return preProcessGroupByData({ return preProcessGroupByData({
result, result,
fieldKey, fieldKey,
@ -250,8 +277,10 @@ const createGroupByFieldsResolver = function(model, fields, name) {
*/ */
const generateConnectionFieldsTypes = function(fields, model) { const generateConnectionFieldsTypes = function(fields, model) {
const { globalId, attributes } = model; const { globalId, attributes } = model;
const primitiveFields = getFieldsByTypes(fields, isNotOfTypeArray, (type, name) => const primitiveFields = getFieldsByTypes(
extractType(type, (attributes[name] || {}).type) fields,
isNotOfTypeArray,
(type, name) => extractType(type, (attributes[name] || {}).type)
); );
const connectionFields = _.mapValues(primitiveFields, fieldType => ({ const connectionFields = _.mapValues(primitiveFields, fieldType => ({
@ -262,9 +291,9 @@ const generateConnectionFieldsTypes = function(fields, model) {
return Object.keys(primitiveFields) return Object.keys(primitiveFields)
.map( .map(
fieldKey => fieldKey =>
`type ${globalId}Connection${_.upperFirst(fieldKey)} {${Schema.formatGQL( `type ${globalId}Connection${_.upperFirst(
connectionFields[fieldKey] fieldKey
)}}` )} {${Schema.formatGQL(connectionFields[fieldKey])}}`
) )
.join('\n\n'); .join('\n\n');
}; };
@ -277,23 +306,30 @@ const formatConnectionGroupBy = function(fields, model, name) {
const groupByFields = getFieldsByTypes( const groupByFields = getFieldsByTypes(
fields, fields,
isNotOfTypeArray, isNotOfTypeArray,
(fieldType, fieldName) => `[${globalId}Connection${_.upperFirst(fieldName)}]` (fieldType, fieldName) =>
`[${globalId}Connection${_.upperFirst(fieldName)}]`
); );
// Get the generated field types // Get the generated field types
let groupByTypes = `type ${groupByGlobalId} {${Schema.formatGQL(groupByFields)}}\n\n`; let groupByTypes = `type ${groupByGlobalId} {${Schema.formatGQL(
groupByFields
)}}\n\n`;
groupByTypes += generateConnectionFieldsTypes(fields, model); groupByTypes += generateConnectionFieldsTypes(fields, model);
return { return {
globalId: groupByGlobalId, globalId: groupByGlobalId,
type: groupByTypes, type: groupByTypes,
resolver: { resolver: {
[groupByGlobalId]: createGroupByFieldsResolver(model, groupByFields, name), [groupByGlobalId]: createGroupByFieldsResolver(
model,
groupByFields,
name
),
}, },
}; };
}; };
const formatConnectionAggregator = function(fields, model) { const formatConnectionAggregator = function(fields, model, modelName) {
const { globalId } = model; const { globalId } = model;
// Extract all fields of type Integer and Float and change their type to Float // Extract all fields of type Integer and Float and change their type to Float
@ -314,26 +350,19 @@ const formatConnectionAggregator = function(fields, model) {
} }
const gqlNumberFormat = Schema.formatGQL(numericFields); const gqlNumberFormat = Schema.formatGQL(numericFields);
let aggregatorTypes = `type ${aggregatorGlobalId} {${Schema.formatGQL(initialFields)}}\n\n`; let aggregatorTypes = `type ${aggregatorGlobalId} {${Schema.formatGQL(
initialFields
)}}\n\n`;
let resolvers = { let resolvers = {
[aggregatorGlobalId]: { [aggregatorGlobalId]: {
count: async (obj, options, context) => { count(obj, options, context) {
return buildQuery({ const opts = GraphQLQuery.convertToQuery(obj.where);
model,
filters: { return strapi.query(modelName).count(opts);
limit: obj.limit,
where: obj.where,
},
}).count();
}, },
totalCount: async (obj, options, context) => { totalCount(obj, options, context) {
return buildQuery({ return strapi.query(modelName).count({});
model,
filters: {
where: obj.where,
},
}).count();
}, },
}, },
}; };
@ -483,12 +512,7 @@ const formatModelConnectionsGQL = function(fields, model, name, modelResolver) {
return obj; return obj;
}, },
aggregate(obj, options, context) { aggregate(obj, options, context) {
const params = { return obj;
...GraphQLQuery.convertToParams(_.omit(obj, 'where')),
...GraphQLQuery.convertToQuery(obj.where),
};
return convertRestQueryParams(params);
}, },
}, },
...aggregatorFormat.resolver, ...aggregatorFormat.resolver,

View File

@ -210,10 +210,7 @@ module.exports = {
} }
if (options.input && options.input.where) { if (options.input && options.input.where) {
context.params = Query.convertToParams( context.params = Query.convertToParams(options.input.where || {});
options.input.where || {},
primaryKey
);
} else { } else {
context.params = {}; context.params = {};
} }

View File

@ -18,9 +18,9 @@ module.exports = {
* @return Object * @return Object
*/ */
convertToParams: (params, primaryKey) => { convertToParams: params => {
return Object.keys(params).reduce((acc, current) => { return Object.keys(params).reduce((acc, current) => {
const key = current === 'id' ? primaryKey : `_${current}`; const key = current === 'id' ? 'id' : `_${current}`;
acc[key] = params[current]; acc[key] = params[current];
return acc; return acc;
}, {}); }, {});
@ -190,7 +190,7 @@ module.exports = {
return async (ctx, next) => { return async (ctx, next) => {
ctx.params = { ctx.params = {
...params, ...params,
[model.primaryKey]: ctx.query[model.primaryKey], id: ctx.query.id,
}; };
// Return the controller. // Return the controller.
@ -282,24 +282,12 @@ module.exports = {
// cause a lost of the Object prototype. // cause a lost of the Object prototype.
const opts = this.amountLimiting(_options); const opts = this.amountLimiting(_options);
Object.defineProperties(ctx, { ctx.query = {
query: { ...this.convertToParams(_.omit(opts, 'where')),
value: { ...this.convertToQuery(opts.where),
...this.convertToParams( };
_.omit(opts, 'where'),
model ? model.primaryKey : 'id' ctx.params = this.convertToParams(opts);
),
...this.convertToQuery(opts.where),
},
writable: true,
configurable: true,
},
params: {
value: this.convertToParams(opts, model ? model.primaryKey : 'id'),
writable: true,
configurable: true,
},
});
if (isController) { if (isController) {
const values = await resolver.call(null, ctx, null); const values = await resolver.call(null, ctx, null);