initial commit

This commit is contained in:
wea_ondara
2022-07-11 21:18:54 +02:00
commit 8bb2265abd
34 changed files with 2488 additions and 0 deletions

View File

@@ -0,0 +1,33 @@
package jef.expressions;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.List;
import java.util.stream.Collectors;
@Getter
@AllArgsConstructor
public class AndExpression implements Expression {
private final List<Expression> exprs;
public AndExpression(Expression... exprs) {
this.exprs = List.of(exprs);
}
@Override
public Type getType() {
return Type.AND;
}
@Override
public String toString() {
return exprs.stream().map(e -> {
if (e instanceof OrExpression) {
return "(" + e + ")";
} else {
return e.toString();
}
}).collect(Collectors.joining(" AND "));
}
}

View File

@@ -0,0 +1,60 @@
package jef.expressions;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Map;
@Getter
@AllArgsConstructor
public class BinaryExpression implements Expression {
private final Expression left;
private final Expression right;
private final Operator operator;
@Override
public Type getType() {
return Type.BINARY;
}
@Override
public String toString() {
return left + " " + operator + " " + right;
}
@AllArgsConstructor
public enum Operator {
EQ("="),
NE("<>"),
LT("<"),
LE("<="),
GT(">"),
GE(">="),
// OR("OR"),
// AND("AND"),
IN("IN"),
;
private final String string;
@Override
public String toString() {
return string;
}
private static final Map<Operator, Operator> INVERSION = Map.of(
EQ, NE,
NE, EQ,
LT, GE,
GE, LT,
LE, GT,
GT, LE);
public Operator invert() {
return INVERSION.get(this);
}
public boolean isInvertible() {
return INVERSION.containsKey(this);
}
}
}

View File

@@ -0,0 +1,23 @@
package jef.expressions;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public class ConstantExpression implements Expression {
public static final jef.expressions.ConstantExpression I0 = new jef.expressions.ConstantExpression(0);
public static final jef.expressions.ConstantExpression I1 = new jef.expressions.ConstantExpression(1);
protected final Object value;
@Override
public Type getType() {
return Type.CONSTANT;
}
@Override
public String toString() {
return value.toString();
}
}

View File

@@ -0,0 +1,19 @@
package jef.expressions;
public interface Expression {
Type getType();
public enum Type {
AND,
BINARY,
CONSTANT,
FIELD,
OR,
PARAMETER,
SELECT,
TABLE,
TERNARY,
UNARY,
WHERE,
}
}

View File

@@ -0,0 +1,23 @@
package jef.expressions;
import lombok.Getter;
@Getter
public class FieldExpression extends ConstantExpression implements Expression {
private final String name;
public FieldExpression(String name) {
super(name);
this.name = name;
}
@Override
public Type getType() {
return Type.FIELD;
}
@Override
public String toString() {
return name;
}
}

View File

@@ -0,0 +1,27 @@
package jef.expressions;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.List;
import java.util.stream.Collectors;
@Getter
@AllArgsConstructor
public class OrExpression implements Expression {
private final List<Expression> exprs;
public OrExpression(Expression... exprs) {
this.exprs = List.of(exprs);
}
@Override
public Type getType() {
return Type.OR;
}
@Override
public String toString() {
return exprs.stream().map(Expression::toString).collect(Collectors.joining(" OR "));
}
}

View File

@@ -0,0 +1,35 @@
package jef.expressions;
import lombok.Getter;
import java.util.Collection;
import java.util.stream.Collectors;
@Getter
public class ParameterExpression extends ConstantExpression implements Expression {
private final int index;
private final boolean isInput;
public ParameterExpression(int index, Object value, boolean isInput) {
super(value);
this.index = index;
this.isInput = isInput;
}
@Override
public Type getType() {
return Type.PARAMETER;
}
@Override
public String toString() {
if (isInput) {
return "param #" + index;
} else if (this.value == null) {
return "null";
} else if (this.value instanceof Collection) {
return "(" + ((Collection) this.value).stream().map(Object::toString).collect(Collectors.joining(",")) + ")";
}
return value.toString();
}
}

