mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-05 05:29:26 +08:00
feat(plugin-workflow-aggregate): add precision option (#6491)
This commit is contained in:
parent
30c612cb08
commit
7da1c200ed
@ -22,7 +22,7 @@ export class BelongsToManyRepository extends MultipleRelationRepository {
|
|||||||
async aggregate(options: AggregateOptions) {
|
async aggregate(options: AggregateOptions) {
|
||||||
const targetRepository = this.targetCollection.repository;
|
const targetRepository = this.targetCollection.repository;
|
||||||
|
|
||||||
const sourceModel = await this.getSourceModel();
|
const sourceModel = await this.getSourceModel(await this.getTransaction(options));
|
||||||
|
|
||||||
const association = this.association as any;
|
const association = this.association as any;
|
||||||
|
|
||||||
|
@ -387,6 +387,21 @@ export default class extends Instruction {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
precision: {
|
||||||
|
type: 'number',
|
||||||
|
title: `{{t("Result precision", { ns: "${NAMESPACE}" })}}`,
|
||||||
|
description: `{{t("Number of decimal places for query result.", { ns: "${NAMESPACE}" })}}`,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'InputNumber',
|
||||||
|
'x-component-props': {
|
||||||
|
min: 0,
|
||||||
|
max: 14,
|
||||||
|
step: 1,
|
||||||
|
precision: 0,
|
||||||
|
className: 'auto-width',
|
||||||
|
},
|
||||||
|
default: 2,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
scope = {
|
scope = {
|
||||||
useCollectionDataSource,
|
useCollectionDataSource,
|
||||||
|
@ -8,5 +8,7 @@
|
|||||||
"Data of associated collection": "关联数据表数据",
|
"Data of associated collection": "关联数据表数据",
|
||||||
"Field to aggregate": "聚合字段",
|
"Field to aggregate": "聚合字段",
|
||||||
"Distinct": "去重",
|
"Distinct": "去重",
|
||||||
"Query result": "查询结果"
|
"Query result": "查询结果",
|
||||||
|
"Result precision": "结果精度",
|
||||||
|
"Number of decimal places for query result.": "查询结果小数位数"
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ const aggregators = {
|
|||||||
|
|
||||||
export default class extends Instruction {
|
export default class extends Instruction {
|
||||||
async run(node: FlowNodeModel, input, processor: Processor) {
|
async run(node: FlowNodeModel, input, processor: Processor) {
|
||||||
const { aggregator, associated, collection, association = {}, params = {} } = node.config;
|
const { aggregator, associated, collection, association = {}, params = {}, precision = 2 } = node.config;
|
||||||
const options = processor.getParsedValue(params, node.id);
|
const options = processor.getParsedValue(params, node.id);
|
||||||
const [dataSourceName, collectionName] = parseCollectionName(collection);
|
const [dataSourceName, collectionName] = parseCollectionName(collection);
|
||||||
const { collectionManager } = this.workflow.app.dataSourceManager.dataSources.get(dataSourceName);
|
const { collectionManager } = this.workflow.app.dataSourceManager.dataSources.get(dataSourceName);
|
||||||
@ -49,7 +49,10 @@ export default class extends Instruction {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
result: round((options.dataType === DataTypes.DOUBLE ? Number(result) : result) || 0, 14),
|
result: round(
|
||||||
|
(options.dataType === DataTypes.DOUBLE ? Number(result) : result) || 0,
|
||||||
|
Math.max(0, Math.min(precision, 14)),
|
||||||
|
),
|
||||||
status: JOB_STATUS.RESOLVED,
|
status: JOB_STATUS.RESOLVED,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,7 @@ describe('workflow > instructions > aggregate', () => {
|
|||||||
TagRepo = db.getCollection('tags').repository;
|
TagRepo = db.getCollection('tags').repository;
|
||||||
|
|
||||||
workflow = await WorkflowModel.create({
|
workflow = await WorkflowModel.create({
|
||||||
|
sync: true,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
type: 'collection',
|
type: 'collection',
|
||||||
config: {
|
config: {
|
||||||
@ -62,8 +63,6 @@ describe('workflow > instructions > aggregate', () => {
|
|||||||
|
|
||||||
const post = await PostRepo.create({ values: { title: 't1' } });
|
const post = await PostRepo.create({ values: { title: 't1' } });
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const [execution] = await workflow.getExecutions();
|
const [execution] = await workflow.getExecutions();
|
||||||
const [job] = await execution.getJobs();
|
const [job] = await execution.getJobs();
|
||||||
expect(job.result).toBe(1);
|
expect(job.result).toBe(1);
|
||||||
@ -86,8 +85,6 @@ describe('workflow > instructions > aggregate', () => {
|
|||||||
|
|
||||||
const post = await PostRepo.create({ values: { title: 't1' } });
|
const post = await PostRepo.create({ values: { title: 't1' } });
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const [execution] = await workflow.getExecutions();
|
const [execution] = await workflow.getExecutions();
|
||||||
const [job] = await execution.getJobs();
|
const [job] = await execution.getJobs();
|
||||||
expect(job.result).toBe(0);
|
expect(job.result).toBe(0);
|
||||||
@ -107,16 +104,12 @@ describe('workflow > instructions > aggregate', () => {
|
|||||||
|
|
||||||
const p1 = await PostRepo.create({ values: { title: 't1', read: 1 } });
|
const p1 = await PostRepo.create({ values: { title: 't1', read: 1 } });
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const [e1] = await workflow.getExecutions();
|
const [e1] = await workflow.getExecutions();
|
||||||
const [j1] = await e1.getJobs();
|
const [j1] = await e1.getJobs();
|
||||||
expect(j1.result).toBe(1);
|
expect(j1.result).toBe(1);
|
||||||
|
|
||||||
const p2 = await PostRepo.create({ values: { title: 't2', read: 2 } });
|
const p2 = await PostRepo.create({ values: { title: 't2', read: 2 } });
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const [e2] = await workflow.getExecutions({ order: [['id', 'desc']] });
|
const [e2] = await workflow.getExecutions({ order: [['id', 'desc']] });
|
||||||
const [j2] = await e2.getJobs();
|
const [j2] = await e2.getJobs();
|
||||||
expect(j2.result).toBe(3);
|
expect(j2.result).toBe(3);
|
||||||
@ -136,22 +129,18 @@ describe('workflow > instructions > aggregate', () => {
|
|||||||
|
|
||||||
const p1 = await PostRepo.create({ values: { title: 't1', score: 0.1 } });
|
const p1 = await PostRepo.create({ values: { title: 't1', score: 0.1 } });
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const [e1] = await workflow.getExecutions();
|
const [e1] = await workflow.getExecutions();
|
||||||
const [j1] = await e1.getJobs();
|
const [j1] = await e1.getJobs();
|
||||||
expect(j1.result).toBe(0.1);
|
expect(j1.result).toBe(0.1);
|
||||||
|
|
||||||
const p2 = await PostRepo.create({ values: { title: 't2', score: 0.2 } });
|
const p2 = await PostRepo.create({ values: { title: 't2', score: 0.2 } });
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const [e2] = await workflow.getExecutions({ order: [['id', 'desc']] });
|
const [e2] = await workflow.getExecutions({ order: [['id', 'desc']] });
|
||||||
const [j2] = await e2.getJobs();
|
const [j2] = await e2.getJobs();
|
||||||
expect(j2.result).toBe(0.3);
|
expect(j2.result).toBe(0.3);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sum number will be rounded', async () => {
|
it('sum number will be rounded to 2 decimal places by default', async () => {
|
||||||
const n1 = await workflow.createNode({
|
const n1 = await workflow.createNode({
|
||||||
type: 'aggregate',
|
type: 'aggregate',
|
||||||
config: {
|
config: {
|
||||||
@ -163,9 +152,59 @@ describe('workflow > instructions > aggregate', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const p1 = await PostRepo.create({ values: { title: 't1', score: 0.100000000000001 } });
|
const p1 = await PostRepo.create({ values: { title: 't1', score: 0.123 } });
|
||||||
|
|
||||||
await sleep(500);
|
const [e1] = await workflow.getExecutions();
|
||||||
|
const [j1] = await e1.getJobs();
|
||||||
|
expect(j1.result).toBe(0.12);
|
||||||
|
|
||||||
|
const p2 = await PostRepo.create({ values: { title: 't2', score: 0.456 } });
|
||||||
|
|
||||||
|
const [e2] = await workflow.getExecutions({ order: [['id', 'desc']] });
|
||||||
|
const [j2] = await e2.getJobs();
|
||||||
|
expect(j2.result).toBe(0.58);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sum precision configured -1 as 0', async () => {
|
||||||
|
const n1 = await workflow.createNode({
|
||||||
|
type: 'aggregate',
|
||||||
|
config: {
|
||||||
|
aggregator: 'sum',
|
||||||
|
collection: 'posts',
|
||||||
|
params: {
|
||||||
|
field: 'score',
|
||||||
|
},
|
||||||
|
precision: -1,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const p1 = await PostRepo.create({ values: { title: 't1', score: 0.123 } });
|
||||||
|
|
||||||
|
const [e1] = await workflow.getExecutions();
|
||||||
|
const [j1] = await e1.getJobs();
|
||||||
|
expect(j1.result).toBe(0);
|
||||||
|
|
||||||
|
const p2 = await PostRepo.create({ values: { title: 't2', score: 0.456 } });
|
||||||
|
|
||||||
|
const [e2] = await workflow.getExecutions({ order: [['id', 'desc']] });
|
||||||
|
const [j2] = await e2.getJobs();
|
||||||
|
expect(j2.result).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sum precision configured over 14 as 14', async () => {
|
||||||
|
const n1 = await workflow.createNode({
|
||||||
|
type: 'aggregate',
|
||||||
|
config: {
|
||||||
|
aggregator: 'sum',
|
||||||
|
collection: 'posts',
|
||||||
|
params: {
|
||||||
|
field: 'score',
|
||||||
|
},
|
||||||
|
precision: 15,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const p1 = await PostRepo.create({ values: { title: 't1', score: 0.100000000000001 } });
|
||||||
|
|
||||||
const [e1] = await workflow.getExecutions();
|
const [e1] = await workflow.getExecutions();
|
||||||
const [j1] = await e1.getJobs();
|
const [j1] = await e1.getJobs();
|
||||||
@ -173,8 +212,6 @@ describe('workflow > instructions > aggregate', () => {
|
|||||||
|
|
||||||
const p2 = await PostRepo.create({ values: { title: 't2', score: 0.200000000000001 } });
|
const p2 = await PostRepo.create({ values: { title: 't2', score: 0.200000000000001 } });
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const [e2] = await workflow.getExecutions({ order: [['id', 'desc']] });
|
const [e2] = await workflow.getExecutions({ order: [['id', 'desc']] });
|
||||||
const [j2] = await e2.getJobs();
|
const [j2] = await e2.getJobs();
|
||||||
expect(j2.result).toBe(0.3);
|
expect(j2.result).toBe(0.3);
|
||||||
@ -194,8 +231,6 @@ describe('workflow > instructions > aggregate', () => {
|
|||||||
|
|
||||||
const p2 = await PostRepo.create({ values: { title: 't2' } });
|
const p2 = await PostRepo.create({ values: { title: 't2' } });
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const [e1] = await workflow.getExecutions();
|
const [e1] = await workflow.getExecutions();
|
||||||
const [j1] = await e1.getJobs();
|
const [j1] = await e1.getJobs();
|
||||||
expect(j1.result).toBe(0);
|
expect(j1.result).toBe(0);
|
||||||
@ -215,16 +250,12 @@ describe('workflow > instructions > aggregate', () => {
|
|||||||
|
|
||||||
const p1 = await PostRepo.create({ values: { title: 't1', read: 1 } });
|
const p1 = await PostRepo.create({ values: { title: 't1', read: 1 } });
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const [e1] = await workflow.getExecutions();
|
const [e1] = await workflow.getExecutions();
|
||||||
const [j1] = await e1.getJobs();
|
const [j1] = await e1.getJobs();
|
||||||
expect(j1.result).toBe(1);
|
expect(j1.result).toBe(1);
|
||||||
|
|
||||||
const p2 = await PostRepo.create({ values: { title: 't2', read: 2 } });
|
const p2 = await PostRepo.create({ values: { title: 't2', read: 2 } });
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const [e2] = await workflow.getExecutions({ order: [['id', 'desc']] });
|
const [e2] = await workflow.getExecutions({ order: [['id', 'desc']] });
|
||||||
const [j2] = await e2.getJobs();
|
const [j2] = await e2.getJobs();
|
||||||
expect(j2.result).toBe(1.5);
|
expect(j2.result).toBe(1.5);
|
||||||
@ -244,16 +275,12 @@ describe('workflow > instructions > aggregate', () => {
|
|||||||
|
|
||||||
const p1 = await PostRepo.create({ values: { title: 't1', read: 1 } });
|
const p1 = await PostRepo.create({ values: { title: 't1', read: 1 } });
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const [e1] = await workflow.getExecutions();
|
const [e1] = await workflow.getExecutions();
|
||||||
const [j1] = await e1.getJobs();
|
const [j1] = await e1.getJobs();
|
||||||
expect(j1.result).toBe(1);
|
expect(j1.result).toBe(1);
|
||||||
|
|
||||||
const p2 = await PostRepo.create({ values: { title: 't2', read: 2 } });
|
const p2 = await PostRepo.create({ values: { title: 't2', read: 2 } });
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const [e2] = await workflow.getExecutions({ order: [['id', 'desc']] });
|
const [e2] = await workflow.getExecutions({ order: [['id', 'desc']] });
|
||||||
const [j2] = await e2.getJobs();
|
const [j2] = await e2.getJobs();
|
||||||
expect(j2.result).toBe(1);
|
expect(j2.result).toBe(1);
|
||||||
@ -273,16 +300,12 @@ describe('workflow > instructions > aggregate', () => {
|
|||||||
|
|
||||||
const p1 = await PostRepo.create({ values: { title: 't1', read: 1 } });
|
const p1 = await PostRepo.create({ values: { title: 't1', read: 1 } });
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const [e1] = await workflow.getExecutions();
|
const [e1] = await workflow.getExecutions();
|
||||||
const [j1] = await e1.getJobs();
|
const [j1] = await e1.getJobs();
|
||||||
expect(j1.result).toBe(1);
|
expect(j1.result).toBe(1);
|
||||||
|
|
||||||
const p2 = await PostRepo.create({ values: { title: 't2', read: 2 } });
|
const p2 = await PostRepo.create({ values: { title: 't2', read: 2 } });
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const [e2] = await workflow.getExecutions({ order: [['id', 'desc']] });
|
const [e2] = await workflow.getExecutions({ order: [['id', 'desc']] });
|
||||||
const [j2] = await e2.getJobs();
|
const [j2] = await e2.getJobs();
|
||||||
expect(j2.result).toBe(2);
|
expect(j2.result).toBe(2);
|
||||||
@ -333,8 +356,6 @@ describe('workflow > instructions > aggregate', () => {
|
|||||||
|
|
||||||
const p1 = await PostRepo.create({ values: { title: 't1', comments: [{}, { status: 1 }] } });
|
const p1 = await PostRepo.create({ values: { title: 't1', comments: [{}, { status: 1 }] } });
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const [e1] = await workflow.getExecutions();
|
const [e1] = await workflow.getExecutions();
|
||||||
const [j1, j2] = await e1.getJobs({ order: [['id', 'ASC']] });
|
const [j1, j2] = await e1.getJobs({ order: [['id', 'ASC']] });
|
||||||
expect(j1.result).toBe(2);
|
expect(j1.result).toBe(2);
|
||||||
@ -343,7 +364,7 @@ describe('workflow > instructions > aggregate', () => {
|
|||||||
|
|
||||||
it('sum', async () => {
|
it('sum', async () => {
|
||||||
const PostModel = db.getCollection('posts').model;
|
const PostModel = db.getCollection('posts').model;
|
||||||
const p1 = await PostModel.create({ title: 't1', read: 1 });
|
const p1 = await PostModel.create({ title: 't1', read: 1 }, { hooks: false });
|
||||||
|
|
||||||
const n1 = await workflow.createNode({
|
const n1 = await workflow.createNode({
|
||||||
type: 'create',
|
type: 'create',
|
||||||
@ -400,8 +421,6 @@ describe('workflow > instructions > aggregate', () => {
|
|||||||
|
|
||||||
const p2 = await PostRepo.create({ values: { title: 't2', read: 2 } });
|
const p2 = await PostRepo.create({ values: { title: 't2', read: 2 } });
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const [e1] = await workflow.getExecutions();
|
const [e1] = await workflow.getExecutions();
|
||||||
const [j1, j2, j3] = await e1.getJobs({ order: [['id', 'ASC']] });
|
const [j1, j2, j3] = await e1.getJobs({ order: [['id', 'ASC']] });
|
||||||
expect(j2.result).toBe(3);
|
expect(j2.result).toBe(3);
|
||||||
@ -429,8 +448,6 @@ describe('workflow > instructions > aggregate', () => {
|
|||||||
|
|
||||||
await PostRepo.create({ values: { title: 't1' } });
|
await PostRepo.create({ values: { title: 't1' } });
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const [execution] = await workflow.getExecutions();
|
const [execution] = await workflow.getExecutions();
|
||||||
expect(execution.status).toBe(EXECUTION_STATUS.RESOLVED);
|
expect(execution.status).toBe(EXECUTION_STATUS.RESOLVED);
|
||||||
const [job] = await execution.getJobs();
|
const [job] = await execution.getJobs();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user