fix(plugin-workflow): test changedWithAssociations() (#950)

* fix(plugin-workflow): test changedWithAssociations()

* fix: toChangedWithAssociations

* fix(plugin-workflow): add test cases

Co-authored-by: chenos <chenlinxh@gmail.com>
# Conflicts:
#	packages/core/database/src/model.ts
This commit is contained in:
Junyi 2022-10-23 18:17:59 +08:00 committed by chenos
parent 9ba1d128f4
commit a8cf72281f
4 changed files with 112 additions and 6 deletions

View File

@ -24,6 +24,38 @@ export class Model<TModelAttributes extends {} = any, TCreationAttributes extend
public static collection: Collection; public static collection: Collection;
[key: string]: any; [key: string]: any;
protected _changedWithAssociations = new Set();
protected _previousDataValuesWithAssociations = {};
// TODO
public toChangedWithAssociations() {
// @ts-ignore
this._changedWithAssociations = new Set([...this._changedWithAssociations, ...this._changed]);
// @ts-ignore
this._previousDataValuesWithAssociations = this._previousDataValues;
}
public changedWithAssociations(key?: string, value?: any) {
if (key === undefined) {
if (this._changedWithAssociations.size > 0) {
return Array.from(this._changedWithAssociations);
}
return false;
}
if (value === true) {
this._changedWithAssociations.add(key);
return this;
}
if (value === false) {
this._changedWithAssociations.delete(key);
return this;
}
return this._changedWithAssociations.has(key);
}
public clearChangedWithAssociations() {
this._changedWithAssociations = new Set();
}
public toJSON<T extends TModelAttributes>(): T { public toJSON<T extends TModelAttributes>(): T {
const handleObj = (obj, options: JSONTransformerOptions) => { const handleObj = (obj, options: JSONTransformerOptions) => {

View File

@ -33,6 +33,7 @@ const FieldsSelect = observer((props) => {
.filter(field => ( .filter(field => (
!field.hidden !field.hidden
&& (field.uiSchema ? !field.uiSchema['x-read-pretty'] : true) && (field.uiSchema ? !field.uiSchema['x-read-pretty'] : true)
&& !['linkTo', 'hasOne', 'hasMany', 'belongsToMany'].includes(field.type)
)) ))
.map(field => ( .map(field => (
<Select.Option key={field.name} value={field.name}>{compile(field.uiSchema?.title)}</Select.Option> <Select.Option key={field.name} value={field.name}>{compile(field.uiSchema?.title)}</Select.Option>

View File

@ -45,4 +45,62 @@ describe('workflow > triggers > collection', () => {
expect(executions.length).toBe(0); expect(executions.length).toBe(0);
}); });
}); });
describe('config.changed', () => {
it('no changed config', async () => {
const workflow = await WorkflowModel.create({
enabled: true,
type: 'collection',
config: {
mode: 2,
collection: 'posts'
}
});
const post = await PostRepo.create({ values: { title: 't1' } });
await PostRepo.update({ filterByTk: post.id, values: { title: 't2' } });
const executions = await workflow.getExecutions();
expect(executions.length).toBe(1);
expect(executions[0].context.data.title).toBe('t2');
});
it('field in changed config', async () => {
const workflow = await WorkflowModel.create({
enabled: true,
type: 'collection',
config: {
mode: 2,
collection: 'posts',
changed: ['title']
}
});
const post = await PostRepo.create({ values: { title: 't1' } });
await PostRepo.update({ filterByTk: post.id, values: { title: 't2' } });
const executions = await workflow.getExecutions();
expect(executions.length).toBe(1);
expect(executions[0].status).toBe(EXECUTION_STATUS.RESOLVED);
expect(executions[0].context.data.title).toBe('t2');
});
it('field not in changed config', async () => {
const workflow = await WorkflowModel.create({
enabled: true,
type: 'collection',
config: {
mode: 2,
collection: 'posts',
changed: ['published']
}
});
const post = await PostRepo.create({ values: { title: 't1' } });
await PostRepo.update({ filterByTk: post.id, values: { title: 't2' } });
const executions = await workflow.getExecutions();
expect(executions.length).toBe(0);
});
});
}); });

View File

@ -1,5 +1,5 @@
import { Model } from "@nocobase/database"; import { Collection, Model } from "@nocobase/database";
import Plugin, { Trigger } from ".."; import { Trigger } from "..";
import WorkflowModel from "../models/Workflow"; import WorkflowModel from "../models/Workflow";
export interface CollectionChangeTriggerConfig { export interface CollectionChangeTriggerConfig {
@ -26,19 +26,34 @@ function getHookId(workflow, type) {
return `${type}#${workflow.id}`; return `${type}#${workflow.id}`;
} }
function getFieldRawName(collection: Collection, name: string) {
const field = collection.getField(name);
if (field && field.type === 'belongsTo') {
return field.foreignKey;
}
return name;
}
// async function, should return promise // async function, should return promise
async function handler(this: CollectionTrigger, workflow: WorkflowModel, data: Model, options) { async function handler(this: CollectionTrigger, workflow: WorkflowModel, data: Model, options) {
const { collection, condition, changed } = workflow.config; const { collection: collectionName, condition, changed } = workflow.config;
const collection = (<typeof Model>data.constructor).database.getCollection(collectionName);
// NOTE: if no configured fields changed, do not trigger // NOTE: if no configured fields changed, do not trigger
if (changed && changed.length && changed.every(name => !data.changed(name))) { if (changed
&& changed.length
&& changed
.filter(name => !['linkTo', 'hasOne', 'hasMany', 'belongsToMany'].includes(collection.getField(name).type))
.every(name => !data.changedWithAssociations(getFieldRawName(collection, name)))
) {
// TODO: temp comment out // TODO: temp comment out
// return; return;
} }
// NOTE: if no configured condition match, do not trigger // NOTE: if no configured condition match, do not trigger
if (condition && condition.$and?.length) { if (condition && condition.$and?.length) {
// TODO: change to map filter format to calculation format // TODO: change to map filter format to calculation format
// const calculation = toCalculation(condition); // const calculation = toCalculation(condition);
const { repository, model } = (<typeof Model>data.constructor).database.getCollection(collection); const { repository, model } = collection;
const { transaction, context } = options; const { transaction, context } = options;
const count = await repository.count({ const count = await repository.count({
filter: { filter: {