View File

@@ -0,0 +1,27 @@
package jef.expressions;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.List;
import java.util.stream.Collectors;
@Getter
@AllArgsConstructor
public class SelectExpression implements Expression {
private final List<String> fields;
private final Expression from;
private final String fromAlias;
@Override
public Type getType() {
return Type.SELECT;
}
@Override
public String toString() {
return "SELECT " + fields.stream().map(e -> e.equals("*") ? e : "`" + e + "`").collect(Collectors.joining(", ")) + " FROM "
+ (!(from instanceof TableExpression) ? "(" + from + ")" : from)
+ ((fromAlias == null || fromAlias.isBlank()) ? "" : " " + fromAlias);
}
}

View File

@@ -0,0 +1,28 @@
package jef.expressions;
import lombok.Getter;
@Getter
public class TableExpression extends ConstantExpression {
private final String name;
public TableExpression(String name) {
super(name);
this.name = name;
}
@Override
public Type getType() {
return Type.TABLE;
}
@Override
public String getValue() {
return (String) super.getValue();
}
@Override
public String toString() {
return "`" + super.toString() + "`";
}
}

View File

@@ -0,0 +1,24 @@
package jef.expressions;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public class TernaryExpression implements Expression {
private final Expression cond;
private final Expression whenTrue;
private final Expression whenFalse;
@Override
public Type getType() {
return Type.TERNARY;
}
@Override
public String toString() {
return cond
+ " ? " + (!(whenTrue instanceof ConstantExpression) ? "(" + whenTrue + ")" : whenTrue)
+ " : " + (!(whenFalse instanceof ConstantExpression) ? "(" + whenFalse + ")" : whenFalse);
}
}

View File

@@ -0,0 +1,35 @@
package jef.expressions;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public class UnaryExpression implements Expression {
private final Expression expr;
private final Operator operator;
@Override
public Type getType() {
return Type.UNARY;
}
@Override
public String toString() {
return operator + " (" + expr + ")";
}
@AllArgsConstructor
public enum Operator {
NOT("NOT"),
// NEG("-"),
// POS("+"),
;
private final String string;
@Override
public String toString() {
return string;
}
}
}

View File

@@ -0,0 +1,21 @@
package jef.expressions;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public class WhereExpression implements Expression {
private Expression queryable;
private Expression where;
@Override
public Type getType() {
return Type.WHERE;
}
@Override
public String toString() {
return queryable + " WHERE " + where;
}
}

View File

@@ -0,0 +1,89 @@
package jef.expressions.modifier;
import jef.expressions.AndExpression;
import jef.expressions.BinaryExpression;
import jef.expressions.ConstantExpression;
import jef.expressions.Expression;
import jef.expressions.FieldExpression;
import jef.expressions.OrExpression;
import jef.expressions.ParameterExpression;
import jef.expressions.SelectExpression;
import jef.expressions.TableExpression;
import jef.expressions.TernaryExpression;
import jef.expressions.UnaryExpression;
import jef.expressions.WhereExpression;
import java.util.ArrayList;
public abstract class ExpressionModifier {
public Expression modify(Expression expr) {
return switch (expr.getType()) {
case AND -> modifyAnd((AndExpression) expr);
case BINARY -> modifyBinary((BinaryExpression) expr);
case CONSTANT -> modifyConstant((ConstantExpression) expr);
case FIELD -> modifyField((FieldExpression) expr);
case OR -> modifyOr((OrExpression) expr);
case PARAMETER -> modifyParameter((ParameterExpression) expr);
case SELECT -> modifySelect((SelectExpression) expr);
case TABLE -> modifyTable((TableExpression) expr);
case TERNARY -> modifyTernary((TernaryExpression) expr);
case UNARY -> modifyUnary((UnaryExpression) expr);
case WHERE -> modifyWhere((WhereExpression) expr);
default -> throw new IllegalStateException();
};
}
public Expression modifyAnd(AndExpression expr) {
var exprs = new ArrayList<Expression>(expr.getExprs().size());
for (Expression e : expr.getExprs()) {
exprs.add(modify(e));
}
return new AndExpression(exprs);
}
public Expression modifyBinary(BinaryExpression expr) {
return new BinaryExpression(modify(expr.getLeft()), modify(expr.getRight()), expr.getOperator());
}
public Expression modifyConstant(ConstantExpression expr) {
return expr;
}
public Expression modifyField(FieldExpression expr) {
return expr;
}
public Expression modifyOr(OrExpression expr) {
var exprs = new ArrayList<Expression>(expr.getExprs().size());
for (Expression e : expr.getExprs()) {
exprs.add(modify(e));
}
return new OrExpression(exprs);
}
public Expression modifyParameter(ParameterExpression expr) {
return expr;
}
public Expression modifySelect(SelectExpression expr) {
return new SelectExpression(expr.getFields(), modify(expr.getFrom()), expr.getFromAlias());
}
public Expression modifyTable(TableExpression expr) {
return expr;
}
public Expression modifyTernary(TernaryExpression expr) {
return new TernaryExpression(modify(expr.getCond()), modify(expr.getWhenTrue()), modify(expr.getWhenFalse()));
}
public Expression modifyUnary(UnaryExpression expr) {
return new UnaryExpression(modify(expr.getExpr()), expr.getOperator());
}
public Expression modifyWhere(WhereExpression expr) {
return new WhereExpression(modify(expr.getQueryable()), modify(expr.getWhere()));
}
}

