import { IAction, IActionResult, IActionNode, IActionProperty, IContext, } from "../types/ActionTypes"; import { actionAddins } from "."; interface Props { displayName: string; sources: Sources; condition: string; conditionO: Condition; verName: VerName; } interface Condition { queryString: string; index: number; type: string; children: Child[]; parent: null; logicalOperator: string; } interface Child { index: number; type: string; parent: string; object: Object; operator: ChildOperator; value: Value; } interface Value { sharedText: string; _t: string; objectType: string; actionName: string; displayName: string; name: Name; } interface Name { name: string; } interface ChildOperator { label: string; value: string; } interface Object { sharedText: string; _t: string; name: string; objectType: string; type: string; code: string; label: string; noLabel: boolean; required: boolean; minLength: string; maxLength: string; expression: string; hideExpression: boolean; unique: boolean; defaultValue: string; } interface VerName { name: string; actionName: string; displayName: string; vars: Var[]; } interface Var { id: string; field: Field2; logicalOperator: LogicalOperator; vName: string; } interface LogicalOperator { operator: string; label: string; } interface Field2 { sharedText: string; _t: string; name: string; objectType: string; type: string; code: string; label: string; noLabel: boolean; required: boolean; minLength: string; maxLength: string; expression: string; hideExpression: boolean; unique: boolean; defaultValue: string; } interface Sources { app: App; fields: Field[]; } interface Field { name: string; type: string; code: string; label: string; noLabel: boolean; required: boolean; minLength: string; maxLength: string; expression: string; hideExpression: boolean; unique: boolean; defaultValue: string; } interface App { id: string; name: string; description: string; createdate: string; } export class DataProcessingAction implements IAction { name: string; actionProps: IActionProperty[]; dataProcessingProps: Props | null; constructor() { this.name = "データ処理"; this.actionProps = []; this.dataProcessingProps = null; this.register(); } async process( nodes: IActionNode, event: any, context: IContext ): Promise { this.actionProps = nodes.actionProps; this.dataProcessingProps = nodes.ActionValue as Props; this.dataProcessingProps.conditionO = JSON.parse( this.dataProcessingProps.condition ); let result = { canNext: true, result: "", } as IActionResult; try { if (!this.dataProcessingProps) { return result; } const data = await selectData( varGet( this.dataProcessingProps.conditionO.queryString, context.variables ) ); console.log("data ", data); context.variables[this.dataProcessingProps.verName.name] = this.dataProcessingProps.verName.vars.reduce((acc, f) => { const v = calc(f, data); if (v) { acc[f.vName] = calc(f, data); } return acc; }, {} as AnyObject); console.log("context ", context); return result; } catch (error) { console.error(error); event.error = error; return result; } } register(): void { actionAddins[this.name] = this; } } new DataProcessingAction(); const varGet = (str: string, vars: any) => { console.log(str); const regex = /var\((.*?)\)/g; let match; while ((match = regex.exec(str)) !== null) { const varName = match[1]; if (varName in vars) { str = str.replace(match[0], vars[varName]); } else { throw new Error(`変数${varName}が見つかりません`); } } console.log(str); return str; }; const selectData = async (query?: string) => { return kintone .api(kintone.api.url("/k/v1/records", true), "GET", { app: kintone.app.getId(), query: query, }) .then((resp: Resp) => { const result: Result = {}; resp.records.forEach((element) => { for (const [key, value] of Object.entries(element)) { if (!result[key]) { result[key] = { type: value.type, value: [] }; } result[key].value.push(value.value); } }); return result; }); }; type Resp = { records: RespRecordType[] }; type RespRecordType = { [key: string]: { type: string; value: any; }; }; type Result = { [key: string]: { type: string; value: any[]; }; }; type AnyObject = { [key: string]: any; }; const ERROR_TYPE = "ERROR_TYPE"; const calc = (f: Var, result: Result) => { const type = typeCheck(f.field.type); if (!type) { return ERROR_TYPE; } const fun = calcFunc[ `${type}_${Operator[f.logicalOperator.operator as keyof typeof Operator]}` ]; if (!fun) { return ERROR_TYPE; } const values = result[f.field.code].value; if (!values) { return null; } return fun(values); }; const typeCheck = (type: string) => { switch (type) { case "RECORD_NUMBER": case "NUMBER": return CalcType.NUMBER; case "SINGLE_LINE_TEXT": case "MULTI_LINE_TEXT": case "RICH_TEXT": return CalcType.STRING; case "DATE": return CalcType.DATE; case "TIME": return CalcType.TIME; case "DATETIME": case "UPDATED_TIME": return CalcType.DATETIME; default: return null; } }; enum Operator { SUM = "SUM", AVG = "AVG", MAX = "MAX", MIN = "MIN", COUNT = "COUNT", FIRST = "FIRST", } enum CalcType { NUMBER = "number", STRING = "string", DATE = "date", TIME = "time", DATETIME = "datetime", } const calcFunc: Record string | null> = { [`${CalcType.NUMBER}_${Operator.COUNT}`]: (value: string[]) => value.length.toString(), [`${CalcType.STRING}_${Operator.COUNT}`]: (value: string[]) => value.length.toString(), [`${CalcType.DATE}_${Operator.COUNT}`]: (value: string[]) => value.length.toString(), [`${CalcType.TIME}_${Operator.COUNT}`]: (value: string[]) => value.length.toString(), [`${CalcType.DATETIME}_${Operator.COUNT}`]: (value: string[]) => value.length.toString(), [`${CalcType.NUMBER}_${Operator.SUM}`]: (value: string[]) => value.reduce((acc, v) => acc + Number(v), 0).toString(), [`${CalcType.NUMBER}_${Operator.AVG}`]: (value: string[]) => (value.reduce((acc, v) => acc + Number(v), 0) / value.length).toString(), [`${CalcType.NUMBER}_${Operator.MAX}`]: (value: string[]) => Math.max(...value.map(Number)).toString(), [`${CalcType.NUMBER}_${Operator.MIN}`]: (value: string[]) => Math.min(...value.map(Number)).toString(), [`${CalcType.STRING}_${Operator.SUM}`]: (value: string[]) => value.join(" "), [`${CalcType.DATE}_${Operator.MAX}`]: (value: string[]) => value.reduce((maxDate, currentDate) => maxDate > currentDate ? maxDate : currentDate ), [`${CalcType.DATE}_${Operator.MIN}`]: (value: string[]) => value.reduce((minDate, currentDate) => minDate < currentDate ? minDate : currentDate ), [`${CalcType.TIME}_${Operator.MAX}`]: (value: string[]) => value.reduce((maxTime, currentTime) => maxTime > currentTime ? maxTime : currentTime ), [`${CalcType.TIME}_${Operator.MIN}`]: (value: string[]) => value.reduce((minTime, currentTime) => minTime < currentTime ? minTime : currentTime ), [`${CalcType.DATETIME}_${Operator.MAX}`]: (value: string[]) => value.reduce((maxDateTime, currentDateTime) => new Date(maxDateTime) > new Date(currentDateTime) ? maxDateTime : currentDateTime ), [`${CalcType.DATETIME}_${Operator.MIN}`]: (value: string[]) => value.reduce((minDateTime, currentDateTime) => new Date(minDateTime) < new Date(currentDateTime) ? minDateTime : currentDateTime ), [`${CalcType.STRING}_${Operator.FIRST}`]: (value: string[]) => { return value[0]; }, };