Skip to content

Commit

Permalink
refactor: 优化类型转换失败时的性能
Browse files Browse the repository at this point in the history
  • Loading branch information
zhou-hao committed Jul 29, 2024
1 parent aa2949c commit af30e4c
Show file tree
Hide file tree
Showing 9 changed files with 172 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,20 @@ public DefaultReactorQLRecord(
String name,
Object thisRecord,
ReactorQLContext context) {
this();
this(context);
if (name != null) {
records.put(name, thisRecord);
}
this.name = name;
if (thisRecord != null) {
records.put(THIS_RECORD, thisRecord);
}
this.context = context;
}

private DefaultReactorQLRecord() {
records = new ConcurrentHashMap<>(32);
results = new ConcurrentHashMap<>(32);
private DefaultReactorQLRecord(ReactorQLContext context) {
this.context = context;
this.records = this.context.newContainer();
this.results = this.context.newContainer();
}

@Override
Expand Down Expand Up @@ -145,8 +145,7 @@ public ReactorQLRecord putRecordToResult() {

@Override
public ReactorQLRecord resultToRecord(String name) {
DefaultReactorQLRecord record = new DefaultReactorQLRecord();
record.context = this.context;
DefaultReactorQLRecord record = new DefaultReactorQLRecord(context);
record.name = name;
record.records.putAll(records);
Map<String, Object> thisRecord = new ConcurrentHashMap<>(results);
Expand Down Expand Up @@ -177,7 +176,7 @@ public int compareTo(DefaultReactorQLRecord o) {

@Override
public ReactorQLRecord copy() {
DefaultReactorQLRecord record = new DefaultReactorQLRecord();
DefaultReactorQLRecord record = new DefaultReactorQLRecord(context);
record.results.putAll(results);
record.records.putAll(records);
record.context = context;
Expand Down
7 changes: 6 additions & 1 deletion src/main/java/org/jetlinks/reactor/ql/ReactorQLContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@

import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiFunction;
import java.util.function.Function;

/**
* ReactorQL上下文,通过上下文传递参数及数据
*
* @author zhouhao
* @since 1.0.0
* @see DefaultReactorQLContext
* @since 1.0.0
*/
public interface ReactorQLContext {

Expand Down Expand Up @@ -109,4 +111,7 @@ default ReactorQLContext bindAll(Map<String, Object> value) {
*/
ReactorQLContext transfer(BiFunction<String, Flux<Object>, Flux<Object>> dataSourceMapper);

default Map<String, Object> newContainer() {
return new ConcurrentHashMap<>(32);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.jetlinks.reactor.ql.exception;

public class TypeCastException extends RuntimeException {

public TypeCastException(String message) {
super(message);
}

public TypeCastException(String message, Throwable cause) {
super(message, cause);
}

@Override
public synchronized Throwable fillInStackTrace() {
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
import reactor.util.function.Tuple2;
import reactor.util.function.Tuples;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
Expand Down Expand Up @@ -207,7 +209,15 @@ public void visit(SignedExpression expr) {
, l -> -l
, d -> -d
, f -> -f
, d -> -d.doubleValue()
, d -> {
if (d instanceof BigDecimal) {
return ((BigDecimal) d).negate();
}
if (d instanceof BigInteger) {
return ((BigInteger) d).negate();
}
return -d.doubleValue();
}
);
break;
case '~':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,17 @@
import org.reactivestreams.Publisher;
import reactor.core.publisher.Mono;

import java.util.Arrays;
import java.util.Date;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;

public class BetweenFilter implements FilterFeature {

private static final String ID = FeatureId.Filter.between.getId();

@SuppressWarnings("all")
private static final ThreadLocal<List<Comparable>> SHARE = ThreadLocal.withInitial(() -> new ArrayList<>(3));

@Override
public BiFunction<ReactorQLRecord, Object, Mono<Boolean>> createPredicate(Expression expression, ReactorQLMetadata metadata) {

Expand All @@ -44,26 +46,62 @@ static BiFunction<ReactorQLRecord, Object, Mono<Boolean>> doCreate(Expression le
.map(tp3 -> not != predicate(tp3.getT1(), tp3.getT2(), tp3.getT3()));
}

public static boolean predicate(Object val, Object between, Object and) {
if (val == null || between == null || and == null) {
public static boolean predicate(Object val, Object between, Object and) {
try {
if (val == null || between == null || and == null) {
return false;
}
if (val.equals(between) || val.equals(and)) {
return true;
}
if (val instanceof Date || between instanceof Date || and instanceof Date) {
val = CastUtils.castDate(val, ignore -> null);
between = CastUtils.castDate(between, ignore -> null);
and = CastUtils.castDate(and, ignore -> null);
}
if (val instanceof Number || between instanceof Number || and instanceof Number) {
Number numberValue = CastUtils.castNumber(val, (ignore) -> null),
numberBetween = CastUtils.castNumber(between, (ignore) -> null),
numberAnd = CastUtils.castNumber(and, (ignore) -> null);

if (numberValue == null ||
numberBetween == null ||
numberAnd == null) {
return false;
}

return numberValue.doubleValue() >= numberBetween.doubleValue()
&& numberValue.doubleValue() <= numberAnd.doubleValue();
}

if (val == null || between == null || and == null) {
return false;
}
return compare0(val, between, and);
} catch (Throwable error) {
return false;
}
if (val.equals(between) || val.equals(and)) {
return true;
}
if (val instanceof Date || between instanceof Date || and instanceof Date) {
val = CastUtils.castDate(val);
between = CastUtils.castDate(between);
and = CastUtils.castDate(and);
}
if (val instanceof Number || between instanceof Number || and instanceof Number) {
double doubleVal = CastUtils.castNumber(val).doubleValue();
return doubleVal >= CastUtils.castNumber(between).doubleValue() && doubleVal <= CastUtils.castNumber(and).doubleValue();
}

private static Comparable<?> castComparable(Object va) {
if (va instanceof Comparable) {
return (Comparable<?>) va;
}
return String.valueOf(va);
}

Object[] arr = new Object[]{val, between, and};
Arrays.sort(arr);
return arr[1] == val;
@SuppressWarnings("all")
protected static boolean compare0(Object val, Object between, Object and) {
List<Comparable> arr = SHARE.get();
try {
arr.add(castComparable(val));
arr.add(castComparable(between));
arr.add(castComparable(and));
Collections.sort(arr);
return val == arr.get(1);
} finally {
arr.clear();
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,15 @@ public BinaryFilterFeature(String type) {

@Override
public BiFunction<ReactorQLRecord, Object, Mono<Boolean>> createPredicate(Expression expression, ReactorQLMetadata metadata) {
Tuple2<Function<ReactorQLRecord,Publisher<?>>,
Function<ReactorQLRecord,Publisher<?>>> tuple2 = ValueMapFeature.createBinaryMapper(expression, metadata);
Tuple2<Function<ReactorQLRecord, Publisher<?>>,
Function<ReactorQLRecord, Publisher<?>>> tuple2 = ValueMapFeature.createBinaryMapper(expression, metadata);

Function<ReactorQLRecord, Publisher<?>> leftMapper = tuple2.getT1();
Function<ReactorQLRecord, Publisher<?>> rightMapper = tuple2.getT2();
Function<ReactorQLRecord, Publisher<?>> rightMapper = tuple2.getT2();

return (row, column) -> Mono.zip(Mono.from(leftMapper.apply(row)), Mono.from(rightMapper.apply(row)), this::test).defaultIfEmpty(false);
return (row, column) -> Mono
.zip(Mono.from(leftMapper.apply(row)), Mono.from(rightMapper.apply(row)), this::test)
.defaultIfEmpty(false);
}

public boolean test(Object left, Object right) {
Expand All @@ -47,17 +49,32 @@ public boolean test(Object left, Object right) {
if (right instanceof Map && ((Map<?, ?>) right).size() == 1) {
right = ((Map<?, ?>) right).values().iterator().next();
}
if (left instanceof Date || right instanceof Date || left instanceof LocalDateTime || right instanceof LocalDateTime || left instanceof Instant || right instanceof Instant) {
return doTest(CastUtils.castDate(left), CastUtils.castDate(right));
if (left instanceof Date
|| right instanceof Date
|| left instanceof LocalDateTime
|| right instanceof LocalDateTime
|| left instanceof Instant
|| right instanceof Instant) {
Date dateLeft = CastUtils.castDate(left);
Date dateRight = CastUtils.castDate(right);
if (dateLeft == null || dateRight == null) {
return false;
}
return doTest(dateLeft, dateRight);
}
if (left instanceof Number || right instanceof Number) {
return doTest(CastUtils.castNumber(left), CastUtils.castNumber(right));
Number numberLeft = CastUtils.castNumber(left, ignore -> null);
Number numberRight = CastUtils.castNumber(right, ignore -> null);
if (numberLeft == null || numberRight == null) {
return false;
}
return doTest(numberLeft, numberRight);
}
if (left instanceof String || right instanceof String) {
return doTest(String.valueOf(left), String.valueOf(right));
}
return doTest(left, right);
}catch (Throwable e){
} catch (Throwable e) {
return false;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ public BiFunction<ReactorQLRecord, Object, Mono<Boolean>> createPredicate(Expres
LikeExpression like = ((LikeExpression) expression);
boolean not = like.isNot();

return (row, column) -> Mono.zip(Mono.from(leftMapper.apply(row)), Mono.from(rightMapper.apply(row)), (left, right) -> doTest(not, left, right));
return (row, column) -> Mono
.zip(Mono.from(leftMapper.apply(row)),
Mono.from(rightMapper.apply(row)),
(left, right) -> doTest(not, left, right));
}

public static boolean doTest(boolean not, Object left, Object right) {
Expand Down
37 changes: 27 additions & 10 deletions src/main/java/org/jetlinks/reactor/ql/utils/CastUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.hswebframework.utils.StringUtils;
import org.hswebframework.utils.time.DateFormatter;
import org.jetlinks.reactor.ql.exception.TypeCastException;
import org.jetlinks.reactor.ql.supports.DefaultPropertyFeature;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
Expand All @@ -21,7 +22,6 @@

public class CastUtils {


public static <T> Flux<T> handleFirst(Flux<?> stream, BiFunction<Object, Flux<?>, Publisher<T>> handler) {
return stream.switchOnFirst((signal, objectFlux) -> {
if (!signal.hasValue()) {
Expand Down Expand Up @@ -65,6 +65,9 @@ public static boolean castBoolean(Object value) {
if (value instanceof Boolean) {
return ((Boolean) value);
}
if (value instanceof Number) {
return ((Number) value).intValue() == 1;
}
String strVal = String.valueOf(value);

return "true".equalsIgnoreCase(strVal) ||
Expand Down Expand Up @@ -144,20 +147,22 @@ public static Number castNumber(Object value,

}

public static Number castNumber(Object value) {
public static Number castNumber(Object value, Function<Object, Number> fallback) {
if (value instanceof CharSequence) {
String stringValue = String.valueOf(value);
if (stringValue.startsWith("0x")) {
return Long.parseLong(stringValue.substring(2), 16);
}
if (stringValue.isEmpty()) {
return fallback.apply(value);
}
try {
BigDecimal decimal = new BigDecimal(stringValue);
if (decimal.scale() == 0) {
return decimal.longValue();
}
return decimal.doubleValue();
} catch (NumberFormatException ignore) {

}
}
if (value instanceof Character) {
Expand All @@ -172,15 +177,18 @@ public static Number castNumber(Object value) {
if (value instanceof Date) {
return ((Date) value).getTime();
}

//日期格式的字符串?
try {
return castDate(value).getTime();
} catch (Throwable ignore) {

} catch (Throwable error) {
return fallback.apply(value);
}
}

throw new UnsupportedOperationException("can not cast to number:" + value);
public static Number castNumber(Object value) {
return castNumber(value, (val) -> {
throw new TypeCastException("can not cast to number:" + value);
});
}

public static LocalDateTime castLocalDateTime(Object value) {
Expand All @@ -195,11 +203,14 @@ public static LocalDateTime castLocalDateTime(Object value) {
}

Date date = castDate(value);
return LocalDateTime.ofInstant(date.toInstant(),ZoneId.systemDefault());
return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
}

public static Date castDate(Object value) {
public static Date castDate(Object value, Function<Object, Date> fallback) {
if (value instanceof String) {
if (((String) value).isEmpty()) {
return fallback.apply(value);
}
if (StringUtils.isNumber(value)) {
value = Long.parseLong(String.valueOf(value));
} else {
Expand Down Expand Up @@ -260,7 +271,13 @@ public static Date castDate(Object value) {
if (value instanceof Date) {
return ((Date) value);
}
throw new UnsupportedOperationException("can not cast to date:" + value);
return fallback.apply(value);
}

public static Date castDate(Object value) {
return castDate(value, val -> {
throw new TypeCastException("can not cast to date:" + val);
});
}

public static Duration parseDuration(String timeString) {
Expand Down
Loading

0 comments on commit af30e4c

Please sign in to comment.