/src/java/com/googlecode/axolotl/jdbc/GrailsDomainSqlFactory.java
Java | 467 lines | 319 code | 95 blank | 53 comment | 48 complexity | 8fd8dcfb507f86fd93ea265f31eddb02 MD5 | raw file
- /*
- * Axolotl - Alternate persistence for Grails
- * Copyright (C) 2008 Juanjo Garc?a Latre
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
- package com.googlecode.axolotl.jdbc;
- import java.sql.ResultSet;
- import java.sql.SQLException;
- import java.sql.Types;
- import java.util.ArrayList;
- import java.util.Date;
- import java.util.List;
- import java.util.Map;
- import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler;
- import org.codehaus.groovy.grails.commons.GrailsApplication;
- import org.codehaus.groovy.grails.commons.GrailsDomainClass;
- import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty;
- import org.codehaus.groovy.grails.plugins.support.aware.GrailsApplicationAware;
- import org.springframework.beans.BeanWrapper;
- import org.springframework.beans.BeanWrapperImpl;
- import org.springframework.jdbc.core.PreparedStatementCreator;
- import org.springframework.jdbc.core.PreparedStatementCreatorFactory;
- import org.springframework.jdbc.core.RowMapper;
- import org.springframework.jdbc.core.SqlTypeValue;
- import org.springframework.util.CachingMapDecorator;
- import com.googlecode.axolotl.Database;
- import com.googlecode.axolotl.grails.GrailsDomainUtils;
- import com.googlecode.axolotl.lazy.LazyEntity;
- import com.googlecode.axolotl.lazy.LazyEntitySet;
- import com.googlecode.axolotl.query.Criterion;
- import com.googlecode.axolotl.query.Equals;
- import com.googlecode.axolotl.query.Order;
- import com.googlecode.axolotl.query.Query;
- public class GrailsDomainSqlFactory implements SqlFactory, GrailsApplicationAware {
- private GrailsApplication application;
-
- private Map convertersCache = new CachingMapDecorator() {
- protected Object create(Object clazz) {
- return new GrailsDomainConverter((Class) clazz);
- }
- };
-
-
- public void setGrailsApplication(GrailsApplication application) {
- this.application = application;
- }
-
-
- public String getTableName(Class clazz) {
- GrailsDomainClass domainClass = getDomainClass(clazz);
- return getTableName(domainClass);
- }
-
-
- public String getColumnName(Class clazz, String property) {
- GrailsDomainClass domainClass = getDomainClass(clazz);
- return getColumnName( domainClass.getPropertyByName(property) );
- }
-
-
- public String getSelectRow(Class clazz) {
- GrailsDomainClass domainClass = getDomainClass(clazz);
-
- StringBuilder sql = new StringBuilder("select ")
- .append( getColumnName(domainClass.getIdentifier()) );
- GrailsDomainClassProperty[] properties = getPersistentProperties(domainClass);
- for (int i = 0 ; i < properties.length ; i++) {
- sql.append(",").append( getColumnName(properties[i]) );
- }
- sql.append(" from ").append( getTableName(domainClass) )
- .append(" where ").append( getColumnName( domainClass.getIdentifier() ) ).append("=?");
- return sql.toString();
- }
-
- public String getSelectCount(Class clazz, Object criteria) {
- GrailsDomainClass domainClass = getDomainClass(clazz);
- GrailsDomainSqlCriteriaBuilder criteriaBuilder =
- new GrailsDomainSqlCriteriaBuilder(application, domainClass, this);
- CharSequence where = buildWhere(criteriaBuilder, criteria);
- StringBuilder sql = new StringBuilder(512);
- sql.append("select count(distinct ");
- sql.append( getTableName(domainClass) )
- .append('.').append( getColumnName( domainClass.getIdentifier() ) );
- sql.append(") from ").append( buildFrom(domainClass, criteriaBuilder) );
- if (where.length() > 0) {
- sql.append(" where ").append(where);
- }
- return sql.toString();
- }
-
- public String getSelectIds(Class clazz, Object criteria, Object order) {
- GrailsDomainClass domainClass = getDomainClass(clazz);
- GrailsDomainSqlCriteriaBuilder criteriaBuilder =
- new GrailsDomainSqlCriteriaBuilder(application, domainClass, this);
- CharSequence orderBy = buildOrderBy(domainClass, criteriaBuilder, order);
- CharSequence where = buildWhere(criteriaBuilder, criteria);
- StringBuilder sql = new StringBuilder(512);
- sql.append("select ");
- if (criteriaBuilder.needsDistinct()) {
- sql.append("distinct ");
- }
- sql.append( getTableName(domainClass) )
- .append('.').append( getColumnName( domainClass.getIdentifier() ) );
- if (criteriaBuilder.needsDistinct()) {
- for (String o: criteriaBuilder.getOrders()) {
- sql.append(", ").append(o);
- }
- }
- sql.append(" from ").append( buildFrom(domainClass, criteriaBuilder) );
- if (where.length() > 0) {
- sql.append(" where ").append(where);
- }
- if (orderBy.length() > 0) {
- sql.append(" order by ").append(orderBy);
- }
- return sql.toString();
- }
-
- public String getInsertRow(Class clazz) {
- GrailsDomainClass domainClass = getDomainClass(clazz);
- GrailsDomainClassProperty[] properties = getPersistentProperties(domainClass);
-
- StringBuilder sql = new StringBuilder()
- .append("insert into ").append( getTableName(domainClass) )
- .append(" (");
- for (int i = 0 ; i < properties.length ; i++) {
- sql.append(i==0 ? "" : ",").append( getColumnName(properties[i]) );
- }
-
- sql.append(") values (");
-
- for (int i = 0 ; i < properties.length ; i++) {
- sql.append(i==0 ? "" : ",").append('?');
- }
-
- sql.append(")");
- return sql.toString();
- }
-
-
- public String getUpdateRow(Class clazz) {
- GrailsDomainClass domainClass = getDomainClass(clazz);
- StringBuilder sql = new StringBuilder()
- .append("update ").append( getTableName(domainClass) )
- .append(" set ");
-
- GrailsDomainClassProperty[] properties = getPersistentProperties(domainClass);
- for (int i = 0; i < properties.length; i++) {
- sql.append( i==0 ? "" : "," );
- sql.append( getColumnName(properties[i]) ).append("=?");
- }
- sql.append(" where ").append( getColumnName( domainClass.getIdentifier() ) ).append("=?");
- return sql.toString();
- }
-
-
- public String getDeleteRow(Class clazz) {
- GrailsDomainClass domainClass = getDomainClass(clazz);
- StringBuilder sql = new StringBuilder()
- .append("delete from ").append( getTableName(domainClass) )
- .append(" where ").append( getColumnName( domainClass.getIdentifier() ) ).append("=?");
- return sql.toString();
- }
- public Converter getConverter(Class clazz) {
- return (Converter) convertersCache.get(clazz);
- }
- //-------------------------------------------------------------------------------------------
-
- protected class GrailsDomainConverter implements Converter {
-
- private final GrailsDomainClass domainClass;
- private final String identifierColumn;
- private final PreparedStatementCreatorFactory preparedInsertCreatorFactory;
- private final PreparedStatementCreatorFactory preparedUpdateCreatorFactory;
- private final PreparedStatementCreatorFactory preparedDeleteCreatorFactory;
- private Class[] subclasses;
-
- public GrailsDomainConverter(Class clazz) {
- this.domainClass = getDomainClass(clazz);
- this.identifierColumn = getColumnName( domainClass.getIdentifier() );
-
- this.preparedInsertCreatorFactory =
- new PreparedStatementCreatorFactory( getInsertRow(clazz), getPersistentTypes(domainClass) );
- this.preparedUpdateCreatorFactory =
- new PreparedStatementCreatorFactory( getUpdateRow(clazz), getPersistentTypesWithId(domainClass) );
- this.preparedDeleteCreatorFactory =
- new PreparedStatementCreatorFactory( getDeleteRow(clazz), new int[] {getPersistentType(domainClass.getIdentifier())} );
- }
-
-
- public Class[] getSubClasses() {
- if (subclasses == null) {
- if (domainClass.hasSubClasses()) {
- List subDomainClasses = new ArrayList( domainClass.getSubClasses() );
- subclasses = new Class[ subDomainClasses.size() ];
- for (int i = 0; i < subDomainClasses.size(); i++) {
- subclasses[ i ] = ((GrailsDomainClass) subDomainClasses.get(i)).getClazz();
- }
- }
- else {
- subclasses = new Class[0];
- }
- }
- return subclasses;
- }
-
- public RowMapper getEntityReader(final Database database) {
- return new RowMapper() {
- public Object mapRow(ResultSet rs, int row) throws SQLException {
- BeanWrapper instance = new BeanWrapperImpl( domainClass.getClazz() );
- final Object id = rs.getObject(identifierColumn);
- instance.setPropertyValue(domainClass.getIdentifier().getName(), id);
- for (GrailsDomainClassProperty property: domainClass.getPersistentProperties()) {
- Object value = null;
- final Class refType = property.getReferencedPropertyType();
- if (!property.isOneToMany() && !property.isManyToMany()) {
- String columnName = getColumnName(property);
- value = rs.getObject(columnName);
- if (property.isManyToOne() || property.isOneToOne()) {
- if (property.getFetchMode() == GrailsDomainClassProperty.FETCH_LAZY) {
- value = LazyEntity.create(refType, value, database);
- }
- else if (property.getFetchMode() == GrailsDomainClassProperty.FETCH_EAGER) {
- value = database.load(refType, value);
- }
- }
- }
- else if (property.isOneToMany()) {
- String keyName = property.getOtherSide().getName();
- Object keyValue = instance.getWrappedInstance();
- Query query = new Query(refType, new Equals<Object>(keyName, keyValue), null);
- value = new LazyEntitySet(query, database);
- }
- instance.setPropertyValue(property.getName(), value);
- }
- return instance.getWrappedInstance();
- }
- };
- }
- public RowMapper getIdReader() {
- return new RowMapper() {
- public Object mapRow(ResultSet rs, int row) throws SQLException {
- return rs.getObject(1); //identifierColumn); TODO?
- }
- };
- }
-
-
- public PreparedStatementCreator getInsertStatementCreator(Object entity) {
- List values = GrailsDomainUtils.getPersistentValues(domainClass, entity);
- return preparedInsertCreatorFactory.newPreparedStatementCreator(values);
- }
-
-
- public PreparedStatementCreator getUpdateStatementCreator(Object entity) {
- List values = GrailsDomainUtils.getPersistentValues(domainClass, entity);
- values.add( GrailsDomainUtils.getIdentifierValue(domainClass, entity) );
- return preparedUpdateCreatorFactory.newPreparedStatementCreator(values);
- }
-
-
- public PreparedStatementCreator getDeleteStatementCreator(Object entity) {
- Object id = GrailsDomainUtils.getIdentifierValue(domainClass, entity);
- return preparedDeleteCreatorFactory.newPreparedStatementCreator( new Object[] {id} );
- }
-
- // private List getPersistentValues(Object entity) {
- // BeanWrapper wrapper = (entity instanceof BeanWrapper) ? (BeanWrapper) entity : new BeanWrapperImpl(entity);
- // List<Object> values = new ArrayList<Object>();
- // for (GrailsDomainClassProperty property : getPersistentProperties(domainClass)) {
- // Object value = wrapper.getPropertyValue( property.getName() );
- // if ((property.isManyToOne() || property.isOneToOne()) && value != null) {
- // if (LazyEntity.isLazy(value)) {
- // value = LazyEntity.getId(value);
- // }
- // else {
- // value = GrailsDomainUtils.getIdentifierValue(
- // property.getReferencedDomainClass(), value);
- // }
- // }
- // values.add(value);
- // }
- // return values;
- // }
- }
-
-
- protected String getTableName(GrailsDomainClass domainClass) {
- return SqlNamingUtils.getTableName(domainClass);
- // return underscorize( domainClass.getName() );
- }
-
-
- protected String[] getColumnNames(GrailsDomainClassProperty[] properties) {
- String[] columnNames = new String[ properties.length ];
- for (int i = 0; i < columnNames.length; i++) {
- columnNames[i] = getColumnName( properties[i] );
- }
- return columnNames;
- }
-
- protected String getColumnName(GrailsDomainClassProperty property) {
- return SqlNamingUtils.getColumnName(property);
- // StringBuilder name = new StringBuilder( underscorize(property.getName()) );
- // if (property.isManyToOne() || property.isOneToOne()) {
- // name.append("_id");
- // }
- // return name.toString();
- }
-
- @Deprecated
- protected GrailsDomainClass getDomainClass(Class clazz) {
- return (GrailsDomainClass) application.getArtefact(DomainClassArtefactHandler.TYPE, clazz.getName());
- }
-
-
- @Deprecated
- protected GrailsDomainClassProperty[] getPersistentProperties(GrailsDomainClass domainClass) {
- return GrailsDomainUtils.getPersistentProperties(domainClass);
- // List<GrailsDomainClassProperty> properties = new ArrayList<GrailsDomainClassProperty>();
- // for (GrailsDomainClassProperty property: domainClass.getPersistentProperties()) {
- // if (!property.isOneToMany() && !property.isManyToMany()) {
- // properties.add(property);
- // }
- // }
- // return properties.toArray(new GrailsDomainClassProperty[properties.size()]);
- }
-
-
- protected int[] getPersistentTypes(GrailsDomainClass domainClass) {
- GrailsDomainClassProperty[] properties = getPersistentProperties(domainClass);
- int[] types = new int[ properties.length ];
- for (int i = 0; i < properties.length; i++) {
- types[ i ] = getPersistentType( properties[ i ] );
- }
- return types;
- }
-
-
- protected int[] getPersistentTypesWithId(GrailsDomainClass domainClass) {
- int[] persistentTypes = getPersistentTypes(domainClass);
- int[] typesWithId = new int[ persistentTypes.length + 1 ];
- System.arraycopy(persistentTypes, 0, typesWithId, 0, persistentTypes.length);
- typesWithId[ typesWithId.length - 1 ] = getPersistentType( domainClass.getIdentifier() );
- return typesWithId;
- }
-
-
- protected int getPersistentType(GrailsDomainClassProperty property) {
- Class type = property.getType();
- if (Number.class.isAssignableFrom(type)) {
- return Types.NUMERIC;
- }
- else if (CharSequence.class.isAssignableFrom(type)) {
- return Types.VARCHAR;
- }
- else if (Date.class.isAssignableFrom(type)) {
- return Types.TIMESTAMP;
- }
- else {
- return SqlTypeValue.TYPE_UNKNOWN;
- }
- }
-
-
- private CharSequence buildFrom(GrailsDomainClass domainClass, GrailsDomainSqlCriteriaBuilder criteriaBuilder) {
- StringBuilder from = new StringBuilder( getTableName(domainClass) );
- // append join tables found by criteria builder.
- for (GrailsDomainSqlCriteriaBuilder.JoinInfo join: criteriaBuilder.getJoins()) {
- from.append(", ").append( join.getTable() );
- }
- return from;
- }
-
-
- private CharSequence buildWhere(GrailsDomainSqlCriteriaBuilder criteriaBuilder, Object criteria) {
- String filter = "";
- if (criteria instanceof Criterion) {
- filter = ((Criterion) criteria).accept(criteriaBuilder);
- }
- else if (criteria != null) {
- filter = criteria.toString();
- }
- StringBuilder where = new StringBuilder();
- // append join criteria found by renderer.
- for (GrailsDomainSqlCriteriaBuilder.JoinInfo join: criteriaBuilder.getJoins()) {
- if (where.length() > 0) {
- where.append(" and ");
- }
- where.append( join.getCriterion() );
- }
- // if there was a previous filter, then it should be appended after join criteria.
- if (filter.length() > 0) {
- if (where.length() > 0) {
- where.append(" and ");
- }
- where.append(filter);
- }
- return where;
- }
- private CharSequence buildOrderBy(GrailsDomainClass domainClass,
- GrailsDomainSqlCriteriaBuilder criteriaBuilder, Object order) {
-
- StringBuilder orderBy = new StringBuilder();
- final Object o = order;//(order == null ? domainClass.getDefaultOrder() : order);
- if (o instanceof Order) {
- orderBy.append( ((Order) o).accept(criteriaBuilder) );
- }
- else if (o != null) {
- orderBy.append(o);
- }
- return orderBy;
- }
-
- }