From e60d674bfe2666244fc1f618ace142f3739a497f Mon Sep 17 00:00:00 2001 From: Gavin King Date: Mon, 4 Nov 2024 20:48:58 +0100 Subject: [PATCH] HHH-18809 support @Formula @Generated Signed-off-by: Gavin King --- .../ast/tree/expression/ColumnReference.java | 28 +++---- .../formula/FormulaGeneratedTest.java | 80 +++++++++++++++++++ 2 files changed, 92 insertions(+), 16 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/mapping/generated/formula/FormulaGeneratedTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/ColumnReference.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/ColumnReference.java index 1be3b4e7ba..f130ac4935 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/ColumnReference.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/ColumnReference.java @@ -10,7 +10,6 @@ import java.util.Locale; import java.util.Objects; import java.util.function.Consumer; -import org.hibernate.internal.util.StringHelper; import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.SelectableMapping; import org.hibernate.metamodel.mapping.SelectablePath; @@ -22,6 +21,7 @@ import org.hibernate.sql.ast.tree.update.Assignable; import org.checkerframework.checker.nullness.qual.Nullable; +import static org.hibernate.internal.util.StringHelper.nullIfEmpty; import static org.hibernate.internal.util.StringHelper.replace; import static org.hibernate.sql.Template.TEMPLATE; @@ -116,21 +116,20 @@ public class ColumnReference implements Expression, Assignable { boolean isFormula, String customReadExpression, JdbcMapping jdbcMapping) { - this.qualifier = StringHelper.nullIfEmpty( qualifier ); + this.qualifier = nullIfEmpty( qualifier ); if ( isFormula ) { - assert qualifier != null; - this.columnExpression = replace( columnExpression, TEMPLATE, qualifier ); + this.columnExpression = qualifier == null + ? replace( columnExpression, TEMPLATE + '.', "" ) + : replace( columnExpression, TEMPLATE, qualifier ); } else { this.columnExpression = columnExpression; } - if ( selectablePath == null ) { - this.selectablePath = new SelectablePath( this.columnExpression ); - } - else { - this.selectablePath = selectablePath; - } + + this.selectablePath = selectablePath == null + ? new SelectablePath( this.columnExpression ) + : selectablePath; this.isFormula = isFormula; this.readExpression = customReadExpression; @@ -181,12 +180,9 @@ public class ColumnReference implements Expression, Assignable { appender.accept( columnExpression ); } else if ( readExpression != null ) { - if ( qualifier == null ) { - appender.accept( replace( readExpression, TEMPLATE + ".", "" ) ); - } - else { - appender.accept( replace( readExpression, TEMPLATE, qualifier ) ); - } + appender.accept( qualifier == null + ? replace( readExpression, TEMPLATE + '.', "" ) + : replace( readExpression, TEMPLATE, qualifier ) ); } else { if ( qualifier != null ) { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/generated/formula/FormulaGeneratedTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/generated/formula/FormulaGeneratedTest.java new file mode 100644 index 0000000000..a770789439 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/generated/formula/FormulaGeneratedTest.java @@ -0,0 +1,80 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.mapping.generated.formula; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import org.hibernate.annotations.Formula; +import org.hibernate.annotations.Generated; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.testing.orm.junit.Setting; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; + +import static org.hibernate.cfg.JdbcSettings.USE_GET_GENERATED_KEYS; +import static org.junit.Assert.assertEquals; + +/** + * @author Gavin King + */ +@SuppressWarnings("JUnitMalformedDeclaration") +@DomainModel(annotatedClasses = FormulaGeneratedTest.OrderLine.class) +@SessionFactory +@ServiceRegistry(settings = @Setting(name = USE_GET_GENERATED_KEYS, value = "false")) +public class FormulaGeneratedTest { + + @Test + public void test(SessionFactoryScope scope) { + BigDecimal unitPrice = new BigDecimal("12.99"); + scope.inTransaction( session -> { + OrderLine entity = new OrderLine( unitPrice, 5 ); + session.persist(entity); + session.flush(); + assertEquals( "new", entity.status ); + assertEquals( unitPrice, entity.unitPrice ); + assertEquals( 5, entity.quantity ); + } ); + scope.inTransaction( session -> { + OrderLine entity = session.createQuery("from WithDefault", OrderLine.class ).getSingleResult(); + assertEquals( unitPrice, entity.unitPrice ); + assertEquals( 5, entity.quantity ); + assertEquals( "new", entity.status ); + entity.status = "old"; //should be ignored when fetch=true + } ); + scope.inTransaction( session -> { + OrderLine entity = session.createQuery("from WithDefault", OrderLine.class ).getSingleResult(); + assertEquals( unitPrice, entity.unitPrice ); + assertEquals( 5, entity.quantity ); + assertEquals( "new", entity.status ); + } ); + } + + @AfterEach + public void dropTestData(SessionFactoryScope scope) { + scope.inTransaction( session -> session.createQuery( "delete WithDefault" ).executeUpdate() ); + } + + @Entity(name="WithDefault") + public static class OrderLine { + @Id + private BigDecimal unitPrice; + @Id + private int quantity = 1; + @Generated + @Formula(value = "'new'") + private String status; + + public OrderLine() {} + public OrderLine(BigDecimal unitPrice, int quantity) { + this.unitPrice = unitPrice; + this.quantity = quantity; + } + } +}