From e0253adea781b61d671dec53f84066e7b1600558 Mon Sep 17 00:00:00 2001 From: Alden Quimby Date: Sun, 6 Apr 2014 13:31:06 -0400 Subject: [PATCH 1/4] refactor quirks and allow bidirectional converters --- core/pom.xml | 2 - core/src/main/java/org/sql2o/Connection.java | 4 +- .../java/org/sql2o/PojoResultSetIterator.java | 5 +- core/src/main/java/org/sql2o/Query.java | 255 ++++++++---------- .../java/org/sql2o/ResultSetIteratorBase.java | 15 +- core/src/main/java/org/sql2o/Sql2o.java | 86 ++++-- .../src/main/java/org/sql2o/SqlParameter.java | 24 ++ .../sql2o/converters/BigDecimalConverter.java | 7 + .../sql2o/converters/BooleanConverter.java | 17 +- .../converters/BuiltInConverterBase.java | 12 + .../sql2o/converters/ByteArrayConverter.java | 8 +- .../org/sql2o/converters/ByteConverter.java | 14 + .../java/org/sql2o/converters/Convert.java | 4 +- .../java/org/sql2o/converters/Converter.java | 8 + .../org/sql2o/converters/DateConverter.java | 20 +- .../converters/DateConverterNoTimestamp.java | 14 + .../converters/DefaultEnumConverter.java | 22 +- .../org/sql2o/converters/DoubleConverter.java | 15 ++ .../org/sql2o/converters/FloatConverter.java | 15 ++ .../converters/InputStreamConverter.java | 9 +- .../sql2o/converters/IntegerConverter.java | 16 +- .../sql2o/converters/JodaTimeConverter.java | 23 -- .../sql2o/converters/LocalTimeConverter.java | 22 -- .../org/sql2o/converters/LongConverter.java | 17 +- .../org/sql2o/converters/NumberConverter.java | 19 +- .../org/sql2o/converters/ShortConverter.java | 15 ++ .../org/sql2o/converters/StringConverter.java | 14 +- .../org/sql2o/converters/UUIDConverter.java | 9 +- .../converters/joda/DateTimeConverter.java | 45 ++++ .../converters/joda/LocalTimeConverter.java | 43 +++ .../sql2o/data/TableResultSetIterator.java | 6 +- .../main/java/org/sql2o/quirks/Db2Quirks.java | 34 +++ .../main/java/org/sql2o/quirks/NoQuirks.java | 26 ++ .../java/org/sql2o/quirks/PostgresQuirks.java | 12 + .../main/java/org/sql2o/quirks/Quirks.java | 20 ++ .../org/sql2o/quirks/SqlServerQuirks.java | 8 + .../sql2o/tools/NamedParameterStatement.java | 6 +- .../sql2o/tools/StatementParameterSetter.java | 32 +++ .../java/org/sql2o/issues/PostgresTest.java | 4 +- 39 files changed, 674 insertions(+), 253 deletions(-) create mode 100644 core/src/main/java/org/sql2o/SqlParameter.java create mode 100644 core/src/main/java/org/sql2o/converters/BuiltInConverterBase.java create mode 100644 core/src/main/java/org/sql2o/converters/DateConverterNoTimestamp.java delete mode 100644 core/src/main/java/org/sql2o/converters/JodaTimeConverter.java delete mode 100644 core/src/main/java/org/sql2o/converters/LocalTimeConverter.java create mode 100644 core/src/main/java/org/sql2o/converters/joda/DateTimeConverter.java create mode 100644 core/src/main/java/org/sql2o/converters/joda/LocalTimeConverter.java create mode 100644 core/src/main/java/org/sql2o/quirks/Db2Quirks.java create mode 100644 core/src/main/java/org/sql2o/quirks/NoQuirks.java create mode 100644 core/src/main/java/org/sql2o/quirks/PostgresQuirks.java create mode 100644 core/src/main/java/org/sql2o/quirks/Quirks.java create mode 100644 core/src/main/java/org/sql2o/quirks/SqlServerQuirks.java create mode 100644 core/src/main/java/org/sql2o/tools/StatementParameterSetter.java diff --git a/core/pom.xml b/core/pom.xml index 0495aa94..158ae44c 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -115,8 +115,6 @@ spring-jdbc 4.0.2.RELEASE - - diff --git a/core/src/main/java/org/sql2o/Connection.java b/core/src/main/java/org/sql2o/Connection.java index 3e36908e..2ad360f5 100644 --- a/core/src/main/java/org/sql2o/Connection.java +++ b/core/src/main/java/org/sql2o/Connection.java @@ -61,9 +61,7 @@ public Sql2o getSql2o() { } public Query createQuery(String queryText, String name){ - // If postgresql, the default behaviour should be not to retur generated keys, as this will throw an exception on - // every query that does not create any new keys. - boolean returnGeneratedKeys = !(this.sql2o.quirksMode == QuirksMode.PostgreSQL); + boolean returnGeneratedKeys = this.sql2o.getQuirks().returnGeneratedKeysByDefault(); return createQuery(queryText, name, returnGeneratedKeys); } diff --git a/core/src/main/java/org/sql2o/PojoResultSetIterator.java b/core/src/main/java/org/sql2o/PojoResultSetIterator.java index a0726de0..15dce18b 100644 --- a/core/src/main/java/org/sql2o/PojoResultSetIterator.java +++ b/core/src/main/java/org/sql2o/PojoResultSetIterator.java @@ -3,6 +3,7 @@ import org.sql2o.converters.Convert; import org.sql2o.converters.Converter; import org.sql2o.converters.ConverterException; +import org.sql2o.quirks.Quirks; import org.sql2o.reflection.Pojo; import org.sql2o.reflection.PojoMetadata; import org.sql2o.tools.ResultSetUtils; @@ -21,8 +22,8 @@ public class PojoResultSetIterator extends ResultSetIteratorBase { private Converter converter; private boolean useExecuteScalar; - public PojoResultSetIterator(ResultSet rs, boolean isCaseSensitive, QuirksMode quirksMode, PojoMetadata metadata) { - super(rs, isCaseSensitive, quirksMode); + public PojoResultSetIterator(ResultSet rs, boolean isCaseSensitive, Quirks quirks, PojoMetadata metadata) { + super(rs, isCaseSensitive, quirks); this.metadata = metadata; this.converter = Convert.getConverterIfExists(metadata.getType()); diff --git a/core/src/main/java/org/sql2o/Query.java b/core/src/main/java/org/sql2o/Query.java index fb19a033..0b397114 100644 --- a/core/src/main/java/org/sql2o/Query.java +++ b/core/src/main/java/org/sql2o/Query.java @@ -1,14 +1,15 @@ package org.sql2o; -import org.joda.time.DateTime; import org.sql2o.converters.Convert; import org.sql2o.converters.Converter; import org.sql2o.converters.ConverterException; -import org.sql2o.data.*; +import org.sql2o.data.LazyTable; +import org.sql2o.data.Row; +import org.sql2o.data.Table; +import org.sql2o.data.TableResultSetIterator; import org.sql2o.logging.LocalLoggerFactory; import org.sql2o.logging.Logger; import org.sql2o.reflection.PojoMetadata; -import org.sql2o.tools.FeatureDetector; import org.sql2o.tools.NamedParameterStatement; import org.sql2o.tools.ResultSetUtils; @@ -16,7 +17,6 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.sql.*; -import java.sql.Date; import java.util.*; /** @@ -26,6 +26,15 @@ public class Query { private final Logger logger = LocalLoggerFactory.getLogger(Query.class); + private Connection connection; + private Map caseSensitiveColumnMappings; + private Map columnMappings; + private NamedParameterStatement statement; + private boolean caseSensitive; + private boolean autoDeriveColumnNames; + private String name; + private boolean returnGeneratedKeys; + public Query(Connection connection, String queryText, String name, boolean returnGeneratedKeys) { this.connection = connection; this.name = name; @@ -42,38 +51,64 @@ public Query(Connection connection, String queryText, String name, boolean retur this.caseSensitive = connection.getSql2o().isDefaultCaseSensitive(); } - private Connection connection; + // ------------------------------------------------ + // ------------- Getter/Setters ------------------- + // ------------------------------------------------ - private Map caseSensitiveColumnMappings; - private Map columnMappings; + public boolean isCaseSensitive() { + return caseSensitive; + } - private NamedParameterStatement statement; + public Query setCaseSensitive(boolean caseSensitive) { + this.caseSensitive = caseSensitive; + return this; + } - private boolean caseSensitive; - private boolean autoDeriveColumnNames; + public boolean isAutoDeriveColumnNames() { + return autoDeriveColumnNames; + } - private final String name; - private boolean returnGeneratedKeys; + public Query setAutoDeriveColumnNames(boolean autoDeriveColumnNames) { + this.autoDeriveColumnNames = autoDeriveColumnNames; + return this; + } + + public Connection getConnection(){ + return this.connection; + } + + public String getName() { + return name; + } // ------------------------------------------------ // ------------- Add Parameters ------------------- // ------------------------------------------------ - public Query addParameter(String name, Object value){ + public Query addParameter(String name, Object value) { + value = convertParameter(value); - if (tryAddJodaDateTimeParameter(name, value)) { - return this; - } - - try{ + try { statement.setObject(name, value); } - catch(SQLException ex){ + catch(SQLException ex) { throw new RuntimeException(ex); } return this; } + private Object convertParameter(Object value) { + if (value == null) { + return null; + } + Converter converter = Convert.getConverterIfExists(value.getClass()); + if (converter == null) { + return null; + } + //noinspection unchecked + return converter.toDatabaseParam(value); + } + public Query addParameter(String name, InputStream value){ try{ statement.setInputStream(name, value); @@ -85,20 +120,21 @@ public Query addParameter(String name, InputStream value){ } public Query addParameter(String name, int value){ - try{ + try { statement.setInt(name, value); } - catch (SQLException ex){ - throw new Sql2oException(ex); + catch(SQLException ex) { + throw new RuntimeException(ex); } return this; } - public Query addParameter(String name, Integer value){ - try{ - if (value == null){ + public Query addParameter(String name, Integer value) { + try { + if (value == null) { statement.setNull(name, Types.INTEGER); - }else{ + } + else { statement.setInt(name, value); } } @@ -109,20 +145,21 @@ public Query addParameter(String name, Integer value){ } public Query addParameter(String name, long value){ - try{ + try { statement.setLong(name, value); } - catch(SQLException ex){ + catch(SQLException ex) { throw new RuntimeException(ex); } return this; } public Query addParameter(String name, Long value){ - try{ - if (value == null){ - statement.setNull(name, Types.INTEGER); - } else { + try { + if (value == null) { + statement.setNull(name, Types.BIGINT); + } + else { statement.setLong(name, value); } } @@ -132,151 +169,83 @@ public Query addParameter(String name, Long value){ return this; } - public Query addParameter(String name, String value){ - try{ - if (value == null){ + public Query addParameter(String name, String value) { + try { + if (value == null) { statement.setNull(name, Types.VARCHAR); - }else{ + } + else { statement.setString(name, value); } } - catch(Exception ex){ + catch (SQLException ex) { throw new RuntimeException(ex); } return this; } public Query addParameter(String name, Timestamp value){ - try{ - if (value == null){ + try { + if (value == null) { statement.setNull(name, Types.TIMESTAMP); - } else { + } + else { statement.setTimestamp(name, value); } } - catch(Exception ex){ + catch(SQLException ex) { throw new RuntimeException(ex); } return this; } - public Query addParameter(String name, Date value){ - if (value != null && this.connection.getSql2o().quirksMode == QuirksMode.DB2){ - // With the DB2 driver you can get an error if trying to put a date value into a timestamp column, - // but of some reason it works if using setObject(). - return addParameter(name, (Object)value); - } - - // by default add a timestamp, because it works with DATE, DATETIME, TIMESTAMP columns - Timestamp timestamp = value == null ? null : new Timestamp(value.getTime()); - return addParameter(name, timestamp); - } - - public Query addParameter(String name, java.util.Date value){ - Date sqlDate = value == null ? null : new Date(value.getTime()); - return addParameter(name, sqlDate); - - } - - public Query addParameter(String name, Time value){ + public Query addParameter(String name, Time value) { try { if (value == null){ statement.setNull(name, Types.TIME); - } else { + } + else { statement.setTime(name,value); } - } catch (SQLException e) { + } + catch (SQLException e) { throw new RuntimeException(e); } return this; } - public Query addParameter(String name, Enum value) { - String strVal = value == null ? null : value.toString(); - return addParameter(name, strVal); - } - - /** - * @return {@code true} if {@code value} is type DateTime and parameter added. - */ - private boolean tryAddJodaDateTimeParameter(String name, Object value) { - - if (FeatureDetector.isJodaTimeAvailable() && value != null) { - if (DateTime.class.isAssignableFrom(value.getClass())) { - Timestamp timestamp = new Timestamp(((DateTime)value).toDate().getTime()); - addParameter(name, timestamp); - return true; - } - } - - return false; - } - - public Query bind(Object bean){ + public Query bind(Object bean) { Class clazz = bean.getClass(); Method[] methods = clazz.getDeclaredMethods(); - for(Method method : methods){ - try{ + for(Method method : methods) { + try { method.setAccessible(true); String methodName = method.getName(); - /* - It looks in the class for all the methods that start with get - */ + + // look in the class for all the methods that start with get if(methodName.startsWith("get") && method.getParameterTypes().length == 0){ String param = methodName.substring(3);//remove the get prefix param = param.substring(0, 1).toLowerCase() + param.substring(1);//set the first letter in Lowercase => so getItem produces item Object res = method.invoke(bean); - if( res!= null){ - try { - Method addParam = this.getClass().getDeclaredMethod("addParameter", param.getClass(), method.getReturnType()); - addParam.invoke(this, param, res); - } catch (NoSuchMethodException ex) { - logger.debug("Using addParameter(String, Object)", ex); - addParameter(param, res); - } - } - else { - addParameter(param, res); - } + this.addParameter(param, res); } - }catch(IllegalArgumentException ex){ + } + catch(IllegalArgumentException ex) { logger.debug("Ignoring Illegal Arguments", ex); - }catch(IllegalAccessException ex){ - throw new RuntimeException(ex); - } catch (SecurityException ex) { + } + catch(IllegalAccessException ex) { throw new RuntimeException(ex); - } catch (InvocationTargetException ex) { + } + catch (InvocationTargetException ex) { throw new RuntimeException(ex); } } return this; } - public boolean isCaseSensitive() { - return caseSensitive; - } - - public Query setCaseSensitive(boolean caseSensitive) { - this.caseSensitive = caseSensitive; - return this; - } - - public boolean isAutoDeriveColumnNames() { - return autoDeriveColumnNames; - } - - public Query setAutoDeriveColumnNames(boolean autoDeriveColumnNames) { - this.autoDeriveColumnNames = autoDeriveColumnNames; - return this; - } - - public Connection getConnection(){ - return this.connection; - } - - public String getName() { - return name; - } + // ------------------------------------------------ + // -------------------- Execute ------------------- + // ------------------------------------------------ /** * Iterable {@link java.sql.ResultSet} that wraps {@link PojoResultSetIterator}. @@ -336,7 +305,7 @@ public ResultSetIterable executeAndFetchLazy(final Class returnType) { private PojoMetadata pojoMetadata = new PojoMetadata(returnType, isCaseSensitive(), isAutoDeriveColumnNames(), getColumnMappings()); public Iterator iterator() { - return new PojoResultSetIterator(rs, isCaseSensitive(), getConnection().getSql2o().quirksMode, pojoMetadata); + return new PojoResultSetIterator(rs, isCaseSensitive(), getConnection().getSql2o().getQuirks(), pojoMetadata); } }; } @@ -381,7 +350,7 @@ public LazyTable executeAndFetchTableLazy() { lt.setRows(new ResultSetIterableBase() { public Iterator iterator() { - return new TableResultSetIterator(rs, isCaseSensitive(), getConnection().getSql2o().quirksMode, lt); + return new TableResultSetIterator(rs, isCaseSensitive(), getConnection().getSql2o().getQuirks(), lt); } }); @@ -399,11 +368,14 @@ public Table executeAndFetchTable() { for (Row item : lt.rows()) { rows.add(item); } - } finally { - lt.close(); + } + finally { + if (lt != null) { + lt.close(); + } } - return new Table(lt.getName(), rows, lt.columns()); + return lt == null ? null : new Table(lt.getName(), rows, lt.columns()); } public Connection executeUpdate(){ @@ -461,10 +433,11 @@ public Object executeScalar(){ public V executeScalar(Class returnType){ Object value = executeScalar(); - Converter converter; + Converter converter; try { + //noinspection unchecked converter = Convert.getConverter(returnType); - return (V)converter.convert(value); + return converter.convert(value); } catch (ConverterException e) { throw new Sql2oException("Error occured while converting value from database to type " + returnType.toString(), e); } @@ -475,11 +448,12 @@ public List executeScalarList(Class returnType){ long start = System.currentTimeMillis(); List list = new ArrayList(); try{ - Converter converter = Convert.getConverter(returnType); + //noinspection unchecked + Converter converter = Convert.getConverter(returnType); ResultSet rs = this.statement.executeQuery(); while(rs.next()){ Object value = ResultSetUtils.getRSVal(rs, 1); - list.add((T)converter.convert(value)); + list.add(converter.convert(value)); } long end = System.currentTimeMillis(); @@ -570,6 +544,7 @@ public Query addColumnMapping(String columnName, String propertyName){ } /************** private stuff ***************/ + private void closeConnectionIfNecessary(){ try{ if (connection.autoClose && !connection.getJdbcConnection().isClosed() && statement != null){ diff --git a/core/src/main/java/org/sql2o/ResultSetIteratorBase.java b/core/src/main/java/org/sql2o/ResultSetIteratorBase.java index 03ecba79..9e633d24 100644 --- a/core/src/main/java/org/sql2o/ResultSetIteratorBase.java +++ b/core/src/main/java/org/sql2o/ResultSetIteratorBase.java @@ -1,5 +1,7 @@ package org.sql2o; +import org.sql2o.quirks.Quirks; + import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; @@ -16,13 +18,13 @@ public abstract class ResultSetIteratorBase implements Iterator { // fields needed to read result set protected ResultSet rs; protected boolean isCaseSensitive; - protected QuirksMode quirksMode; + protected Quirks quirks; protected ResultSetMetaData meta; - public ResultSetIteratorBase(ResultSet rs, boolean isCaseSensitive, QuirksMode quirksMode) { + public ResultSetIteratorBase(ResultSet rs, boolean isCaseSensitive, Quirks quirks) { this.rs = rs; this.isCaseSensitive = isCaseSensitive; - this.quirksMode = quirksMode; + this.quirks = quirks; try { meta = rs.getMetaData(); } @@ -92,11 +94,6 @@ private T safeReadNext() protected abstract T readNext() throws SQLException; protected String getColumnName(int colIdx) throws SQLException { - if (quirksMode == QuirksMode.DB2){ - return meta.getColumnName(colIdx); - } - else { - return meta.getColumnLabel(colIdx); - } + return quirks.getColumnName(meta, colIdx); } } diff --git a/core/src/main/java/org/sql2o/Sql2o.java b/core/src/main/java/org/sql2o/Sql2o.java index 4be021bd..b9cc0068 100644 --- a/core/src/main/java/org/sql2o/Sql2o.java +++ b/core/src/main/java/org/sql2o/Sql2o.java @@ -1,5 +1,9 @@ package org.sql2o; +import org.sql2o.converters.Convert; +import org.sql2o.converters.Converter; +import org.sql2o.quirks.*; + import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; @@ -18,12 +22,17 @@ * was specified in the constructor, a simple data source is created, which works as a simple wrapper around the jdbc * driver. *

- * Some jdbc implementations has quirks, therefor it may be necessary to use a constructor with the quirksMode parameter. - * When quirksMode is specified, Sql2o will use workarounds to avoid these quirks. + * Some jdbc implementations have quirks, therefore it may be necessary to use a constructor with the quirks parameter. + * When quirks are specified, Sql2o will use workarounds to avoid these quirks. * @author Lars Aaberg */ public class Sql2o { + private Quirks quirks; + private final DataSource dataSource; + private Map defaultColumnMappings; + private boolean defaultCaseSensitive; + public Sql2o(String jndiLookup) { this(_getJndiDatasource(jndiLookup)); } @@ -61,47 +70,86 @@ private static DataSource _getJndiDatasource(String jndiLookup) { * @param pass database password */ public Sql2o(String url, String user, String pass){ - this(url,user,pass,QuirksMode.None); + this(url, user, pass, new NoQuirks()); } /** - * Created a new instance of the Sql2o class. Internally this constructor will create a {@link GenericDatasource}, - * and call the {@link Sql2o#Sql2o(javax.sql.DataSource)} constructor which takes a DataSource as parameter. - * @param url JDBC database url - * @param user database username - * @param pass database password - * @param quirksMode @{link QuirksMode} allows sql2o to work around known quirks and issues in different JDBC drivers. + * Use {@link #Sql2o(String, String, String, org.sql2o.quirks.Quirks)}. */ + @Deprecated public Sql2o(String url, String user, String pass, QuirksMode quirksMode) { this(new GenericDatasource(url, user, pass), quirksMode); } + /** + * Created a new instance of the Sql2o class. Internally this constructor will create a {@link GenericDatasource}, + * and call the {@link Sql2o#Sql2o(javax.sql.DataSource)} constructor which takes a DataSource as parameter. + * @param url JDBC database url + * @param user database username + * @param pass database password + * @param quirks {@link org.sql2o.quirks.Quirks} allows sql2o to work around known quirks and issues in different JDBC drivers. + */ + public Sql2o(String url, String user, String pass, Quirks quirks) { + this(new GenericDatasource(url, user, pass), quirks); + } + /** * Creates a new instance of the Sql2o class, which uses the given DataSource to acquire connections to the database. * @param dataSource The DataSource Sql2o uses to acquire connections to the database. */ public Sql2o(DataSource dataSource) { - this(dataSource, QuirksMode.None); + this(dataSource, new NoQuirks()); } /** - * Creates a new instance of the Sql2o class, which uses the given DataSource to acquire connections to the database. - * @param dataSource The DataSource Sql2o uses to acquire connections to the database. - * @param quirksMode @{link QuirksMode} allows sql2o to work around known quirks and issues in different JDBC drivers. + * Use {@link #Sql2o(javax.sql.DataSource, org.sql2o.quirks.Quirks)}. */ - public Sql2o(DataSource dataSource, QuirksMode quirksMode){ + @Deprecated + public Sql2o(DataSource dataSource, QuirksMode quirksMode) { this.dataSource = dataSource; - this.quirksMode = quirksMode; + this.setQuirks(getQuirksForMode(quirksMode)); + this.defaultColumnMappings = new HashMap(); + } + /** + * Creates a new instance of the Sql2o class, which uses the given DataSource to acquire connections to the database. + * @param dataSource The DataSource Sql2o uses to acquire connections to the database. + * @param quirks {@link org.sql2o.quirks.Quirks} allows sql2o to work around known quirks and issues in different JDBC drivers. + */ + public Sql2o(DataSource dataSource, Quirks quirks){ + this.dataSource = dataSource; + this.setQuirks(quirks); this.defaultColumnMappings = new HashMap(); } - private final DataSource dataSource; - QuirksMode quirksMode; + // TODO delete this method when {@link org.sql2o.QuirksMode} removed. + private Quirks getQuirksForMode(QuirksMode quirksMode) { + if (quirksMode == QuirksMode.DB2) { + return new Db2Quirks(); + } + else if (quirksMode == QuirksMode.PostgreSQL) { + return new PostgresQuirks(); + } + else if (quirksMode == QuirksMode.MSSqlServer) { + return new SqlServerQuirks(); + } + else { + return new NoQuirks(); + } + } - private Map defaultColumnMappings; + Quirks getQuirks() { + return quirks; + } + + private void setQuirks(Quirks quirks) { + this.quirks = quirks; - private boolean defaultCaseSensitive = false; + // register custom converters + for (Map.Entry entry : quirks.customConverters().entrySet()) { + Convert.registerConverter(entry.getKey(), entry.getValue()); + } + } /** * Gets the DataSource that Sql2o uses internally to acquire database connections. diff --git a/core/src/main/java/org/sql2o/SqlParameter.java b/core/src/main/java/org/sql2o/SqlParameter.java new file mode 100644 index 00000000..67e88760 --- /dev/null +++ b/core/src/main/java/org/sql2o/SqlParameter.java @@ -0,0 +1,24 @@ +package org.sql2o; + +/** + * @author aldenquimby@gmail.com + * @since 4/6/14 + */ +public class SqlParameter { + + private int sqlType; + private Object value; + + public SqlParameter(int sqlType, Object value) { + this.sqlType = sqlType; + this.value = value; + } + + public int getSqlType() { + return sqlType; + } + + public Object getValue() { + return value; + } +} diff --git a/core/src/main/java/org/sql2o/converters/BigDecimalConverter.java b/core/src/main/java/org/sql2o/converters/BigDecimalConverter.java index 40fea5f9..62ff647d 100644 --- a/core/src/main/java/org/sql2o/converters/BigDecimalConverter.java +++ b/core/src/main/java/org/sql2o/converters/BigDecimalConverter.java @@ -1,6 +1,9 @@ package org.sql2o.converters; +import org.sql2o.tools.StatementParameterSetter; + import java.math.BigDecimal; +import java.sql.SQLException; /** * Used by sql2o to convert a value from the database into a {@link BigDecimal}. @@ -30,4 +33,8 @@ protected BigDecimal convertStringValue(String val) { protected String getTypeDescription() { return BigDecimal.class.toString(); } + + public void addParameter(StatementParameterSetter stmt, String name, BigDecimal val) throws SQLException { + stmt.setObject(name, val); + } } diff --git a/core/src/main/java/org/sql2o/converters/BooleanConverter.java b/core/src/main/java/org/sql2o/converters/BooleanConverter.java index d64211ac..940b01c1 100644 --- a/core/src/main/java/org/sql2o/converters/BooleanConverter.java +++ b/core/src/main/java/org/sql2o/converters/BooleanConverter.java @@ -1,5 +1,11 @@ package org.sql2o.converters; +import org.sql2o.SqlParameter; +import org.sql2o.tools.StatementParameterSetter; + +import java.sql.SQLException; +import java.sql.Types; + /** * Created with IntelliJ IDEA. * User: lars @@ -7,7 +13,7 @@ * Time: 10:54 PM * To change this template use File | Settings | File Templates. */ -public class BooleanConverter implements Converter { +public class BooleanConverter extends BuiltInConverterBase { public Boolean convert(Object val) throws ConverterException { if (val == null) return null; @@ -28,4 +34,13 @@ public Boolean convert(Object val) throws ConverterException { throw new ConverterException("Don't know how to convert type " + val.getClass().getName() + " to " + Boolean.class.getName()); } + + public void addParameter(StatementParameterSetter stmt, String name, Boolean val) throws SQLException { + if (val == null) { + stmt.setNull(name, Types.BOOLEAN); + } + else { + stmt.setObject(name, val); + } + } } diff --git a/core/src/main/java/org/sql2o/converters/BuiltInConverterBase.java b/core/src/main/java/org/sql2o/converters/BuiltInConverterBase.java new file mode 100644 index 00000000..d7027a2c --- /dev/null +++ b/core/src/main/java/org/sql2o/converters/BuiltInConverterBase.java @@ -0,0 +1,12 @@ +package org.sql2o.converters; + +/** + * @author aldenquimby@gmail.com + * @since 4/6/14 + */ +abstract class BuiltInConverterBase implements Converter { + + public Object toDatabaseParam(T val) { + return val; + } +} diff --git a/core/src/main/java/org/sql2o/converters/ByteArrayConverter.java b/core/src/main/java/org/sql2o/converters/ByteArrayConverter.java index 6cce6c20..eacd1783 100644 --- a/core/src/main/java/org/sql2o/converters/ByteArrayConverter.java +++ b/core/src/main/java/org/sql2o/converters/ByteArrayConverter.java @@ -1,6 +1,7 @@ package org.sql2o.converters; import org.sql2o.tools.IOUtils; +import org.sql2o.tools.StatementParameterSetter; import java.io.IOException; import java.sql.Blob; @@ -13,7 +14,8 @@ * Time: 11:36 PM * To change this template use File | Settings | File Templates. */ -public class ByteArrayConverter implements Converter { +public class ByteArrayConverter extends BuiltInConverterBase { + public byte[] convert(Object val) throws ConverterException { if (val == null) return null; @@ -34,4 +36,8 @@ public byte[] convert(Object val) throws ConverterException { throw new RuntimeException("could not convert " + val.getClass().getName() + " to byte[]"); } + + public void addParameter(StatementParameterSetter stmt, String name, byte[] val) throws SQLException { + stmt.setObject(name, val); + } } diff --git a/core/src/main/java/org/sql2o/converters/ByteConverter.java b/core/src/main/java/org/sql2o/converters/ByteConverter.java index 7b32677d..8374c7e8 100644 --- a/core/src/main/java/org/sql2o/converters/ByteConverter.java +++ b/core/src/main/java/org/sql2o/converters/ByteConverter.java @@ -1,5 +1,10 @@ package org.sql2o.converters; +import org.sql2o.tools.StatementParameterSetter; + +import java.sql.SQLException; +import java.sql.Types; + /** * Used by sql2o to convert a value from the database into a {@link Byte}. */ @@ -23,4 +28,13 @@ protected Byte convertStringValue(String val) { protected String getTypeDescription() { return Byte.class.toString(); } + + public void addParameter(StatementParameterSetter stmt, String name, Byte val) throws SQLException { + if (val == null) { + stmt.setNull(name, Types.TINYINT); + } + else { + stmt.setInt(name, val); + } + } } diff --git a/core/src/main/java/org/sql2o/converters/Convert.java b/core/src/main/java/org/sql2o/converters/Convert.java index 336870c9..e75e3175 100644 --- a/core/src/main/java/org/sql2o/converters/Convert.java +++ b/core/src/main/java/org/sql2o/converters/Convert.java @@ -2,6 +2,8 @@ import org.joda.time.DateTime; import org.joda.time.LocalTime; +import org.sql2o.converters.joda.DateTimeConverter; +import org.sql2o.converters.joda.LocalTimeConverter; import org.sql2o.tools.FeatureDetector; import java.io.ByteArrayInputStream; @@ -63,7 +65,7 @@ public class Convert { registerConverter(UUID.class, new UUIDConverter()); if (FeatureDetector.isJodaTimeAvailable()) { - registerConverter(DateTime.class, new JodaTimeConverter()); + registerConverter(DateTime.class, new DateTimeConverter()); registerConverter(LocalTime.class, new LocalTimeConverter()); } } diff --git a/core/src/main/java/org/sql2o/converters/Converter.java b/core/src/main/java/org/sql2o/converters/Converter.java index 18cff2b5..36d1145f 100644 --- a/core/src/main/java/org/sql2o/converters/Converter.java +++ b/core/src/main/java/org/sql2o/converters/Converter.java @@ -1,9 +1,17 @@ package org.sql2o.converters; +import org.sql2o.tools.StatementParameterSetter; + +import java.sql.SQLException; + /** * Represents a converter. */ public interface Converter { T convert(Object val) throws ConverterException; + + void addParameter(StatementParameterSetter stmt, String name, T val) throws SQLException; + + Object toDatabaseParam(T val); } diff --git a/core/src/main/java/org/sql2o/converters/DateConverter.java b/core/src/main/java/org/sql2o/converters/DateConverter.java index 008782b0..a4fdcd32 100644 --- a/core/src/main/java/org/sql2o/converters/DateConverter.java +++ b/core/src/main/java/org/sql2o/converters/DateConverter.java @@ -1,7 +1,10 @@ package org.sql2o.converters; -import org.sql2o.Sql2oException; +import org.sql2o.tools.StatementParameterSetter; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.sql.Types; import java.util.Date; /** @@ -20,4 +23,19 @@ public Date convert(Object val) throws ConverterException { throw new ConverterException("Cannot convert type " + val.getClass().toString() + " to java.util.Date"); } + + public void addParameter(StatementParameterSetter stmt, String name, Date val) throws SQLException { + if (val == null) { + stmt.setNull(name, Types.DATE); + } + else { + // by default add a timestamp, because it works with DATE, DATETIME, TIMESTAMP columns + Timestamp timestamp = new Timestamp(val.getTime()); + stmt.setTimestamp(name, timestamp); + } + } + + public Object toDatabaseParam(Date val) { + return new Timestamp(val.getTime()); + } } diff --git a/core/src/main/java/org/sql2o/converters/DateConverterNoTimestamp.java b/core/src/main/java/org/sql2o/converters/DateConverterNoTimestamp.java new file mode 100644 index 00000000..1f5439f0 --- /dev/null +++ b/core/src/main/java/org/sql2o/converters/DateConverterNoTimestamp.java @@ -0,0 +1,14 @@ +package org.sql2o.converters; + +import java.util.Date; + +/** + * @author aldenquimby@gmail.com + * @since 4/6/14 + */ +public class DateConverterNoTimestamp extends DateConverter { + @Override + public Object toDatabaseParam(Date val) { + return new java.sql.Date(val.getTime()); + } +} diff --git a/core/src/main/java/org/sql2o/converters/DefaultEnumConverter.java b/core/src/main/java/org/sql2o/converters/DefaultEnumConverter.java index ffb71665..e6e5f506 100644 --- a/core/src/main/java/org/sql2o/converters/DefaultEnumConverter.java +++ b/core/src/main/java/org/sql2o/converters/DefaultEnumConverter.java @@ -1,11 +1,16 @@ package org.sql2o.converters; +import org.sql2o.tools.StatementParameterSetter; + +import java.sql.SQLException; +import java.sql.Types; + /** * Default implementation of {@link org.sql2o.converters.EnumConverter}, * used by sql2o to convert a value from the database into an {@link Enum}. */ -public class DefaultEnumConverter implements EnumConverter -{ +public class DefaultEnumConverter implements EnumConverter { + private Class enumType; public void setEnumType(Class clazz) @@ -26,4 +31,17 @@ public Enum convert(Object val) throws ConverterException { } throw new ConverterException("Cannot convert type '" + val.getClass().getName() + "' to an Enum"); } + + public void addParameter(StatementParameterSetter stmt, String name, Enum val) throws SQLException { + if (val == null) { + stmt.setNull(name, Types.VARCHAR); + } + else { + stmt.setString(name, val.toString()); + } + } + + public Object toDatabaseParam(Enum val) { + return val.toString(); + } } diff --git a/core/src/main/java/org/sql2o/converters/DoubleConverter.java b/core/src/main/java/org/sql2o/converters/DoubleConverter.java index 5a368857..d8125a15 100644 --- a/core/src/main/java/org/sql2o/converters/DoubleConverter.java +++ b/core/src/main/java/org/sql2o/converters/DoubleConverter.java @@ -1,5 +1,11 @@ package org.sql2o.converters; +import org.sql2o.SqlParameter; +import org.sql2o.tools.StatementParameterSetter; + +import java.sql.SQLException; +import java.sql.Types; + /** * Used by sql2o to convert a value from the database into a {@link Double}. */ @@ -23,4 +29,13 @@ protected Double convertStringValue(String val) { protected String getTypeDescription() { return Double.class.toString(); } + + public void addParameter(StatementParameterSetter stmt, String name, Double val) throws SQLException { + if (val == null) { + stmt.setNull(name, Types.DOUBLE); + } + else { + stmt.setObject(name, val); + } + } } diff --git a/core/src/main/java/org/sql2o/converters/FloatConverter.java b/core/src/main/java/org/sql2o/converters/FloatConverter.java index 1dea719a..4c9ab2ac 100644 --- a/core/src/main/java/org/sql2o/converters/FloatConverter.java +++ b/core/src/main/java/org/sql2o/converters/FloatConverter.java @@ -1,5 +1,11 @@ package org.sql2o.converters; +import org.sql2o.SqlParameter; +import org.sql2o.tools.StatementParameterSetter; + +import java.sql.SQLException; +import java.sql.Types; + /** * Used by sql2o to convert a value from the database into a {@link Float}. */ @@ -23,4 +29,13 @@ protected Float convertStringValue(String val) { protected String getTypeDescription() { return Float.class.toString(); } + + public void addParameter(StatementParameterSetter stmt, String name, Float val) throws SQLException { + if (val == null) { + stmt.setNull(name, Types.FLOAT); + } + else { + stmt.setObject(name, val); + } + } } diff --git a/core/src/main/java/org/sql2o/converters/InputStreamConverter.java b/core/src/main/java/org/sql2o/converters/InputStreamConverter.java index a3ff3d98..c8cdd623 100644 --- a/core/src/main/java/org/sql2o/converters/InputStreamConverter.java +++ b/core/src/main/java/org/sql2o/converters/InputStreamConverter.java @@ -1,6 +1,9 @@ package org.sql2o.converters; +import org.sql2o.tools.StatementParameterSetter; + import java.io.ByteArrayInputStream; +import java.sql.SQLException; /** * Created with IntelliJ IDEA. @@ -9,7 +12,7 @@ * Time: 11:40 PM * To change this template use File | Settings | File Templates. */ -public class InputStreamConverter implements Converter { +public class InputStreamConverter extends BuiltInConverterBase { public ByteArrayInputStream convert(Object val) throws ConverterException { if (val == null) return null; @@ -19,4 +22,8 @@ public ByteArrayInputStream convert(Object val) throws ConverterException { throw new ConverterException("Error converting Blob to InputSteam"); } } + + public void addParameter(StatementParameterSetter stmt, String name, ByteArrayInputStream val) throws SQLException { + stmt.setObject(name, val); + } } diff --git a/core/src/main/java/org/sql2o/converters/IntegerConverter.java b/core/src/main/java/org/sql2o/converters/IntegerConverter.java index d1db638c..cc84b8b0 100644 --- a/core/src/main/java/org/sql2o/converters/IntegerConverter.java +++ b/core/src/main/java/org/sql2o/converters/IntegerConverter.java @@ -1,9 +1,10 @@ package org.sql2o.converters; -import org.sql2o.Sql2oException; +import org.sql2o.SqlParameter; +import org.sql2o.tools.StatementParameterSetter; -import java.math.BigDecimal; -import java.math.BigInteger; +import java.sql.SQLException; +import java.sql.Types; /** * Used by sql2o to convert a value from the database into an {@link Integer}. @@ -28,4 +29,13 @@ protected Integer convertStringValue(String val) { protected String getTypeDescription() { return Integer.class.toString(); } + + public void addParameter(StatementParameterSetter stmt, String name, Integer val) throws SQLException { + if (val == null) { + stmt.setNull(name, Types.INTEGER); + } + else { + stmt.setInt(name, val); + } + } } diff --git a/core/src/main/java/org/sql2o/converters/JodaTimeConverter.java b/core/src/main/java/org/sql2o/converters/JodaTimeConverter.java deleted file mode 100644 index 1a1bfb98..00000000 --- a/core/src/main/java/org/sql2o/converters/JodaTimeConverter.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.sql2o.converters; - -import org.joda.time.DateTime; -import org.joda.time.DateTimeZone; -import org.joda.time.LocalDateTime; - -/** - * Used by sql2o to convert a value from the database into a {@link DateTime} instance. - */ -public class JodaTimeConverter implements Converter { - public DateTime convert(Object val) throws ConverterException { - if (val == null){ - return null; - } - - try{ - return new LocalDateTime(val).toDateTime(DateTimeZone.UTC); - } - catch(Throwable t){ - throw new ConverterException("Error while converting type " + val.getClass().toString() + " to jodatime", t); - } - } -} diff --git a/core/src/main/java/org/sql2o/converters/LocalTimeConverter.java b/core/src/main/java/org/sql2o/converters/LocalTimeConverter.java deleted file mode 100644 index 5d312518..00000000 --- a/core/src/main/java/org/sql2o/converters/LocalTimeConverter.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.sql2o.converters; - -import org.joda.time.LocalTime; - -import java.sql.Time; - -/** - * Created by lars on 12/18/13. - */ -public class LocalTimeConverter implements Converter { - public LocalTime convert(Object val) throws ConverterException { - if (val == null) { - return null; - } - - if (!(val instanceof Time)){ - throw new ConverterException("Don't know how to convert from type '" + val.getClass().getName() + "' to type '" + LocalTime.class.getName() + "'"); - } - - return new LocalTime(val); - } -} diff --git a/core/src/main/java/org/sql2o/converters/LongConverter.java b/core/src/main/java/org/sql2o/converters/LongConverter.java index ac7dc77d..3fec4e5b 100644 --- a/core/src/main/java/org/sql2o/converters/LongConverter.java +++ b/core/src/main/java/org/sql2o/converters/LongConverter.java @@ -1,9 +1,15 @@ package org.sql2o.converters; +import org.sql2o.SqlParameter; +import org.sql2o.tools.StatementParameterSetter; + +import java.sql.SQLException; +import java.sql.Types; + /** * Used by sql2o to convert a value from the database into a {@link Long}. */ -public class LongConverter extends NumberConverter{ +public class LongConverter extends NumberConverter { public LongConverter(boolean primitive) { super(primitive); @@ -23,4 +29,13 @@ protected Long convertStringValue(String val) { protected String getTypeDescription() { return Long.class.toString(); } + + public void addParameter(StatementParameterSetter stmt, String name, Long val) throws SQLException { + if (val == null) { + stmt.setNull(name, Types.BIGINT); + } + else { + stmt.setLong(name, val); + } + } } diff --git a/core/src/main/java/org/sql2o/converters/NumberConverter.java b/core/src/main/java/org/sql2o/converters/NumberConverter.java index 672ec4ed..75c6c40b 100644 --- a/core/src/main/java/org/sql2o/converters/NumberConverter.java +++ b/core/src/main/java/org/sql2o/converters/NumberConverter.java @@ -3,15 +3,17 @@ /** * Base class for numeric converters. */ -public abstract class NumberConverter implements Converter{ +public abstract class NumberConverter extends BuiltInConverterBase{ + + private boolean isPrimitive; public NumberConverter(boolean primitive) { isPrimitive = primitive; } public V convert(Object val) { - if (val == null){ - return null; + if (val == null) { + return isPrimitive ? convertNumberValue(0) : null; } else if (val.getClass().isPrimitive() || Number.class.isAssignableFrom( val.getClass()) ) { return convertNumberValue((Number)val); @@ -20,11 +22,8 @@ else if (val.getClass().equals(String.class)){ String stringVal = ((String)val).trim(); stringVal = stringVal.isEmpty() ? null : stringVal; - if (stringVal == null && isPrimitive){ - return convertNumberValue(0); - } - else if (stringVal == null){ - return null; + if (stringVal == null) { + return isPrimitive ? convertNumberValue(0) : null; } return convertStringValue(stringVal); @@ -33,12 +32,10 @@ else if (stringVal == null){ throw new IllegalArgumentException("Cannot convert type " + val.getClass().toString() + " to " + getTypeDescription()); } } - + protected abstract V convertNumberValue(Number val); protected abstract V convertStringValue(String val); protected abstract String getTypeDescription(); - - private boolean isPrimitive; } diff --git a/core/src/main/java/org/sql2o/converters/ShortConverter.java b/core/src/main/java/org/sql2o/converters/ShortConverter.java index 46813630..9c48854c 100644 --- a/core/src/main/java/org/sql2o/converters/ShortConverter.java +++ b/core/src/main/java/org/sql2o/converters/ShortConverter.java @@ -1,5 +1,11 @@ package org.sql2o.converters; +import org.sql2o.SqlParameter; +import org.sql2o.tools.StatementParameterSetter; + +import java.sql.SQLException; +import java.sql.Types; + /** * Used by sql2o to convert a value from the database into a {@link Short}. */ @@ -23,4 +29,13 @@ protected Short convertStringValue(String val) { protected String getTypeDescription() { return Short.class.toString(); } + + public void addParameter(StatementParameterSetter stmt, String name, Short val) throws SQLException { + if (val == null) { + stmt.setNull(name, Types.SMALLINT); + } + else { + stmt.setInt(name, val); + } + } } diff --git a/core/src/main/java/org/sql2o/converters/StringConverter.java b/core/src/main/java/org/sql2o/converters/StringConverter.java index 673b2d14..be3b99b0 100644 --- a/core/src/main/java/org/sql2o/converters/StringConverter.java +++ b/core/src/main/java/org/sql2o/converters/StringConverter.java @@ -1,12 +1,15 @@ package org.sql2o.converters; +import org.sql2o.tools.StatementParameterSetter; + import java.sql.Clob; import java.sql.SQLException; +import java.sql.Types; /** * Used by sql2o to convert a value from the database into a {@link String}. */ -public class StringConverter implements Converter{ +public class StringConverter extends BuiltInConverterBase { public String convert(Object val) throws ConverterException { if (val == null){ @@ -24,4 +27,13 @@ public String convert(Object val) throws ConverterException { return val.toString().trim(); } + + public void addParameter(StatementParameterSetter stmt, String name, String val) throws SQLException { + if (val == null) { + stmt.setNull(name, Types.VARCHAR); + } + else { + stmt.setString(name, val); + } + } } diff --git a/core/src/main/java/org/sql2o/converters/UUIDConverter.java b/core/src/main/java/org/sql2o/converters/UUIDConverter.java index e5facbcb..88d743c6 100644 --- a/core/src/main/java/org/sql2o/converters/UUIDConverter.java +++ b/core/src/main/java/org/sql2o/converters/UUIDConverter.java @@ -1,13 +1,14 @@ package org.sql2o.converters; -import org.sql2o.Sql2oException; +import org.sql2o.tools.StatementParameterSetter; +import java.sql.SQLException; import java.util.UUID; /** * Used by sql2o to convert a value from the database into a {@link UUID}. */ -public class UUIDConverter implements Converter { +public class UUIDConverter extends BuiltInConverterBase { public UUID convert(Object val) throws ConverterException { if (val == null){ @@ -20,5 +21,9 @@ public UUID convert(Object val) throws ConverterException { throw new ConverterException("Cannot convert type " + val.getClass().toString() + " to java.util.UUID"); } + + public void addParameter(StatementParameterSetter stmt, String name, UUID val) throws SQLException { + stmt.setObject(name, val); + } } diff --git a/core/src/main/java/org/sql2o/converters/joda/DateTimeConverter.java b/core/src/main/java/org/sql2o/converters/joda/DateTimeConverter.java new file mode 100644 index 00000000..065fcf06 --- /dev/null +++ b/core/src/main/java/org/sql2o/converters/joda/DateTimeConverter.java @@ -0,0 +1,45 @@ +package org.sql2o.converters.joda; + +import org.joda.time.DateTime; +import org.joda.time.DateTimeZone; +import org.joda.time.LocalDateTime; +import org.sql2o.converters.Converter; +import org.sql2o.converters.ConverterException; +import org.sql2o.tools.StatementParameterSetter; + +import java.sql.SQLException; +import java.sql.Timestamp; +import java.sql.Types; + +/** + * Used by sql2o to convert a value from the database into a {@link DateTime} instance. + */ +public class DateTimeConverter implements Converter { + + public DateTime convert(Object val) throws ConverterException { + if (val == null){ + return null; + } + + try{ + return new LocalDateTime(val).toDateTime(DateTimeZone.UTC); + } + catch(Throwable t){ + throw new ConverterException("Error while converting type " + val.getClass().toString() + " to jodatime", t); + } + } + + public Object toDatabaseParam(DateTime val) { + return new Timestamp(val.getMillis()); + } + + public void addParameter(StatementParameterSetter stmt, String name, DateTime val) throws SQLException { + if (val == null) { + stmt.setNull(name, Types.TIMESTAMP); + } + else { + Timestamp sqlTimestamp = new Timestamp(val.getMillis()); + stmt.setTimestamp(name, sqlTimestamp); + } + } +} diff --git a/core/src/main/java/org/sql2o/converters/joda/LocalTimeConverter.java b/core/src/main/java/org/sql2o/converters/joda/LocalTimeConverter.java new file mode 100644 index 00000000..ccd62b3d --- /dev/null +++ b/core/src/main/java/org/sql2o/converters/joda/LocalTimeConverter.java @@ -0,0 +1,43 @@ +package org.sql2o.converters.joda; + +import org.joda.time.LocalTime; +import org.sql2o.SqlParameter; +import org.sql2o.converters.Converter; +import org.sql2o.converters.ConverterException; +import org.sql2o.tools.StatementParameterSetter; + +import java.sql.SQLException; +import java.sql.Time; +import java.sql.Types; + +/** + * Created by lars on 12/18/13. + */ +public class LocalTimeConverter implements Converter { + + public LocalTime convert(Object val) throws ConverterException { + if (val == null) { + return null; + } + + if (!(val instanceof Time)){ + throw new ConverterException("Don't know how to convert from type '" + val.getClass().getName() + "' to type '" + LocalTime.class.getName() + "'"); + } + + return new LocalTime(val); + } + + public Object toDatabaseParam(LocalTime val) { + return new Time(val.toDateTimeToday().getMillis()); + } + + public void addParameter(StatementParameterSetter stmt, String name, LocalTime val) throws SQLException { + if (val == null) { + stmt.setNull(name, Types.TIME); + } + else { + Time sqlTime = new Time(val.toDateTimeToday().getMillis()); + stmt.setTime(name, sqlTime); + } + } +} diff --git a/core/src/main/java/org/sql2o/data/TableResultSetIterator.java b/core/src/main/java/org/sql2o/data/TableResultSetIterator.java index f7023b03..9f47b93e 100644 --- a/core/src/main/java/org/sql2o/data/TableResultSetIterator.java +++ b/core/src/main/java/org/sql2o/data/TableResultSetIterator.java @@ -1,8 +1,8 @@ package org.sql2o.data; -import org.sql2o.QuirksMode; import org.sql2o.ResultSetIteratorBase; import org.sql2o.Sql2oException; +import org.sql2o.quirks.Quirks; import java.sql.ResultSet; import java.sql.SQLException; @@ -18,8 +18,8 @@ public class TableResultSetIterator extends ResultSetIteratorBase { private Map columnNameToIdxMap; private List columns; - public TableResultSetIterator(ResultSet rs, boolean isCaseSensitive, QuirksMode quirksMode, LazyTable lt) { - super(rs, isCaseSensitive, quirksMode); + public TableResultSetIterator(ResultSet rs, boolean isCaseSensitive, Quirks quirks, LazyTable lt) { + super(rs, isCaseSensitive, quirks); this.columnNameToIdxMap = new HashMap(); this.columns = new ArrayList(); diff --git a/core/src/main/java/org/sql2o/quirks/Db2Quirks.java b/core/src/main/java/org/sql2o/quirks/Db2Quirks.java new file mode 100644 index 00000000..9d0667df --- /dev/null +++ b/core/src/main/java/org/sql2o/quirks/Db2Quirks.java @@ -0,0 +1,34 @@ +package org.sql2o.quirks; + +import org.sql2o.converters.Converter; +import org.sql2o.converters.DateConverterNoTimestamp; + +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * @author aldenquimby@gmail.com + * @since 4/6/14 + */ +public class Db2Quirks extends NoQuirks { + + public Map customConverters() { + Map customConverters = new HashMap(); + + Converter dateConverter = new DateConverterNoTimestamp(); + customConverters.put(Date.class, dateConverter); + customConverters.put(java.sql.Date.class, dateConverter); + customConverters.put(java.sql.Time.class, dateConverter); + customConverters.put(java.sql.Timestamp.class, dateConverter); + + return customConverters; + } + + @Override + public String getColumnName(ResultSetMetaData meta, int colIdx) throws SQLException { + return meta.getColumnName(colIdx); + } +} diff --git a/core/src/main/java/org/sql2o/quirks/NoQuirks.java b/core/src/main/java/org/sql2o/quirks/NoQuirks.java new file mode 100644 index 00000000..0561f4bd --- /dev/null +++ b/core/src/main/java/org/sql2o/quirks/NoQuirks.java @@ -0,0 +1,26 @@ +package org.sql2o.quirks; + +import org.sql2o.converters.Converter; + +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.util.Collections; +import java.util.Map; + +/** + * @author aldenquimby@gmail.com + * @since 4/6/14 + */ +public class NoQuirks implements Quirks { + public Map customConverters() { + return Collections.emptyMap(); + } + + public String getColumnName(ResultSetMetaData meta, int colIdx) throws SQLException { + return meta.getColumnLabel(colIdx); + } + + public boolean returnGeneratedKeysByDefault() { + return true; + } +} diff --git a/core/src/main/java/org/sql2o/quirks/PostgresQuirks.java b/core/src/main/java/org/sql2o/quirks/PostgresQuirks.java new file mode 100644 index 00000000..8afc99d6 --- /dev/null +++ b/core/src/main/java/org/sql2o/quirks/PostgresQuirks.java @@ -0,0 +1,12 @@ +package org.sql2o.quirks; + +/** + * @author aldenquimby@gmail.com + * @since 4/6/14 + */ +public class PostgresQuirks extends NoQuirks { + @Override + public boolean returnGeneratedKeysByDefault() { + return false; + } +} diff --git a/core/src/main/java/org/sql2o/quirks/Quirks.java b/core/src/main/java/org/sql2o/quirks/Quirks.java new file mode 100644 index 00000000..49a5c781 --- /dev/null +++ b/core/src/main/java/org/sql2o/quirks/Quirks.java @@ -0,0 +1,20 @@ +package org.sql2o.quirks; + +import org.sql2o.converters.Converter; + +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.util.Map; + +/** + * @author aldenquimby@gmail.com + * @since 4/6/14 + */ +public interface Quirks { + + Map customConverters(); + + String getColumnName(ResultSetMetaData meta, int colIdx) throws SQLException; + + boolean returnGeneratedKeysByDefault(); +} diff --git a/core/src/main/java/org/sql2o/quirks/SqlServerQuirks.java b/core/src/main/java/org/sql2o/quirks/SqlServerQuirks.java new file mode 100644 index 00000000..bbb46150 --- /dev/null +++ b/core/src/main/java/org/sql2o/quirks/SqlServerQuirks.java @@ -0,0 +1,8 @@ +package org.sql2o.quirks; + +/** + * @author aldenquimby@gmail.com + * @since 4/6/14 + */ +public class SqlServerQuirks extends NoQuirks { +} diff --git a/core/src/main/java/org/sql2o/tools/NamedParameterStatement.java b/core/src/main/java/org/sql2o/tools/NamedParameterStatement.java index 8e94c5af..50ccb91a 100644 --- a/core/src/main/java/org/sql2o/tools/NamedParameterStatement.java +++ b/core/src/main/java/org/sql2o/tools/NamedParameterStatement.java @@ -37,7 +37,7 @@ * * @author adam_crume */ -public class NamedParameterStatement { +public class NamedParameterStatement implements StatementParameterSetter { /** The statement this object is wrapping. */ private final PreparedStatement statement; @@ -71,7 +71,7 @@ public NamedParameterStatement(Connection connection, String query, boolean retu * @param paramMap map to hold parameter-index mappings * @return the parsed query */ - private static final String parse(String query, Map paramMap) { + private static String parse(String query, Map paramMap) { // I was originally using regular expressions, but they didn't work well for ignoring // parameter-like strings inside quotes. int length=query.length(); @@ -180,7 +180,7 @@ public void setNull(String name, int sqlType) throws SQLException { * @throws IllegalArgumentException if the parameter does not exist * @see PreparedStatement#setBinaryStream(int, java.io.InputStream inputStream) */ - public void setInputStream( String name, InputStream value ) throws SQLException { + public void setInputStream(String name, InputStream value) throws SQLException { int[] indexes=getIndexes(name); for (int i = 0; i < indexes.length; i++){ statement.setBinaryStream( indexes[i], value ); diff --git a/core/src/main/java/org/sql2o/tools/StatementParameterSetter.java b/core/src/main/java/org/sql2o/tools/StatementParameterSetter.java new file mode 100644 index 00000000..d3604469 --- /dev/null +++ b/core/src/main/java/org/sql2o/tools/StatementParameterSetter.java @@ -0,0 +1,32 @@ +package org.sql2o.tools; + +import java.io.InputStream; +import java.sql.Date; +import java.sql.SQLException; +import java.sql.Time; +import java.sql.Timestamp; + +/** + * @author aldenquimby@gmail.com + * @since 4/6/14 + */ +public interface StatementParameterSetter +{ + void setObject(String name, Object value) throws SQLException; + + void setNull(String name, int sqlType) throws SQLException; + + void setInputStream(String name, InputStream value) throws SQLException; + + void setString(String name, String value) throws SQLException; + + void setInt(String name, int value) throws SQLException; + + void setLong(String name, long value) throws SQLException; + + void setTimestamp(String name, Timestamp value) throws SQLException; + + void setDate(String name, Date value) throws SQLException; + + void setTime(String name, Time value) throws SQLException; +} diff --git a/core/src/test/java/org/sql2o/issues/PostgresTest.java b/core/src/test/java/org/sql2o/issues/PostgresTest.java index ea7f3664..ac022889 100644 --- a/core/src/test/java/org/sql2o/issues/PostgresTest.java +++ b/core/src/test/java/org/sql2o/issues/PostgresTest.java @@ -2,10 +2,10 @@ import org.junit.Test; import org.sql2o.Connection; -import org.sql2o.QuirksMode; import org.sql2o.Sql2o; import org.sql2o.data.Row; import org.sql2o.data.Table; +import org.sql2o.quirks.PostgresQuirks; import java.util.UUID; @@ -27,7 +27,7 @@ public class PostgresTest { public PostgresTest() { - sql2o = new Sql2o("jdbc:postgresql:testdb", "test", "testtest", QuirksMode.PostgreSQL); + sql2o = new Sql2o("jdbc:postgresql:testdb", "test", "testtest", new PostgresQuirks()); } @Test From 1ae1d7215f8006f4b756d5c2bb7f7e298dfde5b3 Mon Sep 17 00:00:00 2001 From: Alden Quimby Date: Sun, 6 Apr 2014 13:39:05 -0400 Subject: [PATCH 2/4] cleanup unused ideas --- .../java/org/sql2o/GenericDatasource.java | 11 ++----- core/src/main/java/org/sql2o/Sql2o.java | 3 -- .../src/main/java/org/sql2o/SqlParameter.java | 24 -------------- .../sql2o/converters/BigDecimalConverter.java | 7 ---- .../sql2o/converters/BooleanConverter.java | 17 +--------- .../sql2o/converters/ByteArrayConverter.java | 7 +--- .../org/sql2o/converters/ByteConverter.java | 14 -------- .../java/org/sql2o/converters/Converter.java | 6 ---- ...nConverterBase.java => ConverterBase.java} | 2 +- .../org/sql2o/converters/DateConverter.java | 15 --------- .../converters/DefaultEnumConverter.java | 20 +++--------- .../org/sql2o/converters/DoubleConverter.java | 15 --------- .../org/sql2o/converters/FloatConverter.java | 15 --------- .../converters/InputStreamConverter.java | 9 +----- .../sql2o/converters/IntegerConverter.java | 15 --------- .../org/sql2o/converters/LongConverter.java | 15 --------- .../org/sql2o/converters/NumberConverter.java | 2 +- .../org/sql2o/converters/ShortConverter.java | 15 --------- .../org/sql2o/converters/StringConverter.java | 14 +------- .../org/sql2o/converters/UUIDConverter.java | 9 +----- .../converters/joda/DateTimeConverter.java | 13 -------- .../converters/joda/LocalTimeConverter.java | 14 -------- core/src/main/java/org/sql2o/data/Column.java | 1 - .../org/sql2o/quirks/SqlServerQuirks.java | 8 ----- .../sql2o/tools/NamedParameterStatement.java | 2 +- .../sql2o/tools/StatementParameterSetter.java | 32 ------------------- 26 files changed, 15 insertions(+), 290 deletions(-) delete mode 100644 core/src/main/java/org/sql2o/SqlParameter.java rename core/src/main/java/org/sql2o/converters/{BuiltInConverterBase.java => ConverterBase.java} (71%) delete mode 100644 core/src/main/java/org/sql2o/quirks/SqlServerQuirks.java delete mode 100644 core/src/main/java/org/sql2o/tools/StatementParameterSetter.java diff --git a/core/src/main/java/org/sql2o/GenericDatasource.java b/core/src/main/java/org/sql2o/GenericDatasource.java index 930e5217..fd6daa3e 100644 --- a/core/src/main/java/org/sql2o/GenericDatasource.java +++ b/core/src/main/java/org/sql2o/GenericDatasource.java @@ -1,12 +1,11 @@ package org.sql2o; -import org.sql2o.logging.LocalLoggerFactory; -import org.sql2o.logging.Logger; - import javax.sql.DataSource; import java.io.PrintWriter; -import java.sql.*; import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; /** * Used internally by sql2o, if the {@link Sql2o#Sql2o(String, String, String)} constructor overload. @@ -17,8 +16,6 @@ public class GenericDatasource implements DataSource { private final String user; private final String password; - private final Logger logger; - public GenericDatasource(String url, String user, String password) { if (!url.startsWith("jdbc")){ @@ -28,8 +25,6 @@ public GenericDatasource(String url, String user, String password) { this.url = url; this.user = user; this.password = password; - - this.logger = LocalLoggerFactory.getLogger(GenericDatasource.class); } public String getUrl() { diff --git a/core/src/main/java/org/sql2o/Sql2o.java b/core/src/main/java/org/sql2o/Sql2o.java index b9cc0068..a750ebd2 100644 --- a/core/src/main/java/org/sql2o/Sql2o.java +++ b/core/src/main/java/org/sql2o/Sql2o.java @@ -130,9 +130,6 @@ private Quirks getQuirksForMode(QuirksMode quirksMode) { else if (quirksMode == QuirksMode.PostgreSQL) { return new PostgresQuirks(); } - else if (quirksMode == QuirksMode.MSSqlServer) { - return new SqlServerQuirks(); - } else { return new NoQuirks(); } diff --git a/core/src/main/java/org/sql2o/SqlParameter.java b/core/src/main/java/org/sql2o/SqlParameter.java deleted file mode 100644 index 67e88760..00000000 --- a/core/src/main/java/org/sql2o/SqlParameter.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.sql2o; - -/** - * @author aldenquimby@gmail.com - * @since 4/6/14 - */ -public class SqlParameter { - - private int sqlType; - private Object value; - - public SqlParameter(int sqlType, Object value) { - this.sqlType = sqlType; - this.value = value; - } - - public int getSqlType() { - return sqlType; - } - - public Object getValue() { - return value; - } -} diff --git a/core/src/main/java/org/sql2o/converters/BigDecimalConverter.java b/core/src/main/java/org/sql2o/converters/BigDecimalConverter.java index 62ff647d..40fea5f9 100644 --- a/core/src/main/java/org/sql2o/converters/BigDecimalConverter.java +++ b/core/src/main/java/org/sql2o/converters/BigDecimalConverter.java @@ -1,9 +1,6 @@ package org.sql2o.converters; -import org.sql2o.tools.StatementParameterSetter; - import java.math.BigDecimal; -import java.sql.SQLException; /** * Used by sql2o to convert a value from the database into a {@link BigDecimal}. @@ -33,8 +30,4 @@ protected BigDecimal convertStringValue(String val) { protected String getTypeDescription() { return BigDecimal.class.toString(); } - - public void addParameter(StatementParameterSetter stmt, String name, BigDecimal val) throws SQLException { - stmt.setObject(name, val); - } } diff --git a/core/src/main/java/org/sql2o/converters/BooleanConverter.java b/core/src/main/java/org/sql2o/converters/BooleanConverter.java index 940b01c1..e7a316d3 100644 --- a/core/src/main/java/org/sql2o/converters/BooleanConverter.java +++ b/core/src/main/java/org/sql2o/converters/BooleanConverter.java @@ -1,11 +1,5 @@ package org.sql2o.converters; -import org.sql2o.SqlParameter; -import org.sql2o.tools.StatementParameterSetter; - -import java.sql.SQLException; -import java.sql.Types; - /** * Created with IntelliJ IDEA. * User: lars @@ -13,7 +7,7 @@ * Time: 10:54 PM * To change this template use File | Settings | File Templates. */ -public class BooleanConverter extends BuiltInConverterBase { +public class BooleanConverter extends ConverterBase { public Boolean convert(Object val) throws ConverterException { if (val == null) return null; @@ -34,13 +28,4 @@ public Boolean convert(Object val) throws ConverterException { throw new ConverterException("Don't know how to convert type " + val.getClass().getName() + " to " + Boolean.class.getName()); } - - public void addParameter(StatementParameterSetter stmt, String name, Boolean val) throws SQLException { - if (val == null) { - stmt.setNull(name, Types.BOOLEAN); - } - else { - stmt.setObject(name, val); - } - } } diff --git a/core/src/main/java/org/sql2o/converters/ByteArrayConverter.java b/core/src/main/java/org/sql2o/converters/ByteArrayConverter.java index eacd1783..af90881b 100644 --- a/core/src/main/java/org/sql2o/converters/ByteArrayConverter.java +++ b/core/src/main/java/org/sql2o/converters/ByteArrayConverter.java @@ -1,7 +1,6 @@ package org.sql2o.converters; import org.sql2o.tools.IOUtils; -import org.sql2o.tools.StatementParameterSetter; import java.io.IOException; import java.sql.Blob; @@ -14,7 +13,7 @@ * Time: 11:36 PM * To change this template use File | Settings | File Templates. */ -public class ByteArrayConverter extends BuiltInConverterBase { +public class ByteArrayConverter extends ConverterBase { public byte[] convert(Object val) throws ConverterException { if (val == null) return null; @@ -36,8 +35,4 @@ public byte[] convert(Object val) throws ConverterException { throw new RuntimeException("could not convert " + val.getClass().getName() + " to byte[]"); } - - public void addParameter(StatementParameterSetter stmt, String name, byte[] val) throws SQLException { - stmt.setObject(name, val); - } } diff --git a/core/src/main/java/org/sql2o/converters/ByteConverter.java b/core/src/main/java/org/sql2o/converters/ByteConverter.java index 8374c7e8..7b32677d 100644 --- a/core/src/main/java/org/sql2o/converters/ByteConverter.java +++ b/core/src/main/java/org/sql2o/converters/ByteConverter.java @@ -1,10 +1,5 @@ package org.sql2o.converters; -import org.sql2o.tools.StatementParameterSetter; - -import java.sql.SQLException; -import java.sql.Types; - /** * Used by sql2o to convert a value from the database into a {@link Byte}. */ @@ -28,13 +23,4 @@ protected Byte convertStringValue(String val) { protected String getTypeDescription() { return Byte.class.toString(); } - - public void addParameter(StatementParameterSetter stmt, String name, Byte val) throws SQLException { - if (val == null) { - stmt.setNull(name, Types.TINYINT); - } - else { - stmt.setInt(name, val); - } - } } diff --git a/core/src/main/java/org/sql2o/converters/Converter.java b/core/src/main/java/org/sql2o/converters/Converter.java index 36d1145f..fc9251b9 100644 --- a/core/src/main/java/org/sql2o/converters/Converter.java +++ b/core/src/main/java/org/sql2o/converters/Converter.java @@ -1,9 +1,5 @@ package org.sql2o.converters; -import org.sql2o.tools.StatementParameterSetter; - -import java.sql.SQLException; - /** * Represents a converter. */ @@ -11,7 +7,5 @@ public interface Converter { T convert(Object val) throws ConverterException; - void addParameter(StatementParameterSetter stmt, String name, T val) throws SQLException; - Object toDatabaseParam(T val); } diff --git a/core/src/main/java/org/sql2o/converters/BuiltInConverterBase.java b/core/src/main/java/org/sql2o/converters/ConverterBase.java similarity index 71% rename from core/src/main/java/org/sql2o/converters/BuiltInConverterBase.java rename to core/src/main/java/org/sql2o/converters/ConverterBase.java index d7027a2c..91443dcc 100644 --- a/core/src/main/java/org/sql2o/converters/BuiltInConverterBase.java +++ b/core/src/main/java/org/sql2o/converters/ConverterBase.java @@ -4,7 +4,7 @@ * @author aldenquimby@gmail.com * @since 4/6/14 */ -abstract class BuiltInConverterBase implements Converter { +abstract class ConverterBase implements Converter { public Object toDatabaseParam(T val) { return val; diff --git a/core/src/main/java/org/sql2o/converters/DateConverter.java b/core/src/main/java/org/sql2o/converters/DateConverter.java index a4fdcd32..405cdf9b 100644 --- a/core/src/main/java/org/sql2o/converters/DateConverter.java +++ b/core/src/main/java/org/sql2o/converters/DateConverter.java @@ -1,10 +1,6 @@ package org.sql2o.converters; -import org.sql2o.tools.StatementParameterSetter; - -import java.sql.SQLException; import java.sql.Timestamp; -import java.sql.Types; import java.util.Date; /** @@ -24,17 +20,6 @@ public Date convert(Object val) throws ConverterException { throw new ConverterException("Cannot convert type " + val.getClass().toString() + " to java.util.Date"); } - public void addParameter(StatementParameterSetter stmt, String name, Date val) throws SQLException { - if (val == null) { - stmt.setNull(name, Types.DATE); - } - else { - // by default add a timestamp, because it works with DATE, DATETIME, TIMESTAMP columns - Timestamp timestamp = new Timestamp(val.getTime()); - stmt.setTimestamp(name, timestamp); - } - } - public Object toDatabaseParam(Date val) { return new Timestamp(val.getTime()); } diff --git a/core/src/main/java/org/sql2o/converters/DefaultEnumConverter.java b/core/src/main/java/org/sql2o/converters/DefaultEnumConverter.java index e6e5f506..4c85f1e5 100644 --- a/core/src/main/java/org/sql2o/converters/DefaultEnumConverter.java +++ b/core/src/main/java/org/sql2o/converters/DefaultEnumConverter.java @@ -1,10 +1,5 @@ package org.sql2o.converters; -import org.sql2o.tools.StatementParameterSetter; - -import java.sql.SQLException; -import java.sql.Types; - /** * Default implementation of {@link org.sql2o.converters.EnumConverter}, * used by sql2o to convert a value from the database into an {@link Enum}. @@ -19,8 +14,10 @@ public void setEnumType(Class clazz) } public Enum convert(Object val) throws ConverterException { - if (val == null) return null; - try{ + if (val == null) { + return null; + } + try { if (String.class.isAssignableFrom(val.getClass())){ return Enum.valueOf(enumType, val.toString()); } else if (Number.class.isAssignableFrom(val.getClass())){ @@ -32,15 +29,6 @@ public Enum convert(Object val) throws ConverterException { throw new ConverterException("Cannot convert type '" + val.getClass().getName() + "' to an Enum"); } - public void addParameter(StatementParameterSetter stmt, String name, Enum val) throws SQLException { - if (val == null) { - stmt.setNull(name, Types.VARCHAR); - } - else { - stmt.setString(name, val.toString()); - } - } - public Object toDatabaseParam(Enum val) { return val.toString(); } diff --git a/core/src/main/java/org/sql2o/converters/DoubleConverter.java b/core/src/main/java/org/sql2o/converters/DoubleConverter.java index d8125a15..5a368857 100644 --- a/core/src/main/java/org/sql2o/converters/DoubleConverter.java +++ b/core/src/main/java/org/sql2o/converters/DoubleConverter.java @@ -1,11 +1,5 @@ package org.sql2o.converters; -import org.sql2o.SqlParameter; -import org.sql2o.tools.StatementParameterSetter; - -import java.sql.SQLException; -import java.sql.Types; - /** * Used by sql2o to convert a value from the database into a {@link Double}. */ @@ -29,13 +23,4 @@ protected Double convertStringValue(String val) { protected String getTypeDescription() { return Double.class.toString(); } - - public void addParameter(StatementParameterSetter stmt, String name, Double val) throws SQLException { - if (val == null) { - stmt.setNull(name, Types.DOUBLE); - } - else { - stmt.setObject(name, val); - } - } } diff --git a/core/src/main/java/org/sql2o/converters/FloatConverter.java b/core/src/main/java/org/sql2o/converters/FloatConverter.java index 4c9ab2ac..1dea719a 100644 --- a/core/src/main/java/org/sql2o/converters/FloatConverter.java +++ b/core/src/main/java/org/sql2o/converters/FloatConverter.java @@ -1,11 +1,5 @@ package org.sql2o.converters; -import org.sql2o.SqlParameter; -import org.sql2o.tools.StatementParameterSetter; - -import java.sql.SQLException; -import java.sql.Types; - /** * Used by sql2o to convert a value from the database into a {@link Float}. */ @@ -29,13 +23,4 @@ protected Float convertStringValue(String val) { protected String getTypeDescription() { return Float.class.toString(); } - - public void addParameter(StatementParameterSetter stmt, String name, Float val) throws SQLException { - if (val == null) { - stmt.setNull(name, Types.FLOAT); - } - else { - stmt.setObject(name, val); - } - } } diff --git a/core/src/main/java/org/sql2o/converters/InputStreamConverter.java b/core/src/main/java/org/sql2o/converters/InputStreamConverter.java index c8cdd623..daf388cf 100644 --- a/core/src/main/java/org/sql2o/converters/InputStreamConverter.java +++ b/core/src/main/java/org/sql2o/converters/InputStreamConverter.java @@ -1,9 +1,6 @@ package org.sql2o.converters; -import org.sql2o.tools.StatementParameterSetter; - import java.io.ByteArrayInputStream; -import java.sql.SQLException; /** * Created with IntelliJ IDEA. @@ -12,7 +9,7 @@ * Time: 11:40 PM * To change this template use File | Settings | File Templates. */ -public class InputStreamConverter extends BuiltInConverterBase { +public class InputStreamConverter extends ConverterBase { public ByteArrayInputStream convert(Object val) throws ConverterException { if (val == null) return null; @@ -22,8 +19,4 @@ public ByteArrayInputStream convert(Object val) throws ConverterException { throw new ConverterException("Error converting Blob to InputSteam"); } } - - public void addParameter(StatementParameterSetter stmt, String name, ByteArrayInputStream val) throws SQLException { - stmt.setObject(name, val); - } } diff --git a/core/src/main/java/org/sql2o/converters/IntegerConverter.java b/core/src/main/java/org/sql2o/converters/IntegerConverter.java index cc84b8b0..6f24d4c1 100644 --- a/core/src/main/java/org/sql2o/converters/IntegerConverter.java +++ b/core/src/main/java/org/sql2o/converters/IntegerConverter.java @@ -1,11 +1,5 @@ package org.sql2o.converters; -import org.sql2o.SqlParameter; -import org.sql2o.tools.StatementParameterSetter; - -import java.sql.SQLException; -import java.sql.Types; - /** * Used by sql2o to convert a value from the database into an {@link Integer}. */ @@ -29,13 +23,4 @@ protected Integer convertStringValue(String val) { protected String getTypeDescription() { return Integer.class.toString(); } - - public void addParameter(StatementParameterSetter stmt, String name, Integer val) throws SQLException { - if (val == null) { - stmt.setNull(name, Types.INTEGER); - } - else { - stmt.setInt(name, val); - } - } } diff --git a/core/src/main/java/org/sql2o/converters/LongConverter.java b/core/src/main/java/org/sql2o/converters/LongConverter.java index 3fec4e5b..d5b210a5 100644 --- a/core/src/main/java/org/sql2o/converters/LongConverter.java +++ b/core/src/main/java/org/sql2o/converters/LongConverter.java @@ -1,11 +1,5 @@ package org.sql2o.converters; -import org.sql2o.SqlParameter; -import org.sql2o.tools.StatementParameterSetter; - -import java.sql.SQLException; -import java.sql.Types; - /** * Used by sql2o to convert a value from the database into a {@link Long}. */ @@ -29,13 +23,4 @@ protected Long convertStringValue(String val) { protected String getTypeDescription() { return Long.class.toString(); } - - public void addParameter(StatementParameterSetter stmt, String name, Long val) throws SQLException { - if (val == null) { - stmt.setNull(name, Types.BIGINT); - } - else { - stmt.setLong(name, val); - } - } } diff --git a/core/src/main/java/org/sql2o/converters/NumberConverter.java b/core/src/main/java/org/sql2o/converters/NumberConverter.java index 75c6c40b..e1999e15 100644 --- a/core/src/main/java/org/sql2o/converters/NumberConverter.java +++ b/core/src/main/java/org/sql2o/converters/NumberConverter.java @@ -3,7 +3,7 @@ /** * Base class for numeric converters. */ -public abstract class NumberConverter extends BuiltInConverterBase{ +public abstract class NumberConverter extends ConverterBase { private boolean isPrimitive; diff --git a/core/src/main/java/org/sql2o/converters/ShortConverter.java b/core/src/main/java/org/sql2o/converters/ShortConverter.java index 9c48854c..46813630 100644 --- a/core/src/main/java/org/sql2o/converters/ShortConverter.java +++ b/core/src/main/java/org/sql2o/converters/ShortConverter.java @@ -1,11 +1,5 @@ package org.sql2o.converters; -import org.sql2o.SqlParameter; -import org.sql2o.tools.StatementParameterSetter; - -import java.sql.SQLException; -import java.sql.Types; - /** * Used by sql2o to convert a value from the database into a {@link Short}. */ @@ -29,13 +23,4 @@ protected Short convertStringValue(String val) { protected String getTypeDescription() { return Short.class.toString(); } - - public void addParameter(StatementParameterSetter stmt, String name, Short val) throws SQLException { - if (val == null) { - stmt.setNull(name, Types.SMALLINT); - } - else { - stmt.setInt(name, val); - } - } } diff --git a/core/src/main/java/org/sql2o/converters/StringConverter.java b/core/src/main/java/org/sql2o/converters/StringConverter.java index be3b99b0..3eaf3186 100644 --- a/core/src/main/java/org/sql2o/converters/StringConverter.java +++ b/core/src/main/java/org/sql2o/converters/StringConverter.java @@ -1,15 +1,12 @@ package org.sql2o.converters; -import org.sql2o.tools.StatementParameterSetter; - import java.sql.Clob; import java.sql.SQLException; -import java.sql.Types; /** * Used by sql2o to convert a value from the database into a {@link String}. */ -public class StringConverter extends BuiltInConverterBase { +public class StringConverter extends ConverterBase { public String convert(Object val) throws ConverterException { if (val == null){ @@ -27,13 +24,4 @@ public String convert(Object val) throws ConverterException { return val.toString().trim(); } - - public void addParameter(StatementParameterSetter stmt, String name, String val) throws SQLException { - if (val == null) { - stmt.setNull(name, Types.VARCHAR); - } - else { - stmt.setString(name, val); - } - } } diff --git a/core/src/main/java/org/sql2o/converters/UUIDConverter.java b/core/src/main/java/org/sql2o/converters/UUIDConverter.java index 88d743c6..cb13ec9f 100644 --- a/core/src/main/java/org/sql2o/converters/UUIDConverter.java +++ b/core/src/main/java/org/sql2o/converters/UUIDConverter.java @@ -1,14 +1,11 @@ package org.sql2o.converters; -import org.sql2o.tools.StatementParameterSetter; - -import java.sql.SQLException; import java.util.UUID; /** * Used by sql2o to convert a value from the database into a {@link UUID}. */ -public class UUIDConverter extends BuiltInConverterBase { +public class UUIDConverter extends ConverterBase { public UUID convert(Object val) throws ConverterException { if (val == null){ @@ -21,9 +18,5 @@ public UUID convert(Object val) throws ConverterException { throw new ConverterException("Cannot convert type " + val.getClass().toString() + " to java.util.UUID"); } - - public void addParameter(StatementParameterSetter stmt, String name, UUID val) throws SQLException { - stmt.setObject(name, val); - } } diff --git a/core/src/main/java/org/sql2o/converters/joda/DateTimeConverter.java b/core/src/main/java/org/sql2o/converters/joda/DateTimeConverter.java index 065fcf06..91f6e01b 100644 --- a/core/src/main/java/org/sql2o/converters/joda/DateTimeConverter.java +++ b/core/src/main/java/org/sql2o/converters/joda/DateTimeConverter.java @@ -5,11 +5,8 @@ import org.joda.time.LocalDateTime; import org.sql2o.converters.Converter; import org.sql2o.converters.ConverterException; -import org.sql2o.tools.StatementParameterSetter; -import java.sql.SQLException; import java.sql.Timestamp; -import java.sql.Types; /** * Used by sql2o to convert a value from the database into a {@link DateTime} instance. @@ -32,14 +29,4 @@ public DateTime convert(Object val) throws ConverterException { public Object toDatabaseParam(DateTime val) { return new Timestamp(val.getMillis()); } - - public void addParameter(StatementParameterSetter stmt, String name, DateTime val) throws SQLException { - if (val == null) { - stmt.setNull(name, Types.TIMESTAMP); - } - else { - Timestamp sqlTimestamp = new Timestamp(val.getMillis()); - stmt.setTimestamp(name, sqlTimestamp); - } - } } diff --git a/core/src/main/java/org/sql2o/converters/joda/LocalTimeConverter.java b/core/src/main/java/org/sql2o/converters/joda/LocalTimeConverter.java index ccd62b3d..f9741d58 100644 --- a/core/src/main/java/org/sql2o/converters/joda/LocalTimeConverter.java +++ b/core/src/main/java/org/sql2o/converters/joda/LocalTimeConverter.java @@ -1,14 +1,10 @@ package org.sql2o.converters.joda; import org.joda.time.LocalTime; -import org.sql2o.SqlParameter; import org.sql2o.converters.Converter; import org.sql2o.converters.ConverterException; -import org.sql2o.tools.StatementParameterSetter; -import java.sql.SQLException; import java.sql.Time; -import java.sql.Types; /** * Created by lars on 12/18/13. @@ -30,14 +26,4 @@ public LocalTime convert(Object val) throws ConverterException { public Object toDatabaseParam(LocalTime val) { return new Time(val.toDateTimeToday().getMillis()); } - - public void addParameter(StatementParameterSetter stmt, String name, LocalTime val) throws SQLException { - if (val == null) { - stmt.setNull(name, Types.TIME); - } - else { - Time sqlTime = new Time(val.toDateTimeToday().getMillis()); - stmt.setTime(name, sqlTime); - } - } } diff --git a/core/src/main/java/org/sql2o/data/Column.java b/core/src/main/java/org/sql2o/data/Column.java index a973e9e7..82432783 100644 --- a/core/src/main/java/org/sql2o/data/Column.java +++ b/core/src/main/java/org/sql2o/data/Column.java @@ -9,7 +9,6 @@ public class Column { private Integer index; private String type; - public Column(String name, Integer index, String type) { this.name = name; this.index = index; diff --git a/core/src/main/java/org/sql2o/quirks/SqlServerQuirks.java b/core/src/main/java/org/sql2o/quirks/SqlServerQuirks.java deleted file mode 100644 index bbb46150..00000000 --- a/core/src/main/java/org/sql2o/quirks/SqlServerQuirks.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.sql2o.quirks; - -/** - * @author aldenquimby@gmail.com - * @since 4/6/14 - */ -public class SqlServerQuirks extends NoQuirks { -} diff --git a/core/src/main/java/org/sql2o/tools/NamedParameterStatement.java b/core/src/main/java/org/sql2o/tools/NamedParameterStatement.java index 50ccb91a..87c5be60 100644 --- a/core/src/main/java/org/sql2o/tools/NamedParameterStatement.java +++ b/core/src/main/java/org/sql2o/tools/NamedParameterStatement.java @@ -37,7 +37,7 @@ * * @author adam_crume */ -public class NamedParameterStatement implements StatementParameterSetter { +public class NamedParameterStatement { /** The statement this object is wrapping. */ private final PreparedStatement statement; diff --git a/core/src/main/java/org/sql2o/tools/StatementParameterSetter.java b/core/src/main/java/org/sql2o/tools/StatementParameterSetter.java deleted file mode 100644 index d3604469..00000000 --- a/core/src/main/java/org/sql2o/tools/StatementParameterSetter.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.sql2o.tools; - -import java.io.InputStream; -import java.sql.Date; -import java.sql.SQLException; -import java.sql.Time; -import java.sql.Timestamp; - -/** - * @author aldenquimby@gmail.com - * @since 4/6/14 - */ -public interface StatementParameterSetter -{ - void setObject(String name, Object value) throws SQLException; - - void setNull(String name, int sqlType) throws SQLException; - - void setInputStream(String name, InputStream value) throws SQLException; - - void setString(String name, String value) throws SQLException; - - void setInt(String name, int value) throws SQLException; - - void setLong(String name, long value) throws SQLException; - - void setTimestamp(String name, Timestamp value) throws SQLException; - - void setDate(String name, Date value) throws SQLException; - - void setTime(String name, Time value) throws SQLException; -} From 2970e3bda05fb8a4c7ed8a629578f81498ef59ef Mon Sep 17 00:00:00 2001 From: Alden Quimby Date: Sun, 6 Apr 2014 13:47:08 -0400 Subject: [PATCH 3/4] add some docs --- core/src/main/java/org/sql2o/QuirksMode.java | 3 ++- .../main/java/org/sql2o/converters/Converter.java | 8 +++++++- core/src/main/java/org/sql2o/quirks/Quirks.java | 12 ++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/sql2o/QuirksMode.java b/core/src/main/java/org/sql2o/QuirksMode.java index 3293fa7c..dfbe261d 100644 --- a/core/src/main/java/org/sql2o/QuirksMode.java +++ b/core/src/main/java/org/sql2o/QuirksMode.java @@ -1,8 +1,9 @@ package org.sql2o; /** - * Many JDBC drivers has quirks and needs special treatment. This enum is used to specify which quirks sql2o should expect. + * Use {@link org.sql2o.quirks.Quirks}. */ +@Deprecated public enum QuirksMode { None, DB2, PostgreSQL, MSSqlServer diff --git a/core/src/main/java/org/sql2o/converters/Converter.java b/core/src/main/java/org/sql2o/converters/Converter.java index fc9251b9..fb05a9ab 100644 --- a/core/src/main/java/org/sql2o/converters/Converter.java +++ b/core/src/main/java/org/sql2o/converters/Converter.java @@ -4,8 +4,14 @@ * Represents a converter. */ public interface Converter { - + + /** + * Conversion from SQL to Java. + */ T convert(Object val) throws ConverterException; + /** + * Conversion from Java to SQL. + */ Object toDatabaseParam(T val); } diff --git a/core/src/main/java/org/sql2o/quirks/Quirks.java b/core/src/main/java/org/sql2o/quirks/Quirks.java index 49a5c781..b682ea26 100644 --- a/core/src/main/java/org/sql2o/quirks/Quirks.java +++ b/core/src/main/java/org/sql2o/quirks/Quirks.java @@ -7,14 +7,26 @@ import java.util.Map; /** + * Interface for JDBC driver specific quirks. + * See {@link org.sql2o.quirks.NoQuirks} for defaults. + * * @author aldenquimby@gmail.com * @since 4/6/14 */ public interface Quirks { + /** + * @return converters to register by default + */ Map customConverters(); + /** + * @return name of column at index {@code colIdx} for result set {@code meta} + */ String getColumnName(ResultSetMetaData meta, int colIdx) throws SQLException; + /** + * @return true if queries should return generated keys by default, false otherwise + */ boolean returnGeneratedKeysByDefault(); } From 44112930aa6f7e66d58c9b76860cac8836ce73db Mon Sep 17 00:00:00 2001 From: Alden Quimby Date: Sun, 6 Apr 2014 14:09:01 -0400 Subject: [PATCH 4/4] add test for two way converter --- .../org/sql2o/converters/UUIDConverter.java | 2 +- .../BidirectionalConverterTest.java | 83 +++++++++++++++++++ .../sql2o/converters/CustomUUIDConverter.java | 27 ++++++ .../org/sql2o/converters/UUIDWrapper.java | 44 ++++++++++ 4 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 core/src/test/java/org/sql2o/converters/BidirectionalConverterTest.java create mode 100644 core/src/test/java/org/sql2o/converters/CustomUUIDConverter.java create mode 100644 core/src/test/java/org/sql2o/converters/UUIDWrapper.java diff --git a/core/src/main/java/org/sql2o/converters/UUIDConverter.java b/core/src/main/java/org/sql2o/converters/UUIDConverter.java index cb13ec9f..7817dbf4 100644 --- a/core/src/main/java/org/sql2o/converters/UUIDConverter.java +++ b/core/src/main/java/org/sql2o/converters/UUIDConverter.java @@ -16,7 +16,7 @@ public UUID convert(Object val) throws ConverterException { return (UUID)val; } - throw new ConverterException("Cannot convert type " + val.getClass().toString() + " to java.util.UUID"); + throw new ConverterException("Cannot convert type " + val.getClass() + " " + UUID.class); } } diff --git a/core/src/test/java/org/sql2o/converters/BidirectionalConverterTest.java b/core/src/test/java/org/sql2o/converters/BidirectionalConverterTest.java new file mode 100644 index 00000000..f4afaf06 --- /dev/null +++ b/core/src/test/java/org/sql2o/converters/BidirectionalConverterTest.java @@ -0,0 +1,83 @@ +package org.sql2o.converters; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.sql2o.*; + +import java.util.*; + +import static org.junit.Assert.*; + +/** + * @author aldenquimby@gmail.com + * @since 4/6/14 + */ +public class BidirectionalConverterTest { + + private Sql2o sql2o; + private List wrappers; + + @Before + public void setUp() + { + this.sql2o = new Sql2o("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1", "sa", ""); + Convert.registerConverter(UUID.class, new CustomUUIDConverter()); + this.wrappers = randomWrappers(); + this.createAndFillTable(this.wrappers); + } + + @After + public void tearDown() + { + deleteTable(); + } + + @Test + public void toDatabase_fromDatabase_doExecute() + { + List notConverted = sql2o.createQuery("select text from uuid_wrapper") + .executeAndFetch(String.class); + + // if conversion to database worked, all "-" from UUID were replaced with "!" + for (String s : notConverted) { + assertNotNull(UUID.fromString(s.replace('!', '-'))); + } + + List converted = sql2o.createQuery("select * from uuid_wrapper") + .executeAndFetch(UUIDWrapper.class); + + // if conversion from database worked, should have the list we inserted + assertEquals(wrappers, converted); + } + + /************** Helper stuff ******************/ + + private List randomWrappers() { + List wrappers = new ArrayList(); + for (int i = 0; i < 10; i++) { + wrappers.add(new UUIDWrapper(UUID.randomUUID())); + } + return wrappers; + } + + private void createAndFillTable(List wrappers) { + sql2o.createQuery("create table uuid_wrapper(\n" + + "text varchar(100) primary key)").executeUpdate(); + + Query insQuery = sql2o.createQuery("insert into uuid_wrapper(text) values (:text)"); + for (UUIDWrapper wrapper : wrappers) { + insQuery.addParameter("text", wrapper.getText()).addToBatch(); + } + insQuery.executeBatch(); + } + + private void deleteTable(){ + try { + sql2o.createQuery("drop table uuid_wrapper").executeUpdate(); + } + catch(Sql2oException e) { + // if it fails, its because the User table doesn't exists. Just ignore this. + } + } +} \ No newline at end of file diff --git a/core/src/test/java/org/sql2o/converters/CustomUUIDConverter.java b/core/src/test/java/org/sql2o/converters/CustomUUIDConverter.java new file mode 100644 index 00000000..811fad54 --- /dev/null +++ b/core/src/test/java/org/sql2o/converters/CustomUUIDConverter.java @@ -0,0 +1,27 @@ +package org.sql2o.converters; + +import java.util.UUID; + +/** + * Stores UUIDs as strings with ! delimiter instead of -. + * + * @author aldenquimby@gmail.com + * @since 4/6/14 + */ +public class CustomUUIDConverter implements Converter { + public UUID convert(Object val) throws ConverterException { + if (val == null){ + return null; + } + + if (String.class.isAssignableFrom(val.getClass())) { + return UUID.fromString(((String)val).replace('!', '-')); + } + + throw new ConverterException("Cannot convert type " + val.getClass() + " " + UUID.class); + } + + public Object toDatabaseParam(UUID val) { + return val.toString().replace('-', '!'); + } +} diff --git a/core/src/test/java/org/sql2o/converters/UUIDWrapper.java b/core/src/test/java/org/sql2o/converters/UUIDWrapper.java new file mode 100644 index 00000000..acf0288d --- /dev/null +++ b/core/src/test/java/org/sql2o/converters/UUIDWrapper.java @@ -0,0 +1,44 @@ +package org.sql2o.converters; + +import java.util.UUID; + +/** + * @author aldenquimby@gmail.com + * @since 4/6/14 + */ +public class UUIDWrapper +{ + private UUID text; + + public UUIDWrapper() { + } + + public UUIDWrapper(UUID text) { + this.text = text; + } + + public UUID getText() { + return text; + } + + public void setText(UUID text) { + this.text = text; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + UUIDWrapper that = (UUIDWrapper) o; + + if (text != null ? !text.equals(that.text) : that.text != null) return false; + + return true; + } + + @Override + public int hashCode() { + return text != null ? text.hashCode() : 0; + } +}