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 InsertQuery<T> {
public final String sql;
private final Function<T, Object[]> paramBuilder;
InsertQuery(Class<T> entityClass) {
List<Field> paramFields = Lists.newArrayList();
StringBuilder builder = new StringBuilder("INSERT INTO ");
Table table = entityClass.getDeclaredAnnotation(Table.class);
builder.append(table.name()).append(" (");
List<Field> fields = Classes.instanceFields(entityClass);
int index = 0;
for (Field field : fields) {
PrimaryKey primaryKey = field.getDeclaredAnnotation(PrimaryKey.class);
if (primaryKey != null && primaryKey.autoIncrement()) continue;
Column column = field.getDeclaredAnnotation(Column.class);
if (index > 0) builder.append(", ");
builder.append(column.name());
paramFields.add(field);
index++;
}
builder.append(") VALUES (");
for (int i = 0; i < paramFields.size(); i++) {
if (i > 0) builder.append(", ");
builder.append('?');
}
builder.append(')');
sql = builder.toString();
paramBuilder = paramBuilder(entityClass, paramFields);
}
private Function<T, Object[]> paramBuilder(Class<T> entityClass, List<Field> paramFields) {
CodeBuilder builder = new CodeBuilder();
builder.append("public Object apply(Object value) {\n")
.indent(1).append("{} entity = ({}) value;", entityClass.getCanonicalName(), entityClass.getCanonicalName())
.indent(1).append("Object[] params = new Object[{}];\n", paramFields.size());
int index = 0;
for (Field paramField : paramFields) {
builder.indent(1).append("params[{}] = entity.{};\n", index, paramField.getName());
index++;
}
builder.append("return params;\n")
.append("}");
DynamicInstanceBuilder<Function<T, Object[]>> dynamicInstanceBuilder = new DynamicInstanceBuilder<>(Function.class, InsertQuery.class.getCanonicalName() + "$" + entityClass.getSimpleName() + "$InsertQueryParamBuilder");
dynamicInstanceBuilder.addMethod(builder.build());
return dynamicInstanceBuilder.build();
}
Object[] params(T entity) {
return paramBuilder.apply(entity);
}
}