diff --git a/src/java/com/samskivert/jdbc/depot/Computed.java b/src/java/com/samskivert/jdbc/depot/Computed.java new file mode 100644 index 0000000..c6fb193 --- /dev/null +++ b/src/java/com/samskivert/jdbc/depot/Computed.java @@ -0,0 +1,31 @@ +// +// $Id$ +// +// samskivert library - useful routines for java programs +// Copyright (C) 2006 Michael Bayne +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.samskivert.jdbc.depot; + +/** + * Marks a field as computed, meaning it's ignored for schema purposes, it does not directly + * correspond to a column in a table, and thus its value must be overridden in the {@link Query}. + * + * TODO: Add fieldDefinition="count (*)" or somesuch. + */ +public @interface Computed +{ +} diff --git a/src/java/com/samskivert/jdbc/depot/DepotMarshaller.java b/src/java/com/samskivert/jdbc/depot/DepotMarshaller.java index 310d613..dcc37b8 100644 --- a/src/java/com/samskivert/jdbc/depot/DepotMarshaller.java +++ b/src/java/com/samskivert/jdbc/depot/DepotMarshaller.java @@ -172,11 +172,23 @@ public class DepotMarshaller // generate our full list of fields/columns for use in queries _allFields = fields.toArray(new String[fields.size()]); - // create the SQL used to create and migrate our table + // figure out the list of fields that correspond to actual table columns and create the SQL + // used to create and migrate our table + _columnFields = new String[_allFields.length]; _columnDefinitions = new String[_allFields.length]; + int jj = 0; for (int ii = 0; ii < _allFields.length; ii++) { - _columnDefinitions[ii] = _fields.get(_allFields[ii]).getColumnDefinition(); + // include all persistent non-computed fields + String colDef = _fields.get(_allFields[ii]).getColumnDefinition(); + if (colDef != null) { + _columnFields[jj] = _allFields[ii]; + _columnDefinitions[jj] = colDef; + jj ++; + } } + _columnFields = ArrayUtil.splice(_columnFields, jj); + _columnDefinitions = ArrayUtil.splice(_columnDefinitions, jj); + // add the primary key, if we have one if (hasPrimaryKey()) { String[] indices = new String[_pkColumns.size()]; @@ -306,7 +318,7 @@ public class DepotMarshaller columns.add(rs.getString("COLUMN_NAME")); } - for (String fname : _allFields) { + for (String fname : _columnFields) { FieldMarshaller fmarsh = _fields.get(fname); if (columns.contains(fmarsh.getColumnName())) { continue; @@ -372,9 +384,9 @@ public class DepotMarshaller try { StringBuilder insert = new StringBuilder(); insert.append("insert into ").append(getTableName()); - insert.append(" (").append(StringUtil.join(_allFields, ",")); + insert.append(" (").append(StringUtil.join(_columnFields, ",")); insert.append(")").append(" values("); - for (int ii = 0; ii < _allFields.length; ii++) { + for (int ii = 0; ii < _columnFields.length; ii++) { if (ii > 0) { insert.append(", "); } @@ -385,7 +397,7 @@ public class DepotMarshaller // TODO: handle primary key, nullable fields specially? PreparedStatement pstmt = conn.prepareStatement(insert.toString()); int idx = 0; - for (String field : _allFields) { + for (String field : _columnFields) { _fields.get(field).setValue(po, pstmt, ++idx); } return pstmt; @@ -437,7 +449,7 @@ public class DepotMarshaller public PreparedStatement createUpdate (Connection conn, Object po, Key key) throws SQLException { - return createUpdate(conn, po, key, _allFields); + return createUpdate(conn, po, key, _columnFields); } /** @@ -599,6 +611,9 @@ public class DepotMarshaller /** The persisent fields of our object, in definition order. */ protected String[] _allFields; + /** The fields of our object with directly corresponding table columns. */ + protected String[] _columnFields; + /** The version of our persistent object schema as specified in the class * definition. */ protected int _schemaVersion = -1; diff --git a/src/java/com/samskivert/jdbc/depot/FieldMarshaller.java b/src/java/com/samskivert/jdbc/depot/FieldMarshaller.java index 9a14265..94587ea 100644 --- a/src/java/com/samskivert/jdbc/depot/FieldMarshaller.java +++ b/src/java/com/samskivert/jdbc/depot/FieldMarshaller.java @@ -172,6 +172,12 @@ public abstract class FieldMarshaller } } + // if this field is @Computed, it has no SQL definition + if (field.getAnnotation(Computed.class) != null) { + _columnDefinition = null; + return; + } + // create our SQL column definition StringBuilder builder = new StringBuilder(); if (column != null && !StringUtil.isBlank(column.columnDefinition())) { diff --git a/src/java/com/samskivert/jdbc/depot/Query.java b/src/java/com/samskivert/jdbc/depot/Query.java index b3ad4bc..1217493 100644 --- a/src/java/com/samskivert/jdbc/depot/Query.java +++ b/src/java/com/samskivert/jdbc/depot/Query.java @@ -91,7 +91,7 @@ public abstract class Query throw new RuntimeException("createQuery() called with _mainClass == null"); } - DepotMarshaller mainMarshaller = _classMap.get(_mainType); + DepotMarshaller mainMarshaller = _classMap.get(_mainType); String[] fields = mainMarshaller._allFields; StringBuilder query = new StringBuilder("select "); for (int ii = 0; ii < fields.length; ii ++) { @@ -101,8 +101,11 @@ public abstract class Query FieldOverrideClause clause = _disMap.get(fields[ii]); if (clause != null) { clause.appendClause(this, query); - } else { + } else if (mainMarshaller._fields.get(fields[ii]).getColumnDefinition() != null) { query.append("T.").append(fields[ii]); + } else { + throw new SQLException( + "Computed field must be overridden [field=" + fields[ii] + "]"); } } query.append(" from " + mainMarshaller.getTableName() + " as T "); diff --git a/src/java/com/samskivert/jdbc/depot/clause/FieldOverrideClause.java b/src/java/com/samskivert/jdbc/depot/clause/FieldOverrideClause.java index 2d0e345..02fe459 100644 --- a/src/java/com/samskivert/jdbc/depot/clause/FieldOverrideClause.java +++ b/src/java/com/samskivert/jdbc/depot/clause/FieldOverrideClause.java @@ -63,6 +63,7 @@ public class FieldOverrideClause public void appendClause (Query query, StringBuilder builder) { _override.appendExpression(query, builder); + builder.append(" as ").append(_field); } // from QueryClause