2022-01-09 14:22:26 +00:00
|
|
|
// config: {
|
|
|
|
// not: false,
|
|
|
|
// group: {
|
|
|
|
// type: 'and',
|
|
|
|
// calculations: [
|
|
|
|
// {
|
|
|
|
// calculator: 'time.equal',
|
|
|
|
// operands: [{ type: 'context', options: { path: 'time' } }, { type: 'fn', options: { name: 'newDate', args: [] } }]
|
|
|
|
// },
|
|
|
|
// {
|
|
|
|
// calculator: 'value.equal',
|
|
|
|
// operands: [{ type: 'job.result', options: { id: 213, path: '' } }, { type: 'constant', value: { a: 1 } }]
|
|
|
|
// }
|
|
|
|
// ]
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
2022-01-25 18:27:23 +00:00
|
|
|
import Sequelize = require('sequelize');
|
|
|
|
import { getValue, Operand } from "../utils/getter";
|
|
|
|
import { getCalculator } from "../utils/calculators";
|
|
|
|
import { JOB_STATUS } from "../constants";
|
2022-01-09 14:22:26 +00:00
|
|
|
|
|
|
|
type BaseCalculation = {
|
|
|
|
not?: boolean;
|
|
|
|
};
|
|
|
|
|
|
|
|
type SingleCalculation = BaseCalculation & {
|
|
|
|
calculation: string;
|
|
|
|
operands?: Operand[];
|
|
|
|
};
|
|
|
|
|
|
|
|
type GroupCalculationOptions = {
|
|
|
|
type: 'and' | 'or';
|
|
|
|
calculations: Calculation[]
|
|
|
|
};
|
|
|
|
|
|
|
|
type GroupCalculation = BaseCalculation & {
|
|
|
|
group: GroupCalculationOptions
|
|
|
|
};
|
|
|
|
|
|
|
|
// TODO(type)
|
|
|
|
type Calculation = SingleCalculation | GroupCalculation;
|
|
|
|
|
|
|
|
function calculate(config, input, execution) {
|
|
|
|
if (!config) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
const { not, group } = config;
|
|
|
|
let result;
|
|
|
|
if (group) {
|
|
|
|
const method = group.type === 'and' ? 'every' : 'some';
|
|
|
|
result = group.calculations[method](calculation => calculate(calculation, input, execution));
|
|
|
|
} else {
|
|
|
|
const args = config.operands.map(operand => getValue(operand, input, execution));
|
|
|
|
const fn = getCalculator(config.calculator);
|
|
|
|
if (!fn) {
|
|
|
|
throw new Error(`no calculator function registered for "${config.calculator}"`);
|
|
|
|
}
|
|
|
|
result = fn(...args);
|
|
|
|
}
|
|
|
|
|
|
|
|
return not ? !result : result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export default {
|
2022-01-25 18:27:23 +00:00
|
|
|
async run(this, prevJob, execution) {
|
2022-01-09 14:22:26 +00:00
|
|
|
// TODO(optimize): loading of jobs could be reduced and turned into incrementally in execution
|
2022-01-25 18:27:23 +00:00
|
|
|
// const jobs = await execution.getJobs();
|
|
|
|
const { calculation } = this.config || {};
|
|
|
|
const result = calculate(calculation, prevJob, execution);
|
|
|
|
|
|
|
|
if (!result && this.config.rejectOnFalse) {
|
|
|
|
return {
|
|
|
|
status: JOB_STATUS.REJECTED,
|
|
|
|
result
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
const job = {
|
|
|
|
status: JOB_STATUS.RESOLVED,
|
|
|
|
result,
|
|
|
|
// TODO(optimize): try unify the building of job
|
2022-01-27 16:25:26 +00:00
|
|
|
nodeId: this.id,
|
|
|
|
upstreamId: prevJob instanceof Sequelize.Model ? prevJob.get('id') : null
|
2022-01-25 18:27:23 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const branchNode = execution.nodes
|
2022-01-27 16:25:26 +00:00
|
|
|
.find(item => item.upstream === this && Boolean(item.branchIndex) === result);
|
2022-01-25 18:27:23 +00:00
|
|
|
|
|
|
|
if (!branchNode) {
|
|
|
|
return job;
|
|
|
|
}
|
|
|
|
|
|
|
|
const savedJob = await execution.saveJob(job);
|
|
|
|
|
2022-02-01 04:04:08 +00:00
|
|
|
return execution.exec(branchNode, savedJob);
|
2022-01-25 18:27:23 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
async resume(this, branchJob, execution) {
|
|
|
|
if (branchJob.status === JOB_STATUS.RESOLVED) {
|
2022-02-01 04:04:08 +00:00
|
|
|
// return to continue this.downstream
|
|
|
|
return branchJob;
|
2022-01-25 18:27:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// pass control to upper scope by ending current scope
|
|
|
|
return execution.end(this, branchJob);
|
2022-01-09 14:22:26 +00:00
|
|
|
}
|
|
|
|
}
|