package org.simpleflatmapper.jdbc; import org.simpleflatmapper.jdbc.impl.CrudFactory; import org.simpleflatmapper.jdbc.impl.CrudMeta; import org.simpleflatmapper.jdbc.impl.LazyCrud; import org.simpleflatmapper.jdbc.impl.DataSourceTransactionTemplate; import org.simpleflatmapper.reflect.meta.AliasProviderService; import org.simpleflatmapper.reflect.meta.ClassMeta; import org.simpleflatmapper.reflect.meta.DefaultPropertyNameMatcher; import org.simpleflatmapper.reflect.meta.Table; import org.simpleflatmapper.util.TypeHelper; import javax.sql.DataSource; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; public class CrudDSL<T, K> { private final ClassMeta<T> target; private final ClassMeta<K> keyTarget; private final JdbcMapperFactory jdbcMapperFactory; public CrudDSL(ClassMeta<T> target, ClassMeta<K> keyTarget, JdbcMapperFactory jdbcMapperFactory) { this.target = target; this.keyTarget = keyTarget; this.jdbcMapperFactory = jdbcMapperFactory; } /** * Create a crud that will validate on the first interaction with a connection. * The table name is derived from the jpa annotation or from the class name. * @return a new crud instance */ public Crud<T, K> crud() { return new LazyCrud<T, K>(this, null); } /** * Create a crud against the specified table that will validate on the first interaction with a connection. * @param table the table name * @return a new crud instance */ public Crud<T, K> table(String table) { return new LazyCrud<T, K>(this, table); } /** * Create a crud against the specified table validating it against the specified connection. * @param connection the connection * @param table the table * @return a new crud instance * @throws SQLException if an error occurred */ public Crud<T, K> table(Connection connection, String table) throws SQLException { CrudMeta crudMeta = CrudMeta.of(connection, table, jdbcMapperFactory.columnDefinitions()); return CrudFactory.<T, K>newInstance(target, keyTarget, crudMeta, jdbcMapperFactory); } /** * Create a connected crud against the specified table validating it against the specified datasource. * @param dataSource the datasource * @param table the table * @return a new crud instance * @throws SQLException if an error occurred */ public ConnectedCrud<T, K> table(DataSource dataSource, String table) throws SQLException { Connection connection = dataSource.getConnection(); try { return new ConnectedCrud<T, K>(new DataSourceTransactionTemplate(dataSource), table(connection, table)); } finally { connection.close(); } } /** * Create a connected crud validating it against the specified datasource. * The table name is derived from the jpa annotation or from the class name. * @param dataSource the datasource * @return a new crud instance * @throws SQLException if an error occurred */ public ConnectedCrud<T, K> to(DataSource dataSource) throws SQLException { Connection connection = dataSource.getConnection(); try { return new ConnectedCrud<T, K>(new DataSourceTransactionTemplate(dataSource), to(connection)); } finally { connection.close(); } } /** * Create a connected crud validating it against the specified connection. * The table name is derived from the jpa annotation or from the class name. * @param connection the connection * @return a new crud instance * @throws SQLException if an error occurred */ public Crud<T, K> to(Connection connection) throws SQLException { return table(connection, getTable(connection, target)); } private String getTable(Connection connection, ClassMeta<T> target) throws SQLException { final Class<Object> targetClass = TypeHelper.toClass(target.getType()); Table table = AliasProviderService.getAliasProvider().getTable(targetClass); StringBuilder sb = new StringBuilder(); if (table.schema() != null && table.schema().length() > 0) { sb.append(table.schema()).append("."); } if (table.table() == null) { DatabaseMetaData metaData = connection.getMetaData(); final ResultSet tables = getTables(connection, metaData); final String className = TypeHelper.toClass(targetClass).getSimpleName(); try { while(tables.next()) { String tableName = tables.getString("TABLE_NAME"); if (DefaultPropertyNameMatcher.of(tableName).matches(className)) { sb.append(tableName); return sb.toString(); } } } finally { tables.close(); } throw new IllegalArgumentException("Type " + target.getType() + " has no table mapping"); } sb.append(table.table()); return sb.toString(); } private ResultSet getTables(Connection connection, DatabaseMetaData metaData) throws SQLException { try { return metaData.getTables(connection.getCatalog(), null, null, null); } catch (SQLException e) { if ("S1009".equals(e.getSQLState())) { // see https://bugs.mysql.com/bug.php?id=81105 return metaData.getTables(connection.getCatalog(), null, "", null); } throw e; } } }