提交 ebce5fb6 authored 作者: Thomas Mueller's avatar Thomas Mueller

Cleanup:

- the dialect detection will most likely be based on the URL, not on the class name
- 'declaration' is a much too generic term for 'set column = value'
- method names should start with a verb (getTableName instead of tableName)
- remove redundancy and unnecessary formatting in Javadocs (keep it as simple as possible)
上级 991c3742
...@@ -56,11 +56,10 @@ public class Db { ...@@ -56,11 +56,10 @@ public class Db {
public Db(Connection conn) { public Db(Connection conn) {
this.conn = conn; this.conn = conn;
dialect = getDialect(conn.getClass().getCanonicalName()); dialect = getDialect(conn);
} }
private SQLDialect getDialect(String clazz) { private SQLDialect getDialect(Connection conn) {
int todo;
// TODO add special cases here // TODO add special cases here
return new DefaultSQLDialect(); return new DefaultSQLDialect();
} }
...@@ -155,7 +154,7 @@ public class Db { ...@@ -155,7 +154,7 @@ public class Db {
Db upgradeDb() { Db upgradeDb() {
if (!upgradeChecked.contains(dbUpgrader.getClass())) { if (!upgradeChecked.contains(dbUpgrader.getClass())) {
// Flag as checked immediately because calls are nested. // flag as checked immediately because calls are nested.
upgradeChecked.add(dbUpgrader.getClass()); upgradeChecked.add(dbUpgrader.getClass());
JQDatabase model = dbUpgrader.getClass().getAnnotation(JQDatabase.class); JQDatabase model = dbUpgrader.getClass().getAnnotation(JQDatabase.class);
...@@ -165,16 +164,16 @@ public class Db { ...@@ -165,16 +164,16 @@ public class Db {
// (SCHEMA="" && TABLE="") == DATABASE // (SCHEMA="" && TABLE="") == DATABASE
from(v).where(v.schema).is("").and(v.table).is("").selectFirst(); from(v).where(v.schema).is("").and(v.table).is("").selectFirst();
if (dbVersion == null) { if (dbVersion == null) {
// Database has no version registration, but model specifies // database has no version registration, but model specifies
// version. Insert DbVersion entry and return. // version: insert DbVersion entry and return.
DbVersion newDb = new DbVersion(model.version()); DbVersion newDb = new DbVersion(model.version());
insert(newDb); insert(newDb);
} else { } else {
// Database has a version registration, // database has a version registration:
// check to see if upgrade is required. // check to see if upgrade is required.
if ((model.version() > dbVersion.version) if ((model.version() > dbVersion.version)
&& (dbUpgrader != null)) { && (dbUpgrader != null)) {
// Database is an older version than model. // database is an older version than the model
boolean success = dbUpgrader.upgradeDatabase(this, boolean success = dbUpgrader.upgradeDatabase(this,
dbVersion.version, model.version()); dbVersion.version, model.version());
if (success) { if (success) {
...@@ -190,29 +189,29 @@ public class Db { ...@@ -190,29 +189,29 @@ public class Db {
<T> void upgradeTable(TableDefinition<T> model) { <T> void upgradeTable(TableDefinition<T> model) {
if (!upgradeChecked.contains(model.getModelClass())) { if (!upgradeChecked.contains(model.getModelClass())) {
// Flag as checked immediately because calls are nested. // flag is checked immediately because calls are nested
upgradeChecked.add(model.getModelClass()); upgradeChecked.add(model.getModelClass());
if (model.tableVersion > 0) { if (model.tableVersion > 0) {
// Table is using JaQu version tracking. // table is using JaQu version tracking.
DbVersion v = new DbVersion(); DbVersion v = new DbVersion();
String schema = StringUtils.isNullOrEmpty(model.schemaName) ? "" : model.schemaName; String schema = StringUtils.isNullOrEmpty(model.schemaName) ? "" : model.schemaName;
DbVersion dbVersion = DbVersion dbVersion =
from(v).where(v.schema).like(schema).and(v.table) from(v).where(v.schema).like(schema).and(v.table)
.like(model.tableName).selectFirst(); .like(model.tableName).selectFirst();
if (dbVersion == null) { if (dbVersion == null) {
// Table has no version registration, but model specifies // table has no version registration, but model specifies
// version. Insert DbVersion entry and return. // version: insert DbVersion entry
DbVersion newTable = new DbVersion(model.tableVersion); DbVersion newTable = new DbVersion(model.tableVersion);
newTable.schema = schema; newTable.schema = schema;
newTable.table = model.tableName; newTable.table = model.tableName;
insert(newTable); insert(newTable);
} else { } else {
// Table has a version registration. // table has a version registration:
// Check to see if upgrade is required. // check if upgrade is required
if ((model.tableVersion > dbVersion.version) if ((model.tableVersion > dbVersion.version)
&& (dbUpgrader != null)) { && (dbUpgrader != null)) {
// Table is an older version than model. // table is an older version than model
boolean success = dbUpgrader.upgradeTable(this, schema, boolean success = dbUpgrader.upgradeTable(this, schema,
model.tableName, dbVersion.version, model.tableVersion); model.tableName, dbVersion.version, model.tableVersion);
if (success) { if (success) {
...@@ -237,7 +236,7 @@ public class Db { ...@@ -237,7 +236,7 @@ public class Db {
Table table = (Table) t; Table table = (Table) t;
Define.define(def, table); Define.define(def, table);
} else if (clazz.isAnnotationPresent(JQTable.class)) { } else if (clazz.isAnnotationPresent(JQTable.class)) {
// Annotated Class skips Define().define() static initializer // annotated classes skip the Define().define() static initializer
T t = instance(clazz); T t = instance(clazz);
def.mapObject(t); def.mapObject(t);
} }
......
...@@ -32,7 +32,7 @@ public class Query<T> { ...@@ -32,7 +32,7 @@ public class Query<T> {
private Db db; private Db db;
private SelectTable<T> from; private SelectTable<T> from;
private ArrayList<Token> conditions = Utils.newArrayList(); private ArrayList<Token> conditions = Utils.newArrayList();
private ArrayList<UpdateColumn> declarations = Utils.newArrayList(); private ArrayList<UpdateColumn> updateColumnDeclarations = Utils.newArrayList();
private ArrayList<SelectTable<?>> joins = Utils.newArrayList(); private ArrayList<SelectTable<?>> joins = Utils.newArrayList();
private final IdentityHashMap<Object, SelectColumn<T>> aliasMap = Utils.newIdentityHashMap(); private final IdentityHashMap<Object, SelectColumn<T>> aliasMap = Utils.newIdentityHashMap();
private ArrayList<OrderExpression<T>> orderByList = Utils.newArrayList(); private ArrayList<OrderExpression<T>> orderByList = Utils.newArrayList();
...@@ -122,17 +122,15 @@ public class Query<T> { ...@@ -122,17 +122,15 @@ public class Query<T> {
} }
public <A> UpdateColumnSet<T, A> set(A field) { public <A> UpdateColumnSet<T, A> set(A field) {
int renameSetColumnClassToUpdateSetColumn;
return new UpdateColumnSet<T, A>(this, field); return new UpdateColumnSet<T, A>(this, field);
} }
public <A> UpdateColumnIncrement<T, A> increment(A field) { public <A> UpdateColumnIncrement<T, A> increment(A field) {
int renameIncrementColumnClassToUpdateIncrementColumn;
return new UpdateColumnIncrement<T, A>(this, field); return new UpdateColumnIncrement<T, A>(this, field);
} }
public int update() { public int update() {
if (declarations.size() == 0) { if (updateColumnDeclarations.size() == 0) {
throw new RuntimeException("Missing set or increment call."); throw new RuntimeException("Missing set or increment call.");
} }
SQLStatement stat = new SQLStatement(db); SQLStatement stat = new SQLStatement(db);
...@@ -140,7 +138,7 @@ public class Query<T> { ...@@ -140,7 +138,7 @@ public class Query<T> {
from.appendSQL(stat); from.appendSQL(stat);
stat.appendSQL(" SET "); stat.appendSQL(" SET ");
int i = 0; int i = 0;
for (UpdateColumn declaration : declarations) { for (UpdateColumn declaration : updateColumnDeclarations) {
if (i++ > 0) { if (i++ > 0) {
stat.appendSQL(", "); stat.appendSQL(", ");
} }
...@@ -329,9 +327,8 @@ public class Query<T> { ...@@ -329,9 +327,8 @@ public class Query<T> {
conditions.add(condition); conditions.add(condition);
} }
void addDeclarationToken(UpdateColumn declaration) { void addUpdateColumnDeclaration(UpdateColumn declaration) {
int todoWhatIsDeclaration; updateColumnDeclarations.add(declaration);
declarations.add(declaration);
} }
void appendWhere(SQLStatement stat) { void appendWhere(SQLStatement stat) {
......
...@@ -23,7 +23,7 @@ public interface SQLDialect { ...@@ -23,7 +23,7 @@ public interface SQLDialect {
* @param table the table name * @param table the table name
* @return the SQL snippet * @return the SQL snippet
*/ */
String tableName(String schema, String table); String getTableName(String schema, String table);
/** /**
* Get the CREATE INDEX statement. * Get the CREATE INDEX statement.
...@@ -33,7 +33,7 @@ public interface SQLDialect { ...@@ -33,7 +33,7 @@ public interface SQLDialect {
* @param index the index definition * @param index the index definition
* @return the SQL statement * @return the SQL statement
*/ */
String createIndex(String schema, String table, IndexDefinition index); String getCreateIndex(String schema, String table, IndexDefinition index);
/** /**
* Append "LIMIT limit" to the SQL statement. * Append "LIMIT limit" to the SQL statement.
...@@ -51,20 +51,31 @@ public interface SQLDialect { ...@@ -51,20 +51,31 @@ public interface SQLDialect {
*/ */
void appendOffset(SQLStatement stat, long offset); void appendOffset(SQLStatement stat, long offset);
/**
* Whether memory tables are supported.
*
* @return true if they are
*/
boolean supportsMemoryTables();
/** /**
* Default implementation of an SQL dialect. * Default implementation of an SQL dialect.
* Designed for an H2 database. May be suitable for others. * Designed for an H2 database. May be suitable for others.
*/ */
public static class DefaultSQLDialect implements SQLDialect { public static class DefaultSQLDialect implements SQLDialect {
public String tableName(String schema, String table) { public String getTableName(String schema, String table) {
if (StringUtils.isNullOrEmpty(schema)) { if (StringUtils.isNullOrEmpty(schema)) {
return table; return table;
} }
return schema + "." + table; return schema + "." + table;
} }
public String createIndex(String schema, String table, IndexDefinition index) { public boolean supportsMemoryTables() {
return true;
}
public String getCreateIndex(String schema, String table, IndexDefinition index) {
StatementBuilder buff = new StatementBuilder(); StatementBuilder buff = new StatementBuilder();
buff.append("CREATE "); buff.append("CREATE ");
switch(index.type) { switch(index.type) {
......
...@@ -40,7 +40,7 @@ public class SQLStatement { ...@@ -40,7 +40,7 @@ public class SQLStatement {
} }
public SQLStatement appendTable(String schema, String table) { public SQLStatement appendTable(String schema, String table) {
return appendSQL(db.getDialect().tableName(schema, table)); return appendSQL(db.getDialect().getTableName(schema, table));
} }
String getSQL() { String getSQL() {
......
...@@ -13,110 +13,75 @@ import java.lang.annotation.Target; ...@@ -13,110 +13,75 @@ import java.lang.annotation.Target;
/** /**
* A class that implements this interface can be used as a database table. * A class that implements this interface can be used as a database table.
*/
/**
* A class that implements the JaQu model mapping options.
* <p> * <p>
* You may implement the Table interface on your model object and optionally use * You may implement the Table interface on your model object and optionally use
* JQColumn annotations.<br> * JQColumn annotations (which imposes a compile-time and runtime-dependency on
* <i>This imposes a compile-time and runtime-dependency on JaQu.</i> * JaQu), or may choose to use the JQTable and JQColumn annotations only (which
* <p> * imposes a compile-time and runtime-dependency on this file only).
* <u>OR</u>
* <p>
* You may choose to use the JQTable and JQColumn annotations only.<br>
* <i>This imposes a compile-time and runtime-dependency on this file only.</i>
* <p> * <p>
* <b>NOTE</b><br> * If a class is annotated with JQTable and at the same time implements Table,
* Classes that are annotated with JQTable <b>and</b> implement Table will NOT * the define() method is not called.
* call the define() method.
* <p> * <p>
* <b>Supported Data Types</b> * Supported data types:
* <table> * <table>
* <tr> * <tr>
* <td>java.lang.String</td> * <td>java.lang.String</td>
* <td>VARCHAR (maxLength > 0) / TEXT (maxLength == 0)</td> * <td>VARCHAR (maxLength > 0) / TEXT (maxLength == 0)</td>
* </tr> * </tr>
* <tr> * <tr>
* <td>java.lang.Boolean</td> * <td>java.lang.Boolean</td><td>BIT</td>
* <td>BIT</td>
* </tr> * </tr>
* <tr> * <tr>
* <td>java.lang.Byte</td> * <td>java.lang.Byte</td><td>TINYINT</td>
* <td>TINYINT</td>
* </tr> * </tr>
* <tr> * <tr>
* <td>java.lang.Short</td> * <td>java.lang.Short</td><td>SMALLINT</td>
* <td>SMALLINT</td>
* </tr> * </tr>
* <tr> * <tr>
* <td>java.lang.Integer</td> * <td>java.lang.Integer</td><td>INT</td>
* <td>INT</td>
* </tr> * </tr>
* <tr> * <tr>
* <td>java.lang.Long</td> * <td>java.lang.Long</td><td>BIGINT</td>
* <td>BIGINT</td>
* </tr> * </tr>
* <tr> * <tr>
* <td>java.lang.Float</td> * <td>java.lang.Float</td><td>REAL</td>
* <td>REAL</td>
* </tr> * </tr>
* <tr> * <tr>
* <td>java.lang.Double</td> * <td>java.lang.Double</td><td>DOUBLE</td>
* <td>DOUBLE</td>
* </tr> * </tr>
* <tr> * <tr>
* <td>java.math.BigDecimal</td> * <td>java.math.BigDecimal</td><td>DECIMAL</td>
* <td>DECIMAL</td>
* </tr> * </tr>
* <tr> * <tr>
* <td>java.util.Date</td> * <td>java.util.Date</td><td>TIMESTAMP</td>
* <td>TIMESTAMP</td>
* </tr> * </tr>
* <tr> * <tr>
* <td>java.sql.Date</td> * <td>java.sql.Date</td><td>DATE</td>
* <td>DATE</td>
* </tr> * </tr>
* <tr> * <tr>
* <td>java.sql.Time</td> * <td>java.sql.Time</td><td>TIME</td>
* <td>TIME</td>
* </tr> * </tr>
* <tr> * <tr>
* <td>java.sql.Timestamp</td> * <td>java.sql.Timestamp</td><td>TIMESTAMP</td>
* <td>TIMESTAMP</td>
* </tr> * </tr>
* </table> * </table>
* <p> * <p>
* <b>Unsupported Data Types</b> * Unsupported data types: binary types (BLOB, etc), and custom types.
* <ul>
* <li>Binary types (BLOB, etc)
* <li>Custom types
* </ul>
* <p> * <p>
* <b>Table and Field Mapping</b> * Table and field mapping: by default, the mapped table name is the class name
* <p> * and the public fields are reflectively mapped, by their name, to columns. As
* By default, the mapped table name is the class name and the <i>public</i> * an alternative, you may specify both the table and column definition by
* fields are reflectively mapped, by their name, to columns.
* <p>
* As an alternative, you may specify both the table and column definition by
* annotations. * annotations.
* <p> * <p>
* <b>Table Interface</b> * Table Interface: you may set additional parameters such as table name,
* <p> * primary key, and indexes in the define() method.
* You may set additional parameters such as table name, primary key, and
* indexes in the <i>define()</i> method.
* <p>
* <b>Annotations</b>
* <p> * <p>
* You may use the annotations with or without implementing the Table interface. * Annotations: you may use the annotations with or without implementing the
* <br> * Table interface. The annotations allow you to decouple your model completely
* The annotations allow you to decouple your model completely from JaQu other * from JaQu other than this file.
* than this file.
* <p> * <p>
* <b>Automatic Model Generation</b> * Automatic model generation: you may automatically generate model classes as
* <p> * strings with the Db and DbInspector objects:
* You may automatically generate model classes as strings with the <i>Db</i>
* and <i>DbInspector</i> objects.
*
* <pre> * <pre>
* Db db = Db.open(&quot;jdbc:h2:mem:&quot;, &quot;sa&quot;, &quot;sa&quot;); * Db db = Db.open(&quot;jdbc:h2:mem:&quot;, &quot;sa&quot;, &quot;sa&quot;);
* DbInspector inspector = new DbInspector(db); * DbInspector inspector = new DbInspector(db);
...@@ -124,10 +89,8 @@ import java.lang.annotation.Target; ...@@ -124,10 +89,8 @@ import java.lang.annotation.Target;
* inspector.generateModel(schema, table, packageName, * inspector.generateModel(schema, table, packageName,
* annotateSchema, trimStrings) * annotateSchema, trimStrings)
* </pre> * </pre>
* * Or you may use the GenerateModels tool to generate and save your classes to
* OR you may use the <i>GenerateModels</i> tool to generate and save your * the file system:
* classes to the filesystem.
*
* <pre> * <pre>
* java -cp h2jaqu.jar org.h2.jaqu.util.GenerateModels * java -cp h2jaqu.jar org.h2.jaqu.util.GenerateModels
* -url &quot;jdbc:h2:mem:&quot; * -url &quot;jdbc:h2:mem:&quot;
...@@ -136,18 +99,12 @@ import java.lang.annotation.Target; ...@@ -136,18 +99,12 @@ import java.lang.annotation.Target;
* -annotateSchema false -trimStrings true * -annotateSchema false -trimStrings true
* </pre> * </pre>
* *
* <b>Model Validation</b> * Model validation: you may validate your model class with DbInspector object.
* <p> * The DbInspector will report errors, warnings, and suggestions:
* You may validate your model class with <i>DbInspector</i> object.<br>
* The DbInspector will report ERRORS, WARNINGS, and
* SUGGESTIONS to help you.
*
* <pre> * <pre>
* Db db = Db.open(&quot;jdbc:h2:mem:&quot;, * Db db = Db.open(&quot;jdbc:h2:mem:&quot;, &quot;sa&quot;, &quot;sa&quot;);
* &quot;sa&quot;, &quot;sa&quot;);
* DbInspector inspector = new DbInspector(db); * DbInspector inspector = new DbInspector(db);
* List&lt;Validation&gt; remarks = * List&lt;Validation&gt; remarks = inspector.validateModel(new MyModel(), throwOnError);
* inspector.validateModel(new MyModel(), throwOnError);
* for (Validation remark : remarks) { * for (Validation remark : remarks) {
* System.out.println(remark); * System.out.println(remark);
* } * }
...@@ -155,31 +112,39 @@ import java.lang.annotation.Target; ...@@ -155,31 +112,39 @@ import java.lang.annotation.Target;
*/ */
public interface Table { public interface Table {
static final int reviewWholeClassAndJavadocs = 0; /**
* An annotation for a database.
*/
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE) @Target(ElementType.TYPE)
public @interface JQDatabase { public @interface JQDatabase {
/** /**
* If version is set to a non-zero value, JaQu will * If set to a non-zero value, JaQu
* maintain a "_jq_versions" table within your database. The * maintains a "_jq_versions" table within your database. The
* version number will be used to call to a registered * version number is used to call to a registered
* DbUpgrader implementation to perform relevant ALTER statements. * DbUpgrader implementation to perform relevant ALTER statements.
* Default: 0. * Default: 0.
* You must specify a DbUpgrader on your Db object to * You must specify a DbUpgrader on your Db object to
* use this parameter. * use this parameter.
*/ */
int version() default 0; int version() default 0;
} }
/**
* An annotation for a schema.
*/
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE) @Target(ElementType.TYPE)
public @interface JQSchema { public @interface JQSchema {
/** /**
* The schema may be optionally specified. If it is not specified the * The schema may be optionally specified.
* schema will be ignored. Default: Unspecified. * Default: unspecified.
*/ */
String name() default ""; String name() default "";
} }
/** /**
...@@ -189,66 +154,64 @@ public interface Table { ...@@ -189,66 +154,64 @@ public interface Table {
STANDARD, UNIQUE, HASH, UNIQUE_HASH; STANDARD, UNIQUE, HASH, UNIQUE_HASH;
} }
/**
* An index annotation.
*/
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE) @Target(ElementType.TYPE)
public @interface JQIndex { public @interface JQIndex {
/** /**
* Standard indexes may be optionally specified. If not specified, * Standard indexes may be optionally specified.
* these values will be ignored.
* <ul> * <ul>
* <li>standard = "id, name" * <li>standard = "id, name"</li>
* <li>standard = "id name" * <li>standard = "id name"</li>
* <li>standard = { "id name", "date" } * <li>standard = { "id name", "date" }</li>
* </ul> * </ul>
* Standard indexes may still be added in the define() method if * Standard indexes may still be added in the define() method if
* the model class is not annotated with JQTable. * the model class is not annotated with JQTable.
* Default: Unspecified. * Default: unspecified.
*/ */
String[] standard() default {}; String[] standard() default {};
/** /**
* <b>unique</b> indexes may be optionally specified. If not specified, * Unique indexes may be optionally specified.
* these values will be ignored.
* <ul> * <ul>
* <li>unique = "id, name" * <li>unique = "id, name"</li>
* <li>unique = "id name" * <li>unique = "id name"</li>
* <li>unique = { "id name", "date" } * <li>unique = { "id name", "date" }</li>
* </ul> * </ul>
* Unique indexes may still be added in the <i>define()</i> method if * Unique indexes may still be added in the define() method if
* the model class is not annotated with JQTable. * the model class is not annotated with JQTable.
* <p> * Default: unspecified.
* <b>Default: <i>Unspecified</i></b>
*/ */
String[] unique() default {}; String[] unique() default {};
/** /**
* <b>hash</b> indexes may be optionally specified. If not specified, * Hash indexes may be optionally specified.
* these values will be ignored.
* <ul> * <ul>
* <li>hash = "name" * <li>hash = "name"
* <li>hash = { "name", "date" } * <li>hash = { "name", "date" }
* </ul> * </ul>
* Hash indexes may still be added in the <i>define()</i> method if * Hash indexes may still be added in the define() method if
* the model class is not annotated with JQTable. * the model class is not annotated with JQTable.
* <p> * Default: unspecified.
* <b>Default: <i>Unspecified</i></b>
*/ */
String[] hash() default {}; String[] hash() default {};
/** /**
* <b>uniqueHash</b> indexes may be optionally specified. If not specified, * Unique hash indexes may be optionally specified.
* these values will be ignored.
* <ul> * <ul>
* <li>uniqueHash = "id" * <li>uniqueHash = "id"
* <li>uniqueHash = "name" * <li>uniqueHash = "name"
* <li>uniqueHash = { "id", "name" } * <li>uniqueHash = { "id", "name" }
* </ul> * </ul>
* UniqueHash indexes may still be added in the <i>define()</i> method if * Unique hash indexes may still be added in the define() method if
* the model class is not annotated with JQTable. * the model class is not annotated with JQTable.
* <p> * Default: unspecified.
* <b>Default: <i>Unspecified</i></b>
*/ */
String[] uniqueHash() default {}; String[] uniqueHash() default {};
} }
/** /**
...@@ -259,189 +222,151 @@ public interface Table { ...@@ -259,189 +222,151 @@ public interface Table {
public @interface JQTable { public @interface JQTable {
/** /**
* <b>name</b> may be optionally specified. If it is not specified the * The table name. If not specified the
* class name will be used as the table name. * class name is used as the table name.
* <p> * <p>
* The table name may still be overridden in the <i>define()</i> method * The table name may still be overridden in the define() method
* if the model class is not annotated with JQTable. * if the model class is not annotated with JQTable.
* <p> * Default: unspecified.
* <b>Default: <i>Unspecified</i></b>
*/ */
String name() default ""; String name() default "";
/** /**
* <b>primaryKey</b> may be optionally specified. If it is not * The primary key may be optionally specified. If it is not
* specified, then no primary key will be set by the JQTable annotation. * specified, then no primary key is set by the JQTable annotation.
* You may specify a composite primary key. * You may specify a composite primary key.
* <ul> * <ul>
* <li>primaryKey = "id, name" * <li>primaryKey = "id, name"
* <li>primaryKey = "id name" * <li>primaryKey = "id name"
* </ul> * </ul>
* The primaryKey may still be overridden in the <i>define()</i> method * The primary key may still be overridden in the define() method
* if the model class is not annotated with JQTable. * if the model class is not annotated with JQTable.
* <p> * Default: unspecified.
* <b>Default: <i>Unspecified</i></b>
*/ */
String primaryKey() default ""; String primaryKey() default "";
/** /**
* <b>inheritColumns</b> allows this model class to inherit columns from * The inherit columns allows this model class to inherit columns from
* its super class. Any JQTable annotation present on the super class is * its super class. Any JQTable annotation present on the super class is
* ignored.<br> * ignored.
* <p> * Default: false.
* <b>Default: <i>false</i></b>
*/ */
boolean inheritColumns() default false; boolean inheritColumns() default false;
/** /**
* <b>createIfRequired</b> allows user to control whether or not * Whether or not JaQu tries to create the table and indexes. Default:
* JaQu tries to create the table and indexes. * true.
* <p>
* <b>Default: <i>true</i></b>
*/ */
boolean createIfRequired() default true; boolean createIfRequired() default true;
/** /**
* <b>strictTypeMapping</b> allows user to specify that only supported * Whether only supported types are mapped.
* types are mapped.<br> * If true, unsupported mapped types will throw a RuntimeException.
* If set <i>true</i>, unsupported mapped types will throw a * If false, unsupported mapped types will default to VARCHAR.
* RuntimeException.<br> * Default: true.
* If set <i>false</i>, unsupported mapped types will default to
* VARCHAR.
* <p>
* <b>Default: <i>true</i></b>
*/ */
boolean strictTypeMapping() default true; boolean strictTypeMapping() default true;
/** /**
* <b>annotationsOnly</b> controls reflective field mapping on your * If true, only fields that are explicitly
* model object. If set <i>true</i>, only fields that are explicitly
* annotated as JQColumn are mapped. * annotated as JQColumn are mapped.
* <p> * Default: true.
* <b>Default: <i>true</i></b>
*/ */
boolean annotationsOnly() default true; boolean annotationsOnly() default true;
/** /**
* If <b>memoryTable</b> is set <i>true</i>, this table is created as a * If true, this table is created as a memory table where data is persistent,
* memory table where data is persistent, but index data is kept in main * but index data is kept in main memory.
* memory.<br> * Valid only for H2 databases.
* The JDBC Connection class is verified before applying this property * Default: false.
* in the CREATE phase.
* <p>
* <b>Default: <i>false</i></b>
* <p>
* <u>Valid only for H2 databases.</u>
*/ */
boolean memoryTable() default false; boolean memoryTable() default false;
/** /**
* If <b>version</b> is set to a <i>non-zero</i> value, JaQu will * If non-zero, JaQu will
* maintain a "_jq_versions" table within your database. The * maintain a "_jq_versions" table within your database. The
* <i>version</i> number will be used to call to a registered * version number is used to call to a registered
* <i>DbUpgrader</i> implementation to perform relevant ALTER * DbUpgrader implementation to perform relevant ALTER
* statements. * statements.
* <p> * Default: 0.
* <b>Default: <i>0</i></b> * You must specify a DbUpgrader on your Db object to
* <p>
* <bNOTE:</b><br>
* You must specify a <i>DbUpgrader</i> on your <i>Db</i> object to
* use this parameter. * use this parameter.
*/ */
int version() default 0; int version() default 0;
} }
/** /**
* Annotation to define a Column. Annotated fields may have any Scope with * Annotation to define a column. Annotated fields may have any scope
* the understanding that under some circumstances, the JVM may raise a * (however, the JVM may raise a SecurityException if the SecurityManager
* SecurityException. * doesn't allow JaQu to access the field.)
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD) @Target(ElementType.FIELD)
public @interface JQColumn { public @interface JQColumn {
/** /**
* If <b>name</b> is not specified the instance variable field name will * If not specified, the field name is used as the column name.
* be used as the column name. * Default: the field name.
* <p>
* <b>Default: <i>reflective field name mapping</i></b>
*/ */
String name() default ""; String name() default "";
/** /**
* If <b>primaryKey</b> is true, this column will be the PrimaryKey. * This column is the primary key.
* <p> * Default: false.
* <b>Default: <i>false</i></b>
*/ */
boolean primaryKey() default false; boolean primaryKey() default false;
/** /**
* If <b>autoIncrement</b> is true, the column will be created with a * The column is created with a
* sequence as the default value. * sequence as the default value.
* <p> * Default: false.
* <b>Default: <i>false</i></b>
*/ */
boolean autoIncrement() default false; boolean autoIncrement() default false;
/** /**
* If <b>maxLength</b> > 0 it is used during the CREATE TABLE phase. It * If larger than zero, it is used during the CREATE TABLE phase. It
* may also be optionally used to prevent database exceptions on INSERT * may also be used to prevent database exceptions on INSERT
* and UPDATE statements (see <i>trimString</i>). * and UPDATE statements (see trimString).
* <p> * <p>
* Any maxLength set in <i>define()</i> may override this annotation * Any maxLength set in define() may override this annotation
* setting if the model class is not annotated with JQTable. * setting if the model class is not annotated with JQTable.
* <p> * Default: 0.
* <b>Default: <i>0</i></b>
*/ */
int maxLength() default 0; int maxLength() default 0;
/** /**
* If <b>trimString</b> is <i>true</i> JaQu will automatically trim the * If true, JaQu will automatically trim the
* string if it exceeds <b>maxLength</b>. * string if it exceeds maxLength
* <p> * (value.substring(0, maxLength)).
* e.g. stringValue = stringValue.substring(0, maxLength) * Default: false.
* <p>
* <b>Default: <i>false</i></b>
*/ */
boolean trimString() default false; boolean trimString() default false;
/** /**
* If <b>allowNull</b> is <i>false</i> then JaQu will set * If false, JaQu will set
* the column NOT NULL during the CREATE TABLE phase. * the column NOT NULL during the CREATE TABLE phase.
* <p> * Default: false.
* <b>Default: <i>false</i></b>
*/ */
boolean allowNull() default false; boolean allowNull() default false;
/** /**
* <b>defaultValue</b> is the value assigned to the column during the * The default value assigned to the column during the CREATE TABLE
* CREATE TABLE phase. * phase. This field could contain a literal single-quoted value, or a
* <p> * function call. Empty strings are considered NULL. Examples:
* To set <b>null</b>, defaultValue="" (default)
* <p>
* This field could contain a literal <u>single-quoted value</u>.<br>
* Or a function call.<br>
* Empty strings will be considered NULL.
* <ul> * <ul>
* <li>defaultValue="" (null) * <li>defaultValue="" (null)
* <li>defaultValue="CURRENT_TIMESTAMP" (H2 current_timestamp()) * <li>defaultValue="CURRENT_TIMESTAMP"
* <li>defaultValue="''" (default empty string) * <li>defaultValue="''" (empty string)
* <li>defaultValue="'0'" (default number) * <li>defaultValue="'0'"
* <li>defaultValue="'1970-01-01 00:00:01'" (default date) * <li>defaultValue="'1970-01-01 00:00:01'"
* </ul>
* if (
* <ul>
* <li>defaultValue is properly specified
* <li>AND <i>autoIncrement</i> == false
* <li>AND <i>primaryKey</i> == false
* </ul> * </ul>
* )<br> * if the default value is specified, and auto increment is disabled,
* then this value will be included in the "DEFAULT ..." phrase of a * and primary key is disabled, then this value is included in the
* column during the CREATE TABLE process. * "DEFAULT ..." phrase of a column during the CREATE TABLE process.
* <p> * Default: unspecified (null).
* <b>Default: <i>unspecified, null</i></b>
*/ */
String defaultValue() default ""; String defaultValue() default "";
} }
/** /**
...@@ -449,4 +374,5 @@ public interface Table { ...@@ -449,4 +374,5 @@ public interface Table {
* and the table name. * and the table name.
*/ */
void define(); void define();
} }
...@@ -79,7 +79,6 @@ class TableDefinition<T> { ...@@ -79,7 +79,6 @@ class TableDefinition<T> {
void setValue(Object obj, Object o) { void setValue(Object obj, Object o) {
try { try {
int setAccessibleShouldNotBeRequiredHere;
if (!field.isAccessible()) { if (!field.isAccessible()) {
field.setAccessible(true); field.setAccessible(true);
} }
...@@ -101,6 +100,7 @@ class TableDefinition<T> { ...@@ -101,6 +100,7 @@ class TableDefinition<T> {
String schemaName; String schemaName;
String tableName; String tableName;
int tableVersion;
private boolean createTableIfRequired = true; private boolean createTableIfRequired = true;
private Class<T> clazz; private Class<T> clazz;
private ArrayList<FieldDefinition> fields = Utils.newArrayList(); private ArrayList<FieldDefinition> fields = Utils.newArrayList();
...@@ -111,8 +111,6 @@ class TableDefinition<T> { ...@@ -111,8 +111,6 @@ class TableDefinition<T> {
private ArrayList<IndexDefinition> indexes = Utils.newArrayList(); private ArrayList<IndexDefinition> indexes = Utils.newArrayList();
private boolean memoryTable; private boolean memoryTable;
int tableVersion;
TableDefinition(Class<T> clazz) { TableDefinition(Class<T> clazz) {
this.clazz = clazz; this.clazz = clazz;
schemaName = null; schemaName = null;
...@@ -275,13 +273,13 @@ class TableDefinition<T> { ...@@ -275,13 +273,13 @@ class TableDefinition<T> {
} }
/** /**
* Optionally truncates strings to maxLength * Optionally truncates strings to the maximum length
*/ */
private Object getValue(Object obj, FieldDefinition field) { private Object getValue(Object obj, FieldDefinition field) {
Object value = field.getValue(obj); Object value = field.getValue(obj);
if (field.trimString && field.maxLength > 0) { if (field.trimString && field.maxLength > 0) {
if (value instanceof String) { if (value instanceof String) {
// Clip Strings // clip strings
String s = (String) value; String s = (String) value;
if (s.length() > field.maxLength) { if (s.length() > field.maxLength) {
return s.substring(0, field.maxLength); return s.substring(0, field.maxLength);
...@@ -297,7 +295,7 @@ class TableDefinition<T> { ...@@ -297,7 +295,7 @@ class TableDefinition<T> {
long insert(Db db, Object obj, boolean returnKey) { long insert(Db db, Object obj, boolean returnKey) {
SQLStatement stat = new SQLStatement(db); SQLStatement stat = new SQLStatement(db);
StatementBuilder buff = new StatementBuilder("INSERT INTO "); StatementBuilder buff = new StatementBuilder("INSERT INTO ");
buff.append(db.getDialect().tableName(schemaName, tableName)).append('('); buff.append(db.getDialect().getTableName(schemaName, tableName)).append('(');
for (FieldDefinition field : fields) { for (FieldDefinition field : fields) {
buff.appendExceptFirst(", "); buff.appendExceptFirst(", ");
buff.append(field.columnName); buff.append(field.columnName);
...@@ -326,7 +324,7 @@ class TableDefinition<T> { ...@@ -326,7 +324,7 @@ class TableDefinition<T> {
} }
SQLStatement stat = new SQLStatement(db); SQLStatement stat = new SQLStatement(db);
StatementBuilder buff = new StatementBuilder("MERGE INTO "); StatementBuilder buff = new StatementBuilder("MERGE INTO ");
buff.append(db.getDialect().tableName(schemaName, tableName)).append(" ("); buff.append(db.getDialect().getTableName(schemaName, tableName)).append(" (");
buff.resetCount(); buff.resetCount();
for (FieldDefinition field : fields) { for (FieldDefinition field : fields) {
buff.appendExceptFirst(", "); buff.appendExceptFirst(", ");
...@@ -362,7 +360,7 @@ class TableDefinition<T> { ...@@ -362,7 +360,7 @@ class TableDefinition<T> {
} }
SQLStatement stat = new SQLStatement(db); SQLStatement stat = new SQLStatement(db);
StatementBuilder buff = new StatementBuilder("UPDATE "); StatementBuilder buff = new StatementBuilder("UPDATE ");
buff.append(db.getDialect().tableName(schemaName, tableName)).append(" SET "); buff.append(db.getDialect().getTableName(schemaName, tableName)).append(" SET ");
buff.resetCount(); buff.resetCount();
for (FieldDefinition field : fields) { for (FieldDefinition field : fields) {
...@@ -403,7 +401,7 @@ class TableDefinition<T> { ...@@ -403,7 +401,7 @@ class TableDefinition<T> {
} }
SQLStatement stat = new SQLStatement(db); SQLStatement stat = new SQLStatement(db);
StatementBuilder buff = new StatementBuilder("DELETE FROM "); StatementBuilder buff = new StatementBuilder("DELETE FROM ");
buff.append(db.getDialect().tableName(schemaName, tableName)); buff.append(db.getDialect().getTableName(schemaName, tableName));
buff.resetCount(); buff.resetCount();
Object alias = Utils.newObject(obj.getClass()); Object alias = Utils.newObject(obj.getClass());
Query<Object> query = Query.from(db, alias); Query<Object> query = Query.from(db, alias);
...@@ -429,44 +427,38 @@ class TableDefinition<T> { ...@@ -429,44 +427,38 @@ class TableDefinition<T> {
TableDefinition<T> createTableIfRequired(Db db) { TableDefinition<T> createTableIfRequired(Db db) {
if (!createTableIfRequired) { if (!createTableIfRequired) {
// Skip table and index creation // skip table and index creation
// But still check for upgrades // but still check for upgrades
db.upgradeTable(this); db.upgradeTable(this);
return this; return this;
} }
SQLDialect dialect = db.getDialect();
SQLStatement stat = new SQLStatement(db); SQLStatement stat = new SQLStatement(db);
StatementBuilder buff; StatementBuilder buff;
if (memoryTable && if (memoryTable && dialect.supportsMemoryTables()) {
db.getConnection().getClass()
.getCanonicalName().equals("org.h2.jdbc.JdbcConnection")) {
buff = new StatementBuilder("CREATE MEMORY TABLE IF NOT EXISTS "); buff = new StatementBuilder("CREATE MEMORY TABLE IF NOT EXISTS ");
} else { } else {
buff = new StatementBuilder("CREATE TABLE IF NOT EXISTS "); buff = new StatementBuilder("CREATE TABLE IF NOT EXISTS ");
} }
int todoChangeToGetTableNameChangeAllMethodsInDialectInterface; buff.append(dialect.getTableName(schemaName, tableName)).append('(');
buff.append(db.getDialect().tableName(schemaName, tableName)).append('(');
for (FieldDefinition field : fields) { for (FieldDefinition field : fields) {
buff.appendExceptFirst(", "); buff.appendExceptFirst(", ");
buff.append(field.columnName).append(' ').append(field.dataType); buff.append(field.columnName).append(' ').append(field.dataType);
// FIELD LENGTH
if (field.maxLength > 0) { if (field.maxLength > 0) {
buff.append('(').append(field.maxLength).append(')'); buff.append('(').append(field.maxLength).append(')');
} }
// AUTO_INCREMENT
if (field.isAutoIncrement) { if (field.isAutoIncrement) {
buff.append(" AUTO_INCREMENT"); buff.append(" AUTO_INCREMENT");
} }
// NOT NULL
if (!field.allowNull) { if (!field.allowNull) {
buff.append(" NOT NULL"); buff.append(" NOT NULL");
} }
// DEFAULT... // default values
if (!field.isAutoIncrement && !field.isPrimaryKey) { if (!field.isAutoIncrement && !field.isPrimaryKey) {
String dv = field.defaultValue; String dv = field.defaultValue;
if (!StringUtils.isNullOrEmpty(dv)) { if (!StringUtils.isNullOrEmpty(dv)) {
...@@ -478,8 +470,7 @@ class TableDefinition<T> { ...@@ -478,8 +470,7 @@ class TableDefinition<T> {
} }
} }
int reviewJavadoc; // primary key
// PRIMARY KEY...
if (primaryKeyColumnNames != null && primaryKeyColumnNames.size() > 0) { if (primaryKeyColumnNames != null && primaryKeyColumnNames.size() > 0) {
buff.append(", PRIMARY KEY("); buff.append(", PRIMARY KEY(");
buff.resetCount(); buff.resetCount();
...@@ -494,24 +485,24 @@ class TableDefinition<T> { ...@@ -494,24 +485,24 @@ class TableDefinition<T> {
StatementLogger.create(stat.getSQL()); StatementLogger.create(stat.getSQL());
stat.executeUpdate(); stat.executeUpdate();
// Create Indexes // create indexes
for (IndexDefinition index:indexes) { for (IndexDefinition index:indexes) {
String sql = db.getDialect().createIndex(schemaName, tableName, index); String sql = db.getDialect().getCreateIndex(schemaName, tableName, index);
stat.setSQL(sql); stat.setSQL(sql);
StatementLogger.create(stat.getSQL()); StatementLogger.create(stat.getSQL());
stat.executeUpdate(); stat.executeUpdate();
} }
// Table is created IF NOT EXISTS, otherwise statement is ignored // tables are created using IF NOT EXISTS
// But we still need to process potential Upgrade // but we may still need to upgrade
db.upgradeTable(this); db.upgradeTable(this);
return this; return this;
} }
/** /**
* Retrieve list of columns from CSV whitespace notated index * Retrieve list of columns from index definition.
* *
* @param index the index columns * @param index the index columns, separated by space
* @return the column list * @return the column list
*/ */
private List<String> getColumns(String index) { private List<String> getColumns(String index) {
...@@ -569,7 +560,7 @@ class TableDefinition<T> { ...@@ -569,7 +560,7 @@ class TableDefinition<T> {
if (clazz.isAnnotationPresent(JQIndex.class)) { if (clazz.isAnnotationPresent(JQIndex.class)) {
JQIndex indexAnnotation = clazz.getAnnotation(JQIndex.class); JQIndex indexAnnotation = clazz.getAnnotation(JQIndex.class);
// Setup the indexes, if properly annotated // setup the indexes, if properly annotated
addIndexes(IndexType.STANDARD, indexAnnotation.standard()); addIndexes(IndexType.STANDARD, indexAnnotation.standard());
addIndexes(IndexType.UNIQUE, indexAnnotation.unique()); addIndexes(IndexType.UNIQUE, indexAnnotation.unique());
addIndexes(IndexType.HASH, indexAnnotation.hash()); addIndexes(IndexType.HASH, indexAnnotation.hash());
......
...@@ -493,8 +493,7 @@ public class TableInspector { ...@@ -493,8 +493,7 @@ public class TableInspector {
JQColumn.class.getSimpleName(), fieldDef.isAutoIncrement, JQColumn.class.getSimpleName(), fieldDef.isAutoIncrement,
col.isAutoIncrement))); col.isAutoIncrement)));
} }
// last check // default value
// default value...
if (!col.isAutoIncrement && !col.isPrimaryKey) { if (!col.isAutoIncrement && !col.isPrimaryKey) {
// check Model.defaultValue format // check Model.defaultValue format
if (!ModelUtils.isProperlyFormattedDefaultValue(fieldDef.defaultValue)) { if (!ModelUtils.isProperlyFormattedDefaultValue(fieldDef.defaultValue)) {
...@@ -510,20 +509,20 @@ public class TableInspector { ...@@ -510,20 +509,20 @@ public class TableInspector {
&& !isNullOrEmpty(col.defaultValue)) { && !isNullOrEmpty(col.defaultValue)) {
// Model.defaultValue is NULL, Column.defaultValue is NOT NULL // Model.defaultValue is NULL, Column.defaultValue is NOT NULL
remarks.add(warn(table, col, format("{0}.defaultValue=\"\"" remarks.add(warn(table, col, format("{0}.defaultValue=\"\""
+ " while Column default=\"{1}\"", + " while column default=\"{1}\"",
JQColumn.class.getSimpleName(), col.defaultValue))); JQColumn.class.getSimpleName(), col.defaultValue)));
} else if (!isNullOrEmpty(fieldDef.defaultValue) } else if (!isNullOrEmpty(fieldDef.defaultValue)
&& isNullOrEmpty(col.defaultValue)) { && isNullOrEmpty(col.defaultValue)) {
// Column.defaultValue is NULL, Model.defaultValue is NOT NULL // Column.defaultValue is NULL, Model.defaultValue is NOT NULL
remarks.add(warn(table, col, format("{0}.defaultValue=\"{1}\"" remarks.add(warn(table, col, format("{0}.defaultValue=\"{1}\""
+ " while Column default=\"\"", + " while column default=\"\"",
JQColumn.class.getSimpleName(), fieldDef.defaultValue))); JQColumn.class.getSimpleName(), fieldDef.defaultValue)));
} else if (!isNullOrEmpty(fieldDef.defaultValue) } else if (!isNullOrEmpty(fieldDef.defaultValue)
&& !isNullOrEmpty(col.defaultValue)) { && !isNullOrEmpty(col.defaultValue)) {
if (!fieldDef.defaultValue.equals(col.defaultValue)) { if (!fieldDef.defaultValue.equals(col.defaultValue)) {
// Model.defaultValue != Column.defaultValue // Model.defaultValue != Column.defaultValue
remarks.add(warn(table, col, format("{0}.defaultValue=\"{1}\"" remarks.add(warn(table, col, format("{0}.defaultValue=\"{1}\""
+ " while Column default=\"{2}\"", + " while column default=\"{2}\"",
JQColumn.class.getSimpleName(), fieldDef.defaultValue, JQColumn.class.getSimpleName(), fieldDef.defaultValue,
col.defaultValue))); col.defaultValue)));
} }
...@@ -533,7 +532,7 @@ public class TableInspector { ...@@ -533,7 +532,7 @@ public class TableInspector {
if (!ModelUtils.isValidDefaultValue(fieldDef.field.getType(), if (!ModelUtils.isValidDefaultValue(fieldDef.field.getType(),
fieldDef.defaultValue)) { fieldDef.defaultValue)) {
remarks.add(error(table, col, remarks.add(error(table, col,
format("{0}.defaultValue=\"{1}\" is invalid!!", format("{0}.defaultValue=\"{1}\" is invalid!",
JQColumn.class.getSimpleName(), JQColumn.class.getSimpleName(),
fieldDef.defaultValue))); fieldDef.defaultValue)));
} }
......
...@@ -25,7 +25,7 @@ public class UpdateColumnIncrement<T, A> implements UpdateColumn { ...@@ -25,7 +25,7 @@ public class UpdateColumnIncrement<T, A> implements UpdateColumn {
} }
public Query<T> by(A y) { public Query<T> by(A y) {
query.addDeclarationToken(this); query.addUpdateColumnDeclaration(this);
this.y = y; this.y = y;
return query; return query;
} }
......
...@@ -25,7 +25,7 @@ public class UpdateColumnSet<T, A> implements UpdateColumn { ...@@ -25,7 +25,7 @@ public class UpdateColumnSet<T, A> implements UpdateColumn {
} }
public Query<T> to(A y) { public Query<T> to(A y) {
query.addDeclarationToken(this); query.addUpdateColumnDeclaration(this);
this.y = y; this.y = y;
return query; return query;
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论