wip
This commit is contained in:
@@ -4,19 +4,24 @@ import jef.expressions.Expression;
|
||||
import jef.expressions.SelectExpression;
|
||||
import jef.expressions.TableExpression;
|
||||
import jef.expressions.selectable.DatabaseSelectAllExpression;
|
||||
import jef.model.DbContext;
|
||||
import jef.serializable.SerializableObject;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Spliterator;
|
||||
|
||||
public class DbSet<T extends SerializableObject> implements Queryable<T> {
|
||||
@Getter
|
||||
private final DbContext context;
|
||||
@Getter
|
||||
private final Class<T> clazz;
|
||||
private final String table;
|
||||
|
||||
public DbSet(Class<T> clazz, String table) {
|
||||
public DbSet(DbContext context, Class<T> clazz, String table) {
|
||||
this.context = context;
|
||||
this.clazz = clazz;
|
||||
this.table = table;
|
||||
}
|
||||
@@ -36,6 +41,23 @@ public class DbSet<T extends SerializableObject> implements Queryable<T> {
|
||||
return "SELECT * FROM `" + table + "`";
|
||||
}
|
||||
|
||||
@Override
|
||||
public DbSet<T> originalSet() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public void add(T entity) throws SQLException {
|
||||
context.getDatabase().add(context, clazz, entity);
|
||||
}
|
||||
|
||||
public void update(T entity) throws SQLException {
|
||||
context.getDatabase().update(context, clazz, entity);
|
||||
}
|
||||
|
||||
public void delete(T entity) throws SQLException {
|
||||
context.getDatabase().delete(context, clazz, entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return null;
|
||||
|
||||
@@ -6,13 +6,15 @@ import jef.operations.FilterOp;
|
||||
import jef.operations.LimitOp;
|
||||
import jef.operations.SortOp;
|
||||
import jef.serializable.SerializableFunction;
|
||||
import jef.serializable.SerializableObject;
|
||||
import jef.serializable.SerializablePredicate;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Spliterator;
|
||||
|
||||
public interface Queryable<T extends Serializable> {
|
||||
public interface Queryable<T extends SerializableObject> {
|
||||
|
||||
//TODO documentation
|
||||
//TODO table alias thing still not ready
|
||||
@@ -22,6 +24,8 @@ public interface Queryable<T extends Serializable> {
|
||||
|
||||
String toString();
|
||||
|
||||
DbSet<T> originalSet();
|
||||
|
||||
//stream functions
|
||||
default Iterator<T> iterator() {
|
||||
return null;
|
||||
@@ -131,6 +135,9 @@ public interface Queryable<T extends Serializable> {
|
||||
// default Object[] toArray() {
|
||||
// return new Object[0];
|
||||
// }
|
||||
default List<T> toList() throws SQLException {
|
||||
return originalSet().getContext().getDatabase().queryExpression(originalSet().getContext(), originalSet().getClazz(), getExpression());
|
||||
}
|
||||
//
|
||||
// default <A> A[] toArray(IntFunction<A[]> intFunction) {
|
||||
// return null;
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package jef;
|
||||
|
||||
import jef.expressions.Expression;
|
||||
import jef.serializable.SerializableObject;
|
||||
import jef.serializable.SerializablePredicate;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Iterator;
|
||||
import java.util.Spliterator;
|
||||
|
||||
public class QueryableProxy<T extends Serializable> implements Queryable<T> {
|
||||
public class QueryableProxy<T extends SerializableObject> implements Queryable<T> {
|
||||
private final Queryable<T> delegate;
|
||||
|
||||
public QueryableProxy(Queryable<T> delegate) {
|
||||
@@ -24,6 +24,11 @@ public class QueryableProxy<T extends Serializable> implements Queryable<T> {
|
||||
return delegate.getExpression();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DbSet<T> originalSet() {
|
||||
return delegate.originalSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return delegate.iterator();
|
||||
|
||||
26
core/src/main/java/jef/asm/access/ClassAnalyzer.java
Normal file
26
core/src/main/java/jef/asm/access/ClassAnalyzer.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package jef.asm.access;
|
||||
|
||||
import jef.asm.access.model.ClassDescription;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class ClassAnalyzer {
|
||||
public ClassDescription analyze(Class clazz) {
|
||||
return analyzeClass(clazz);
|
||||
}
|
||||
|
||||
private ClassDescription analyzeClass(Class clazz) {
|
||||
try (var is = clazz.getClassLoader().getResourceAsStream(clazz.getName().replace(".", "/") + ".class")) {
|
||||
var result = new ClassDescription[1];
|
||||
var byteCode = is.readAllBytes();
|
||||
var reader = new ClassReader(byteCode);
|
||||
var visitor = new ClassAnalyzerVisitor(Opcodes.ASM9, description -> result[0] = description);
|
||||
reader.accept(visitor, 0);
|
||||
return result[0];
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
69
core/src/main/java/jef/asm/access/ClassAnalyzerVisitor.java
Normal file
69
core/src/main/java/jef/asm/access/ClassAnalyzerVisitor.java
Normal file
@@ -0,0 +1,69 @@
|
||||
package jef.asm.access;
|
||||
|
||||
import jef.asm.access.model.ClassDescription;
|
||||
import jef.asm.access.model.ConstructorDescription;
|
||||
import jef.asm.access.model.FieldDescription;
|
||||
import jef.asm.access.model.GetterDescription;
|
||||
import jef.asm.access.model.SetterDescription;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
class ClassAnalyzerVisitor extends ClassVisitor {
|
||||
private final Consumer<ClassDescription> callback;
|
||||
|
||||
private String className;
|
||||
private String superClassName;
|
||||
private final List<FieldDescription> declaredFields = new ArrayList<>();
|
||||
private final List<ConstructorDescription> declaredConstructor = new ArrayList<>();
|
||||
private final List<GetterDescription> declaredGetters = new ArrayList<>();
|
||||
private final List<SetterDescription> declaredSetters = new ArrayList<>();
|
||||
|
||||
protected ClassAnalyzerVisitor(int api, Consumer<ClassDescription> callback) {
|
||||
super(api);
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
protected ClassAnalyzerVisitor(int api, ClassVisitor classVisitor, Consumer<ClassDescription> callback) {
|
||||
super(api, classVisitor);
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
|
||||
className = name.replace("/", ".");
|
||||
superClassName = superName.replace("/", ".");
|
||||
super.visit(version, access, name, signature, superName, interfaces);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
|
||||
declaredFields.add(new FieldDescription(className, name));
|
||||
return super.visitField(access, name, descriptor, signature, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
|
||||
var type = Type.getMethodType(descriptor);
|
||||
var returnClassName = type.getReturnType().getClassName();
|
||||
var parameterClassNames = Arrays.stream(type.getArgumentTypes()).map(Type::getClassName).toArray(String[]::new);
|
||||
return new MethodAnalyzerVisitor(Opcodes.ASM9, className, name, returnClassName, parameterClassNames, entityAccess -> {
|
||||
declaredConstructor.addAll(entityAccess.getDeclaredConstructors());
|
||||
declaredGetters.addAll(entityAccess.getDeclaredGetters());
|
||||
declaredSetters.addAll(entityAccess.getDeclaredSetters());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
super.visitEnd();
|
||||
callback.accept(new ClassDescription(className, superClassName, declaredFields, declaredConstructor, declaredGetters, declaredSetters));
|
||||
}
|
||||
}
|
||||
308
core/src/main/java/jef/asm/access/MethodAnalyzerVisitor.java
Normal file
308
core/src/main/java/jef/asm/access/MethodAnalyzerVisitor.java
Normal file
@@ -0,0 +1,308 @@
|
||||
package jef.asm.access;
|
||||
|
||||
import jef.asm.access.model.ClassDescription;
|
||||
import jef.asm.access.model.ConstructorDescription;
|
||||
import jef.asm.access.model.ConstructorParameterDescription;
|
||||
import jef.asm.access.model.GetterDescription;
|
||||
import jef.asm.access.model.SetterDescription;
|
||||
import jef.asm.access.model.SuperConstructorParameterDescription;
|
||||
import lombok.Getter;
|
||||
import org.objectweb.asm.Handle;
|
||||
import org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@Getter
|
||||
public class MethodAnalyzerVisitor extends MethodVisitor {//TODO verify param count
|
||||
private final Consumer<ClassDescription> callback;
|
||||
private final String methodClassName;
|
||||
private final String methodName;
|
||||
private final String returnClassName;
|
||||
private final String[] parameterClassNames;
|
||||
|
||||
private List<ConstructorParameterDescription> constructorParameterDescriptions = new ArrayList<>();
|
||||
private List<SuperConstructorParameterDescription> superConstructorParameterDescriptions = new ArrayList<>();
|
||||
private Stack<Integer> varIndexStack = new Stack<>();
|
||||
private String fieldDeclaringClassName = null;
|
||||
private String fieldName = null;
|
||||
|
||||
private ConstructorSteps constructorStep = ConstructorSteps.INIT;
|
||||
private GetterSteps getterStep = GetterSteps.INIT;
|
||||
private SetterSteps setterStep = SetterSteps.INIT;
|
||||
|
||||
enum ConstructorSteps {
|
||||
INIT,
|
||||
CODE,
|
||||
PRE_SUPER_INIT_ALOAD_0,
|
||||
PRE_SUPER_INIT_VAR_LOAD,
|
||||
SUPER_INIT,
|
||||
ALOAD_0,
|
||||
VAR_LOAD,
|
||||
PUT_FIELD,
|
||||
RETURN,
|
||||
INVALID
|
||||
}
|
||||
|
||||
enum GetterSteps {
|
||||
INIT,
|
||||
CODE,
|
||||
ALOAD_0,
|
||||
GET_FIELD,
|
||||
RETURN,
|
||||
INVALID
|
||||
}
|
||||
|
||||
enum SetterSteps {
|
||||
INIT,
|
||||
CODE,
|
||||
ALOAD_0,
|
||||
VAR_LOAD,
|
||||
PUT_FIELD,
|
||||
RETURN,
|
||||
INVALID
|
||||
}
|
||||
|
||||
protected MethodAnalyzerVisitor(int api, String methodClassName, String methodName, String returnClassName, String[] parameterClassNames, Consumer<ClassDescription> callback) {
|
||||
super(api);
|
||||
this.methodClassName = methodClassName;
|
||||
this.methodName = methodName;
|
||||
this.returnClassName = returnClassName;
|
||||
this.parameterClassNames = parameterClassNames;
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCode() {
|
||||
constructorStep = constructorStep == ConstructorSteps.INIT ? ConstructorSteps.CODE : ConstructorSteps.INVALID;
|
||||
getterStep = getterStep == GetterSteps.INIT ? GetterSteps.CODE : GetterSteps.INVALID;
|
||||
setterStep = setterStep == SetterSteps.INIT ? SetterSteps.CODE : SetterSteps.INVALID;
|
||||
super.visitCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFrame(int type, int numLocal, Object[] local, int numStack, Object[] stack) {
|
||||
constructorStep = ConstructorSteps.INVALID;
|
||||
getterStep = GetterSteps.INVALID;
|
||||
setterStep = SetterSteps.INVALID;
|
||||
super.visitFrame(type, numLocal, local, numStack, stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInsn(int opcode) {
|
||||
if (Set.of(Opcodes.IRETURN, Opcodes.LRETURN, Opcodes.FRETURN, Opcodes.DRETURN, Opcodes.ARETURN).contains(opcode)) {
|
||||
getterStep = getterStep == GetterSteps.GET_FIELD ? GetterSteps.RETURN : GetterSteps.INVALID;
|
||||
} else {
|
||||
getterStep = GetterSteps.INVALID;
|
||||
}
|
||||
if (opcode == Opcodes.RETURN) {
|
||||
constructorStep = constructorStep == ConstructorSteps.PUT_FIELD ? ConstructorSteps.RETURN : ConstructorSteps.INVALID;
|
||||
setterStep = setterStep == SetterSteps.PUT_FIELD ? SetterSteps.RETURN : SetterSteps.INVALID;
|
||||
} else {
|
||||
constructorStep = ConstructorSteps.INVALID;
|
||||
setterStep = SetterSteps.INVALID;
|
||||
}
|
||||
super.visitInsn(opcode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIntInsn(int opcode, int operand) {
|
||||
constructorStep = ConstructorSteps.INVALID;
|
||||
getterStep = GetterSteps.INVALID;
|
||||
setterStep = SetterSteps.INVALID;
|
||||
super.visitIntInsn(opcode, operand);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitVarInsn(int opcode, int varIndex) {
|
||||
if (Set.of(Opcodes.ILOAD, Opcodes.LLOAD, Opcodes.FLOAD, Opcodes.DLOAD, Opcodes.ALOAD).contains(opcode)) {
|
||||
varIndexStack.push(varIndex);
|
||||
}
|
||||
if (opcode == Opcodes.ALOAD && varIndex == 0) {
|
||||
if (constructorStep == ConstructorSteps.CODE) {
|
||||
constructorStep = ConstructorSteps.PRE_SUPER_INIT_ALOAD_0;
|
||||
} else if (constructorStep == ConstructorSteps.SUPER_INIT || constructorStep == ConstructorSteps.PUT_FIELD) {
|
||||
constructorStep = ConstructorSteps.ALOAD_0;
|
||||
} else {
|
||||
constructorStep = ConstructorSteps.INVALID;
|
||||
}
|
||||
} else if (Set.of(Opcodes.ILOAD, Opcodes.LLOAD, Opcodes.FLOAD, Opcodes.DLOAD, Opcodes.ALOAD).contains(opcode)) {
|
||||
if (constructorStep == ConstructorSteps.PRE_SUPER_INIT_ALOAD_0) {
|
||||
constructorStep = ConstructorSteps.PRE_SUPER_INIT_VAR_LOAD;
|
||||
} else if (constructorStep == ConstructorSteps.PRE_SUPER_INIT_VAR_LOAD) {
|
||||
constructorStep = ConstructorSteps.PRE_SUPER_INIT_VAR_LOAD;
|
||||
} else if (constructorStep == ConstructorSteps.ALOAD_0) {
|
||||
constructorStep = ConstructorSteps.VAR_LOAD;
|
||||
} else {
|
||||
constructorStep = ConstructorSteps.INVALID;
|
||||
}
|
||||
} else {
|
||||
constructorStep = ConstructorSteps.INVALID;
|
||||
}
|
||||
if (opcode == Opcodes.ALOAD && varIndex == 0) {
|
||||
getterStep = getterStep == GetterSteps.CODE ? GetterSteps.ALOAD_0 : GetterSteps.INVALID;
|
||||
} else {
|
||||
getterStep = GetterSteps.INVALID;
|
||||
}
|
||||
if (opcode == Opcodes.ALOAD && varIndex == 0) {
|
||||
setterStep = setterStep == SetterSteps.CODE ? SetterSteps.ALOAD_0 : SetterSteps.INVALID;
|
||||
} else if (Set.of(Opcodes.ILOAD, Opcodes.LLOAD, Opcodes.FLOAD, Opcodes.DLOAD, Opcodes.ALOAD).contains(opcode)) {
|
||||
setterStep = setterStep == SetterSteps.ALOAD_0 ? SetterSteps.VAR_LOAD : SetterSteps.INVALID;
|
||||
} else {
|
||||
setterStep = SetterSteps.INVALID;
|
||||
}
|
||||
super.visitVarInsn(opcode, varIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeInsn(int opcode, String type) {
|
||||
constructorStep = ConstructorSteps.INVALID;
|
||||
getterStep = GetterSteps.INVALID;
|
||||
setterStep = SetterSteps.INVALID;
|
||||
super.visitTypeInsn(opcode, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFieldInsn(int opcode, String owner, String name, String descriptor) {
|
||||
var lastLoadedVarIndex = -1;
|
||||
if (opcode == Opcodes.PUTFIELD) {
|
||||
lastLoadedVarIndex = varIndexStack.pop();
|
||||
varIndexStack.pop();
|
||||
constructorStep = constructorStep == ConstructorSteps.VAR_LOAD ? ConstructorSteps.PUT_FIELD : ConstructorSteps.INVALID;
|
||||
getterStep = GetterSteps.INVALID;
|
||||
setterStep = setterStep == SetterSteps.VAR_LOAD ? SetterSteps.PUT_FIELD : SetterSteps.INVALID;
|
||||
} else if (opcode == Opcodes.GETFIELD) {
|
||||
lastLoadedVarIndex = varIndexStack.pop();
|
||||
constructorStep = ConstructorSteps.INVALID;
|
||||
getterStep = getterStep == GetterSteps.ALOAD_0 ? GetterSteps.GET_FIELD : GetterSteps.INVALID;
|
||||
setterStep = SetterSteps.INVALID;
|
||||
} else {
|
||||
constructorStep = ConstructorSteps.INVALID;
|
||||
getterStep = GetterSteps.INVALID;
|
||||
setterStep = SetterSteps.INVALID;
|
||||
}
|
||||
this.fieldDeclaringClassName = owner.replace("/", ".");
|
||||
this.fieldName = name;
|
||||
this.constructorParameterDescriptions.add(new ConstructorParameterDescription(lastLoadedVarIndex - 1, this.fieldDeclaringClassName, this.fieldName)); //lastLoadedVarIndex - 1 because arg 0 of an instance function is always this
|
||||
super.visitFieldInsn(opcode, owner, name, descriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
|
||||
var argIndexes = new ArrayList<Integer>();
|
||||
for (var i = 0; i < Type.getArgumentTypes(descriptor).length; i++) {
|
||||
argIndexes.add(0, varIndexStack.pop());
|
||||
}
|
||||
varIndexStack.pop(); // also pop ALOAD0
|
||||
if (opcode == Opcodes.INVOKESPECIAL && name.equals("<init>") //TODO does it have to be called '<init>' or is this just convention
|
||||
&& Set.of(ConstructorSteps.PRE_SUPER_INIT_ALOAD_0, ConstructorSteps.PRE_SUPER_INIT_VAR_LOAD).contains(constructorStep)) {
|
||||
for (int i = 0; i < argIndexes.size(); i++) {
|
||||
superConstructorParameterDescriptions.add(new SuperConstructorParameterDescription(argIndexes.get(i), i));
|
||||
}
|
||||
constructorStep = ConstructorSteps.SUPER_INIT;
|
||||
} else {
|
||||
constructorStep = ConstructorSteps.INVALID;
|
||||
}
|
||||
getterStep = GetterSteps.INVALID;
|
||||
setterStep = SetterSteps.INVALID;
|
||||
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInvokeDynamicInsn(String name, String descriptor, Handle bootstrapMethodHandle, Object... bootstrapMethodArguments) {
|
||||
constructorStep = ConstructorSteps.INVALID;
|
||||
getterStep = GetterSteps.INVALID;
|
||||
setterStep = SetterSteps.INVALID;
|
||||
super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJumpInsn(int opcode, Label label) {
|
||||
constructorStep = ConstructorSteps.INVALID;
|
||||
getterStep = GetterSteps.INVALID;
|
||||
setterStep = SetterSteps.INVALID;
|
||||
super.visitJumpInsn(opcode, label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLabel(Label label) {
|
||||
// constructorStep = ConstructorSteps.INVALID;
|
||||
// getterStep = GetterSteps.INVALID;
|
||||
// setterStep = SetterSteps.INVALID;
|
||||
super.visitLabel(label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLdcInsn(Object value) {
|
||||
constructorStep = ConstructorSteps.INVALID;
|
||||
getterStep = GetterSteps.INVALID;
|
||||
setterStep = SetterSteps.INVALID;
|
||||
super.visitLdcInsn(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIincInsn(int varIndex, int increment) {
|
||||
constructorStep = ConstructorSteps.INVALID;
|
||||
getterStep = GetterSteps.INVALID;
|
||||
setterStep = SetterSteps.INVALID;
|
||||
super.visitIincInsn(varIndex, increment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) {
|
||||
constructorStep = ConstructorSteps.INVALID;
|
||||
getterStep = GetterSteps.INVALID;
|
||||
setterStep = SetterSteps.INVALID;
|
||||
super.visitTableSwitchInsn(min, max, dflt, labels);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
|
||||
constructorStep = ConstructorSteps.INVALID;
|
||||
getterStep = GetterSteps.INVALID;
|
||||
setterStep = SetterSteps.INVALID;
|
||||
super.visitLookupSwitchInsn(dflt, keys, labels);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMultiANewArrayInsn(String descriptor, int numDimensions) {
|
||||
constructorStep = ConstructorSteps.INVALID;
|
||||
getterStep = GetterSteps.INVALID;
|
||||
setterStep = SetterSteps.INVALID;
|
||||
super.visitMultiANewArrayInsn(descriptor, numDimensions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
|
||||
constructorStep = ConstructorSteps.INVALID;
|
||||
getterStep = GetterSteps.INVALID;
|
||||
setterStep = SetterSteps.INVALID;
|
||||
super.visitTryCatchBlock(start, end, handler, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLocalVariable(String name, String descriptor, String signature, Label start, Label end, int index) {
|
||||
super.visitLocalVariable(name, descriptor, signature, start, end, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMaxs(int maxStack, int maxLocals) {
|
||||
super.visitMaxs(maxStack, maxLocals);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
super.visitEnd();
|
||||
List<ConstructorDescription> constructors = constructorStep == ConstructorSteps.RETURN ? List.of(new ConstructorDescription(constructorParameterDescriptions, superConstructorParameterDescriptions)) : List.of();
|
||||
List<GetterDescription> getters = getterStep == GetterSteps.RETURN ? List.of(new GetterDescription(methodClassName, methodName, returnClassName, parameterClassNames, fieldDeclaringClassName, fieldName)) : List.of();
|
||||
List<SetterDescription> setters = setterStep == SetterSteps.RETURN ? List.of(new SetterDescription(methodClassName, methodName, returnClassName, parameterClassNames, fieldDeclaringClassName, fieldName)) : List.of();
|
||||
var access = new ClassDescription(null, null, null, constructors, getters, setters);
|
||||
callback.accept(access);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package jef.asm.access.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public class ClassDescription {
|
||||
private final String className;
|
||||
private final String superClassName;
|
||||
private final List<FieldDescription> declaredFields;
|
||||
private final List<ConstructorDescription> declaredConstructors;
|
||||
private final List<GetterDescription> declaredGetters;
|
||||
private final List<SetterDescription> declaredSetters;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ClassDescription{" +
|
||||
"className='" + className + '\'' +
|
||||
", superClassName='" + superClassName + '\'' +
|
||||
", declaredFields=" + declaredFields +
|
||||
", declaredConstructors=" + declaredConstructors +
|
||||
", declaredGetters=" + declaredGetters +
|
||||
", declaredSetters=" + declaredSetters +
|
||||
'}';
|
||||
}
|
||||
|
||||
public String toStringFriendly() {
|
||||
return "ClassAccessDescription{\n"
|
||||
+ " className: " + className + '\n'
|
||||
+ " superClassName: " + superClassName + '\n'
|
||||
+ " declaredFields: " + declaredFields + '\n'
|
||||
+ " declaredConstructors:\n" + declaredConstructors.stream().map(e -> " " + e.toString() + '\n').collect(Collectors.joining())
|
||||
+ " declaredGetters:\n" + declaredGetters.stream().map(e -> " " + e.toString() + '\n').collect(Collectors.joining())
|
||||
+ " declaredSetters:\n" + declaredSetters.stream().map(e -> " " + e.toString()+ '\n').collect(Collectors.joining())
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package jef.asm.access.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@ToString
|
||||
public class ConstructorDescription {
|
||||
private final List<ConstructorParameterDescription> constructorParameterDescriptions;
|
||||
private final List<SuperConstructorParameterDescription> superConstructorParameterDescriptions;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package jef.asm.access.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@ToString
|
||||
public class ConstructorParameterDescription {
|
||||
private final int parameterIndex;
|
||||
private final String declaringClassName;
|
||||
private final String fieldName;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package jef.asm.access.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@ToString
|
||||
public class FieldDescription {
|
||||
private final String fieldDeclaringClassName;
|
||||
private final String fieldName;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package jef.asm.access.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@ToString
|
||||
public class GetterDescription {
|
||||
private final String methodDeclaringClassName;
|
||||
private final String methodName;
|
||||
private final String methodReturnClassName;
|
||||
private final String[] methodParameterClassNames;
|
||||
private final String fieldDeclaringClassName;
|
||||
private final String fieldName;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package jef.asm.access.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@ToString
|
||||
public class SetterDescription {
|
||||
private final String methodDeclaringClassName;
|
||||
private final String methodName;
|
||||
private final String methodReturnClassName;
|
||||
private final String[] methodParameterClassNames;
|
||||
private final String fieldDeclaringClassName;
|
||||
private final String fieldName;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package jef.asm.access.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@ToString
|
||||
public class SuperConstructorParameterDescription {
|
||||
private final int constructorParameterIndex;
|
||||
private final int superConstructorParameterIndex;
|
||||
}
|
||||
@@ -40,7 +40,7 @@ public abstract class DbContext {
|
||||
f.setAccessible(true);
|
||||
Clazz anno = f.getAnnotation(Clazz.class);
|
||||
try {
|
||||
f.set(this, new DbSet(anno.value(), f.getName()));//TODO use table name from modelbuilder
|
||||
f.set(this, new DbSet(this, anno.value(), f.getName()));//TODO use table name from modelbuilder
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package jef.operations;
|
||||
|
||||
import jef.DbSet;
|
||||
import jef.Queryable;
|
||||
import jef.asm.AsmParseException;
|
||||
import jef.asm.OptimizedAsmParser;
|
||||
@@ -8,13 +9,13 @@ import jef.expressions.SelectExpression;
|
||||
import jef.expressions.WhereExpression;
|
||||
import jef.expressions.modifier.TableAliasInjector;
|
||||
import jef.expressions.selectable.DatabaseSelectAllExpression;
|
||||
import jef.serializable.SerializableObject;
|
||||
import jef.serializable.SerializablePredicate;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class FilterOp<T extends Serializable> implements Queryable<T>, Operation<T> {
|
||||
public class FilterOp<T extends SerializableObject> implements Queryable<T>, Operation<T> {
|
||||
|
||||
private final Queryable<T> queryable;
|
||||
private final Predicate<? super T> predicate;
|
||||
@@ -50,4 +51,9 @@ public class FilterOp<T extends Serializable> implements Queryable<T>, Operation
|
||||
public String toString() {
|
||||
return getExpression().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DbSet<T> originalSet() {
|
||||
return queryable.originalSet();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
package jef.operations;
|
||||
|
||||
import jef.DbSet;
|
||||
import jef.Queryable;
|
||||
import jef.expressions.Expression;
|
||||
import jef.expressions.LimitExpression;
|
||||
import jef.expressions.SelectExpression;
|
||||
import jef.expressions.selectable.DatabaseSelectAllExpression;
|
||||
import jef.serializable.SerializableObject;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
public class LimitOp<T extends Serializable> implements Queryable<T> {
|
||||
public class LimitOp<T extends SerializableObject> implements Queryable<T> {
|
||||
private final Queryable<T> queryable;
|
||||
private Long start;
|
||||
private Long count;
|
||||
@@ -35,6 +36,11 @@ public class LimitOp<T extends Serializable> implements Queryable<T> {
|
||||
return getExpression().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DbSet<T> originalSet() {
|
||||
return queryable.originalSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Queryable<T> limit(long l) {
|
||||
count = l;
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
package jef.operations;
|
||||
|
||||
import jef.Queryable;
|
||||
import jef.serializable.SerializableObject;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public interface Operation<T extends Serializable> extends Queryable<T> {
|
||||
public interface Operation<T extends SerializableObject> extends Queryable<T> {//TODO is this class required
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package jef.operations;
|
||||
|
||||
import jef.DbSet;
|
||||
import jef.Queryable;
|
||||
import jef.asm.AsmParseException;
|
||||
import jef.asm.AsmParser;
|
||||
@@ -13,14 +14,14 @@ import jef.expressions.modifier.TableAliasInjector;
|
||||
import jef.expressions.modifier.TernaryRewriter;
|
||||
import jef.expressions.selectable.DatabaseSelectAllExpression;
|
||||
import jef.serializable.SerializableFunction;
|
||||
import jef.serializable.SerializableObject;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class SortOp<T extends Serializable> implements Queryable<T> {
|
||||
public class SortOp<T extends SerializableObject> implements Queryable<T> {
|
||||
private final Queryable<T> queryable;
|
||||
private final List<OrderExpression.Sort> sorts = new ArrayList<>();
|
||||
|
||||
@@ -45,6 +46,11 @@ public class SortOp<T extends Serializable> implements Queryable<T> {
|
||||
return getExpression().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DbSet<T> originalSet() {
|
||||
return queryable.originalSet();
|
||||
}
|
||||
|
||||
public SortOp<T> thenSorted(SerializableFunction<? super T, ?> fieldSelector) {
|
||||
var f = parseFunction(fieldSelector);
|
||||
this.sorts.add(new OrderExpression.Sort(f, OrderExpression.SortDirection.ASCENDING));
|
||||
|
||||
@@ -1,25 +1,96 @@
|
||||
package jef.platform.base;
|
||||
|
||||
import jef.MigrationException;
|
||||
import jef.expressions.Expression;
|
||||
import jef.model.DbContext;
|
||||
import jef.model.DbFieldBuilder;
|
||||
import jef.model.ModelBuilder;
|
||||
import jef.serializable.SerializableObject;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public abstract class Database {
|
||||
// private final DatabaseConfiguration config;
|
||||
protected final Connection connection;
|
||||
protected final DatabaseOptions options;
|
||||
|
||||
public abstract void migrate() throws MigrationException;
|
||||
|
||||
// public ResultSet executeRaw(String s) throws SQLException {
|
||||
// try (var stmt = connection.prepareStatement(s)) {
|
||||
// try (var res = stmt.executeQuery()) {
|
||||
// return res;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
public abstract <T extends SerializableObject> List<T> queryExpression(DbContext context, Class<T> clazz, Expression expression) throws SQLException;
|
||||
|
||||
public <T extends SerializableObject> List<T> queryRaw(DbContext context, Class<T> clazz, String query) throws SQLException {
|
||||
var modelBuilder = ModelBuilder.from(context.getClass());
|
||||
var entity = modelBuilder.entity(clazz);
|
||||
var fields = entity.fields();
|
||||
try (var stmt = connection.prepareStatement(query)) {
|
||||
return queryRaw(stmt, clazz, fields);
|
||||
}
|
||||
}
|
||||
|
||||
protected <T extends SerializableObject> List<T> queryRaw(PreparedStatement stmt, Class<T> clazz, List<DbFieldBuilder<?>> fields) throws SQLException {
|
||||
try (var result = stmt.executeQuery()) {
|
||||
var ret = new ArrayList<T>();
|
||||
while (result.next()) {
|
||||
ret.add(readRow(result, clazz, fields));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
protected <T extends SerializableObject> T readRow(ResultSet res, Class<T> clazz, List<DbFieldBuilder<?>> fields) throws SQLException {
|
||||
//TODO replace with by runtime generated class
|
||||
try {
|
||||
var model = (T) clazz.getConstructor().newInstance();
|
||||
for (DbFieldBuilder<?> field : fields) {
|
||||
if (!field.getField().isDatabaseField()) {
|
||||
continue;
|
||||
}
|
||||
Field f = field.getField().getField();
|
||||
if (f == null) {
|
||||
System.out.println("not class member for " + field.getField().getName());
|
||||
continue;
|
||||
}
|
||||
f.setAccessible(true);
|
||||
if (field.getField().getType() == String.class) {
|
||||
f.set(model, res.getString(f.getName()));
|
||||
} else if (field.getField().getType() == byte.class || field.getField().getType() == Byte.class) {
|
||||
f.set(model, res.getByte(f.getName()));
|
||||
} else if (field.getField().getType() == char.class || field.getField().getType() == Character.class) {
|
||||
// f.set(model, res.getString(f.getName()));//TODO handle char
|
||||
throw new UnsupportedOperationException("char");
|
||||
} else if (field.getField().getType() == short.class || field.getField().getType() == Short.class) {
|
||||
f.set(model, res.getShort(f.getName()));
|
||||
} else if (field.getField().getType() == int.class || field.getField().getType() == Integer.class) {
|
||||
f.set(model, res.getInt(f.getName()));
|
||||
} else if (field.getField().getType() == long.class || field.getField().getType() == Long.class) {
|
||||
f.set(model, res.getLong(f.getName()));
|
||||
} else if (field.getField().getType() == float.class || field.getField().getType() == Float.class) {
|
||||
f.set(model, res.getFloat(f.getName()));
|
||||
} else if (field.getField().getType() == double.class || field.getField().getType() == Double.class) {
|
||||
f.set(model, res.getDouble(f.getName()));
|
||||
} else {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
return model;
|
||||
} catch (IllegalAccessException | InvocationTargetException | InstantiationException | NoSuchMethodException e) {//TODO better handling
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract <T extends SerializableObject> void add(DbContext context, Class<T> clazz, T model) throws SQLException;
|
||||
|
||||
public abstract <T extends SerializableObject> void update(DbContext context, Class<T> clazz, T model) throws SQLException;
|
||||
|
||||
public abstract <T extends SerializableObject> void delete(DbContext context, Class<T> clazz, T model) throws SQLException;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
package jef.platform.dummy;
|
||||
|
||||
import jef.MigrationException;
|
||||
import jef.expressions.Expression;
|
||||
import jef.model.DbContext;
|
||||
import jef.platform.base.Database;
|
||||
import jef.serializable.SerializableObject;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
public class DummyDatabase extends Database {
|
||||
public DummyDatabase() {
|
||||
@@ -11,4 +17,28 @@ public class DummyDatabase extends Database {
|
||||
@Override
|
||||
public void migrate() throws MigrationException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends SerializableObject> List<T> queryExpression(DbContext context, Class<T> clazz, Expression expression) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends SerializableObject> List<T> queryRaw(DbContext context, Class<T> clazz, String query) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends SerializableObject> void add(DbContext context, Class<T> clazz, T entity) throws SQLException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends SerializableObject> void update(DbContext context, Class<T> clazz, T model) throws SQLException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends SerializableObject> void delete(DbContext context, Class<T> clazz, T model) throws SQLException {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,11 @@ public abstract class Util {
|
||||
R apply(T t, U u) throws Throwable;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface ThrowableBiConsumer<T, U> {
|
||||
void accept(T t, U u) throws Throwable;
|
||||
}
|
||||
|
||||
public interface Equality<T> {
|
||||
boolean check(T t1, T t2);
|
||||
}
|
||||
|
||||
58
core/src/test/java/jef/asm/access/ClassAnalyzerTest.java
Normal file
58
core/src/test/java/jef/asm/access/ClassAnalyzerTest.java
Normal file
@@ -0,0 +1,58 @@
|
||||
package jef.asm.access;
|
||||
|
||||
import jef.model.ModelBuilder;
|
||||
import jef.model.annotations.ForeignKey;
|
||||
import jef.serializable.SerializableObject;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
|
||||
class ClassAnalyzerTest {
|
||||
|
||||
@Test
|
||||
void analyze() {
|
||||
var analyzer = new ClassAnalyzer();
|
||||
var result = analyzer.analyze(Employee.class);
|
||||
System.out.println(result.toStringFriendly());
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@ToString
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public static class Company extends SerializableObject {
|
||||
private int id;
|
||||
private String name;
|
||||
|
||||
private Employee ceo;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@ToString
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public static class Employee extends SerializableObject {
|
||||
private int id;
|
||||
private String name;
|
||||
|
||||
private Employee boss;
|
||||
@ForeignKey(getterOrField = "boss")
|
||||
private int bossId;
|
||||
|
||||
private Company company;
|
||||
@ForeignKey(getterOrField = "company")
|
||||
private int companyId;
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ public class FilterOpTest {
|
||||
@Test
|
||||
public void testSimple() {
|
||||
String act;
|
||||
act = new DbSet<>(TestClass.class, "table1")
|
||||
act = new DbSet<>(null, TestClass.class, "table1")
|
||||
.filter(e -> true)
|
||||
.toString();
|
||||
Assertions.assertEquals("SELECT * FROM (SELECT * FROM `table1`) a WHERE 1", act);
|
||||
@@ -23,7 +23,7 @@ public class FilterOpTest {
|
||||
public void testMultipleFilter() {
|
||||
String act;
|
||||
var s = List.of(1, 3);
|
||||
act = new DbSet<>(TestClass.class, "table1")
|
||||
act = new DbSet<>(null, TestClass.class, "table1")
|
||||
.filter(e -> s.contains(e.i))
|
||||
.filter(e -> e.i == 1337)
|
||||
.toString();
|
||||
|
||||
@@ -8,25 +8,25 @@ public class LimitOpTest {
|
||||
@Test
|
||||
public void test() {
|
||||
String act;
|
||||
act = new DbSet<>(FilterOpTest.TestClass.class, "table1")
|
||||
act = new DbSet<>(null, FilterOpTest.TestClass.class, "table1")
|
||||
.limit(10).skip(5)
|
||||
.toString();
|
||||
Assertions.assertEquals("SELECT * FROM (SELECT * FROM `table1`) a OFFSET 5 LIMIT 10", act);
|
||||
|
||||
|
||||
act = new DbSet<>(FilterOpTest.TestClass.class, "table1")
|
||||
act = new DbSet<>(null, FilterOpTest.TestClass.class, "table1")
|
||||
.skip(5).limit(10)
|
||||
.toString();
|
||||
Assertions.assertEquals("SELECT * FROM (SELECT * FROM `table1`) a OFFSET 5 LIMIT 10", act);
|
||||
|
||||
|
||||
act = new DbSet<>(FilterOpTest.TestClass.class, "table1")
|
||||
act = new DbSet<>(null, FilterOpTest.TestClass.class, "table1")
|
||||
.skip(5)
|
||||
.toString();
|
||||
Assertions.assertEquals("SELECT * FROM (SELECT * FROM `table1`) a OFFSET 5", act);
|
||||
|
||||
|
||||
act = new DbSet<>(FilterOpTest.TestClass.class, "table1")
|
||||
act = new DbSet<>(null, FilterOpTest.TestClass.class, "table1")
|
||||
.limit(10)
|
||||
.toString();
|
||||
Assertions.assertEquals("SELECT * FROM (SELECT * FROM `table1`) a LIMIT 10", act);
|
||||
|
||||
@@ -8,27 +8,27 @@ class SortOpTest {
|
||||
@Test
|
||||
public void test() {
|
||||
String act;
|
||||
act = new DbSet<>(FilterOpTest.TestClass.class, "table1")
|
||||
act = new DbSet<>(null, FilterOpTest.TestClass.class, "table1")
|
||||
.sorted(e -> e.getI()).thenSorted(e -> e.getD()).thenSorted(e -> e.getF()).thenSorted(e -> e.getL()).thenSorted(e -> e.getO())
|
||||
.toString();
|
||||
Assertions.assertEquals("SELECT * FROM (SELECT * FROM `table1`) a ORDER BY `a`.`i` ASC, `a`.`d` ASC, `a`.`f` ASC, `a`.`l` ASC, `a`.`o` ASC", act);
|
||||
|
||||
|
||||
act = new DbSet<>(FilterOpTest.TestClass.class, "table1")
|
||||
act = new DbSet<>(null, FilterOpTest.TestClass.class, "table1")
|
||||
.sortedDescending(e -> e.getI()).thenSortedDescending(e -> e.getD()).thenSortedDescending(e -> e.getF())
|
||||
/**/.thenSortedDescending(e -> e.getL()).thenSortedDescending(e -> e.getO())
|
||||
.toString();
|
||||
Assertions.assertEquals("SELECT * FROM (SELECT * FROM `table1`) a ORDER BY `a`.`i` DESC, `a`.`d` DESC, `a`.`f` DESC, `a`.`l` DESC, `a`.`o` DESC", act);
|
||||
|
||||
//alternating patterns
|
||||
act = new DbSet<>(FilterOpTest.TestClass.class, "table1")
|
||||
act = new DbSet<>(null, FilterOpTest.TestClass.class, "table1")
|
||||
.sortedDescending(e -> e.getI()).thenSorted(e -> e.getD()).thenSortedDescending(e -> e.getF()).thenSorted(e -> e.getL())
|
||||
/**/.thenSortedDescending(e -> e.getO())
|
||||
.toString();
|
||||
Assertions.assertEquals("SELECT * FROM (SELECT * FROM `table1`) a ORDER BY `a`.`i` DESC, `a`.`d` ASC, `a`.`f` DESC, `a`.`l` ASC, `a`.`o` DESC", act);
|
||||
|
||||
|
||||
act = new DbSet<>(FilterOpTest.TestClass.class, "table1")
|
||||
act = new DbSet<>(null, FilterOpTest.TestClass.class, "table1")
|
||||
.sorted(e -> e.getI()).thenSortedDescending(e -> e.getD()).thenSorted(e -> e.getF()).thenSortedDescending(e -> e.getL())
|
||||
/**/.thenSorted(e -> e.getO())
|
||||
.toString();
|
||||
|
||||
@@ -12,11 +12,11 @@ class DebugExpressionVisitorTest {
|
||||
@Test
|
||||
public void test() {
|
||||
var s = List.of(1, 3);
|
||||
Queryable<FilterOpTest.TestClass> q = new DbSet<>(FilterOpTest.TestClass.class, "table1")
|
||||
Queryable<FilterOpTest.TestClass> q = new DbSet<>(null, FilterOpTest.TestClass.class, "table1")
|
||||
.filter(e -> s.contains(e.i) && e.i == 1337 && e.i == 420);
|
||||
new DebugExpressionVisitor().visit(q.getExpression());
|
||||
|
||||
Queryable<FilterOpTest.TestClass> q2 = new DbSet<>(FilterOpTest.TestClass.class, "table1")
|
||||
Queryable<FilterOpTest.TestClass> q2 = new DbSet<>(null, FilterOpTest.TestClass.class, "table1")
|
||||
.filter(e -> s.contains(e.i) || e.i == 1337);
|
||||
new DebugExpressionVisitor().visit(q2.getExpression());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user