import { IAction, IActionResult, IActionNode, IActionProperty, IContext, } from "../types/ActionTypes"; import { actionAddins } from "."; type DataProcessingProps = { app: { id: string; name: string; }; conditionsQuery: string; propcessing: { varRootName: string; fields: Field[]; }; }; type Field = { name: string; code: string; type: string; varName: string; operator: string; }; export class DataProcessingAction implements IAction { name: string; actionProps: IActionProperty[]; dataProcessingProps: DataProcessingProps | null; constructor() { this.name = "データ処理"; this.actionProps = []; this.dataProcessingProps = null; this.register(); } async process( nodes: IActionNode,event: any,context: IContext ): Promise { this.initActionProps(nodes); this.initTypedActionProps(); let result = { canNext: true, result: "", } as IActionResult; try { if (!this.dataProcessingProps) { return result; } const data = await selectData(this.dataProcessingProps.conditionsQuery); console.log("data ", data); context.variables[this.dataProcessingProps.propcessing.varRootName] = this.dataProcessingProps.propcessing.fields.reduce((acc, f) => { const v = calc(f, data); if (v) { acc[f.varName] = calc(f, data); } return acc; }, {} as Var); console.log("context ", context); return result; } catch (error) { console.error(error); event.error=error; return result; } } register(): void { actionAddins[this.name] = this; } private initActionProps(nodes: IActionNode) { this.actionProps = nodes.actionProps; } private initTypedActionProps() { this.dataProcessingProps = { app: { id: "", name: "", }, conditionsQuery: "", propcessing: { varRootName: "", fields: [], }, }; for (const action of this.actionProps) { if (action.component === "AppFieldSelect") { this.dataProcessingProps.app.id = action.props.modelValue.app.id; this.dataProcessingProps.app.name = action.props.modelValue.app.name; } else if (action.component === "DataProcessing") { this.dataProcessingProps.propcessing.varRootName = action.props.modelValue.name; for (const f of action.props.modelValue.vars) { this.dataProcessingProps.propcessing.fields.push({ name: f.field.name, code: f.field.code, type: f.field.type, varName: f.vName, operator: f.logicalOperator.operator, }); } } else if (action.component === "ConditionInput") { this.dataProcessingProps.conditionsQuery = JSON.parse( action.props.modelValue ).queryString; } } } } new DataProcessingAction(); 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 Var = { [key: string]: any; }; const ERROR_TYPE = "ERROR_TYPE"; const calc = (field: Field, result: Result) => { const type = typeCheck(field.type); if (!type) { return ERROR_TYPE; } const fun = calcFunc[`${type}_${Operator[field.operator as keyof typeof Operator]}`]; if (!fun) { return ERROR_TYPE; } const values = result[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]; } };