View File

@@ -0,0 +1,102 @@
package jef.expressions.modifier;
import jef.expressions.AndExpression;
import jef.expressions.BinaryExpression;
import jef.expressions.ConstantExpression;
import jef.expressions.Expression;
import jef.expressions.OrExpression;
import jef.expressions.TernaryExpression;
import jef.expressions.UnaryExpression;
import java.util.ArrayList;
public class ExpressionOptimizer extends ExpressionModifier {
@Override
public Expression modifyAnd(AndExpression expr) {
var ands = new ArrayList<Expression>(expr.getExprs().size() * 2);
//squash ands
for (Expression e : expr.getExprs()) {
if (e.getType() == Expression.Type.AND) {
ands.addAll(((AndExpression) e).getExprs());
} else {
ands.add(e);
}
}
ands.replaceAll(this::modify);
// x && false -> false
for (Expression e : ands) {
if (e == ConstantExpression.I0) {
return ConstantExpression.I0;
}
}
while (ands.remove(ConstantExpression.I1)) ;
return new AndExpression(ands);
}
@Override
public Expression modifyOr(OrExpression expr) {
var ors = new ArrayList<Expression>(expr.getExprs().size() * 2);
//squash ors
for (Expression e : expr.getExprs()) {
if (e.getType() == Expression.Type.OR) {
ors.addAll(((OrExpression) e).getExprs());
} else {
ors.add(e);
}
}
ors.replaceAll(this::modify);
// x || true -> true
for (Expression e : ors) {
if (e == ConstantExpression.I1) {
return ConstantExpression.I1;
}
}
while (ors.remove(ConstantExpression.I0)) ;
return new OrExpression(ors);
}
@Override
public Expression modifyTernary(TernaryExpression expr) {
if (expr.getWhenFalse() == ConstantExpression.I1 && expr.getWhenFalse() == ConstantExpression.I0) {
//x ? 1 : 0 -> x
return modify(expr.getCond());
} else if (expr.getWhenFalse() == ConstantExpression.I0 && expr.getWhenFalse() == ConstantExpression.I1) {
//x ? 0 : 1 -> !x
return modify(new UnaryExpression(expr.getCond(), UnaryExpression.Operator.NOT));
} else if (expr.getWhenFalse() == ConstantExpression.I0) {
//x ? y : 0 -> x && y
return modify(new AndExpression(expr.getCond(), expr.getWhenTrue()));
} else if (expr.getWhenFalse() == ConstantExpression.I1) {
//x ? y : 1 -> !x or y
return modify(new OrExpression(new UnaryExpression(expr.getCond(), UnaryExpression.Operator.NOT), expr.getWhenTrue()));
} else if (expr.getWhenTrue() instanceof TernaryExpression t && expr.getWhenFalse() == t.getWhenFalse()) {
// x ? (y ? z : u) : u -> (x && y) ? z : u
return new TernaryExpression(new AndExpression(expr.getCond(), t.getCond()), t.getWhenTrue(), t.getWhenFalse());
} else {
return super.modifyTernary(expr);
}
}
@Override
public Expression modifyUnary(UnaryExpression expr) {
if (expr.getExpr() instanceof UnaryExpression u
&& expr.getOperator() == u.getOperator()
&& expr.getOperator() == UnaryExpression.Operator.NOT) {
//!!x -> x
return modify(u.getExpr());
} else if (expr.getExpr() instanceof BinaryExpression b
&& expr.getOperator() == UnaryExpression.Operator.NOT
&& b.getOperator().isInvertible()) {
//!(a < b) -> a >= b
return new BinaryExpression(b.getLeft(), b.getRight(), b.getOperator().invert());
} else {
return super.modifyUnary(expr);
}
}
}

