Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
221ec3d
HIBERNATE-58
stIncMale May 7, 2025
4ed1ce7
Remove custom array-handling code
stIncMale Jun 17, 2025
c4986fa
Hack-in `null` support to how the tests behave
stIncMale Jun 18, 2025
01a7365
Undo "Hack-in `null` support to how the tests behave"
stIncMale Jun 18, 2025
78d8892
Do changes identified during the code walkthrough
stIncMale Jun 19, 2025
2e9088a
Merge branch 'main' into HIBERNATE-58
stIncMale Jun 19, 2025
c13fda9
Get rid of the custom primitive types and arrays of them
stIncMale Jun 26, 2025
179f451
Simplify the invocation of `addDescriptorIfAbsent`
stIncMale Jun 26, 2025
68bea86
Remove the unused `ValueConversions.toCharDomainValue` method
stIncMale Jun 26, 2025
0b76dd3
Simplify `ValueConversions.toDomainValue(BsonString value)`
stIncMale Jun 26, 2025
f0899ef
Fix copyright comments
stIncMale Jun 26, 2025
1573746
Require presence of insertable columns in structs, which is stricter …
stIncMale Jun 26, 2025
8499612
Use `var` where possible
stIncMale Jun 26, 2025
1ca8201
Use `var` where possible
stIncMale Jun 26, 2025
865cf7e
Rename the parameter of the `assertCollectionContainsExactly` method
stIncMale Jun 26, 2025
dbb00b9
Update the code comment about Hibernate ORM reading `null` instead of…
stIncMale Jun 26, 2025
ed6fb2c
Replace bulky `instanceof` casts&assertions with a new more compact `…
stIncMale Jun 27, 2025
6de1bfe
`ValueConversions.toDomainValue` can never get `null` `value`
stIncMale Jun 27, 2025
20f8e83
Move setup methods to the top of test classes
stIncMale Jun 27, 2025
ec24448
Support missing fields in structs
stIncMale Jun 28, 2025
2998250
Use `var`
stIncMale Jul 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ public static void assertUsingRecursiveComparison(
@Nullable Object actual,
BiConsumer<RecursiveComparisonAssert<?>, Object> assertion) {
assertion.accept(
assertThat(expected)
assertThat(actual)
.usingRecursiveComparison()
.usingOverriddenEquals()
.withStrictTypeChecking(),
actual);
expected);
}

/**
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import static java.lang.String.format;

import com.mongodb.hibernate.internal.FeatureNotSupportedException;
import com.mongodb.hibernate.internal.type.MongoArrayJdbcType;
import com.mongodb.hibernate.internal.type.MongoStructJdbcType;
import org.hibernate.dialect.aggregate.AggregateSupportImpl;
import org.hibernate.mapping.AggregateColumn;
Expand All @@ -38,10 +39,11 @@ public String aggregateComponentCustomReadExpression(
AggregateColumn aggregateColumn,
Column column) {
var aggregateColumnType = aggregateColumn.getTypeCode();
if (aggregateColumnType == MongoStructJdbcType.JDBC_TYPE.getVendorTypeNumber()) {
if (aggregateColumnType == MongoStructJdbcType.JDBC_TYPE.getVendorTypeNumber()
|| aggregateColumnType == MongoArrayJdbcType.HIBERNATE_SQL_TYPE) {
return format(
"unused from %s.aggregateComponentCustomReadExpression",
MongoAggregateSupport.class.getSimpleName());
"unused from %s.aggregateComponentCustomReadExpression for SQL type code [%d]",
MongoAggregateSupport.class.getSimpleName(), aggregateColumnType);
}
throw new FeatureNotSupportedException(format("The SQL type code [%d] is not supported", aggregateColumnType));
}
Expand All @@ -53,17 +55,19 @@ public String aggregateComponentAssignmentExpression(
AggregateColumn aggregateColumn,
Column column) {
var aggregateColumnType = aggregateColumn.getTypeCode();
if (aggregateColumnType == MongoStructJdbcType.JDBC_TYPE.getVendorTypeNumber()) {
if (aggregateColumnType == MongoStructJdbcType.JDBC_TYPE.getVendorTypeNumber()
|| aggregateColumnType == MongoArrayJdbcType.HIBERNATE_SQL_TYPE) {
return format(
"unused from %s.aggregateComponentAssignmentExpression",
MongoAggregateSupport.class.getSimpleName());
"unused from %s.aggregateComponentAssignmentExpression for SQL type code [%d]",
MongoAggregateSupport.class.getSimpleName(), aggregateColumnType);
}
throw new FeatureNotSupportedException(format("The SQL type code [%d] is not supported", aggregateColumnType));
}

@Override
public boolean requiresAggregateCustomWriteExpressionRenderer(int aggregateSqlTypeCode) {
if (aggregateSqlTypeCode == MongoStructJdbcType.JDBC_TYPE.getVendorTypeNumber()) {
if (aggregateSqlTypeCode == MongoStructJdbcType.JDBC_TYPE.getVendorTypeNumber()
|| aggregateSqlTypeCode == MongoArrayJdbcType.HIBERNATE_SQL_TYPE) {
return false;
}
throw new FeatureNotSupportedException(format("The SQL type code [%d] is not supported", aggregateSqlTypeCode));
Expand Down
25 changes: 24 additions & 1 deletion src/main/java/com/mongodb/hibernate/dialect/MongoDialect.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
import static java.lang.String.format;

import com.mongodb.hibernate.internal.translate.MongoTranslatorFactory;
import com.mongodb.hibernate.internal.type.MongoArrayJdbcType;
import com.mongodb.hibernate.internal.type.MongoStructJdbcType;
import com.mongodb.hibernate.internal.type.MqlType;
import com.mongodb.hibernate.internal.type.ObjectIdJavaType;
import com.mongodb.hibernate.internal.type.ObjectIdJdbcType;
import com.mongodb.hibernate.jdbc.MongoConnectionProvider;
Expand All @@ -31,6 +33,7 @@
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
import org.jspecify.annotations.Nullable;

/**
Expand Down Expand Up @@ -91,9 +94,24 @@ public SqlAstTranslatorFactory getSqlAstTranslatorFactory() {
@Override
public void contribute(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
super.contribute(typeContributions, serviceRegistry);
contributeObjectIdType(typeContributions);
typeContributions.contributeJdbcTypeConstructor(MongoArrayJdbcType.Constructor.INSTANCE);
typeContributions.contributeJdbcType(MongoStructJdbcType.INSTANCE);
}

private void contributeObjectIdType(TypeContributions typeContributions) {
typeContributions.contributeJavaType(ObjectIdJavaType.INSTANCE);
typeContributions.contributeJdbcType(ObjectIdJdbcType.INSTANCE);
typeContributions.contributeJdbcType(MongoStructJdbcType.INSTANCE);
var objectIdTypeCode = MqlType.OBJECT_ID.getVendorTypeNumber();
typeContributions
.getTypeConfiguration()
.getDdlTypeRegistry()
.addDescriptorIfAbsent(new DdlTypeImpl(
objectIdTypeCode,
format(
"unused from %s.contributeObjectIdType for SQL type code [%d]",
MongoDialect.class.getSimpleName(), objectIdTypeCode),
this));
}

@Override
Expand All @@ -105,4 +123,9 @@ public void contribute(TypeContributions typeContributions, ServiceRegistry serv
public AggregateSupport getAggregateSupport() {
return MongoAggregateSupport.INSTANCE;
}

@Override
public boolean supportsStandardArrays() {
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public void contribute(
InFlightMetadataCollector metadata,
ResourceStreamLocator resourceStreamLocator,
MetadataBuildingContext buildingContext) {
forbidEmbeddablesWithoutPersistentAttributes(metadata);
metadata.getEntityBindings().forEach(persistentClass -> {
forbidDynamicInsert(persistentClass);
checkColumnNames(persistentClass);
Expand All @@ -67,7 +68,8 @@ public void contribute(

private static void forbidDynamicInsert(PersistentClass persistentClass) {
if (persistentClass.useDynamicInsert()) {
throw new FeatureNotSupportedException(format("%s is not supported", DynamicInsert.class.getSimpleName()));
throw new FeatureNotSupportedException(
format("%s: %s is not supported", persistentClass, DynamicInsert.class.getSimpleName()));
}
}

Expand Down Expand Up @@ -100,6 +102,15 @@ private static void forbidStructIdentifier(PersistentClass persistentClass) {
}
}

private static void forbidEmbeddablesWithoutPersistentAttributes(InFlightMetadataCollector metadata) {
metadata.visitRegisteredComponents(component -> {
if (!component.hasAnyInsertableColumns()) {
throw new FeatureNotSupportedException(
format("%s: must have at least one persistent attribute", component));
}
});
}

private static void setIdentifierColumnName(PersistentClass persistentClass) {
var identifier = persistentClass.getIdentifier();
assertFalse(identifier.hasFormula());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -950,6 +950,7 @@ private static boolean isComparingFieldWithValue(ComparisonPredicate comparisonP
}

private static BsonValue toBsonValue(Object value) {
// TODO-HIBERNATE-74 decide if `value` is nullable
try {
return ValueConversions.toBsonValue(value);
} catch (SQLFeatureNotSupportedException e) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright 2025-present MongoDB, Inc.
*
* Licensed 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
*
* http://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 com.mongodb.hibernate.internal.type;

import static com.mongodb.hibernate.internal.MongoAssertions.assertTrue;

import java.io.Serial;
import java.sql.JDBCType;
import java.sql.SQLException;
import org.hibernate.dialect.Dialect;
import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation;
import org.hibernate.type.SqlTypes;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.jdbc.ArrayJdbcType;
import org.hibernate.type.descriptor.jdbc.BasicExtractor;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcTypeConstructor;
import org.hibernate.type.spi.TypeConfiguration;
import org.jspecify.annotations.Nullable;

/** Thread-safe. */
public final class MongoArrayJdbcType extends ArrayJdbcType {
@Serial
private static final long serialVersionUID = 1L;

public static final JDBCType JDBC_TYPE = JDBCType.ARRAY;
public static final int HIBERNATE_SQL_TYPE = SqlTypes.STRUCT_ARRAY;

private MongoArrayJdbcType(JdbcType elementJdbcType) {
super(elementJdbcType);
}

@Override
public int getJdbcTypeCode() {
var result = super.getJdbcTypeCode();
assertTrue(result == JDBC_TYPE.getVendorTypeNumber());
return result;
}

/** This method is overridden to make it accessible from our code. */
@Override
protected <X> @Nullable X getArray(
BasicExtractor<X> extractor, java.sql.@Nullable Array array, WrapperOptions options) throws SQLException {
return super.getArray(extractor, array, options);
}

public static final class Constructor implements JdbcTypeConstructor {
public static final Constructor INSTANCE = new Constructor();

private Constructor() {}

@Override
public JdbcType resolveType(
TypeConfiguration typeConfiguration,
Dialect dialect,
JdbcType elementType,
ColumnTypeInformation columnTypeInformation) {
return new MongoArrayJdbcType(elementType);
}

@Override
public int getDefaultSqlTypeCode() {
return JDBC_TYPE.getVendorTypeNumber();
}
}
}
Loading