Skip to content

Commit

Permalink
feat: eval-calc-formula
Browse files Browse the repository at this point in the history
  • Loading branch information
devezhao committed Dec 5, 2023
1 parent 7b7ce27 commit 4e606f3
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import com.googlecode.aviator.AviatorEvaluatorInstance;
import com.googlecode.aviator.Options;
import com.googlecode.aviator.exception.ExpressionSyntaxErrorException;
import com.googlecode.aviator.lexer.token.OperatorType;
import com.googlecode.aviator.runtime.function.system.AssertFunction;
import com.googlecode.aviator.runtime.type.AviatorFunction;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -20,7 +21,7 @@
import java.util.Map;

/**
* // https://www.yuque.com/boyan-avfmj/aviatorscript
* https://www.yuque.com/boyan-avfmj/aviatorscript
*
* @author devezhao
* @since 2021/4/12
Expand All @@ -43,6 +44,9 @@ public class AviatorUtils {
} catch (Exception ignored) {
}

AVIATOR.addOpFunction(OperatorType.ADD, new OverOperatorType.DateAdd());
AVIATOR.addOpFunction(OperatorType.SUB, new OverOperatorType.DateSub());

addCustomFunction(new DateDiffFunction());
addCustomFunction(new DateAddFunction());
addCustomFunction(new DateSubFunction());
Expand All @@ -55,13 +59,21 @@ public class AviatorUtils {
}

/**
* 表达式计算
*
* @param expression
* @return
* @see #eval(String, Map, boolean)
*/
public static Object eval(String expression) {
return eval(expression, null, false);
}