View File

@@ -0,0 +1,108 @@
package jef.expressions.modifier;
import jef.expressions.AndExpression;
import jef.expressions.BinaryExpression;
import jef.expressions.ConstantExpression;
import jef.expressions.Expression;
import jef.expressions.OrExpression;
import jef.expressions.TernaryExpression;
import jef.expressions.UnaryExpression;
import java.util.ArrayList;
public class ExpressionOptimizerBottomUp extends ExpressionModifier {
@Override
public Expression modifyAnd(AndExpression expr) {
var andsOpt = expr.getExprs().stream().map(this::modify).toList();
var ands = new ArrayList<Expression>(expr.getExprs().size() * 2);
//squash ands
for (Expression e : andsOpt) {
if (e.getType() == Expression.Type.AND) {
ands.addAll(((AndExpression) e).getExprs());
} else {
ands.add(e);
}
}
ands.replaceAll(this::modify);
// x && false -> false
for (Expression e : ands) {
if (e == ConstantExpression.I0) {
return ConstantExpression.I0;
}
}
while (ands.remove(ConstantExpression.I1)) ;
return new AndExpression(ands);
}
@Override
public Expression modifyOr(OrExpression expr) {
var orsOpt = expr.getExprs().stream().map(this::modify).toList();
var ors = new ArrayList<Expression>(expr.getExprs().size() * 2);
//squash ors
for (Expression e : orsOpt) {
if (e.getType() == Expression.Type.OR) {
ors.addAll(((OrExpression) e).getExprs());
} else {
ors.add(e);
}
}
ors.replaceAll(this::modify);
// x || true -> true
for (Expression e : ors) {
if (e == ConstantExpression.I1) {
return ConstantExpression.I1;
}
}
while (ors.remove(ConstantExpression.I0)) ;
return new OrExpression(ors);
}
@Override
public Expression modifyTernary(TernaryExpression expr) {
var cond = modify(expr.getCond());
var whenTrue = modify(expr.getWhenTrue());
var whenFalse = modify(expr.getWhenFalse());
if (whenTrue == ConstantExpression.I1 && whenFalse == ConstantExpression.I0) {
//x ? 1 : 0 -> x
return cond;
} else if (whenTrue == ConstantExpression.I0 && whenFalse == ConstantExpression.I1) {
//x ? 0 : 1 -> !x
return modify(new UnaryExpression(cond, UnaryExpression.Operator.NOT));
} else if (whenFalse == ConstantExpression.I0) {
//x ? y : 0 -> x && y
return modify(new AndExpression(cond, whenTrue));
} else if (whenFalse == ConstantExpression.I1) {
//x ? y : 1 -> !x or y
return modify(new OrExpression(new UnaryExpression(cond, UnaryExpression.Operator.NOT), whenTrue));
} else if (whenTrue instanceof TernaryExpression t && whenFalse == t.getWhenFalse()) {
// x ? (y ? z : u) : u -> (x && y) ? z : u
return new TernaryExpression(new AndExpression(cond, t.getCond()), t.getWhenTrue(), t.getWhenFalse());
} else {
return super.modifyTernary(expr);
}
}
@Override
public Expression modifyUnary(UnaryExpression expr) {
var inner = modify(expr.getExpr());
if (inner instanceof UnaryExpression u
&& expr.getOperator() == u.getOperator()
&& expr.getOperator() == UnaryExpression.Operator.NOT) {
//!!x -> x
return modify(u.getExpr());
} else if (inner instanceof BinaryExpression b
&& expr.getOperator() == UnaryExpression.Operator.NOT
&& b.getOperator().isInvertible()) {
//!(a < b) -> a >= b
return new BinaryExpression(b.getLeft(), b.getRight(), b.getOperator().invert());
} else {
return super.modifyUnary(expr);
}
}
}

