From 4ea6f43f90013194bbcc491ba8a0ef0c3e76528f Mon Sep 17 00:00:00 2001 From: Kirill Kurdyukov Date: Tue, 18 Feb 2025 19:27:45 +0300 Subject: [PATCH 1/2] [Spring Data JDBC YDB Dialect]: Update CHANGELOG.md and pom.xml --- spring-data-jdbc-ydb/CHANGELOG.md | 4 ++++ spring-data-jdbc-ydb/pom.xml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/spring-data-jdbc-ydb/CHANGELOG.md b/spring-data-jdbc-ydb/CHANGELOG.md index 12c509e..12ba48b 100644 --- a/spring-data-jdbc-ydb/CHANGELOG.md +++ b/spring-data-jdbc-ydb/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.1.0 ## +- Fixed bug: No MethodInvocation found for Spring version 3.4.0 +- Added JdbcRepositoryBeanPostProcessor for @ViewIndex annotation + ## 1.0.0 ## - quoting index name in VIEW statement (ex. VIEW \`index_name\`) diff --git a/spring-data-jdbc-ydb/pom.xml b/spring-data-jdbc-ydb/pom.xml index acfe785..aaa9f63 100644 --- a/spring-data-jdbc-ydb/pom.xml +++ b/spring-data-jdbc-ydb/pom.xml @@ -6,7 +6,7 @@ tech.ydb.dialects spring-data-jdbc-ydb - 1.0.0 + 1.1.0 Spring Data JDBC YDB Dialect Support Spring Data JDBC YDB (YQL) Dialect From 6668343e204c06ada000ac3eeca3842b395c2fd1 Mon Sep 17 00:00:00 2001 From: Kirill Kurdyukov Date: Wed, 2 Apr 2025 17:31:01 +0300 Subject: [PATCH 2/2] Supported YDB Serial type --- .../ydb/hibernate/dialect/YdbDialect.java | 17 ++++++ .../identity/YdbIdentityColumnSupport.java | 49 ++++++++++++++++ .../auto_inc/GenerationTypeIdentityTest.java | 56 +++++++++++++++++++ .../hibernate/auto_inc/TestEntityFail.java | 29 ++++++++++ .../ydb/hibernate/auto_inc/TestEntityInt.java | 29 ++++++++++ .../hibernate/auto_inc/TestEntityLong.java | 29 ++++++++++ .../hibernate/auto_inc/TestEntityShort.java | 29 ++++++++++ 7 files changed, 238 insertions(+) create mode 100644 hibernate-dialect/src/main/java/tech/ydb/hibernate/dialect/identity/YdbIdentityColumnSupport.java create mode 100644 hibernate-dialect/src/test/java/tech/ydb/hibernate/auto_inc/GenerationTypeIdentityTest.java create mode 100644 hibernate-dialect/src/test/java/tech/ydb/hibernate/auto_inc/TestEntityFail.java create mode 100644 hibernate-dialect/src/test/java/tech/ydb/hibernate/auto_inc/TestEntityInt.java create mode 100644 hibernate-dialect/src/test/java/tech/ydb/hibernate/auto_inc/TestEntityLong.java create mode 100644 hibernate-dialect/src/test/java/tech/ydb/hibernate/auto_inc/TestEntityShort.java diff --git a/hibernate-dialect/src/main/java/tech/ydb/hibernate/dialect/YdbDialect.java b/hibernate-dialect/src/main/java/tech/ydb/hibernate/dialect/YdbDialect.java index 5434736..44c165d 100644 --- a/hibernate-dialect/src/main/java/tech/ydb/hibernate/dialect/YdbDialect.java +++ b/hibernate-dialect/src/main/java/tech/ydb/hibernate/dialect/YdbDialect.java @@ -7,6 +7,7 @@ import org.hibernate.boot.model.TypeContributions; import org.hibernate.dialect.Dialect; import org.hibernate.dialect.function.CurrentFunction; +import org.hibernate.dialect.identity.IdentityColumnSupport; import org.hibernate.dialect.pagination.LimitHandler; import org.hibernate.dialect.pagination.LimitOffsetLimitHandler; import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo; @@ -67,6 +68,7 @@ import tech.ydb.hibernate.dialect.hint.PragmaQueryHintHandler; import tech.ydb.hibernate.dialect.hint.QueryHintHandler; import tech.ydb.hibernate.dialect.hint.ScanQueryHintHandler; +import tech.ydb.hibernate.dialect.identity.YdbIdentityColumnSupport; import tech.ydb.hibernate.dialect.translator.YdbSqlAstTranslatorFactory; import tech.ydb.hibernate.dialect.types.BigDecimalJavaType; import tech.ydb.hibernate.dialect.types.DecimalJdbcType; @@ -368,4 +370,19 @@ public Exporter getForeignKeyExporter() { public boolean supportsColumnCheck() { return false; } + + @Override + public IdentityColumnSupport getIdentityColumnSupport() { + return YdbIdentityColumnSupport.INSTANCE; + } + + @Override + public boolean supportsInsertReturning() { + return true; + } + + @Override + public boolean supportsInsertReturningGeneratedKeys() { + return true; + } } diff --git a/hibernate-dialect/src/main/java/tech/ydb/hibernate/dialect/identity/YdbIdentityColumnSupport.java b/hibernate-dialect/src/main/java/tech/ydb/hibernate/dialect/identity/YdbIdentityColumnSupport.java new file mode 100644 index 0000000..071405a --- /dev/null +++ b/hibernate-dialect/src/main/java/tech/ydb/hibernate/dialect/identity/YdbIdentityColumnSupport.java @@ -0,0 +1,49 @@ +package tech.ydb.hibernate.dialect.identity; + +import java.sql.JDBCType; +import org.hibernate.MappingException; +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.identity.IdentityColumnSupportImpl; +import org.hibernate.id.PostInsertIdentityPersister; +import org.hibernate.id.insert.GetGeneratedKeysDelegate; +import static org.hibernate.type.SqlTypes.BIGINT; +import static org.hibernate.type.SqlTypes.INTEGER; +import static org.hibernate.type.SqlTypes.SMALLINT; +import static org.hibernate.type.SqlTypes.TINYINT; + +/** + * @author Kirill Kurdyukov + */ +public class YdbIdentityColumnSupport extends IdentityColumnSupportImpl { + + public static final YdbIdentityColumnSupport INSTANCE = new YdbIdentityColumnSupport(); + + @Override + public boolean hasDataTypeInIdentityColumn() { + return false; + } + + @Override + public String getIdentityColumnString(int type) throws MappingException { + return switch (type) { + case TINYINT, SMALLINT -> "SmallSerial"; + case INTEGER -> "Serial"; + case BIGINT -> "BigSerial"; + default -> throw new MappingException( + "Ydb does not support identity key generation for sqlType: " + JDBCType.valueOf(type)); + }; + } + + @Override + public boolean supportsIdentityColumns() { + return true; + } + + @Override + public GetGeneratedKeysDelegate buildGetGeneratedKeysDelegate( + PostInsertIdentityPersister persister, + Dialect dialect + ) { + return new GetGeneratedKeysDelegate(persister, dialect, false); + } +} diff --git a/hibernate-dialect/src/test/java/tech/ydb/hibernate/auto_inc/GenerationTypeIdentityTest.java b/hibernate-dialect/src/test/java/tech/ydb/hibernate/auto_inc/GenerationTypeIdentityTest.java new file mode 100644 index 0000000..b6c472c --- /dev/null +++ b/hibernate-dialect/src/test/java/tech/ydb/hibernate/auto_inc/GenerationTypeIdentityTest.java @@ -0,0 +1,56 @@ +package tech.ydb.hibernate.auto_inc; + +import org.hibernate.MappingException; +import org.hibernate.cfg.AvailableSettings; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.extension.RegisterExtension; +import static tech.ydb.hibernate.TestUtils.SESSION_FACTORY; +import static tech.ydb.hibernate.TestUtils.basedConfiguration; +import static tech.ydb.hibernate.TestUtils.jdbcUrl; +import tech.ydb.test.junit5.YdbHelperExtension; + +/** + * @author Kirill Kurdyukov + */ +public class GenerationTypeIdentityTest { + + @RegisterExtension + private static final YdbHelperExtension ydb = new YdbHelperExtension(); + +// @Test + void serialTypesTest() { + /* + create table test_table_int_auto_inc ( + id Serial, + text Text, + primary key (id) + ) + */ + + SESSION_FACTORY = basedConfiguration() + .addAnnotatedClass(TestEntityInt.class) + .addAnnotatedClass(TestEntityLong.class) + .addAnnotatedClass(TestEntityShort.class) + .setProperty(AvailableSettings.URL, jdbcUrl(ydb)) + .buildSessionFactory(); + + Assertions.assertThrows(MappingException.class, () -> basedConfiguration() + .addAnnotatedClass(TestEntityFail.class) + .setProperty(AvailableSettings.URL, jdbcUrl(ydb)) + .buildSessionFactory()); + + SESSION_FACTORY.inTransaction( + session -> { + var intE = new TestEntityInt(); + intE.setText("test"); + session.persist(intE); + var intS = new TestEntityShort(); + intS.setText("test"); + session.persist(intS); + var intL = new TestEntityLong(); + intL.setText("test"); + session.persist(intL); + } + ); + } +} diff --git a/hibernate-dialect/src/test/java/tech/ydb/hibernate/auto_inc/TestEntityFail.java b/hibernate-dialect/src/test/java/tech/ydb/hibernate/auto_inc/TestEntityFail.java new file mode 100644 index 0000000..d3c5dd4 --- /dev/null +++ b/hibernate-dialect/src/test/java/tech/ydb/hibernate/auto_inc/TestEntityFail.java @@ -0,0 +1,29 @@ +package tech.ydb.hibernate.auto_inc; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author Kirill Kurdyukov + */ +@Entity +@Data +@AllArgsConstructor +@NoArgsConstructor +@Table(name = "test_table_int_auto_fail") +public class TestEntityFail { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private String id; + + @Column + private String text; +} diff --git a/hibernate-dialect/src/test/java/tech/ydb/hibernate/auto_inc/TestEntityInt.java b/hibernate-dialect/src/test/java/tech/ydb/hibernate/auto_inc/TestEntityInt.java new file mode 100644 index 0000000..a55a263 --- /dev/null +++ b/hibernate-dialect/src/test/java/tech/ydb/hibernate/auto_inc/TestEntityInt.java @@ -0,0 +1,29 @@ +package tech.ydb.hibernate.auto_inc; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author Kirill Kurdyukov + */ +@Entity +@Data +@AllArgsConstructor +@NoArgsConstructor +@Table(name = "test_table_int_auto_inc") +public class TestEntityInt { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + + @Column + private String text; +} diff --git a/hibernate-dialect/src/test/java/tech/ydb/hibernate/auto_inc/TestEntityLong.java b/hibernate-dialect/src/test/java/tech/ydb/hibernate/auto_inc/TestEntityLong.java new file mode 100644 index 0000000..c2b66b5 --- /dev/null +++ b/hibernate-dialect/src/test/java/tech/ydb/hibernate/auto_inc/TestEntityLong.java @@ -0,0 +1,29 @@ +package tech.ydb.hibernate.auto_inc; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author Kirill Kurdyukov + */ +@Entity +@Data +@AllArgsConstructor +@NoArgsConstructor +@Table(name = "test_table_int_auto_long") +public class TestEntityLong { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + @Column + private String text; +} diff --git a/hibernate-dialect/src/test/java/tech/ydb/hibernate/auto_inc/TestEntityShort.java b/hibernate-dialect/src/test/java/tech/ydb/hibernate/auto_inc/TestEntityShort.java new file mode 100644 index 0000000..a3f88a5 --- /dev/null +++ b/hibernate-dialect/src/test/java/tech/ydb/hibernate/auto_inc/TestEntityShort.java @@ -0,0 +1,29 @@ +package tech.ydb.hibernate.auto_inc; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author Kirill Kurdyukov + */ +@Entity +@Data +@AllArgsConstructor +@NoArgsConstructor +@Table(name = "test_table_int_auto_short") +public class TestEntityShort { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private short id; + + @Column + private String text; +}