/**
* @param expression
* @return
* @see #eval(String, Map, boolean)
*/
public static Object evalQuietly(String expression) {
return eval(expression, null, true);
public static Object eval(String expression, Map<String, Object> env) {
return eval(expression, env, false);
}

/**
Expand All @@ -74,7 +86,7 @@ public static Object evalQuietly(String expression) {
*/
public static Object eval(String expression, Map<String, Object> env, boolean quietly) {
try {
return AVIATOR.execute(expression, env);
return AVIATOR.execute(expression, env == null ? Collections.emptyMap() : env);
} catch (Exception ex) {
if (ex instanceof AssertFunction.AssertFailed) {
throw new AssertFailedException((AssertFunction.AssertFailed) ex);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*!
Copyright (c) REBUILD <https://getrebuild.com/> and/or its owners. All rights reserved.
rebuild is dual-licensed under commercial and open source licenses (GPLv3).
See LICENSE and COMMERCIAL in the project root for license information.
*/

package com.rebuild.core.service.trigger.aviator;

import cn.devezhao.commons.CalendarUtils;
import com.googlecode.aviator.lexer.token.OperatorType;
import com.googlecode.aviator.runtime.function.AbstractFunction;
import com.googlecode.aviator.runtime.type.AviatorLong;
import com.googlecode.aviator.runtime.type.AviatorObject;

import java.util.Date;
import java.util.Map;

/**
* 操作符重载
*
* @author RB
* @since 2023/12/6
*/
public class OverOperatorType {

private OverOperatorType() {}

/**
* 日期加
*/
static class DateAdd extends AbstractFunction {
@Override
public String getName() {
return OperatorType.ADD.getToken();
}

@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2) {
Object $argv1 = arg1.getValue(env);
Object $argv2 = arg2.getValue(env);

if ($argv1 instanceof Date && $argv2 instanceof Number) {
return opDate((Date) $argv1, ((Number) $argv2).intValue());
} else if ($argv2 instanceof Date && $argv1 instanceof Number) {
return opDate((Date) $argv2, ((Number) $argv1).intValue());
} else {
return arg1.add(arg2, env); // Use default
}
}
}

/**
* 日期减
*/
static class DateSub extends AbstractFunction {
@Override
public String getName() {
return OperatorType.SUB.getToken();
}

@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2) {
Object $argv1 = arg1.getValue(env);
Object $argv2 = arg2.getValue(env);

if ($argv1 instanceof Date && $argv2 instanceof Number) {
return opDate((Date) $argv1, -((Number) $argv2).intValue());
} else if ($argv2 instanceof Date && $argv1 instanceof Number) {
return opDate((Date) $argv2, -((Number) $argv1).intValue());
} else if ($argv1 instanceof Date && $argv2 instanceof Date) {
int diff = CalendarUtils.getDayLeft((Date) $argv1, (Date) $argv2);
return AviatorLong.valueOf(diff);
} else {
return arg1.add(arg2, env); // Use default
}
}
}

static AviatorDate opDate(Date date, int num) {
Date d = CalendarUtils.addDay(date, num);
return new AviatorDate(d);
}
}
19 changes: 0 additions & 19 deletions src/main/java/com/rebuild/core/support/SimpleEval.java

This file was deleted.

30 changes: 26 additions & 4 deletions src/main/java/com/rebuild/web/general/ModelExtrasController.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,21 @@
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONAware;
import com.alibaba.fastjson.JSONObject;
import com.rebuild.api.RespBody;
import com.rebuild.core.Application;
import com.rebuild.core.configuration.general.AutoFillinManager;
import com.rebuild.core.metadata.MetadataHelper;
import com.rebuild.core.metadata.easymeta.DisplayType;
import com.rebuild.core.metadata.easymeta.EasyEntity;
import com.rebuild.core.metadata.easymeta.EasyField;
import com.rebuild.core.metadata.easymeta.EasyMetaFactory;
import com.rebuild.core.metadata.impl.EasyFieldConfigProps;
import com.rebuild.core.privileges.UserHelper;
import com.rebuild.core.privileges.bizz.User;
import com.rebuild.core.service.general.RepeatedRecordsException;
import com.rebuild.core.service.general.transform.RecordTransfomer;
import com.rebuild.core.service.trigger.aviator.AviatorUtils;
import com.rebuild.core.support.i18n.I18nUtils;
import com.rebuild.core.support.i18n.Language;
import com.rebuild.utils.JSONUtils;
Expand Down Expand Up @@ -200,13 +205,30 @@ public JSON checkCreates(HttpServletRequest request) {

@PostMapping("eval-calc-formula")
public RespBody evalCalcFormula(@EntityParam Entity entity, HttpServletRequest request) {
String fieldName = getParameterNotNull(request, "field");
if (!entity.containsField(fieldName)) return RespBody.error();
String targetField = getParameterNotNull(request, "field");
if (!entity.containsField(targetField)) return RespBody.error();

JSON data = ServletUtils.getRequestJson(request);
JSONObject vars = (JSONObject) ServletUtils.getRequestJson(request);

System.out.println(data.toJSONString());
EasyField easyField = EasyMetaFactory.valueOf(entity.getField(targetField));
String formula = easyField.getExtraAttr(EasyFieldConfigProps.DATE_CALCFORMULA);
Object evalVal = AviatorUtils.eval(formula, vars.getInnerMap(), true);
if (evalVal == null) return RespBody.ok();

DisplayType dt = easyField.getDisplayType();
if (dt == DisplayType.DATE || dt == DisplayType.DATETIME) {
if (evalVal instanceof Date) {
evalVal = easyField.wrapValue(evalVal);
return RespBody.ok(evalVal);
}
} else if (dt == DisplayType.NUMBER || dt == DisplayType.DECIMAL) {
if (evalVal instanceof Number) {
evalVal = easyField.wrapValue(evalVal);
return RespBody.ok(evalVal);
}
}

log.warn("Bad eval value : {}", evalVal);
return RespBody.ok();
}
}
4 changes: 3 additions & 1 deletion src/main/resources/web/assets/js/general/rb-forms.js
Original file line number Diff line number Diff line change
Expand Up @@ -1198,7 +1198,7 @@ class RbFormNumber extends RbFormText {
if ($emptyNum(s.value)) {
delete calcFormulaValues[s.name]
} else {
calcFormulaValues[s.name] = this._removeComma(s.value)
calcFormulaValues[s.name] = s.value
}

if (_timer) {
Expand All @@ -1210,6 +1210,8 @@ class RbFormNumber extends RbFormText {
_timer = setTimeout(() => {
$.post(evalUrl, JSON.stringify(calcFormulaValues), (res) => {
console.log(res)
if (res.data) this.setValue(res.data)
else this.setValue(null)
})
}, 200)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@

package com.rebuild.core.service.trigger.aviator;

import cn.devezhao.commons.CalendarUtils;
import com.googlecode.aviator.exception.ExpressionRuntimeException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
Expand All @@ -22,7 +24,7 @@ class AviatorUtilsTest {

@Test
void eval() {
System.out.println(AviatorUtils.evalQuietly("123*123"));
System.out.println(AviatorUtils.eval("123*123"));

System.out.println(AviatorUtils.eval(
"abc12_.abc+123", Collections.singletonMap("abc12_.abc", 100), true));
Expand All @@ -36,30 +38,30 @@ void validate() {

@Test
void func() {
AviatorUtils.evalQuietly("p(DATEDIFF('2021-03-04 00:00:00', '2022-03-05 23:59:59', 'D'))");
AviatorUtils.evalQuietly("p(DATEDIFF('2021-03-04 00:00:00', '2022-03-05 23:59:59', 'M'))");
AviatorUtils.evalQuietly("p(DATEDIFF('2021-03-04 00:00:00', '2022-03-09 23:59:59', 'Y'))");
AviatorUtils.eval("p(DATEDIFF('2021-03-04 00:00:00', '2022-03-05 23:59:59', 'D'))");
AviatorUtils.eval("p(DATEDIFF('2021-03-04 00:00:00', '2022-03-05 23:59:59', 'M'))");
AviatorUtils.eval("p(DATEDIFF('2021-03-04 00:00:00', '2022-03-09 23:59:59', 'Y'))");

AviatorUtils.evalQuietly("p(DATEADD('2021-01-01 18:17:00', '2H'))");
AviatorUtils.eval("p(DATEADD('2021-01-01 18:17:00', '2H'))");

AviatorUtils.evalQuietly("p(DATESUB('2021-01-01 18:17:00', '1'))");
AviatorUtils.eval("p(DATESUB('2021-01-01 18:17:00', '1'))");
}

@Test
void funcComplex() {
AviatorUtils.evalQuietly("p(100 + DATEDIFF('2021-01-01 18:17:00', '2021-01-01 16:17:00', 'H'))");
AviatorUtils.evalQuietly("p(DATEADD(DATEADD('2021-01-01 18:17:00', '2H'), '1D'))");
AviatorUtils.eval("p(100 + DATEDIFF('2021-01-01 18:17:00', '2021-01-01 16:17:00', 'H'))");
AviatorUtils.eval("p(DATEADD(DATEADD('2021-01-01 18:17:00', '2H'), '1D'))");
}

@Test
void funcRequestFunction() {
AviatorUtils.evalQuietly("p(REQUEST('https://www.baidu.com/'))");
AviatorUtils.evalQuietly("p(REQUEST('https://www.google.com/', 'imdefault'))");
AviatorUtils.eval("p(REQUEST('https://www.baidu.com/'))");
AviatorUtils.eval("p(REQUEST('https://www.google.com/', 'imdefault'))");
}

@Test
void funcLocationDistanceFunction() {
AviatorUtils.evalQuietly("p(LOCATIONDISTANCE('123.456789,123.456789', '地址$$$$123.456789,123.456789'))");
AviatorUtils.eval("p(LOCATIONDISTANCE('123.456789,123.456789', '地址$$$$123.456789,123.456789'))");
}

@Test
Expand All @@ -75,6 +77,19 @@ void testNull() {

@Test
void testJava() {
AviatorUtils.evalQuietly("p(StringUtils.upperCase('abcd'));");
AviatorUtils.eval("p(StringUtils.upperCase('abcd'));");
}

@Test
void testDateOp() {
Map<String, Object> env = new HashMap<>();
env.put("date1", CalendarUtils.now());
AviatorUtils.eval("p(date1 + 8)", env, true);
AviatorUtils.eval("p(date1 - 8)", env, true);
AviatorUtils.eval("p(date1 - date1)", env, true);

// BAD
Assertions.assertThrows(ExpressionRuntimeException.class,
() -> AviatorUtils.eval("date1 + date1", env, false));
}
}

0 comments on commit 4e606f3

Please sign in to comment.