This is an automated email from the ASF dual-hosted git repository. borinquenkid pushed a commit to branch 8.0.x-hibernate7-dev in repository https://gitbox.apache.org/repos/asf/grails-core.git
commit bab38a15c9bff53b28d3126460e6509394e5434b Author: Walter Duque de Estrada <[email protected]> AuthorDate: Wed Mar 4 14:25:14 2026 -0600 refactor(hibernate7): replace HibernateDatastore.FlushMode with org.hibernate.FlushMode --- .../orm/hibernate/GrailsHibernateTemplate.java | 18 ++- .../grails/orm/hibernate/HibernateDatastore.java | 126 ++++++--------------- .../orm/hibernate/HibernateGormStaticApi.groovy | 5 +- .../org/grails/orm/hibernate/HibernateSession.java | 6 +- .../orm/hibernate/SchemaTenantDataSource.groovy | 57 ++++++++++ .../HibernateDatastoreIntegrationSpec.groovy | 30 ++--- .../hibernate/SchemaTenantDataSourceSpec.groovy | 78 +++++++++++++ 7 files changed, 200 insertions(+), 120 deletions(-) diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/GrailsHibernateTemplate.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/GrailsHibernateTemplate.java index 474982d0d8..41abd6a36b 100644 --- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/GrailsHibernateTemplate.java +++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/GrailsHibernateTemplate.java @@ -112,7 +112,13 @@ public class GrailsHibernateTemplate implements IHibernateTemplate { } public GrailsHibernateTemplate(SessionFactory sessionFactory, HibernateDatastore datastore) { - this(sessionFactory, datastore, datastore.getDefaultFlushMode()); + this(sessionFactory); + if (datastore != null) { + cacheQueries = datastore.isCacheQueries(); + this.osivReadOnly = datastore.isOsivReadOnly(); + this.passReadOnlyToHibernate = datastore.isPassReadOnlyToHibernate(); + this.flushMode = hibernateFlushModeToConstant(datastore.getDefaultFlushMode()); + } } public GrailsHibernateTemplate( @@ -126,6 +132,16 @@ public class GrailsHibernateTemplate implements IHibernateTemplate { this.flushMode = defaultFlushMode; } + /** Maps a Hibernate {@link FlushMode} to one of the {@code FLUSH_*} constants of this class. */ + static int hibernateFlushModeToConstant(FlushMode mode) { + switch (mode) { + case MANUAL: return FLUSH_NEVER; + case COMMIT: return FLUSH_COMMIT; + case ALWAYS: return FLUSH_ALWAYS; + default: return FLUSH_AUTO; + } + } + @Override public <T> T execute(Closure<T> callable) { HibernateCallback<T> hibernateCallback = diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateDatastore.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateDatastore.java index 8c76d7909d..f82c3bf47f 100644 --- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateDatastore.java +++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateDatastore.java @@ -34,8 +34,6 @@ import org.grails.datastore.gorm.events.AutoTimestampEventListener; import org.grails.datastore.gorm.events.ConfigurableApplicationContextEventPublisher; import org.grails.datastore.gorm.events.ConfigurableApplicationEventPublisher; import org.grails.datastore.gorm.events.DefaultApplicationEventPublisher; -import org.grails.datastore.gorm.jdbc.MultiTenantConnection; -import org.grails.datastore.gorm.jdbc.MultiTenantDataSource; import org.grails.datastore.gorm.jdbc.connections.DataSourceConnectionSource; import org.grails.datastore.gorm.jdbc.connections.DataSourceConnectionSourceFactory; import org.grails.datastore.gorm.jdbc.connections.DataSourceSettings; @@ -76,9 +74,9 @@ import org.grails.orm.hibernate.connections.HibernateConnectionSourceFactory; import org.grails.orm.hibernate.query.HibernateQueryArgument; import org.grails.orm.hibernate.connections.HibernateConnectionSourceSettings; import org.grails.orm.hibernate.event.listener.HibernateEventListener; -import org.grails.orm.hibernate.event.listener.HibernateEventListener; import org.grails.orm.hibernate.multitenancy.MultiTenantEventListener; import org.grails.orm.hibernate.support.ClosureEventTriggeringInterceptor; +import org.hibernate.FlushMode; import org.hibernate.SessionFactory; import org.hibernate.boot.Metadata; import org.hibernate.cfg.Environment; @@ -139,8 +137,8 @@ public class HibernateDatastore extends AbstractDatastore protected final ConnectionSources<SessionFactory, HibernateConnectionSourceSettings> connectionSources; - /** The default flush mode name. */ - protected final String defaultFlushModeName; + /** The default flush mode. */ + protected final FlushMode defaultFlushMode; /** The multi tenant mode. */ protected final MultiTenancySettings.MultiTenancyMode multiTenantMode; @@ -163,9 +161,6 @@ public class HibernateDatastore extends AbstractDatastore /** The is cache queries. */ protected final boolean isCacheQueries; - /** The default flush mode. */ - protected final int defaultFlushMode; - /** The fail on error. */ protected final boolean failOnError; @@ -211,10 +206,8 @@ public class HibernateDatastore extends AbstractDatastore this.isCacheQueries = hibernateSettings.getCache().isQueries(); this.failOnError = settings.isFailOnError(); Boolean markDirty = settings.getMarkDirty(); - this.markDirty = markDirty == null ? false : markDirty; - FlushMode flushMode = FlushMode.valueOf(hibernateSettings.getFlush().getMode().name()); - this.defaultFlushModeName = flushMode.name(); - this.defaultFlushMode = flushMode.getLevel(); + this.markDirty = markDirty != null && markDirty; + this.defaultFlushMode = FlushMode.valueOf(hibernateSettings.getFlush().getMode().name()); MultiTenancySettings multiTenancySettings = settings.getMultiTenancy(); final TenantResolver multiTenantResolver = multiTenancySettings.getTenantResolver(); this.multiTenantMode = multiTenancySettings.getMode(); @@ -231,17 +224,17 @@ public class HibernateDatastore extends AbstractDatastore new GrailsHibernateTransactionManager( defaultConnectionSource.getSource(), defaultConnectionSource.getDataSource(), - org.hibernate.FlushMode.valueOf(defaultFlushModeName)); + defaultFlushMode); this.eventPublisher = eventPublisher; this.eventTriggeringInterceptor = new HibernateEventListener(this); this.autoTimestampEventListener = new AutoTimestampEventListener(this); ClosureEventTriggeringInterceptor interceptor = - (ClosureEventTriggeringInterceptor) hibernateSettings.getEventTriggeringInterceptor(); + hibernateSettings.getEventTriggeringInterceptor(); interceptor.setDatastore(this); interceptor.setEventPublisher(eventPublisher); registerEventListeners(this.eventPublisher); - configureValidatorRegistry(settings, mappingContext); + configureValidatorRegistry(mappingContext); this.mappingContext.addMappingContextListener( new MappingContext.Listener() { @Override @@ -547,12 +540,9 @@ public class HibernateDatastore extends AbstractDatastore config.getProperty(HibernateQueryArgument.CONFIG_CACHE_QUERIES.value(), Boolean.class, false); if (config.getProperty(SETTING_AUTO_FLUSH, Boolean.class, false)) { - this.defaultFlushModeName = FlushMode.AUTO.name(); - this.defaultFlushMode = FlushMode.AUTO.level; + this.defaultFlushMode = FlushMode.AUTO; } else { - FlushMode fm = config.getProperty(SETTING_FLUSH_MODE, FlushMode.class, FlushMode.COMMIT); - this.defaultFlushModeName = fm.name(); - this.defaultFlushMode = fm.level; + this.defaultFlushMode = config.getProperty(SETTING_FLUSH_MODE, FlushMode.class, FlushMode.COMMIT); } this.failOnError = config.getProperty(SETTING_FAIL_ON_ERROR, Boolean.class, false); this.markDirty = config.getProperty(SETTING_MARK_DIRTY, Boolean.class, false); @@ -624,9 +614,7 @@ public class HibernateDatastore extends AbstractDatastore public void setMessageSource(MessageSource messageSource) { HibernateMappingContext mappingContext = getMappingContext(); ValidatorRegistry validatorRegistry = createValidatorRegistry(messageSource); - HibernateConnectionSourceSettings settings = - getConnectionSources().getDefaultConnectionSource().getSettings(); - configureValidatorRegistry(settings, mappingContext, validatorRegistry, messageSource); + configureValidatorRegistry(mappingContext, validatorRegistry, messageSource); } protected void registerEventListeners(ConfigurableApplicationEventPublisher eventPublisher) { @@ -638,14 +626,13 @@ public class HibernateDatastore extends AbstractDatastore } protected void configureValidatorRegistry( - HibernateConnectionSourceSettings settings, HibernateMappingContext mappingContext) { + HibernateMappingContext mappingContext) { StaticMessageSource messageSource = new StaticMessageSource(); ValidatorRegistry defaultValidatorRegistry = createValidatorRegistry(messageSource); - configureValidatorRegistry(settings, mappingContext, defaultValidatorRegistry, messageSource); + configureValidatorRegistry(mappingContext, defaultValidatorRegistry, messageSource); } protected void configureValidatorRegistry( - HibernateConnectionSourceSettings settings, HibernateMappingContext mappingContext, ValidatorRegistry validatorRegistry, MessageSource messageSource) { @@ -726,15 +713,14 @@ public class HibernateDatastore extends AbstractDatastore HibernateConnectionSourceSettings.HibernateSettings hibernateSettings = settings.getHibernate(); ClosureEventTriggeringInterceptor interceptor = - (ClosureEventTriggeringInterceptor) hibernateSettings.getEventTriggeringInterceptor(); + hibernateSettings.getEventTriggeringInterceptor(); interceptor.setDatastore(this); interceptor.setEventPublisher(eventPublisher); - MappingContext mappingContext = getMappingContext(); + HibernateMappingContext mappingContext = getMappingContext(); // make messages from the application context available to validation ValidatorRegistry validatorRegistry = createValidatorRegistry(applicationContext); configureValidatorRegistry( - settings, - (HibernateMappingContext) mappingContext, + mappingContext, validatorRegistry, applicationContext); mappingContext.setValidatorRegistry(validatorRegistry); @@ -755,7 +741,7 @@ public class HibernateDatastore extends AbstractDatastore try { if (session != null) { previousMode = session.getHibernateFlushMode(); - session.setHibernateFlushMode(org.hibernate.FlushMode.valueOf(flushMode.name())); + session.setHibernateFlushMode(flushMode); } try { reset = callable.call(); @@ -771,7 +757,7 @@ public class HibernateDatastore extends AbstractDatastore public org.hibernate.Session openSession() { org.hibernate.Session session = this.sessionFactory.openSession(); - session.setHibernateFlushMode(org.hibernate.FlushMode.valueOf(defaultFlushModeName)); + session.setHibernateFlushMode(defaultFlushMode); return session; } @@ -779,7 +765,7 @@ public class HibernateDatastore extends AbstractDatastore public Session getCurrentSession() throws ConnectionNotFoundException { // HibernateSession, just a thin wrapper around default session handling so simply return a new // instance here - return new HibernateSession(this, sessionFactory, getDefaultFlushMode()); + return new HibernateSession(this, sessionFactory); } @Override @@ -818,9 +804,8 @@ public class HibernateDatastore extends AbstractDatastore dataSource = ((TransactionAwareDataSourceProxy) dataSource).getTargetDataSource(); } Object existing = TransactionSynchronizationManager.getResource(dataSource); - if (existing instanceof ConnectionHolder) { - ConnectionHolder connectionHolder = (ConnectionHolder) existing; - Connection connection = connectionHolder.getConnection(); + if (existing instanceof ConnectionHolder connectionHolder) { + Connection connection = connectionHolder.getConnection(); try { if (!connection.isClosed() && !connection.isReadOnly()) { schemaHandler.useDefaultSchema(connection); @@ -855,8 +840,8 @@ public class HibernateDatastore extends AbstractDatastore HibernateConnectionSourceSettings tenantSettings; try { tenantSettings = - (HibernateConnectionSourceSettings) - connectionSources.getDefaultConnectionSource().getSettings().clone(); + (HibernateConnectionSourceSettings) + connectionSources.getDefaultConnectionSource().getSettings().clone(); } catch (CloneNotSupportedException e) { throw new ConfigurationException( "Couldn't clone default Hibernate settings! " + e.getMessage(), e); @@ -894,22 +879,7 @@ public class HibernateDatastore extends AbstractDatastore } DataSource dataSource = defaultConnectionSource.getDataSource(); - dataSource = - new MultiTenantDataSource(dataSource, schemaName) { - @Override - public Connection getConnection() throws SQLException { - Connection connection = super.getConnection(); - schemaHandler.useSchema(connection, schemaName); - return new MultiTenantConnection(connection, schemaHandler); - } - - @Override - public Connection getConnection(String username, String password) throws SQLException { - Connection connection = super.getConnection(username, password); - schemaHandler.useSchema(connection, schemaName); - return new MultiTenantConnection(connection, schemaHandler); - } - }; + dataSource = new SchemaTenantDataSource(dataSource, schemaName, schemaHandler); DefaultConnectionSource<DataSource, DataSourceSettings> dataSourceConnectionSource = new DefaultConnectionSource<>(schemaName, dataSource, tenantSettings.getDataSource()); ConnectionSource<SessionFactory, HibernateConnectionSourceSettings> connectionSource = @@ -1023,13 +993,13 @@ public class HibernateDatastore extends AbstractDatastore /** Returns whether auto flush. */ public boolean isAutoFlush() { - return defaultFlushMode == FlushMode.AUTO.level; + return defaultFlushMode == FlushMode.AUTO; } /** - * @return Obtains the default flush mode level + * @return The default flush mode */ - public int getDefaultFlushMode() { + public FlushMode getDefaultFlushMode() { return defaultFlushMode; } @@ -1037,7 +1007,7 @@ public class HibernateDatastore extends AbstractDatastore * @return The name of the default flush mode */ public String getDefaultFlushModeName() { - return defaultFlushModeName; + return defaultFlushMode.name(); } /** Returns whether fail on error. */ @@ -1096,7 +1066,7 @@ public class HibernateDatastore extends AbstractDatastore /** Gets the hibernate template using the default flush mode. */ public IHibernateTemplate getHibernateTemplate() { - return getHibernateTemplate(defaultFlushMode); + return new GrailsHibernateTemplate(getSessionFactory(), this); } @Override @@ -1151,17 +1121,17 @@ public class HibernateDatastore extends AbstractDatastore final boolean isMultiTenant = getMultiTenancyMode() == MultiTenancySettings.MultiTenancyMode.DISCRIMINATOR; return isMultiTenant - ? new Closure<T>(this) { - @Override - public T call(Object... args) { + ? new Closure<>(this) { + @Override + public T call(Object... args) { enableMultiTenancyFilter(); try { - return callable.call(args); + return callable.call(args); } finally { - disableMultiTenancyFilter(); + disableMultiTenancyFilter(); } - } } + } : callable; } @@ -1175,30 +1145,4 @@ public class HibernateDatastore extends AbstractDatastore } } - /** - * We use a separate enum here because the classes differ between Hibernate 3 and 4 - * - * @see org.hibernate.FlushMode - */ - public enum FlushMode { - /** The manual constant. */ - MANUAL(0), - /** The commit constant. */ - COMMIT(5), - /** The auto constant. */ - AUTO(10), - /** The always constant. */ - ALWAYS(20); - - private final int level; - - FlushMode(int level) { - this.level = level; - } - - /** Gets the level. */ - public int getLevel() { - return level; - } - } } diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateGormStaticApi.groovy b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateGormStaticApi.groovy index 69e3fb41f0..2ac3406a78 100644 --- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateGormStaticApi.groovy +++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateGormStaticApi.groovy @@ -69,7 +69,6 @@ class HibernateGormStaticApi<D> extends GormStaticApi<D> { protected Class identityType protected ClassLoader classLoader private HibernateGormInstanceApi<D> instanceApi - private int defaultFlushMode HibernateGormStaticApi(Class<D> persistentClass, HibernateDatastore datastore, List<FinderMethod> finders, ClassLoader classLoader, PlatformTransactionManager transactionManager) { @@ -79,13 +78,11 @@ class HibernateGormStaticApi<D> extends GormStaticApi<D> { this.proxyHandler = datastore.mappingContext.proxyHandler this.hibernateSession = new HibernateSession( (HibernateDatastore)datastore, - hibernateTemplate.getSessionFactory(), - hibernateTemplate.getFlushMode() + hibernateTemplate.getSessionFactory() ) this.classLoader = classLoader this.sessionFactory = datastore.getSessionFactory() this.identityType = persistentEntity.identity?.type - this.defaultFlushMode = datastore.getDefaultFlushMode() this.instanceApi = new HibernateGormInstanceApi<>(persistentClass, datastore, classLoader) } diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateSession.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateSession.java index 32f36b2a71..2c17bb95d4 100644 --- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateSession.java +++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateSession.java @@ -79,16 +79,12 @@ public class HibernateSession extends AbstractAttributeStoringSession DefaultTimestampProvider timestampProvider; public HibernateSession( - HibernateDatastore hibernateDatastore, SessionFactory sessionFactory, int defaultFlushMode) { + HibernateDatastore hibernateDatastore, SessionFactory sessionFactory) { datastore = hibernateDatastore; hibernateTemplate = new GrailsHibernateTemplate(sessionFactory, (HibernateDatastore) getDatastore()); } - public HibernateSession(HibernateDatastore hibernateDatastore, SessionFactory sessionFactory) { - this(hibernateDatastore, sessionFactory, hibernateDatastore.getDefaultFlushMode()); - } - @Override public boolean isSchemaless() { return false; diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/SchemaTenantDataSource.groovy b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/SchemaTenantDataSource.groovy new file mode 100644 index 0000000000..398c9289b7 --- /dev/null +++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/SchemaTenantDataSource.groovy @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.grails.orm.hibernate + +import java.sql.Connection + +import groovy.transform.CompileStatic +import javax.sql.DataSource +import org.grails.datastore.gorm.jdbc.MultiTenantConnection +import org.grails.datastore.gorm.jdbc.MultiTenantDataSource +import org.grails.datastore.gorm.jdbc.schema.SchemaHandler + +/** + * A {@link MultiTenantDataSource} that switches to a specific schema on every connection + * and wraps the returned connection in a {@link MultiTenantConnection} so that the schema + * is restored when the connection is closed. + */ +@CompileStatic +class SchemaTenantDataSource extends MultiTenantDataSource { + + private final SchemaHandler schemaHandler + + SchemaTenantDataSource(DataSource target, String schemaName, SchemaHandler schemaHandler) { + super(target, schemaName) + this.schemaHandler = schemaHandler + } + + @Override + Connection getConnection() { + Connection connection = super.getConnection() + schemaHandler.useSchema(connection, tenantId) + new MultiTenantConnection(connection, schemaHandler) + } + + @Override + Connection getConnection(String username, String password) { + Connection connection = super.getConnection(username, password) + schemaHandler.useSchema(connection, tenantId) + new MultiTenantConnection(connection, schemaHandler) + } +} diff --git a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/HibernateDatastoreIntegrationSpec.groovy b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/HibernateDatastoreIntegrationSpec.groovy index 16c57a3ecd..f46c53971a 100644 --- a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/HibernateDatastoreIntegrationSpec.groovy +++ b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/HibernateDatastoreIntegrationSpec.groovy @@ -23,6 +23,7 @@ import grails.gorm.hibernate.HibernateEntity import grails.gorm.specs.HibernateGormDatastoreSpec import org.grails.orm.hibernate.cfg.HibernateMappingContext import org.grails.orm.hibernate.event.listener.HibernateEventListener +import org.hibernate.FlushMode import org.springframework.transaction.support.TransactionSynchronizationManager import org.testcontainers.containers.PostgreSQLContainer import org.testcontainers.spock.Testcontainers @@ -116,10 +117,9 @@ class HibernateDatastoreIntegrationSpec extends HibernateGormDatastoreSpec { !datastore.autoFlush } - void "defaultFlushMode is COMMIT level by default"() { + void "defaultFlushMode is COMMIT by default"() { expect: - // HibernateDatastore.FlushMode.COMMIT.level == 5 - datastore.defaultFlushMode == HibernateDatastore.FlushMode.COMMIT.level + datastore.defaultFlushMode == FlushMode.COMMIT } void "defaultFlushModeName is COMMIT by default"() { @@ -148,24 +148,16 @@ class HibernateDatastoreIntegrationSpec extends HibernateGormDatastoreSpec { } // ------------------------------------------------------------------------- - // FlushMode enum (HibernateDatastore.FlushMode) + // FlushMode (org.hibernate.FlushMode) // ------------------------------------------------------------------------- - void "FlushMode enum levels are correctly ordered"() { - expect: - HibernateDatastore.FlushMode.MANUAL.level == 0 - HibernateDatastore.FlushMode.COMMIT.level == 5 - HibernateDatastore.FlushMode.AUTO.level == 10 - HibernateDatastore.FlushMode.ALWAYS.level == 20 - } - void "FlushMode enum values are all present"() { expect: - HibernateDatastore.FlushMode.values().size() == 4 - HibernateDatastore.FlushMode.valueOf('MANUAL') != null - HibernateDatastore.FlushMode.valueOf('COMMIT') != null - HibernateDatastore.FlushMode.valueOf('AUTO') != null - HibernateDatastore.FlushMode.valueOf('ALWAYS') != null + FlushMode.values().size() == 4 + FlushMode.valueOf('MANUAL') != null + FlushMode.valueOf('COMMIT') != null + FlushMode.valueOf('AUTO') != null + FlushMode.valueOf('ALWAYS') != null } // ------------------------------------------------------------------------- @@ -239,7 +231,7 @@ class HibernateDatastoreIntegrationSpec extends HibernateGormDatastoreSpec { when: DatastoreBook.withTransaction { - datastore.withFlushMode(HibernateDatastore.FlushMode.AUTO) { + datastore.withFlushMode(FlushMode.AUTO) { executed = true true } @@ -258,7 +250,7 @@ class HibernateDatastoreIntegrationSpec extends HibernateGormDatastoreSpec { def sess = sessionFactory.currentSession org.hibernate.FlushMode modeBefore = sess.hibernateFlushMode - datastore.withFlushMode(HibernateDatastore.FlushMode.ALWAYS) { true } + datastore.withFlushMode(FlushMode.ALWAYS) { true } modeAfter = sess.hibernateFlushMode } diff --git a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/SchemaTenantDataSourceSpec.groovy b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/SchemaTenantDataSourceSpec.groovy new file mode 100644 index 0000000000..6a08eb95e9 --- /dev/null +++ b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/SchemaTenantDataSourceSpec.groovy @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.grails.orm.hibernate + +import java.sql.Connection +import javax.sql.DataSource + +import spock.lang.Specification +import spock.lang.Subject + +import org.grails.datastore.gorm.jdbc.MultiTenantConnection +import org.grails.datastore.gorm.jdbc.schema.SchemaHandler + +class SchemaTenantDataSourceSpec extends Specification { + + static final String SCHEMA = 'tenant_schema' + + DataSource targetDataSource = Mock() + Connection rawConnection = Mock() + SchemaHandler schemaHandler = Mock() + + @Subject + SchemaTenantDataSource dataSource = new SchemaTenantDataSource(targetDataSource, SCHEMA, schemaHandler) + + def "getConnection() switches to the tenant schema and returns a MultiTenantConnection"() { + given: + targetDataSource.getConnection() >> rawConnection + + when: + Connection result = dataSource.getConnection() + + then: + 1 * schemaHandler.useSchema(rawConnection, SCHEMA) + result instanceof MultiTenantConnection + (result as MultiTenantConnection).target == rawConnection + (result as MultiTenantConnection).schemaHandler == schemaHandler + } + + def "getConnection(username, password) switches to the tenant schema and returns a MultiTenantConnection"() { + given: + targetDataSource.getConnection('user', 'pass') >> rawConnection + + when: + Connection result = dataSource.getConnection('user', 'pass') + + then: + 1 * schemaHandler.useSchema(rawConnection, SCHEMA) + result instanceof MultiTenantConnection + (result as MultiTenantConnection).target == rawConnection + (result as MultiTenantConnection).schemaHandler == schemaHandler + } + + def "tenantId is stored correctly"() { + expect: + dataSource.tenantId == SCHEMA + } + + def "target DataSource is stored correctly"() { + expect: + dataSource.target == targetDataSource + } +}
