package org.simpleflatmapper.jdbc.impl;
import org.simpleflatmapper.jdbc.Crud;
import org.simpleflatmapper.jdbc.JdbcMapper;
import org.simpleflatmapper.jdbc.JdbcMapperBuilder;
import org.simpleflatmapper.jdbc.JdbcMapperFactory;
import org.simpleflatmapper.jdbc.PreparedStatementMapperBuilder;
import org.simpleflatmapper.jdbc.QueryPreparer;
import org.simpleflatmapper.jdbc.named.NamedSqlQuery;
import org.simpleflatmapper.reflect.meta.ClassMeta;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class CrudFactory {
public static <T, K> Crud<T, K> newInstance(
ClassMeta<T> target,
ClassMeta<K> keyTarget,
CrudMeta crudMeta,
JdbcMapperFactory jdbcMapperFactory) throws SQLException {
JdbcMapperFactory mapperFactory = JdbcMapperFactory.newInstance(jdbcMapperFactory);
return createCrud(target, keyTarget, crudMeta, mapperFactory);
}
private static <T, K> Crud<T, K> createCrud(ClassMeta<T> target, ClassMeta<K> keyTarget, CrudMeta crudMeta, JdbcMapperFactory mapperFactory) throws SQLException {
crudMeta.addColumnProperties(mapperFactory);
QueryPreparer<T> insert = buildInsert(target, crudMeta, mapperFactory);
QueryPreparer<T> update = buildUpdate(target, crudMeta, mapperFactory);
QueryPreparer<K> select = buildSelect(keyTarget, crudMeta, mapperFactory);
QueryPreparer<K> delete = buildDelete(keyTarget, crudMeta, mapperFactory);
QueryPreparer<T> upsert = buildUpsert(target, crudMeta, mapperFactory);
KeyTupleQueryPreparer<K> keyTupleQueryPreparer = buildKeyTupleQueryPreparer(keyTarget, crudMeta, mapperFactory);
JdbcMapper<T> selectMapper = buildSelectMapper(target, crudMeta, mapperFactory);
JdbcMapper<K> keyMapper = buildKeyMapper(keyTarget, crudMeta, mapperFactory);
boolean hasGeneratedKeys = crudMeta.hasGeneratedKeys();
DefaultCrud<T, K> defaultCrud = new DefaultCrud<T, K>(
insert,
update,
select,
upsert,
keyTupleQueryPreparer,
selectMapper,
delete,
keyMapper,
crudMeta.getTable(),
hasGeneratedKeys,
new SelectQueryWhereFactory<T>(crudMeta.getTable(), selectMapper, mapperFactory));
if (crudMeta.getDatabaseMeta().isMysql()) {
return MysqlCrudFactory.newInstance(target, keyTarget, crudMeta, mapperFactory, defaultCrud);
} else if (crudMeta.getDatabaseMeta().isPostgresSql()) {
return PostgresqlCrudFactory.newInstance(target, keyTarget, crudMeta, mapperFactory, defaultCrud);
}
return defaultCrud;
}
private static <T, K> QueryPreparer<T> buildUpsert(ClassMeta<T> target, CrudMeta crudMeta, JdbcMapperFactory mapperFactory) {
if (crudMeta.getDatabaseMeta().isMysql()) {
return MysqlCrudFactory.buildUpsert(target, crudMeta, mapperFactory);
} else if (crudMeta.getDatabaseMeta().isPostgresSql() && crudMeta.getDatabaseMeta().isVersionMet(9, 5)) {
return PostgresqlCrudFactory.buildUpsert(target, crudMeta, mapperFactory);
}
return new UnsupportedQueryPreparer<T>("Upsert Not Supported on " + crudMeta.getDatabaseMeta());
}
private static <T, K> KeyTupleQueryPreparer<K> buildKeyTupleQueryPreparer(ClassMeta<K> keyTarget, CrudMeta crudMeta, JdbcMapperFactory jdbcMapperFactory) {
PreparedStatementMapperBuilder<K> builder = jdbcMapperFactory.from(keyTarget);
List<String> primaryKeys = new ArrayList<String>();
int i = 1;
for(ColumnMeta cm : crudMeta.getColumnMetas()) {
if (cm.isKey()) {
primaryKeys.add(cm.getColumn());
builder.addColumn(cm.toJdbcColumnKey(i));
i++;
}
}
return new KeyTupleQueryPreparer<K>(builder.buildIndexFieldMappers(), primaryKeys.toArray(new String[0]));
}
private static <T, K>JdbcMapper<K> buildKeyMapper(ClassMeta<K> keyTarget, CrudMeta crudMeta, JdbcMapperFactory jdbcMapperFactory) {
JdbcMapperBuilder<K> mapperBuilder = jdbcMapperFactory.newBuilder(keyTarget);
int i = 1;
for(ColumnMeta cm : crudMeta.getColumnMetas()) {
if (cm.isKey()) {
mapperBuilder.addMapping(cm.toJdbcColumnKey(i));
i++;
}
}
if (i == 1) {
throw new IllegalArgumentException("No key defined to map to " + keyTarget.getType() + ", specify key using DSL or add a primary key to the table");
}
return mapperBuilder.mapper();
}
private static <T, K> JdbcMapper<T> buildSelectMapper(ClassMeta<T> target, CrudMeta crudMeta, JdbcMapperFactory jdbcMapperFactory) throws SQLException {
JdbcMapperBuilder<T> mapperBuilder = jdbcMapperFactory.<T>newBuilder(target);
int i = 1;
for(ColumnMeta cm : crudMeta.getColumnMetas()) {
mapperBuilder.addMapping(cm.toJdbcColumnKey(i));
i++;
}
return mapperBuilder.mapper();
}
private static <T, K> QueryPreparer<T> buildInsert(ClassMeta<T> target, CrudMeta crudMeta, JdbcMapperFactory jdbcMapperFactory) throws SQLException {
List<String> generatedKeys = new ArrayList<String>();
StringBuilder sb = new StringBuilder("INSERT INTO ");
appendTableName(sb, crudMeta);
sb.append("(");
boolean first = true;
for(ColumnMeta cm : crudMeta.getColumnMetas()) {
if (cm.isInsertable()) {
if (!first) {
sb.append(", ");
}
sb.append(cm.getColumn());
first = false;
}
if (cm.isGenerated()) {
generatedKeys.add(cm.getColumn());
}
}
sb.append(") VALUES(");
first = true;
for(ColumnMeta cm : crudMeta.getColumnMetas()) {
if (cm.isInsertable()) {
if (!first) {
sb.append(", ");
}
sb.append(cm.getInsertExpression());
first = false;
}
}
sb.append(")");
return jdbcMapperFactory.<T>from(target).to(NamedSqlQuery.parse(sb), generatedKeys.isEmpty() ? null : generatedKeys.toArray(new String[0]));
}
private static <T, K> QueryPreparer<T> buildUpdate(ClassMeta<T> target, CrudMeta crudMeta, JdbcMapperFactory jdbcMapperFactory) throws SQLException {
StringBuilder sb = new StringBuilder("UPDATE ");
appendTableName(sb, crudMeta);
sb.append(" SET ");
boolean first = true;
for(ColumnMeta cm : crudMeta.getColumnMetas()) {
String columnName = cm.getColumn();
if (!cm.isKey()) {
if (!first) {
sb.append(", ");
}
sb.append(columnName);
sb.append(" = ?");
first = false;
}
}
addWhereOnPrimaryKeys(crudMeta, sb);
return jdbcMapperFactory.<T>from(target).to(NamedSqlQuery.parse(sb));
}
private static <T, K> QueryPreparer<K> buildSelect(ClassMeta<K> keyTarget, CrudMeta crudMeta, JdbcMapperFactory jdbcMapperFactory) throws SQLException {
StringBuilder sb = new StringBuilder("SELECT ");
boolean first = true;
for(ColumnMeta cm : crudMeta.getColumnMetas()) {
if (!first) {
sb.append(", ");
}
sb.append(cm.getColumn());
first = false;
}
sb.append(" FROM ");
appendTableName(sb, crudMeta);
addWhereOnPrimaryKeys(crudMeta, sb);
return jdbcMapperFactory.<K>from(keyTarget).to(NamedSqlQuery.parse(sb));
}
private static void appendTableName(StringBuilder sb, CrudMeta crudMeta) {
sb.append(crudMeta.getTable());
}
private static <T, K> QueryPreparer<K> buildDelete(ClassMeta<K> keyTarget, CrudMeta crudMeta, JdbcMapperFactory jdbcMapperFactory) throws SQLException {
StringBuilder sb = new StringBuilder("DELETE FROM ");
appendTableName(sb, crudMeta);
addWhereOnPrimaryKeys(crudMeta, sb);
return jdbcMapperFactory.<K>from(keyTarget).to(NamedSqlQuery.parse(sb));
}
private static <T, K> void addWhereOnPrimaryKeys(CrudMeta crudMeta, StringBuilder sb) {
sb.append(" WHERE ");
boolean first = true;
for(ColumnMeta cm : crudMeta.getColumnMetas()) {
if (cm.isKey()) {
if (!first) {
sb.append("AND ");
}
sb.append(cm.getColumn());
sb.append(" = ? ");
first = false;
}
}
}
}