fix: association find and count
This commit is contained in:
parent
629a4de173
commit
04e9393dea
@ -1,4 +1,4 @@
|
|||||||
import { Utils, Op } from 'sequelize';
|
import { Utils, Op, Sequelize } from 'sequelize';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { Context, Next } from '.';
|
import { Context, Next } from '.';
|
||||||
import {
|
import {
|
||||||
@ -12,6 +12,136 @@ import {
|
|||||||
import { DEFAULT_PAGE, DEFAULT_PER_PAGE } from '@nocobase/resourcer';
|
import { DEFAULT_PAGE, DEFAULT_PER_PAGE } from '@nocobase/resourcer';
|
||||||
import { filterByFields } from '../utils';
|
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)) {
|
if (!(associated instanceof AssociatedModel)) {
|
||||||
throw new Error(`${associatedName} associated model invalid`);
|
throw new Error(`${associatedName} associated model invalid`);
|
||||||
}
|
}
|
||||||
const getAccessor = resourceField.getAccessors().get;
|
// const getAccessor = resourceField.getAccessors().get;
|
||||||
const countAccessor = resourceField.getAccessors().count;
|
// const countAccessor = resourceField.getAccessors().count;
|
||||||
options.scope = options.scopes||[];
|
options.scope = options.scopes||[];
|
||||||
const rows = await associated[getAccessor]({
|
const association = AssociatedModel.associations[resourceField.options.name];
|
||||||
joinTableAttributes: [],
|
if (resourceField instanceof BELONGSTOMANY) {
|
||||||
...options,
|
data = await belongsToManyGet.call(association, associated, {
|
||||||
context: ctx,
|
joinTableAttributes: [],
|
||||||
});
|
...options,
|
||||||
const associatedOptions = _.omit(options, [
|
context: ctx,
|
||||||
'attributes',
|
});
|
||||||
'limit',
|
}
|
||||||
'offset',
|
if (resourceField instanceof HASMANY) {
|
||||||
'order'
|
data = await hasManyGet.call(association, associated, {
|
||||||
]);
|
joinTableAttributes: [],
|
||||||
if (associatedOptions.include) {
|
...options,
|
||||||
associatedOptions.include = associatedOptions.include.map(includeOptions => {
|
context: ctx,
|
||||||
includeOptions.attributes = [];
|
|
||||||
return includeOptions;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const count = await associated[countAccessor]({ ...associatedOptions, context: ctx });
|
|
||||||
data = {
|
|
||||||
rows,
|
|
||||||
count,
|
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
Model = ctx.db.getModel(resourceName);
|
Model = ctx.db.getModel(resourceName);
|
||||||
options = Model.parseApiJson({
|
options = Model.parseApiJson({
|
||||||
|
Loading…
Reference in New Issue
Block a user