@nocobase/plugin-workflow-aggregate 0.17.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +9 -0
- package/README.zh-CN.md +9 -0
- package/client.d.ts +2 -0
- package/client.js +1 -0
- package/dist/client/AggregateInstruction.d.ts +212 -0
- package/dist/client/index.d.ts +6 -0
- package/dist/client/index.js +4 -0
- package/dist/externalVersion.js +10 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +39 -0
- package/dist/locale/en-US.json +12 -0
- package/dist/locale/index.d.ts +3 -0
- package/dist/locale/index.js +39 -0
- package/dist/locale/zh-CN.json +12 -0
- package/dist/server/AggregateInstruction.d.ts +7 -0
- package/dist/server/AggregateInstruction.js +54 -0
- package/dist/server/Plugin.d.ts +6 -0
- package/dist/server/Plugin.js +42 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +33 -0
- package/package.json +24 -0
- package/server.d.ts +2 -0
- package/server.js +1 -0
- package/src/client/AggregateInstruction.tsx +399 -0
- package/src/client/index.ts +19 -0
- package/src/index.ts +2 -0
- package/src/locale/en-US.json +12 -0
- package/src/locale/index.ts +12 -0
- package/src/locale/zh-CN.json +12 -0
- package/src/server/AggregateInstruction.ts +39 -0
- package/src/server/Plugin.ts +14 -0
- package/src/server/__tests__/instruction.test.ts +298 -0
- package/src/server/index.ts +1 -0
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
import Database from '@nocobase/database';
|
|
2
|
+
import { Application } from '@nocobase/server';
|
|
3
|
+
import { getApp, sleep } from '@nocobase/plugin-workflow-test';
|
|
4
|
+
|
|
5
|
+
import Plugin from '..';
|
|
6
|
+
|
|
7
|
+
describe('workflow > instructions > aggregate', () => {
|
|
8
|
+
let app: Application;
|
|
9
|
+
let db: Database;
|
|
10
|
+
let PostRepo;
|
|
11
|
+
let CommentRepo;
|
|
12
|
+
let TagRepo;
|
|
13
|
+
let WorkflowModel;
|
|
14
|
+
let workflow;
|
|
15
|
+
|
|
16
|
+
beforeEach(async () => {
|
|
17
|
+
app = await getApp({
|
|
18
|
+
plugins: [Plugin],
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
db = app.db;
|
|
22
|
+
WorkflowModel = db.getCollection('workflows').model;
|
|
23
|
+
WorkflowModel = db.getCollection('workflows').model;
|
|
24
|
+
PostRepo = db.getCollection('posts').repository;
|
|
25
|
+
CommentRepo = db.getCollection('comments').repository;
|
|
26
|
+
TagRepo = db.getCollection('tags').repository;
|
|
27
|
+
|
|
28
|
+
workflow = await WorkflowModel.create({
|
|
29
|
+
enabled: true,
|
|
30
|
+
type: 'collection',
|
|
31
|
+
config: {
|
|
32
|
+
mode: 1,
|
|
33
|
+
collection: 'posts',
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
afterEach(() => app.destroy());
|
|
39
|
+
|
|
40
|
+
describe('based on collection', () => {
|
|
41
|
+
it('count', async () => {
|
|
42
|
+
const n1 = await workflow.createNode({
|
|
43
|
+
type: 'aggregate',
|
|
44
|
+
config: {
|
|
45
|
+
aggregator: 'count',
|
|
46
|
+
collection: 'posts',
|
|
47
|
+
params: {
|
|
48
|
+
field: 'id',
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const post = await PostRepo.create({ values: { title: 't1' } });
|
|
54
|
+
|
|
55
|
+
await sleep(500);
|
|
56
|
+
|
|
57
|
+
const [execution] = await workflow.getExecutions();
|
|
58
|
+
const [job] = await execution.getJobs();
|
|
59
|
+
expect(job.result).toBe(1);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('sum', async () => {
|
|
63
|
+
const n1 = await workflow.createNode({
|
|
64
|
+
type: 'aggregate',
|
|
65
|
+
config: {
|
|
66
|
+
aggregator: 'sum',
|
|
67
|
+
collection: 'posts',
|
|
68
|
+
params: {
|
|
69
|
+
field: 'read',
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const p1 = await PostRepo.create({ values: { title: 't1', read: 1 } });
|
|
75
|
+
|
|
76
|
+
await sleep(500);
|
|
77
|
+
|
|
78
|
+
const [e1] = await workflow.getExecutions();
|
|
79
|
+
const [j1] = await e1.getJobs();
|
|
80
|
+
expect(j1.result).toBe(1);
|
|
81
|
+
|
|
82
|
+
const p2 = await PostRepo.create({ values: { title: 't2', read: 2 } });
|
|
83
|
+
|
|
84
|
+
await sleep(500);
|
|
85
|
+
|
|
86
|
+
const [e2] = await workflow.getExecutions({ order: [['id', 'desc']] });
|
|
87
|
+
const [j2] = await e2.getJobs();
|
|
88
|
+
expect(j2.result).toBe(3);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('avg', async () => {
|
|
92
|
+
const n1 = await workflow.createNode({
|
|
93
|
+
type: 'aggregate',
|
|
94
|
+
config: {
|
|
95
|
+
aggregator: 'avg',
|
|
96
|
+
collection: 'posts',
|
|
97
|
+
params: {
|
|
98
|
+
field: 'read',
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
const p1 = await PostRepo.create({ values: { title: 't1', read: 1 } });
|
|
104
|
+
|
|
105
|
+
await sleep(500);
|
|
106
|
+
|
|
107
|
+
const [e1] = await workflow.getExecutions();
|
|
108
|
+
const [j1] = await e1.getJobs();
|
|
109
|
+
expect(j1.result).toBe(1);
|
|
110
|
+
|
|
111
|
+
const p2 = await PostRepo.create({ values: { title: 't2', read: 2 } });
|
|
112
|
+
|
|
113
|
+
await sleep(500);
|
|
114
|
+
|
|
115
|
+
const [e2] = await workflow.getExecutions({ order: [['id', 'desc']] });
|
|
116
|
+
const [j2] = await e2.getJobs();
|
|
117
|
+
expect(j2.result).toBe(1.5);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('min', async () => {
|
|
121
|
+
const n1 = await workflow.createNode({
|
|
122
|
+
type: 'aggregate',
|
|
123
|
+
config: {
|
|
124
|
+
aggregator: 'min',
|
|
125
|
+
collection: 'posts',
|
|
126
|
+
params: {
|
|
127
|
+
field: 'read',
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
const p1 = await PostRepo.create({ values: { title: 't1', read: 1 } });
|
|
133
|
+
|
|
134
|
+
await sleep(500);
|
|
135
|
+
|
|
136
|
+
const [e1] = await workflow.getExecutions();
|
|
137
|
+
const [j1] = await e1.getJobs();
|
|
138
|
+
expect(j1.result).toBe(1);
|
|
139
|
+
|
|
140
|
+
const p2 = await PostRepo.create({ values: { title: 't2', read: 2 } });
|
|
141
|
+
|
|
142
|
+
await sleep(500);
|
|
143
|
+
|
|
144
|
+
const [e2] = await workflow.getExecutions({ order: [['id', 'desc']] });
|
|
145
|
+
const [j2] = await e2.getJobs();
|
|
146
|
+
expect(j2.result).toBe(1);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('max', async () => {
|
|
150
|
+
const n1 = await workflow.createNode({
|
|
151
|
+
type: 'aggregate',
|
|
152
|
+
config: {
|
|
153
|
+
aggregator: 'max',
|
|
154
|
+
collection: 'posts',
|
|
155
|
+
params: {
|
|
156
|
+
field: 'read',
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
const p1 = await PostRepo.create({ values: { title: 't1', read: 1 } });
|
|
162
|
+
|
|
163
|
+
await sleep(500);
|
|
164
|
+
|
|
165
|
+
const [e1] = await workflow.getExecutions();
|
|
166
|
+
const [j1] = await e1.getJobs();
|
|
167
|
+
expect(j1.result).toBe(1);
|
|
168
|
+
|
|
169
|
+
const p2 = await PostRepo.create({ values: { title: 't2', read: 2 } });
|
|
170
|
+
|
|
171
|
+
await sleep(500);
|
|
172
|
+
|
|
173
|
+
const [e2] = await workflow.getExecutions({ order: [['id', 'desc']] });
|
|
174
|
+
const [j2] = await e2.getJobs();
|
|
175
|
+
expect(j2.result).toBe(2);
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
describe('based on data associated collection', () => {
|
|
180
|
+
it('count', async () => {
|
|
181
|
+
const n1 = await workflow.createNode({
|
|
182
|
+
type: 'aggregate',
|
|
183
|
+
config: {
|
|
184
|
+
aggregator: 'count',
|
|
185
|
+
collection: 'comments',
|
|
186
|
+
associated: true,
|
|
187
|
+
association: {
|
|
188
|
+
name: 'comments',
|
|
189
|
+
associatedKey: '{{$context.data.id}}',
|
|
190
|
+
associatedCollection: 'posts',
|
|
191
|
+
},
|
|
192
|
+
params: {
|
|
193
|
+
field: 'id',
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
const n2 = await workflow.createNode({
|
|
198
|
+
upstreamId: n1.id,
|
|
199
|
+
type: 'aggregate',
|
|
200
|
+
config: {
|
|
201
|
+
aggregator: 'count',
|
|
202
|
+
collection: 'comments',
|
|
203
|
+
associated: true,
|
|
204
|
+
association: {
|
|
205
|
+
name: 'comments',
|
|
206
|
+
associatedKey: '{{$context.data.id}}',
|
|
207
|
+
associatedCollection: 'posts',
|
|
208
|
+
},
|
|
209
|
+
params: {
|
|
210
|
+
field: 'id',
|
|
211
|
+
filter: {
|
|
212
|
+
$and: [{ status: 1 }],
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
});
|
|
217
|
+
await n1.setDownstream(n2);
|
|
218
|
+
|
|
219
|
+
await CommentRepo.create({ values: [{}, {}] });
|
|
220
|
+
|
|
221
|
+
const p1 = await PostRepo.create({ values: { title: 't1', comments: [{}, { status: 1 }] } });
|
|
222
|
+
|
|
223
|
+
await sleep(500);
|
|
224
|
+
|
|
225
|
+
const [e1] = await workflow.getExecutions();
|
|
226
|
+
const [j1, j2] = await e1.getJobs({ order: [['id', 'ASC']] });
|
|
227
|
+
expect(j1.result).toBe(2);
|
|
228
|
+
expect(j2.result).toBe(1);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it('sum', async () => {
|
|
232
|
+
const PostModel = db.getCollection('posts').model;
|
|
233
|
+
const p1 = await PostModel.create({ title: 't1', read: 1 });
|
|
234
|
+
|
|
235
|
+
const n1 = await workflow.createNode({
|
|
236
|
+
type: 'create',
|
|
237
|
+
config: {
|
|
238
|
+
collection: 'tags',
|
|
239
|
+
params: {
|
|
240
|
+
values: {
|
|
241
|
+
posts: [p1.id, '{{$context.data.id}}'],
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
});
|
|
246
|
+
const n2 = await workflow.createNode({
|
|
247
|
+
upstreamId: n1.id,
|
|
248
|
+
type: 'aggregate',
|
|
249
|
+
config: {
|
|
250
|
+
aggregator: 'sum',
|
|
251
|
+
collection: 'posts',
|
|
252
|
+
associated: true,
|
|
253
|
+
association: {
|
|
254
|
+
name: 'posts',
|
|
255
|
+
associatedKey: `{{$jobsMapByNodeKey.${n1.key}.id}}`,
|
|
256
|
+
associatedCollection: 'tags',
|
|
257
|
+
},
|
|
258
|
+
params: {
|
|
259
|
+
field: 'read',
|
|
260
|
+
},
|
|
261
|
+
},
|
|
262
|
+
});
|
|
263
|
+
await n1.setDownstream(n2);
|
|
264
|
+
const n3 = await workflow.createNode({
|
|
265
|
+
upstreamId: n2.id,
|
|
266
|
+
type: 'aggregate',
|
|
267
|
+
config: {
|
|
268
|
+
aggregator: 'sum',
|
|
269
|
+
collection: 'posts',
|
|
270
|
+
associated: true,
|
|
271
|
+
association: {
|
|
272
|
+
name: 'posts',
|
|
273
|
+
associatedKey: `{{$jobsMapByNodeKey.${n1.key}.id}}`,
|
|
274
|
+
associatedCollection: 'tags',
|
|
275
|
+
},
|
|
276
|
+
params: {
|
|
277
|
+
field: 'read',
|
|
278
|
+
filter: {
|
|
279
|
+
$and: [{ title: 't1' }],
|
|
280
|
+
},
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
});
|
|
284
|
+
await n2.setDownstream(n3);
|
|
285
|
+
|
|
286
|
+
await TagRepo.create({ values: [{}, {}] });
|
|
287
|
+
|
|
288
|
+
const p2 = await PostRepo.create({ values: { title: 't2', read: 2 } });
|
|
289
|
+
|
|
290
|
+
await sleep(500);
|
|
291
|
+
|
|
292
|
+
const [e1] = await workflow.getExecutions();
|
|
293
|
+
const [j1, j2, j3] = await e1.getJobs({ order: [['id', 'ASC']] });
|
|
294
|
+
expect(j2.result).toBe(3);
|
|
295
|
+
expect(j3.result).toBe(1);
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './Plugin';
|