package io.trygvis.persistence.generators; import io.trygvis.container.compiler.SqlUnitModel; import io.trygvis.container.compiler.model.ClassG; import io.trygvis.container.compiler.model.Constructor; import io.trygvis.container.compiler.model.FieldRef; import io.trygvis.container.compiler.model.Imports; import io.trygvis.container.compiler.model.MethodRef; import io.trygvis.container.compiler.model.Parameters; import io.trygvis.container.compiler.model.TypeRef; import io.trygvis.persistence.EntityMirror; import io.trygvis.persistence.FieldMirror; import io.trygvis.persistence.GeneratorConfiguration; import io.trygvis.persistence.TypeHandler; import io.trygvis.persistence.sql.SqlDao; import io.trygvis.persistence.sql.SqlEntityMeta; import java.io.IOException; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import static io.trygvis.container.compiler.Utils.*; import static io.trygvis.container.compiler.model.TypeRef.VOID; import static io.trygvis.persistence.FieldMirror.FieldType.PRIMITIVE; import static io.trygvis.persistence.FieldMirror.FieldType.REFERENCE; import static io.trygvis.persistence.FieldMirror.SetterType; import static java.lang.String.format; import static java.lang.reflect.Modifier.PUBLIC; import static org.apache.commons.lang.StringUtils.join; public class DaoGenerator { private final GeneratorConfiguration generatorConfiguration; private final SqlUnitModel unit; private final EntityMirror entity; public DaoGenerator(GeneratorConfiguration generatorConfiguration, SqlUnitModel unit, EntityMirror entity) { this.generatorConfiguration = generatorConfiguration; this.unit = unit; this.entity = entity; } public ClassG generate() throws IOException { ClassG g = new ClassG(PUBLIC, entity.daoType). extendsType(new TypeRef(SqlDao.class).args(entity.idType, entity.type, unit.sessionType, entity.rowType)); Parameters p = new Parameters(); Parameters.ParameterRef session = p.addParameter(unit.sessionType, "session"); g.add(new Constructor(p, "super(" + session.name + ");")); TypeRef stringType = g.imports.add(String.class); TypeRef sqlEntityDescType = g.imports.add(SqlEntityMeta.class); TypeRef sqlException = g.imports.add(SQLException.class); // TypeRef listOfEntityType = new TypeRef(List.class).args(entity.type); FieldRef createTableSql = g.addPublicStaticFinalField(stringType, "createTableSql"). value(toJavaString(createTableSql())); g.add(new MethodRef(PUBLIC, stringType, "createTableSql", "return createTableSql;")); FieldRef dropTableSql = g.addPublicStaticFinalField(stringType, "dropTableSql"). value(toJavaString(dropTableSql())); g.add(new MethodRef(PUBLIC, stringType, "dropTableSql", "return dropTableSql;")); g.addPublicStaticFinalField(stringType, "insertIntoSql"). value(toJavaString(insertIntoSql())); g.addPublicStaticFinalField(stringType, "deleteFromSql"). value(toJavaString(deleteFromSql())); String desc = "new " + sqlEntityDescType + "(" + toJavaString(entity.tableName) + ", " + toJavaString(defaultFields()) + ", " + createTableSql.name + ", " + dropTableSql.name + ")"; g.addPublicStaticFinalField(sqlEntityDescType, "desc").value(desc); DaoUtilsGenerator daoUtil = new DaoUtilsGenerator(unit, generatorConfiguration, entity); // g.addInnerClass(daoUtil.queryType(g.imports)); g.addInnerClass(daoUtil.utils()); g.add(newRow(g.imports)); g.add(newEntity(g.imports)); { p = new Parameters(); Parameters.ParameterRef entity = p.addParameter(this.entity.type, "entity"); g.add(new MethodRef(PUBLIC, VOID, "insert", p, "Utils.insert" + this.entity.type.className + "(super.session.c, " + entity.name + ");"). exception(sqlException)); } g.add(selectById(g.imports)); g.add(selectWhere(g.imports)); { p = new Parameters(); Parameters.ParameterRef entity = p.addParameter(this.entity.type, "entity"); g.add(new MethodRef(PUBLIC, VOID, "delete", p, "Utils.delete" + this.entity.type.className + "(super.session.c, " + entity.name + ");"). exception(sqlException)); } { p = new Parameters(); Parameters.ParameterRef id = p.addParameter(entity.idType, "id"); g.add(new MethodRef(PUBLIC, VOID, "deleteById", p, "Utils.delete" + entity.type.className + "ById(super.session.c, " + id.name + ");"). exception(sqlException)); } { p = new Parameters(); Parameters.ParameterRef entity = p.addParameter(this.entity.type, "entity"); g.add(new MethodRef(PUBLIC, VOID, "update", p, "Utils.update" + this.entity.type.className + "(super.session.c, " + entity.name + ");"). exception(sqlException)); } return g; } public ClassG generateRow() { ClassG g = new ClassG(PUBLIC, entity.rowType); Parameters parameters = new Parameters(); List body = new ArrayList<>(); for (FieldMirror field : entity.getFields()) { TypeRef type; if (field.fieldType == PRIMITIVE) { type = field.type; } else { EntityMirror entity = unit.getEntities().get(field.type); type = entity.getIdField().type; } FieldRef f = g.addPublicFinalField(type, field.javaName); Parameters.ParameterRef p = parameters.addParameter(type, field.javaName); body.add("this." + f.name + " = " + p.name + ";"); } g.add(new Constructor(parameters, body)); return g; } public String createTableSql() { List columns = new ArrayList<>(); for (FieldMirror field : entity.getFields()) { String s; if (field.fieldType == PRIMITIVE) { TypeHandler typeHandler = generatorConfiguration.typeHandler(field.type); s = " " + field.sqlName + " " + typeHandler.sqlType(field); if (field.id) { s += " PRIMARY KEY"; } else if (field.notNull) { s += " NOT NULL"; } else if (field.unique) { s += " UNIQUE"; } } else if (field.fieldType == REFERENCE) { EntityMirror referenced = unit.get(field.type); FieldMirror idField = referenced.getIdField(); TypeHandler typeHandler = generatorConfiguration.typeHandler(idField.type); s = " " + field.sqlName + " " + typeHandler.sqlType(field); s += " REFERENCES " + referenced.tableName + "(" + idField.sqlName + ")"; if (field.notNull) { s += " NOT NULL"; } else if (field.unique) { s += " UNIQUE"; } } else { throw new RuntimeException("Unknown field type: " + field.getClass()); } columns.add(s); } return format("CREATE TABLE " + entity.tableName + "(%n" + join(columns, ",%n") + "%n);"); } public String dropTableSql() { return "DROP TABLE " + entity.tableName + ";"; } public String insertIntoSql() { List columns = new ArrayList<>(); List values = new ArrayList<>(); for (FieldMirror field : entity.getFields()) { columns.add(field.sqlName); if (field.id) { values.add("nextval('" + unit.getDefaultSequence().sequenceName + "')"); } else { values.add("?"); } } return "INSERT INTO " + entity.tableName + "(" + join(columns, ", ") + ") " + "VALUES(" + join(values, ", ") + ");"; } public String deleteFromSql() { List ss = new ArrayList<>(); ss.add(entity.getIdField().sqlName + "=?"); return "DELETE FROM " + entity.tableName + " WHERE " + join(ss, " AND ") + ";"; } public MethodRef selectById(Imports imports) { TypeRef preparedStatementType = imports.add(PreparedStatement.class); TypeRef sqlExceptionType = imports.add(SQLException.class); Parameters p = new Parameters(); Parameters.ParameterRef idP = p.addParameter(entity.idType, "id"); TypeRef entityListType = imports.add(List.class).args(entity.type); List body = new ArrayList<>(); FieldMirror id = entity.getIdField(); body.add("String sql = \"SELECT \" + desc.defaultFields + \" FROM " + entity.tableName + " WHERE " + id.sqlName + "=?\";"); body.add(entityListType + " list = runQuery(new Preparator() {"); body.add(" @Override"); body.add(" public void prepare(" + preparedStatementType.plainName + " stmt) throws " + sqlExceptionType + " {"); TypeHandler typeHandler = generatorConfiguration.typeHandler(entity.getIdField().type); body.add(" stmt." + typeHandler.setter(1, idP.name) + ";"); body.add(" }"); body.add("}, sql);"); body.add("if (list.isEmpty()) {"); body.add(" return null;"); body.add("}"); body.add("return list.get(0);"); return new MethodRef(PUBLIC, entity.type, "selectById", p, body). exception(imports.add(SQLException.class)); } public MethodRef selectWhere(Imports imports) { TypeRef sqlExceptionType = imports.add(SQLException.class); Parameters p = new Parameters(); Parameters.ParameterRef where = p.addParameter(imports.add(String.class), "where"); List body = new ArrayList<>(); body.add("String sql = \"SELECT \" + desc.defaultFields + \" FROM " + entity.tableName + " WHERE \" + " + where.name + " + \";\";"); body.add("return runQuery(sql);"); TypeRef listOfEntityType = new TypeRef(List.class).args(entity.type); return new MethodRef(PUBLIC, listOfEntityType, "selectWhere", p, body). exception(sqlExceptionType); } public MethodRef newRow(Imports g) { TypeRef rsType = g.add(ResultSet.class); Parameters p = new Parameters(); Parameters.ParameterRef rs = p.addParameter(rsType, "rs"); List body = new ArrayList<>(); List fields = new ArrayList<>(); for (int i = 0; i < entity.getFields().size(); i++) { FieldMirror field = entity.getFields().get(i); String getter; TypeRef type; if (field.fieldType == PRIMITIVE) { TypeHandler typeHandler = generatorConfiguration.typeHandler(field.type); type = field.type; getter = typeHandler.getter(rs.name, i + 1); } else { EntityMirror referencedEntity = unit.getEntities().get(field.type); type = referencedEntity.getIdField().type; TypeHandler typeHandler = generatorConfiguration.typeHandler(type); getter = typeHandler.getter(rs.name, i + 1); } String x = type.plainName + " " + field.javaName; body.add(x + " = " + getter + ";"); fields.add(field.javaName); } body.add("return new " + entity.rowType.plainName + "(" + join(fields, ", ") + ");"); return new MethodRef(PUBLIC, entity.rowType, "newRow", p, body). exception(g.add(SQLException.class)); } public MethodRef newEntity(Imports g) { Parameters p = new Parameters(); Parameters.ParameterRef row = p.addParameter(this.entity.rowType, "row"); List body = new ArrayList<>(); List cArgs = new ArrayList<>(); List method = new ArrayList<>(); for (int i = 0; i < entity.getFields().size(); i++) { FieldMirror field = this.entity.getFields().get(i); String value; if (field.fieldType == PRIMITIVE) { value = row.name + "." + field.javaName; } else { EntityMirror referencedEntity = unit.getEntities().get(field.type); // String x = field.type.plainName + " " + field.javaName + " = " + value = "session." + toFieldName(referencedEntity.type) + ".selectById(" + row.name + "." + field.javaName + ")"; // body.add(x); } if (field.setterType == SetterType.CONSTRUCTOR) { cArgs.add(value); } else if (field.setterType == SetterType.METHOD) { method.add("_entity." + toSetterName(field.javaName) + "(" + value + ");"); } else if (field.setterType == SetterType.FIELD) { method.add("_entity." + field.javaName + " = " + value + ";"); } } body.add(entity.type.plainName + " _entity = new " + entity.type.plainName + "(" + join(cArgs, ", ") + ");"); /* Contact contact = new Contact(row.name, row.gender); contact.company = session.company.selectById(row.company); return contact; */ body.addAll(method); body.add("return _entity;"); return new MethodRef(PUBLIC, this.entity.type, "newEntity", p, body). exception(g.add(SQLException.class)); } public String defaultFields() { List names = new ArrayList<>(); for (FieldMirror field : entity.getFields()) { names.add(field.sqlName); } return join(names, ", "); } }