fix: association find and count

This commit is contained in:
chenos 2020-12-27 21:08:06 +08:00
parent 629a4de173
commit 04e9393dea

View File

@ -1,4 +1,4 @@
import { Utils, Op } from 'sequelize';
import { Utils, Op, Sequelize } from 'sequelize';
import _ from 'lodash';
import { Context, Next } from '.';
import {
@ -12,6 +12,136 @@ import {
import { DEFAULT_PAGE, DEFAULT_PER_PAGE } from '@nocobase/resourcer';
import { filterByFields } from '../utils';
async function hasManyGet(instances, options: any = {}) {
const where = {};
let Model = this.target;
let instance;
let values;
if (!Array.isArray(instances)) {
instance = instances;
instances = undefined;
}
options = { ...options };
if (this.scope) {
Object.assign(where, this.scope);
}
if (instances) {
values = instances.map(_instance => _instance.get(this.sourceKey, { raw: true }));
if (options.limit && instances.length > 1) {
options.groupedLimit = {
limit: options.limit,
on: this, // association
values
};
delete options.limit;
} else {
where[this.foreignKey] = {
[Op.in]: values
};
delete options.groupedLimit;
}
} else {
where[this.foreignKey] = instance.get(this.sourceKey, { raw: true });
}
options.where = options.where ?
{ [Op.and]: [where, options.where] } :
where;
if (Object.prototype.hasOwnProperty.call(options, 'scope')) {
if (!options.scope) {
Model = Model.unscoped();
} else {
Model = Model.scope(options.scope);
}
}
if (Object.prototype.hasOwnProperty.call(options, 'schema')) {
Model = Model.schema(options.schema, options.schemaDelimiter);
}
const results = await Model.findAndCountAll(options);
if (instance) return results;
const result = {};
for (const _instance of instances) {
result[_instance.get(this.sourceKey, { raw: true })] = [];
}
for (const _instance of results) {
result[_instance.get(this.foreignKey, { raw: true })].push(_instance);
}
return result;
}
async function belongsToManyGet(instance, options) {
options = Utils.cloneDeep(options) || {};
const through = this.through;
let scopeWhere;
let throughWhere;
if (this.scope) {
scopeWhere = { ...this.scope };
}
options.where = {
[Op.and]: [
scopeWhere,
options.where
]
};
if (Object(through.model) === through.model) {
throughWhere = {};
throughWhere[this.foreignKey] = instance.get(this.sourceKey);
if (through.scope) {
Object.assign(throughWhere, through.scope);
}
//If a user pass a where on the options through options, make an "and" with the current throughWhere
if (options.through && options.through.where) {
throughWhere = {
[Op.and]: [throughWhere, options.through.where]
};
}
options.include = options.include || [];
options.include.push({
association: this.oneFromTarget,
attributes: options.joinTableAttributes,
required: true,
paranoid: _.get(options.through, 'paranoid', true),
where: throughWhere
});
}
let model = this.target;
if (Object.prototype.hasOwnProperty.call(options, 'scope')) {
if (!options.scope) {
model = model.unscoped();
} else {
model = model.scope(options.scope);
}
}
if (Object.prototype.hasOwnProperty.call(options, 'schema')) {
model = model.schema(options.schema, options.schemaDelimiter);
}
return model.findAndCountAll(options);
}
/**
*
*
@ -53,31 +183,24 @@ export async function list(ctx: Context, next: Next) {
if (!(associated instanceof AssociatedModel)) {
throw new Error(`${associatedName} associated model invalid`);
}
const getAccessor = resourceField.getAccessors().get;
const countAccessor = resourceField.getAccessors().count;
// const getAccessor = resourceField.getAccessors().get;
// const countAccessor = resourceField.getAccessors().count;
options.scope = options.scopes||[];
const rows = await associated[getAccessor]({
const association = AssociatedModel.associations[resourceField.options.name];
if (resourceField instanceof BELONGSTOMANY) {
data = await belongsToManyGet.call(association, associated, {
joinTableAttributes: [],
...options,
context: ctx,
});
const associatedOptions = _.omit(options, [
'attributes',
'limit',
'offset',
'order'
]);
if (associatedOptions.include) {
associatedOptions.include = associatedOptions.include.map(includeOptions => {
includeOptions.attributes = [];
return includeOptions;
}
if (resourceField instanceof HASMANY) {
data = await hasManyGet.call(association, associated, {
joinTableAttributes: [],
...options,
context: ctx,
});
}
const count = await associated[countAccessor]({ ...associatedOptions, context: ctx });
data = {
rows,
count,
};
} else {
Model = ctx.db.getModel(resourceName);
options = Model.parseApiJson({