package core.framework.impl.db;
import core.framework.api.db.Column;
import core.framework.api.db.PrimaryKey;
import core.framework.api.db.Table;
import core.framework.api.util.Lists;
import core.framework.impl.code.CodeBuilder;
import core.framework.impl.code.DynamicInstanceBuilder;
import core.framework.impl.reflect.Classes;
import java.lang.reflect.Field;
import java.util.List;
import java.util.function.Function;
/**
* @author neo
*/
final class UpdateQuery<T> {
private final Function<T, Query> queryBuilder;
UpdateQuery(Class<T> entityClass) {
List<Field> primaryKeyFields = Lists.newArrayList();
List<Field> columnFields = Lists.newArrayList();
for (Field field : Classes.instanceFields(entityClass)) {
if (field.isAnnotationPresent(PrimaryKey.class)) {
primaryKeyFields.add(field);
} else if (field.isAnnotationPresent(Column.class)) {
columnFields.add(field);
}
}
queryBuilder = queryBuilder(entityClass, primaryKeyFields, columnFields);
}
private Function<T, Query> queryBuilder(Class<T> entityClass, List<Field> primaryKeyFields, List<Field> columnFields) {
CodeBuilder builder = new CodeBuilder();
builder.append("public Object apply(Object value) {\n")
.indent(1).append("{} entity = ({}) value;\n", entityClass.getCanonicalName(), entityClass.getCanonicalName());
for (Field primaryKeyField : primaryKeyFields) {
builder.indent(1).append("if (entity.{} == null) throw new Error(\"primary key must not be null, field={}\");\n", primaryKeyField.getName(), primaryKeyField.getName());
}
builder.indent(1).append("StringBuilder sql = new StringBuilder(\"UPDATE {} SET \");\n", entityClass.getDeclaredAnnotation(Table.class).name());
builder.indent(1).append("java.util.List params = new java.util.ArrayList();\n");
builder.indent(1).append("int index = 0;\n");
for (Field field : columnFields) {
builder.indent(1).append("if (entity.{} != null) {\n", field.getName())
.indent(2).append("if (index > 0) sql.append(\", \");\n")
.indent(2).append("sql.append(\"{} = ?\");\n", field.getDeclaredAnnotation(Column.class).name())
.indent(2).append("params.add(entity.{});\n", field.getName())
.indent(2).append("index++;\n")
.indent(1).append("}\n");
}
builder.indent(1).append("sql.append(\"");
int index = 0;
for (Field primaryKeyField : primaryKeyFields) {
if (index == 0) {
builder.append(" WHERE ");
} else {
builder.append(" AND ");
}
builder.append("{} = ?", primaryKeyField.getDeclaredAnnotation(Column.class).name());
index++;
}
builder.append("\");\n");
for (Field primaryKeyField : primaryKeyFields) {
builder.indent(1).append("params.add(entity.{});\n", primaryKeyField.getName());
}
builder.indent(1).append("return new {}(sql.toString(), params.toArray());\n", Query.class.getCanonicalName())
.append("}");
DynamicInstanceBuilder<Function<T, Query>> dynamicInstanceBuilder = new DynamicInstanceBuilder<>(Function.class, UpdateQuery.class.getCanonicalName() + "$" + entityClass.getSimpleName() + "$UpdateQueryBuilder");
dynamicInstanceBuilder.addMethod(builder.build());
return dynamicInstanceBuilder.build();
}
Query query(T entity) {
return queryBuilder.apply(entity);
}
static class Query {
final String sql;
final Object[] params;
Query(String sql, Object[] params) {
this.sql = sql;
this.params = params;
}
}
}