Files
KintoneAppBuilder/plugin/kintone-addins/src/actions/data-processing.ts

375 lines
8.0 KiB
TypeScript

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<IActionResult> {
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, (value: string[]) => 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];
},
};