* create-nocobase-app template from [develop] * change create-nocobase-app package.json config * feat: load configuration from directory * feat: configuration repository toObject * feat: create application from configuration dir * feat: application factory with plugins options * export type * feat: read application config & application with plugins options * feat: release command * fix: database release * chore: workflow package.json * feat: nocobase cli package * feat: console command * chore: load application in command * fix: load packages from process.cwd * feat: cli load env file * feat: create-nocobase-app * fix: gitignore create-nocobase-app lib * fix: sqlite path * feat: create plugin * chore: plugin files template * chore: move cli into application * chore: create-nocobase-app * fix: create plugin * chore: app-client && app-server * chore: package.json * feat: create-nocobase-app download template from npm * chore: create-nocobase-app template * fix: config of plugin-users * fix: yarn.lock * fix: database build error * fix: yarn.lock * fix: resourcer config * chore: cross-env * chore: app-client dependents * fix: env * chore: v0.6.0-alpha.1 * chore: verdaccio * chore(versions): 😊 publish v0.6.0 * chore(versions): 😊 publish v0.6.1-alpha.0 * chore(versions): 😊 publish v0.6.2-alpha.0 * chore(versions): 😊 publish v0.6.2-alpha.1 * chore: 0.6.2-alpha.2 * feat: workspaces * chore(versions): 😊 publish v0.6.2-alpha.3 * chore(versions): 😊 publish v0.6.2-alpha.4 * chore: create-nocobase-app * chore: create-nocobase-app lib * fix: update tsconfig.jest.json * chore: .env * chore(versions): 😊 publish v0.6.2-alpha.5 * chore(versions): 😊 publish v0.6.2-alpha.6 * feat: improve code * chore(versions): 😊 publish v0.6.2-alpha.7 * fix: cleanup * chore(versions): 😊 publish v0.6.2-alpha.8 * chore: tsconfig for app server package * fix: move files * fix: move files Co-authored-by: chenos <chenlinxh@gmail.com>
213 lines
4.7 KiB
TypeScript
213 lines
4.7 KiB
TypeScript
import { get as getWithPath } from 'lodash';
|
|
import { Registry } from "@nocobase/utils";
|
|
|
|
import ExecutionModel from '../models/Execution';
|
|
import JobModel from '../models/Job';
|
|
|
|
export const calculators = new Registry<Function>();
|
|
|
|
export default calculators;
|
|
|
|
|
|
export type OperandType = '$context' | '$input' | '$jobsMapByNodeId' | '$calculation';
|
|
|
|
export type ObjectGetterOptions = {
|
|
path?: string
|
|
};
|
|
|
|
export type JobGetterOptions = ObjectGetterOptions & {
|
|
nodeId: number
|
|
};
|
|
|
|
export type CalculationOptions = {
|
|
calculator: string,
|
|
operands: Operand[]
|
|
};
|
|
|
|
export type ConstantOperand = {
|
|
type?: 'constant';
|
|
value: any
|
|
};
|
|
|
|
export type ContextOperand = {
|
|
type: '$context';
|
|
options: ObjectGetterOptions;
|
|
};
|
|
|
|
export type InputOperand = {
|
|
type: '$input';
|
|
options: ObjectGetterOptions;
|
|
};
|
|
|
|
export type JobOperand = {
|
|
type: '$jobsMapByNodeId';
|
|
options: JobGetterOptions;
|
|
};
|
|
|
|
export type Calculation = {
|
|
type: '$calculation';
|
|
options: CalculationOptions
|
|
};
|
|
|
|
// TODO(type): union type here is wrong
|
|
export type Operand = ContextOperand | InputOperand | JobOperand | ConstantOperand | Calculation;
|
|
|
|
// @deprecated
|
|
// HACK: if no path provided, return self
|
|
// @see https://github.com/lodash/lodash/pull/1270
|
|
// TODO(question): should add default value as lodash?
|
|
function get(object, path?: string | Array<string>) {
|
|
return path == null || !path.length ? object : getWithPath(object, path);
|
|
}
|
|
|
|
// NOTE:
|
|
// this method could only be used in executing nodes.
|
|
// because type of 'job' need loaded jobs in runtime execution.
|
|
// or the execution should be prepared first.
|
|
export function calculate(operand: Operand, lastJob: JobModel, execution: ExecutionModel) {
|
|
switch (operand.type) {
|
|
// @Deprecated
|
|
// from execution context
|
|
case '$context':
|
|
return get(execution.context, operand.options.path);
|
|
|
|
// @Deprecated
|
|
// from last job (or input job)
|
|
case '$input':
|
|
return lastJob ?? get(lastJob.result, operand.options.path);
|
|
|
|
// @Deprecated
|
|
// from job in execution
|
|
case '$jobsMapByNodeId':
|
|
// assume jobs have been fetched from execution before
|
|
const job = execution.jobsMapByNodeId[operand.options.nodeId];
|
|
return job && get(job, operand.options.path);
|
|
|
|
case '$calculation':
|
|
const fn = calculators.get(operand.options.calculator);
|
|
if (!fn) {
|
|
throw new Error(`no calculator function registered for "${operand.options.calculator}"`);
|
|
}
|
|
return fn(...operand.options.operands.map(item => calculate(item, lastJob, execution)));
|
|
|
|
// constant
|
|
default:
|
|
return operand.value;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// built-in functions
|
|
|
|
function equal(a, b) {
|
|
return a === b;
|
|
}
|
|
|
|
function notEqual(a, b) {
|
|
return a !== b;
|
|
}
|
|
|
|
function gt(a, b) {
|
|
return a > b;
|
|
}
|
|
|
|
function gte(a, b) {
|
|
return a >= b;
|
|
}
|
|
|
|
function lt(a, b) {
|
|
return a < b;
|
|
}
|
|
|
|
function lte(a, b) {
|
|
return a <= b;
|
|
}
|
|
|
|
calculators.register('equal', equal);
|
|
calculators.register('notEqual', notEqual);
|
|
calculators.register('gt', gt);
|
|
calculators.register('gte', gte);
|
|
calculators.register('lt', lt);
|
|
calculators.register('lte', lte);
|
|
|
|
calculators.register('===', equal);
|
|
calculators.register('!==', notEqual);
|
|
calculators.register('>', gt);
|
|
calculators.register('>=', gte);
|
|
calculators.register('<', lt);
|
|
calculators.register('<=', lte);
|
|
|
|
|
|
|
|
function add(...args) {
|
|
return args.reduce((sum, a) => sum + a, 0);
|
|
}
|
|
|
|
function minus(a, b) {
|
|
return a - b;
|
|
}
|
|
|
|
function multipe(...args) {
|
|
return args.reduce((result, a) => result * a, 1);
|
|
}
|
|
|
|
function divide(a, b) {
|
|
return a / b;
|
|
}
|
|
|
|
function mod(a, b) {
|
|
return a % b;
|
|
}
|
|
|
|
calculators.register('add', add);
|
|
calculators.register('minus', minus);
|
|
calculators.register('multipe', multipe);
|
|
calculators.register('divide', divide);
|
|
calculators.register('mod', mod);
|
|
|
|
calculators.register('+', add);
|
|
calculators.register('-', minus);
|
|
calculators.register('*', multipe);
|
|
calculators.register('/', divide);
|
|
calculators.register('%', mod);
|
|
|
|
function includes(a, b) {
|
|
return a.includes(b);
|
|
}
|
|
|
|
function notIncludes(a, b) {
|
|
return !a.includes(b);
|
|
}
|
|
|
|
function startsWith(a: string, b: string) {
|
|
return a.startsWith(b);
|
|
}
|
|
|
|
function notStartsWith(a: string, b: string) {
|
|
return !a.startsWith(b);
|
|
}
|
|
|
|
function endsWith(a: string, b: string) {
|
|
return a.endsWith(b);
|
|
}
|
|
|
|
function notEndsWith(a: string, b: string) {
|
|
return !a.endsWith(b);
|
|
}
|
|
|
|
calculators.register('includes', includes);
|
|
calculators.register('notIncludes', notIncludes);
|
|
calculators.register('startsWith', startsWith);
|
|
calculators.register('notStartsWith', notStartsWith);
|
|
calculators.register('endsWith', endsWith);
|
|
calculators.register('notEndsWith', notEndsWith);
|
|
|
|
function before(a: string, b: string) {
|
|
return a < b;
|
|
}
|
|
|
|
calculators.register('now', () => new Date());
|
|
|
|
// TODO: add more common calculators
|