- Improved automatic date conversions
- Revised data type adapters to be specified separately with the @TypeAdapter annotation
additions:
+ - Add runtime mode support (DEV, TEST, & PROD)
- Add a DAO feature similar to JDBI
- Added Gson, XStream, and SnakeYaml type adapters
dependencyChanges: ~
import com.iciql.Iciql.IQTable;
import com.iciql.Iciql.IQVersion;
import com.iciql.Iciql.IQView;
+import com.iciql.Iciql.Mode;
import com.iciql.util.IciqlLogger;
import com.iciql.util.JdbcUtils;
import com.iciql.util.StringUtils;
private static final Map<String, Class<? extends SQLDialect>> DIALECTS;
private final Connection conn;
+ private final Mode mode;
private final Map<Class<?>, TableDefinition<?>> classMap = Collections
.synchronizedMap(new HashMap<Class<?>, TableDefinition<?>>());
private final SQLDialect dialect;
DIALECTS.put("SQLite", SQLDialectSQLite.class);
}
- private Db(Connection conn) {
+ private Db(Connection conn, Mode mode) {
this.conn = conn;
+ this.mode = mode;
String databaseName = null;
try {
DatabaseMetaData data = conn.getMetaData();
}
public static Db open(String url) {
+ return open(url, Mode.PROD);
+ }
+
+ public static Db open(String url, Mode mode) {
try {
Connection conn = JdbcUtils.getConnection(null, url, null, null);
- return new Db(conn);
+ return new Db(conn, mode);
} catch (SQLException e) {
throw new IciqlException(e);
}
}
public static Db open(String url, String user, String password) {
+ return open(url, user, password, Mode.PROD);
+ }
+
+ public static Db open(String url, String user, String password, Mode mode) {
try {
Connection conn = JdbcUtils.getConnection(null, url, user, password);
- return new Db(conn);
+ return new Db(conn, mode);
} catch (SQLException e) {
throw new IciqlException(e);
}
}
public static Db open(String url, String user, char[] password) {
+ return open(url, user, password, Mode.PROD);
+ }
+
+ public static Db open(String url, String user, char[] password, Mode mode) {
try {
Connection conn = JdbcUtils.getConnection(null, url, user, password == null ? null : new String(password));
- return new Db(conn);
+ return new Db(conn, mode);
} catch (SQLException e) {
throw new IciqlException(e);
}
}
+ public static Db open(DataSource ds) {
+ return open(ds, Mode.PROD);
+ }
+
/**
* Create a new database instance using a data source. This method is fast,
* so that you can always call open() / close() on usage.
*
* @param ds
* the data source
+ * @param mode
+ * the runtime mode
* @return the database instance.
*/
- public static Db open(DataSource ds) {
+ public static Db open(DataSource ds, Mode mode) {
try {
- return new Db(ds.getConnection());
+ return new Db(ds.getConnection(), mode);
} catch (SQLException e) {
throw new IciqlException(e);
}
}
public static Db open(Connection conn) {
- return new Db(conn);
+ return open(conn, Mode.PROD);
+ }
+
+ public static Db open(Connection conn, Mode mode) {
+ return new Db(conn, mode);
+ }
+
+ /**
+ * Returns the Iciql runtime mode.
+ *
+ * @return the runtime mode
+ */
+ public Mode getMode() {
+ return mode;
}
/**
return this.autoSavePoint;
}
+ /**
+ *
+ * @author James Moger
+ *
+ */
+ class NoExternalDaoStatements implements DaoStatementProvider {
+
+ @Override
+ public String getStatement(String idOrStatement) {
+ return idOrStatement;
+ }
+
+ }
}
public @interface IQIgnore{\r
}\r
\r
+ /**\r
+ * The runtime mode for Iciql.\r
+ */\r
+ public static enum Mode {\r
+\r
+ DEV, TEST, PROD;\r
+\r
+ public static Mode fromValue(String value) {\r
+\r
+ for (Mode mode : values()) {\r
+ if (mode.name().equalsIgnoreCase(value)) {\r
+ return mode;\r
+ }\r
+ }\r
+\r
+ return PROD;\r
+ }\r
+ }\r
+\r
/**\r
* This method is called to let the table define the primary key, indexes,\r
* and the table name.\r
*/\r
Class<T> getJavaType();\r
\r
+\r
+ /**\r
+ * Set the runtime mode.\r
+ * <p>\r
+ * Allows type adapters to adapt type mappings based on the runtime\r
+ * mode.\r
+ * </p>\r
+ *\r
+ * @param mode\r
+ */\r
+ void setMode(Mode mode);\r
+\r
/**\r
* Serializes your Java object into a JDBC object.\r
*\r
import com.iciql.Iciql.ConstraintDeleteType;
import com.iciql.Iciql.ConstraintUpdateType;
import com.iciql.Iciql.DataTypeAdapter;
+import com.iciql.Iciql.Mode;
import com.iciql.TableDefinition.ConstraintForeignKeyDefinition;
import com.iciql.TableDefinition.ConstraintUniqueDefinition;
import com.iciql.TableDefinition.FieldDefinition;
int databaseMinorVersion;
String databaseName;
String productVersion;
+ Mode mode;
Map<Class<? extends DataTypeAdapter<?>>, DataTypeAdapter<?>> typeAdapters;
public SQLDialectDefault() {
} catch (SQLException e) {
throw new IciqlException(e, "failed to retrieve database metadata!");
}
+
+ mode = db.getMode();
}
@Override
@Override
public DataTypeAdapter<?> getAdapter(Class<? extends DataTypeAdapter<?>> typeAdapter) {
- DataTypeAdapter<?> dtt = typeAdapters.get(typeAdapter);
- if (dtt == null) {
- dtt = Utils.newObject(typeAdapter);
- typeAdapters.put(typeAdapter, dtt);
+ DataTypeAdapter<?> dta = typeAdapters.get(typeAdapter);
+ if (dta == null) {
+ dta = Utils.newObject(typeAdapter);
+ typeAdapters.put(typeAdapter, dta);
}
- return dtt;
+ dta.setMode(mode);
+ return dta;
}
@SuppressWarnings("unchecked")
return value;
}
- DataTypeAdapter<T> dtt = (DataTypeAdapter<T>) getAdapter(typeAdapter);
- return dtt.serialize(value);
+ DataTypeAdapter<T> dta = (DataTypeAdapter<T>) getAdapter(typeAdapter);
+ return dta.serialize(value);
}
@Override
public Object deserialize(Object value, Class<? extends DataTypeAdapter<?>> typeAdapter) {
- DataTypeAdapter<?> dtt = typeAdapters.get(typeAdapter);
- if (dtt == null) {
- dtt = Utils.newObject(typeAdapter);
- typeAdapters.put(typeAdapter, dtt);
+ if (typeAdapter == null) {
+ // pass-through
+ return value;
}
- return dtt.deserialize(value);
+ DataTypeAdapter<?> dta = getAdapter(typeAdapter);
+ return dta.deserialize(value);
}
@Override
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.iciql.Iciql.DataTypeAdapter;
+import com.iciql.Iciql.Mode;
/**
* Base class for inserting/retrieving a Java Object (de)serialized as JSON
*/
public abstract class GsonTypeAdapter<T> implements DataTypeAdapter<T> {
+ protected Mode mode;
+
protected Gson gson() {
return new GsonBuilder().create();
}
+ @Override
+ public void setMode(Mode mode) {
+ this.mode = mode;
+ }
+
@Override
public String getDataType() {
return "TEXT";
import java.sql.Blob;
import java.sql.SQLException;
-import com.iciql.Iciql;
-import com.iciql.IciqlException;
import com.iciql.Iciql.DataTypeAdapter;
+import com.iciql.Iciql.Mode;
+import com.iciql.IciqlException;
/**
* Base class for inserting/retrieving a Java Object as a BLOB field using Java Serialization.
*/
public abstract class JavaSerializationTypeAdapter<T> implements DataTypeAdapter<T> {
+ protected Mode mode;
+
+ @Override
+ public void setMode(Mode mode) {
+ this.mode = mode;
+ }
+
@Override
public final String getDataType() {
return "BLOB";
import org.yaml.snakeyaml.nodes.Tag;
import com.iciql.Iciql.DataTypeAdapter;
+import com.iciql.Iciql.Mode;
/**
* Base class for inserting/retrieving a Java Object (de)serialized as YAML using SnakeYaml.
*/
public abstract class SnakeYamlTypeAdapter<T> implements DataTypeAdapter<T> {
+ protected Mode mode;
+
protected Yaml yaml() {
return new Yaml();
}
+ @Override
+ public void setMode(Mode mode) {
+ this.mode = mode;
+ }
+
@Override
public String getDataType() {
return "TEXT";
package com.iciql.adapter;
import com.iciql.Iciql.DataTypeAdapter;
+import com.iciql.Iciql.Mode;
import com.thoughtworks.xstream.XStream;
/**
*/
public class XStreamTypeAdapter implements DataTypeAdapter<Object> {
+ protected Mode mode;
+
protected XStream xstream() {
return new XStream();
}
+ @Override
+ public void setMode(Mode mode) {
+ this.mode = mode;
+ }
+
@Override
public String getDataType() {
return "TEXT";
import org.postgresql.util.PGobject;
import com.iciql.Iciql.DataTypeAdapter;
+import com.iciql.Iciql.Mode;
/**
* Handles transforming raw strings to/from the Postgres JSON data type.
*/
public class JsonStringAdapter implements DataTypeAdapter<String> {
+ protected Mode mode;
+
+ @Override
+ public void setMode(Mode mode) {
+ this.mode = mode;
+ }
+
@Override
public String getDataType() {
return "json";
import org.postgresql.util.PGobject;
import com.iciql.Iciql.DataTypeAdapter;
+import com.iciql.Iciql.Mode;
/**
* Handles transforming raw strings to/from the Postgres JSONB data type.
*/
public class JsonbStringAdapter implements DataTypeAdapter<String> {
+ protected Mode mode;
+
+ @Override
+ public void setMode(Mode mode) {
+ this.mode = mode;
+ }
+
@Override
public String getDataType() {
return "jsonb";
import org.postgresql.util.PGobject;
import com.iciql.Iciql.DataTypeAdapter;
+import com.iciql.Iciql.Mode;
/**
* Handles transforming raw strings to/from the Postgres XML data type.
*/
public class XmlStringAdapter implements DataTypeAdapter<String> {
+ protected Mode mode;
+
+ @Override
+ public void setMode(Mode mode) {
+ this.mode = mode;
+ }
+
@Override
public String getDataType() {
return "xml";
---JAVA---\r
public class InvoiceAdapterImpl implements DataTypeAdapter<Invoice> {\r
\r
+ Mode mode;\r
+ \r
+ @Override\r
+ public void setMode(Mode mode) {\r
+ this.mode = mode;\r
+ }\r
+\r
@Override\r
public String getDataType() {\r
return "jsonb";\r
\r
Here you can see how the *InvoiceTypeAdapter* defines a [Postgres JSONB data type](http://www.postgresql.org/docs/9.4/static/datatype-json.html) and automatically handles JSON (de)serialization with [Google Gson](https://code.google.com/p/google-gson) so that the database gets the content in a form that it requires but we can continue to work with objects in Java.\r
\r
+### Runtime Mode\r
+\r
+Data type adapters can respond to the Iciql runtime mode (`DEV`, `TEST`, or `PROD`) allowing them to change their behavior. This is useful for targetting a data type that might be available in your production database but may not be available in your development or testing database.\r
+\r
### Custom annotations\r
\r
It is a little verbose to repeat `@TypeAdapter(InvoiceAdapterImpl.class)` everywhere you want to use your adapter.\r