Skip to content

Commit 1396799

Browse files
authored
Explicitly forbid StatelessSession.upsert (#126)
HIBERNATE-97
1 parent 2411aa6 commit 1396799

File tree

2 files changed

+97
-0
lines changed

2 files changed

+97
-0
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright 2025-present MongoDB, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.mongodb.hibernate;
18+
19+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
20+
21+
import com.mongodb.hibernate.internal.FeatureNotSupportedException;
22+
import com.mongodb.hibernate.junit.MongoExtension;
23+
import jakarta.persistence.Entity;
24+
import jakarta.persistence.Id;
25+
import jakarta.persistence.Table;
26+
import org.hibernate.testing.orm.junit.DomainModel;
27+
import org.hibernate.testing.orm.junit.SessionFactory;
28+
import org.hibernate.testing.orm.junit.SessionFactoryScope;
29+
import org.hibernate.testing.orm.junit.SessionFactoryScopeAware;
30+
import org.junit.jupiter.api.Test;
31+
import org.junit.jupiter.api.extension.ExtendWith;
32+
33+
@SessionFactory(exportSchema = false)
34+
@DomainModel(annotatedClasses = {UpsertIntegrationTests.Item.class})
35+
@ExtendWith(MongoExtension.class)
36+
class UpsertIntegrationTests implements SessionFactoryScopeAware {
37+
private SessionFactoryScope sessionFactoryScope;
38+
39+
@Override
40+
public void injectSessionFactoryScope(SessionFactoryScope sessionFactoryScope) {
41+
this.sessionFactoryScope = sessionFactoryScope;
42+
}
43+
44+
@Test
45+
void unsupported() {
46+
var item = new Item(1, 1);
47+
sessionFactoryScope.inStatelessTransaction(session ->
48+
assertThatThrownBy(() -> session.upsert(item)).isInstanceOf(FeatureNotSupportedException.class));
49+
}
50+
51+
@Entity
52+
@Table(name = Item.COLLECTION_NAME)
53+
static class Item {
54+
static final String COLLECTION_NAME = "items";
55+
56+
@Id
57+
int id;
58+
/**
59+
* {@link org.hibernate.StatelessSession#upsert(Object)} results in no commands issued to the DBMS if {@link Id}
60+
* is the only persistent attribute, which must be a bug.
61+
*/
62+
int v;
63+
64+
Item() {}
65+
66+
Item(int id, int v) {
67+
this.id = id;
68+
v = 1;
69+
}
70+
}
71+
}

src/main/java/com/mongodb/hibernate/dialect/MongoDialect.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import static com.mongodb.hibernate.internal.MongoConstants.MONGO_DBMS_NAME;
2020
import static java.lang.String.format;
2121

22+
import com.mongodb.hibernate.internal.FeatureNotSupportedException;
2223
import com.mongodb.hibernate.internal.dialect.function.array.MongoArrayConstructorFunction;
2324
import com.mongodb.hibernate.internal.dialect.function.array.MongoArrayContainsFunction;
2425
import com.mongodb.hibernate.internal.dialect.function.array.MongoArrayIncludesFunction;
@@ -35,8 +36,16 @@
3536
import org.hibernate.dialect.Dialect;
3637
import org.hibernate.dialect.aggregate.AggregateSupport;
3738
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
39+
import org.hibernate.engine.jdbc.mutation.JdbcValueBindings;
40+
import org.hibernate.engine.spi.SessionFactoryImplementor;
41+
import org.hibernate.engine.spi.SharedSessionContractImplementor;
42+
import org.hibernate.persister.entity.mutation.EntityMutationTarget;
3843
import org.hibernate.service.ServiceRegistry;
3944
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
45+
import org.hibernate.sql.model.MutationOperation;
46+
import org.hibernate.sql.model.ValuesAnalysis;
47+
import org.hibernate.sql.model.internal.OptionalTableUpdate;
48+
import org.hibernate.sql.model.jdbc.OptionalTableUpdateOperation;
4049
import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
4150
import org.jspecify.annotations.Nullable;
4251

@@ -237,4 +246,21 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
237246
functionRegistry.register("array_includes", new MongoArrayIncludesFunction(false, typeConfiguration));
238247
functionRegistry.register("array_includes_nullable", new MongoArrayIncludesFunction(true, typeConfiguration));
239248
}
249+
250+
@Override
251+
public MutationOperation createOptionalTableUpdateOperation(
252+
EntityMutationTarget mutationTarget,
253+
OptionalTableUpdate optionalTableUpdate,
254+
SessionFactoryImplementor factory) {
255+
return new OptionalTableUpdateOperation(mutationTarget, optionalTableUpdate, factory) {
256+
@Override
257+
public void performMutation(
258+
JdbcValueBindings jdbcValueBindings,
259+
ValuesAnalysis valuesAnalysis,
260+
SharedSessionContractImplementor session) {
261+
throw new FeatureNotSupportedException(
262+
"TODO-HIBERNATE-94 https://jira.mongodb.org/browse/HIBERNATE-94");
263+
}
264+
};
265+
}
240266
}

0 commit comments

Comments
 (0)