View File

@@ -0,0 +1,19 @@
package jef.expressions.modifier;
import jef.expressions.Expression;
import jef.expressions.FieldExpression;
public class TableAliasInjector extends ExpressionModifier {
private final String tableAlias;
private final String prefix;
public TableAliasInjector(String tableAlias) {
this.tableAlias = tableAlias;
this.prefix = (tableAlias == null || tableAlias.isBlank()) ? "" : tableAlias + ".";
}
@Override
public Expression modifyField(FieldExpression expr) {
return new FieldExpression(prefix + expr.getName());
}
}

View File

@@ -0,0 +1,20 @@
package jef.expressions.modifier;
import jef.expressions.AndExpression;
import jef.expressions.BinaryExpression;
import jef.expressions.ConstantExpression;
import jef.expressions.Expression;
import jef.expressions.OrExpression;
import jef.expressions.TernaryExpression;
import jef.expressions.UnaryExpression;
import java.util.ArrayList;
public class TernaryRewriter extends ExpressionModifier {
@Override
public Expression modifyTernary(TernaryExpression expr) {
return new OrExpression(new AndExpression(expr.getCond(), expr.getWhenTrue()),
new AndExpression(new UnaryExpression(expr.getCond(), UnaryExpression.Operator.NOT), expr.getWhenFalse()));
// return new OrExpression(new AndExpression(expr.getCond(), expr.getWhenTrue()), expr.getWhenFalse());
}
}

View File

@@ -0,0 +1,128 @@
package jef.expressions.visitors;
import jef.expressions.AndExpression;
import jef.expressions.BinaryExpression;
import jef.expressions.ConstantExpression;
import jef.expressions.FieldExpression;
import jef.expressions.OrExpression;
import jef.expressions.ParameterExpression;
import jef.expressions.SelectExpression;
import jef.expressions.TableExpression;
import jef.expressions.TernaryExpression;
import jef.expressions.UnaryExpression;
import jef.expressions.WhereExpression;
import java.util.Collection;
import java.util.stream.Collectors;
public class DebugExpressionVisitor extends ExpressionVisitor {
private int indent = 0;
@Override
public void visitAnd(AndExpression expr) {
for (int i = 0; i < expr.getExprs().size(); i++) {
indent++;
visit(expr.getExprs().get(i));
indent--;
if (i + 1 < expr.getExprs().size())
System.out.println(i() + "AND");
}
}
@Override
public void visitBinary(BinaryExpression expr) {
indent++;
visit(expr.getLeft());
indent--;
System.out.println(i() + expr.getOperator());
indent++;
visit(expr.getRight());
indent--;
}
@Override
public void visitConstant(ConstantExpression expr) {
System.out.println(i() + expr.getValue());
}
@Override
public void visitField(FieldExpression expr) {
System.out.println(i() + expr.getName());
}
@Override
public void visitOr(OrExpression expr) {
for (int i = 0; i < expr.getExprs().size(); i++) {
indent++;
visit(expr.getExprs().get(i));
indent--;
if (i + 1 < expr.getExprs().size())
System.out.println(i() + "OR");
}
}
@Override
public void visitParameter(ParameterExpression expr) {
if (expr.getValue() instanceof Collection c) {
System.out.println(i() + c.stream().map(String::valueOf).collect(Collectors.joining(",")));
} else {
System.out.println(i() + expr.getValue());
}
}
@Override
public void visitSelect(SelectExpression expr) {
var table = expr.getFrom() instanceof TableExpression;
var tableName = table ? ((TableExpression) expr.getFrom()).getName() : null;
var tableAlias = (expr.getFromAlias() == null || expr.getFromAlias().isBlank()) ? "" : " " + expr.getFromAlias();
System.out.println(i() + "SELECT " + expr.getFields().stream().collect(Collectors.joining(", "))
+ " FROM" + (!table ? " (" : tableName + " " + tableAlias));
if (!table) {
indent++;
visit(expr.getFrom());
indent--;
System.out.println(i() + ")" + tableAlias);
}
}
@Override
public void visitTable(TableExpression expr) {
System.out.println(i() + expr.getValue());
}
@Override
public void visitTernary(TernaryExpression expr) {
indent++;
visit(expr.getCond());
indent--;
System.out.println(i() + "?");
indent++;
visit(expr.getWhenTrue());
indent--;
System.out.println(i() + ":");
indent++;
visit(expr.getWhenFalse());
indent--;
}
@Override
public void visitUnary(UnaryExpression expr) {
System.out.println(i() + expr.getOperator());
indent++;
visit(expr.getExpr());
indent--;
}
@Override
public void visitWhere(WhereExpression expr) {
visit(expr.getQueryable());
System.out.println(i() + "WHERE");
indent++;
visit(expr.getWhere());
indent--;
}
private String i() {
return " ".repeat(indent);
}
}

