优化时间日期

This commit is contained in:
devezhao 2019-08-29 17:27:07 +08:00
parent 749259238d
commit bb8a206568
3 changed files with 109 additions and 67 deletions

View file

@ -33,7 +33,6 @@ import com.rebuild.server.metadata.entity.DisplayType;
import com.rebuild.server.metadata.entity.EasyMeta;
import com.rebuild.server.service.bizz.UserHelper;
import com.rebuild.server.service.bizz.privileges.Department;
import com.rebuild.web.IllegalParameterException;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
@ -169,44 +168,55 @@ public class AdvFilterParser {
if (hasAndFlag) {
field = field.substring(1);
}
final String[] fieldPath = field.split("\\.");
if (fieldPath.length > 2) {
throw new IllegalParameterException("Unsupportted joins : " + field);
}
if (!rootEntity.containsField(fieldPath[0])) {
final Field fieldMeta = MetadataHelper.getLastJoinField(rootEntity, field);
if (fieldMeta == null) {
LOG.warn("Unknow field '" + field + "' in '" + rootEntity.getName() + "'");
return null;
}
Field fieldMeta = rootEntity.getField(fieldPath[0]);
if (fieldPath.length > 1) {
if (EasyMeta.getDisplayType(fieldMeta) != DisplayType.REFERENCE) {
throw new IllegalParameterException("Non reference-field : " + field);
}
fieldMeta = fieldMeta.getReferenceEntity().getField(fieldPath[1]);
}
DisplayType dt = EasyMeta.getDisplayType(fieldMeta);
// TODO 分类字段仅能查询最后一级
final DisplayType dt = EasyMeta.getDisplayType(fieldMeta);
if (dt == DisplayType.CLASSIFICATION || hasAndFlag) {
field = "&" + field;
}
final String op = item.getString("op");
String op = item.getString("op");
String value = item.getString("value");
String valueEnd = null;
// 日期时间
if (dt == DisplayType.DATETIME || dt == DisplayType.DATE) {
if ("TDA".equalsIgnoreCase(op) || "YTA".equalsIgnoreCase(op) || "TTA".equalsIgnoreCase(op)) {
value = getUTCDateFormat().format(CalendarUtils.now());
if ("YTA".equalsIgnoreCase(op)) {
value = getUTCDateFormat().format(CalendarUtils.addDay(-1));
} else if ("TTA".equalsIgnoreCase(op)) {
value = getUTCDateFormat().format(CalendarUtils.addDay(1));
}
if (dt == DisplayType.DATETIME) {
op = "BW";
valueEnd = parseValue(value, op, fieldMeta, true);
} else {
op = "EQ";
}
}
if ("EQ".equalsIgnoreCase(op) && dt == DisplayType.DATETIME && StringUtils.length(value) == 10) {
op = "BW";
valueEnd = parseValue(value, op, fieldMeta, true);
}
}
StringBuilder sb = new StringBuilder(field)
.append(' ')
.append(convOp(op))
.append(' ');
.append(convOp(op));
if (op.equalsIgnoreCase("NL") || op.equalsIgnoreCase("NT")) {
return sb.toString();
} else {
sb.append(' ');
}
String value = item.getString("value");
String valueEnd = null;
// TODO 自定义函数
if ("BFD".equalsIgnoreCase(op)) {
@ -221,19 +231,7 @@ public class AdvFilterParser {
value = getUTCDateFormat().format(CalendarUtils.addDay(-NumberUtils.toInt(value))) + FULL_TIME;
} else if ("REM".equalsIgnoreCase(op)) {
value = getUTCDateFormat().format(CalendarUtils.addMonth(-NumberUtils.toInt(value))) + FULL_TIME;
} else if ("YTA".equalsIgnoreCase(op)) {
value = getUTCDateFormat().format(CalendarUtils.addDay(-1));
valueEnd = value + FULL_TIME;
value = value + ZERO_TIME;
} else if ("TDA".equalsIgnoreCase(op)) {
value = getUTCDateFormat().format(CalendarUtils.now());
valueEnd = value + FULL_TIME;
value = value + ZERO_TIME;
} else if ("TTA".equalsIgnoreCase(op)) {
value = getUTCDateFormat().format(CalendarUtils.addDay(1));
valueEnd = value + FULL_TIME;
value = value + ZERO_TIME;
} else if ("SFU".equalsIgnoreCase(op)) {
} else if ("SFU".equalsIgnoreCase(op)) {
value = Application.getCurrentUser().toLiteral();
} else if ("SFB".equalsIgnoreCase(op)) {
Department dept = UserHelper.getDepartment(Application.getCurrentUser());
@ -257,40 +255,45 @@ public class AdvFilterParser {
}
}
}
if (StringUtils.isBlank(value)) {
LOG.warn("Invalid item of AdvFilter : " + item.toJSONString());
return null;
}
// 占位 {1}
// 快速搜索的占位 {1}
if (value.matches("\\{\\d+\\}")) {
if (values == null) {
LOG.warn("Invalid item of AdvFilter : " + item.toJSONString());
return null;
}
String valHold = value.replaceAll("[\\{\\}]", "");
value = parseValue(values.get(valHold), op, fieldMeta);
value = parseValue(values.get(valHold), op, fieldMeta, false);
} else {
value = parseValue(value, op, fieldMeta);
value = parseValue(value, op, fieldMeta, false);
}
// No value
if (value == null) {
LOG.warn("Invalid item of AdvFilter : " + item.toJSONString());
return null;
}
// 区间
boolean isBetween = op.equalsIgnoreCase("BW");
valueEnd = isBetween ? parseValue(item.getString("value2"), op, fieldMeta) : valueEnd;
if (isBetween && valueEnd == null) {
valueEnd = value;
}
valueEnd = parseValue(item.getString("value2"), op, fieldMeta, true);
if (valueEnd == null) {
valueEnd = value;
}
}
// IN
if (op.equalsIgnoreCase("IN") || op.equalsIgnoreCase("NIN") || op.equalsIgnoreCase("SFD")) {
sb.append(value);
} else {
// LIKE
if (op.equalsIgnoreCase("LK") || op.equalsIgnoreCase("NLK")) {
value = '%' + value + '%';
}
@ -298,25 +301,23 @@ public class AdvFilterParser {
}
if (isBetween) {
sb.append(" and ").append(quoteValue(valueEnd, fieldMeta.getType()));
} else if (valueEnd != null) {
sb.insert(0, '(')
.append(" and ")
.append(field)
.append(" <= ")
.append(quoteValue(valueEnd, fieldMeta.getType()))
.append(')');
}
return sb.toString();
sb.insert(0, "( ")
.append(" and ").append(quoteValue(valueEnd, fieldMeta.getType()))
.append(" )");
}
System.out.println(item + "\n>> " + sb);
return sb.toString().trim();
}
/**
* @param val
* @param op
* @param field
* @param endVal 仅对日期时间有意义
* @return
*/
private String parseValue(Object val, String op, Field field) {
private String parseValue(Object val, String op, Field field, boolean endVal) {
String value;
// IN
if (val instanceof JSONArray) {
@ -331,8 +332,19 @@ public class AdvFilterParser {
if (StringUtils.isBlank(value)) {
return null;
}
// 兼容 | 号分割
// TIMESTAMP 仅指定了日期值
if (field.getType() == FieldType.TIMESTAMP && StringUtils.length(value) == 10) {
if ("GT".equalsIgnoreCase(op)) {
value += FULL_TIME;
} else if ("LT".equalsIgnoreCase(op)) {
value += ZERO_TIME;
} else if ("BW".equalsIgnoreCase(op)) {
value += (endVal ? FULL_TIME : ZERO_TIME);
}
}
// 多个值的情况下兼容 | 号分割
if (op.equalsIgnoreCase("IN") || op.equalsIgnoreCase("NIN") || op.equalsIgnoreCase("SFD")) {
Set<String> inVals = new HashSet<>();
for (String v : value.split("\\|")) {

View file

@ -207,7 +207,7 @@ class AdvFilter extends React.Component {
}
}
const OP_TYPE = { LK: '包含', NLK: '不包含', IN: '包含', NIN: '不包含', EQ: '等于', NEQ: '不等于', GT: '大于', LT: '小于', BW: '区间', NL: '为空', NT: '不为空', BFD: '...天前', BFM: '...月前', AFD: '...天后', AFM: '...月后', RED: '最近...天', REM: '最近...月', SFU: '本人', SFB: '本部门', SFD: '本部门及子部门', YTA:'昨天', TDA:'今天', TTA:'明天' }
const OP_TYPE = { LK: '包含', NLK: '不包含', IN: '包含', NIN: '不包含', EQ: '等于', NEQ: '不等于', GT: '大于', LT: '小于', BW: '区间', NL: '为空', NT: '不为空', BFD: '...天前', BFM: '...月前', AFD: '...天后', AFM: '...月后', RED: '最近...天', REM: '最近...月', SFU: '本人', SFB: '本部门', SFD: '本部门及子部门', YTA: '昨天', TDA: '今天', TTA: '明天' }
const OP_DATE_NOPICKER = ['BFD', 'BFM', 'AFD', 'AFM', 'RED', 'REM']
const OP_NOVALUE = ['NL', 'NT', 'SFU', 'SFB', 'SFD', 'YTA', 'TDA', 'TTA']
const PICKLIST_CACHE = {}
@ -259,7 +259,7 @@ class FilterItem extends React.Component {
if (fieldType === 'NUMBER' || fieldType === 'DECIMAL') {
op = ['GT', 'LT', 'BW', 'EQ']
} else if (fieldType === 'DATE' || fieldType === 'DATETIME') {
op = ['YTA', 'TDA', 'TTA', 'GT', 'LT', 'BW', 'RED', 'REM', 'BFD', 'BFM', 'AFD', 'AFM']
op = ['TDA', 'YTA', 'TTA', 'GT', 'LT', 'EQ', 'BW', 'RED', 'REM', 'BFD', 'BFM', 'AFD', 'AFM']
} else if (fieldType === 'FILE' || fieldType === 'IMAGE') {
op = []
} else if (fieldType === 'PICKLIST') {

View file

@ -62,4 +62,34 @@ public class AdvFilterParserTest extends TestSupport {
String where = new AdvFilterParser(filterExp).toSqlWhere();
System.out.println(where);
}
@Test
public void testDateAndDatetime() throws Exception {
JSONObject filterExp = new JSONObject();
filterExp.put("entity", TEST_ENTITY);
JSONArray items = new JSONArray();
filterExp.put("items", items);
// Use `=`
items.add(JSON.parseObject("{ op:'EQ', field:'date', value:'2019-09-09' }"));
// Use `between`
items.add(JSON.parseObject("{ op:'EQ', field:'datetime', value:'2019-09-09' }"));
System.out.println(new AdvFilterParser(filterExp).toSqlWhere());
items.clear();
// Use `=`
items.add(JSON.parseObject("{ op:'TDA', field:'date' }"));
// Use `between`
items.add(JSON.parseObject("{ op:'TDA', field:'datetime' }"));
System.out.println(new AdvFilterParser(filterExp).toSqlWhere());
items.clear();
// No padding
items.add(JSON.parseObject("{ op:'GT', field:'date', value:'2019-09-09' }"));
// Padding time
items.add(JSON.parseObject("{ op:'GT', field:'datetime', value:'2019-09-09' }"));
// No padding
items.add(JSON.parseObject("{ op:'GT', field:'datetime', value:'2019-09-09 12:12:54' }"));
System.out.println(new AdvFilterParser(filterExp).toSqlWhere());
}
}