View File

@@ -0,0 +1,81 @@
package jef.expressions.visitors;
import jef.expressions.AndExpression;
import jef.expressions.BinaryExpression;
import jef.expressions.ConstantExpression;
import jef.expressions.Expression;
import jef.expressions.FieldExpression;
import jef.expressions.OrExpression;
import jef.expressions.ParameterExpression;
import jef.expressions.SelectExpression;
import jef.expressions.TableExpression;
import jef.expressions.TernaryExpression;
import jef.expressions.UnaryExpression;
import jef.expressions.WhereExpression;
public abstract class ExpressionVisitor {
public void visit(Expression expr) {
switch (expr.getType()) {
case AND -> visitAnd((AndExpression) expr);
case BINARY -> visitBinary((BinaryExpression) expr);
case CONSTANT -> visitConstant((ConstantExpression) expr);
case FIELD -> visitField((FieldExpression) expr);
case OR -> visitOr((OrExpression) expr);
case PARAMETER -> visitParameter((ParameterExpression) expr);
case SELECT -> visitSelect((SelectExpression) expr);
case TABLE -> visitTable((TableExpression) expr);
case TERNARY -> visitTernary((TernaryExpression) expr);
case UNARY -> visitUnary((UnaryExpression) expr);
case WHERE -> visitWhere((WhereExpression) expr);
default -> throw new IllegalStateException();
}
}
public void visitAnd(AndExpression expr) {
for (Expression e : expr.getExprs()) {
visit(e);
}
}
public void visitBinary(BinaryExpression expr) {
visit(expr.getLeft());
visit(expr.getRight());
}
public void visitConstant(ConstantExpression expr) {
}
public void visitField(FieldExpression expr) {
}
public void visitOr(OrExpression expr) {
for (Expression e : expr.getExprs()) {
visit(e);
}
}
public void visitParameter(ParameterExpression expr) {
}
public void visitSelect(SelectExpression expr) {
visit(expr.getFrom());
}
public void visitTable(TableExpression expr) {
}
public void visitTernary(TernaryExpression expr) {
visit(expr.getCond());
visit(expr.getWhenTrue());
visit(expr.getWhenFalse());
}
public void visitUnary(UnaryExpression expr) {
visit(expr.getExpr());
}
public void visitWhere(WhereExpression expr) {
visit(expr.getQueryable());
visit(expr.getWhere());
}
}