From 18a90e7f9c8bbd0ae1b4f92300830eb98c1f93b7 Mon Sep 17 00:00:00 2001 From: Alexander <45239372+Rinoyt@users.noreply.github.com> Date: Thu, 20 Nov 2025 15:15:36 +0300 Subject: [PATCH 01/98] Initial commit --- README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 00000000..a4f49b95 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# ydb-jimmer-orm \ No newline at end of file From a892eb09cfa0f8d821824a65975219d747a6eccd Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Mon, 8 Dec 2025 15:17:41 +0300 Subject: [PATCH 02/98] added the pom file --- .gitignore | 2 ++ dialect/pom.xml | 30 ++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 .gitignore create mode 100644 dialect/pom.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..c38fa4e0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea +*.iml diff --git a/dialect/pom.xml b/dialect/pom.xml new file mode 100644 index 00000000..b25895a8 --- /dev/null +++ b/dialect/pom.xml @@ -0,0 +1,30 @@ + + 4.0.0 + + jimmer.ydb + jimmer-ydb-dialect + 1.0-SNAPSHOT + YDB dialect for Jimmer ORM + + + 25 + + + + + + org.babyfish.jimmer + jimmer-sql + 0.9.117 + + + + org.json + json + 20250517 + + + From 16df237ad300456178b337f1739c195614c22d73 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Mon, 8 Dec 2025 15:18:05 +0300 Subject: [PATCH 03/98] v0.1 for the YDB dialect Without tests --- dialect/src/main/java/YDBDialect.java | 238 ++++++++++++++++++++++++++ 1 file changed, 238 insertions(+) create mode 100644 dialect/src/main/java/YDBDialect.java diff --git a/dialect/src/main/java/YDBDialect.java b/dialect/src/main/java/YDBDialect.java new file mode 100644 index 00000000..7bf08b53 --- /dev/null +++ b/dialect/src/main/java/YDBDialect.java @@ -0,0 +1,238 @@ +import org.babyfish.jimmer.sql.ast.impl.Ast; +import org.babyfish.jimmer.sql.ast.impl.Literals; +import org.babyfish.jimmer.sql.ast.impl.query.ForUpdate; +import org.babyfish.jimmer.sql.ast.impl.render.AbstractSqlBuilder; +import org.babyfish.jimmer.sql.dialect.DefaultDialect; +import org.jetbrains.annotations.Nullable; +import org.json.JSONObject; + +import java.math.BigDecimal; +import java.sql.Date; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Time; +import java.sql.Timestamp; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetDateTime; +import java.time.OffsetTime; +import java.time.ZonedDateTime; +import java.util.UUID; + +public class YDBDialect extends DefaultDialect { + @Override + public String sqlType(Class elementType) { + if (elementType == String.class) { + return "String"; + } else if (elementType == UUID.class) { + return "Uuid"; + } else if (elementType == boolean.class) { + return "Bool"; + } else if (elementType == byte.class) { + return "Int8"; + } else if (elementType == short.class) { + return "Int16"; + } else if (elementType == int.class) { + return "Int32"; + } else if (elementType == long.class) { + return "Int64"; + } else if (elementType == float.class) { + return "Float"; + } else if (elementType == double.class) { + return "Double"; + } else if (elementType == BigDecimal.class) { + return "Decimal(35, 35)"; + } else if (elementType == Date.class) { + return "Date"; + } else if (elementType == LocalDate.class) { + return "Date32"; + } else if (elementType == Time.class || elementType == OffsetTime.class) { + return "Timestamp"; + } else if (elementType == LocalTime.class + || elementType == java.util.Date.class + || elementType == Timestamp.class) { + return "Timestamp64"; + } else if (elementType == LocalDateTime.class || elementType == OffsetDateTime.class) { + return "DateTime64"; + } else if (elementType == ZonedDateTime.class) { + return "TzDateTime64"; + } else { + return null; + } + } + + @Override + public boolean isDeleteAliasSupported() { + return false; + } + + @Override + public boolean isUpdateAliasSupported() { + return false; + } + + @Override + public boolean isArraySupported() { + return true; + } + + @Override + public T[] getArray(ResultSet rs, int col, Class arrayType) throws SQLException { + return rs.getObject(col, arrayType); + } + + @Override + public boolean isTableOfSubQueryMutable() { + return false; + } + + @Override + public Class getJsonBaseType() { + return JSONObject.class; + } + + @Override + public @Nullable Object jsonToBaseValue(@Nullable String json) { + return json == null ? new JSONObject() : new JSONObject(json); + } + + @Override + public @Nullable String baseValueToJson(@Nullable Object baseValue) { + return baseValue == null ? null : baseValue.toString(); + } + + @Override + public boolean isForeignKeySupported() { + return false; + } + + @Override + public boolean isInsertedIdReturningRequired() { + return true; + } + + @Override + public boolean isExplicitBatchRequired() { + return true; + } + + @Override + public boolean isBatchDumb() { + return true; + } + + @Override + public boolean isUpsertSupported() { + return true; + } + + @Override + public boolean isNoIdUpsertSupported() { + return false; + } + + @Override + public boolean isUpsertWithOptimisticLockSupported() { + return true; + } + + @Override + public boolean isUpsertWithNullableKeySupported() { + return true; + } + + @Override + public boolean isTransactionAbortedByError() { + return true; + } + + @Override + public void update(UpdateContext ctx) { + ctx.sql("UPDATE ") + .appendTableName() + .enter(AbstractSqlBuilder.ScopeType.SET) + .appendAssignments() + .leave() + .enter(AbstractSqlBuilder.ScopeType.WHERE) + .appendPredicates() + .leave() + .sql(" RETURNING ") + .appendId(); + } + + @Override + public void upsert(UpsertContext ctx) { + if (ctx.isUpdateIgnored() || !ctx.hasUpdatedColumns()) { + ctx.sql("INSERT INTO ") + .appendTableName() + .enter(AbstractSqlBuilder.ScopeType.MULTIPLE_LINE_TUPLE) + .appendInsertedColumns("") + .leave() + .sql("VALUES ") + .enter(AbstractSqlBuilder.ScopeType.MULTIPLE_LINE_TUPLE) + .appendInsertingValues() + .leave(); + } else { + ctx.sql("UPSERT INTO ") + .appendTableName() + .enter(AbstractSqlBuilder.ScopeType.MULTIPLE_LINE_TUPLE) + .appendInsertedColumns("") + .leave() + .sql("VALUES ") + .enter(AbstractSqlBuilder.ScopeType.MULTIPLE_LINE_TUPLE) + .appendInsertingValues() + .leave(); + } + } + + @Override + public void renderLPad(AbstractSqlBuilder builder, int currentPrecedence, Ast expression, Ast length, Ast padString) { + throw new UnsupportedOperationException( + "The current dialect \"" + getClass().getName() + "\" does not support LPad." + ); + } + + @Override + public void renderRPad(AbstractSqlBuilder builder, int currentPrecedence, Ast expression, Ast length, Ast padString) { + throw new UnsupportedOperationException( + "The current dialect \"" + getClass().getName() + "\" does not support RPad." + ); + } + + @Override + public void renderPosition(AbstractSqlBuilder builder, int currentPrecedence, Ast subStrAst, Ast expressionAst, @Nullable Ast startAst) { + builder.sql("FIND(") + .ast(expressionAst, currentPrecedence) + .sql(", ") + .ast(subStrAst, currentPrecedence); + if (startAst != null) { + builder.sql(", ") + .ast(startAst, currentPrecedence); + } + builder.sql(")"); + } + + @Override + public void renderLeft(AbstractSqlBuilder builder, int currentPrecedence, Ast expressionAst, Ast lengthAst) { + renderSubString(builder, currentPrecedence, expressionAst, (Ast) Literals.number(0), lengthAst); + } + + @Override + public void renderRight(AbstractSqlBuilder builder, int currentPrecedence, Ast expressionAst, Ast lengthAst) { + builder.sql("substring(") + .ast(expressionAst, currentPrecedence) + .sql(", (LENGTH(") + .ast(expressionAst, currentPrecedence) + .sql(") - ") + .ast(lengthAst, currentPrecedence) + .sql("))"); + } + + @Override + public void renderForUpdate(AbstractSqlBuilder builder, ForUpdate forUpdate) { + throw new UnsupportedOperationException( + "The current dialect \"" + getClass().getName() + "\" does not support 'for update' hint." + ); + } +} From 5346933eb25ed7f12ef6f8122b7f305f7c444aea Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Wed, 4 Feb 2026 00:05:13 +0300 Subject: [PATCH 04/98] dialect name change --- .../{YDBDialect.java => ydb/jimmer/dialect/YdbDialect.java} | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) rename dialect/src/main/java/{YDBDialect.java => ydb/jimmer/dialect/YdbDialect.java} (98%) diff --git a/dialect/src/main/java/YDBDialect.java b/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java similarity index 98% rename from dialect/src/main/java/YDBDialect.java rename to dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java index 7bf08b53..9457a9e4 100644 --- a/dialect/src/main/java/YDBDialect.java +++ b/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java @@ -1,3 +1,5 @@ +package ydb.jimmer.dialect; + import org.babyfish.jimmer.sql.ast.impl.Ast; import org.babyfish.jimmer.sql.ast.impl.Literals; import org.babyfish.jimmer.sql.ast.impl.query.ForUpdate; @@ -20,7 +22,7 @@ import java.time.ZonedDateTime; import java.util.UUID; -public class YDBDialect extends DefaultDialect { +public class YdbDialect extends DefaultDialect { @Override public String sqlType(Class elementType) { if (elementType == String.class) { From 6e9da30b8f199fa3453d1ece7c35d2cf8eb7b98c Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Wed, 4 Feb 2026 00:05:18 +0300 Subject: [PATCH 05/98] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c38fa4e0..e98ea6e3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .idea *.iml +/dialect/target From 48013f75f1b9aa547a76d2b3bc869778dba13f1b Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Wed, 4 Feb 2026 00:05:27 +0300 Subject: [PATCH 06/98] Update pom.xml --- dialect/pom.xml | 60 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/dialect/pom.xml b/dialect/pom.xml index b25895a8..35dd39dc 100644 --- a/dialect/pom.xml +++ b/dialect/pom.xml @@ -10,6 +10,8 @@ YDB dialect for Jimmer ORM + 0.9.117 + 7.0.2 25 @@ -18,7 +20,7 @@ org.babyfish.jimmer jimmer-sql - 0.9.117 + ${jimmer.version} @@ -26,5 +28,61 @@ json 20250517 + + org.junit.jupiter + junit-jupiter + 5.11.4 + test + + + + tech.ydb.jdbc + ydb-jdbc-driver + 2.3.20 + test + + + + org.springframework + spring-jdbc + ${spring.version} + test + + + + org.apache.logging.log4j + log4j-slf4j2-impl + 2.25.3 + test + + + + tech.ydb.test + ydb-junit5-support + 2.3.29 + test + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.10.1 + + + + org.babyfish.jimmer + jimmer-apt + ${jimmer.version} + + + + -parameters + + + + + From c0c0d548abaa361783ac01bd844f8eef53ec6216 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Wed, 4 Feb 2026 00:05:50 +0300 Subject: [PATCH 07/98] models for tests --- .../java/ydb/jimmer/dialect/model/Group.java | 17 +++++++++++++ .../ydb/jimmer/dialect/model/Student.java | 25 +++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/Group.java create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/Student.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/Group.java b/dialect/src/test/java/ydb/jimmer/dialect/model/Group.java new file mode 100644 index 00000000..5f753294 --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/Group.java @@ -0,0 +1,17 @@ +package ydb.jimmer.dialect.model; + +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.GeneratedValue; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.meta.UUIDIdGenerator; + +import java.util.UUID; + +@Entity +public interface Group { + @Id + @GeneratedValue(generatorType = UUIDIdGenerator.class) + UUID id(); + + String name(); +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/Student.java b/dialect/src/test/java/ydb/jimmer/dialect/model/Student.java new file mode 100644 index 00000000..3f4a5a0c --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/Student.java @@ -0,0 +1,25 @@ +package ydb.jimmer.dialect.model; + +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.ForeignKeyType; +import org.babyfish.jimmer.sql.GeneratedValue; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.JoinColumn; +import org.babyfish.jimmer.sql.ManyToOne; +import org.babyfish.jimmer.sql.meta.UUIDIdGenerator; + +import java.util.UUID; + +@Entity +public interface Student { + @Id + @GeneratedValue(generatorType = UUIDIdGenerator.class) + UUID id(); + + + String name(); + + @ManyToOne + @JoinColumn(foreignKeyType = ForeignKeyType.FAKE) + Group group(); +} From 006155b4f01ccaedeb4a871ce648e816014def93 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Wed, 4 Feb 2026 00:06:31 +0300 Subject: [PATCH 08/98] Classes to monitor sql requests for tests --- .../dialect/sqlMonitor/ExecutorLog.java | 22 ++++++++++ .../dialect/sqlMonitor/ExecutorMonitor.java | 40 +++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorLog.java create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorMonitor.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorLog.java b/dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorLog.java new file mode 100644 index 00000000..78dc0964 --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorLog.java @@ -0,0 +1,22 @@ +package ydb.jimmer.dialect.sqlMonitor; + +import org.babyfish.jimmer.sql.runtime.ExecutionPurpose; + +import java.util.Collections; +import java.util.List; + +public class ExecutorLog { + private final String sql; + private final ExecutionPurpose purpose; + private final List> variablesList; + + public ExecutorLog(String sql, ExecutionPurpose purpose, List> variablesList) { + this.sql = sql; + this.purpose = purpose; + this.variablesList = variablesList; + } + + public static ExecutorLog simple(String sql, ExecutionPurpose purpose, List variables) { + return new ExecutorLog(sql, purpose, Collections.singletonList(variables)); + } +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorMonitor.java b/dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorMonitor.java new file mode 100644 index 00000000..50431aa3 --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorMonitor.java @@ -0,0 +1,40 @@ +package ydb.jimmer.dialect.sqlMonitor; + +import org.babyfish.jimmer.meta.ImmutableProp; +import org.babyfish.jimmer.sql.runtime.DefaultExecutor; +import org.babyfish.jimmer.sql.runtime.ExecutionPurpose; +import org.babyfish.jimmer.sql.runtime.Executor; +import org.babyfish.jimmer.sql.runtime.JSqlClientImplementor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.sql.Connection; +import java.util.ArrayList; +import java.util.List; + +public class ExecutorMonitor implements Executor { + private final Executor executor = DefaultExecutor.INSTANCE; + + private final List executorLogs = new ArrayList<>(); + + @Override + public R execute(@NotNull Args args) { + executorLogs.add(ExecutorLog.simple(args.sql, args.purpose, args.variables)); + return executor.execute(args); + } + + @Override + public BatchContext executeBatch( + @NotNull Connection con, + @NotNull String sql, + @Nullable ImmutableProp generatedIdProp, + @NotNull ExecutionPurpose purpose, + @NotNull JSqlClientImplementor sqlClient + ) { + return executor.executeBatch(con, sql, generatedIdProp, purpose, sqlClient); + } + + public List getLogs() { + return executorLogs; + } +} From eaf4f10fbbf5561b165c0550a82cec4e0afc7cda Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Wed, 4 Feb 2026 00:07:23 +0300 Subject: [PATCH 09/98] Initial integration test (pre-alpha) --- .../java/ydb/jimmer/dialect/QueryTest.java | 17 +++++ .../test/java/ydb/jimmer/dialect/YdbUtil.java | 70 +++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/QueryTest.java create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/YdbUtil.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/QueryTest.java b/dialect/src/test/java/ydb/jimmer/dialect/QueryTest.java new file mode 100644 index 00000000..3c8abaf7 --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/QueryTest.java @@ -0,0 +1,17 @@ +package ydb.jimmer.dialect; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import tech.ydb.test.junit5.YdbHelperExtension; + +import static ydb.jimmer.dialect.YdbUtil.initDatabase; + +public class QueryTest { + @RegisterExtension + private static final YdbHelperExtension ydb = new YdbHelperExtension(); + + @Test + public void OneEntityTest() { + initDatabase(); + } +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/YdbUtil.java b/dialect/src/test/java/ydb/jimmer/dialect/YdbUtil.java new file mode 100644 index 00000000..e5b87823 --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/YdbUtil.java @@ -0,0 +1,70 @@ +package ydb.jimmer.dialect; + +import org.babyfish.jimmer.sql.ast.query.TypedRootQuery; +import org.junit.jupiter.api.Assertions; +import org.springframework.core.io.UrlResource; +import org.springframework.core.io.support.EncodedResource; +import org.springframework.jdbc.datasource.SimpleDriverDataSource; +import org.springframework.jdbc.datasource.init.ScriptUtils; +import tech.ydb.jdbc.YdbDriver; + +import javax.sql.DataSource; +import java.net.URL; +import java.sql.Connection; +import java.sql.Driver; +import java.sql.SQLException; +import java.util.List; + +public final class YdbUtil { + private static final Driver DRIVER = new YdbDriver(); + private static final String URL = "jdbc:ydb:grpc://localhost:2136/local"; + + public static final DataSource YDB_DATA_SOURCE; + + static { + YDB_DATA_SOURCE = new SimpleDriverDataSource( + DRIVER, + URL + ); + } + + private YdbUtil() { + } + + public static void initDatabase() { + try (Connection connection = YDB_DATA_SOURCE.getConnection()) { + URL url = YdbUtil.class.getClassLoader().getResource("database-ydb.sql"); + if (url == null) { + throw new IllegalStateException("Cannot load 'database-ydb.sql'"); + } + ScriptUtils.executeSqlScript( + connection, + new EncodedResource(new UrlResource(url)), + false, + false, + "--", + ";", + "/*", + "*/"); + } catch (SQLException e) { + Assertions.fail("Database threw an exception: " + e.getMessage()); + } + } + + public static List connectAndExecute(boolean rollback, TypedRootQuery query) { + try (Connection connection = YDB_DATA_SOURCE.getConnection()) { + connection.setAutoCommit(!rollback); + try { + return query.execute(connection); + } finally { + if (rollback) { + connection.rollback(); + } + } + } catch (SQLException e) { + Assertions.fail("Database threw an exception: " + e.getMessage()); + } + + return null; + } +} From 88d30f9f70e9da8676ece119fb5f57a79a29212b Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Wed, 4 Feb 2026 00:08:09 +0300 Subject: [PATCH 10/98] Files to start the docker image of DB and stop it --- dialect/src/test/resources/docker-compose.yml | 21 +++++++++++++++++++ dialect/src/test/resources/install.sh | 17 +++++++++++++++ dialect/src/test/resources/uninstall.sh | 4 ++++ 3 files changed, 42 insertions(+) create mode 100644 dialect/src/test/resources/docker-compose.yml create mode 100644 dialect/src/test/resources/install.sh create mode 100644 dialect/src/test/resources/uninstall.sh diff --git a/dialect/src/test/resources/docker-compose.yml b/dialect/src/test/resources/docker-compose.yml new file mode 100644 index 00000000..bfdb3a9a --- /dev/null +++ b/dialect/src/test/resources/docker-compose.yml @@ -0,0 +1,21 @@ +services: + ydb: + image: ydbplatform/local-ydb:latest + container_name: jimmer_test_ydb + restart: always + platform: "linux/amd64" + ports: + - "2135:2135" + - "2136:2136" + - "8765:8765" + environment: + GRPC_TLS_PORT: 2135 + GRPC_PORT: 2136 + MON_PORT: 8765 + volumes: + - ydb_certs:/ydb_certs + - ydb_data:/ydb_data + +volumes: + ydb_certs: + ydb_data: \ No newline at end of file diff --git a/dialect/src/test/resources/install.sh b/dialect/src/test/resources/install.sh new file mode 100644 index 00000000..7e4946d5 --- /dev/null +++ b/dialect/src/test/resources/install.sh @@ -0,0 +1,17 @@ +docker run \ + --restart=always \ + -d --rm \ + --name jimmer_test_ydb \ + -h localhost \ + --platform linux/amd64 \ + -p 2135:2135 \ + -p 2136:2136 \ + -p 8765:8765 \ + -p 9092:9092 \ + -v $(pwd)/ydb_certs:/ydb_certs \ + -v $(pwd)/ydb_data:/ydb_data \ + -e GRPC_TLS_PORT=2135 \ + -e GRPC_PORT=2136 \ + -e MON_PORT=8765 \ + -e YDB_KAFKA_PROXY_PORT=9092 \ + ydbplatform/local-ydb:latest diff --git a/dialect/src/test/resources/uninstall.sh b/dialect/src/test/resources/uninstall.sh new file mode 100644 index 00000000..18083f39 --- /dev/null +++ b/dialect/src/test/resources/uninstall.sh @@ -0,0 +1,4 @@ +docker stop jimmer_test_ydb +docker rm jimmer_test_ydb +docker volume rm ydb_certs +docker volume rm ydb_data \ No newline at end of file From 495a77fea491721fc30f4c63bfda9d263180a101 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Wed, 4 Feb 2026 00:08:27 +0300 Subject: [PATCH 11/98] sql file for creating tables for models --- dialect/src/test/resources/database-ydb.sql | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 dialect/src/test/resources/database-ydb.sql diff --git a/dialect/src/test/resources/database-ydb.sql b/dialect/src/test/resources/database-ydb.sql new file mode 100644 index 00000000..0a39e55d --- /dev/null +++ b/dialect/src/test/resources/database-ydb.sql @@ -0,0 +1,14 @@ +CREATE TABLE group ( + id Uuid, + name String, + PRIMARY KEY (id) +); + +CREATE TABLE student ( + id Uuid, + name String, + group Uuid, + PRIMARY KEY (id) +); + +COMMIT; \ No newline at end of file From 9658e1dbeebe69b9577e41215741f9e9a93ecbf5 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Wed, 4 Feb 2026 16:45:00 +0300 Subject: [PATCH 12/98] fixed test initialization 1. Started using YdbHelperExtension 2. fixed errors in the SQL file and added a check for dropping tables from the SQL file --- .../java/ydb/jimmer/dialect/QueryTest.java | 17 ---- .../java/ydb/jimmer/dialect/SelectTest.java | 17 ++++ .../test/java/ydb/jimmer/dialect/YdbTest.java | 92 +++++++++++++++++++ .../test/java/ydb/jimmer/dialect/YdbUtil.java | 70 -------------- .../resources/database-drop-tables-ydb.sql | 2 + dialect/src/test/resources/database-ydb.sql | 4 +- 6 files changed, 112 insertions(+), 90 deletions(-) delete mode 100644 dialect/src/test/java/ydb/jimmer/dialect/QueryTest.java create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/SelectTest.java create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java delete mode 100644 dialect/src/test/java/ydb/jimmer/dialect/YdbUtil.java create mode 100644 dialect/src/test/resources/database-drop-tables-ydb.sql diff --git a/dialect/src/test/java/ydb/jimmer/dialect/QueryTest.java b/dialect/src/test/java/ydb/jimmer/dialect/QueryTest.java deleted file mode 100644 index 3c8abaf7..00000000 --- a/dialect/src/test/java/ydb/jimmer/dialect/QueryTest.java +++ /dev/null @@ -1,17 +0,0 @@ -package ydb.jimmer.dialect; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; -import tech.ydb.test.junit5.YdbHelperExtension; - -import static ydb.jimmer.dialect.YdbUtil.initDatabase; - -public class QueryTest { - @RegisterExtension - private static final YdbHelperExtension ydb = new YdbHelperExtension(); - - @Test - public void OneEntityTest() { - initDatabase(); - } -} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/SelectTest.java b/dialect/src/test/java/ydb/jimmer/dialect/SelectTest.java new file mode 100644 index 00000000..3272b9b3 --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/SelectTest.java @@ -0,0 +1,17 @@ +package ydb.jimmer.dialect; + +import org.junit.jupiter.api.Test; +import ydb.jimmer.dialect.model.StudentTable; + +import java.sql.SQLException; + +public class SelectTest extends YdbTest { + @Test + public void OneEntityTest() throws SQLException { + initDatabase(); + + StudentTable table = StudentTable.$; + + + } +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java b/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java new file mode 100644 index 00000000..24c50684 --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java @@ -0,0 +1,92 @@ +package ydb.jimmer.dialect; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.springframework.core.io.UrlResource; +import org.springframework.core.io.support.EncodedResource; +import org.springframework.jdbc.datasource.init.ScriptException; +import org.springframework.jdbc.datasource.init.ScriptUtils; +import tech.ydb.test.junit5.YdbHelperExtension; + +import java.net.URL; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +public class YdbTest { + @RegisterExtension + private static final YdbHelperExtension ydb = new YdbHelperExtension(); + + public void initDatabase() { + try (Connection connection = DriverManager.getConnection(getJdbcURL())) { + URL dropTablesUrl = YdbTest.class.getClassLoader().getResource("database-drop-tables-ydb.sql"); + if (dropTablesUrl == null) { + throw new IllegalStateException("Cannot load 'database-drop-tables-ydb.sql'"); + } + try { + executeYqlScript(connection, dropTablesUrl); + } catch (ScriptException _) { + // + } + + URL url = YdbTest.class.getClassLoader().getResource("database-ydb.sql"); + if (url == null) { + throw new IllegalStateException("Cannot load 'database-ydb.sql'"); + } + executeYqlScript(connection, url); + try (PreparedStatement select = connection + .prepareStatement("select count(1) as cnt from group")) { + ResultSet rs = select.executeQuery(); + rs.next(); + Assertions.assertEquals(0, rs.getLong("cnt")); + } + } catch (SQLException e) { + Assertions.fail("Database threw an exception: " + e.getMessage()); + } + } + + private void executeYqlScript(Connection connection, URL url) throws ScriptException { + ScriptUtils.executeSqlScript( + connection, + new EncodedResource(new UrlResource(url)), + false, + false, + "--", + ";", + "/*", + "*/"); + } + + private String getJdbcURL() { + StringBuilder jdbc = new StringBuilder("jdbc:ydb:") + .append(ydb.useTls() ? "grpcs://" : "grpc://") + .append(ydb.endpoint()) + .append("/") + .append(ydb.database()); + + if (ydb.authToken() != null) { + jdbc.append("?").append("token=").append(ydb.authToken()); + } + + return jdbc.toString(); + } + +// public static List connectAndExecute(boolean rollback, TypedRootQuery query) { +// try (Connection connection = YDB_DATA_SOURCE.getConnection()) { +// connection.setAutoCommit(!rollback); +// try { +// return query.execute(connection); +// } finally { +// if (rollback) { +// connection.rollback(); +// } +// } +// } catch (SQLException e) { +// Assertions.fail("Database threw an exception: " + e.getMessage()); +// } +// +// return null; +// } +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/YdbUtil.java b/dialect/src/test/java/ydb/jimmer/dialect/YdbUtil.java deleted file mode 100644 index e5b87823..00000000 --- a/dialect/src/test/java/ydb/jimmer/dialect/YdbUtil.java +++ /dev/null @@ -1,70 +0,0 @@ -package ydb.jimmer.dialect; - -import org.babyfish.jimmer.sql.ast.query.TypedRootQuery; -import org.junit.jupiter.api.Assertions; -import org.springframework.core.io.UrlResource; -import org.springframework.core.io.support.EncodedResource; -import org.springframework.jdbc.datasource.SimpleDriverDataSource; -import org.springframework.jdbc.datasource.init.ScriptUtils; -import tech.ydb.jdbc.YdbDriver; - -import javax.sql.DataSource; -import java.net.URL; -import java.sql.Connection; -import java.sql.Driver; -import java.sql.SQLException; -import java.util.List; - -public final class YdbUtil { - private static final Driver DRIVER = new YdbDriver(); - private static final String URL = "jdbc:ydb:grpc://localhost:2136/local"; - - public static final DataSource YDB_DATA_SOURCE; - - static { - YDB_DATA_SOURCE = new SimpleDriverDataSource( - DRIVER, - URL - ); - } - - private YdbUtil() { - } - - public static void initDatabase() { - try (Connection connection = YDB_DATA_SOURCE.getConnection()) { - URL url = YdbUtil.class.getClassLoader().getResource("database-ydb.sql"); - if (url == null) { - throw new IllegalStateException("Cannot load 'database-ydb.sql'"); - } - ScriptUtils.executeSqlScript( - connection, - new EncodedResource(new UrlResource(url)), - false, - false, - "--", - ";", - "/*", - "*/"); - } catch (SQLException e) { - Assertions.fail("Database threw an exception: " + e.getMessage()); - } - } - - public static List connectAndExecute(boolean rollback, TypedRootQuery query) { - try (Connection connection = YDB_DATA_SOURCE.getConnection()) { - connection.setAutoCommit(!rollback); - try { - return query.execute(connection); - } finally { - if (rollback) { - connection.rollback(); - } - } - } catch (SQLException e) { - Assertions.fail("Database threw an exception: " + e.getMessage()); - } - - return null; - } -} diff --git a/dialect/src/test/resources/database-drop-tables-ydb.sql b/dialect/src/test/resources/database-drop-tables-ydb.sql new file mode 100644 index 00000000..0fc388ec --- /dev/null +++ b/dialect/src/test/resources/database-drop-tables-ydb.sql @@ -0,0 +1,2 @@ +DROP TABLE group; +DROP TABLE student; \ No newline at end of file diff --git a/dialect/src/test/resources/database-ydb.sql b/dialect/src/test/resources/database-ydb.sql index 0a39e55d..04c21071 100644 --- a/dialect/src/test/resources/database-ydb.sql +++ b/dialect/src/test/resources/database-ydb.sql @@ -9,6 +9,4 @@ CREATE TABLE student ( name String, group Uuid, PRIMARY KEY (id) -); - -COMMIT; \ No newline at end of file +); \ No newline at end of file From 0c99f2dfbf103e7223aceb43ec8ee370abd06502 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Wed, 4 Feb 2026 22:03:49 +0300 Subject: [PATCH 13/98] fixed the select test (pre-alpha) The test now successfully sends a "select" request to the DB. Next, there needs be a checker for the result and sql script generated --- .../java/ydb/jimmer/dialect/SelectTest.java | 6 +- .../test/java/ydb/jimmer/dialect/YdbTest.java | 71 +++++++++++++------ .../ydb/jimmer/dialect/model/Student.java | 10 ++- 3 files changed, 61 insertions(+), 26 deletions(-) diff --git a/dialect/src/test/java/ydb/jimmer/dialect/SelectTest.java b/dialect/src/test/java/ydb/jimmer/dialect/SelectTest.java index 3272b9b3..f3fb9045 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/SelectTest.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/SelectTest.java @@ -12,6 +12,10 @@ public void OneEntityTest() throws SQLException { StudentTable table = StudentTable.$; - + executeAndExpect( + getYqlClient() + .createQuery(table) + .select(table) + ); } } diff --git a/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java b/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java index 24c50684..45cec7c0 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java @@ -1,5 +1,8 @@ package ydb.jimmer.dialect; +import org.babyfish.jimmer.sql.JSqlClient; +import org.babyfish.jimmer.sql.ast.query.TypedRootQuery; +import org.babyfish.jimmer.sql.runtime.Executor; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.extension.RegisterExtension; import org.springframework.core.io.UrlResource; @@ -7,6 +10,8 @@ import org.springframework.jdbc.datasource.init.ScriptException; import org.springframework.jdbc.datasource.init.ScriptUtils; import tech.ydb.test.junit5.YdbHelperExtension; +import ydb.jimmer.dialect.sqlMonitor.ExecutorLog; +import ydb.jimmer.dialect.sqlMonitor.ExecutorMonitor; import java.net.URL; import java.sql.Connection; @@ -14,12 +19,27 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.List; public class YdbTest { @RegisterExtension private static final YdbHelperExtension ydb = new YdbHelperExtension(); - public void initDatabase() { + private static final Executor executor = new ExecutorMonitor(); + private static final JSqlClient yqlClient; + + static { + yqlClient = JSqlClient.newBuilder() + .setExecutor(executor) + .setDialect(new YdbDialect()) + .build(); + } + + protected JSqlClient getYqlClient() { + return yqlClient; + } + + protected void initDatabase() { try (Connection connection = DriverManager.getConnection(getJdbcURL())) { URL dropTablesUrl = YdbTest.class.getClassLoader().getResource("database-drop-tables-ydb.sql"); if (dropTablesUrl == null) { @@ -36,12 +56,12 @@ public void initDatabase() { throw new IllegalStateException("Cannot load 'database-ydb.sql'"); } executeYqlScript(connection, url); - try (PreparedStatement select = connection - .prepareStatement("select count(1) as cnt from group")) { - ResultSet rs = select.executeQuery(); - rs.next(); - Assertions.assertEquals(0, rs.getLong("cnt")); - } +// try (PreparedStatement select = connection +// .prepareStatement("select count(1) as cnt from group")) { +// ResultSet rs = select.executeQuery(); +// rs.next(); +// Assertions.assertEquals(0, rs.getLong("cnt")); +// } } catch (SQLException e) { Assertions.fail("Database threw an exception: " + e.getMessage()); } @@ -73,20 +93,25 @@ private String getJdbcURL() { return jdbc.toString(); } -// public static List connectAndExecute(boolean rollback, TypedRootQuery query) { -// try (Connection connection = YDB_DATA_SOURCE.getConnection()) { -// connection.setAutoCommit(!rollback); -// try { -// return query.execute(connection); -// } finally { -// if (rollback) { -// connection.rollback(); -// } -// } -// } catch (SQLException e) { -// Assertions.fail("Database threw an exception: " + e.getMessage()); -// } -// -// return null; -// } + public void executeAndExpect(TypedRootQuery query) { + List rows = connectAndExecute(true, query); + System.out.println(rows); + } + + protected List connectAndExecute(boolean rollback, TypedRootQuery query) { + try (Connection connection = DriverManager.getConnection(getJdbcURL())) { + connection.setAutoCommit(!rollback); + try { + return query.execute(connection); + } finally { + if (rollback) { + connection.rollback(); + } + } + } catch (SQLException e) { + Assertions.fail("Database threw an exception: " + e.getMessage()); + } + + return null; + } } diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/Student.java b/dialect/src/test/java/ydb/jimmer/dialect/model/Student.java index 3f4a5a0c..3ba0119b 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/model/Student.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/Student.java @@ -1,25 +1,31 @@ package ydb.jimmer.dialect.model; +import org.babyfish.jimmer.sql.Column; import org.babyfish.jimmer.sql.Entity; import org.babyfish.jimmer.sql.ForeignKeyType; import org.babyfish.jimmer.sql.GeneratedValue; import org.babyfish.jimmer.sql.Id; import org.babyfish.jimmer.sql.JoinColumn; import org.babyfish.jimmer.sql.ManyToOne; +import org.babyfish.jimmer.sql.Table; import org.babyfish.jimmer.sql.meta.UUIDIdGenerator; +import javax.annotation.Nullable; import java.util.UUID; @Entity +@Table(name = "student") public interface Student { @Id @GeneratedValue(generatorType = UUIDIdGenerator.class) + @Column(name = "id") UUID id(); - + @Column(name = "name") String name(); @ManyToOne - @JoinColumn(foreignKeyType = ForeignKeyType.FAKE) + @Nullable + @JoinColumn(name = "group", foreignKeyType = ForeignKeyType.FAKE) Group group(); } From 268cd6897c214187424c46793953d3b4aa7680f3 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Wed, 4 Feb 2026 22:13:04 +0300 Subject: [PATCH 14/98] Added table/column names to the Group model in tests --- dialect/src/test/java/ydb/jimmer/dialect/model/Group.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/Group.java b/dialect/src/test/java/ydb/jimmer/dialect/model/Group.java index 5f753294..cb69a3b0 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/model/Group.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/Group.java @@ -1,17 +1,22 @@ package ydb.jimmer.dialect.model; +import org.babyfish.jimmer.sql.Column; import org.babyfish.jimmer.sql.Entity; import org.babyfish.jimmer.sql.GeneratedValue; import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; import org.babyfish.jimmer.sql.meta.UUIDIdGenerator; import java.util.UUID; @Entity +@Table(name = "group") public interface Group { @Id @GeneratedValue(generatorType = UUIDIdGenerator.class) + @Column(name = "id") UUID id(); + @Column(name = "name") String name(); } From 18d732f910db0dbfe90392f3d1ce5ed2280c6db1 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Fri, 6 Feb 2026 15:33:21 +0300 Subject: [PATCH 15/98] simple "select" test has been implemented --- .../ydb/jimmer/dialect/QueryTestContext.java | 29 ++++++++++++++++ .../java/ydb/jimmer/dialect/SelectTest.java | 7 +++- .../test/java/ydb/jimmer/dialect/YdbTest.java | 10 +++--- .../dialect/sqlMonitor/ExecutorLog.java | 22 ------------ .../dialect/sqlMonitor/ExecutorMonitor.java | 8 ++--- .../jimmer/dialect/sqlMonitor/QueryLog.java | 34 +++++++++++++++++++ 6 files changed, 77 insertions(+), 33 deletions(-) create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java delete mode 100644 dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorLog.java create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/QueryLog.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java b/dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java new file mode 100644 index 00000000..f88fc8ab --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java @@ -0,0 +1,29 @@ +package ydb.jimmer.dialect; + +import org.junit.jupiter.api.Assertions; +import ydb.jimmer.dialect.sqlMonitor.QueryLog; + +import java.util.List; + +public class QueryTestContext { + private final List logs; + private final List rows; + + private int index = 0; + + public QueryTestContext(List logs, List rows) { + this.logs = logs; + this.rows = rows; + } + + public void nextStatement() { + index++; + } + + public void sql(String sql) { + Assertions.assertEquals( + sql.replace("--->", ""), + logs.get(index).getSql(), + "statements[" + index + "].sql"); + } +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/SelectTest.java b/dialect/src/test/java/ydb/jimmer/dialect/SelectTest.java index f3fb9045..4d2cfad8 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/SelectTest.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/SelectTest.java @@ -15,7 +15,12 @@ public void OneEntityTest() throws SQLException { executeAndExpect( getYqlClient() .createQuery(table) - .select(table) + .select(table), + cxt -> { + cxt.sql( + "select tb_1_.id, tb_1_.name, tb_1_.group " + + "from student tb_1_"); + } ); } } diff --git a/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java b/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java index 45cec7c0..c2f2835b 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java @@ -10,22 +10,20 @@ import org.springframework.jdbc.datasource.init.ScriptException; import org.springframework.jdbc.datasource.init.ScriptUtils; import tech.ydb.test.junit5.YdbHelperExtension; -import ydb.jimmer.dialect.sqlMonitor.ExecutorLog; import ydb.jimmer.dialect.sqlMonitor.ExecutorMonitor; import java.net.URL; import java.sql.Connection; import java.sql.DriverManager; -import java.sql.PreparedStatement; -import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; +import java.util.function.Consumer; public class YdbTest { @RegisterExtension private static final YdbHelperExtension ydb = new YdbHelperExtension(); - private static final Executor executor = new ExecutorMonitor(); + private static final ExecutorMonitor executor = new ExecutorMonitor(); private static final JSqlClient yqlClient; static { @@ -93,9 +91,9 @@ private String getJdbcURL() { return jdbc.toString(); } - public void executeAndExpect(TypedRootQuery query) { + public void executeAndExpect(TypedRootQuery query, Consumer block) { List rows = connectAndExecute(true, query); - System.out.println(rows); + block.accept(new QueryTestContext(executor.getLogs(), rows)); } protected List connectAndExecute(boolean rollback, TypedRootQuery query) { diff --git a/dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorLog.java b/dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorLog.java deleted file mode 100644 index 78dc0964..00000000 --- a/dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorLog.java +++ /dev/null @@ -1,22 +0,0 @@ -package ydb.jimmer.dialect.sqlMonitor; - -import org.babyfish.jimmer.sql.runtime.ExecutionPurpose; - -import java.util.Collections; -import java.util.List; - -public class ExecutorLog { - private final String sql; - private final ExecutionPurpose purpose; - private final List> variablesList; - - public ExecutorLog(String sql, ExecutionPurpose purpose, List> variablesList) { - this.sql = sql; - this.purpose = purpose; - this.variablesList = variablesList; - } - - public static ExecutorLog simple(String sql, ExecutionPurpose purpose, List variables) { - return new ExecutorLog(sql, purpose, Collections.singletonList(variables)); - } -} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorMonitor.java b/dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorMonitor.java index 50431aa3..b2a0a757 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorMonitor.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorMonitor.java @@ -15,11 +15,11 @@ public class ExecutorMonitor implements Executor { private final Executor executor = DefaultExecutor.INSTANCE; - private final List executorLogs = new ArrayList<>(); + private final List queryLogs = new ArrayList<>(); @Override public R execute(@NotNull Args args) { - executorLogs.add(ExecutorLog.simple(args.sql, args.purpose, args.variables)); + queryLogs.add(QueryLog.simple(args.sql, args.purpose, args.variables)); return executor.execute(args); } @@ -34,7 +34,7 @@ public BatchContext executeBatch( return executor.executeBatch(con, sql, generatedIdProp, purpose, sqlClient); } - public List getLogs() { - return executorLogs; + public List getLogs() { + return queryLogs; } } diff --git a/dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/QueryLog.java b/dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/QueryLog.java new file mode 100644 index 00000000..50fba64a --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/QueryLog.java @@ -0,0 +1,34 @@ +package ydb.jimmer.dialect.sqlMonitor; + +import org.babyfish.jimmer.sql.runtime.ExecutionPurpose; + +import java.util.Collections; +import java.util.List; + +public class QueryLog { + private final String sql; + private final ExecutionPurpose purpose; + private final List> variablesList; + + public QueryLog(String sql, ExecutionPurpose purpose, List> variablesList) { + this.sql = sql; + this.purpose = purpose; + this.variablesList = variablesList; + } + + public static QueryLog simple(String sql, ExecutionPurpose purpose, List variables) { + return new QueryLog(sql, purpose, Collections.singletonList(variables)); + } + + public String getSql() { + return sql; + } + + public ExecutionPurpose getPurpose() { + return purpose; + } + + public List> getVariablesList() { + return variablesList; + } +} From a0a3c31818a25deb3b94deb6d5a2cf3f41227fac Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Sat, 7 Feb 2026 13:43:43 +0300 Subject: [PATCH 16/98] Changed Java version from 25 to 17 Java version 17 is the minimum Java version to support all Jimmer features. --- dialect/pom.xml | 2 +- dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dialect/pom.xml b/dialect/pom.xml index 35dd39dc..cc6f5b6e 100644 --- a/dialect/pom.xml +++ b/dialect/pom.xml @@ -12,7 +12,7 @@ 0.9.117 7.0.2 - 25 + 17 diff --git a/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java b/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java index c2f2835b..363ae6dd 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java @@ -45,7 +45,7 @@ protected void initDatabase() { } try { executeYqlScript(connection, dropTablesUrl); - } catch (ScriptException _) { + } catch (ScriptException e) { // } From 5fe2f135731a693c5e95255d5406274e0b269c93 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Sat, 7 Feb 2026 16:30:02 +0300 Subject: [PATCH 17/98] Transaction cache table is now supported for YDB auto-increment has been replaced by Uuid generated by Java --- dialect/pom.xml | 7 + .../cache/UuidTransactionCacheOperator.java | 121 ++++++++++++++++++ .../java/ydb/jimmer/dialect/YdbDialect.java | 12 ++ 3 files changed, 140 insertions(+) create mode 100644 dialect/src/main/java/ydb/jimmer/cache/UuidTransactionCacheOperator.java diff --git a/dialect/pom.xml b/dialect/pom.xml index cc6f5b6e..1bbf75e3 100644 --- a/dialect/pom.xml +++ b/dialect/pom.xml @@ -28,6 +28,13 @@ json 20250517 + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + 2.21.0 + compile + org.junit.jupiter junit-jupiter diff --git a/dialect/src/main/java/ydb/jimmer/cache/UuidTransactionCacheOperator.java b/dialect/src/main/java/ydb/jimmer/cache/UuidTransactionCacheOperator.java new file mode 100644 index 00000000..8d6bb4f9 --- /dev/null +++ b/dialect/src/main/java/ydb/jimmer/cache/UuidTransactionCacheOperator.java @@ -0,0 +1,121 @@ +package ydb.jimmer.cache; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.babyfish.jimmer.jackson.ImmutableModule; +import org.babyfish.jimmer.meta.ImmutableProp; +import org.babyfish.jimmer.meta.ImmutableType; +import org.babyfish.jimmer.sql.cache.TransactionCacheOperator; +import org.babyfish.jimmer.sql.cache.UsedCache; +import org.babyfish.jimmer.sql.exception.ExecutionException; + +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.Collection; +import java.util.Collections; +import java.util.UUID; + +public class UuidTransactionCacheOperator extends TransactionCacheOperator { + public static final String TABLE_NAME = "JIMMER_TRANS_CACHE_OPERATOR"; + + private static final String ID = "ID"; + + private static final String IMMUTABLE_TYPE = "IMMUTABLE_TYPE"; + + private static final String IMMUTABLE_PROP = "IMMUTABLE_PROP"; + + private static final String CACHE_KEY = "CACHE_KEY"; + + private static final String REASON = "REASON"; + + private static final String INSERT_WITH_UUID = + "insert into " + + TABLE_NAME + "(" + + ID + + ", " + + IMMUTABLE_TYPE + + ", " + + IMMUTABLE_PROP + + ", " + + CACHE_KEY + + ", " + + REASON + + ") values(?, ?, ?, ?, ?)"; + + private final ObjectMapper mapper; + + public UuidTransactionCacheOperator() { + this(null, 32); + } + + public UuidTransactionCacheOperator(int batchSize) { + this(null, batchSize); + } + + public UuidTransactionCacheOperator(ObjectMapper mapper) { + this(mapper, 32); + } + + public UuidTransactionCacheOperator(ObjectMapper mapper, int batchSize) { + super(mapper, batchSize); + + if (batchSize < 1) { + throw new IllegalArgumentException("`batchSize` cannot be less than 1"); + } + this.mapper = mapper != null ? + mapper : + new ObjectMapper() + .registerModule(new JavaTimeModule()) + .registerModule(new ImmutableModule()); + } + + @Override + public void delete(UsedCache cache, Object key, Object reason) { + if (reason != null && !(reason instanceof String)) { + throw new IllegalArgumentException( + "The cache deletion reason can only be null or string when trigger type is `TRANSACTION_ONLY`" + ); + } + save(cache.type(), cache.prop(), Collections.singleton(key), (String) reason); + } + + @Override + public void deleteAll(UsedCache cache, Collection keys, Object reason) { + if (keys.isEmpty()) { + return; + } + if (reason != null && !(reason instanceof String)) { + throw new IllegalArgumentException( + "The cache deletion reason can only be null or string when trigger type is `TRANSACTION_ONLY`" + ); + } + save(cache.type(), cache.prop(), keys, (String) reason); + } + + private void save( + ImmutableType type, + ImmutableProp prop, + Collection keys, + String reason + ) { + sqlClient().getConnectionManager().execute(con -> { + try { + try (PreparedStatement stmt = con.prepareStatement(INSERT_WITH_UUID)) { + for (Object key : keys) { + stmt.setString(1, UUID.randomUUID().toString()); + stmt.setString(2, type != null ? type.toString() : null); + stmt.setString(3, prop != null ? prop.toString() : null); + stmt.setString(4, mapper.writeValueAsString(key)); + stmt.setString(5, reason); + stmt.addBatch(); + } + stmt.executeBatch(); + } + } catch (SQLException | JsonProcessingException ex) { + throw new ExecutionException("Failed to save delayed cache deletion", ex); + } + return null; + }); + } +} diff --git a/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java b/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java index 9457a9e4..14aec159 100644 --- a/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java +++ b/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java @@ -188,6 +188,18 @@ public void upsert(UpsertContext ctx) { } } + @Override + public String transCacheOperatorTableDDL() { + return "CREATE TABLE JIMMER_TRANS_CACHE_OPERATOR(\n" + + "\tID Uuid NOT NULL,\n" + + "\tIMMUTABLE_TYPE String,\n" + + "\tIMMUTABLE_PROP String,\n" + + "\tCACHE_KEY String NOT NULL,\n" + + "\tREASON String,\n" + + "\tPRIMARY KEY(ID)\n" + + ")"; + } + @Override public void renderLPad(AbstractSqlBuilder builder, int currentPrecedence, Ast expression, Ast length, Ast padString) { throw new UnsupportedOperationException( From 61c475361bce425c2806d987f5058a3ebf2e1a3b Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Sat, 7 Feb 2026 16:36:31 +0300 Subject: [PATCH 18/98] Made transCacheOperatorTableDDL() look a bit nicer --- .../java/ydb/jimmer/dialect/YdbDialect.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java b/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java index 14aec159..2ce2077e 100644 --- a/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java +++ b/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java @@ -190,14 +190,15 @@ public void upsert(UpsertContext ctx) { @Override public String transCacheOperatorTableDDL() { - return "CREATE TABLE JIMMER_TRANS_CACHE_OPERATOR(\n" + - "\tID Uuid NOT NULL,\n" + - "\tIMMUTABLE_TYPE String,\n" + - "\tIMMUTABLE_PROP String,\n" + - "\tCACHE_KEY String NOT NULL,\n" + - "\tREASON String,\n" + - "\tPRIMARY KEY(ID)\n" + - ")"; + return """ + CREATE TABLE JIMMER_TRANS_CACHE_OPERATOR( + \tID Uuid NOT NULL, + \tIMMUTABLE_TYPE String, + \tIMMUTABLE_PROP String, + \tCACHE_KEY String NOT NULL, + \tREASON String, + \tPRIMARY KEY(ID) + )"""; } @Override From 2df198c1fdbd36b489a31968085e7d2162ee4478 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Sun, 8 Feb 2026 00:32:18 +0300 Subject: [PATCH 19/98] Moved classes to a different package --- .../jimmer/{cache => client}/UuidTransactionCacheOperator.java | 2 +- .../main/java/ydb/jimmer/{dialect => client}/YdbDialect.java | 2 +- dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename dialect/src/main/java/ydb/jimmer/{cache => client}/UuidTransactionCacheOperator.java (99%) rename dialect/src/main/java/ydb/jimmer/{dialect => client}/YdbDialect.java (99%) diff --git a/dialect/src/main/java/ydb/jimmer/cache/UuidTransactionCacheOperator.java b/dialect/src/main/java/ydb/jimmer/client/UuidTransactionCacheOperator.java similarity index 99% rename from dialect/src/main/java/ydb/jimmer/cache/UuidTransactionCacheOperator.java rename to dialect/src/main/java/ydb/jimmer/client/UuidTransactionCacheOperator.java index 8d6bb4f9..11337303 100644 --- a/dialect/src/main/java/ydb/jimmer/cache/UuidTransactionCacheOperator.java +++ b/dialect/src/main/java/ydb/jimmer/client/UuidTransactionCacheOperator.java @@ -1,4 +1,4 @@ -package ydb.jimmer.cache; +package ydb.jimmer.client; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; diff --git a/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java b/dialect/src/main/java/ydb/jimmer/client/YdbDialect.java similarity index 99% rename from dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java rename to dialect/src/main/java/ydb/jimmer/client/YdbDialect.java index 2ce2077e..9cb9619c 100644 --- a/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java +++ b/dialect/src/main/java/ydb/jimmer/client/YdbDialect.java @@ -1,4 +1,4 @@ -package ydb.jimmer.dialect; +package ydb.jimmer.client; import org.babyfish.jimmer.sql.ast.impl.Ast; import org.babyfish.jimmer.sql.ast.impl.Literals; diff --git a/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java b/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java index 363ae6dd..84d64be2 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java @@ -2,7 +2,6 @@ import org.babyfish.jimmer.sql.JSqlClient; import org.babyfish.jimmer.sql.ast.query.TypedRootQuery; -import org.babyfish.jimmer.sql.runtime.Executor; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.extension.RegisterExtension; import org.springframework.core.io.UrlResource; @@ -10,6 +9,7 @@ import org.springframework.jdbc.datasource.init.ScriptException; import org.springframework.jdbc.datasource.init.ScriptUtils; import tech.ydb.test.junit5.YdbHelperExtension; +import ydb.jimmer.client.YdbDialect; import ydb.jimmer.dialect.sqlMonitor.ExecutorMonitor; import java.net.URL; From a08ace7a0e7d4c439b054383c7a527ba3891000a Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Sun, 8 Feb 2026 19:23:28 +0300 Subject: [PATCH 20/98] renamed a package --- .../{client => dialect}/UuidTransactionCacheOperator.java | 2 +- .../main/java/ydb/jimmer/{client => dialect}/YdbDialect.java | 2 +- dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) rename dialect/src/main/java/ydb/jimmer/{client => dialect}/UuidTransactionCacheOperator.java (99%) rename dialect/src/main/java/ydb/jimmer/{client => dialect}/YdbDialect.java (99%) diff --git a/dialect/src/main/java/ydb/jimmer/client/UuidTransactionCacheOperator.java b/dialect/src/main/java/ydb/jimmer/dialect/UuidTransactionCacheOperator.java similarity index 99% rename from dialect/src/main/java/ydb/jimmer/client/UuidTransactionCacheOperator.java rename to dialect/src/main/java/ydb/jimmer/dialect/UuidTransactionCacheOperator.java index 11337303..213bb14a 100644 --- a/dialect/src/main/java/ydb/jimmer/client/UuidTransactionCacheOperator.java +++ b/dialect/src/main/java/ydb/jimmer/dialect/UuidTransactionCacheOperator.java @@ -1,4 +1,4 @@ -package ydb.jimmer.client; +package ydb.jimmer.dialect; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; diff --git a/dialect/src/main/java/ydb/jimmer/client/YdbDialect.java b/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java similarity index 99% rename from dialect/src/main/java/ydb/jimmer/client/YdbDialect.java rename to dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java index 9cb9619c..2ce2077e 100644 --- a/dialect/src/main/java/ydb/jimmer/client/YdbDialect.java +++ b/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java @@ -1,4 +1,4 @@ -package ydb.jimmer.client; +package ydb.jimmer.dialect; import org.babyfish.jimmer.sql.ast.impl.Ast; import org.babyfish.jimmer.sql.ast.impl.Literals; diff --git a/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java b/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java index 84d64be2..f8053859 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java @@ -9,7 +9,6 @@ import org.springframework.jdbc.datasource.init.ScriptException; import org.springframework.jdbc.datasource.init.ScriptUtils; import tech.ydb.test.junit5.YdbHelperExtension; -import ydb.jimmer.client.YdbDialect; import ydb.jimmer.dialect.sqlMonitor.ExecutorMonitor; import java.net.URL; From 7ee5bd1f889e5add201b6eeb48b7bb8a83ac5bc8 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Tue, 10 Feb 2026 17:26:11 +0300 Subject: [PATCH 21/98] Added tests for YDB data types --- .../java/ydb/jimmer/dialect/DataTypeTest.java | 226 ++++++++++++++++++ .../ydb/jimmer/dialect/QueryTestContext.java | 24 ++ .../test/java/ydb/jimmer/dialect/YdbTest.java | 17 +- .../jimmer/dialect/model/type/YdbBool.java | 17 ++ .../jimmer/dialect/model/type/YdbDate.java | 19 ++ .../jimmer/dialect/model/type/YdbDate32.java | 19 ++ .../dialect/model/type/YdbDateTime64.java | 19 ++ .../jimmer/dialect/model/type/YdbDecimal.java | 19 ++ .../jimmer/dialect/model/type/YdbDouble.java | 17 ++ .../jimmer/dialect/model/type/YdbFloat.java | 17 ++ .../jimmer/dialect/model/type/YdbInt16.java | 17 ++ .../jimmer/dialect/model/type/YdbInt32.java | 17 ++ .../jimmer/dialect/model/type/YdbInt64.java | 17 ++ .../jimmer/dialect/model/type/YdbInt8.java | 17 ++ .../jimmer/dialect/model/type/YdbJson.java | 18 ++ .../jimmer/dialect/model/type/YdbString.java | 17 ++ .../dialect/model/type/YdbTimestamp.java | 19 ++ .../dialect/model/type/YdbTimestamp64.java | 19 ++ .../jimmer/dialect/model/type/YdbUuid.java | 19 ++ .../dialect/sqlMonitor/ExecutorMonitor.java | 6 +- 20 files changed, 552 insertions(+), 8 deletions(-) create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/DataTypeTest.java create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbBool.java create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDate.java create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDate32.java create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDateTime64.java create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDecimal.java create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDouble.java create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbFloat.java create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInt16.java create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInt32.java create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInt64.java create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInt8.java create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbJson.java create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbString.java create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbTimestamp.java create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbTimestamp64.java create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbUuid.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/DataTypeTest.java b/dialect/src/test/java/ydb/jimmer/dialect/DataTypeTest.java new file mode 100644 index 00000000..5fd20def --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/DataTypeTest.java @@ -0,0 +1,226 @@ +package ydb.jimmer.dialect; + +import org.babyfish.jimmer.sql.ast.PropExpression; +import org.babyfish.jimmer.sql.ast.table.spi.AbstractTypedTable; +import org.junit.jupiter.api.Test; +import ydb.jimmer.dialect.model.type.YdbBoolTable; +import ydb.jimmer.dialect.model.type.YdbDate32Table; +import ydb.jimmer.dialect.model.type.YdbDateTable; +import ydb.jimmer.dialect.model.type.YdbDateTime64Table; +import ydb.jimmer.dialect.model.type.YdbDecimalTable; +import ydb.jimmer.dialect.model.type.YdbDoubleTable; +import ydb.jimmer.dialect.model.type.YdbFloatTable; +import ydb.jimmer.dialect.model.type.YdbInt16Table; +import ydb.jimmer.dialect.model.type.YdbInt32Table; +import ydb.jimmer.dialect.model.type.YdbInt64Table; +import ydb.jimmer.dialect.model.type.YdbInt8Table; +import ydb.jimmer.dialect.model.type.YdbStringTable; +import ydb.jimmer.dialect.model.type.YdbTimestamp64Table; +import ydb.jimmer.dialect.model.type.YdbTimestampTable; +import ydb.jimmer.dialect.model.type.YdbUuidTable; + +public class DataTypeTest extends YdbTest { + private void createTable(String tableName, String typeName) { + executeSql( + "CREATE TABLE " + tableName + "(" + + "id Int8," + + "value " + typeName + "," + + "PRIMARY KEY (id)" + + ")"); + } + + private void insert(String tableName, String... values) { + if (values.length == 0) { + return; + } + StringBuilder sql = new StringBuilder("INSERT INTO " + tableName + " (id, value) VALUES "); + for (int i = 0; i < values.length; i++) { + if (i > 0) { + sql.append(", "); + } + sql.append("(").append(i).append(", ").append(values[i]).append(")"); + } + executeSql(sql.toString()); + } + + /** + * + * @param typeName + * @param table + * @param prop + * @param valuesToInsert + * @param expectedValues expected and sorted (ASC) return values of the query + */ + private void typeTest(String tableName, + String typeName, + AbstractTypedTable table, + PropExpression prop, + String[] valuesToInsert, + String[] expectedValues) { + createTable(tableName, typeName); + + insert(tableName, valuesToInsert); + + StringBuilder json = new StringBuilder("["); + for (int i = 0; i < valuesToInsert.length; i++) { + if (json.length() != 1) { + json.append(","); + } + json.append("{"); + json.append("\"id\":").append(i).append(",\"value\":").append(expectedValues[i]); + json.append("}"); + } + json.append("]"); + + executeAndExpect( + getYqlClient() + .createQuery(table) + .orderBy(prop) + .select(table), + cxt -> { + cxt.sql( + "select tb_1_.id, tb_1_.value from " + tableName + " tb_1_ order by tb_1_.value asc"); + cxt.rows(json.toString()); + } + ); + } + + @Test + public void boolTest() { + String[] valuesToInsert = new String[]{"false", "true"}; + String[] expectedValues = new String[]{"false", "true"}; + typeTest("ydb_test", "Bool", + YdbBoolTable.$, YdbBoolTable.$.value(), + valuesToInsert, expectedValues); + } + + @Test + public void dateTest() { + String[] valuesToInsert = new String[]{"Date(\"2000-01-01\")", "DATE(\"2017-11-27\")"}; + String[] expectedValues = new String[]{"\"2000-01-01\"", "\"2017-11-27\""}; + typeTest("ydb_date", "Date", + YdbDateTable.$, YdbDateTable.$.value(), + valuesToInsert, expectedValues); + } + + @Test + public void date32Test() { + String[] valuesToInsert = new String[]{"Date32(\"144169-01-01\")"}; + String[] expectedValues = new String[]{"\"+144169-01-01\""}; + typeTest("ydb_date32", "Date32", + YdbDate32Table.$, YdbDate32Table.$.value(), + valuesToInsert, expectedValues); + } + + @Test + public void dateTime64Test() { + String[] valuesToInsert = new String[]{"DateTime64(\"2017-11-27T13:24:00Z\")"}; + String[] expectedValues = new String[]{"\"2017-11-27T13:24:00\""}; + typeTest("ydb_dateTime64", "DateTime64", + YdbDateTime64Table.$, YdbDateTime64Table.$.value(), + valuesToInsert, expectedValues); + } + + @Test + public void decimalTest() { + String[] valuesToInsert = new String[]{"Decimal(\"1.23\", 5, 2)"}; + String[] expectedValues = new String[]{"1.23"}; + typeTest("ydb_decimal", "Decimal(5, 2)", + YdbDecimalTable.$, YdbDecimalTable.$.value(), + valuesToInsert, expectedValues); + } + + @Test + public void doubleTest() { + String[] valuesToInsert = new String[]{"Double(\"1.23\")"}; + String[] expectedValues = new String[]{"1.23"}; + typeTest("ydb_double", "Double", + YdbDoubleTable.$, YdbDoubleTable.$.value(), + valuesToInsert, expectedValues); + } + + @Test + public void floatTest() { + String[] valuesToInsert = new String[]{"Float(\"1.23\")"}; + String[] expectedValues = new String[]{"1.23"}; + typeTest("ydb_float", "Float", + YdbFloatTable.$, YdbFloatTable.$.value(), + valuesToInsert, expectedValues); + } + + @Test + public void int8Test() { + String[] valuesToInsert = new String[]{"-1", "0", "10"}; + String[] expectedValues = new String[]{"-1", "0", "10"}; + typeTest("ydb_int8", "Int8", + YdbInt8Table.$, YdbInt8Table.$.value(), + valuesToInsert, expectedValues); + } + + @Test + public void int16Test() { + String[] valuesToInsert = new String[]{"-1", "0", "10"}; + String[] expectedValues = new String[]{"-1", "0", "10"}; + typeTest("ydb_int16", "Int16", + YdbInt16Table.$, YdbInt16Table.$.value(), + valuesToInsert, expectedValues); + } + + @Test + public void int32Test() { + String[] valuesToInsert = new String[]{"-1", "0", "10"}; + String[] expectedValues = new String[]{"-1", "0", "10"}; + typeTest("ydb_int32", "Int32", + YdbInt32Table.$, YdbInt32Table.$.value(), + valuesToInsert, expectedValues); + } + + @Test + public void int64Test() { + String[] valuesToInsert = new String[]{"-1", "0", "10"}; + String[] expectedValues = new String[]{"-1", "0", "10"}; + typeTest("ydb_int64", "Int64", + YdbInt64Table.$, YdbInt64Table.$.value(), + valuesToInsert, expectedValues); + } + + @Test + public void stringTest() { + String[] valuesToInsert = new String[]{"\"0\"", "\"string\""}; + String[] expectedValues = new String[]{"\"0\"", "\"string\""}; + typeTest("ydb_string", "String", + YdbStringTable.$, YdbStringTable.$.value(), + valuesToInsert, expectedValues); + } + + @Test + public void timestampTest() { + String[] valuesToInsert = new String[]{"Timestamp(\"2017-11-27T13:24:00.123456Z\")"}; + String[] expectedValues = new String[]{"\"2017-11-27T13:24:00.123456\""}; + typeTest("ydb_timestamp", "Timestamp", + YdbTimestampTable.$, YdbTimestampTable.$.value(), + valuesToInsert, expectedValues); + } + + @Test + public void timestamp64Test() { + String[] valuesToInsert = new String[]{"Timestamp64(\"2017-11-27T13:24:00.123456Z\")"}; + String[] expectedValues = new String[]{"\"2017-11-27T13:24:00.123456\""}; + typeTest("ydb_timestamp64", "Timestamp64", + YdbTimestamp64Table.$, YdbTimestamp64Table.$.value(), + valuesToInsert, expectedValues); + } + + @Test + public void uuidTest() { + String[] valuesToInsert = new String[]{ + "Uuid(\"9e197d65-1914-4d57-a65f-77a52a06baa7\")", + "Uuid(\"8e0f2cf4-4656-4d73-970e-a18be9ead78b\")"}; + String[] expectedValues = new String[]{ + "\"9e197d65-1914-4d57-a65f-77a52a06baa7\"", + "\"8e0f2cf4-4656-4d73-970e-a18be9ead78b\""}; + typeTest("ydb_uuid", "Uuid", + YdbUuidTable.$, YdbUuidTable.$.value(), + valuesToInsert, expectedValues); + } +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java b/dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java index f88fc8ab..88a4a53d 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java @@ -1,11 +1,24 @@ package ydb.jimmer.dialect; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.babyfish.jimmer.jackson.ImmutableModule; import org.junit.jupiter.api.Assertions; import ydb.jimmer.dialect.sqlMonitor.QueryLog; +import java.text.SimpleDateFormat; import java.util.List; public class QueryTestContext { + private static final ObjectMapper MAPPER = new ObjectMapper() + .registerModule(new ImmutableModule()) + .registerModule(new JavaTimeModule()); + + static { + MAPPER.setDateFormat(new SimpleDateFormat("yyyy-MM-dd")); + } + private final List logs; private final List rows; @@ -26,4 +39,15 @@ public void sql(String sql) { logs.get(index).getSql(), "statements[" + index + "].sql"); } + + public void rows(String json) { + try { + Assertions.assertEquals( + json.replace("--->", ""), + MAPPER.writeValueAsString(rows) + ); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } } diff --git a/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java b/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java index f8053859..0bd1c5e4 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java @@ -15,6 +15,7 @@ import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; +import java.sql.Statement; import java.util.List; import java.util.function.Consumer; @@ -53,12 +54,6 @@ protected void initDatabase() { throw new IllegalStateException("Cannot load 'database-ydb.sql'"); } executeYqlScript(connection, url); -// try (PreparedStatement select = connection -// .prepareStatement("select count(1) as cnt from group")) { -// ResultSet rs = select.executeQuery(); -// rs.next(); -// Assertions.assertEquals(0, rs.getLong("cnt")); -// } } catch (SQLException e) { Assertions.fail("Database threw an exception: " + e.getMessage()); } @@ -111,4 +106,14 @@ protected List connectAndExecute(boolean rollback, TypedRootQuery quer return null; } + + protected void executeSql(String sql) { + try (Connection connection = DriverManager.getConnection(getJdbcURL())) { + try (Statement stmt = connection.createStatement()) { + stmt.execute(sql); + } + } catch (SQLException e) { + Assertions.fail("Database threw an exception: " + e.getMessage()); + } + } } diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbBool.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbBool.java new file mode 100644 index 00000000..f05311fa --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbBool.java @@ -0,0 +1,17 @@ +package ydb.jimmer.dialect.model.type; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +@Entity +@Table(name = "ydb_test") +public interface YdbBool { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + boolean value(); +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDate.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDate.java new file mode 100644 index 00000000..8a0c1ebf --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDate.java @@ -0,0 +1,19 @@ +package ydb.jimmer.dialect.model.type; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +import java.sql.Date; + +@Entity +@Table(name = "ydb_date") +public interface YdbDate { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + Date value(); +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDate32.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDate32.java new file mode 100644 index 00000000..45f1541a --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDate32.java @@ -0,0 +1,19 @@ +package ydb.jimmer.dialect.model.type; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +import java.time.LocalDate; + +@Entity +@Table(name = "ydb_date32") +public interface YdbDate32 { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + LocalDate value(); +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDateTime64.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDateTime64.java new file mode 100644 index 00000000..4c9f3662 --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDateTime64.java @@ -0,0 +1,19 @@ +package ydb.jimmer.dialect.model.type; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +import java.time.LocalDateTime; + +@Entity +@Table(name = "ydb_dateTime64") +public interface YdbDateTime64 { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + LocalDateTime value(); +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDecimal.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDecimal.java new file mode 100644 index 00000000..ecbff4c8 --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDecimal.java @@ -0,0 +1,19 @@ +package ydb.jimmer.dialect.model.type; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +import java.math.BigDecimal; + +@Entity +@Table(name = "ydb_decimal") +public interface YdbDecimal { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + BigDecimal value(); +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDouble.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDouble.java new file mode 100644 index 00000000..21f5a42b --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDouble.java @@ -0,0 +1,17 @@ +package ydb.jimmer.dialect.model.type; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +@Entity +@Table(name = "ydb_double") +public interface YdbDouble { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + double value(); +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbFloat.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbFloat.java new file mode 100644 index 00000000..c3e70dca --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbFloat.java @@ -0,0 +1,17 @@ +package ydb.jimmer.dialect.model.type; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +@Entity +@Table(name = "ydb_float") +public interface YdbFloat { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + float value(); +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInt16.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInt16.java new file mode 100644 index 00000000..3db0ce59 --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInt16.java @@ -0,0 +1,17 @@ +package ydb.jimmer.dialect.model.type; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +@Entity +@Table(name = "ydb_int16") +public interface YdbInt16 { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + short value(); +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInt32.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInt32.java new file mode 100644 index 00000000..12ab7df8 --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInt32.java @@ -0,0 +1,17 @@ +package ydb.jimmer.dialect.model.type; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +@Entity +@Table(name = "ydb_int32") +public interface YdbInt32 { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + int value(); +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInt64.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInt64.java new file mode 100644 index 00000000..bf1514ed --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInt64.java @@ -0,0 +1,17 @@ +package ydb.jimmer.dialect.model.type; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +@Entity +@Table(name = "ydb_int64") +public interface YdbInt64 { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + long value(); +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInt8.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInt8.java new file mode 100644 index 00000000..1984935b --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInt8.java @@ -0,0 +1,17 @@ +package ydb.jimmer.dialect.model.type; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +@Entity +@Table(name = "ydb_int8") +public interface YdbInt8 { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + byte value(); +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbJson.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbJson.java new file mode 100644 index 00000000..40fc1ce4 --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbJson.java @@ -0,0 +1,18 @@ +package ydb.jimmer.dialect.model.type; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; +import org.json.JSONObject; + +@Entity +@Table(name = "ydb_json") +public interface YdbJson { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + JSONObject value(); +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbString.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbString.java new file mode 100644 index 00000000..ab8747d9 --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbString.java @@ -0,0 +1,17 @@ +package ydb.jimmer.dialect.model.type; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +@Entity +@Table(name = "ydb_string") +public interface YdbString { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + String value(); +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbTimestamp.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbTimestamp.java new file mode 100644 index 00000000..f25c5ce8 --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbTimestamp.java @@ -0,0 +1,19 @@ +package ydb.jimmer.dialect.model.type; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +import java.sql.Time; + +@Entity +@Table(name = "ydb_timestamp") +public interface YdbTimestamp { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + Time value(); +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbTimestamp64.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbTimestamp64.java new file mode 100644 index 00000000..7091e2b5 --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbTimestamp64.java @@ -0,0 +1,19 @@ +package ydb.jimmer.dialect.model.type; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +import java.time.LocalTime; + +@Entity +@Table(name = "ydb_timestamp64") +public interface YdbTimestamp64 { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + LocalTime value(); +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbUuid.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbUuid.java new file mode 100644 index 00000000..1fe3ee5c --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbUuid.java @@ -0,0 +1,19 @@ +package ydb.jimmer.dialect.model.type; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +import java.util.UUID; + +@Entity +@Table(name = "ydb_uuid") +public interface YdbUuid { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + UUID value(); +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorMonitor.java b/dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorMonitor.java index b2a0a757..d218f33e 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorMonitor.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorMonitor.java @@ -15,7 +15,7 @@ public class ExecutorMonitor implements Executor { private final Executor executor = DefaultExecutor.INSTANCE; - private final List queryLogs = new ArrayList<>(); + private List queryLogs = new ArrayList<>(); @Override public R execute(@NotNull Args args) { @@ -35,6 +35,8 @@ public BatchContext executeBatch( } public List getLogs() { - return queryLogs; + List tmp = queryLogs; + queryLogs = new ArrayList<>(); + return tmp; } } From d3094f97973d31fe702db637ad0289300c3e2eb4 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Thu, 12 Feb 2026 15:15:31 +0300 Subject: [PATCH 22/98] added YDB JDBC type constants --- .../ydb/jimmer/dialect/constant/YdbConst.java | 8 ++ .../jimmer/dialect/constant/YdbJdbcTypes.java | 136 ++++++++++++++++++ 2 files changed, 144 insertions(+) create mode 100644 dialect/src/main/java/ydb/jimmer/dialect/constant/YdbConst.java create mode 100644 dialect/src/main/java/ydb/jimmer/dialect/constant/YdbJdbcTypes.java diff --git a/dialect/src/main/java/ydb/jimmer/dialect/constant/YdbConst.java b/dialect/src/main/java/ydb/jimmer/dialect/constant/YdbConst.java new file mode 100644 index 00000000..d5547cc5 --- /dev/null +++ b/dialect/src/main/java/ydb/jimmer/dialect/constant/YdbConst.java @@ -0,0 +1,8 @@ +package ydb.jimmer.dialect.constant; + +public final class YdbConst { + private YdbConst() {} + + public static final int SQL_KIND_PRIMITIVE = 10000; + public static final int SQL_KIND_DECIMAL = 1 << 14; // 16384 +} diff --git a/dialect/src/main/java/ydb/jimmer/dialect/constant/YdbJdbcTypes.java b/dialect/src/main/java/ydb/jimmer/dialect/constant/YdbJdbcTypes.java new file mode 100644 index 00000000..3674fff0 --- /dev/null +++ b/dialect/src/main/java/ydb/jimmer/dialect/constant/YdbJdbcTypes.java @@ -0,0 +1,136 @@ +package ydb.jimmer.dialect.constant; + +public final class YdbJdbcTypes { + private YdbJdbcTypes() {} + + /** Boolean value. */ + public static final int BOOL = YdbConst.SQL_KIND_PRIMITIVE; + + /** A signed integer. Acceptable values: from -2^7 to 2^7–1. Not supported for table columns */ + public static final int INT8 = YdbConst.SQL_KIND_PRIMITIVE + 1; + + /** An unsigned integer. Acceptable values: from 0 to 2^8–1. */ + public static final int UINT8 = YdbConst.SQL_KIND_PRIMITIVE + 2; + + /** A signed integer. Acceptable values: from –2^15 to 2^15–1. Not supported for table columns */ + public static final int INT16 = YdbConst.SQL_KIND_PRIMITIVE + 3; + + /** An unsigned integer. Acceptable values: from 0 to 2^16–1. Not supported for table columns */ + public static final int UINT16 = YdbConst.SQL_KIND_PRIMITIVE + 4; + + /** A signed integer. Acceptable values: from –2^31 to 2^31–1. */ + public static final int INT32 = YdbConst.SQL_KIND_PRIMITIVE + 5; + + /** An unsigned integer. Acceptable values: from 0 to 2^32–1. */ + public static final int UINT32 = YdbConst.SQL_KIND_PRIMITIVE + 6; + + /** A signed integer. Acceptable values: from –2^63 to 2^63–1. */ + public static final int INT64 = YdbConst.SQL_KIND_PRIMITIVE + 7; + + /** An unsigned integer. Acceptable values: from 0 to 2^64–1. */ + public static final int UINT64 = YdbConst.SQL_KIND_PRIMITIVE + 8; + + /** A real number with variable precision, 4 bytes in size. Can't be used in the primary key */ + public static final int FLOAT = YdbConst.SQL_KIND_PRIMITIVE + 9; + + /** A real number with variable precision, 8 bytes in size. Can't be used in the primary key */ + public static final int DOUBLE = YdbConst.SQL_KIND_PRIMITIVE + 10; + + /** A binary data, synonym for YDB type String */ + public static final int BYTES = YdbConst.SQL_KIND_PRIMITIVE + 11; + + /** Text encoded in UTF-8, synonym for YDB type Utf8 */ + public static final int TEXT = YdbConst.SQL_KIND_PRIMITIVE + 12; + + /** YSON in a textual or binary representation. Doesn't support matching, can't be used in the primary key */ + public static final int YSON = YdbConst.SQL_KIND_PRIMITIVE + 13; + + /** JSON represented as text. Doesn't support matching, can't be used in the primary key */ + public static final int JSON = YdbConst.SQL_KIND_PRIMITIVE + 14; + + /** Universally unique identifier UUID. Not supported for table columns */ + public static final int UUID = YdbConst.SQL_KIND_PRIMITIVE + 15; + + /** + * A moment in time corresponding to midnight in UTC, precision to the day. + *

+ * Possible values: + * from 00:00 01.01.1970 to 00:00 01.01.2106 + */ + public static final int DATE = YdbConst.SQL_KIND_PRIMITIVE + 16; + + /** + * A moment in time in UTC, precision to the second + *

+ * Possible values: + * from 00:00 01.01.1970 to 00:00 01.01.2106 + */ + public static final int DATETIME = YdbConst.SQL_KIND_PRIMITIVE + 17; + + /** + * A moment in time in UTC, precision to the microsecond + *

+ * Possible values: + * from 00:00 01.01.1970 to 00:00 01.01.2106 + */ + public static final int TIMESTAMP = YdbConst.SQL_KIND_PRIMITIVE + 18; + + /** + * Time interval, precision to the microsecond + *

+ * Possible values: + * from -136 years to +136 years + */ + public static final int INTERVAL = YdbConst.SQL_KIND_PRIMITIVE + 19; + + /** Date with time zone label, precision to the day */ + public static final int TZ_DATE = YdbConst.SQL_KIND_PRIMITIVE + 20; + + /** Date/time with time zone label, precision to the second */ + public static final int TZ_DATETIME = YdbConst.SQL_KIND_PRIMITIVE + 21; + + /** Date/time with time zone label, precision to the microsecond */ + public static final int TZ_TIMESTAMP = YdbConst.SQL_KIND_PRIMITIVE + 22; + + /** JSON in an indexed binary representation. Doesn't support matching, can't be used in the primary key */ + public static final int JSON_DOCUMENT = YdbConst.SQL_KIND_PRIMITIVE + 23; + + /** + * A moment in time corresponding to midnight in UTC, precision to the day. + *

+ * Possible values: + * from 00:00 01.01.144169 BC to 00:00 01.01.148107 AD + */ + public static final int DATE32 = YdbConst.SQL_KIND_PRIMITIVE + 25; + + /** + * A moment in time in UTC, precision to the second + *

+ * Possible values: + * from 00:00 01.01.144169 BC to 00:00 01.01.148107 AD + */ + public static final int DATETIME64 = YdbConst.SQL_KIND_PRIMITIVE + 26; + + /** + * A moment in time in UTC, precision to the microsecond + *

+ * Possible values: + * from 00:00 01.01.144169 BC to 00:00 01.01.148107 AD + */ + public static final int TIMESTAMP64 = YdbConst.SQL_KIND_PRIMITIVE + 27; + + /** + * Time interval, precision to the microsecond + *

+ * Possible values: + * from -292277 years to +292277 years + */ + public static final int INTERVAL64 = YdbConst.SQL_KIND_PRIMITIVE + 28; + + /** + * Real number with fixed precision + *

+ * Default value + */ + public static final int DECIMAL_22_9 = YdbConst.SQL_KIND_DECIMAL + (22 << 6) + 9; +} From db8d0fe82bc802792f15d5660f31452802a4670e Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Thu, 12 Feb 2026 15:52:31 +0300 Subject: [PATCH 23/98] Removed Timestamp from tests --- .../java/ydb/jimmer/dialect/DataTypeTest.java | 14 ++------------ .../dialect/model/type/YdbTimestamp.java | 19 ------------------- .../dialect/model/type/YdbTimestamp64.java | 4 ++-- 3 files changed, 4 insertions(+), 33 deletions(-) delete mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbTimestamp.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/DataTypeTest.java b/dialect/src/test/java/ydb/jimmer/dialect/DataTypeTest.java index 5fd20def..549e26b7 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/DataTypeTest.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/DataTypeTest.java @@ -16,7 +16,6 @@ import ydb.jimmer.dialect.model.type.YdbInt8Table; import ydb.jimmer.dialect.model.type.YdbStringTable; import ydb.jimmer.dialect.model.type.YdbTimestamp64Table; -import ydb.jimmer.dialect.model.type.YdbTimestampTable; import ydb.jimmer.dialect.model.type.YdbUuidTable; public class DataTypeTest extends YdbTest { @@ -96,7 +95,7 @@ public void boolTest() { @Test public void dateTest() { - String[] valuesToInsert = new String[]{"Date(\"2000-01-01\")", "DATE(\"2017-11-27\")"}; + String[] valuesToInsert = new String[]{"Date(\"2000-01-01\")", "Date(\"2017-11-27\")"}; String[] expectedValues = new String[]{"\"2000-01-01\"", "\"2017-11-27\""}; typeTest("ydb_date", "Date", YdbDateTable.$, YdbDateTable.$.value(), @@ -193,19 +192,10 @@ public void stringTest() { valuesToInsert, expectedValues); } - @Test - public void timestampTest() { - String[] valuesToInsert = new String[]{"Timestamp(\"2017-11-27T13:24:00.123456Z\")"}; - String[] expectedValues = new String[]{"\"2017-11-27T13:24:00.123456\""}; - typeTest("ydb_timestamp", "Timestamp", - YdbTimestampTable.$, YdbTimestampTable.$.value(), - valuesToInsert, expectedValues); - } - @Test public void timestamp64Test() { String[] valuesToInsert = new String[]{"Timestamp64(\"2017-11-27T13:24:00.123456Z\")"}; - String[] expectedValues = new String[]{"\"2017-11-27T13:24:00.123456\""}; + String[] expectedValues = new String[]{"\"2017-11-27T13:24:00.123456Z\""}; typeTest("ydb_timestamp64", "Timestamp64", YdbTimestamp64Table.$, YdbTimestamp64Table.$.value(), valuesToInsert, expectedValues); diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbTimestamp.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbTimestamp.java deleted file mode 100644 index f25c5ce8..00000000 --- a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbTimestamp.java +++ /dev/null @@ -1,19 +0,0 @@ -package ydb.jimmer.dialect.model.type; - -import org.babyfish.jimmer.sql.Column; -import org.babyfish.jimmer.sql.Entity; -import org.babyfish.jimmer.sql.Id; -import org.babyfish.jimmer.sql.Table; - -import java.sql.Time; - -@Entity -@Table(name = "ydb_timestamp") -public interface YdbTimestamp { - @Id - @Column(name = "id") - int getId(); - - @Column(name = "value") - Time value(); -} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbTimestamp64.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbTimestamp64.java index 7091e2b5..d1f94938 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbTimestamp64.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbTimestamp64.java @@ -5,7 +5,7 @@ import org.babyfish.jimmer.sql.Id; import org.babyfish.jimmer.sql.Table; -import java.time.LocalTime; +import java.time.Instant; @Entity @Table(name = "ydb_timestamp64") @@ -15,5 +15,5 @@ public interface YdbTimestamp64 { int getId(); @Column(name = "value") - LocalTime value(); + Instant value(); } From 01a0685e9e4fb1e3b80be32481004e1c7f4da2eb Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Thu, 12 Feb 2026 18:08:14 +0300 Subject: [PATCH 24/98] Fixed sqlType() Changed mapping of Java classes to SQL types to be the same as in the YDB JDBC --- .../java/ydb/jimmer/dialect/YdbDialect.java | 52 +++++++++---------- 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java b/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java index 2ce2077e..826d435c 100644 --- a/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java +++ b/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java @@ -9,56 +9,52 @@ import org.json.JSONObject; import java.math.BigDecimal; +import java.math.BigInteger; import java.sql.Date; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Time; import java.sql.Timestamp; +import java.time.Duration; +import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; -import java.time.OffsetDateTime; -import java.time.OffsetTime; -import java.time.ZonedDateTime; import java.util.UUID; public class YdbDialect extends DefaultDialect { @Override public String sqlType(Class elementType) { - if (elementType == String.class) { - return "String"; - } else if (elementType == UUID.class) { - return "Uuid"; - } else if (elementType == boolean.class) { + if (elementType == boolean.class || elementType == Boolean.class) { return "Bool"; - } else if (elementType == byte.class) { + } else if (elementType == byte.class || elementType == Byte.class) { return "Int8"; - } else if (elementType == short.class) { + } else if (elementType == short.class || elementType == Short.class) { return "Int16"; - } else if (elementType == int.class) { + } else if (elementType == int.class || elementType == Integer.class || elementType == LocalTime.class || elementType == Time.class) { return "Int32"; - } else if (elementType == long.class) { + } else if (elementType == long.class || elementType == Long.class || elementType == BigInteger.class) { return "Int64"; - } else if (elementType == float.class) { + } else if (elementType == float.class || elementType == Float.class) { return "Float"; - } else if (elementType == double.class) { + } else if (elementType == double.class || elementType == Double.class) { return "Double"; - } else if (elementType == BigDecimal.class) { - return "Decimal(35, 35)"; - } else if (elementType == Date.class) { - return "Date"; - } else if (elementType == LocalDate.class) { + } else if (elementType == String.class) { + return "Utf8"; + } else if (elementType == byte[].class) { + return "String"; + } else if (elementType == UUID.class) { + return "Uuid"; + } else if (elementType == Date.class || elementType == LocalDate.class) { return "Date32"; - } else if (elementType == Time.class || elementType == OffsetTime.class) { - return "Timestamp"; - } else if (elementType == LocalTime.class - || elementType == java.util.Date.class - || elementType == Timestamp.class) { + } else if (elementType == LocalDateTime.class) { + return "Datetime64"; + } else if (elementType == java.util.Date.class || elementType == Timestamp.class || elementType == Instant.class) { return "Timestamp64"; - } else if (elementType == LocalDateTime.class || elementType == OffsetDateTime.class) { - return "DateTime64"; - } else if (elementType == ZonedDateTime.class) { - return "TzDateTime64"; + } else if (elementType == BigDecimal.class) { + return "Decimal(22, 9)"; + } else if (elementType == Duration.class) { + return "Interval64"; } else { return null; } From 7bd0a93cd8b65fc7129f0839714696f44b590163 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Thu, 12 Feb 2026 18:52:23 +0300 Subject: [PATCH 25/98] Reworked sqlType() in YdbDialect and added resolveJdbcType() --- .../java/ydb/jimmer/dialect/YdbDialect.java | 56 +++++-------------- .../dialect/constant/YdbClassMapping.java | 52 +++++++++++++++++ 2 files changed, 65 insertions(+), 43 deletions(-) create mode 100644 dialect/src/main/java/ydb/jimmer/dialect/constant/YdbClassMapping.java diff --git a/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java b/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java index 826d435c..c571e2ad 100644 --- a/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java +++ b/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java @@ -8,56 +8,26 @@ import org.jetbrains.annotations.Nullable; import org.json.JSONObject; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.sql.Date; import java.sql.ResultSet; import java.sql.SQLException; -import java.sql.Time; -import java.sql.Timestamp; -import java.time.Duration; -import java.time.Instant; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.util.UUID; +import java.sql.Types; + +import static ydb.jimmer.dialect.constant.YdbClassMapping.classToJdbcType; +import static ydb.jimmer.dialect.constant.YdbClassMapping.classToYdbType; public class YdbDialect extends DefaultDialect { @Override public String sqlType(Class elementType) { - if (elementType == boolean.class || elementType == Boolean.class) { - return "Bool"; - } else if (elementType == byte.class || elementType == Byte.class) { - return "Int8"; - } else if (elementType == short.class || elementType == Short.class) { - return "Int16"; - } else if (elementType == int.class || elementType == Integer.class || elementType == LocalTime.class || elementType == Time.class) { - return "Int32"; - } else if (elementType == long.class || elementType == Long.class || elementType == BigInteger.class) { - return "Int64"; - } else if (elementType == float.class || elementType == Float.class) { - return "Float"; - } else if (elementType == double.class || elementType == Double.class) { - return "Double"; - } else if (elementType == String.class) { - return "Utf8"; - } else if (elementType == byte[].class) { - return "String"; - } else if (elementType == UUID.class) { - return "Uuid"; - } else if (elementType == Date.class || elementType == LocalDate.class) { - return "Date32"; - } else if (elementType == LocalDateTime.class) { - return "Datetime64"; - } else if (elementType == java.util.Date.class || elementType == Timestamp.class || elementType == Instant.class) { - return "Timestamp64"; - } else if (elementType == BigDecimal.class) { - return "Decimal(22, 9)"; - } else if (elementType == Duration.class) { - return "Interval64"; - } else { - return null; + return classToYdbType.get(elementType); + } + + @Override + public int resolveJdbcType(Class sqlType) { + Integer jdbcType = classToJdbcType.get(sqlType); + if (jdbcType == null) { + return Types.OTHER; } + return jdbcType; } @Override diff --git a/dialect/src/main/java/ydb/jimmer/dialect/constant/YdbClassMapping.java b/dialect/src/main/java/ydb/jimmer/dialect/constant/YdbClassMapping.java new file mode 100644 index 00000000..bc284e77 --- /dev/null +++ b/dialect/src/main/java/ydb/jimmer/dialect/constant/YdbClassMapping.java @@ -0,0 +1,52 @@ +package ydb.jimmer.dialect.constant; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.sql.Date; +import java.sql.Time; +import java.sql.Timestamp; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public final class YdbClassMapping { + private YdbClassMapping() {} + + public static final Map, String> classToYdbType = new HashMap<>(); + public static final Map, Integer> classToJdbcType = new HashMap<>(); + + static { + add("Bool", YdbJdbcTypes.BOOL, boolean.class, Boolean.class); + + add("Int8", YdbJdbcTypes.INT8, byte.class, Byte.class); + add("Int16", YdbJdbcTypes.INT16, short.class, Short.class); + add("Int32", YdbJdbcTypes.INT32, int.class, Integer.class, LocalTime.class, Time.class); + add("Int64", YdbJdbcTypes.INT64, long.class, Long.class, BigInteger.class); + add("Decimal(22, 9)", YdbJdbcTypes.DECIMAL_22_9, BigDecimal.class); + + add("Float", YdbJdbcTypes.FLOAT, float.class, Float.class); + add("Double", YdbJdbcTypes.DOUBLE, double.class, Double.class); + + add("Utf8", YdbJdbcTypes.TEXT, String.class); + add("String", YdbJdbcTypes.BYTES, byte[].class); + + add("Uuid", YdbJdbcTypes.UUID, UUID.class); + + add("Date32", YdbJdbcTypes.DATE32, Date.class, LocalDate.class); + add("Datetime64", YdbJdbcTypes.DATETIME64, LocalDateTime.class); + add("Timestamp64", YdbJdbcTypes.TIMESTAMP64, java.util.Date.class, Timestamp.class, Instant.class); + add("Interval64", YdbJdbcTypes.INTERVAL64, Duration.class); + } + + private static void add(String ydbType, int jdbcType, Class... classes) { + for (Class clazz : classes) { + classToYdbType.put(clazz, ydbType); + classToJdbcType.put(clazz, jdbcType); + } + } +} From 55da70c999db3bb8c0619b89ac720b4f5151f6db Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Thu, 12 Feb 2026 20:03:13 +0300 Subject: [PATCH 26/98] Fixed Interval64 --- .../dialect/scalar/DurationProvider.java | 42 +++++++++++++++++++ .../java/ydb/jimmer/dialect/DataTypeTest.java | 38 ++++++++++------- .../test/java/ydb/jimmer/dialect/YdbTest.java | 2 + .../type/{YdbJson.java => YdbInterval64.java} | 9 ++-- .../jimmer/dialect/model/type/YdbString.java | 2 +- .../model/type/{YdbDate.java => YdbUtf8.java} | 8 ++-- 6 files changed, 77 insertions(+), 24 deletions(-) create mode 100644 dialect/src/main/java/ydb/jimmer/dialect/scalar/DurationProvider.java rename dialect/src/test/java/ydb/jimmer/dialect/model/type/{YdbJson.java => YdbInterval64.java} (70%) rename dialect/src/test/java/ydb/jimmer/dialect/model/type/{YdbDate.java => YdbUtf8.java} (74%) diff --git a/dialect/src/main/java/ydb/jimmer/dialect/scalar/DurationProvider.java b/dialect/src/main/java/ydb/jimmer/dialect/scalar/DurationProvider.java new file mode 100644 index 00000000..79fd05fd --- /dev/null +++ b/dialect/src/main/java/ydb/jimmer/dialect/scalar/DurationProvider.java @@ -0,0 +1,42 @@ +package ydb.jimmer.dialect.scalar; + +import org.babyfish.jimmer.sql.runtime.AbstractScalarProvider; +import org.babyfish.jimmer.sql.runtime.Reader; +import org.jetbrains.annotations.NotNull; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.time.Duration; + +public class DurationProvider extends AbstractScalarProvider { + public DurationProvider() { + super(Duration.class, Duration.class); + } + + @Override + public Duration toScalar(@NotNull Duration sqlValue) { + return sqlValue; + } + + @Override + public Duration toSql(@NotNull Duration scalarValue) { + return scalarValue; + } + + @Override + public Reader reader() { + return new DurationReader(); + } + + private static class DurationReader implements Reader { + @Override + public Duration read(ResultSet rs, Context ctx) throws SQLException { + return rs.getObject(ctx.col(), Duration.class); + } + + @Override + public void skip(Context ctx) { + ctx.col(); + } + } +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/DataTypeTest.java b/dialect/src/test/java/ydb/jimmer/dialect/DataTypeTest.java index 549e26b7..8c6949bc 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/DataTypeTest.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/DataTypeTest.java @@ -5,7 +5,6 @@ import org.junit.jupiter.api.Test; import ydb.jimmer.dialect.model.type.YdbBoolTable; import ydb.jimmer.dialect.model.type.YdbDate32Table; -import ydb.jimmer.dialect.model.type.YdbDateTable; import ydb.jimmer.dialect.model.type.YdbDateTime64Table; import ydb.jimmer.dialect.model.type.YdbDecimalTable; import ydb.jimmer.dialect.model.type.YdbDoubleTable; @@ -14,8 +13,10 @@ import ydb.jimmer.dialect.model.type.YdbInt32Table; import ydb.jimmer.dialect.model.type.YdbInt64Table; import ydb.jimmer.dialect.model.type.YdbInt8Table; +import ydb.jimmer.dialect.model.type.YdbInterval64Table; import ydb.jimmer.dialect.model.type.YdbStringTable; import ydb.jimmer.dialect.model.type.YdbTimestamp64Table; +import ydb.jimmer.dialect.model.type.YdbUtf8Table; import ydb.jimmer.dialect.model.type.YdbUuidTable; public class DataTypeTest extends YdbTest { @@ -93,15 +94,6 @@ public void boolTest() { valuesToInsert, expectedValues); } - @Test - public void dateTest() { - String[] valuesToInsert = new String[]{"Date(\"2000-01-01\")", "Date(\"2017-11-27\")"}; - String[] expectedValues = new String[]{"\"2000-01-01\"", "\"2017-11-27\""}; - typeTest("ydb_date", "Date", - YdbDateTable.$, YdbDateTable.$.value(), - valuesToInsert, expectedValues); - } - @Test public void date32Test() { String[] valuesToInsert = new String[]{"Date32(\"144169-01-01\")"}; @@ -122,9 +114,9 @@ public void dateTime64Test() { @Test public void decimalTest() { - String[] valuesToInsert = new String[]{"Decimal(\"1.23\", 5, 2)"}; - String[] expectedValues = new String[]{"1.23"}; - typeTest("ydb_decimal", "Decimal(5, 2)", + String[] valuesToInsert = new String[]{"Decimal(\"1.23\", 22, 9)"}; + String[] expectedValues = new String[]{"1.230000000"}; + typeTest("ydb_decimal", "Decimal(22, 9)", YdbDecimalTable.$, YdbDecimalTable.$.value(), valuesToInsert, expectedValues); } @@ -183,10 +175,19 @@ public void int64Test() { valuesToInsert, expectedValues); } + @Test + public void interval64Test() { + String[] valuesToInsert = new String[]{"Interval(\"P0DT0H0M0.567890S\")"}; + String[] expectedValues = new String[]{"0.567890000"}; + typeTest("ydb_interval64", "Interval64", + YdbInterval64Table.$, YdbInterval64Table.$.value(), + valuesToInsert, expectedValues); + } + @Test public void stringTest() { String[] valuesToInsert = new String[]{"\"0\"", "\"string\""}; - String[] expectedValues = new String[]{"\"0\"", "\"string\""}; + String[] expectedValues = new String[]{"\"MA==\"", "\"c3RyaW5n\""}; typeTest("ydb_string", "String", YdbStringTable.$, YdbStringTable.$.value(), valuesToInsert, expectedValues); @@ -201,6 +202,15 @@ public void timestamp64Test() { valuesToInsert, expectedValues); } + @Test + public void utf8Test() { + String[] valuesToInsert = new String[]{"\"0\"", "\"string\""}; + String[] expectedValues = new String[]{"\"0\"", "\"string\""}; + typeTest("ydb_utf8", "Utf8", + YdbUtf8Table.$, YdbUtf8Table.$.value(), + valuesToInsert, expectedValues); + } + @Test public void uuidTest() { String[] valuesToInsert = new String[]{ diff --git a/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java b/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java index 0bd1c5e4..dd779bb3 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java @@ -9,6 +9,7 @@ import org.springframework.jdbc.datasource.init.ScriptException; import org.springframework.jdbc.datasource.init.ScriptUtils; import tech.ydb.test.junit5.YdbHelperExtension; +import ydb.jimmer.dialect.scalar.DurationProvider; import ydb.jimmer.dialect.sqlMonitor.ExecutorMonitor; import java.net.URL; @@ -30,6 +31,7 @@ public class YdbTest { yqlClient = JSqlClient.newBuilder() .setExecutor(executor) .setDialect(new YdbDialect()) + .addScalarProvider(new DurationProvider()) .build(); } diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbJson.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInterval64.java similarity index 70% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbJson.java rename to dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInterval64.java index 40fc1ce4..09c85373 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbJson.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInterval64.java @@ -4,15 +4,16 @@ import org.babyfish.jimmer.sql.Entity; import org.babyfish.jimmer.sql.Id; import org.babyfish.jimmer.sql.Table; -import org.json.JSONObject; + +import java.time.Duration; @Entity -@Table(name = "ydb_json") -public interface YdbJson { +@Table(name = "ydb_interval64") +public interface YdbInterval64 { @Id @Column(name = "id") int getId(); @Column(name = "value") - JSONObject value(); + Duration value(); } diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbString.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbString.java index ab8747d9..7dda7140 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbString.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbString.java @@ -13,5 +13,5 @@ public interface YdbString { int getId(); @Column(name = "value") - String value(); + byte[] value(); } diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDate.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbUtf8.java similarity index 74% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDate.java rename to dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbUtf8.java index 8a0c1ebf..e6573ba4 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDate.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbUtf8.java @@ -5,15 +5,13 @@ import org.babyfish.jimmer.sql.Id; import org.babyfish.jimmer.sql.Table; -import java.sql.Date; - @Entity -@Table(name = "ydb_date") -public interface YdbDate { +@Table(name = "ydb_utf8") +public interface YdbUtf8 { @Id @Column(name = "id") int getId(); @Column(name = "value") - Date value(); + String value(); } From 5f6390e825c7f5d6e998a7df924ef9ce7a42b9c9 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Thu, 12 Feb 2026 21:18:48 +0300 Subject: [PATCH 27/98] Added more tests for data types --- .../dialect/constant/YdbClassMapping.java | 2 +- .../java/ydb/jimmer/dialect/DataTypeTest.java | 169 +++++++++++++----- .../jimmer/dialect/model/type/YdbUtf8.java | 17 -- .../{YdbBool.java => ydbBool/YdbBoolean.java} | 6 +- .../model/type/ydbBool/YdbBooleanClass.java | 17 ++ .../dialect/model/type/ydbDate32/YdbDate.java | 20 +++ .../YdbLocalDate.java} | 6 +- .../YdbLocalDateTime.java} | 6 +- .../YdbBigDecimal.java} | 6 +- .../model/type/{ => ydbDouble}/YdbDouble.java | 2 +- .../model/type/ydbDouble/YdbDoubleClass.java | 17 ++ .../model/type/{ => ydbFloat}/YdbFloat.java | 2 +- .../model/type/ydbFloat/YdbFloatClass.java | 17 ++ .../{YdbInt16.java => ydbInt16/YdbShort.java} | 6 +- .../model/type/ydbInt16/YdbShortClass.java | 17 ++ .../{YdbInt32.java => ydbInt32/YdbInt.java} | 6 +- .../model/type/ydbInt32/YdbInteger.java | 17 ++ .../model/type/ydbInt32/YdbLocalTime.java | 19 ++ .../dialect/model/type/ydbInt32/YdbTime.java | 20 +++ .../model/type/ydbInt64/YdbBigInteger.java | 19 ++ .../{YdbInt64.java => ydbInt64/YdbLong.java} | 6 +- .../model/type/ydbInt64/YdbLongClass.java | 17 ++ .../{YdbInt8.java => ydbInt8/YdbByte.java} | 6 +- .../model/type/ydbInt8/YdbByteClass.java | 17 ++ .../YdbDuration.java} | 6 +- .../model/type/ydbString/YdbByteArray.java | 17 ++ .../YdbInstant.java} | 6 +- .../type/ydbTimestamp64/YdbTimestamp.java | 20 +++ .../type/ydbTimestamp64/YdbUtilDate.java | 20 +++ .../model/type/{ => ydbUtf8}/YdbString.java | 4 +- .../model/type/{ => ydbUuid}/YdbUuid.java | 2 +- 31 files changed, 419 insertions(+), 93 deletions(-) delete mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbUtf8.java rename dialect/src/test/java/ydb/jimmer/dialect/model/type/{YdbBool.java => ydbBool/YdbBoolean.java} (71%) create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbBool/YdbBooleanClass.java create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDate32/YdbDate.java rename dialect/src/test/java/ydb/jimmer/dialect/model/type/{YdbDate32.java => ydbDate32/YdbLocalDate.java} (72%) rename dialect/src/test/java/ydb/jimmer/dialect/model/type/{YdbDateTime64.java => ydbDatetime64/YdbLocalDateTime.java} (70%) rename dialect/src/test/java/ydb/jimmer/dialect/model/type/{YdbDecimal.java => ydbDecimal/YdbBigDecimal.java} (71%) rename dialect/src/test/java/ydb/jimmer/dialect/model/type/{ => ydbDouble}/YdbDouble.java (86%) create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDouble/YdbDoubleClass.java rename dialect/src/test/java/ydb/jimmer/dialect/model/type/{ => ydbFloat}/YdbFloat.java (86%) create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbFloat/YdbFloatClass.java rename dialect/src/test/java/ydb/jimmer/dialect/model/type/{YdbInt16.java => ydbInt16/YdbShort.java} (71%) create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt16/YdbShortClass.java rename dialect/src/test/java/ydb/jimmer/dialect/model/type/{YdbInt32.java => ydbInt32/YdbInt.java} (72%) create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbInteger.java create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbLocalTime.java create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbTime.java create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt64/YdbBigInteger.java rename dialect/src/test/java/ydb/jimmer/dialect/model/type/{YdbInt64.java => ydbInt64/YdbLong.java} (72%) create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt64/YdbLongClass.java rename dialect/src/test/java/ydb/jimmer/dialect/model/type/{YdbInt8.java => ydbInt8/YdbByte.java} (72%) create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt8/YdbByteClass.java rename dialect/src/test/java/ydb/jimmer/dialect/model/type/{YdbInterval64.java => ydbInterval64/YdbDuration.java} (71%) create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbString/YdbByteArray.java rename dialect/src/test/java/ydb/jimmer/dialect/model/type/{YdbTimestamp64.java => ydbTimestamp64/YdbInstant.java} (71%) create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbTimestamp64/YdbTimestamp.java create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbTimestamp64/YdbUtilDate.java rename dialect/src/test/java/ydb/jimmer/dialect/model/type/{ => ydbUtf8}/YdbString.java (81%) rename dialect/src/test/java/ydb/jimmer/dialect/model/type/{ => ydbUuid}/YdbUuid.java (87%) diff --git a/dialect/src/main/java/ydb/jimmer/dialect/constant/YdbClassMapping.java b/dialect/src/main/java/ydb/jimmer/dialect/constant/YdbClassMapping.java index bc284e77..0da04d15 100644 --- a/dialect/src/main/java/ydb/jimmer/dialect/constant/YdbClassMapping.java +++ b/dialect/src/main/java/ydb/jimmer/dialect/constant/YdbClassMapping.java @@ -35,7 +35,7 @@ private YdbClassMapping() {} add("Utf8", YdbJdbcTypes.TEXT, String.class); add("String", YdbJdbcTypes.BYTES, byte[].class); - add("Uuid", YdbJdbcTypes.UUID, UUID.class); + add("Uuid", YdbJdbcTypes.UUID, UUID.class); add("Date32", YdbJdbcTypes.DATE32, Date.class, LocalDate.class); add("Datetime64", YdbJdbcTypes.DATETIME64, LocalDateTime.class); diff --git a/dialect/src/test/java/ydb/jimmer/dialect/DataTypeTest.java b/dialect/src/test/java/ydb/jimmer/dialect/DataTypeTest.java index 8c6949bc..23cadcc8 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/DataTypeTest.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/DataTypeTest.java @@ -3,21 +3,34 @@ import org.babyfish.jimmer.sql.ast.PropExpression; import org.babyfish.jimmer.sql.ast.table.spi.AbstractTypedTable; import org.junit.jupiter.api.Test; -import ydb.jimmer.dialect.model.type.YdbBoolTable; -import ydb.jimmer.dialect.model.type.YdbDate32Table; -import ydb.jimmer.dialect.model.type.YdbDateTime64Table; -import ydb.jimmer.dialect.model.type.YdbDecimalTable; -import ydb.jimmer.dialect.model.type.YdbDoubleTable; -import ydb.jimmer.dialect.model.type.YdbFloatTable; -import ydb.jimmer.dialect.model.type.YdbInt16Table; -import ydb.jimmer.dialect.model.type.YdbInt32Table; -import ydb.jimmer.dialect.model.type.YdbInt64Table; -import ydb.jimmer.dialect.model.type.YdbInt8Table; -import ydb.jimmer.dialect.model.type.YdbInterval64Table; -import ydb.jimmer.dialect.model.type.YdbStringTable; -import ydb.jimmer.dialect.model.type.YdbTimestamp64Table; -import ydb.jimmer.dialect.model.type.YdbUtf8Table; -import ydb.jimmer.dialect.model.type.YdbUuidTable; +import ydb.jimmer.dialect.model.type.ydbBool.YdbBooleanClassTable; +import ydb.jimmer.dialect.model.type.ydbBool.YdbBooleanTable; +import ydb.jimmer.dialect.model.type.ydbDate32.YdbDateTable; +import ydb.jimmer.dialect.model.type.ydbDate32.YdbLocalDateTable; +import ydb.jimmer.dialect.model.type.ydbDatetime64.YdbLocalDateTimeTable; +import ydb.jimmer.dialect.model.type.ydbDecimal.YdbBigDecimalTable; +import ydb.jimmer.dialect.model.type.ydbDouble.YdbDoubleClassTable; +import ydb.jimmer.dialect.model.type.ydbDouble.YdbDoubleTable; +import ydb.jimmer.dialect.model.type.ydbFloat.YdbFloatClassTable; +import ydb.jimmer.dialect.model.type.ydbFloat.YdbFloatTable; +import ydb.jimmer.dialect.model.type.ydbInt16.YdbShortClassTable; +import ydb.jimmer.dialect.model.type.ydbInt16.YdbShortTable; +import ydb.jimmer.dialect.model.type.ydbInt32.YdbIntTable; +import ydb.jimmer.dialect.model.type.ydbInt32.YdbIntegerTable; +import ydb.jimmer.dialect.model.type.ydbInt32.YdbLocalTimeTable; +import ydb.jimmer.dialect.model.type.ydbInt32.YdbTimeTable; +import ydb.jimmer.dialect.model.type.ydbInt64.YdbBigIntegerTable; +import ydb.jimmer.dialect.model.type.ydbInt64.YdbLongClassTable; +import ydb.jimmer.dialect.model.type.ydbInt64.YdbLongTable; +import ydb.jimmer.dialect.model.type.ydbInt8.YdbByteClassTable; +import ydb.jimmer.dialect.model.type.ydbInt8.YdbByteTable; +import ydb.jimmer.dialect.model.type.ydbInterval64.YdbDurationTable; +import ydb.jimmer.dialect.model.type.ydbString.YdbByteArrayTable; +import ydb.jimmer.dialect.model.type.ydbTimestamp64.YdbInstantTable; +import ydb.jimmer.dialect.model.type.ydbTimestamp64.YdbTimestampTable; +import ydb.jimmer.dialect.model.type.ydbTimestamp64.YdbUtilDateTable; +import ydb.jimmer.dialect.model.type.ydbUtf8.YdbStringTable; +import ydb.jimmer.dialect.model.type.ydbUuid.YdbUuidTable; public class DataTypeTest extends YdbTest { private void createTable(String tableName, String typeName) { @@ -89,17 +102,29 @@ private void typeTest(String tableName, public void boolTest() { String[] valuesToInsert = new String[]{"false", "true"}; String[] expectedValues = new String[]{"false", "true"}; - typeTest("ydb_test", "Bool", - YdbBoolTable.$, YdbBoolTable.$.value(), + + typeTest("ydb_boolean", "Bool", + YdbBooleanTable.$, YdbBooleanTable.$.value(), + valuesToInsert, expectedValues); + + typeTest("ydb_boolean_class", "Bool", + YdbBooleanClassTable.$, YdbBooleanClassTable.$.value(), valuesToInsert, expectedValues); } @Test public void date32Test() { String[] valuesToInsert = new String[]{"Date32(\"144169-01-01\")"}; - String[] expectedValues = new String[]{"\"+144169-01-01\""}; - typeTest("ydb_date32", "Date32", - YdbDate32Table.$, YdbDate32Table.$.value(), + String[] expectedValues = new String[]{"\"4169-01-01\""}; + + typeTest("ydb_date", "Date32", + YdbDateTable.$, YdbDateTable.$.value(), + valuesToInsert, expectedValues); + + expectedValues = new String[]{"\"+144169-01-01\""}; + + typeTest("ydb_local_date", "Date32", + YdbLocalDateTable.$, YdbLocalDateTable.$.value(), valuesToInsert, expectedValues); } @@ -107,8 +132,9 @@ public void date32Test() { public void dateTime64Test() { String[] valuesToInsert = new String[]{"DateTime64(\"2017-11-27T13:24:00Z\")"}; String[] expectedValues = new String[]{"\"2017-11-27T13:24:00\""}; - typeTest("ydb_dateTime64", "DateTime64", - YdbDateTime64Table.$, YdbDateTime64Table.$.value(), + + typeTest("ydb_local_date_time", "DateTime64", + YdbLocalDateTimeTable.$, YdbLocalDateTimeTable.$.value(), valuesToInsert, expectedValues); } @@ -116,8 +142,9 @@ public void dateTime64Test() { public void decimalTest() { String[] valuesToInsert = new String[]{"Decimal(\"1.23\", 22, 9)"}; String[] expectedValues = new String[]{"1.230000000"}; - typeTest("ydb_decimal", "Decimal(22, 9)", - YdbDecimalTable.$, YdbDecimalTable.$.value(), + + typeTest("ydb_big_decimal", "Decimal(22, 9)", + YdbBigDecimalTable.$, YdbBigDecimalTable.$.value(), valuesToInsert, expectedValues); } @@ -125,26 +152,41 @@ public void decimalTest() { public void doubleTest() { String[] valuesToInsert = new String[]{"Double(\"1.23\")"}; String[] expectedValues = new String[]{"1.23"}; + typeTest("ydb_double", "Double", YdbDoubleTable.$, YdbDoubleTable.$.value(), valuesToInsert, expectedValues); + + typeTest("ydb_double_class", "Double", + YdbDoubleClassTable.$, YdbDoubleClassTable.$.value(), + valuesToInsert, expectedValues); } @Test public void floatTest() { String[] valuesToInsert = new String[]{"Float(\"1.23\")"}; String[] expectedValues = new String[]{"1.23"}; + typeTest("ydb_float", "Float", YdbFloatTable.$, YdbFloatTable.$.value(), valuesToInsert, expectedValues); + + typeTest("ydb_float_class", "Float", + YdbFloatClassTable.$, YdbFloatClassTable.$.value(), + valuesToInsert, expectedValues); } @Test public void int8Test() { String[] valuesToInsert = new String[]{"-1", "0", "10"}; String[] expectedValues = new String[]{"-1", "0", "10"}; - typeTest("ydb_int8", "Int8", - YdbInt8Table.$, YdbInt8Table.$.value(), + + typeTest("ydb_byte", "Int8", + YdbByteTable.$, YdbByteTable.$.value(), + valuesToInsert, expectedValues); + + typeTest("ydb_byte_class", "Int8", + YdbByteClassTable.$, YdbByteClassTable.$.value(), valuesToInsert, expectedValues); } @@ -152,8 +194,13 @@ public void int8Test() { public void int16Test() { String[] valuesToInsert = new String[]{"-1", "0", "10"}; String[] expectedValues = new String[]{"-1", "0", "10"}; - typeTest("ydb_int16", "Int16", - YdbInt16Table.$, YdbInt16Table.$.value(), + + typeTest("ydb_short", "Int16", + YdbShortTable.$, YdbShortTable.$.value(), + valuesToInsert, expectedValues); + + typeTest("ydb_short_class", "Int16", + YdbShortClassTable.$, YdbShortClassTable.$.value(), valuesToInsert, expectedValues); } @@ -161,8 +208,26 @@ public void int16Test() { public void int32Test() { String[] valuesToInsert = new String[]{"-1", "0", "10"}; String[] expectedValues = new String[]{"-1", "0", "10"}; - typeTest("ydb_int32", "Int32", - YdbInt32Table.$, YdbInt32Table.$.value(), + + typeTest("ydb_int", "Int32", + YdbIntTable.$, YdbIntTable.$.value(), + valuesToInsert, expectedValues); + + typeTest("ydb_integer", "Int32", + YdbIntegerTable.$, YdbIntegerTable.$.value(), + valuesToInsert, expectedValues); + + expectedValues = new String[]{"\"02:59:59.999\"", "\"03:00:00\"", "\"03:00:00.01\""}; + + typeTest("ydb_local_time", "Int32", + YdbLocalTimeTable.$, YdbLocalTimeTable.$.value(), + valuesToInsert, expectedValues); + + valuesToInsert = new String[]{"0", "10"}; + expectedValues = new String[]{"\"00:00:00\"", "\"00:00:10\""}; + + typeTest("ydb_time", "Int32", + YdbTimeTable.$, YdbTimeTable.$.value(), valuesToInsert, expectedValues); } @@ -170,8 +235,17 @@ public void int32Test() { public void int64Test() { String[] valuesToInsert = new String[]{"-1", "0", "10"}; String[] expectedValues = new String[]{"-1", "0", "10"}; - typeTest("ydb_int64", "Int64", - YdbInt64Table.$, YdbInt64Table.$.value(), + + typeTest("ydb_big_integer", "Int64", + YdbBigIntegerTable.$, YdbBigIntegerTable.$.value(), + valuesToInsert, expectedValues); + + typeTest("ydb_long", "Int64", + YdbLongTable.$, YdbLongTable.$.value(), + valuesToInsert, expectedValues); + + typeTest("ydb_long_class", "Int64", + YdbLongClassTable.$, YdbLongClassTable.$.value(), valuesToInsert, expectedValues); } @@ -179,8 +253,9 @@ public void int64Test() { public void interval64Test() { String[] valuesToInsert = new String[]{"Interval(\"P0DT0H0M0.567890S\")"}; String[] expectedValues = new String[]{"0.567890000"}; - typeTest("ydb_interval64", "Interval64", - YdbInterval64Table.$, YdbInterval64Table.$.value(), + + typeTest("ydb_duration", "Interval64", + YdbDurationTable.$, YdbDurationTable.$.value(), valuesToInsert, expectedValues); } @@ -188,8 +263,9 @@ public void interval64Test() { public void stringTest() { String[] valuesToInsert = new String[]{"\"0\"", "\"string\""}; String[] expectedValues = new String[]{"\"MA==\"", "\"c3RyaW5n\""}; - typeTest("ydb_string", "String", - YdbStringTable.$, YdbStringTable.$.value(), + + typeTest("ydb_byte_array", "String", + YdbByteArrayTable.$, YdbByteArrayTable.$.value(), valuesToInsert, expectedValues); } @@ -197,8 +273,19 @@ public void stringTest() { public void timestamp64Test() { String[] valuesToInsert = new String[]{"Timestamp64(\"2017-11-27T13:24:00.123456Z\")"}; String[] expectedValues = new String[]{"\"2017-11-27T13:24:00.123456Z\""}; - typeTest("ydb_timestamp64", "Timestamp64", - YdbTimestamp64Table.$, YdbTimestamp64Table.$.value(), + + typeTest("ydb_instant", "Timestamp64", + YdbInstantTable.$, YdbInstantTable.$.value(), + valuesToInsert, expectedValues); + + expectedValues = new String[]{"\"2017-11-27\""}; + + typeTest("ydb_timestamp", "Timestamp64", + YdbTimestampTable.$, YdbTimestampTable.$.value(), + valuesToInsert, expectedValues); + + typeTest("ydb_util_date", "Timestamp64", + YdbUtilDateTable.$, YdbUtilDateTable.$.value(), valuesToInsert, expectedValues); } @@ -206,8 +293,9 @@ public void timestamp64Test() { public void utf8Test() { String[] valuesToInsert = new String[]{"\"0\"", "\"string\""}; String[] expectedValues = new String[]{"\"0\"", "\"string\""}; - typeTest("ydb_utf8", "Utf8", - YdbUtf8Table.$, YdbUtf8Table.$.value(), + + typeTest("ydb_string", "Utf8", + YdbStringTable.$, YdbStringTable.$.value(), valuesToInsert, expectedValues); } @@ -219,6 +307,7 @@ public void uuidTest() { String[] expectedValues = new String[]{ "\"9e197d65-1914-4d57-a65f-77a52a06baa7\"", "\"8e0f2cf4-4656-4d73-970e-a18be9ead78b\""}; + typeTest("ydb_uuid", "Uuid", YdbUuidTable.$, YdbUuidTable.$.value(), valuesToInsert, expectedValues); diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbUtf8.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbUtf8.java deleted file mode 100644 index e6573ba4..00000000 --- a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbUtf8.java +++ /dev/null @@ -1,17 +0,0 @@ -package ydb.jimmer.dialect.model.type; - -import org.babyfish.jimmer.sql.Column; -import org.babyfish.jimmer.sql.Entity; -import org.babyfish.jimmer.sql.Id; -import org.babyfish.jimmer.sql.Table; - -@Entity -@Table(name = "ydb_utf8") -public interface YdbUtf8 { - @Id - @Column(name = "id") - int getId(); - - @Column(name = "value") - String value(); -} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbBool.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbBool/YdbBoolean.java similarity index 71% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbBool.java rename to dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbBool/YdbBoolean.java index f05311fa..3a17a26b 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbBool.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbBool/YdbBoolean.java @@ -1,4 +1,4 @@ -package ydb.jimmer.dialect.model.type; +package ydb.jimmer.dialect.model.type.ydbBool; import org.babyfish.jimmer.sql.Column; import org.babyfish.jimmer.sql.Entity; @@ -6,8 +6,8 @@ import org.babyfish.jimmer.sql.Table; @Entity -@Table(name = "ydb_test") -public interface YdbBool { +@Table(name = "ydb_boolean") +public interface YdbBoolean { @Id @Column(name = "id") int getId(); diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbBool/YdbBooleanClass.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbBool/YdbBooleanClass.java new file mode 100644 index 00000000..02d7da81 --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbBool/YdbBooleanClass.java @@ -0,0 +1,17 @@ +package ydb.jimmer.dialect.model.type.ydbBool; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +@Entity +@Table(name = "ydb_boolean_class") +public interface YdbBooleanClass { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + Boolean value(); +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDate32/YdbDate.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDate32/YdbDate.java new file mode 100644 index 00000000..3d7411bc --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDate32/YdbDate.java @@ -0,0 +1,20 @@ +package ydb.jimmer.dialect.model.type.ydbDate32; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +import java.sql.Date; +import java.time.LocalDate; + +@Entity +@Table(name = "ydb_date") +public interface YdbDate { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + Date value(); +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDate32.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDate32/YdbLocalDate.java similarity index 72% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDate32.java rename to dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDate32/YdbLocalDate.java index 45f1541a..e46c2b37 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDate32.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDate32/YdbLocalDate.java @@ -1,4 +1,4 @@ -package ydb.jimmer.dialect.model.type; +package ydb.jimmer.dialect.model.type.ydbDate32; import org.babyfish.jimmer.sql.Column; import org.babyfish.jimmer.sql.Entity; @@ -8,8 +8,8 @@ import java.time.LocalDate; @Entity -@Table(name = "ydb_date32") -public interface YdbDate32 { +@Table(name = "ydb_local_date") +public interface YdbLocalDate { @Id @Column(name = "id") int getId(); diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDateTime64.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDatetime64/YdbLocalDateTime.java similarity index 70% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDateTime64.java rename to dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDatetime64/YdbLocalDateTime.java index 4c9f3662..6ebbebb3 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDateTime64.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDatetime64/YdbLocalDateTime.java @@ -1,4 +1,4 @@ -package ydb.jimmer.dialect.model.type; +package ydb.jimmer.dialect.model.type.ydbDatetime64; import org.babyfish.jimmer.sql.Column; import org.babyfish.jimmer.sql.Entity; @@ -8,8 +8,8 @@ import java.time.LocalDateTime; @Entity -@Table(name = "ydb_dateTime64") -public interface YdbDateTime64 { +@Table(name = "ydb_local_date_time") +public interface YdbLocalDateTime { @Id @Column(name = "id") int getId(); diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDecimal.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDecimal/YdbBigDecimal.java similarity index 71% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDecimal.java rename to dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDecimal/YdbBigDecimal.java index ecbff4c8..b664a6e0 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDecimal.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDecimal/YdbBigDecimal.java @@ -1,4 +1,4 @@ -package ydb.jimmer.dialect.model.type; +package ydb.jimmer.dialect.model.type.ydbDecimal; import org.babyfish.jimmer.sql.Column; import org.babyfish.jimmer.sql.Entity; @@ -8,8 +8,8 @@ import java.math.BigDecimal; @Entity -@Table(name = "ydb_decimal") -public interface YdbDecimal { +@Table(name = "ydb_big_decimal") +public interface YdbBigDecimal { @Id @Column(name = "id") int getId(); diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDouble.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDouble/YdbDouble.java similarity index 86% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDouble.java rename to dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDouble/YdbDouble.java index 21f5a42b..d0308496 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbDouble.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDouble/YdbDouble.java @@ -1,4 +1,4 @@ -package ydb.jimmer.dialect.model.type; +package ydb.jimmer.dialect.model.type.ydbDouble; import org.babyfish.jimmer.sql.Column; import org.babyfish.jimmer.sql.Entity; diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDouble/YdbDoubleClass.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDouble/YdbDoubleClass.java new file mode 100644 index 00000000..f4ec49d7 --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDouble/YdbDoubleClass.java @@ -0,0 +1,17 @@ +package ydb.jimmer.dialect.model.type.ydbDouble; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +@Entity +@Table(name = "ydb_double_class") +public interface YdbDoubleClass { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + Double value(); +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbFloat.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbFloat/YdbFloat.java similarity index 86% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbFloat.java rename to dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbFloat/YdbFloat.java index c3e70dca..c3d453c8 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbFloat.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbFloat/YdbFloat.java @@ -1,4 +1,4 @@ -package ydb.jimmer.dialect.model.type; +package ydb.jimmer.dialect.model.type.ydbFloat; import org.babyfish.jimmer.sql.Column; import org.babyfish.jimmer.sql.Entity; diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbFloat/YdbFloatClass.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbFloat/YdbFloatClass.java new file mode 100644 index 00000000..5cd4fe4e --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbFloat/YdbFloatClass.java @@ -0,0 +1,17 @@ +package ydb.jimmer.dialect.model.type.ydbFloat; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +@Entity +@Table(name = "ydb_float_class") +public interface YdbFloatClass { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + Float value(); +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInt16.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt16/YdbShort.java similarity index 71% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInt16.java rename to dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt16/YdbShort.java index 3db0ce59..c8ce74a9 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInt16.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt16/YdbShort.java @@ -1,4 +1,4 @@ -package ydb.jimmer.dialect.model.type; +package ydb.jimmer.dialect.model.type.ydbInt16; import org.babyfish.jimmer.sql.Column; import org.babyfish.jimmer.sql.Entity; @@ -6,8 +6,8 @@ import org.babyfish.jimmer.sql.Table; @Entity -@Table(name = "ydb_int16") -public interface YdbInt16 { +@Table(name = "ydb_short") +public interface YdbShort { @Id @Column(name = "id") int getId(); diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt16/YdbShortClass.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt16/YdbShortClass.java new file mode 100644 index 00000000..28ec44e0 --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt16/YdbShortClass.java @@ -0,0 +1,17 @@ +package ydb.jimmer.dialect.model.type.ydbInt16; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +@Entity +@Table(name = "ydb_short_class") +public interface YdbShortClass { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + Short value(); +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInt32.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbInt.java similarity index 72% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInt32.java rename to dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbInt.java index 12ab7df8..dc22ac17 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInt32.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbInt.java @@ -1,4 +1,4 @@ -package ydb.jimmer.dialect.model.type; +package ydb.jimmer.dialect.model.type.ydbInt32; import org.babyfish.jimmer.sql.Column; import org.babyfish.jimmer.sql.Entity; @@ -6,8 +6,8 @@ import org.babyfish.jimmer.sql.Table; @Entity -@Table(name = "ydb_int32") -public interface YdbInt32 { +@Table(name = "ydb_int") +public interface YdbInt { @Id @Column(name = "id") int getId(); diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbInteger.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbInteger.java new file mode 100644 index 00000000..a158daf2 --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbInteger.java @@ -0,0 +1,17 @@ +package ydb.jimmer.dialect.model.type.ydbInt32; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +@Entity +@Table(name = "ydb_integer") +public interface YdbInteger { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + Integer value(); +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbLocalTime.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbLocalTime.java new file mode 100644 index 00000000..2f1528df --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbLocalTime.java @@ -0,0 +1,19 @@ +package ydb.jimmer.dialect.model.type.ydbInt32; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +import java.time.LocalTime; + +@Entity +@Table(name = "ydb_local_time") +public interface YdbLocalTime { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + LocalTime value(); +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbTime.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbTime.java new file mode 100644 index 00000000..45db18cb --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbTime.java @@ -0,0 +1,20 @@ +package ydb.jimmer.dialect.model.type.ydbInt32; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +import java.sql.Time; +import java.time.LocalTime; + +@Entity +@Table(name = "ydb_time") +public interface YdbTime { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + Time value(); +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt64/YdbBigInteger.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt64/YdbBigInteger.java new file mode 100644 index 00000000..78a5b138 --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt64/YdbBigInteger.java @@ -0,0 +1,19 @@ +package ydb.jimmer.dialect.model.type.ydbInt64; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +import java.math.BigInteger; + +@Entity +@Table(name = "ydb_big_integer") +public interface YdbBigInteger { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + BigInteger value(); +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInt64.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt64/YdbLong.java similarity index 72% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInt64.java rename to dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt64/YdbLong.java index bf1514ed..0cb82320 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInt64.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt64/YdbLong.java @@ -1,4 +1,4 @@ -package ydb.jimmer.dialect.model.type; +package ydb.jimmer.dialect.model.type.ydbInt64; import org.babyfish.jimmer.sql.Column; import org.babyfish.jimmer.sql.Entity; @@ -6,8 +6,8 @@ import org.babyfish.jimmer.sql.Table; @Entity -@Table(name = "ydb_int64") -public interface YdbInt64 { +@Table(name = "ydb_long") +public interface YdbLong { @Id @Column(name = "id") int getId(); diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt64/YdbLongClass.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt64/YdbLongClass.java new file mode 100644 index 00000000..acf706ab --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt64/YdbLongClass.java @@ -0,0 +1,17 @@ +package ydb.jimmer.dialect.model.type.ydbInt64; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +@Entity +@Table(name = "ydb_long_class") +public interface YdbLongClass { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + Long value(); +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInt8.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt8/YdbByte.java similarity index 72% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInt8.java rename to dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt8/YdbByte.java index 1984935b..83fb8eb3 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInt8.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt8/YdbByte.java @@ -1,4 +1,4 @@ -package ydb.jimmer.dialect.model.type; +package ydb.jimmer.dialect.model.type.ydbInt8; import org.babyfish.jimmer.sql.Column; import org.babyfish.jimmer.sql.Entity; @@ -6,8 +6,8 @@ import org.babyfish.jimmer.sql.Table; @Entity -@Table(name = "ydb_int8") -public interface YdbInt8 { +@Table(name = "ydb_byte") +public interface YdbByte { @Id @Column(name = "id") int getId(); diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt8/YdbByteClass.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt8/YdbByteClass.java new file mode 100644 index 00000000..c05df232 --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt8/YdbByteClass.java @@ -0,0 +1,17 @@ +package ydb.jimmer.dialect.model.type.ydbInt8; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +@Entity +@Table(name = "ydb_byte_class") +public interface YdbByteClass { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + Byte value(); +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInterval64.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInterval64/YdbDuration.java similarity index 71% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInterval64.java rename to dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInterval64/YdbDuration.java index 09c85373..ed4551bc 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbInterval64.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInterval64/YdbDuration.java @@ -1,4 +1,4 @@ -package ydb.jimmer.dialect.model.type; +package ydb.jimmer.dialect.model.type.ydbInterval64; import org.babyfish.jimmer.sql.Column; import org.babyfish.jimmer.sql.Entity; @@ -8,8 +8,8 @@ import java.time.Duration; @Entity -@Table(name = "ydb_interval64") -public interface YdbInterval64 { +@Table(name = "ydb_duration") +public interface YdbDuration { @Id @Column(name = "id") int getId(); diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbString/YdbByteArray.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbString/YdbByteArray.java new file mode 100644 index 00000000..354bff96 --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbString/YdbByteArray.java @@ -0,0 +1,17 @@ +package ydb.jimmer.dialect.model.type.ydbString; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +@Entity +@Table(name = "ydb_byte_array") +public interface YdbByteArray { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + byte[] value(); +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbTimestamp64.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbTimestamp64/YdbInstant.java similarity index 71% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbTimestamp64.java rename to dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbTimestamp64/YdbInstant.java index d1f94938..aef30ac3 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbTimestamp64.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbTimestamp64/YdbInstant.java @@ -1,4 +1,4 @@ -package ydb.jimmer.dialect.model.type; +package ydb.jimmer.dialect.model.type.ydbTimestamp64; import org.babyfish.jimmer.sql.Column; import org.babyfish.jimmer.sql.Entity; @@ -8,8 +8,8 @@ import java.time.Instant; @Entity -@Table(name = "ydb_timestamp64") -public interface YdbTimestamp64 { +@Table(name = "ydb_instant") +public interface YdbInstant { @Id @Column(name = "id") int getId(); diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbTimestamp64/YdbTimestamp.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbTimestamp64/YdbTimestamp.java new file mode 100644 index 00000000..8bbb9bfa --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbTimestamp64/YdbTimestamp.java @@ -0,0 +1,20 @@ +package ydb.jimmer.dialect.model.type.ydbTimestamp64; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +import java.sql.Timestamp; +import java.time.Instant; + +@Entity +@Table(name = "ydb_timestamp") +public interface YdbTimestamp { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + Timestamp value(); +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbTimestamp64/YdbUtilDate.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbTimestamp64/YdbUtilDate.java new file mode 100644 index 00000000..a4225848 --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbTimestamp64/YdbUtilDate.java @@ -0,0 +1,20 @@ +package ydb.jimmer.dialect.model.type.ydbTimestamp64; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +import java.sql.Timestamp; +import java.util.Date; + +@Entity +@Table(name = "ydb_util_date") +public interface YdbUtilDate { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + Date value(); +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbString.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbUtf8/YdbString.java similarity index 81% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbString.java rename to dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbUtf8/YdbString.java index 7dda7140..f30c172c 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbString.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbUtf8/YdbString.java @@ -1,4 +1,4 @@ -package ydb.jimmer.dialect.model.type; +package ydb.jimmer.dialect.model.type.ydbUtf8; import org.babyfish.jimmer.sql.Column; import org.babyfish.jimmer.sql.Entity; @@ -13,5 +13,5 @@ public interface YdbString { int getId(); @Column(name = "value") - byte[] value(); + String value(); } diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbUuid.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbUuid/YdbUuid.java similarity index 87% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbUuid.java rename to dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbUuid/YdbUuid.java index 1fe3ee5c..2eab2801 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/model/type/YdbUuid.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbUuid/YdbUuid.java @@ -1,4 +1,4 @@ -package ydb.jimmer.dialect.model.type; +package ydb.jimmer.dialect.model.type.ydbUuid; import org.babyfish.jimmer.sql.Column; import org.babyfish.jimmer.sql.Entity; From c1ffb69d0802b1e61a17f27c0c07b169e166b9de Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Thu, 12 Feb 2026 22:10:59 +0300 Subject: [PATCH 28/98] Added Json test and fixed Json in YdbDialect --- .../java/ydb/jimmer/dialect/YdbDialect.java | 16 ------- .../java/ydb/jimmer/dialect/DataTypeTest.java | 46 ++++++++++++++----- .../jimmer/dialect/model/type/json/Json.java | 25 ++++++++++ .../dialect/model/type/json/YdbJson.java | 17 +++++++ 4 files changed, 77 insertions(+), 27 deletions(-) create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/json/Json.java create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/json/YdbJson.java diff --git a/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java b/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java index c571e2ad..0927f9ee 100644 --- a/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java +++ b/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java @@ -6,7 +6,6 @@ import org.babyfish.jimmer.sql.ast.impl.render.AbstractSqlBuilder; import org.babyfish.jimmer.sql.dialect.DefaultDialect; import org.jetbrains.annotations.Nullable; -import org.json.JSONObject; import java.sql.ResultSet; import java.sql.SQLException; @@ -55,21 +54,6 @@ public boolean isTableOfSubQueryMutable() { return false; } - @Override - public Class getJsonBaseType() { - return JSONObject.class; - } - - @Override - public @Nullable Object jsonToBaseValue(@Nullable String json) { - return json == null ? new JSONObject() : new JSONObject(json); - } - - @Override - public @Nullable String baseValueToJson(@Nullable Object baseValue) { - return baseValue == null ? null : baseValue.toString(); - } - @Override public boolean isForeignKeySupported() { return false; diff --git a/dialect/src/test/java/ydb/jimmer/dialect/DataTypeTest.java b/dialect/src/test/java/ydb/jimmer/dialect/DataTypeTest.java index 23cadcc8..0e1787d4 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/DataTypeTest.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/DataTypeTest.java @@ -3,6 +3,7 @@ import org.babyfish.jimmer.sql.ast.PropExpression; import org.babyfish.jimmer.sql.ast.table.spi.AbstractTypedTable; import org.junit.jupiter.api.Test; +import ydb.jimmer.dialect.model.type.json.YdbJsonTable; import ydb.jimmer.dialect.model.type.ydbBool.YdbBooleanClassTable; import ydb.jimmer.dialect.model.type.ydbBool.YdbBooleanTable; import ydb.jimmer.dialect.model.type.ydbDate32.YdbDateTable; @@ -85,17 +86,40 @@ private void typeTest(String tableName, } json.append("]"); - executeAndExpect( - getYqlClient() - .createQuery(table) - .orderBy(prop) - .select(table), - cxt -> { - cxt.sql( - "select tb_1_.id, tb_1_.value from " + tableName + " tb_1_ order by tb_1_.value asc"); - cxt.rows(json.toString()); - } - ); + if (expectedValues.length == 1) { + executeAndExpect( + getYqlClient() + .createQuery(table) + .select(table), + cxt -> { + cxt.sql( + "select tb_1_.id, tb_1_.value from " + tableName + " tb_1_"); + cxt.rows(json.toString()); + } + ); + } else { + executeAndExpect( + getYqlClient() + .createQuery(table) + .orderBy(prop) + .select(table), + cxt -> { + cxt.sql( + "select tb_1_.id, tb_1_.value from " + tableName + " tb_1_ order by tb_1_.value asc"); + cxt.rows(json.toString()); + } + ); + } + } + + @Test + public void jsonTest() { + String[] valuesToInsert = new String[]{"Json(@@{\"a\":1,\"b\":null}@@)"}; + String[] expectedValues = new String[]{"{\"a\":1,\"b\":null}"}; + + typeTest("ydb_json", "Json", + YdbJsonTable.$, YdbJsonTable.$.value(), + valuesToInsert, expectedValues); } @Test diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/json/Json.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/json/Json.java new file mode 100644 index 00000000..19e5baf5 --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/json/Json.java @@ -0,0 +1,25 @@ +package ydb.jimmer.dialect.model.type.json; + +import org.babyfish.jimmer.sql.Serialized; + +@Serialized +public class Json { + private Integer a; + private Integer b; + + public Integer getA() { + return a; + } + + public Integer getB() { + return b; + } + + public void setA(Integer a) { + this.a = a; + } + + public void setB(Integer b) { + this.b = b; + } +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/json/YdbJson.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/json/YdbJson.java new file mode 100644 index 00000000..9aa88aff --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/json/YdbJson.java @@ -0,0 +1,17 @@ +package ydb.jimmer.dialect.model.type.json; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +@Entity +@Table(name = "ydb_json") +public interface YdbJson { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + Json value(); +} From bf44f1bef7bea076c995475cccfb7ac78e218f08 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Thu, 12 Feb 2026 22:51:00 +0300 Subject: [PATCH 29/98] Moved Json model to another package --- .../java/ydb/jimmer/dialect/DataTypeTest.java | 22 +++++++++---------- .../model/type/{json => ydbJson}/Json.java | 2 +- .../model/type/{json => ydbJson}/YdbJson.java | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) rename dialect/src/test/java/ydb/jimmer/dialect/model/type/{json => ydbJson}/Json.java (88%) rename dialect/src/test/java/ydb/jimmer/dialect/model/type/{json => ydbJson}/YdbJson.java (86%) diff --git a/dialect/src/test/java/ydb/jimmer/dialect/DataTypeTest.java b/dialect/src/test/java/ydb/jimmer/dialect/DataTypeTest.java index 0e1787d4..c7f8d1f4 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/DataTypeTest.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/DataTypeTest.java @@ -3,7 +3,7 @@ import org.babyfish.jimmer.sql.ast.PropExpression; import org.babyfish.jimmer.sql.ast.table.spi.AbstractTypedTable; import org.junit.jupiter.api.Test; -import ydb.jimmer.dialect.model.type.json.YdbJsonTable; +import ydb.jimmer.dialect.model.type.ydbJson.YdbJsonTable; import ydb.jimmer.dialect.model.type.ydbBool.YdbBooleanClassTable; import ydb.jimmer.dialect.model.type.ydbBool.YdbBooleanTable; import ydb.jimmer.dialect.model.type.ydbDate32.YdbDateTable; @@ -112,16 +112,6 @@ private void typeTest(String tableName, } } - @Test - public void jsonTest() { - String[] valuesToInsert = new String[]{"Json(@@{\"a\":1,\"b\":null}@@)"}; - String[] expectedValues = new String[]{"{\"a\":1,\"b\":null}"}; - - typeTest("ydb_json", "Json", - YdbJsonTable.$, YdbJsonTable.$.value(), - valuesToInsert, expectedValues); - } - @Test public void boolTest() { String[] valuesToInsert = new String[]{"false", "true"}; @@ -283,6 +273,16 @@ public void interval64Test() { valuesToInsert, expectedValues); } + @Test + public void jsonTest() { + String[] valuesToInsert = new String[]{"Json(@@{\"a\":1,\"b\":null}@@)"}; + String[] expectedValues = new String[]{"{\"a\":1,\"b\":null}"}; + + typeTest("ydb_json", "Json", + YdbJsonTable.$, YdbJsonTable.$.value(), + valuesToInsert, expectedValues); + } + @Test public void stringTest() { String[] valuesToInsert = new String[]{"\"0\"", "\"string\""}; diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/json/Json.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbJson/Json.java similarity index 88% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/json/Json.java rename to dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbJson/Json.java index 19e5baf5..29c4febb 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/model/type/json/Json.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbJson/Json.java @@ -1,4 +1,4 @@ -package ydb.jimmer.dialect.model.type.json; +package ydb.jimmer.dialect.model.type.ydbJson; import org.babyfish.jimmer.sql.Serialized; diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/json/YdbJson.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbJson/YdbJson.java similarity index 86% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/json/YdbJson.java rename to dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbJson/YdbJson.java index 9aa88aff..ed48b625 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/model/type/json/YdbJson.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbJson/YdbJson.java @@ -1,4 +1,4 @@ -package ydb.jimmer.dialect.model.type.json; +package ydb.jimmer.dialect.model.type.ydbJson; import org.babyfish.jimmer.sql.Column; import org.babyfish.jimmer.sql.Entity; From d5d9491e56f507a1c066811f41fe966d8df4098c Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Thu, 12 Feb 2026 22:56:21 +0300 Subject: [PATCH 30/98] Added a Enum test --- .../java/ydb/jimmer/dialect/DataTypeTest.java | 11 +++++++++++ .../dialect/model/type/ydbEnum/Value.java | 8 ++++++++ .../dialect/model/type/ydbEnum/YdbEnum.java | 17 +++++++++++++++++ 3 files changed, 36 insertions(+) create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbEnum/Value.java create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbEnum/YdbEnum.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/DataTypeTest.java b/dialect/src/test/java/ydb/jimmer/dialect/DataTypeTest.java index c7f8d1f4..ccbe6ea2 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/DataTypeTest.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/DataTypeTest.java @@ -3,6 +3,7 @@ import org.babyfish.jimmer.sql.ast.PropExpression; import org.babyfish.jimmer.sql.ast.table.spi.AbstractTypedTable; import org.junit.jupiter.api.Test; +import ydb.jimmer.dialect.model.type.ydbEnum.YdbEnumTable; import ydb.jimmer.dialect.model.type.ydbJson.YdbJsonTable; import ydb.jimmer.dialect.model.type.ydbBool.YdbBooleanClassTable; import ydb.jimmer.dialect.model.type.ydbBool.YdbBooleanTable; @@ -176,6 +177,16 @@ public void doubleTest() { valuesToInsert, expectedValues); } + @Test + public void enumTest() { + String[] valuesToInsert = new String[]{"\"ONE\"", "\"TWO\""}; + String[] expectedValues = new String[]{"\"ONE\"", "\"TWO\""}; + + typeTest("ydb_enum", "Utf8", + YdbEnumTable.$, YdbEnumTable.$.value(), + valuesToInsert, expectedValues); + } + @Test public void floatTest() { String[] valuesToInsert = new String[]{"Float(\"1.23\")"}; diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbEnum/Value.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbEnum/Value.java new file mode 100644 index 00000000..24a524c9 --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbEnum/Value.java @@ -0,0 +1,8 @@ +package ydb.jimmer.dialect.model.type.ydbEnum; + +import org.babyfish.jimmer.sql.EnumType; + +@EnumType(EnumType.Strategy.NAME) +public enum Value { + ONE, TWO +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbEnum/YdbEnum.java b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbEnum/YdbEnum.java new file mode 100644 index 00000000..0fe8f5f7 --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbEnum/YdbEnum.java @@ -0,0 +1,17 @@ +package ydb.jimmer.dialect.model.type.ydbEnum; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +@Entity +@Table(name = "ydb_enum") +public interface YdbEnum { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + Value value(); +} From 9397554378b674e004046284e8eb67cbf2e990c0 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Thu, 12 Feb 2026 23:37:06 +0300 Subject: [PATCH 31/98] Removed support for arrays --- .../src/main/java/ydb/jimmer/dialect/YdbDialect.java | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java b/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java index 0927f9ee..f09fc90e 100644 --- a/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java +++ b/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java @@ -7,8 +7,6 @@ import org.babyfish.jimmer.sql.dialect.DefaultDialect; import org.jetbrains.annotations.Nullable; -import java.sql.ResultSet; -import java.sql.SQLException; import java.sql.Types; import static ydb.jimmer.dialect.constant.YdbClassMapping.classToJdbcType; @@ -39,16 +37,6 @@ public boolean isUpdateAliasSupported() { return false; } - @Override - public boolean isArraySupported() { - return true; - } - - @Override - public T[] getArray(ResultSet rs, int col, Class arrayType) throws SQLException { - return rs.getObject(col, arrayType); - } - @Override public boolean isTableOfSubQueryMutable() { return false; From 48c456e84425bfd7848d8c9c8836e5768c6d4daf Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Fri, 13 Feb 2026 01:50:01 +0300 Subject: [PATCH 32/98] Added batchUpdate and bulkUpsert --- dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java b/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java index f09fc90e..316fa990 100644 --- a/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java +++ b/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java @@ -101,6 +101,10 @@ public void update(UpdateContext ctx) { .appendId(); } + public void batchUpdate(UpdateContext ctx) { + update(ctx.sql("BATCH ")); + } + @Override public void upsert(UpsertContext ctx) { if (ctx.isUpdateIgnored() || !ctx.hasUpdatedColumns()) { @@ -126,6 +130,10 @@ public void upsert(UpsertContext ctx) { } } + public void bulkUpsert(UpsertContext ctx) { + upsert(ctx.sql("BULK ")); + } + @Override public String transCacheOperatorTableDDL() { return """ From bd53d427513c05f606e7e0ac55479067cb1f4af8 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Fri, 13 Feb 2026 05:23:11 +0300 Subject: [PATCH 33/98] Added YqlClentBuilder --- .../ydb/jimmer/dialect/YqlClientBuilder.java | 19 +++++++++++++++++++ .../test/java/ydb/jimmer/dialect/YdbTest.java | 4 +--- 2 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java diff --git a/dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java b/dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java new file mode 100644 index 00000000..88e5d50c --- /dev/null +++ b/dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java @@ -0,0 +1,19 @@ +package ydb.jimmer.dialect; + +import org.babyfish.jimmer.sql.JSqlClient; +import ydb.jimmer.dialect.scalar.DurationProvider; + +public final class YqlClientBuilder { + private YqlClientBuilder() {} + + public static JSqlClient.Builder getBuilder() { + return JSqlClient.newBuilder() + .setDialect(new YdbDialect()) + .addScalarProvider(new DurationProvider()) + .setCacheOperator(new UuidTransactionCacheOperator()); + } + + public static JSqlClient getYqlClient() { + return getBuilder().build(); + } +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java b/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java index dd779bb3..fa5c9f1b 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java @@ -28,10 +28,8 @@ public class YdbTest { private static final JSqlClient yqlClient; static { - yqlClient = JSqlClient.newBuilder() + yqlClient = YqlClientBuilder.getBuilder() .setExecutor(executor) - .setDialect(new YdbDialect()) - .addScalarProvider(new DurationProvider()) .build(); } From ba2c0970904b3192f2e620f0fed3e303a2b9336e Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Fri, 13 Feb 2026 05:23:34 +0300 Subject: [PATCH 34/98] Added a class to manage retries during transactions --- .../dialect/RetryConnectionManager.java | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 dialect/src/main/java/ydb/jimmer/dialect/RetryConnectionManager.java diff --git a/dialect/src/main/java/ydb/jimmer/dialect/RetryConnectionManager.java b/dialect/src/main/java/ydb/jimmer/dialect/RetryConnectionManager.java new file mode 100644 index 00000000..f40c8d57 --- /dev/null +++ b/dialect/src/main/java/ydb/jimmer/dialect/RetryConnectionManager.java @@ -0,0 +1,98 @@ +package ydb.jimmer.dialect; + +import org.babyfish.jimmer.sql.transaction.Propagation; +import org.babyfish.jimmer.sql.transaction.TxConnectionManager; +import org.jetbrains.annotations.Nullable; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.SQLTimeoutException; +import java.util.function.Function; + +/** + * Provides retry from abort/timeout for transactions. + * While using frameworks like spring this class is redundant. + * With spring the "@Retryable" annotation is preferable. + */ +public class RetryConnectionManager implements TxConnectionManager { + private final DataSource dataSource; + private final int maxRetries; + private final long retryDelayMs; + + public RetryConnectionManager(DataSource dataSource, int maxRetries, long retryDelayMs) { + this.dataSource = dataSource; + this.maxRetries = maxRetries; + this.retryDelayMs = retryDelayMs; + } + + @Override + public R executeTransaction(Propagation propagation, Function block) { + for (int i = 0; i < maxRetries; i++) { + try (Connection connection = dataSource.getConnection()) { + try { + connection.setAutoCommit(false); + R result = block.apply(connection); + connection.commit(); + return result; + } catch (SQLException ex) { + connection.rollback(); + if (i == maxRetries - 1 || !isRetryable(ex)) { + throw new RuntimeException(ex); + } + } + } catch (SQLException ex) { + if (i == maxRetries - 1 || !isRetryable(ex)) { + throw new RuntimeException(ex); + } + } + try { + Thread.sleep(retryDelayMs); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + throw new RuntimeException(ie); + } + } + + throw new RuntimeException("Max retries exceeded"); + } + + @Override + public R execute(@Nullable Connection con, Function block) { + if (con != null) { + // No connection management, no transaction management, everything is controlled by user. + return block.apply(con); + } + + for (int i = 0; i < maxRetries; i++) { + try (Connection connection = dataSource.getConnection()) { + return block.apply(connection); + } catch (SQLException ex) { + if (i == maxRetries - 1 || !isRetryable(ex)) { + throw new RuntimeException(ex); + } + try { + Thread.sleep(retryDelayMs); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + throw new RuntimeException(ie); + } + } + } + + throw new RuntimeException("Max retries exceeded"); + } + + private boolean isRetryable(Exception ex) { + return ex instanceof SQLTimeoutException || + (ex instanceof SQLException && isRetryableSqlState((SQLException) ex)); + } + + private boolean isRetryableSqlState(SQLException ex) { + String sqlState = ex.getSQLState(); + return sqlState != null && ( + sqlState.startsWith("40") || // Transaction rollback + "08S01".equals(sqlState) // Communication link failure + ); + } +} From 617cc759a8dae99a8fb2c3efe52a14ec481c2ccf Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Fri, 13 Feb 2026 10:17:48 +0300 Subject: [PATCH 35/98] Added "insert into" tests --- dialect/pom.xml | 13 +- .../ydb/jimmer/dialect/YqlClientBuilder.java | 3 +- .../jimmer/dialect/AbstractInsertTest.java | 30 ++ .../jimmer/dialect/AbstractSelectTest.java | 34 ++ .../{YdbTest.java => AbstractTest.java} | 41 +- .../ydb/jimmer/dialect/QueryTestContext.java | 39 ++ .../java/ydb/jimmer/dialect/SelectTest.java | 2 +- .../dataTypeTest/InsertDataTypeTest.java | 379 ++++++++++++++++++ .../SelectDataTypeTest.java} | 26 +- 9 files changed, 508 insertions(+), 59 deletions(-) create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/AbstractInsertTest.java create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/AbstractSelectTest.java rename dialect/src/test/java/ydb/jimmer/dialect/{YdbTest.java => AbstractTest.java} (68%) create mode 100644 dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java rename dialect/src/test/java/ydb/jimmer/dialect/{DataTypeTest.java => dataTypeTest/SelectDataTypeTest.java} (95%) diff --git a/dialect/pom.xml b/dialect/pom.xml index 1bbf75e3..72c26aa3 100644 --- a/dialect/pom.xml +++ b/dialect/pom.xml @@ -22,12 +22,6 @@ jimmer-sql ${jimmer.version} - - - org.json - json - 20250517 - com.fasterxml.jackson.datatype @@ -69,6 +63,13 @@ 2.3.29 test + + + org.liquibase + liquibase-core + 5.0.1 + compile + diff --git a/dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java b/dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java index 88e5d50c..cfbcbdac 100644 --- a/dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java +++ b/dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java @@ -9,8 +9,7 @@ private YqlClientBuilder() {} public static JSqlClient.Builder getBuilder() { return JSqlClient.newBuilder() .setDialect(new YdbDialect()) - .addScalarProvider(new DurationProvider()) - .setCacheOperator(new UuidTransactionCacheOperator()); + .addScalarProvider(new DurationProvider()); } public static JSqlClient getYqlClient() { diff --git a/dialect/src/test/java/ydb/jimmer/dialect/AbstractInsertTest.java b/dialect/src/test/java/ydb/jimmer/dialect/AbstractInsertTest.java new file mode 100644 index 00000000..76a08acf --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/AbstractInsertTest.java @@ -0,0 +1,30 @@ +package ydb.jimmer.dialect; + +import org.babyfish.jimmer.sql.ast.Executable; +import org.babyfish.jimmer.sql.ast.mutation.MutationResult; +import org.junit.jupiter.api.Assertions; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.function.Consumer; + +public class AbstractInsertTest extends AbstractTest { + protected void executeAndExpect(Executable query, Consumer block) { + MutationResult result = null; + Throwable throwable = null; + try (Connection connection = DriverManager.getConnection(getJdbcURL())) { + try { + result = query.execute(connection); + } catch (Throwable ex) { + throwable = ex; + } finally { + connection.rollback(); + } + } catch (SQLException e) { + Assertions.fail("Database threw an exception: " + e.getMessage()); + } + + block.accept(new QueryTestContext(executor.getLogs(), result, throwable)); + } +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/AbstractSelectTest.java b/dialect/src/test/java/ydb/jimmer/dialect/AbstractSelectTest.java new file mode 100644 index 00000000..aa275ceb --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/AbstractSelectTest.java @@ -0,0 +1,34 @@ +package ydb.jimmer.dialect; + +import org.babyfish.jimmer.sql.ast.query.TypedRootQuery; +import org.junit.jupiter.api.Assertions; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.List; +import java.util.function.Consumer; + +public abstract class AbstractSelectTest extends AbstractTest { + protected void executeAndExpect(TypedRootQuery query, Consumer block) { + List rows = connectAndExecute(true, query); + block.accept(new QueryTestContext(executor.getLogs(), rows)); + } + + private List connectAndExecute(boolean rollback, TypedRootQuery query) { + try (Connection connection = DriverManager.getConnection(getJdbcURL())) { + connection.setAutoCommit(!rollback); + try { + return query.execute(connection); + } finally { + if (rollback) { + connection.rollback(); + } + } + } catch (SQLException e) { + Assertions.fail("Database threw an exception: " + e.getMessage()); + } + + return null; + } +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java b/dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java similarity index 68% rename from dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java rename to dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java index fa5c9f1b..826f22b5 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/YdbTest.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java @@ -1,7 +1,6 @@ package ydb.jimmer.dialect; import org.babyfish.jimmer.sql.JSqlClient; -import org.babyfish.jimmer.sql.ast.query.TypedRootQuery; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.extension.RegisterExtension; import org.springframework.core.io.UrlResource; @@ -9,7 +8,6 @@ import org.springframework.jdbc.datasource.init.ScriptException; import org.springframework.jdbc.datasource.init.ScriptUtils; import tech.ydb.test.junit5.YdbHelperExtension; -import ydb.jimmer.dialect.scalar.DurationProvider; import ydb.jimmer.dialect.sqlMonitor.ExecutorMonitor; import java.net.URL; @@ -17,14 +15,12 @@ import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; -import java.util.List; -import java.util.function.Consumer; -public class YdbTest { +public abstract class AbstractTest { @RegisterExtension private static final YdbHelperExtension ydb = new YdbHelperExtension(); - private static final ExecutorMonitor executor = new ExecutorMonitor(); + protected static final ExecutorMonitor executor = new ExecutorMonitor(); private static final JSqlClient yqlClient; static { @@ -39,7 +35,7 @@ protected JSqlClient getYqlClient() { protected void initDatabase() { try (Connection connection = DriverManager.getConnection(getJdbcURL())) { - URL dropTablesUrl = YdbTest.class.getClassLoader().getResource("database-drop-tables-ydb.sql"); + URL dropTablesUrl = AbstractTest.class.getClassLoader().getResource("database-drop-tables-ydb.sql"); if (dropTablesUrl == null) { throw new IllegalStateException("Cannot load 'database-drop-tables-ydb.sql'"); } @@ -49,7 +45,7 @@ protected void initDatabase() { // } - URL url = YdbTest.class.getClassLoader().getResource("database-ydb.sql"); + URL url = AbstractTest.class.getClassLoader().getResource("database-ydb.sql"); if (url == null) { throw new IllegalStateException("Cannot load 'database-ydb.sql'"); } @@ -71,7 +67,7 @@ private void executeYqlScript(Connection connection, URL url) throws ScriptExcep "*/"); } - private String getJdbcURL() { + protected String getJdbcURL() { StringBuilder jdbc = new StringBuilder("jdbc:ydb:") .append(ydb.useTls() ? "grpcs://" : "grpc://") .append(ydb.endpoint()) @@ -85,26 +81,13 @@ private String getJdbcURL() { return jdbc.toString(); } - public void executeAndExpect(TypedRootQuery query, Consumer block) { - List rows = connectAndExecute(true, query); - block.accept(new QueryTestContext(executor.getLogs(), rows)); - } - - protected List connectAndExecute(boolean rollback, TypedRootQuery query) { - try (Connection connection = DriverManager.getConnection(getJdbcURL())) { - connection.setAutoCommit(!rollback); - try { - return query.execute(connection); - } finally { - if (rollback) { - connection.rollback(); - } - } - } catch (SQLException e) { - Assertions.fail("Database threw an exception: " + e.getMessage()); - } - - return null; + protected void createTable(String tableName, String typeName) { + executeSql( + "CREATE TABLE " + tableName + "(" + + "id Int8," + + "value " + typeName + "," + + "PRIMARY KEY (id)" + + ")"); } protected void executeSql(String sql) { diff --git a/dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java b/dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java index 88a4a53d..7e6bfdee 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java @@ -4,10 +4,14 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.babyfish.jimmer.jackson.ImmutableModule; +import org.babyfish.jimmer.sql.ast.mutation.MutationResult; +import org.babyfish.jimmer.sql.collection.TypedList; import org.junit.jupiter.api.Assertions; import ydb.jimmer.dialect.sqlMonitor.QueryLog; import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; public class QueryTestContext { @@ -21,12 +25,23 @@ public class QueryTestContext { private final List logs; private final List rows; + private final MutationResult result; + private final Throwable throwable; private int index = 0; public QueryTestContext(List logs, List rows) { this.logs = logs; this.rows = rows; + result = null; + throwable = null; + } + + public QueryTestContext(List logs, MutationResult result, Throwable throwable) { + this.logs = logs; + this.rows = new ArrayList<>(); + this.result = result; + this.throwable = throwable; } public void nextStatement() { @@ -40,6 +55,30 @@ public void sql(String sql) { "statements[" + index + "].sql"); } + public void variables(Object ... values) { + Assertions.assertEquals( + values.length, + logs.get(index).getVariablesList().get(0).size(), + "statements[" + index + "].variables.size is error, actual variables: " + + logs.get(index).getVariablesList().get(0) + ); + for (int i = 0; i < values.length; i++) { + Object expect = values[i]; + + Object actual = logs.get(index).getVariablesList().get(0).get(i); + + Assertions.assertEquals( + expect, + actual, + "statements[" + index + "].variables[" + i + "] is error, " + + "expected variables: " + + Arrays.toString(values) + + ", actual variables: " + + actual + ); + } + } + public void rows(String json) { try { Assertions.assertEquals( diff --git a/dialect/src/test/java/ydb/jimmer/dialect/SelectTest.java b/dialect/src/test/java/ydb/jimmer/dialect/SelectTest.java index 4d2cfad8..188dac89 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/SelectTest.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/SelectTest.java @@ -5,7 +5,7 @@ import java.sql.SQLException; -public class SelectTest extends YdbTest { +public class SelectTest extends AbstractSelectTest { @Test public void OneEntityTest() throws SQLException { initDatabase(); diff --git a/dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java b/dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java new file mode 100644 index 00000000..25df8ea5 --- /dev/null +++ b/dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java @@ -0,0 +1,379 @@ +package ydb.jimmer.dialect.dataTypeTest; + +import org.babyfish.jimmer.sql.ast.mutation.SaveMode; +import org.junit.jupiter.api.Test; +import ydb.jimmer.dialect.AbstractInsertTest; +import ydb.jimmer.dialect.model.type.ydbBool.YdbBooleanClassDraft; +import ydb.jimmer.dialect.model.type.ydbBool.YdbBooleanDraft; +import ydb.jimmer.dialect.model.type.ydbDate32.YdbDateDraft; +import ydb.jimmer.dialect.model.type.ydbDate32.YdbLocalDateDraft; +import ydb.jimmer.dialect.model.type.ydbDatetime64.YdbLocalDateTimeDraft; +import ydb.jimmer.dialect.model.type.ydbDecimal.YdbBigDecimalDraft; +import ydb.jimmer.dialect.model.type.ydbDouble.YdbDoubleClassDraft; +import ydb.jimmer.dialect.model.type.ydbDouble.YdbDoubleDraft; +import ydb.jimmer.dialect.model.type.ydbEnum.Value; +import ydb.jimmer.dialect.model.type.ydbEnum.YdbEnumDraft; +import ydb.jimmer.dialect.model.type.ydbFloat.YdbFloatClassDraft; +import ydb.jimmer.dialect.model.type.ydbFloat.YdbFloatDraft; +import ydb.jimmer.dialect.model.type.ydbInt16.YdbShortClassDraft; +import ydb.jimmer.dialect.model.type.ydbInt16.YdbShortDraft; +import ydb.jimmer.dialect.model.type.ydbInt32.YdbIntDraft; +import ydb.jimmer.dialect.model.type.ydbInt32.YdbIntegerDraft; +import ydb.jimmer.dialect.model.type.ydbInt32.YdbLocalTimeDraft; +import ydb.jimmer.dialect.model.type.ydbInt32.YdbTimeDraft; +import ydb.jimmer.dialect.model.type.ydbInt64.YdbBigIntegerDraft; +import ydb.jimmer.dialect.model.type.ydbInt64.YdbLongClassDraft; +import ydb.jimmer.dialect.model.type.ydbInt64.YdbLongDraft; +import ydb.jimmer.dialect.model.type.ydbInt8.YdbByteClassDraft; +import ydb.jimmer.dialect.model.type.ydbInt8.YdbByteDraft; +import ydb.jimmer.dialect.model.type.ydbInterval64.YdbDurationDraft; +import ydb.jimmer.dialect.model.type.ydbJson.Json; +import ydb.jimmer.dialect.model.type.ydbJson.YdbJsonDraft; +import ydb.jimmer.dialect.model.type.ydbString.YdbByteArrayDraft; +import ydb.jimmer.dialect.model.type.ydbTimestamp64.YdbInstantDraft; +import ydb.jimmer.dialect.model.type.ydbTimestamp64.YdbTimestampDraft; +import ydb.jimmer.dialect.model.type.ydbTimestamp64.YdbUtilDateDraft; +import ydb.jimmer.dialect.model.type.ydbUtf8.YdbStringDraft; +import ydb.jimmer.dialect.model.type.ydbUuid.YdbUuidDraft; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.sql.Date; +import java.sql.Time; +import java.sql.Timestamp; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.UUID; + +public class InsertDataTypeTest extends AbstractInsertTest { + private void typeTest(String tableName, + String typeName, + Object input, + Object[] variables) { + createTable(tableName, typeName); + + executeAndExpect( + getYqlClient().getEntities().saveCommand(input) + .setMode(SaveMode.INSERT_ONLY), + cxt -> { + cxt.sql("insert into " + tableName + "(id, value) values(?, ?)"); + cxt.variables(variables); + } + ); + } + + @Test + public void boolTest() { + Object[] variables = new Object[]{0, true}; + + typeTest("ydb_boolean", "Bool", + YdbBooleanDraft.$.produce(t -> { + t.setId((Integer) variables[0]); + t.setValue((Boolean) variables[1]); + }), + variables + ); + + typeTest("ydb_boolean_class", "Bool", + YdbBooleanClassDraft.$.produce(t -> { + t.setId((Integer) variables[0]); + t.setValue((Boolean) variables[1]); + }), + variables); + } + + @Test + public void date32Test() { + Object[] variables1 = new Object[]{0, new Date(0)}; + + typeTest("ydb_date", "Date32", + YdbDateDraft.$.produce(t -> { + t.setId((Integer) variables1[0]); + t.setValue((Date) variables1[1]); + }), + variables1); + + Object[] variables2 = new Object[]{0, LocalDate.parse("1970-01-01")}; + + typeTest("ydb_local_date", "Date32", + YdbLocalDateDraft.$.produce(t -> { + t.setId((Integer) variables2[0]); + t.setValue((LocalDate) variables2[1]); + }), + variables2); + } + + @Test + public void dateTime64Test() { + Object[] variables = new Object[]{0, LocalDateTime.parse("1970-01-01T00:00:00")}; + + typeTest("ydb_local_date_time", "DateTime64", + YdbLocalDateTimeDraft.$.produce(t -> { + t.setId((Integer) variables[0]); + t.setValue((LocalDateTime) variables[1]); + }), + variables); + } + + @Test + public void decimalTest() { + Object[] variables = new Object[]{0, new BigDecimal(0)}; + + typeTest("ydb_big_decimal", "Decimal(22, 9)", + YdbBigDecimalDraft.$.produce(t -> { + t.setId((Integer) variables[0]); + t.setValue((BigDecimal) variables[1]); + }), + variables); + } + + @Test + public void doubleTest() { + Object[] variables = new Object[]{0, 0.1}; + + typeTest("ydb_double", "Double", + YdbDoubleDraft.$.produce(t -> { + t.setId((Integer) variables[0]); + t.setValue((double) variables[1]); + }), + variables); + + typeTest("ydb_double_class", "Double", + YdbDoubleClassDraft.$.produce(t -> { + t.setId((Integer) variables[0]); + t.setValue((Double) variables[1]); + }), + variables); + } + + @Test + public void enumTest() { + Object[] variables = new Object[]{0, Value.ONE}; + + typeTest("ydb_enum", "Utf8", + YdbEnumDraft.$.produce(t -> { + t.setId((Integer) variables[0]); + t.setValue((Value) variables[1]); + }), + new Object[]{0, "ONE"}); + } + + @Test + public void floatTest() { + Object[] variables = new Object[]{0, (float) 0.1}; + + typeTest("ydb_float", "Float", + YdbFloatDraft.$.produce(t -> { + t.setId((Integer) variables[0]); + t.setValue((float) variables[1]); + }), + variables); + + typeTest("ydb_float_class", "Float", + YdbFloatClassDraft.$.produce(t -> { + t.setId((Integer) variables[0]); + t.setValue((Float) variables[1]); + }), + variables); + } + + @Test + public void int8Test() { + Object[] variables = new Object[]{0, (byte) 1}; + + typeTest("ydb_byte", "Int8", + YdbByteDraft.$.produce(t -> { + t.setId((Integer) variables[0]); + t.setValue((byte) variables[1]); + }), + variables); + + typeTest("ydb_byte_class", "Int8", + YdbByteClassDraft.$.produce(t -> { + t.setId((Integer) variables[0]); + t.setValue((Byte) variables[1]); + }), + variables); + } + + @Test + public void int16Test() { + Object[] variables = new Object[]{0, (short) 1}; + + typeTest("ydb_short", "Int16", + YdbShortDraft.$.produce(t -> { + t.setId((Integer) variables[0]); + t.setValue((short) variables[1]); + }), + variables); + + typeTest("ydb_short_class", "Int16", + YdbShortClassDraft.$.produce(t -> { + t.setId((Integer) variables[0]); + t.setValue((Short) variables[1]); + }), + variables); + } + + @Test + public void int32Test() { + Object[] variables = new Object[]{0, 1}; + + typeTest("ydb_int", "Int32", + YdbIntDraft.$.produce(t -> { + t.setId((Integer) variables[0]); + t.setValue((int) variables[1]); + }), + variables); + + typeTest("ydb_integer", "Int32", + YdbIntegerDraft.$.produce(t -> { + t.setId((Integer) variables[0]); + t.setValue((Integer) variables[1]); + }), + variables); + + Object[] variables1 = new Object[]{0, LocalTime.parse("10:15")}; + + typeTest("ydb_local_time", "Int32", + YdbLocalTimeDraft.$.produce(t -> { + t.setId((Integer) variables1[0]); + t.setValue((LocalTime) variables1[1]); + }), + variables1); + + Object[] variables2 = new Object[]{0, new Time(0)}; + + typeTest("ydb_time", "Int32", + YdbTimeDraft.$.produce(t -> { + t.setId((Integer) variables2[0]); + t.setValue((Time) variables2[1]); + }), + variables2); + } + + @Test + public void int64Test() { + Object[] variables = new Object[]{0, new BigInteger("1234567890")}; + + typeTest("ydb_big_integer", "Int64", + YdbBigIntegerDraft.$.produce(t -> { + t.setId((Integer) variables[0]); + t.setValue((BigInteger) variables[1]); + }), + variables); + + Object[] variables1 = new Object[]{0, (long) 1}; + + typeTest("ydb_long", "Int64", + YdbLongDraft.$.produce(t -> { + t.setId((Integer) variables1[0]); + t.setValue((long) variables1[1]); + }), + variables1); + + typeTest("ydb_long_class", "Int64", + YdbLongClassDraft.$.produce(t -> { + t.setId((Integer) variables1[0]); + t.setValue((Long) variables1[1]); + }), + variables1); + } + + @Test + public void interval64Test() { + Object[] variables = new Object[]{0, Duration.ofHours(1)}; + + typeTest("ydb_duration", "Interval64", + YdbDurationDraft.$.produce(t -> { + t.setId((Integer) variables[0]); + t.setValue((Duration) variables[1]); + }), + variables); + } + + @Test + public void jsonTest() { + Json json = new Json(); + json.setA(2); + json.setB(3); + + Object[] variables = new Object[]{0, json}; + + typeTest("ydb_json", "Json", + YdbJsonDraft.$.produce(t -> { + t.setId((Integer) variables[0]); + t.setValue((Json) variables[1]); + }), + variables); + } + + @Test + public void stringTest() { + Object[] variables = new Object[]{0, new byte[]{1, 2}}; + + typeTest("ydb_byte_array", "String", + YdbByteArrayDraft.$.produce(t -> { + t.setId((Integer) variables[0]); + t.setValue((byte[]) variables[1]); + }), + variables); + } + + @Test + public void timestamp64Test() { + Object[] variables = new Object[]{0, Instant.now()}; + + typeTest("ydb_instant", "Timestamp64", + YdbInstantDraft.$.produce(t -> { + t.setId((Integer) variables[0]); + t.setValue((Instant) variables[1]); + }), + variables); + + Object[] variables1 = new Object[]{0, new Timestamp(0)}; + + typeTest("ydb_timestamp", "Timestamp64", + YdbTimestampDraft.$.produce(t -> { + t.setId((Integer) variables1[0]); + t.setValue((Timestamp) variables1[1]); + }), + variables1); + + Object[] variables2 = new Object[]{0, new java.util.Date(0)}; + + typeTest("ydb_util_date", "Timestamp64", + YdbUtilDateDraft.$.produce(t -> { + t.setId((Integer) variables2[0]); + t.setValue((java.util.Date) variables2[1]); + }), + variables2); + } + + @Test + public void utf8Test() { + Object[] variables = new Object[]{0, "ydb"}; + + typeTest("ydb_string", "Utf8", + YdbStringDraft.$.produce(t -> { + t.setId((Integer) variables[0]); + t.setValue((String) variables[1]); + }), + variables); + } + + @Test + public void uuidTest() { + Object[] variables = new Object[]{0, UUID.fromString("9e197d65-1914-4d57-a65f-77a52a06baa7")}; + + typeTest("ydb_uuid", "Uuid", + YdbUuidDraft.$.produce(t -> { + t.setId((Integer) variables[0]); + t.setValue((UUID) variables[1]); + }), + variables); + } +} diff --git a/dialect/src/test/java/ydb/jimmer/dialect/DataTypeTest.java b/dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java similarity index 95% rename from dialect/src/test/java/ydb/jimmer/dialect/DataTypeTest.java rename to dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java index ccbe6ea2..9d67d7c7 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/DataTypeTest.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java @@ -1,10 +1,9 @@ -package ydb.jimmer.dialect; +package ydb.jimmer.dialect.dataTypeTest; import org.babyfish.jimmer.sql.ast.PropExpression; import org.babyfish.jimmer.sql.ast.table.spi.AbstractTypedTable; import org.junit.jupiter.api.Test; -import ydb.jimmer.dialect.model.type.ydbEnum.YdbEnumTable; -import ydb.jimmer.dialect.model.type.ydbJson.YdbJsonTable; +import ydb.jimmer.dialect.AbstractSelectTest; import ydb.jimmer.dialect.model.type.ydbBool.YdbBooleanClassTable; import ydb.jimmer.dialect.model.type.ydbBool.YdbBooleanTable; import ydb.jimmer.dialect.model.type.ydbDate32.YdbDateTable; @@ -13,6 +12,7 @@ import ydb.jimmer.dialect.model.type.ydbDecimal.YdbBigDecimalTable; import ydb.jimmer.dialect.model.type.ydbDouble.YdbDoubleClassTable; import ydb.jimmer.dialect.model.type.ydbDouble.YdbDoubleTable; +import ydb.jimmer.dialect.model.type.ydbEnum.YdbEnumTable; import ydb.jimmer.dialect.model.type.ydbFloat.YdbFloatClassTable; import ydb.jimmer.dialect.model.type.ydbFloat.YdbFloatTable; import ydb.jimmer.dialect.model.type.ydbInt16.YdbShortClassTable; @@ -27,6 +27,7 @@ import ydb.jimmer.dialect.model.type.ydbInt8.YdbByteClassTable; import ydb.jimmer.dialect.model.type.ydbInt8.YdbByteTable; import ydb.jimmer.dialect.model.type.ydbInterval64.YdbDurationTable; +import ydb.jimmer.dialect.model.type.ydbJson.YdbJsonTable; import ydb.jimmer.dialect.model.type.ydbString.YdbByteArrayTable; import ydb.jimmer.dialect.model.type.ydbTimestamp64.YdbInstantTable; import ydb.jimmer.dialect.model.type.ydbTimestamp64.YdbTimestampTable; @@ -34,16 +35,7 @@ import ydb.jimmer.dialect.model.type.ydbUtf8.YdbStringTable; import ydb.jimmer.dialect.model.type.ydbUuid.YdbUuidTable; -public class DataTypeTest extends YdbTest { - private void createTable(String tableName, String typeName) { - executeSql( - "CREATE TABLE " + tableName + "(" + - "id Int8," + - "value " + typeName + "," + - "PRIMARY KEY (id)" + - ")"); - } - +public class SelectDataTypeTest extends AbstractSelectTest { private void insert(String tableName, String... values) { if (values.length == 0) { return; @@ -58,14 +50,6 @@ private void insert(String tableName, String... values) { executeSql(sql.toString()); } - /** - * - * @param typeName - * @param table - * @param prop - * @param valuesToInsert - * @param expectedValues expected and sorted (ASC) return values of the query - */ private void typeTest(String tableName, String typeName, AbstractTypedTable table, From b31d93dd447af06241efe9318dd36fd7d66ee11c Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Mon, 16 Feb 2026 15:38:22 +0300 Subject: [PATCH 36/98] Fixed the error message about slf4j --- dialect/pom.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dialect/pom.xml b/dialect/pom.xml index 72c26aa3..04bb4434 100644 --- a/dialect/pom.xml +++ b/dialect/pom.xml @@ -49,6 +49,13 @@ ${spring.version} test + + + org.slf4j + slf4j-api + 2.0.17 + compile + org.apache.logging.log4j From 3034bc20be839e6c79fd9e0ac7193bd82f48eedf Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Mon, 16 Feb 2026 18:44:58 +0300 Subject: [PATCH 37/98] Changed the structure of my ScalarProviders --- .../dialect/scalar/DumbYdbScalarProvider.java | 45 +++++++++++++++++++ .../dialect/scalar/DurationProvider.java | 37 +-------------- .../dialect/scalar/InstantProvider.java | 9 ++++ 3 files changed, 56 insertions(+), 35 deletions(-) create mode 100644 dialect/src/main/java/ydb/jimmer/dialect/scalar/DumbYdbScalarProvider.java create mode 100644 dialect/src/main/java/ydb/jimmer/dialect/scalar/InstantProvider.java diff --git a/dialect/src/main/java/ydb/jimmer/dialect/scalar/DumbYdbScalarProvider.java b/dialect/src/main/java/ydb/jimmer/dialect/scalar/DumbYdbScalarProvider.java new file mode 100644 index 00000000..38ddafa8 --- /dev/null +++ b/dialect/src/main/java/ydb/jimmer/dialect/scalar/DumbYdbScalarProvider.java @@ -0,0 +1,45 @@ +package ydb.jimmer.dialect.scalar; + +import org.babyfish.jimmer.sql.runtime.AbstractScalarProvider; +import org.babyfish.jimmer.sql.runtime.Reader; +import org.jetbrains.annotations.NotNull; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public abstract class DumbYdbScalarProvider extends AbstractScalarProvider { + private final Class clazz; + + public DumbYdbScalarProvider(Class clazz) { + super(clazz, clazz); + + this.clazz = clazz; + } + + @Override + public T toScalar(@NotNull T sqlValue) { + return sqlValue; + } + + @Override + public T toSql(@NotNull T scalarValue) { + return scalarValue; + } + + @Override + public Reader reader() { + return new DumbReader(); + } + + private class DumbReader implements Reader { + @Override + public T read(ResultSet rs, Context ctx) throws SQLException { + return rs.getObject(ctx.col(), clazz); + } + + @Override + public void skip(Context ctx) { + ctx.col(); + } + } +} diff --git a/dialect/src/main/java/ydb/jimmer/dialect/scalar/DurationProvider.java b/dialect/src/main/java/ydb/jimmer/dialect/scalar/DurationProvider.java index 79fd05fd..b647b3a3 100644 --- a/dialect/src/main/java/ydb/jimmer/dialect/scalar/DurationProvider.java +++ b/dialect/src/main/java/ydb/jimmer/dialect/scalar/DurationProvider.java @@ -1,42 +1,9 @@ package ydb.jimmer.dialect.scalar; -import org.babyfish.jimmer.sql.runtime.AbstractScalarProvider; -import org.babyfish.jimmer.sql.runtime.Reader; -import org.jetbrains.annotations.NotNull; - -import java.sql.ResultSet; -import java.sql.SQLException; import java.time.Duration; -public class DurationProvider extends AbstractScalarProvider { +public class DurationProvider extends DumbYdbScalarProvider { public DurationProvider() { - super(Duration.class, Duration.class); - } - - @Override - public Duration toScalar(@NotNull Duration sqlValue) { - return sqlValue; - } - - @Override - public Duration toSql(@NotNull Duration scalarValue) { - return scalarValue; - } - - @Override - public Reader reader() { - return new DurationReader(); - } - - private static class DurationReader implements Reader { - @Override - public Duration read(ResultSet rs, Context ctx) throws SQLException { - return rs.getObject(ctx.col(), Duration.class); - } - - @Override - public void skip(Context ctx) { - ctx.col(); - } + super(Duration.class); } } diff --git a/dialect/src/main/java/ydb/jimmer/dialect/scalar/InstantProvider.java b/dialect/src/main/java/ydb/jimmer/dialect/scalar/InstantProvider.java new file mode 100644 index 00000000..bf92c581 --- /dev/null +++ b/dialect/src/main/java/ydb/jimmer/dialect/scalar/InstantProvider.java @@ -0,0 +1,9 @@ +package ydb.jimmer.dialect.scalar; + +import java.time.Instant; + +public class InstantProvider extends DumbYdbScalarProvider { + public InstantProvider() { + super(Instant.class); + } +} From 828980c53142cb894fa28e7e0c4bb263f9bbed7b Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Mon, 16 Feb 2026 18:45:52 +0300 Subject: [PATCH 38/98] Extracted adding ScalarProviders to a new function --- .../java/ydb/jimmer/dialect/YqlClientBuilder.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java b/dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java index cfbcbdac..3dac9ce8 100644 --- a/dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java +++ b/dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java @@ -2,17 +2,25 @@ import org.babyfish.jimmer.sql.JSqlClient; import ydb.jimmer.dialect.scalar.DurationProvider; +import ydb.jimmer.dialect.scalar.InstantProvider; public final class YqlClientBuilder { private YqlClientBuilder() {} public static JSqlClient.Builder getBuilder() { - return JSqlClient.newBuilder() + return addScalarProviders( + JSqlClient.newBuilder() .setDialect(new YdbDialect()) - .addScalarProvider(new DurationProvider()); + ); } public static JSqlClient getYqlClient() { return getBuilder().build(); } + + public static JSqlClient.Builder addScalarProviders(JSqlClient.Builder builder) { + return builder + .addScalarProvider(new InstantProvider()) + .addScalarProvider(new DurationProvider()); + } } From 8cd7ac271bf50ed3ef8dab03e49ed991054279af Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Tue, 17 Feb 2026 15:45:49 +0300 Subject: [PATCH 39/98] Amend --- .../ydb/jimmer/dialect/QueryTestContext.java | 49 +++-- .../dataTypeTest/InsertDataTypeTest.java | 170 +++++++++--------- 2 files changed, 117 insertions(+), 102 deletions(-) diff --git a/dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java b/dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java index 7e6bfdee..a7c95514 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java @@ -50,33 +50,48 @@ public void nextStatement() { public void sql(String sql) { Assertions.assertEquals( - sql.replace("--->", ""), - logs.get(index).getSql(), + sql.replace("--->", "").toLowerCase(), + logs.get(index).getSql().toLowerCase(), "statements[" + index + "].sql"); } - public void variables(Object ... values) { + public void variables(Object[][] values) { Assertions.assertEquals( values.length, - logs.get(index).getVariablesList().get(0).size(), - "statements[" + index + "].variables.size is error, actual variables: " + - logs.get(index).getVariablesList().get(0) + logs.get(index).getVariablesList().size(), + "statements[" + index + "] actual batch size = " + + logs.get(index).getVariablesList().size() + + ", but expected batch size = " + + values.length ); - for (int i = 0; i < values.length; i++) { - Object expect = values[i]; - - Object actual = logs.get(index).getVariablesList().get(0).get(i); + for (int i = 0; i < values.length; i++) { Assertions.assertEquals( - expect, - actual, - "statements[" + index + "].variables[" + i + "] is error, " + - "expected variables: " + - Arrays.toString(values) + - ", actual variables: " + - actual + values[i].length, + logs.get(index).getVariablesList().get(i).size(), + "statements[" + index + "].batch[" + i + "] actual number of variables = " + + logs.get(index).getVariablesList().get(i).size() + + ", but expected number of variables = " + + values[i].length ); } + + for (int i = 0; i < values.length; i++) { + for (int j = 0; j < values[i].length; j++) { + Object expect = values[i][j]; + + Object actual = logs.get(index).getVariablesList().get(i).get(j); + + Assertions.assertEquals( + expect, + actual, + "statements[" + index + "].batch[" + i + "].variables[" + j + "] actual value = " + + actual + + ", but expected value = " + + expect + ); + } + } } public void rows(String json) { diff --git a/dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java b/dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java index 25df8ea5..839a3a54 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java @@ -52,7 +52,7 @@ public class InsertDataTypeTest extends AbstractInsertTest { private void typeTest(String tableName, String typeName, Object input, - Object[] variables) { + Object[][] variables) { createTable(tableName, typeName); executeAndExpect( @@ -67,230 +67,230 @@ private void typeTest(String tableName, @Test public void boolTest() { - Object[] variables = new Object[]{0, true}; + Object[][] variables = new Object[][]{{0, true}}; typeTest("ydb_boolean", "Bool", YdbBooleanDraft.$.produce(t -> { - t.setId((Integer) variables[0]); - t.setValue((Boolean) variables[1]); + t.setId((Integer) variables[0][0]); + t.setValue((Boolean) variables[0][1]); }), variables ); typeTest("ydb_boolean_class", "Bool", YdbBooleanClassDraft.$.produce(t -> { - t.setId((Integer) variables[0]); - t.setValue((Boolean) variables[1]); + t.setId((Integer) variables[0][0]); + t.setValue((Boolean) variables[0][1]); }), variables); } @Test public void date32Test() { - Object[] variables1 = new Object[]{0, new Date(0)}; + Object[][] variables1 = new Object[][]{{0, new Date(0)}}; typeTest("ydb_date", "Date32", YdbDateDraft.$.produce(t -> { - t.setId((Integer) variables1[0]); - t.setValue((Date) variables1[1]); + t.setId((Integer) variables1[0][0]); + t.setValue((Date) variables1[0][1]); }), variables1); - Object[] variables2 = new Object[]{0, LocalDate.parse("1970-01-01")}; + Object[][] variables2 = new Object[][]{{0, LocalDate.parse("1970-01-01")}}; typeTest("ydb_local_date", "Date32", YdbLocalDateDraft.$.produce(t -> { - t.setId((Integer) variables2[0]); - t.setValue((LocalDate) variables2[1]); + t.setId((Integer) variables2[0][0]); + t.setValue((LocalDate) variables2[0][1]); }), variables2); } @Test public void dateTime64Test() { - Object[] variables = new Object[]{0, LocalDateTime.parse("1970-01-01T00:00:00")}; + Object[][] variables = new Object[][]{{0, LocalDateTime.parse("1970-01-01T00:00:00")}}; typeTest("ydb_local_date_time", "DateTime64", YdbLocalDateTimeDraft.$.produce(t -> { - t.setId((Integer) variables[0]); - t.setValue((LocalDateTime) variables[1]); + t.setId((Integer) variables[0][0]); + t.setValue((LocalDateTime) variables[0][1]); }), variables); } @Test public void decimalTest() { - Object[] variables = new Object[]{0, new BigDecimal(0)}; + Object[][] variables = new Object[][]{{0, new BigDecimal(0)}}; typeTest("ydb_big_decimal", "Decimal(22, 9)", YdbBigDecimalDraft.$.produce(t -> { - t.setId((Integer) variables[0]); - t.setValue((BigDecimal) variables[1]); + t.setId((Integer) variables[0][0]); + t.setValue((BigDecimal) variables[0][1]); }), variables); } @Test public void doubleTest() { - Object[] variables = new Object[]{0, 0.1}; + Object[][] variables = new Object[][]{{0, 0.1}}; typeTest("ydb_double", "Double", YdbDoubleDraft.$.produce(t -> { - t.setId((Integer) variables[0]); - t.setValue((double) variables[1]); + t.setId((Integer) variables[0][0]); + t.setValue((double) variables[0][1]); }), variables); typeTest("ydb_double_class", "Double", YdbDoubleClassDraft.$.produce(t -> { - t.setId((Integer) variables[0]); - t.setValue((Double) variables[1]); + t.setId((Integer) variables[0][0]); + t.setValue((Double) variables[0][1]); }), variables); } @Test public void enumTest() { - Object[] variables = new Object[]{0, Value.ONE}; + Object[][] variables = new Object[][]{{0, Value.ONE}}; typeTest("ydb_enum", "Utf8", YdbEnumDraft.$.produce(t -> { - t.setId((Integer) variables[0]); - t.setValue((Value) variables[1]); + t.setId((Integer) variables[0][0]); + t.setValue((Value) variables[0][1]); }), - new Object[]{0, "ONE"}); + new Object[][]{{0, "ONE"}}); } @Test public void floatTest() { - Object[] variables = new Object[]{0, (float) 0.1}; + Object[][] variables = new Object[][]{{0, (float) 0.1}}; typeTest("ydb_float", "Float", YdbFloatDraft.$.produce(t -> { - t.setId((Integer) variables[0]); - t.setValue((float) variables[1]); + t.setId((Integer) variables[0][0]); + t.setValue((float) variables[0][1]); }), variables); typeTest("ydb_float_class", "Float", YdbFloatClassDraft.$.produce(t -> { - t.setId((Integer) variables[0]); - t.setValue((Float) variables[1]); + t.setId((Integer) variables[0][0]); + t.setValue((Float) variables[0][1]); }), variables); } @Test public void int8Test() { - Object[] variables = new Object[]{0, (byte) 1}; + Object[][] variables = new Object[][]{{0, (byte) 1}}; typeTest("ydb_byte", "Int8", YdbByteDraft.$.produce(t -> { - t.setId((Integer) variables[0]); - t.setValue((byte) variables[1]); + t.setId((Integer) variables[0][0]); + t.setValue((byte) variables[0][1]); }), variables); typeTest("ydb_byte_class", "Int8", YdbByteClassDraft.$.produce(t -> { - t.setId((Integer) variables[0]); - t.setValue((Byte) variables[1]); + t.setId((Integer) variables[0][0]); + t.setValue((Byte) variables[0][1]); }), variables); } @Test public void int16Test() { - Object[] variables = new Object[]{0, (short) 1}; + Object[][] variables = new Object[][]{{0, (short) 1}}; typeTest("ydb_short", "Int16", YdbShortDraft.$.produce(t -> { - t.setId((Integer) variables[0]); - t.setValue((short) variables[1]); + t.setId((Integer) variables[0][0]); + t.setValue((short) variables[0][1]); }), variables); typeTest("ydb_short_class", "Int16", YdbShortClassDraft.$.produce(t -> { - t.setId((Integer) variables[0]); - t.setValue((Short) variables[1]); + t.setId((Integer) variables[0][0]); + t.setValue((Short) variables[0][1]); }), variables); } @Test public void int32Test() { - Object[] variables = new Object[]{0, 1}; + Object[][] variables = new Object[][]{{0, 1}}; typeTest("ydb_int", "Int32", YdbIntDraft.$.produce(t -> { - t.setId((Integer) variables[0]); - t.setValue((int) variables[1]); + t.setId((Integer) variables[0][0]); + t.setValue((int) variables[0][1]); }), variables); typeTest("ydb_integer", "Int32", YdbIntegerDraft.$.produce(t -> { - t.setId((Integer) variables[0]); - t.setValue((Integer) variables[1]); + t.setId((Integer) variables[0][0]); + t.setValue((Integer) variables[0][1]); }), variables); - Object[] variables1 = new Object[]{0, LocalTime.parse("10:15")}; + Object[][] variables1 = new Object[][]{{0, LocalTime.parse("10:15")}}; typeTest("ydb_local_time", "Int32", YdbLocalTimeDraft.$.produce(t -> { - t.setId((Integer) variables1[0]); - t.setValue((LocalTime) variables1[1]); + t.setId((Integer) variables1[0][0]); + t.setValue((LocalTime) variables1[0][1]); }), variables1); - Object[] variables2 = new Object[]{0, new Time(0)}; + Object[][] variables2 = new Object[][]{{0, new Time(0)}}; typeTest("ydb_time", "Int32", YdbTimeDraft.$.produce(t -> { - t.setId((Integer) variables2[0]); - t.setValue((Time) variables2[1]); + t.setId((Integer) variables2[0][0]); + t.setValue((Time) variables2[0][1]); }), variables2); } @Test public void int64Test() { - Object[] variables = new Object[]{0, new BigInteger("1234567890")}; + Object[][] variables = new Object[][]{{0, new BigInteger("1234567890")}}; typeTest("ydb_big_integer", "Int64", YdbBigIntegerDraft.$.produce(t -> { - t.setId((Integer) variables[0]); - t.setValue((BigInteger) variables[1]); + t.setId((Integer) variables[0][0]); + t.setValue((BigInteger) variables[0][1]); }), variables); - Object[] variables1 = new Object[]{0, (long) 1}; + Object[][] variables1 = new Object[][]{{0, (long) 1}}; typeTest("ydb_long", "Int64", YdbLongDraft.$.produce(t -> { - t.setId((Integer) variables1[0]); - t.setValue((long) variables1[1]); + t.setId((Integer) variables1[0][0]); + t.setValue((long) variables1[0][1]); }), variables1); typeTest("ydb_long_class", "Int64", YdbLongClassDraft.$.produce(t -> { - t.setId((Integer) variables1[0]); - t.setValue((Long) variables1[1]); + t.setId((Integer) variables1[0][0]); + t.setValue((Long) variables1[0][1]); }), variables1); } @Test public void interval64Test() { - Object[] variables = new Object[]{0, Duration.ofHours(1)}; + Object[][] variables = new Object[][]{{0, Duration.ofHours(1)}}; typeTest("ydb_duration", "Interval64", YdbDurationDraft.$.produce(t -> { - t.setId((Integer) variables[0]); - t.setValue((Duration) variables[1]); + t.setId((Integer) variables[0][0]); + t.setValue((Duration) variables[0][1]); }), variables); } @@ -301,78 +301,78 @@ public void jsonTest() { json.setA(2); json.setB(3); - Object[] variables = new Object[]{0, json}; + Object[][] variables = new Object[][]{{0, json}}; typeTest("ydb_json", "Json", YdbJsonDraft.$.produce(t -> { - t.setId((Integer) variables[0]); - t.setValue((Json) variables[1]); + t.setId((Integer) variables[0][0]); + t.setValue((Json) variables[0][1]); }), variables); } @Test public void stringTest() { - Object[] variables = new Object[]{0, new byte[]{1, 2}}; + Object[][] variables = new Object[][]{{0, new byte[]{1, 2}}}; typeTest("ydb_byte_array", "String", YdbByteArrayDraft.$.produce(t -> { - t.setId((Integer) variables[0]); - t.setValue((byte[]) variables[1]); + t.setId((Integer) variables[0][0]); + t.setValue((byte[]) variables[0][1]); }), variables); } @Test public void timestamp64Test() { - Object[] variables = new Object[]{0, Instant.now()}; + Object[][] variables = new Object[][]{{0, Instant.now()}}; typeTest("ydb_instant", "Timestamp64", YdbInstantDraft.$.produce(t -> { - t.setId((Integer) variables[0]); - t.setValue((Instant) variables[1]); + t.setId((Integer) variables[0][0]); + t.setValue((Instant) variables[0][1]); }), variables); - Object[] variables1 = new Object[]{0, new Timestamp(0)}; + Object[][] variables1 = new Object[][]{{0, new Timestamp(0)}}; typeTest("ydb_timestamp", "Timestamp64", YdbTimestampDraft.$.produce(t -> { - t.setId((Integer) variables1[0]); - t.setValue((Timestamp) variables1[1]); + t.setId((Integer) variables1[0][0]); + t.setValue((Timestamp) variables1[0][1]); }), variables1); - Object[] variables2 = new Object[]{0, new java.util.Date(0)}; + Object[][] variables2 = new Object[][]{{0, new java.util.Date(0)}}; typeTest("ydb_util_date", "Timestamp64", YdbUtilDateDraft.$.produce(t -> { - t.setId((Integer) variables2[0]); - t.setValue((java.util.Date) variables2[1]); + t.setId((Integer) variables2[0][0]); + t.setValue((java.util.Date) variables2[0][1]); }), variables2); } @Test public void utf8Test() { - Object[] variables = new Object[]{0, "ydb"}; + Object[][] variables = new Object[][]{{0, "ydb"}}; typeTest("ydb_string", "Utf8", YdbStringDraft.$.produce(t -> { - t.setId((Integer) variables[0]); - t.setValue((String) variables[1]); + t.setId((Integer) variables[0][0]); + t.setValue((String) variables[0][1]); }), variables); } @Test public void uuidTest() { - Object[] variables = new Object[]{0, UUID.fromString("9e197d65-1914-4d57-a65f-77a52a06baa7")}; + Object[][] variables = new Object[][]{{0, UUID.fromString("9e197d65-1914-4d57-a65f-77a52a06baa7")}}; typeTest("ydb_uuid", "Uuid", YdbUuidDraft.$.produce(t -> { - t.setId((Integer) variables[0]); - t.setValue((UUID) variables[1]); + t.setId((Integer) variables[0][0]); + t.setValue((UUID) variables[0][1]); }), variables); } From 23acf02f72c32bd61923931d98cdb5c90fd00c42 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Fri, 27 Feb 2026 21:49:46 +0300 Subject: [PATCH 40/98] Revert "Amend" This reverts commit 8cd7ac271bf50ed3ef8dab03e49ed991054279af. --- .../ydb/jimmer/dialect/QueryTestContext.java | 49 ++--- .../dataTypeTest/InsertDataTypeTest.java | 170 +++++++++--------- 2 files changed, 102 insertions(+), 117 deletions(-) diff --git a/dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java b/dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java index a7c95514..7e6bfdee 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java @@ -50,47 +50,32 @@ public void nextStatement() { public void sql(String sql) { Assertions.assertEquals( - sql.replace("--->", "").toLowerCase(), - logs.get(index).getSql().toLowerCase(), + sql.replace("--->", ""), + logs.get(index).getSql(), "statements[" + index + "].sql"); } - public void variables(Object[][] values) { + public void variables(Object ... values) { Assertions.assertEquals( values.length, - logs.get(index).getVariablesList().size(), - "statements[" + index + "] actual batch size = " + - logs.get(index).getVariablesList().size() + - ", but expected batch size = " + - values.length + logs.get(index).getVariablesList().get(0).size(), + "statements[" + index + "].variables.size is error, actual variables: " + + logs.get(index).getVariablesList().get(0) ); - - for (int i = 0; i < values.length; i++) { - Assertions.assertEquals( - values[i].length, - logs.get(index).getVariablesList().get(i).size(), - "statements[" + index + "].batch[" + i + "] actual number of variables = " + - logs.get(index).getVariablesList().get(i).size() + - ", but expected number of variables = " + - values[i].length - ); - } - for (int i = 0; i < values.length; i++) { - for (int j = 0; j < values[i].length; j++) { - Object expect = values[i][j]; + Object expect = values[i]; - Object actual = logs.get(index).getVariablesList().get(i).get(j); + Object actual = logs.get(index).getVariablesList().get(0).get(i); - Assertions.assertEquals( - expect, - actual, - "statements[" + index + "].batch[" + i + "].variables[" + j + "] actual value = " + - actual + - ", but expected value = " + - expect - ); - } + Assertions.assertEquals( + expect, + actual, + "statements[" + index + "].variables[" + i + "] is error, " + + "expected variables: " + + Arrays.toString(values) + + ", actual variables: " + + actual + ); } } diff --git a/dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java b/dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java index 839a3a54..25df8ea5 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java @@ -52,7 +52,7 @@ public class InsertDataTypeTest extends AbstractInsertTest { private void typeTest(String tableName, String typeName, Object input, - Object[][] variables) { + Object[] variables) { createTable(tableName, typeName); executeAndExpect( @@ -67,230 +67,230 @@ private void typeTest(String tableName, @Test public void boolTest() { - Object[][] variables = new Object[][]{{0, true}}; + Object[] variables = new Object[]{0, true}; typeTest("ydb_boolean", "Bool", YdbBooleanDraft.$.produce(t -> { - t.setId((Integer) variables[0][0]); - t.setValue((Boolean) variables[0][1]); + t.setId((Integer) variables[0]); + t.setValue((Boolean) variables[1]); }), variables ); typeTest("ydb_boolean_class", "Bool", YdbBooleanClassDraft.$.produce(t -> { - t.setId((Integer) variables[0][0]); - t.setValue((Boolean) variables[0][1]); + t.setId((Integer) variables[0]); + t.setValue((Boolean) variables[1]); }), variables); } @Test public void date32Test() { - Object[][] variables1 = new Object[][]{{0, new Date(0)}}; + Object[] variables1 = new Object[]{0, new Date(0)}; typeTest("ydb_date", "Date32", YdbDateDraft.$.produce(t -> { - t.setId((Integer) variables1[0][0]); - t.setValue((Date) variables1[0][1]); + t.setId((Integer) variables1[0]); + t.setValue((Date) variables1[1]); }), variables1); - Object[][] variables2 = new Object[][]{{0, LocalDate.parse("1970-01-01")}}; + Object[] variables2 = new Object[]{0, LocalDate.parse("1970-01-01")}; typeTest("ydb_local_date", "Date32", YdbLocalDateDraft.$.produce(t -> { - t.setId((Integer) variables2[0][0]); - t.setValue((LocalDate) variables2[0][1]); + t.setId((Integer) variables2[0]); + t.setValue((LocalDate) variables2[1]); }), variables2); } @Test public void dateTime64Test() { - Object[][] variables = new Object[][]{{0, LocalDateTime.parse("1970-01-01T00:00:00")}}; + Object[] variables = new Object[]{0, LocalDateTime.parse("1970-01-01T00:00:00")}; typeTest("ydb_local_date_time", "DateTime64", YdbLocalDateTimeDraft.$.produce(t -> { - t.setId((Integer) variables[0][0]); - t.setValue((LocalDateTime) variables[0][1]); + t.setId((Integer) variables[0]); + t.setValue((LocalDateTime) variables[1]); }), variables); } @Test public void decimalTest() { - Object[][] variables = new Object[][]{{0, new BigDecimal(0)}}; + Object[] variables = new Object[]{0, new BigDecimal(0)}; typeTest("ydb_big_decimal", "Decimal(22, 9)", YdbBigDecimalDraft.$.produce(t -> { - t.setId((Integer) variables[0][0]); - t.setValue((BigDecimal) variables[0][1]); + t.setId((Integer) variables[0]); + t.setValue((BigDecimal) variables[1]); }), variables); } @Test public void doubleTest() { - Object[][] variables = new Object[][]{{0, 0.1}}; + Object[] variables = new Object[]{0, 0.1}; typeTest("ydb_double", "Double", YdbDoubleDraft.$.produce(t -> { - t.setId((Integer) variables[0][0]); - t.setValue((double) variables[0][1]); + t.setId((Integer) variables[0]); + t.setValue((double) variables[1]); }), variables); typeTest("ydb_double_class", "Double", YdbDoubleClassDraft.$.produce(t -> { - t.setId((Integer) variables[0][0]); - t.setValue((Double) variables[0][1]); + t.setId((Integer) variables[0]); + t.setValue((Double) variables[1]); }), variables); } @Test public void enumTest() { - Object[][] variables = new Object[][]{{0, Value.ONE}}; + Object[] variables = new Object[]{0, Value.ONE}; typeTest("ydb_enum", "Utf8", YdbEnumDraft.$.produce(t -> { - t.setId((Integer) variables[0][0]); - t.setValue((Value) variables[0][1]); + t.setId((Integer) variables[0]); + t.setValue((Value) variables[1]); }), - new Object[][]{{0, "ONE"}}); + new Object[]{0, "ONE"}); } @Test public void floatTest() { - Object[][] variables = new Object[][]{{0, (float) 0.1}}; + Object[] variables = new Object[]{0, (float) 0.1}; typeTest("ydb_float", "Float", YdbFloatDraft.$.produce(t -> { - t.setId((Integer) variables[0][0]); - t.setValue((float) variables[0][1]); + t.setId((Integer) variables[0]); + t.setValue((float) variables[1]); }), variables); typeTest("ydb_float_class", "Float", YdbFloatClassDraft.$.produce(t -> { - t.setId((Integer) variables[0][0]); - t.setValue((Float) variables[0][1]); + t.setId((Integer) variables[0]); + t.setValue((Float) variables[1]); }), variables); } @Test public void int8Test() { - Object[][] variables = new Object[][]{{0, (byte) 1}}; + Object[] variables = new Object[]{0, (byte) 1}; typeTest("ydb_byte", "Int8", YdbByteDraft.$.produce(t -> { - t.setId((Integer) variables[0][0]); - t.setValue((byte) variables[0][1]); + t.setId((Integer) variables[0]); + t.setValue((byte) variables[1]); }), variables); typeTest("ydb_byte_class", "Int8", YdbByteClassDraft.$.produce(t -> { - t.setId((Integer) variables[0][0]); - t.setValue((Byte) variables[0][1]); + t.setId((Integer) variables[0]); + t.setValue((Byte) variables[1]); }), variables); } @Test public void int16Test() { - Object[][] variables = new Object[][]{{0, (short) 1}}; + Object[] variables = new Object[]{0, (short) 1}; typeTest("ydb_short", "Int16", YdbShortDraft.$.produce(t -> { - t.setId((Integer) variables[0][0]); - t.setValue((short) variables[0][1]); + t.setId((Integer) variables[0]); + t.setValue((short) variables[1]); }), variables); typeTest("ydb_short_class", "Int16", YdbShortClassDraft.$.produce(t -> { - t.setId((Integer) variables[0][0]); - t.setValue((Short) variables[0][1]); + t.setId((Integer) variables[0]); + t.setValue((Short) variables[1]); }), variables); } @Test public void int32Test() { - Object[][] variables = new Object[][]{{0, 1}}; + Object[] variables = new Object[]{0, 1}; typeTest("ydb_int", "Int32", YdbIntDraft.$.produce(t -> { - t.setId((Integer) variables[0][0]); - t.setValue((int) variables[0][1]); + t.setId((Integer) variables[0]); + t.setValue((int) variables[1]); }), variables); typeTest("ydb_integer", "Int32", YdbIntegerDraft.$.produce(t -> { - t.setId((Integer) variables[0][0]); - t.setValue((Integer) variables[0][1]); + t.setId((Integer) variables[0]); + t.setValue((Integer) variables[1]); }), variables); - Object[][] variables1 = new Object[][]{{0, LocalTime.parse("10:15")}}; + Object[] variables1 = new Object[]{0, LocalTime.parse("10:15")}; typeTest("ydb_local_time", "Int32", YdbLocalTimeDraft.$.produce(t -> { - t.setId((Integer) variables1[0][0]); - t.setValue((LocalTime) variables1[0][1]); + t.setId((Integer) variables1[0]); + t.setValue((LocalTime) variables1[1]); }), variables1); - Object[][] variables2 = new Object[][]{{0, new Time(0)}}; + Object[] variables2 = new Object[]{0, new Time(0)}; typeTest("ydb_time", "Int32", YdbTimeDraft.$.produce(t -> { - t.setId((Integer) variables2[0][0]); - t.setValue((Time) variables2[0][1]); + t.setId((Integer) variables2[0]); + t.setValue((Time) variables2[1]); }), variables2); } @Test public void int64Test() { - Object[][] variables = new Object[][]{{0, new BigInteger("1234567890")}}; + Object[] variables = new Object[]{0, new BigInteger("1234567890")}; typeTest("ydb_big_integer", "Int64", YdbBigIntegerDraft.$.produce(t -> { - t.setId((Integer) variables[0][0]); - t.setValue((BigInteger) variables[0][1]); + t.setId((Integer) variables[0]); + t.setValue((BigInteger) variables[1]); }), variables); - Object[][] variables1 = new Object[][]{{0, (long) 1}}; + Object[] variables1 = new Object[]{0, (long) 1}; typeTest("ydb_long", "Int64", YdbLongDraft.$.produce(t -> { - t.setId((Integer) variables1[0][0]); - t.setValue((long) variables1[0][1]); + t.setId((Integer) variables1[0]); + t.setValue((long) variables1[1]); }), variables1); typeTest("ydb_long_class", "Int64", YdbLongClassDraft.$.produce(t -> { - t.setId((Integer) variables1[0][0]); - t.setValue((Long) variables1[0][1]); + t.setId((Integer) variables1[0]); + t.setValue((Long) variables1[1]); }), variables1); } @Test public void interval64Test() { - Object[][] variables = new Object[][]{{0, Duration.ofHours(1)}}; + Object[] variables = new Object[]{0, Duration.ofHours(1)}; typeTest("ydb_duration", "Interval64", YdbDurationDraft.$.produce(t -> { - t.setId((Integer) variables[0][0]); - t.setValue((Duration) variables[0][1]); + t.setId((Integer) variables[0]); + t.setValue((Duration) variables[1]); }), variables); } @@ -301,78 +301,78 @@ public void jsonTest() { json.setA(2); json.setB(3); - Object[][] variables = new Object[][]{{0, json}}; + Object[] variables = new Object[]{0, json}; typeTest("ydb_json", "Json", YdbJsonDraft.$.produce(t -> { - t.setId((Integer) variables[0][0]); - t.setValue((Json) variables[0][1]); + t.setId((Integer) variables[0]); + t.setValue((Json) variables[1]); }), variables); } @Test public void stringTest() { - Object[][] variables = new Object[][]{{0, new byte[]{1, 2}}}; + Object[] variables = new Object[]{0, new byte[]{1, 2}}; typeTest("ydb_byte_array", "String", YdbByteArrayDraft.$.produce(t -> { - t.setId((Integer) variables[0][0]); - t.setValue((byte[]) variables[0][1]); + t.setId((Integer) variables[0]); + t.setValue((byte[]) variables[1]); }), variables); } @Test public void timestamp64Test() { - Object[][] variables = new Object[][]{{0, Instant.now()}}; + Object[] variables = new Object[]{0, Instant.now()}; typeTest("ydb_instant", "Timestamp64", YdbInstantDraft.$.produce(t -> { - t.setId((Integer) variables[0][0]); - t.setValue((Instant) variables[0][1]); + t.setId((Integer) variables[0]); + t.setValue((Instant) variables[1]); }), variables); - Object[][] variables1 = new Object[][]{{0, new Timestamp(0)}}; + Object[] variables1 = new Object[]{0, new Timestamp(0)}; typeTest("ydb_timestamp", "Timestamp64", YdbTimestampDraft.$.produce(t -> { - t.setId((Integer) variables1[0][0]); - t.setValue((Timestamp) variables1[0][1]); + t.setId((Integer) variables1[0]); + t.setValue((Timestamp) variables1[1]); }), variables1); - Object[][] variables2 = new Object[][]{{0, new java.util.Date(0)}}; + Object[] variables2 = new Object[]{0, new java.util.Date(0)}; typeTest("ydb_util_date", "Timestamp64", YdbUtilDateDraft.$.produce(t -> { - t.setId((Integer) variables2[0][0]); - t.setValue((java.util.Date) variables2[0][1]); + t.setId((Integer) variables2[0]); + t.setValue((java.util.Date) variables2[1]); }), variables2); } @Test public void utf8Test() { - Object[][] variables = new Object[][]{{0, "ydb"}}; + Object[] variables = new Object[]{0, "ydb"}; typeTest("ydb_string", "Utf8", YdbStringDraft.$.produce(t -> { - t.setId((Integer) variables[0][0]); - t.setValue((String) variables[0][1]); + t.setId((Integer) variables[0]); + t.setValue((String) variables[1]); }), variables); } @Test public void uuidTest() { - Object[][] variables = new Object[][]{{0, UUID.fromString("9e197d65-1914-4d57-a65f-77a52a06baa7")}}; + Object[] variables = new Object[]{0, UUID.fromString("9e197d65-1914-4d57-a65f-77a52a06baa7")}; typeTest("ydb_uuid", "Uuid", YdbUuidDraft.$.produce(t -> { - t.setId((Integer) variables[0][0]); - t.setValue((UUID) variables[0][1]); + t.setId((Integer) variables[0]); + t.setValue((UUID) variables[1]); }), variables); } From c28a6085f815c12654fe7a3a242d042562af21d6 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Sun, 15 Mar 2026 19:09:24 +0300 Subject: [PATCH 41/98] fixed sql checks in tests --- .../src/test/java/ydb/jimmer/dialect/QueryTestContext.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java b/dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java index 7e6bfdee..54643814 100644 --- a/dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java +++ b/dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java @@ -50,8 +50,8 @@ public void nextStatement() { public void sql(String sql) { Assertions.assertEquals( - sql.replace("--->", ""), - logs.get(index).getSql(), + sql.replace("--->", "").toLowerCase(), + logs.get(index).getSql().toLowerCase(), "statements[" + index + "].sql"); } From 085056b0b55dd31ee4b33531f169e20e51dfd180 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Sun, 15 Mar 2026 19:52:38 +0300 Subject: [PATCH 42/98] renamed the directory for the jimmer dialect --- {dialect => jimmer-dialect}/pom.xml | 0 .../src/main/java/ydb/jimmer/dialect/RetryConnectionManager.java | 0 .../java/ydb/jimmer/dialect/UuidTransactionCacheOperator.java | 0 .../src/main/java/ydb/jimmer/dialect/YdbDialect.java | 0 .../src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java | 0 .../main/java/ydb/jimmer/dialect/constant/YdbClassMapping.java | 0 .../src/main/java/ydb/jimmer/dialect/constant/YdbConst.java | 0 .../src/main/java/ydb/jimmer/dialect/constant/YdbJdbcTypes.java | 0 .../java/ydb/jimmer/dialect/scalar/DumbYdbScalarProvider.java | 0 .../src/main/java/ydb/jimmer/dialect/scalar/DurationProvider.java | 0 .../src/main/java/ydb/jimmer/dialect/scalar/InstantProvider.java | 0 .../src/test/java/ydb/jimmer/dialect/AbstractInsertTest.java | 0 .../src/test/java/ydb/jimmer/dialect/AbstractSelectTest.java | 0 .../src/test/java/ydb/jimmer/dialect/AbstractTest.java | 0 .../src/test/java/ydb/jimmer/dialect/QueryTestContext.java | 0 .../src/test/java/ydb/jimmer/dialect/SelectTest.java | 0 .../java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java | 0 .../java/ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java | 0 .../src/test/java/ydb/jimmer/dialect/model/Group.java | 0 .../src/test/java/ydb/jimmer/dialect/model/Student.java | 0 .../java/ydb/jimmer/dialect/model/type/ydbBool/YdbBoolean.java | 0 .../ydb/jimmer/dialect/model/type/ydbBool/YdbBooleanClass.java | 0 .../java/ydb/jimmer/dialect/model/type/ydbDate32/YdbDate.java | 0 .../ydb/jimmer/dialect/model/type/ydbDate32/YdbLocalDate.java | 0 .../jimmer/dialect/model/type/ydbDatetime64/YdbLocalDateTime.java | 0 .../ydb/jimmer/dialect/model/type/ydbDecimal/YdbBigDecimal.java | 0 .../java/ydb/jimmer/dialect/model/type/ydbDouble/YdbDouble.java | 0 .../ydb/jimmer/dialect/model/type/ydbDouble/YdbDoubleClass.java | 0 .../test/java/ydb/jimmer/dialect/model/type/ydbEnum/Value.java | 0 .../test/java/ydb/jimmer/dialect/model/type/ydbEnum/YdbEnum.java | 0 .../java/ydb/jimmer/dialect/model/type/ydbFloat/YdbFloat.java | 0 .../ydb/jimmer/dialect/model/type/ydbFloat/YdbFloatClass.java | 0 .../java/ydb/jimmer/dialect/model/type/ydbInt16/YdbShort.java | 0 .../ydb/jimmer/dialect/model/type/ydbInt16/YdbShortClass.java | 0 .../test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbInt.java | 0 .../java/ydb/jimmer/dialect/model/type/ydbInt32/YdbInteger.java | 0 .../java/ydb/jimmer/dialect/model/type/ydbInt32/YdbLocalTime.java | 0 .../test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbTime.java | 0 .../ydb/jimmer/dialect/model/type/ydbInt64/YdbBigInteger.java | 0 .../test/java/ydb/jimmer/dialect/model/type/ydbInt64/YdbLong.java | 0 .../java/ydb/jimmer/dialect/model/type/ydbInt64/YdbLongClass.java | 0 .../test/java/ydb/jimmer/dialect/model/type/ydbInt8/YdbByte.java | 0 .../java/ydb/jimmer/dialect/model/type/ydbInt8/YdbByteClass.java | 0 .../ydb/jimmer/dialect/model/type/ydbInterval64/YdbDuration.java | 0 .../src/test/java/ydb/jimmer/dialect/model/type/ydbJson/Json.java | 0 .../test/java/ydb/jimmer/dialect/model/type/ydbJson/YdbJson.java | 0 .../ydb/jimmer/dialect/model/type/ydbString/YdbByteArray.java | 0 .../ydb/jimmer/dialect/model/type/ydbTimestamp64/YdbInstant.java | 0 .../jimmer/dialect/model/type/ydbTimestamp64/YdbTimestamp.java | 0 .../ydb/jimmer/dialect/model/type/ydbTimestamp64/YdbUtilDate.java | 0 .../java/ydb/jimmer/dialect/model/type/ydbUtf8/YdbString.java | 0 .../test/java/ydb/jimmer/dialect/model/type/ydbUuid/YdbUuid.java | 0 .../test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorMonitor.java | 0 .../src/test/java/ydb/jimmer/dialect/sqlMonitor/QueryLog.java | 0 .../src/test/resources/database-drop-tables-ydb.sql | 0 {dialect => jimmer-dialect}/src/test/resources/database-ydb.sql | 0 {dialect => jimmer-dialect}/src/test/resources/docker-compose.yml | 0 {dialect => jimmer-dialect}/src/test/resources/install.sh | 0 {dialect => jimmer-dialect}/src/test/resources/uninstall.sh | 0 59 files changed, 0 insertions(+), 0 deletions(-) rename {dialect => jimmer-dialect}/pom.xml (100%) rename {dialect => jimmer-dialect}/src/main/java/ydb/jimmer/dialect/RetryConnectionManager.java (100%) rename {dialect => jimmer-dialect}/src/main/java/ydb/jimmer/dialect/UuidTransactionCacheOperator.java (100%) rename {dialect => jimmer-dialect}/src/main/java/ydb/jimmer/dialect/YdbDialect.java (100%) rename {dialect => jimmer-dialect}/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java (100%) rename {dialect => jimmer-dialect}/src/main/java/ydb/jimmer/dialect/constant/YdbClassMapping.java (100%) rename {dialect => jimmer-dialect}/src/main/java/ydb/jimmer/dialect/constant/YdbConst.java (100%) rename {dialect => jimmer-dialect}/src/main/java/ydb/jimmer/dialect/constant/YdbJdbcTypes.java (100%) rename {dialect => jimmer-dialect}/src/main/java/ydb/jimmer/dialect/scalar/DumbYdbScalarProvider.java (100%) rename {dialect => jimmer-dialect}/src/main/java/ydb/jimmer/dialect/scalar/DurationProvider.java (100%) rename {dialect => jimmer-dialect}/src/main/java/ydb/jimmer/dialect/scalar/InstantProvider.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/AbstractInsertTest.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/AbstractSelectTest.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/AbstractTest.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/QueryTestContext.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/SelectTest.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/Group.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/Student.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/type/ydbBool/YdbBoolean.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/type/ydbBool/YdbBooleanClass.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/type/ydbDate32/YdbDate.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/type/ydbDate32/YdbLocalDate.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/type/ydbDatetime64/YdbLocalDateTime.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/type/ydbDecimal/YdbBigDecimal.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/type/ydbDouble/YdbDouble.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/type/ydbDouble/YdbDoubleClass.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/type/ydbEnum/Value.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/type/ydbEnum/YdbEnum.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/type/ydbFloat/YdbFloat.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/type/ydbFloat/YdbFloatClass.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/type/ydbInt16/YdbShort.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/type/ydbInt16/YdbShortClass.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbInt.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbInteger.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbLocalTime.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbTime.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/type/ydbInt64/YdbBigInteger.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/type/ydbInt64/YdbLong.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/type/ydbInt64/YdbLongClass.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/type/ydbInt8/YdbByte.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/type/ydbInt8/YdbByteClass.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/type/ydbInterval64/YdbDuration.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/type/ydbJson/Json.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/type/ydbJson/YdbJson.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/type/ydbString/YdbByteArray.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/type/ydbTimestamp64/YdbInstant.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/type/ydbTimestamp64/YdbTimestamp.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/type/ydbTimestamp64/YdbUtilDate.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/type/ydbUtf8/YdbString.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/model/type/ydbUuid/YdbUuid.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorMonitor.java (100%) rename {dialect => jimmer-dialect}/src/test/java/ydb/jimmer/dialect/sqlMonitor/QueryLog.java (100%) rename {dialect => jimmer-dialect}/src/test/resources/database-drop-tables-ydb.sql (100%) rename {dialect => jimmer-dialect}/src/test/resources/database-ydb.sql (100%) rename {dialect => jimmer-dialect}/src/test/resources/docker-compose.yml (100%) rename {dialect => jimmer-dialect}/src/test/resources/install.sh (100%) rename {dialect => jimmer-dialect}/src/test/resources/uninstall.sh (100%) diff --git a/dialect/pom.xml b/jimmer-dialect/pom.xml similarity index 100% rename from dialect/pom.xml rename to jimmer-dialect/pom.xml diff --git a/dialect/src/main/java/ydb/jimmer/dialect/RetryConnectionManager.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/RetryConnectionManager.java similarity index 100% rename from dialect/src/main/java/ydb/jimmer/dialect/RetryConnectionManager.java rename to jimmer-dialect/src/main/java/ydb/jimmer/dialect/RetryConnectionManager.java diff --git a/dialect/src/main/java/ydb/jimmer/dialect/UuidTransactionCacheOperator.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/UuidTransactionCacheOperator.java similarity index 100% rename from dialect/src/main/java/ydb/jimmer/dialect/UuidTransactionCacheOperator.java rename to jimmer-dialect/src/main/java/ydb/jimmer/dialect/UuidTransactionCacheOperator.java diff --git a/dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java similarity index 100% rename from dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java rename to jimmer-dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java diff --git a/dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java similarity index 100% rename from dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java rename to jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java diff --git a/dialect/src/main/java/ydb/jimmer/dialect/constant/YdbClassMapping.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/constant/YdbClassMapping.java similarity index 100% rename from dialect/src/main/java/ydb/jimmer/dialect/constant/YdbClassMapping.java rename to jimmer-dialect/src/main/java/ydb/jimmer/dialect/constant/YdbClassMapping.java diff --git a/dialect/src/main/java/ydb/jimmer/dialect/constant/YdbConst.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/constant/YdbConst.java similarity index 100% rename from dialect/src/main/java/ydb/jimmer/dialect/constant/YdbConst.java rename to jimmer-dialect/src/main/java/ydb/jimmer/dialect/constant/YdbConst.java diff --git a/dialect/src/main/java/ydb/jimmer/dialect/constant/YdbJdbcTypes.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/constant/YdbJdbcTypes.java similarity index 100% rename from dialect/src/main/java/ydb/jimmer/dialect/constant/YdbJdbcTypes.java rename to jimmer-dialect/src/main/java/ydb/jimmer/dialect/constant/YdbJdbcTypes.java diff --git a/dialect/src/main/java/ydb/jimmer/dialect/scalar/DumbYdbScalarProvider.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/scalar/DumbYdbScalarProvider.java similarity index 100% rename from dialect/src/main/java/ydb/jimmer/dialect/scalar/DumbYdbScalarProvider.java rename to jimmer-dialect/src/main/java/ydb/jimmer/dialect/scalar/DumbYdbScalarProvider.java diff --git a/dialect/src/main/java/ydb/jimmer/dialect/scalar/DurationProvider.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/scalar/DurationProvider.java similarity index 100% rename from dialect/src/main/java/ydb/jimmer/dialect/scalar/DurationProvider.java rename to jimmer-dialect/src/main/java/ydb/jimmer/dialect/scalar/DurationProvider.java diff --git a/dialect/src/main/java/ydb/jimmer/dialect/scalar/InstantProvider.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/scalar/InstantProvider.java similarity index 100% rename from dialect/src/main/java/ydb/jimmer/dialect/scalar/InstantProvider.java rename to jimmer-dialect/src/main/java/ydb/jimmer/dialect/scalar/InstantProvider.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/AbstractInsertTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractInsertTest.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/AbstractInsertTest.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractInsertTest.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/AbstractSelectTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractSelectTest.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/AbstractSelectTest.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractSelectTest.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/SelectTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/SelectTest.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/SelectTest.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/SelectTest.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/Group.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/Group.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/Group.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/Group.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/Student.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/Student.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/Student.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/Student.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbBool/YdbBoolean.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbBool/YdbBoolean.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbBool/YdbBoolean.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbBool/YdbBoolean.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbBool/YdbBooleanClass.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbBool/YdbBooleanClass.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbBool/YdbBooleanClass.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbBool/YdbBooleanClass.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDate32/YdbDate.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDate32/YdbDate.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDate32/YdbDate.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDate32/YdbDate.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDate32/YdbLocalDate.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDate32/YdbLocalDate.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDate32/YdbLocalDate.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDate32/YdbLocalDate.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDatetime64/YdbLocalDateTime.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDatetime64/YdbLocalDateTime.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDatetime64/YdbLocalDateTime.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDatetime64/YdbLocalDateTime.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDecimal/YdbBigDecimal.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDecimal/YdbBigDecimal.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDecimal/YdbBigDecimal.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDecimal/YdbBigDecimal.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDouble/YdbDouble.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDouble/YdbDouble.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDouble/YdbDouble.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDouble/YdbDouble.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDouble/YdbDoubleClass.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDouble/YdbDoubleClass.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDouble/YdbDoubleClass.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbDouble/YdbDoubleClass.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbEnum/Value.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbEnum/Value.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbEnum/Value.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbEnum/Value.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbEnum/YdbEnum.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbEnum/YdbEnum.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbEnum/YdbEnum.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbEnum/YdbEnum.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbFloat/YdbFloat.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbFloat/YdbFloat.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbFloat/YdbFloat.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbFloat/YdbFloat.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbFloat/YdbFloatClass.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbFloat/YdbFloatClass.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbFloat/YdbFloatClass.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbFloat/YdbFloatClass.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt16/YdbShort.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt16/YdbShort.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt16/YdbShort.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt16/YdbShort.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt16/YdbShortClass.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt16/YdbShortClass.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt16/YdbShortClass.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt16/YdbShortClass.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbInt.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbInt.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbInt.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbInt.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbInteger.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbInteger.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbInteger.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbInteger.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbLocalTime.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbLocalTime.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbLocalTime.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbLocalTime.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbTime.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbTime.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbTime.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt32/YdbTime.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt64/YdbBigInteger.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt64/YdbBigInteger.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt64/YdbBigInteger.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt64/YdbBigInteger.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt64/YdbLong.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt64/YdbLong.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt64/YdbLong.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt64/YdbLong.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt64/YdbLongClass.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt64/YdbLongClass.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt64/YdbLongClass.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt64/YdbLongClass.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt8/YdbByte.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt8/YdbByte.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt8/YdbByte.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt8/YdbByte.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt8/YdbByteClass.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt8/YdbByteClass.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt8/YdbByteClass.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInt8/YdbByteClass.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInterval64/YdbDuration.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInterval64/YdbDuration.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInterval64/YdbDuration.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbInterval64/YdbDuration.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbJson/Json.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbJson/Json.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbJson/Json.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbJson/Json.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbJson/YdbJson.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbJson/YdbJson.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbJson/YdbJson.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbJson/YdbJson.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbString/YdbByteArray.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbString/YdbByteArray.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbString/YdbByteArray.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbString/YdbByteArray.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbTimestamp64/YdbInstant.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbTimestamp64/YdbInstant.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbTimestamp64/YdbInstant.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbTimestamp64/YdbInstant.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbTimestamp64/YdbTimestamp.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbTimestamp64/YdbTimestamp.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbTimestamp64/YdbTimestamp.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbTimestamp64/YdbTimestamp.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbTimestamp64/YdbUtilDate.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbTimestamp64/YdbUtilDate.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbTimestamp64/YdbUtilDate.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbTimestamp64/YdbUtilDate.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbUtf8/YdbString.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbUtf8/YdbString.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbUtf8/YdbString.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbUtf8/YdbString.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbUuid/YdbUuid.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbUuid/YdbUuid.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbUuid/YdbUuid.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/type/ydbUuid/YdbUuid.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorMonitor.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorMonitor.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorMonitor.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorMonitor.java diff --git a/dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/QueryLog.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/QueryLog.java similarity index 100% rename from dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/QueryLog.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/QueryLog.java diff --git a/dialect/src/test/resources/database-drop-tables-ydb.sql b/jimmer-dialect/src/test/resources/database-drop-tables-ydb.sql similarity index 100% rename from dialect/src/test/resources/database-drop-tables-ydb.sql rename to jimmer-dialect/src/test/resources/database-drop-tables-ydb.sql diff --git a/dialect/src/test/resources/database-ydb.sql b/jimmer-dialect/src/test/resources/database-ydb.sql similarity index 100% rename from dialect/src/test/resources/database-ydb.sql rename to jimmer-dialect/src/test/resources/database-ydb.sql diff --git a/dialect/src/test/resources/docker-compose.yml b/jimmer-dialect/src/test/resources/docker-compose.yml similarity index 100% rename from dialect/src/test/resources/docker-compose.yml rename to jimmer-dialect/src/test/resources/docker-compose.yml diff --git a/dialect/src/test/resources/install.sh b/jimmer-dialect/src/test/resources/install.sh similarity index 100% rename from dialect/src/test/resources/install.sh rename to jimmer-dialect/src/test/resources/install.sh diff --git a/dialect/src/test/resources/uninstall.sh b/jimmer-dialect/src/test/resources/uninstall.sh similarity index 100% rename from dialect/src/test/resources/uninstall.sh rename to jimmer-dialect/src/test/resources/uninstall.sh From d533c08d72ea95d7e730492b078d16309cb2d4e3 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Mon, 16 Mar 2026 15:56:06 +0300 Subject: [PATCH 43/98] fixed upsert SQL in dialect --- .../src/main/java/ydb/jimmer/dialect/YdbDialect.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java index 316fa990..14b5807e 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java @@ -113,7 +113,7 @@ public void upsert(UpsertContext ctx) { .enter(AbstractSqlBuilder.ScopeType.MULTIPLE_LINE_TUPLE) .appendInsertedColumns("") .leave() - .sql("VALUES ") + .sql(" VALUES") .enter(AbstractSqlBuilder.ScopeType.MULTIPLE_LINE_TUPLE) .appendInsertingValues() .leave(); @@ -123,7 +123,7 @@ public void upsert(UpsertContext ctx) { .enter(AbstractSqlBuilder.ScopeType.MULTIPLE_LINE_TUPLE) .appendInsertedColumns("") .leave() - .sql("VALUES ") + .sql(" VALUES") .enter(AbstractSqlBuilder.ScopeType.MULTIPLE_LINE_TUPLE) .appendInsertingValues() .leave(); From 4c031b4ced82d2c5b41eb777ad4769603e709dc8 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Tue, 17 Mar 2026 05:00:19 +0300 Subject: [PATCH 44/98] Added tests for batch operations --- .../java/ydb/jimmer/dialect/AbstractTest.java | 17 ++++- .../ydb/jimmer/dialect/QueryTestContext.java | 17 +++-- .../ydb/jimmer/dialect/batch/BatchTest.java | 59 ++++++++++++++++ .../sqlMonitor/BatchExecutorMonitor.java | 70 +++++++++++++++++++ .../dialect/sqlMonitor/ExecutorMonitor.java | 11 ++- 5 files changed, 166 insertions(+), 8 deletions(-) create mode 100644 jimmer-dialect/src/test/java/ydb/jimmer/dialect/batch/BatchTest.java create mode 100644 jimmer-dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/BatchExecutorMonitor.java diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java index 826f22b5..4ab256d2 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java @@ -22,17 +22,28 @@ public abstract class AbstractTest { protected static final ExecutorMonitor executor = new ExecutorMonitor(); private static final JSqlClient yqlClient; + private static final JSqlClient yqlClientForBatch; static { yqlClient = YqlClientBuilder.getBuilder() .setExecutor(executor) .build(); + + yqlClientForBatch = YqlClientBuilder.getBuilder() + .setExecutor(executor) + .setExplicitBatchEnabled(true) + .setDumbBatchAcceptable(true) + .build(); } protected JSqlClient getYqlClient() { return yqlClient; } + protected JSqlClient getYqlClientForBatch() { + return yqlClientForBatch; + } + protected void initDatabase() { try (Connection connection = DriverManager.getConnection(getJdbcURL())) { URL dropTablesUrl = AbstractTest.class.getClassLoader().getResource("database-drop-tables-ydb.sql"); @@ -67,7 +78,7 @@ private void executeYqlScript(Connection connection, URL url) throws ScriptExcep "*/"); } - protected String getJdbcURL() { + protected static String getJdbcURL() { StringBuilder jdbc = new StringBuilder("jdbc:ydb:") .append(ydb.useTls() ? "grpcs://" : "grpc://") .append(ydb.endpoint()) @@ -81,7 +92,7 @@ protected String getJdbcURL() { return jdbc.toString(); } - protected void createTable(String tableName, String typeName) { + protected static void createTable(String tableName, String typeName) { executeSql( "CREATE TABLE " + tableName + "(" + "id Int8," + @@ -90,7 +101,7 @@ protected void createTable(String tableName, String typeName) { ")"); } - protected void executeSql(String sql) { + protected static void executeSql(String sql) { try (Connection connection = DriverManager.getConnection(getJdbcURL())) { try (Statement stmt = connection.createStatement()) { stmt.execute(sql); diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java index 54643814..188985f2 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java @@ -56,21 +56,30 @@ public void sql(String sql) { } public void variables(Object ... values) { + batchVariables(0, values); + batches(1); + } + + public void batches(int batchCount) { + Assertions.assertEquals(batchCount, logs.get(index).getVariablesList().size()); + } + + public void batchVariables(int batchIndex, Object ... values) { Assertions.assertEquals( values.length, - logs.get(index).getVariablesList().get(0).size(), + logs.get(index).getVariablesList().get(batchIndex).size(), "statements[" + index + "].variables.size is error, actual variables: " + - logs.get(index).getVariablesList().get(0) + logs.get(index).getVariablesList().get(batchIndex) ); for (int i = 0; i < values.length; i++) { Object expect = values[i]; - Object actual = logs.get(index).getVariablesList().get(0).get(i); + Object actual = logs.get(index).getVariablesList().get(batchIndex).get(i); Assertions.assertEquals( expect, actual, - "statements[" + index + "].variables[" + i + "] is error, " + + "statements[" + index + "].batch[" + batchIndex + "].variables[" + i + "] is error, " + "expected variables: " + Arrays.toString(values) + ", actual variables: " + diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/batch/BatchTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/batch/BatchTest.java new file mode 100644 index 00000000..cf03333b --- /dev/null +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/batch/BatchTest.java @@ -0,0 +1,59 @@ +package ydb.jimmer.dialect.batch; + +import org.babyfish.jimmer.sql.TargetTransferMode; +import org.babyfish.jimmer.sql.ast.mutation.SaveMode; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import ydb.jimmer.dialect.AbstractInsertTest; +import ydb.jimmer.dialect.model.type.ydbInt32.YdbIntDraft; + +import java.util.Arrays; + +public class BatchTest extends AbstractInsertTest { + private static final String TABLE_NAME = "ydb_int"; + + private void batchTest(SaveMode saveMode, String sql) { + executeAndExpect( + getYqlClientForBatch().getEntities().saveEntitiesCommand( + Arrays.asList( + YdbIntDraft.$.produce(t -> { + t.setId(0); + t.setValue(123); + }), + YdbIntDraft.$.produce(t -> { + t.setId(1); + t.setValue(456); + }) + )) + .setMode(saveMode), + cxt -> { + cxt.sql(sql); + cxt.batchVariables(0, 0, 123); + cxt.batchVariables(1, 1, 456); + } + ); + } + + @BeforeAll + static void setup() { + createTable(TABLE_NAME, "Int32"); + } + + @Test + public void insertTest() { + batchTest(SaveMode.INSERT_ONLY, + "insert into " + TABLE_NAME + "(id, value) values(?, ?)"); + } + + @Test + public void updateTest() { + batchTest(SaveMode.UPDATE_ONLY, + "update " + TABLE_NAME + " set value = ? where id = ? returning id"); + } + + @Test + public void upsertTest() { + batchTest(SaveMode.UPSERT, + "upsert into " + TABLE_NAME + "(id, value) values(?, ?)"); + } +} diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/BatchExecutorMonitor.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/BatchExecutorMonitor.java new file mode 100644 index 00000000..1517a5e1 --- /dev/null +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/BatchExecutorMonitor.java @@ -0,0 +1,70 @@ +package ydb.jimmer.dialect.sqlMonitor; + +import org.babyfish.jimmer.sql.runtime.ExceptionTranslator; +import org.babyfish.jimmer.sql.runtime.ExecutionPurpose; +import org.babyfish.jimmer.sql.runtime.Executor; +import org.babyfish.jimmer.sql.runtime.ExecutorContext; +import org.babyfish.jimmer.sql.runtime.JSqlClientImplementor; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.function.BiFunction; + +public class BatchExecutorMonitor implements Executor.BatchContext { + private final List queryLogs; + private final Executor.BatchContext raw; + private final List> variablesList = new ArrayList<>(); + + public BatchExecutorMonitor(List queryLogs, Executor.BatchContext raw) { + this.queryLogs = queryLogs; + this.raw = raw; + } + + @Override + public JSqlClientImplementor sqlClient() { + return raw.sqlClient(); + } + + @Override + public String sql() { + return raw.sql(); + } + + @Override + public ExecutionPurpose purpose() { + return raw.purpose(); + } + + @Override + public ExecutorContext ctx() { + return raw.ctx(); + } + + @Override + public void add(List variables) { + raw.add(variables); + variablesList.add(variables); + } + + @Override + public int[] execute(BiFunction exceptionTranslator) { + queryLogs.add(new QueryLog(raw.sql(), raw.purpose(), variablesList)); + return raw.execute(exceptionTranslator); + } + + @Override + public Object[] generatedIds() { + return raw.generatedIds(); + } + + @Override + public void addExecutedListener(Runnable listener) { + raw.addExecutedListener(listener); + } + + @Override + public void close() { + raw.close(); + } +} diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorMonitor.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorMonitor.java index d218f33e..32f37eb4 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorMonitor.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorMonitor.java @@ -31,7 +31,16 @@ public BatchContext executeBatch( @NotNull ExecutionPurpose purpose, @NotNull JSqlClientImplementor sqlClient ) { - return executor.executeBatch(con, sql, generatedIdProp, purpose, sqlClient); + return new BatchExecutorMonitor( + queryLogs, + DefaultExecutor.INSTANCE.executeBatch( + con, + sql, + generatedIdProp, + purpose, + sqlClient + ) + ); } public List getLogs() { From 2e5fa29eb0feb8de2e0d5bb07cf7980aa0ab0f1d Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Wed, 25 Mar 2026 17:42:56 +0300 Subject: [PATCH 45/98] Added a test for Streaming Result Sets --- .../jimmer/dialect/AbstractSelectTest.java | 34 +++++++++++++- .../dataTypeTest/SelectDataTypeTest.java | 29 ++---------- .../dialect/model/streaming/YdbStreaming.java | 17 +++++++ .../dialect/streaming/StreamingTest.java | 45 +++++++++++++++++++ 4 files changed, 97 insertions(+), 28 deletions(-) create mode 100644 jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/streaming/YdbStreaming.java create mode 100644 jimmer-dialect/src/test/java/ydb/jimmer/dialect/streaming/StreamingTest.java diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractSelectTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractSelectTest.java index aa275ceb..85004456 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractSelectTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractSelectTest.java @@ -1,5 +1,6 @@ package ydb.jimmer.dialect; +import org.babyfish.jimmer.sql.ast.Executable; import org.babyfish.jimmer.sql.ast.query.TypedRootQuery; import org.junit.jupiter.api.Assertions; @@ -10,12 +11,12 @@ import java.util.function.Consumer; public abstract class AbstractSelectTest extends AbstractTest { - protected void executeAndExpect(TypedRootQuery query, Consumer block) { + protected void executeAndExpect(Executable> query, Consumer block) { List rows = connectAndExecute(true, query); block.accept(new QueryTestContext(executor.getLogs(), rows)); } - private List connectAndExecute(boolean rollback, TypedRootQuery query) { + private List connectAndExecute(boolean rollback, Executable> query) { try (Connection connection = DriverManager.getConnection(getJdbcURL())) { connection.setAutoCommit(!rollback); try { @@ -31,4 +32,33 @@ private List connectAndExecute(boolean rollback, TypedRootQuery query) return null; } + + protected void insert(String tableName, String... values) { + if (values.length == 0) { + return; + } + StringBuilder sql = new StringBuilder("INSERT INTO " + tableName + " (id, value) VALUES "); + for (int i = 0; i < values.length; i++) { + if (i > 0) { + sql.append(", "); + } + sql.append("(").append(i).append(", ").append(values[i]).append(")"); + } + executeSql(sql.toString()); + } + + protected String buildJsonResponse(String[] valuesToInsert, String[] expectedValues) { + StringBuilder json = new StringBuilder("["); + for (int i = 0; i < valuesToInsert.length; i++) { + if (json.length() != 1) { + json.append(","); + } + json.append("{"); + json.append("\"id\":").append(i).append(",\"value\":").append(expectedValues[i]); + json.append("}"); + } + json.append("]"); + + return json.toString(); + } } diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java index 9d67d7c7..f55a15cd 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java @@ -36,20 +36,6 @@ import ydb.jimmer.dialect.model.type.ydbUuid.YdbUuidTable; public class SelectDataTypeTest extends AbstractSelectTest { - private void insert(String tableName, String... values) { - if (values.length == 0) { - return; - } - StringBuilder sql = new StringBuilder("INSERT INTO " + tableName + " (id, value) VALUES "); - for (int i = 0; i < values.length; i++) { - if (i > 0) { - sql.append(", "); - } - sql.append("(").append(i).append(", ").append(values[i]).append(")"); - } - executeSql(sql.toString()); - } - private void typeTest(String tableName, String typeName, AbstractTypedTable table, @@ -60,16 +46,7 @@ private void typeTest(String tableName, insert(tableName, valuesToInsert); - StringBuilder json = new StringBuilder("["); - for (int i = 0; i < valuesToInsert.length; i++) { - if (json.length() != 1) { - json.append(","); - } - json.append("{"); - json.append("\"id\":").append(i).append(",\"value\":").append(expectedValues[i]); - json.append("}"); - } - json.append("]"); + String json = buildJsonResponse(valuesToInsert, expectedValues); if (expectedValues.length == 1) { executeAndExpect( @@ -79,7 +56,7 @@ private void typeTest(String tableName, cxt -> { cxt.sql( "select tb_1_.id, tb_1_.value from " + tableName + " tb_1_"); - cxt.rows(json.toString()); + cxt.rows(json); } ); } else { @@ -91,7 +68,7 @@ private void typeTest(String tableName, cxt -> { cxt.sql( "select tb_1_.id, tb_1_.value from " + tableName + " tb_1_ order by tb_1_.value asc"); - cxt.rows(json.toString()); + cxt.rows(json); } ); } diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/streaming/YdbStreaming.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/streaming/YdbStreaming.java new file mode 100644 index 00000000..b725e1df --- /dev/null +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/streaming/YdbStreaming.java @@ -0,0 +1,17 @@ +package ydb.jimmer.dialect.model.streaming; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +@Entity +@Table(name = "ydb_streaming") +public interface YdbStreaming { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + int value(); +} diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/streaming/StreamingTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/streaming/StreamingTest.java new file mode 100644 index 00000000..2c4c9759 --- /dev/null +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/streaming/StreamingTest.java @@ -0,0 +1,45 @@ +package ydb.jimmer.dialect.streaming; + +import org.babyfish.jimmer.sql.ast.PropExpression; +import org.babyfish.jimmer.sql.ast.table.spi.AbstractTypedTable; +import org.junit.jupiter.api.Test; +import ydb.jimmer.dialect.AbstractSelectTest; +import ydb.jimmer.dialect.model.streaming.YdbStreamingTable; + +import java.sql.Connection; +import java.util.ArrayList; +import java.util.List; + +public class StreamingTest extends AbstractSelectTest { + @Test + public void cursorTest() { + String tableName = "ydb_streaming"; + String typeName = "Int32"; + AbstractTypedTable table = YdbStreamingTable.$; + PropExpression prop = YdbStreamingTable.$.value(); + String[] valuesToInsert = new String[]{"11", "12", "21", "22"}; + String[] expectedValues = new String[]{"11", "12", "21", "22"}; + + createTable(tableName, typeName); + + insert(tableName, valuesToInsert); + + String json = buildJsonResponse(valuesToInsert, expectedValues); + + executeAndExpect((Connection con) -> { + List responses = new ArrayList<>(); + getYqlClient() + .createQuery(table) + .orderBy(prop) + .select(table) + .forEach(con, 2, responses::add); + return responses; + }, + cxt -> { + cxt.sql( + "select tb_1_.id, tb_1_.value from " + tableName + " tb_1_ order by tb_1_.value asc"); + cxt.rows(json); + } + ); + } +} From e9ab0fc990b6fba2a50f51df250a2d6e0d8d14f8 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Sat, 4 Apr 2026 02:49:41 +0300 Subject: [PATCH 46/98] Added a template for setting isolation levels for transactions --- .../ydb/jimmer/dialect/YqlClientBuilder.java | 27 +++++++++++--- .../IsolationLevelEnabledSqlClient.java | 37 +++++++++++++++++++ .../transaction/TransactionContext.java | 25 +++++++++++++ .../transaction/YdbTxConnectionManager.java | 32 ++++++++++++++++ .../java/ydb/jimmer/dialect/AbstractTest.java | 6 ++- 5 files changed, 119 insertions(+), 8 deletions(-) create mode 100644 jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/IsolationLevelEnabledSqlClient.java create mode 100644 jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/TransactionContext.java create mode 100644 jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YdbTxConnectionManager.java diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java index 3dac9ce8..bb5bd373 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java @@ -1,21 +1,36 @@ package ydb.jimmer.dialect; import org.babyfish.jimmer.sql.JSqlClient; +import org.babyfish.jimmer.sql.runtime.JSqlClientImplementor; import ydb.jimmer.dialect.scalar.DurationProvider; import ydb.jimmer.dialect.scalar.InstantProvider; +import ydb.jimmer.dialect.transaction.IsolationLevelEnabledSqlClient; +import ydb.jimmer.dialect.transaction.YdbTxConnectionManager; + +import javax.sql.DataSource; +import java.util.function.Function; public final class YqlClientBuilder { private YqlClientBuilder() {} - public static JSqlClient.Builder getBuilder() { - return addScalarProviders( + public static JSqlClient getYqlClient( + DataSource dataSource, + Function block) { + return new IsolationLevelEnabledSqlClient((JSqlClientImplementor) buildSqlClient(dataSource, block).build()); + } + + private static JSqlClient.Builder buildSqlClient( + DataSource dataSource, + Function block) { + return block.apply(addScalarProviders( JSqlClient.newBuilder() - .setDialect(new YdbDialect()) - ); + .setDialect(new YdbDialect()) + .setConnectionManager(new YdbTxConnectionManager(dataSource)) + )); } - public static JSqlClient getYqlClient() { - return getBuilder().build(); + public static JSqlClient getYqlClient(DataSource dataSource) { + return getYqlClient(dataSource, x -> x); } public static JSqlClient.Builder addScalarProviders(JSqlClient.Builder builder) { diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/IsolationLevelEnabledSqlClient.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/IsolationLevelEnabledSqlClient.java new file mode 100644 index 00000000..a9e47c03 --- /dev/null +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/IsolationLevelEnabledSqlClient.java @@ -0,0 +1,37 @@ +package ydb.jimmer.dialect.transaction; + +import org.babyfish.jimmer.sql.di.AbstractJSqlClientDelegate; +import org.babyfish.jimmer.sql.runtime.JSqlClientImplementor; + +import java.sql.Connection; +import java.util.function.Supplier; + +public class IsolationLevelEnabledSqlClient extends AbstractJSqlClientDelegate { + private final JSqlClientImplementor delegate; + + public IsolationLevelEnabledSqlClient(JSqlClientImplementor delegate) { + this.delegate = delegate; + } + + @Override + protected JSqlClientImplementor sqlClient() { + return delegate; + } + + public R withIsolation(int isolationLevel, Supplier block) { + try { + TransactionContext.setSettings(isolationLevel); + return transaction(block); + } finally { + TransactionContext.clear(); + } + } + + public R withSnapshotIsolation(Supplier block) { + return withIsolation(Connection.TRANSACTION_REPEATABLE_READ, block); + } + + public R withReadCommitted(Supplier block) { + return withIsolation(Connection.TRANSACTION_READ_COMMITTED, block); + } +} diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/TransactionContext.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/TransactionContext.java new file mode 100644 index 00000000..8aee1361 --- /dev/null +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/TransactionContext.java @@ -0,0 +1,25 @@ +package ydb.jimmer.dialect.transaction; + +public class TransactionContext { + private static final ThreadLocal LOCAL_CONTEXT = new ThreadLocal<>(); + + public static void setSettings(int isolationLevel) { + LOCAL_CONTEXT.set(new TransactionSettings(isolationLevel)); + } + + public static TransactionSettings getSettings() { + return LOCAL_CONTEXT.get(); + } + + public static void clear() { + LOCAL_CONTEXT.remove(); + } + + public static class TransactionSettings { + final int isolationLevel; + + TransactionSettings(int isolationLevel) { + this.isolationLevel = isolationLevel; + } + } +} diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YdbTxConnectionManager.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YdbTxConnectionManager.java new file mode 100644 index 00000000..cd693be1 --- /dev/null +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YdbTxConnectionManager.java @@ -0,0 +1,32 @@ +package ydb.jimmer.dialect.transaction; + +import org.babyfish.jimmer.sql.transaction.AbstractTxConnectionManager; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.SQLException; + +public class YdbTxConnectionManager extends AbstractTxConnectionManager { + private final DataSource dataSource; + + public YdbTxConnectionManager(DataSource dataSource) { + this.dataSource = dataSource; + } + + @Override + protected Connection openConnection() throws SQLException { + return dataSource.getConnection(); + } + + @Override + protected void startTransaction(Connection con) throws SQLException { + super.startTransaction(con); + + TransactionContext.TransactionSettings settings = TransactionContext.getSettings(); + if (settings != null) { + if (settings.isolationLevel != Connection.TRANSACTION_NONE) { + con.setTransactionIsolation(settings.isolationLevel); + } + } + } +} diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java index 4ab256d2..6a814e54 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java @@ -25,11 +25,13 @@ public abstract class AbstractTest { private static final JSqlClient yqlClientForBatch; static { - yqlClient = YqlClientBuilder.getBuilder() + yqlClient = JSqlClient.newBuilder() + .setDialect(new YdbDialect()) .setExecutor(executor) .build(); - yqlClientForBatch = YqlClientBuilder.getBuilder() + yqlClientForBatch = JSqlClient.newBuilder() + .setDialect(new YdbDialect()) .setExecutor(executor) .setExplicitBatchEnabled(true) .setDumbBatchAcceptable(true) From 167cd864e049af3127ad89eb838818a26a5e0616 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Thu, 9 Apr 2026 02:16:01 +0300 Subject: [PATCH 47/98] Added YDB supported Isolation levels --- .../ydb/jimmer/dialect/constant/YdbConst.java | 4 ++++ .../IsolationLevelEnabledSqlClient.java | 21 +++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/constant/YdbConst.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/constant/YdbConst.java index d5547cc5..941f7f2b 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/constant/YdbConst.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/constant/YdbConst.java @@ -5,4 +5,8 @@ private YdbConst() {} public static final int SQL_KIND_PRIMITIVE = 10000; public static final int SQL_KIND_DECIMAL = 1 << 14; // 16384 + + public static final int ONLINE_CONSISTENT_READ_ONLY = 16; + public static final int ONLINE_INCONSISTENT_READ_ONLY = ONLINE_CONSISTENT_READ_ONLY + 1; + public static final int STALE_READ_ONLY = 32; } diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/IsolationLevelEnabledSqlClient.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/IsolationLevelEnabledSqlClient.java index a9e47c03..39525fff 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/IsolationLevelEnabledSqlClient.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/IsolationLevelEnabledSqlClient.java @@ -2,6 +2,7 @@ import org.babyfish.jimmer.sql.di.AbstractJSqlClientDelegate; import org.babyfish.jimmer.sql.runtime.JSqlClientImplementor; +import ydb.jimmer.dialect.constant.YdbConst; import java.sql.Connection; import java.util.function.Supplier; @@ -27,11 +28,23 @@ public R withIsolation(int isolationLevel, Supplier block) { } } - public R withSnapshotIsolation(Supplier block) { - return withIsolation(Connection.TRANSACTION_REPEATABLE_READ, block); + public R serializableReadWrite(Supplier block) { + return withIsolation(Connection.TRANSACTION_SERIALIZABLE, block); } - public R withReadCommitted(Supplier block) { - return withIsolation(Connection.TRANSACTION_READ_COMMITTED, block); + public R snapshotReadOnly(Supplier block) { + return withIsolation(Connection.TRANSACTION_SERIALIZABLE, block); + } + + public R staleReadOnly(Supplier block) { + return withIsolation(YdbConst.STALE_READ_ONLY, block); + } + + public R onlineConsistentReadOnly(Supplier block) { + return withIsolation(YdbConst.ONLINE_CONSISTENT_READ_ONLY, block); + } + + public R onlineInconsistentReadOnly(Supplier block) { + return withIsolation(YdbConst.ONLINE_INCONSISTENT_READ_ONLY, block); } } From af0e0bb5bf76c8a291a162c2f863af15e331bc8e Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Thu, 9 Apr 2026 12:33:19 +0300 Subject: [PATCH 48/98] ReadOnly parameter is now set together with the isolation level --- .../IsolationLevelEnabledSqlClient.java | 14 +++++++------- .../dialect/transaction/TransactionContext.java | 8 +++++--- .../transaction/YdbTxConnectionManager.java | 1 + 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/IsolationLevelEnabledSqlClient.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/IsolationLevelEnabledSqlClient.java index 39525fff..e163c95c 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/IsolationLevelEnabledSqlClient.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/IsolationLevelEnabledSqlClient.java @@ -19,9 +19,9 @@ protected JSqlClientImplementor sqlClient() { return delegate; } - public R withIsolation(int isolationLevel, Supplier block) { + public R withIsolation(int isolationLevel, boolean readOnly, Supplier block) { try { - TransactionContext.setSettings(isolationLevel); + TransactionContext.setSettings(isolationLevel, readOnly); return transaction(block); } finally { TransactionContext.clear(); @@ -29,22 +29,22 @@ public R withIsolation(int isolationLevel, Supplier block) { } public R serializableReadWrite(Supplier block) { - return withIsolation(Connection.TRANSACTION_SERIALIZABLE, block); + return withIsolation(Connection.TRANSACTION_SERIALIZABLE, false, block); } public R snapshotReadOnly(Supplier block) { - return withIsolation(Connection.TRANSACTION_SERIALIZABLE, block); + return withIsolation(Connection.TRANSACTION_SERIALIZABLE, true, block); } public R staleReadOnly(Supplier block) { - return withIsolation(YdbConst.STALE_READ_ONLY, block); + return withIsolation(YdbConst.STALE_READ_ONLY, true, block); } public R onlineConsistentReadOnly(Supplier block) { - return withIsolation(YdbConst.ONLINE_CONSISTENT_READ_ONLY, block); + return withIsolation(YdbConst.ONLINE_CONSISTENT_READ_ONLY, true, block); } public R onlineInconsistentReadOnly(Supplier block) { - return withIsolation(YdbConst.ONLINE_INCONSISTENT_READ_ONLY, block); + return withIsolation(YdbConst.ONLINE_INCONSISTENT_READ_ONLY, true, block); } } diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/TransactionContext.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/TransactionContext.java index 8aee1361..de5dfc69 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/TransactionContext.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/TransactionContext.java @@ -3,8 +3,8 @@ public class TransactionContext { private static final ThreadLocal LOCAL_CONTEXT = new ThreadLocal<>(); - public static void setSettings(int isolationLevel) { - LOCAL_CONTEXT.set(new TransactionSettings(isolationLevel)); + public static void setSettings(int isolationLevel, boolean readOnly) { + LOCAL_CONTEXT.set(new TransactionSettings(isolationLevel, readOnly)); } public static TransactionSettings getSettings() { @@ -17,9 +17,11 @@ public static void clear() { public static class TransactionSettings { final int isolationLevel; + final boolean readOnly; - TransactionSettings(int isolationLevel) { + TransactionSettings(int isolationLevel, boolean readOnly) { this.isolationLevel = isolationLevel; + this.readOnly = readOnly; } } } diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YdbTxConnectionManager.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YdbTxConnectionManager.java index cd693be1..51245225 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YdbTxConnectionManager.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YdbTxConnectionManager.java @@ -27,6 +27,7 @@ protected void startTransaction(Connection con) throws SQLException { if (settings.isolationLevel != Connection.TRANSACTION_NONE) { con.setTransactionIsolation(settings.isolationLevel); } + con.setReadOnly(settings.readOnly); } } } From 7f349713769ef810a393f7740aa7b84c3e8206dd Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Thu, 23 Apr 2026 18:09:06 +0300 Subject: [PATCH 49/98] Made abstract AbstractInsertTest --- .../src/test/java/ydb/jimmer/dialect/AbstractInsertTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractInsertTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractInsertTest.java index 76a08acf..678c0436 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractInsertTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractInsertTest.java @@ -9,7 +9,7 @@ import java.sql.SQLException; import java.util.function.Consumer; -public class AbstractInsertTest extends AbstractTest { +public abstract class AbstractInsertTest extends AbstractTest { protected void executeAndExpect(Executable query, Consumer block) { MutationResult result = null; Throwable throwable = null; From db5041b2f363685fa4a40d09ea41efe4d7daae40 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Thu, 23 Apr 2026 18:10:20 +0300 Subject: [PATCH 50/98] Name change IsolationLevelEnabledSqlClient -> IsolationEnabledSqlClient --- .../main/java/ydb/jimmer/dialect/YqlClientBuilder.java | 10 +++------- ...edSqlClient.java => IsolationEnabledSqlClient.java} | 4 ++-- 2 files changed, 5 insertions(+), 9 deletions(-) rename jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/{IsolationLevelEnabledSqlClient.java => IsolationEnabledSqlClient.java} (90%) diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java index bb5bd373..4bc80d28 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java @@ -2,9 +2,7 @@ import org.babyfish.jimmer.sql.JSqlClient; import org.babyfish.jimmer.sql.runtime.JSqlClientImplementor; -import ydb.jimmer.dialect.scalar.DurationProvider; -import ydb.jimmer.dialect.scalar.InstantProvider; -import ydb.jimmer.dialect.transaction.IsolationLevelEnabledSqlClient; +import ydb.jimmer.dialect.transaction.IsolationEnabledSqlClient; import ydb.jimmer.dialect.transaction.YdbTxConnectionManager; import javax.sql.DataSource; @@ -16,7 +14,7 @@ private YqlClientBuilder() {} public static JSqlClient getYqlClient( DataSource dataSource, Function block) { - return new IsolationLevelEnabledSqlClient((JSqlClientImplementor) buildSqlClient(dataSource, block).build()); + return new IsolationEnabledSqlClient((JSqlClientImplementor) buildSqlClient(dataSource, block).build()); } private static JSqlClient.Builder buildSqlClient( @@ -34,8 +32,6 @@ public static JSqlClient getYqlClient(DataSource dataSource) { } public static JSqlClient.Builder addScalarProviders(JSqlClient.Builder builder) { - return builder - .addScalarProvider(new InstantProvider()) - .addScalarProvider(new DurationProvider()); + return builder; } } diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/IsolationLevelEnabledSqlClient.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/IsolationEnabledSqlClient.java similarity index 90% rename from jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/IsolationLevelEnabledSqlClient.java rename to jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/IsolationEnabledSqlClient.java index e163c95c..ff17e178 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/IsolationLevelEnabledSqlClient.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/IsolationEnabledSqlClient.java @@ -7,10 +7,10 @@ import java.sql.Connection; import java.util.function.Supplier; -public class IsolationLevelEnabledSqlClient extends AbstractJSqlClientDelegate { +public class IsolationEnabledSqlClient extends AbstractJSqlClientDelegate { private final JSqlClientImplementor delegate; - public IsolationLevelEnabledSqlClient(JSqlClientImplementor delegate) { + public IsolationEnabledSqlClient(JSqlClientImplementor delegate) { this.delegate = delegate; } From 3f5a61c798d8fcbca2d36d29cbee7d645bc6c322 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Thu, 23 Apr 2026 18:11:01 +0300 Subject: [PATCH 51/98] Tests: added the function to drop the chosen table in SQL --- .../src/test/java/ydb/jimmer/dialect/AbstractTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java index 6a814e54..56f05579 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java @@ -103,6 +103,11 @@ protected static void createTable(String tableName, String typeName) { ")"); } + protected static void dropTable(String tableName) { + executeSql( + "DROP TABLE " + tableName); + } + protected static void executeSql(String sql) { try (Connection connection = DriverManager.getConnection(getJdbcURL())) { try (Statement stmt = connection.createStatement()) { From 8a24874969be0821afb9fe79317acb59fdfdc2d5 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Thu, 23 Apr 2026 18:11:52 +0300 Subject: [PATCH 52/98] Tests: added the error message checker from SQL insert queries --- .../java/ydb/jimmer/dialect/QueryTestContext.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java index 188985f2..d65dce8d 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java @@ -98,4 +98,16 @@ public void rows(String json) { throw new RuntimeException(e); } } + + public void error(String message) { + if (throwable == null && message == null) { + return; + } + + if (throwable == null) { + Assertions.fail("The query didn't produce an exception: " + message); + } + + Assertions.assertEquals(message, throwable.getMessage()); + } } From 08b7faa14e40cb46f500c35fe8701d88eee83551 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Thu, 23 Apr 2026 18:12:09 +0300 Subject: [PATCH 53/98] Abstract test class for transactions --- .../model/transaction/YdbTransaction.java | 17 ++++ .../transaction/AbstractTransactionTest.java | 89 +++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/transaction/YdbTransaction.java create mode 100644 jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/AbstractTransactionTest.java diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/transaction/YdbTransaction.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/transaction/YdbTransaction.java new file mode 100644 index 00000000..e2803f26 --- /dev/null +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/transaction/YdbTransaction.java @@ -0,0 +1,17 @@ +package ydb.jimmer.dialect.model.transaction; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +@Entity +@Table(name = "ydb_transaction") +public interface YdbTransaction { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + int value(); +} diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/AbstractTransactionTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/AbstractTransactionTest.java new file mode 100644 index 00000000..b995a6e1 --- /dev/null +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/AbstractTransactionTest.java @@ -0,0 +1,89 @@ +package ydb.jimmer.dialect.transaction; + +import org.babyfish.jimmer.sql.JSqlClient; +import org.babyfish.jimmer.sql.ast.mutation.MutationResult; +import org.babyfish.jimmer.sql.ast.mutation.SaveMode; +import org.babyfish.jimmer.sql.runtime.JSqlClientImplementor; +import org.junit.jupiter.api.Test; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import ydb.jimmer.dialect.AbstractSelectTest; +import ydb.jimmer.dialect.QueryTestContext; +import ydb.jimmer.dialect.model.transaction.YdbTransaction; +import ydb.jimmer.dialect.model.transaction.YdbTransactionDraft; + +import javax.sql.DataSource; +import java.util.List; +import java.util.function.Function; +import java.util.function.Supplier; + +public abstract class AbstractTransactionTest extends AbstractSelectTest { + private static final DataSource dataSource = new DriverManagerDataSource(getJdbcURL()); + protected static final IsolationEnabledSqlClient yqlClient = new IsolationEnabledSqlClient( + (JSqlClientImplementor) JSqlClient.newBuilder() + .setConnectionManager(new YdbTxConnectionManager(dataSource)) + .setExecutor(executor) + .build() + ); + + protected void readTest(Function>, List> transaction) { + String tableName = "ydb_transaction"; + String typeName = "Int32"; + String[] valuesToInsert = new String[]{"-1", "0", "10"}; + String[] expectedValues = new String[]{"-1", "0", "10"}; + + createTable(tableName, typeName); + + insert(tableName, valuesToInsert); + + List rows = transaction.apply(() -> + yqlClient.getEntities().findAll(YdbTransaction.class) + ); + QueryTestContext cxt = new QueryTestContext(executor.getLogs(), rows); + + cxt.sql("select tb_1_.id, tb_1_.value from " + tableName + " tb_1_"); + + String json = buildJsonResponse(valuesToInsert, expectedValues); + cxt.rows(json); + + dropTable(tableName); + } + + protected void writeTest(Function, MutationResult> transaction, boolean readOnly) { + String errorMessage = null; + if (readOnly) { + errorMessage = "Cannot execute the DML statement"; + } + + writeTest(transaction, errorMessage); + } + + protected void writeTest(Function, MutationResult> transaction, String errorMessage) { + String tableName = "ydb_transaction"; + String typeName = "Int32"; + Object[] variables = new Object[]{0, 10}; + + createTable(tableName, typeName); + + MutationResult result = null; + Throwable throwable = null; + try { + result = transaction.apply(() -> + yqlClient.getEntities().saveCommand( + YdbTransactionDraft.$.produce(item -> { + item.setId(0); + item.setValue(10); + }) + ).setMode(SaveMode.INSERT_ONLY).execute() + ); + } catch (Throwable ex) { + throwable = ex; + } + QueryTestContext cxt = new QueryTestContext(executor.getLogs(), result, throwable); + + cxt.sql("insert into " + tableName + "(id, value) values(?, ?)"); + cxt.variables(variables); + cxt.error(errorMessage); + + dropTable(tableName); + } +} From f911c3261783c4ce416aa4be575c74669bcc47e2 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Thu, 23 Apr 2026 18:12:22 +0300 Subject: [PATCH 54/98] Added tests for transactions --- .../transaction/OnlineConsistentTest.java | 16 ++++++++++++++++ .../transaction/OnlineInconsistentTest.java | 16 ++++++++++++++++ .../dialect/transaction/SerializableTest.java | 16 ++++++++++++++++ .../jimmer/dialect/transaction/SnapshotTest.java | 16 ++++++++++++++++ .../jimmer/dialect/transaction/StaleTest.java | 16 ++++++++++++++++ 5 files changed, 80 insertions(+) create mode 100644 jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/OnlineConsistentTest.java create mode 100644 jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/OnlineInconsistentTest.java create mode 100644 jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/SerializableTest.java create mode 100644 jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/SnapshotTest.java create mode 100644 jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/StaleTest.java diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/OnlineConsistentTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/OnlineConsistentTest.java new file mode 100644 index 00000000..69246211 --- /dev/null +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/OnlineConsistentTest.java @@ -0,0 +1,16 @@ +package ydb.jimmer.dialect.transaction; + + +import org.junit.jupiter.api.Test; + +public class OnlineConsistentTest extends AbstractTransactionTest { + @Test + public void readTest() { + readTest(yqlClient::onlineConsistentReadOnly); + } + + @Test + public void writeTest() { + writeTest(yqlClient::onlineConsistentReadOnly, true); + } +} diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/OnlineInconsistentTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/OnlineInconsistentTest.java new file mode 100644 index 00000000..ce958c3c --- /dev/null +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/OnlineInconsistentTest.java @@ -0,0 +1,16 @@ +package ydb.jimmer.dialect.transaction; + + +import org.junit.jupiter.api.Test; + +public class OnlineInconsistentTest extends AbstractTransactionTest { + @Test + public void readTest() { + readTest(yqlClient::onlineInconsistentReadOnly); + } + + @Test + public void writeTest() { + writeTest(yqlClient::onlineInconsistentReadOnly, true); + } +} diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/SerializableTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/SerializableTest.java new file mode 100644 index 00000000..84748d58 --- /dev/null +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/SerializableTest.java @@ -0,0 +1,16 @@ +package ydb.jimmer.dialect.transaction; + + +import org.junit.jupiter.api.Test; + +public class SerializableTest extends AbstractTransactionTest { + @Test + public void readTest() { + readTest(yqlClient::serializableReadWrite); + } + + @Test + public void writeTest() { + writeTest(yqlClient::serializableReadWrite, false); + } +} diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/SnapshotTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/SnapshotTest.java new file mode 100644 index 00000000..6c228058 --- /dev/null +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/SnapshotTest.java @@ -0,0 +1,16 @@ +package ydb.jimmer.dialect.transaction; + + +import org.junit.jupiter.api.Test; + +public class SnapshotTest extends AbstractTransactionTest { + @Test + public void readTest() { + readTest(yqlClient::snapshotReadOnly); + } + + @Test + public void writeTest() { + writeTest(yqlClient::snapshotReadOnly, true); + } +} diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/StaleTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/StaleTest.java new file mode 100644 index 00000000..b3c97a5a --- /dev/null +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/StaleTest.java @@ -0,0 +1,16 @@ +package ydb.jimmer.dialect.transaction; + + +import org.junit.jupiter.api.Test; + +public class StaleTest extends AbstractTransactionTest { + @Test + public void readTest() { + readTest(yqlClient::staleReadOnly); + } + + @Test + public void writeTest() { + writeTest(yqlClient::staleReadOnly, true); + } +} From 38aae754bcdd7ac9b9fce886f775e6041da60cd6 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Sun, 26 Apr 2026 23:29:20 +0300 Subject: [PATCH 55/98] Added a class for keyset pagination --- .../jimmer/dialect/YdbKeysetPaginator.java | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 jimmer-dialect/src/main/java/ydb/jimmer/dialect/YdbKeysetPaginator.java diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YdbKeysetPaginator.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YdbKeysetPaginator.java new file mode 100644 index 00000000..c44f0c1f --- /dev/null +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YdbKeysetPaginator.java @@ -0,0 +1,120 @@ +package ydb.jimmer.dialect; + +import org.babyfish.jimmer.sql.JSqlClient; +import org.babyfish.jimmer.sql.ast.Expression; +import org.babyfish.jimmer.sql.ast.NativeBuilder; +import org.babyfish.jimmer.sql.ast.Predicate; +import org.babyfish.jimmer.sql.ast.query.ConfigurableRootQuery; +import org.babyfish.jimmer.sql.ast.query.MutableRootQuery; +import org.babyfish.jimmer.sql.ast.table.spi.TableProxy; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.BiFunction; +import java.util.function.Function; + +public class YdbKeysetPaginator { + private final JSqlClient sqlClient; + + public YdbKeysetPaginator(JSqlClient sqlClient) { + this.sqlClient = sqlClient; + } + + public static class Page { + private final List rows; + private final List nextCursor; + + public Page(List rows, List nextCursor) { + this.rows = rows; + this.nextCursor = nextCursor; + } + + public List getRows() { + return rows; + } + + public List getNextCursor() { + return nextCursor; + } + + public boolean hasNextPage() { + return nextCursor != null; + } + } + + public , E, R> Page fetchPage( + T table, + List> keyColumns, + List cursor, + int limit, + Function> keyExtractor, + BiFunction, T, ConfigurableRootQuery> querySetup + ) { + if (keyColumns.isEmpty()) { + throw new IllegalArgumentException("keyColumns must not be empty"); + } else if (cursor != null && cursor.size() != keyColumns.size()) { + throw new IllegalArgumentException( + "cursor has " + cursor.size() + " values, but keyColumns has " + keyColumns.size() + ); + } + + MutableRootQuery query = sqlClient.createQuery(table); + + if (cursor != null) { + query.where(buildKeysetPredicate(keyColumns, cursor)); + } + + ConfigurableRootQuery configured = querySetup.apply(query, table); + + List fetched = configured.limit(limit + 1, 0L).execute(); + + boolean hasMore = fetched.size() > limit; + List pageRows = hasMore ? new ArrayList<>(fetched.subList(0, limit)) : fetched; + + List nextCursor = hasMore + ? keyExtractor.apply(pageRows.get(pageRows.size() - 1)) + : null; + + return new Page<>(pageRows, nextCursor); + } + + private static Predicate buildKeysetPredicate( + List> keyColumns, + List cursorValues + ) { + int n = keyColumns.size(); + + StringBuilder sql = new StringBuilder("("); + + for (int i = 0; i < n; i++) { + if (i > 0) { + sql.append(", "); + } + + sql.append("%e"); + } + + sql.append(") > ("); + + for (int i = 0; i < n; i++) { + if (i > 0) { + sql.append(", "); + } + + sql.append("%v"); + } + + sql.append(")"); + + NativeBuilder.Prd builder = Predicate.sqlBuilder(sql.toString()); + for (Expression col : keyColumns) { + builder.expression(col); + } + + for (Object val : cursorValues) { + builder.value(val); + } + + return builder.build(); + } +} From 135e09c744fc2de0a9793c644b351ceea63d0ed2 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Mon, 27 Apr 2026 03:00:35 +0300 Subject: [PATCH 56/98] Removed unnecessary parameter from buildJsonResponse() --- .../ydb/jimmer/dialect/AbstractSelectTest.java | 17 ++++++++++------- .../dataTypeTest/SelectDataTypeTest.java | 2 +- .../jimmer/dialect/streaming/StreamingTest.java | 2 +- .../transaction/AbstractTransactionTest.java | 3 +-- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractSelectTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractSelectTest.java index 85004456..fc7dc864 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractSelectTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractSelectTest.java @@ -1,7 +1,6 @@ package ydb.jimmer.dialect; import org.babyfish.jimmer.sql.ast.Executable; -import org.babyfish.jimmer.sql.ast.query.TypedRootQuery; import org.junit.jupiter.api.Assertions; import java.sql.Connection; @@ -11,12 +10,12 @@ import java.util.function.Consumer; public abstract class AbstractSelectTest extends AbstractTest { - protected void executeAndExpect(Executable> query, Consumer block) { + protected static void executeAndExpect(Executable> query, Consumer block) { List rows = connectAndExecute(true, query); block.accept(new QueryTestContext(executor.getLogs(), rows)); } - private List connectAndExecute(boolean rollback, Executable> query) { + private static List connectAndExecute(boolean rollback, Executable> query) { try (Connection connection = DriverManager.getConnection(getJdbcURL())) { connection.setAutoCommit(!rollback); try { @@ -33,7 +32,7 @@ private List connectAndExecute(boolean rollback, Executable { List responses = new ArrayList<>(); diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/AbstractTransactionTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/AbstractTransactionTest.java index b995a6e1..9214bf76 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/AbstractTransactionTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/AbstractTransactionTest.java @@ -4,7 +4,6 @@ import org.babyfish.jimmer.sql.ast.mutation.MutationResult; import org.babyfish.jimmer.sql.ast.mutation.SaveMode; import org.babyfish.jimmer.sql.runtime.JSqlClientImplementor; -import org.junit.jupiter.api.Test; import org.springframework.jdbc.datasource.DriverManagerDataSource; import ydb.jimmer.dialect.AbstractSelectTest; import ydb.jimmer.dialect.QueryTestContext; @@ -42,7 +41,7 @@ protected void readTest(Function>, List Date: Mon, 27 Apr 2026 03:00:59 +0300 Subject: [PATCH 57/98] Added a simple test for the keyset pagination --- .../java/ydb/jimmer/dialect/model/YdbInt.java | 17 ++++ .../jimmer/dialect/pagination/KeysetTest.java | 85 +++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/YdbInt.java create mode 100644 jimmer-dialect/src/test/java/ydb/jimmer/dialect/pagination/KeysetTest.java diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/YdbInt.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/YdbInt.java new file mode 100644 index 00000000..7d424770 --- /dev/null +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/YdbInt.java @@ -0,0 +1,17 @@ +package ydb.jimmer.dialect.model; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; + +@Entity +@Table(name = "simple_table") +public interface YdbInt { + @Id + @Column(name = "id") + int getId(); + + @Column(name = "value") + int value(); +} diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/pagination/KeysetTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/pagination/KeysetTest.java new file mode 100644 index 00000000..8dd704a8 --- /dev/null +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/pagination/KeysetTest.java @@ -0,0 +1,85 @@ +package ydb.jimmer.dialect.pagination; + +import org.babyfish.jimmer.sql.JSqlClient; +import org.babyfish.jimmer.sql.runtime.JSqlClientImplementor; +import org.junit.jupiter.api.Test; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import ydb.jimmer.dialect.AbstractSelectTest; +import ydb.jimmer.dialect.QueryTestContext; +import ydb.jimmer.dialect.YdbKeysetPaginator; +import ydb.jimmer.dialect.model.YdbInt; +import ydb.jimmer.dialect.model.YdbIntTable; +import ydb.jimmer.dialect.transaction.IsolationEnabledSqlClient; +import ydb.jimmer.dialect.transaction.YdbTxConnectionManager; + +import javax.sql.DataSource; +import java.util.Arrays; +import java.util.List; + +public class KeysetTest extends AbstractSelectTest { + private static final String TABLE_NAME = "simple_table"; + private static final String VALUE_TYPE_NAME = "Int32"; + + private static final int N = 100; + private static final int LIMIT = 20; + private static final String[] VALUES = new String[100]; + + static { + for (int i = 0; i < N; i++) { + VALUES[i] = String.valueOf(i); + } + } + + private static final DataSource dataSource = new DriverManagerDataSource(getJdbcURL()); + protected static final IsolationEnabledSqlClient yqlClient = new IsolationEnabledSqlClient( + (JSqlClientImplementor) JSqlClient.newBuilder() + .setConnectionManager(new YdbTxConnectionManager(dataSource)) + .setExecutor(executor) + .build() + ); + + @Test + public void simpleTest() { + createTable(TABLE_NAME, VALUE_TYPE_NAME); + insert(TABLE_NAME, VALUES); + + YdbKeysetPaginator paginator = new YdbKeysetPaginator(yqlClient); + + YdbIntTable table = YdbIntTable.$; + + YdbKeysetPaginator.Page page = null; + for (int i = 0; i < N; i += LIMIT) { + List nextCursor = null; + if (page != null) { + nextCursor = page.getNextCursor(); + } + + page = paginator.fetchPage( + table, + List.of(table.id()), + nextCursor, + LIMIT, + item -> List.of(((YdbInt) item).getId()), + (q, t) -> { + q.orderBy(t.id().asc()); + return q.select(t); + } + ); + + QueryTestContext cxt = new QueryTestContext(executor.getLogs(), page.getRows()); + + StringBuilder expectedSql = new StringBuilder("select tb_1_.id, tb_1_.value from " + TABLE_NAME + " tb_1_"); + if (i != 0) { + expectedSql.append(" where (tb_1_.id) > (?)"); + } + expectedSql.append(" order by tb_1_.id asc limit ?"); + + cxt.sql(expectedSql.toString()); + + String json = buildJsonResponse(i, Arrays.copyOfRange(VALUES, i, i + LIMIT)); + cxt.rows(json); + } + + dropTable(TABLE_NAME); + } +} From 3201907cba0aa7c2d45d1f74529f90ae2e6670c3 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Mon, 27 Apr 2026 03:50:55 +0300 Subject: [PATCH 58/98] Fixed select test for types --- .../src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java | 4 +++- .../src/test/java/ydb/jimmer/dialect/AbstractTest.java | 4 ++++ .../ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java | 6 ++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java index 4bc80d28..39efa55d 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java @@ -2,6 +2,7 @@ import org.babyfish.jimmer.sql.JSqlClient; import org.babyfish.jimmer.sql.runtime.JSqlClientImplementor; +import ydb.jimmer.dialect.scalar.DurationProvider; import ydb.jimmer.dialect.transaction.IsolationEnabledSqlClient; import ydb.jimmer.dialect.transaction.YdbTxConnectionManager; @@ -32,6 +33,7 @@ public static JSqlClient getYqlClient(DataSource dataSource) { } public static JSqlClient.Builder addScalarProviders(JSqlClient.Builder builder) { - return builder; + return builder + .addScalarProvider(new DurationProvider()); } } diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java index 56f05579..e57e47f6 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java @@ -5,11 +5,14 @@ import org.junit.jupiter.api.extension.RegisterExtension; import org.springframework.core.io.UrlResource; import org.springframework.core.io.support.EncodedResource; +import org.springframework.jdbc.datasource.DriverManagerDataSource; import org.springframework.jdbc.datasource.init.ScriptException; import org.springframework.jdbc.datasource.init.ScriptUtils; import tech.ydb.test.junit5.YdbHelperExtension; +import ydb.jimmer.dialect.scalar.DurationProvider; import ydb.jimmer.dialect.sqlMonitor.ExecutorMonitor; +import javax.sql.DataSource; import java.net.URL; import java.sql.Connection; import java.sql.DriverManager; @@ -28,6 +31,7 @@ public abstract class AbstractTest { yqlClient = JSqlClient.newBuilder() .setDialect(new YdbDialect()) .setExecutor(executor) + .addScalarProvider(new DurationProvider()) .build(); yqlClientForBatch = JSqlClient.newBuilder() diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java index 4057589e..6fcdd65f 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java @@ -1,6 +1,8 @@ package ydb.jimmer.dialect.dataTypeTest; +import org.babyfish.jimmer.sql.ast.Executable; import org.babyfish.jimmer.sql.ast.PropExpression; +import org.babyfish.jimmer.sql.ast.query.ConfigurableRootQuery; import org.babyfish.jimmer.sql.ast.table.spi.AbstractTypedTable; import org.junit.jupiter.api.Test; import ydb.jimmer.dialect.AbstractSelectTest; @@ -35,6 +37,8 @@ import ydb.jimmer.dialect.model.type.ydbUtf8.YdbStringTable; import ydb.jimmer.dialect.model.type.ydbUuid.YdbUuidTable; +import java.util.List; + public class SelectDataTypeTest extends AbstractSelectTest { private void typeTest(String tableName, String typeName, @@ -72,6 +76,8 @@ private void typeTest(String tableName, } ); } + + dropTable(tableName); } @Test From 0906b61424c84dc179189edd99a67fe4ae4ce3d5 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Mon, 27 Apr 2026 10:50:26 +0300 Subject: [PATCH 59/98] Removed unnecessary code --- .../dialect/RetryConnectionManager.java | 1 - .../java/ydb/jimmer/dialect/YdbDialect.java | 38 ++++++++++++++++--- .../ydb/jimmer/dialect/YqlClientBuilder.java | 9 +++-- .../dialect/scalar/InstantProvider.java | 9 ----- 4 files changed, 38 insertions(+), 19 deletions(-) delete mode 100644 jimmer-dialect/src/main/java/ydb/jimmer/dialect/scalar/InstantProvider.java diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/RetryConnectionManager.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/RetryConnectionManager.java index f40c8d57..27a49e29 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/RetryConnectionManager.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/RetryConnectionManager.java @@ -60,7 +60,6 @@ public R executeTransaction(Propagation propagation, Function @Override public R execute(@Nullable Connection con, Function block) { if (con != null) { - // No connection management, no transaction management, everything is controlled by user. return block.apply(con); } diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java index 14b5807e..a682c26c 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java @@ -148,21 +148,39 @@ CREATE TABLE JIMMER_TRANS_CACHE_OPERATOR( } @Override - public void renderLPad(AbstractSqlBuilder builder, int currentPrecedence, Ast expression, Ast length, Ast padString) { + public void renderLPad( + AbstractSqlBuilder builder, + int currentPrecedence, + Ast expression, + Ast length, + Ast padString + ) { throw new UnsupportedOperationException( "The current dialect \"" + getClass().getName() + "\" does not support LPad." ); } @Override - public void renderRPad(AbstractSqlBuilder builder, int currentPrecedence, Ast expression, Ast length, Ast padString) { + public void renderRPad( + AbstractSqlBuilder builder, + int currentPrecedence, + Ast expression, + Ast length, + Ast padString + ) { throw new UnsupportedOperationException( "The current dialect \"" + getClass().getName() + "\" does not support RPad." ); } @Override - public void renderPosition(AbstractSqlBuilder builder, int currentPrecedence, Ast subStrAst, Ast expressionAst, @Nullable Ast startAst) { + public void renderPosition( + AbstractSqlBuilder builder, + int currentPrecedence, + Ast subStrAst, + Ast expressionAst, + @Nullable Ast startAst + ) { builder.sql("FIND(") .ast(expressionAst, currentPrecedence) .sql(", ") @@ -175,12 +193,22 @@ public void renderPosition(AbstractSqlBuilder builder, int currentPrecedence, } @Override - public void renderLeft(AbstractSqlBuilder builder, int currentPrecedence, Ast expressionAst, Ast lengthAst) { + public void renderLeft( + AbstractSqlBuilder builder, + int currentPrecedence, + Ast expressionAst, + Ast lengthAst + ) { renderSubString(builder, currentPrecedence, expressionAst, (Ast) Literals.number(0), lengthAst); } @Override - public void renderRight(AbstractSqlBuilder builder, int currentPrecedence, Ast expressionAst, Ast lengthAst) { + public void renderRight( + AbstractSqlBuilder builder, + int currentPrecedence, + Ast expressionAst, + Ast lengthAst + ) { builder.sql("substring(") .ast(expressionAst, currentPrecedence) .sql(", (LENGTH(") diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java index 39efa55d..42e180c9 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java @@ -14,13 +14,15 @@ private YqlClientBuilder() {} public static JSqlClient getYqlClient( DataSource dataSource, - Function block) { + Function block + ) { return new IsolationEnabledSqlClient((JSqlClientImplementor) buildSqlClient(dataSource, block).build()); } private static JSqlClient.Builder buildSqlClient( DataSource dataSource, - Function block) { + Function block + ) { return block.apply(addScalarProviders( JSqlClient.newBuilder() .setDialect(new YdbDialect()) @@ -33,7 +35,6 @@ public static JSqlClient getYqlClient(DataSource dataSource) { } public static JSqlClient.Builder addScalarProviders(JSqlClient.Builder builder) { - return builder - .addScalarProvider(new DurationProvider()); + return builder.addScalarProvider(new DurationProvider()); } } diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/scalar/InstantProvider.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/scalar/InstantProvider.java deleted file mode 100644 index bf92c581..00000000 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/scalar/InstantProvider.java +++ /dev/null @@ -1,9 +0,0 @@ -package ydb.jimmer.dialect.scalar; - -import java.time.Instant; - -public class InstantProvider extends DumbYdbScalarProvider { - public InstantProvider() { - super(Instant.class); - } -} From 8b53b91d406970e70dd8da1ad4aa97a4bb7afb08 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Mon, 27 Apr 2026 10:50:57 +0300 Subject: [PATCH 60/98] Removed unused models from tests --- .../java/ydb/jimmer/dialect/model/Group.java | 22 ------------- .../ydb/jimmer/dialect/model/Student.java | 31 ------------------- 2 files changed, 53 deletions(-) delete mode 100644 jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/Group.java delete mode 100644 jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/Student.java diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/Group.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/Group.java deleted file mode 100644 index cb69a3b0..00000000 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/Group.java +++ /dev/null @@ -1,22 +0,0 @@ -package ydb.jimmer.dialect.model; - -import org.babyfish.jimmer.sql.Column; -import org.babyfish.jimmer.sql.Entity; -import org.babyfish.jimmer.sql.GeneratedValue; -import org.babyfish.jimmer.sql.Id; -import org.babyfish.jimmer.sql.Table; -import org.babyfish.jimmer.sql.meta.UUIDIdGenerator; - -import java.util.UUID; - -@Entity -@Table(name = "group") -public interface Group { - @Id - @GeneratedValue(generatorType = UUIDIdGenerator.class) - @Column(name = "id") - UUID id(); - - @Column(name = "name") - String name(); -} diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/Student.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/Student.java deleted file mode 100644 index 3ba0119b..00000000 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/Student.java +++ /dev/null @@ -1,31 +0,0 @@ -package ydb.jimmer.dialect.model; - -import org.babyfish.jimmer.sql.Column; -import org.babyfish.jimmer.sql.Entity; -import org.babyfish.jimmer.sql.ForeignKeyType; -import org.babyfish.jimmer.sql.GeneratedValue; -import org.babyfish.jimmer.sql.Id; -import org.babyfish.jimmer.sql.JoinColumn; -import org.babyfish.jimmer.sql.ManyToOne; -import org.babyfish.jimmer.sql.Table; -import org.babyfish.jimmer.sql.meta.UUIDIdGenerator; - -import javax.annotation.Nullable; -import java.util.UUID; - -@Entity -@Table(name = "student") -public interface Student { - @Id - @GeneratedValue(generatorType = UUIDIdGenerator.class) - @Column(name = "id") - UUID id(); - - @Column(name = "name") - String name(); - - @ManyToOne - @Nullable - @JoinColumn(name = "group", foreignKeyType = ForeignKeyType.FAKE) - Group group(); -} From 6a4ebe7d3bbc681a919cd665751b6e257f21cd18 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Mon, 27 Apr 2026 10:52:18 +0300 Subject: [PATCH 61/98] Extracted repeated code to the common class in tests --- .../java/ydb/jimmer/dialect/AbstractTest.java | 20 +++++++++++++++-- .../ydb/jimmer/dialect/batch/BatchTest.java | 3 +-- .../dialect/model/{YdbInt.java => Table.java} | 5 ++--- .../jimmer/dialect/pagination/KeysetTest.java | 22 ++++--------------- .../transaction/AbstractTransactionTest.java | 12 +--------- 5 files changed, 26 insertions(+), 36 deletions(-) rename jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/{YdbInt.java => Table.java} (73%) diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java index e57e47f6..c8d77a7c 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java @@ -1,6 +1,7 @@ package ydb.jimmer.dialect; import org.babyfish.jimmer.sql.JSqlClient; +import org.babyfish.jimmer.sql.runtime.JSqlClientImplementor; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.extension.RegisterExtension; import org.springframework.core.io.UrlResource; @@ -11,6 +12,8 @@ import tech.ydb.test.junit5.YdbHelperExtension; import ydb.jimmer.dialect.scalar.DurationProvider; import ydb.jimmer.dialect.sqlMonitor.ExecutorMonitor; +import ydb.jimmer.dialect.transaction.IsolationEnabledSqlClient; +import ydb.jimmer.dialect.transaction.YdbTxConnectionManager; import javax.sql.DataSource; import java.net.URL; @@ -26,6 +29,7 @@ public abstract class AbstractTest { protected static final ExecutorMonitor executor = new ExecutorMonitor(); private static final JSqlClient yqlClient; private static final JSqlClient yqlClientForBatch; + protected static final IsolationEnabledSqlClient isolationClient; static { yqlClient = JSqlClient.newBuilder() @@ -40,16 +44,28 @@ public abstract class AbstractTest { .setExplicitBatchEnabled(true) .setDumbBatchAcceptable(true) .build(); + + DataSource dataSource = new DriverManagerDataSource(getJdbcURL()); + isolationClient = new IsolationEnabledSqlClient( + (JSqlClientImplementor) JSqlClient.newBuilder() + .setConnectionManager(new YdbTxConnectionManager(dataSource)) + .setExecutor(executor) + .build() + ); } - protected JSqlClient getYqlClient() { + protected static JSqlClient getYqlClient() { return yqlClient; } - protected JSqlClient getYqlClientForBatch() { + protected static JSqlClient getYqlClientForBatch() { return yqlClientForBatch; } + protected static IsolationEnabledSqlClient getIsolationClient() { + return isolationClient; + } + protected void initDatabase() { try (Connection connection = DriverManager.getConnection(getJdbcURL())) { URL dropTablesUrl = AbstractTest.class.getClassLoader().getResource("database-drop-tables-ydb.sql"); diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/batch/BatchTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/batch/BatchTest.java index cf03333b..63263540 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/batch/BatchTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/batch/BatchTest.java @@ -1,6 +1,5 @@ package ydb.jimmer.dialect.batch; -import org.babyfish.jimmer.sql.TargetTransferMode; import org.babyfish.jimmer.sql.ast.mutation.SaveMode; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -10,7 +9,7 @@ import java.util.Arrays; public class BatchTest extends AbstractInsertTest { - private static final String TABLE_NAME = "ydb_int"; + private static final String TABLE_NAME = "simple_table"; private void batchTest(SaveMode saveMode, String sql) { executeAndExpect( diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/YdbInt.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/Table.java similarity index 73% rename from jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/YdbInt.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/Table.java index 7d424770..982412c5 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/YdbInt.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/Table.java @@ -3,11 +3,10 @@ import org.babyfish.jimmer.sql.Column; import org.babyfish.jimmer.sql.Entity; import org.babyfish.jimmer.sql.Id; -import org.babyfish.jimmer.sql.Table; @Entity -@Table(name = "simple_table") -public interface YdbInt { +@org.babyfish.jimmer.sql.Table(name = "simple_table") +public interface Table { @Id @Column(name = "id") int getId(); diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/pagination/KeysetTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/pagination/KeysetTest.java index 8dd704a8..cad76fd2 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/pagination/KeysetTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/pagination/KeysetTest.java @@ -1,18 +1,12 @@ package ydb.jimmer.dialect.pagination; -import org.babyfish.jimmer.sql.JSqlClient; -import org.babyfish.jimmer.sql.runtime.JSqlClientImplementor; import org.junit.jupiter.api.Test; -import org.springframework.jdbc.datasource.DriverManagerDataSource; import ydb.jimmer.dialect.AbstractSelectTest; import ydb.jimmer.dialect.QueryTestContext; import ydb.jimmer.dialect.YdbKeysetPaginator; -import ydb.jimmer.dialect.model.YdbInt; +import ydb.jimmer.dialect.model.Table; import ydb.jimmer.dialect.model.YdbIntTable; -import ydb.jimmer.dialect.transaction.IsolationEnabledSqlClient; -import ydb.jimmer.dialect.transaction.YdbTxConnectionManager; -import javax.sql.DataSource; import java.util.Arrays; import java.util.List; @@ -30,24 +24,16 @@ public class KeysetTest extends AbstractSelectTest { } } - private static final DataSource dataSource = new DriverManagerDataSource(getJdbcURL()); - protected static final IsolationEnabledSqlClient yqlClient = new IsolationEnabledSqlClient( - (JSqlClientImplementor) JSqlClient.newBuilder() - .setConnectionManager(new YdbTxConnectionManager(dataSource)) - .setExecutor(executor) - .build() - ); - @Test public void simpleTest() { createTable(TABLE_NAME, VALUE_TYPE_NAME); insert(TABLE_NAME, VALUES); - YdbKeysetPaginator paginator = new YdbKeysetPaginator(yqlClient); + YdbKeysetPaginator paginator = new YdbKeysetPaginator(getIsolationClient()); YdbIntTable table = YdbIntTable.$; - YdbKeysetPaginator.Page page = null; + YdbKeysetPaginator.Page page = null; for (int i = 0; i < N; i += LIMIT) { List nextCursor = null; if (page != null) { @@ -59,7 +45,7 @@ public void simpleTest() { List.of(table.id()), nextCursor, LIMIT, - item -> List.of(((YdbInt) item).getId()), + item -> List.of(((Table) item).getId()), (q, t) -> { q.orderBy(t.id().asc()); return q.select(t); diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/AbstractTransactionTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/AbstractTransactionTest.java index 9214bf76..e65ccb90 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/AbstractTransactionTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/AbstractTransactionTest.java @@ -1,28 +1,18 @@ package ydb.jimmer.dialect.transaction; -import org.babyfish.jimmer.sql.JSqlClient; import org.babyfish.jimmer.sql.ast.mutation.MutationResult; import org.babyfish.jimmer.sql.ast.mutation.SaveMode; -import org.babyfish.jimmer.sql.runtime.JSqlClientImplementor; -import org.springframework.jdbc.datasource.DriverManagerDataSource; import ydb.jimmer.dialect.AbstractSelectTest; import ydb.jimmer.dialect.QueryTestContext; import ydb.jimmer.dialect.model.transaction.YdbTransaction; import ydb.jimmer.dialect.model.transaction.YdbTransactionDraft; -import javax.sql.DataSource; import java.util.List; import java.util.function.Function; import java.util.function.Supplier; public abstract class AbstractTransactionTest extends AbstractSelectTest { - private static final DataSource dataSource = new DriverManagerDataSource(getJdbcURL()); - protected static final IsolationEnabledSqlClient yqlClient = new IsolationEnabledSqlClient( - (JSqlClientImplementor) JSqlClient.newBuilder() - .setConnectionManager(new YdbTxConnectionManager(dataSource)) - .setExecutor(executor) - .build() - ); + protected static final IsolationEnabledSqlClient yqlClient = getIsolationClient(); protected void readTest(Function>, List> transaction) { String tableName = "ydb_transaction"; From 96b357b458f1a1ce301ec2bdb063ce04f7b15f23 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Mon, 27 Apr 2026 10:57:42 +0300 Subject: [PATCH 62/98] Revert "Removed unused models from tests" This reverts commit 8b53b91d406970e70dd8da1ad4aa97a4bb7afb08. --- .../java/ydb/jimmer/dialect/model/Group.java | 22 +++++++++++++ .../ydb/jimmer/dialect/model/Student.java | 31 +++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/Group.java create mode 100644 jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/Student.java diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/Group.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/Group.java new file mode 100644 index 00000000..cb69a3b0 --- /dev/null +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/Group.java @@ -0,0 +1,22 @@ +package ydb.jimmer.dialect.model; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.GeneratedValue; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; +import org.babyfish.jimmer.sql.meta.UUIDIdGenerator; + +import java.util.UUID; + +@Entity +@Table(name = "group") +public interface Group { + @Id + @GeneratedValue(generatorType = UUIDIdGenerator.class) + @Column(name = "id") + UUID id(); + + @Column(name = "name") + String name(); +} diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/Student.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/Student.java new file mode 100644 index 00000000..3ba0119b --- /dev/null +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/Student.java @@ -0,0 +1,31 @@ +package ydb.jimmer.dialect.model; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.ForeignKeyType; +import org.babyfish.jimmer.sql.GeneratedValue; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.JoinColumn; +import org.babyfish.jimmer.sql.ManyToOne; +import org.babyfish.jimmer.sql.Table; +import org.babyfish.jimmer.sql.meta.UUIDIdGenerator; + +import javax.annotation.Nullable; +import java.util.UUID; + +@Entity +@Table(name = "student") +public interface Student { + @Id + @GeneratedValue(generatorType = UUIDIdGenerator.class) + @Column(name = "id") + UUID id(); + + @Column(name = "name") + String name(); + + @ManyToOne + @Nullable + @JoinColumn(name = "group", foreignKeyType = ForeignKeyType.FAKE) + Group group(); +} From 7c3cb4552ab9717f5a5fdde99bb49efcb0933bfa Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Mon, 27 Apr 2026 13:28:25 +0300 Subject: [PATCH 63/98] Renamed the simple entity from "Table" to "Entity" --- .../java/ydb/jimmer/dialect/AbstractTest.java | 16 ++++++---------- .../dialect/dataTypeTest/SelectDataTypeTest.java | 2 -- .../dialect/model/{Table.java => Entity.java} | 8 ++++---- .../jimmer/dialect/pagination/KeysetTest.java | 10 +++++----- 4 files changed, 15 insertions(+), 21 deletions(-) rename jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/{Table.java => Entity.java} (62%) diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java index c8d77a7c..0ee71546 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java @@ -29,7 +29,6 @@ public abstract class AbstractTest { protected static final ExecutorMonitor executor = new ExecutorMonitor(); private static final JSqlClient yqlClient; private static final JSqlClient yqlClientForBatch; - protected static final IsolationEnabledSqlClient isolationClient; static { yqlClient = JSqlClient.newBuilder() @@ -44,14 +43,6 @@ public abstract class AbstractTest { .setExplicitBatchEnabled(true) .setDumbBatchAcceptable(true) .build(); - - DataSource dataSource = new DriverManagerDataSource(getJdbcURL()); - isolationClient = new IsolationEnabledSqlClient( - (JSqlClientImplementor) JSqlClient.newBuilder() - .setConnectionManager(new YdbTxConnectionManager(dataSource)) - .setExecutor(executor) - .build() - ); } protected static JSqlClient getYqlClient() { @@ -63,7 +54,12 @@ protected static JSqlClient getYqlClientForBatch() { } protected static IsolationEnabledSqlClient getIsolationClient() { - return isolationClient; + DataSource dataSource = new DriverManagerDataSource(getJdbcURL()); + return new IsolationEnabledSqlClient( + (JSqlClientImplementor) JSqlClient.newBuilder() + .setConnectionManager(new YdbTxConnectionManager(dataSource)) + .setExecutor(executor) + .build()); } protected void initDatabase() { diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java index 6fcdd65f..8ae4dccc 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java @@ -1,8 +1,6 @@ package ydb.jimmer.dialect.dataTypeTest; -import org.babyfish.jimmer.sql.ast.Executable; import org.babyfish.jimmer.sql.ast.PropExpression; -import org.babyfish.jimmer.sql.ast.query.ConfigurableRootQuery; import org.babyfish.jimmer.sql.ast.table.spi.AbstractTypedTable; import org.junit.jupiter.api.Test; import ydb.jimmer.dialect.AbstractSelectTest; diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/Table.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/Entity.java similarity index 62% rename from jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/Table.java rename to jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/Entity.java index 982412c5..39a70aca 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/Table.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/Entity.java @@ -1,12 +1,12 @@ package ydb.jimmer.dialect.model; import org.babyfish.jimmer.sql.Column; -import org.babyfish.jimmer.sql.Entity; import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Table; -@Entity -@org.babyfish.jimmer.sql.Table(name = "simple_table") -public interface Table { +@org.babyfish.jimmer.sql.Entity +@Table(name = "simple_table") +public interface Entity { @Id @Column(name = "id") int getId(); diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/pagination/KeysetTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/pagination/KeysetTest.java index cad76fd2..105c7e70 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/pagination/KeysetTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/pagination/KeysetTest.java @@ -4,8 +4,8 @@ import ydb.jimmer.dialect.AbstractSelectTest; import ydb.jimmer.dialect.QueryTestContext; import ydb.jimmer.dialect.YdbKeysetPaginator; -import ydb.jimmer.dialect.model.Table; -import ydb.jimmer.dialect.model.YdbIntTable; +import ydb.jimmer.dialect.model.Entity; +import ydb.jimmer.dialect.model.EntityTable; import java.util.Arrays; import java.util.List; @@ -31,9 +31,9 @@ public void simpleTest() { YdbKeysetPaginator paginator = new YdbKeysetPaginator(getIsolationClient()); - YdbIntTable table = YdbIntTable.$; + EntityTable table = EntityTable.$; - YdbKeysetPaginator.Page
page = null; + YdbKeysetPaginator.Page page = null; for (int i = 0; i < N; i += LIMIT) { List nextCursor = null; if (page != null) { @@ -45,7 +45,7 @@ public void simpleTest() { List.of(table.id()), nextCursor, LIMIT, - item -> List.of(((Table) item).getId()), + item -> List.of(((Entity) item).getId()), (q, t) -> { q.orderBy(t.id().asc()); return q.select(t); From 29fd907462da3ec60189ce8df4c8bd94fd76d067 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Mon, 27 Apr 2026 13:28:36 +0300 Subject: [PATCH 64/98] fixed BatchTest --- .../ydb/jimmer/dialect/batch/BatchTest.java | 66 ++++++++++++------- 1 file changed, 44 insertions(+), 22 deletions(-) diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/batch/BatchTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/batch/BatchTest.java index 63263540..71e0a9f7 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/batch/BatchTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/batch/BatchTest.java @@ -1,58 +1,80 @@ package ydb.jimmer.dialect.batch; import org.babyfish.jimmer.sql.ast.mutation.SaveMode; -import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import ydb.jimmer.dialect.AbstractInsertTest; -import ydb.jimmer.dialect.model.type.ydbInt32.YdbIntDraft; +import ydb.jimmer.dialect.model.Entity; +import ydb.jimmer.dialect.model.EntityDraft; -import java.util.Arrays; +import java.util.ArrayList; +import java.util.List; public class BatchTest extends AbstractInsertTest { private static final String TABLE_NAME = "simple_table"; - private void batchTest(SaveMode saveMode, String sql) { + private void batchTest( + SaveMode saveMode, + String sql, + int[][] batches, + int[][] expectedBatches + ) { + List entities = new ArrayList<>(); + for (int[] batch : batches) { + entities.add(EntityDraft.$.produce(t -> { + t.setId(batch[0]); + t.setValue(batch[1]); + })); + } + executeAndExpect( - getYqlClientForBatch().getEntities().saveEntitiesCommand( - Arrays.asList( - YdbIntDraft.$.produce(t -> { - t.setId(0); - t.setValue(123); - }), - YdbIntDraft.$.produce(t -> { - t.setId(1); - t.setValue(456); - }) - )) + getYqlClientForBatch() + .getEntities() + .saveEntitiesCommand(entities) .setMode(saveMode), cxt -> { cxt.sql(sql); - cxt.batchVariables(0, 0, 123); - cxt.batchVariables(1, 1, 456); + + for (int i = 0; i < batches.length; i++) { + cxt.batchVariables(i, expectedBatches[i][0], expectedBatches[i][1]); + } } ); } - @BeforeAll - static void setup() { + @BeforeEach + void setup() { createTable(TABLE_NAME, "Int32"); } + @AfterEach + void teardown() { + dropTable(TABLE_NAME); + } + @Test public void insertTest() { + int[][] batches = new int[][]{{0, 123}, {1, 456}}; batchTest(SaveMode.INSERT_ONLY, - "insert into " + TABLE_NAME + "(id, value) values(?, ?)"); + "insert into " + TABLE_NAME + "(id, value) values(?, ?)", + batches, batches); } @Test public void updateTest() { + int[][] batches = new int[][]{{0, 123}, {1, 456}}; + int[][] expectedBatches = new int[][]{{123, 0}, {456, 1}}; batchTest(SaveMode.UPDATE_ONLY, - "update " + TABLE_NAME + " set value = ? where id = ? returning id"); + "update " + TABLE_NAME + " set value = ? where id = ? returning id", + batches, expectedBatches); } @Test public void upsertTest() { + int[][] batches = new int[][]{{0, 123}, {1, 456}}; batchTest(SaveMode.UPSERT, - "upsert into " + TABLE_NAME + "(id, value) values(?, ?)"); + "upsert into " + TABLE_NAME + "(id, value) values(?, ?)", + batches, batches); } } From e30968ac29bed342211e514341d43e1105737574 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Mon, 27 Apr 2026 14:05:32 +0300 Subject: [PATCH 65/98] removed boilerplate --- .../dataTypeTest/SelectDataTypeTest.java | 143 ++++++++---------- 1 file changed, 62 insertions(+), 81 deletions(-) diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java index 8ae4dccc..4b2df464 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java @@ -35,8 +35,6 @@ import ydb.jimmer.dialect.model.type.ydbUtf8.YdbStringTable; import ydb.jimmer.dialect.model.type.ydbUuid.YdbUuidTable; -import java.util.List; - public class SelectDataTypeTest extends AbstractSelectTest { private void typeTest(String tableName, String typeName, @@ -50,258 +48,241 @@ private void typeTest(String tableName, String json = buildJsonResponse(expectedValues); - if (expectedValues.length == 1) { - executeAndExpect( - getYqlClient() - .createQuery(table) - .select(table), - cxt -> { - cxt.sql( - "select tb_1_.id, tb_1_.value from " + tableName + " tb_1_"); - cxt.rows(json); - } - ); - } else { - executeAndExpect( - getYqlClient() - .createQuery(table) - .orderBy(prop) - .select(table), - cxt -> { - cxt.sql( - "select tb_1_.id, tb_1_.value from " + tableName + " tb_1_ order by tb_1_.value asc"); - cxt.rows(json); - } - ); + var query = getYqlClient().createQuery(table); + StringBuilder sql = new StringBuilder("select tb_1_.id, tb_1_.value from " + tableName + " tb_1_"); + if (expectedValues.length > 1) { + query = query.orderBy(prop); + sql.append(" order by tb_1_.value asc"); } + executeAndExpect( + query.select(table), + cxt -> { + cxt.sql(sql.toString()); + cxt.rows(json); + } + ); + dropTable(tableName); } @Test public void boolTest() { - String[] valuesToInsert = new String[]{"false", "true"}; - String[] expectedValues = new String[]{"false", "true"}; + String[] values = new String[]{"false", "true"}; typeTest("ydb_boolean", "Bool", YdbBooleanTable.$, YdbBooleanTable.$.value(), - valuesToInsert, expectedValues); + values, values); typeTest("ydb_boolean_class", "Bool", YdbBooleanClassTable.$, YdbBooleanClassTable.$.value(), - valuesToInsert, expectedValues); + values, values); } @Test public void date32Test() { - String[] valuesToInsert = new String[]{"Date32(\"144169-01-01\")"}; + String[] values = new String[]{"Date32(\"144169-01-01\")"}; String[] expectedValues = new String[]{"\"4169-01-01\""}; typeTest("ydb_date", "Date32", YdbDateTable.$, YdbDateTable.$.value(), - valuesToInsert, expectedValues); + values, expectedValues); expectedValues = new String[]{"\"+144169-01-01\""}; typeTest("ydb_local_date", "Date32", YdbLocalDateTable.$, YdbLocalDateTable.$.value(), - valuesToInsert, expectedValues); + values, expectedValues); } @Test public void dateTime64Test() { - String[] valuesToInsert = new String[]{"DateTime64(\"2017-11-27T13:24:00Z\")"}; + String[] values = new String[]{"DateTime64(\"2017-11-27T13:24:00Z\")"}; String[] expectedValues = new String[]{"\"2017-11-27T13:24:00\""}; typeTest("ydb_local_date_time", "DateTime64", YdbLocalDateTimeTable.$, YdbLocalDateTimeTable.$.value(), - valuesToInsert, expectedValues); + values, expectedValues); } @Test public void decimalTest() { - String[] valuesToInsert = new String[]{"Decimal(\"1.23\", 22, 9)"}; + String[] values = new String[]{"Decimal(\"1.23\", 22, 9)"}; String[] expectedValues = new String[]{"1.230000000"}; typeTest("ydb_big_decimal", "Decimal(22, 9)", YdbBigDecimalTable.$, YdbBigDecimalTable.$.value(), - valuesToInsert, expectedValues); + values, expectedValues); } @Test public void doubleTest() { - String[] valuesToInsert = new String[]{"Double(\"1.23\")"}; + String[] values = new String[]{"Double(\"1.23\")"}; String[] expectedValues = new String[]{"1.23"}; typeTest("ydb_double", "Double", YdbDoubleTable.$, YdbDoubleTable.$.value(), - valuesToInsert, expectedValues); + values, expectedValues); typeTest("ydb_double_class", "Double", YdbDoubleClassTable.$, YdbDoubleClassTable.$.value(), - valuesToInsert, expectedValues); + values, expectedValues); } @Test public void enumTest() { - String[] valuesToInsert = new String[]{"\"ONE\"", "\"TWO\""}; - String[] expectedValues = new String[]{"\"ONE\"", "\"TWO\""}; + String[] values = new String[]{"\"ONE\"", "\"TWO\""}; typeTest("ydb_enum", "Utf8", YdbEnumTable.$, YdbEnumTable.$.value(), - valuesToInsert, expectedValues); + values, values); } @Test public void floatTest() { - String[] valuesToInsert = new String[]{"Float(\"1.23\")"}; + String[] values = new String[]{"Float(\"1.23\")"}; String[] expectedValues = new String[]{"1.23"}; typeTest("ydb_float", "Float", YdbFloatTable.$, YdbFloatTable.$.value(), - valuesToInsert, expectedValues); + values, expectedValues); typeTest("ydb_float_class", "Float", YdbFloatClassTable.$, YdbFloatClassTable.$.value(), - valuesToInsert, expectedValues); + values, expectedValues); } @Test public void int8Test() { - String[] valuesToInsert = new String[]{"-1", "0", "10"}; - String[] expectedValues = new String[]{"-1", "0", "10"}; + String[] values = new String[]{"-1", "0", "10"}; typeTest("ydb_byte", "Int8", YdbByteTable.$, YdbByteTable.$.value(), - valuesToInsert, expectedValues); + values, values); typeTest("ydb_byte_class", "Int8", YdbByteClassTable.$, YdbByteClassTable.$.value(), - valuesToInsert, expectedValues); + values, values); } @Test public void int16Test() { - String[] valuesToInsert = new String[]{"-1", "0", "10"}; - String[] expectedValues = new String[]{"-1", "0", "10"}; + String[] values = new String[]{"-1", "0", "10"}; typeTest("ydb_short", "Int16", YdbShortTable.$, YdbShortTable.$.value(), - valuesToInsert, expectedValues); + values, values); typeTest("ydb_short_class", "Int16", YdbShortClassTable.$, YdbShortClassTable.$.value(), - valuesToInsert, expectedValues); + values, values); } @Test public void int32Test() { - String[] valuesToInsert = new String[]{"-1", "0", "10"}; - String[] expectedValues = new String[]{"-1", "0", "10"}; + String[] values = new String[]{"-1", "0", "10"}; typeTest("ydb_int", "Int32", YdbIntTable.$, YdbIntTable.$.value(), - valuesToInsert, expectedValues); + values, values); typeTest("ydb_integer", "Int32", YdbIntegerTable.$, YdbIntegerTable.$.value(), - valuesToInsert, expectedValues); + values, values); - expectedValues = new String[]{"\"02:59:59.999\"", "\"03:00:00\"", "\"03:00:00.01\""}; + String[] expectedValues = new String[]{"\"02:59:59.999\"", "\"03:00:00\"", "\"03:00:00.01\""}; typeTest("ydb_local_time", "Int32", YdbLocalTimeTable.$, YdbLocalTimeTable.$.value(), - valuesToInsert, expectedValues); + values, expectedValues); - valuesToInsert = new String[]{"0", "10"}; + values = new String[]{"0", "10"}; expectedValues = new String[]{"\"00:00:00\"", "\"00:00:10\""}; typeTest("ydb_time", "Int32", YdbTimeTable.$, YdbTimeTable.$.value(), - valuesToInsert, expectedValues); + values, expectedValues); } @Test public void int64Test() { - String[] valuesToInsert = new String[]{"-1", "0", "10"}; - String[] expectedValues = new String[]{"-1", "0", "10"}; + String[] values = new String[]{"-1", "0", "10"}; typeTest("ydb_big_integer", "Int64", YdbBigIntegerTable.$, YdbBigIntegerTable.$.value(), - valuesToInsert, expectedValues); + values, values); typeTest("ydb_long", "Int64", YdbLongTable.$, YdbLongTable.$.value(), - valuesToInsert, expectedValues); + values, values); typeTest("ydb_long_class", "Int64", YdbLongClassTable.$, YdbLongClassTable.$.value(), - valuesToInsert, expectedValues); + values, values); } @Test public void interval64Test() { - String[] valuesToInsert = new String[]{"Interval(\"P0DT0H0M0.567890S\")"}; + String[] values = new String[]{"Interval(\"P0DT0H0M0.567890S\")"}; String[] expectedValues = new String[]{"0.567890000"}; typeTest("ydb_duration", "Interval64", YdbDurationTable.$, YdbDurationTable.$.value(), - valuesToInsert, expectedValues); + values, expectedValues); } @Test public void jsonTest() { - String[] valuesToInsert = new String[]{"Json(@@{\"a\":1,\"b\":null}@@)"}; + String[] values = new String[]{"Json(@@{\"a\":1,\"b\":null}@@)"}; String[] expectedValues = new String[]{"{\"a\":1,\"b\":null}"}; typeTest("ydb_json", "Json", YdbJsonTable.$, YdbJsonTable.$.value(), - valuesToInsert, expectedValues); + values, expectedValues); } @Test public void stringTest() { - String[] valuesToInsert = new String[]{"\"0\"", "\"string\""}; + String[] values = new String[]{"\"0\"", "\"string\""}; String[] expectedValues = new String[]{"\"MA==\"", "\"c3RyaW5n\""}; typeTest("ydb_byte_array", "String", YdbByteArrayTable.$, YdbByteArrayTable.$.value(), - valuesToInsert, expectedValues); + values, expectedValues); } @Test public void timestamp64Test() { - String[] valuesToInsert = new String[]{"Timestamp64(\"2017-11-27T13:24:00.123456Z\")"}; + String[] values = new String[]{"Timestamp64(\"2017-11-27T13:24:00.123456Z\")"}; String[] expectedValues = new String[]{"\"2017-11-27T13:24:00.123456Z\""}; typeTest("ydb_instant", "Timestamp64", YdbInstantTable.$, YdbInstantTable.$.value(), - valuesToInsert, expectedValues); + values, expectedValues); expectedValues = new String[]{"\"2017-11-27\""}; typeTest("ydb_timestamp", "Timestamp64", YdbTimestampTable.$, YdbTimestampTable.$.value(), - valuesToInsert, expectedValues); + values, expectedValues); typeTest("ydb_util_date", "Timestamp64", YdbUtilDateTable.$, YdbUtilDateTable.$.value(), - valuesToInsert, expectedValues); + values, expectedValues); } @Test public void utf8Test() { - String[] valuesToInsert = new String[]{"\"0\"", "\"string\""}; - String[] expectedValues = new String[]{"\"0\"", "\"string\""}; + String[] values = new String[]{"\"0\"", "\"string\""}; typeTest("ydb_string", "Utf8", YdbStringTable.$, YdbStringTable.$.value(), - valuesToInsert, expectedValues); + values, values); } @Test public void uuidTest() { - String[] valuesToInsert = new String[]{ + String[] values = new String[]{ "Uuid(\"9e197d65-1914-4d57-a65f-77a52a06baa7\")", "Uuid(\"8e0f2cf4-4656-4d73-970e-a18be9ead78b\")"}; String[] expectedValues = new String[]{ @@ -310,6 +291,6 @@ public void uuidTest() { typeTest("ydb_uuid", "Uuid", YdbUuidTable.$, YdbUuidTable.$.value(), - valuesToInsert, expectedValues); + values, expectedValues); } } From 4c19948ab89604f20b968f657cfb1657c54990c4 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Tue, 28 Apr 2026 13:36:21 +0300 Subject: [PATCH 66/98] Removed boilerplate --- .../dataTypeTest/SelectDataTypeTest.java | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java index 4b2df464..725eb849 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java @@ -36,6 +36,14 @@ import ydb.jimmer.dialect.model.type.ydbUuid.YdbUuidTable; public class SelectDataTypeTest extends AbstractSelectTest { + private void typeTest(String tableName, + String typeName, + AbstractTypedTable table, + PropExpression prop, + String[] values) { + typeTest(tableName, typeName, table, prop, values, values); + } + private void typeTest(String tableName, String typeName, AbstractTypedTable table, @@ -72,11 +80,11 @@ public void boolTest() { typeTest("ydb_boolean", "Bool", YdbBooleanTable.$, YdbBooleanTable.$.value(), - values, values); + values); typeTest("ydb_boolean_class", "Bool", YdbBooleanClassTable.$, YdbBooleanClassTable.$.value(), - values, values); + values); } @Test @@ -135,7 +143,7 @@ public void enumTest() { typeTest("ydb_enum", "Utf8", YdbEnumTable.$, YdbEnumTable.$.value(), - values, values); + values); } @Test @@ -158,11 +166,11 @@ public void int8Test() { typeTest("ydb_byte", "Int8", YdbByteTable.$, YdbByteTable.$.value(), - values, values); + values); typeTest("ydb_byte_class", "Int8", YdbByteClassTable.$, YdbByteClassTable.$.value(), - values, values); + values); } @Test @@ -171,11 +179,11 @@ public void int16Test() { typeTest("ydb_short", "Int16", YdbShortTable.$, YdbShortTable.$.value(), - values, values); + values); typeTest("ydb_short_class", "Int16", YdbShortClassTable.$, YdbShortClassTable.$.value(), - values, values); + values); } @Test @@ -184,11 +192,11 @@ public void int32Test() { typeTest("ydb_int", "Int32", YdbIntTable.$, YdbIntTable.$.value(), - values, values); + values); typeTest("ydb_integer", "Int32", YdbIntegerTable.$, YdbIntegerTable.$.value(), - values, values); + values); String[] expectedValues = new String[]{"\"02:59:59.999\"", "\"03:00:00\"", "\"03:00:00.01\""}; @@ -210,15 +218,15 @@ public void int64Test() { typeTest("ydb_big_integer", "Int64", YdbBigIntegerTable.$, YdbBigIntegerTable.$.value(), - values, values); + values); typeTest("ydb_long", "Int64", YdbLongTable.$, YdbLongTable.$.value(), - values, values); + values); typeTest("ydb_long_class", "Int64", YdbLongClassTable.$, YdbLongClassTable.$.value(), - values, values); + values); } @Test @@ -277,7 +285,7 @@ public void utf8Test() { typeTest("ydb_string", "Utf8", YdbStringTable.$, YdbStringTable.$.value(), - values, values); + values); } @Test From fd7c0a07feff7123d8d9e01586c29aca7499442e Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Tue, 28 Apr 2026 13:37:13 +0300 Subject: [PATCH 67/98] Removed space in the function arguments --- .../src/test/java/ydb/jimmer/dialect/QueryTestContext.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java index d65dce8d..8e8a51f0 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java @@ -55,7 +55,7 @@ public void sql(String sql) { "statements[" + index + "].sql"); } - public void variables(Object ... values) { + public void variables(Object... values) { batchVariables(0, values); batches(1); } @@ -64,7 +64,7 @@ public void batches(int batchCount) { Assertions.assertEquals(batchCount, logs.get(index).getVariablesList().size()); } - public void batchVariables(int batchIndex, Object ... values) { + public void batchVariables(int batchIndex, Object... values) { Assertions.assertEquals( values.length, logs.get(index).getVariablesList().get(batchIndex).size(), From 0decbca90a02f3fd1b8f192fbb96262b40ba7695 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Tue, 28 Apr 2026 15:44:38 +0300 Subject: [PATCH 68/98] In Insert tests the crreated SQL table is dropped at the end --- .../ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java index 25df8ea5..c3e5d7e7 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java @@ -63,6 +63,8 @@ private void typeTest(String tableName, cxt.variables(variables); } ); + + dropTable(tableName); } @Test From 1e8fcbbe1ecc2574424f887f6272ccf3c1fbb203 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Wed, 29 Apr 2026 16:12:27 +0300 Subject: [PATCH 69/98] Extracted the test for the json insert into a new class --- .../dataTypeTest/InsertDataTypeTest.java | 16 ------- .../dialect/dataTypeTest/InsertJsonTest.java | 45 +++++++++++++++++++ 2 files changed, 45 insertions(+), 16 deletions(-) create mode 100644 jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertJsonTest.java diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java index c3e5d7e7..fe643831 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java @@ -297,22 +297,6 @@ public void interval64Test() { variables); } - @Test - public void jsonTest() { - Json json = new Json(); - json.setA(2); - json.setB(3); - - Object[] variables = new Object[]{0, json}; - - typeTest("ydb_json", "Json", - YdbJsonDraft.$.produce(t -> { - t.setId((Integer) variables[0]); - t.setValue((Json) variables[1]); - }), - variables); - } - @Test public void stringTest() { Object[] variables = new Object[]{0, new byte[]{1, 2}}; diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertJsonTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertJsonTest.java new file mode 100644 index 00000000..659f86fe --- /dev/null +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertJsonTest.java @@ -0,0 +1,45 @@ +package ydb.jimmer.dialect.dataTypeTest; + +import org.babyfish.jimmer.sql.ast.mutation.SaveMode; +import org.junit.jupiter.api.Test; +import ydb.jimmer.dialect.AbstractSelectTest; +import ydb.jimmer.dialect.model.type.ydbJson.Json; +import ydb.jimmer.dialect.model.type.ydbJson.YdbJsonDraft; +import ydb.jimmer.dialect.model.type.ydbJson.YdbJsonTable; + +public class InsertJsonTest extends AbstractSelectTest { + private static final String tableName = "ydb_json"; + private static final String typeName = "Json"; + + @Test + public void insertJsonTest() { + Json json = new Json(); + json.setA(2); + json.setB(3); + + Object[] variables = new Object[]{0, json}; + + String[] expectedValues = new String[]{"{\"a\":2,\"b\":3}"}; + String expectedJson = buildJsonResponse(expectedValues); + + YdbJsonTable table = YdbJsonTable.$; + + createTable(tableName, typeName); + + getIsolationClient().getEntities().saveCommand(YdbJsonDraft.$.produce(t -> { + t.setId((Integer) variables[0]); + t.setValue((Json) variables[1]); + })) + .setMode(SaveMode.INSERT_ONLY).execute(); + executeAndExpect(getYqlClient().createQuery(table).select(table), + cxt -> { + cxt.sql("insert into " + tableName + "(id, value) values(?, ?)"); + cxt.nextStatement(); + cxt.sql("select tb_1_.id, tb_1_.value from " + tableName + " tb_1_"); + cxt.rows(expectedJson); + } + ); + + dropTable(tableName); + } +} From dbeed53932305ac7bbdd4b206528c3eab1c51b99 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Wed, 29 Apr 2026 16:13:05 +0300 Subject: [PATCH 70/98] removed unnecessary imports --- .../ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java index fe643831..f9722b09 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java @@ -27,8 +27,6 @@ import ydb.jimmer.dialect.model.type.ydbInt8.YdbByteClassDraft; import ydb.jimmer.dialect.model.type.ydbInt8.YdbByteDraft; import ydb.jimmer.dialect.model.type.ydbInterval64.YdbDurationDraft; -import ydb.jimmer.dialect.model.type.ydbJson.Json; -import ydb.jimmer.dialect.model.type.ydbJson.YdbJsonDraft; import ydb.jimmer.dialect.model.type.ydbString.YdbByteArrayDraft; import ydb.jimmer.dialect.model.type.ydbTimestamp64.YdbInstantDraft; import ydb.jimmer.dialect.model.type.ydbTimestamp64.YdbTimestampDraft; From 9945da4a6f36878baa12ea93a3d8f59f44331f9a Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Thu, 30 Apr 2026 00:15:12 +0300 Subject: [PATCH 71/98] Extracted all data types that are changed by Jimmer before reaching the YDB driver The function responsible for the type change can be found here: org.babyfish.jimmer.sql.ast.impl.Variables.java: handleDateTime(Object value, ZoneId zoneId) --- .../dataTypeTest/InsertDataTypeTest.java | 104 +++++++++--------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java index f9722b09..3f0d69b2 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java @@ -65,6 +65,54 @@ private void typeTest(String tableName, dropTable(tableName); } + @Test + public void handleDateTimeJimmerTest() { + Object[] variables = new Object[]{0, Instant.now()}; + + typeTest("ydb_instant", "Timestamp64", + YdbInstantDraft.$.produce(t -> { + t.setId((Integer) variables[0]); + t.setValue((Instant) variables[1]); + }), + variables); + + Object[] variables1 = new Object[]{0, LocalDateTime.parse("1970-01-01T00:00:00")}; + + typeTest("ydb_local_date_time", "DateTime64", + YdbLocalDateTimeDraft.$.produce(t -> { + t.setId((Integer) variables1[0]); + t.setValue((LocalDateTime) variables1[1]); + }), + variables1); + + Object[] variables2 = new Object[]{0, LocalDate.parse("1970-01-01")}; + + typeTest("ydb_local_date", "Date32", + YdbLocalDateDraft.$.produce(t -> { + t.setId((Integer) variables2[0]); + t.setValue((LocalDate) variables2[1]); + }), + variables2); + + Object[] variables3 = new Object[]{0, LocalTime.parse("10:15")}; + + typeTest("ydb_local_time", "Int32", + YdbLocalTimeDraft.$.produce(t -> { + t.setId((Integer) variables3[0]); + t.setValue((LocalTime) variables3[1]); + }), + variables3); + + Object[] variables4 = new Object[]{0, new java.util.Date(0)}; + + typeTest("ydb_util_date", "Timestamp64", + YdbUtilDateDraft.$.produce(t -> { + t.setId((Integer) variables4[0]); + t.setValue((java.util.Date) variables4[1]); + }), + variables4); + } + @Test public void boolTest() { Object[] variables = new Object[]{0, true}; @@ -95,27 +143,6 @@ public void date32Test() { t.setValue((Date) variables1[1]); }), variables1); - - Object[] variables2 = new Object[]{0, LocalDate.parse("1970-01-01")}; - - typeTest("ydb_local_date", "Date32", - YdbLocalDateDraft.$.produce(t -> { - t.setId((Integer) variables2[0]); - t.setValue((LocalDate) variables2[1]); - }), - variables2); - } - - @Test - public void dateTime64Test() { - Object[] variables = new Object[]{0, LocalDateTime.parse("1970-01-01T00:00:00")}; - - typeTest("ydb_local_date_time", "DateTime64", - YdbLocalDateTimeDraft.$.produce(t -> { - t.setId((Integer) variables[0]); - t.setValue((LocalDateTime) variables[1]); - }), - variables); } @Test @@ -236,15 +263,6 @@ public void int32Test() { }), variables); - Object[] variables1 = new Object[]{0, LocalTime.parse("10:15")}; - - typeTest("ydb_local_time", "Int32", - YdbLocalTimeDraft.$.produce(t -> { - t.setId((Integer) variables1[0]); - t.setValue((LocalTime) variables1[1]); - }), - variables1); - Object[] variables2 = new Object[]{0, new Time(0)}; typeTest("ydb_time", "Int32", @@ -309,32 +327,14 @@ public void stringTest() { @Test public void timestamp64Test() { - Object[] variables = new Object[]{0, Instant.now()}; - - typeTest("ydb_instant", "Timestamp64", - YdbInstantDraft.$.produce(t -> { - t.setId((Integer) variables[0]); - t.setValue((Instant) variables[1]); - }), - variables); - - Object[] variables1 = new Object[]{0, new Timestamp(0)}; + Object[] variables = new Object[]{0, new Timestamp(0)}; typeTest("ydb_timestamp", "Timestamp64", YdbTimestampDraft.$.produce(t -> { - t.setId((Integer) variables1[0]); - t.setValue((Timestamp) variables1[1]); - }), - variables1); - - Object[] variables2 = new Object[]{0, new java.util.Date(0)}; - - typeTest("ydb_util_date", "Timestamp64", - YdbUtilDateDraft.$.produce(t -> { - t.setId((Integer) variables2[0]); - t.setValue((java.util.Date) variables2[1]); + t.setId((Integer) variables[0]); + t.setValue((Timestamp) variables[1]); }), - variables2); + variables); } @Test From 9cf674ee7fa69cf0d525683f32060e1abebe7447 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Thu, 30 Apr 2026 00:22:22 +0300 Subject: [PATCH 72/98] Added a javadoc comment about the handleDateTime --- .../ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java index 3f0d69b2..d00cfef4 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertDataTypeTest.java @@ -44,6 +44,7 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; +import java.time.ZoneId; import java.util.UUID; public class InsertDataTypeTest extends AbstractInsertTest { @@ -65,6 +66,10 @@ private void typeTest(String tableName, dropTable(tableName); } + /** + * {@link org.babyfish.jimmer.sql.ast.impl.Variables#handleDateTime(Object, ZoneId) handleDateTime(Object, ZoneId)} + * this Jimmer method is responsible for changing java types without any user input + */ @Test public void handleDateTimeJimmerTest() { Object[] variables = new Object[]{0, Instant.now()}; From a67f8d9116df8b540b5e6e836d731a9e20385a8e Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Thu, 30 Apr 2026 02:19:27 +0300 Subject: [PATCH 73/98] Removed boilerplate and unnecessary code --- .../jimmer/dialect/AbstractSelectTest.java | 15 +++-------- .../java/ydb/jimmer/dialect/AbstractTest.java | 3 +-- .../ydb/jimmer/dialect/QueryTestContext.java | 1 - .../java/ydb/jimmer/dialect/SelectTest.java | 12 +++------ .../dialect/dataTypeTest/InsertJsonTest.java | 12 ++++----- .../jimmer/dialect/pagination/KeysetTest.java | 4 +-- .../dialect/streaming/StreamingTest.java | 16 ++++++------ .../transaction/AbstractTransactionTest.java | 26 +++++++++---------- 8 files changed, 37 insertions(+), 52 deletions(-) diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractSelectTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractSelectTest.java index fc7dc864..8a669227 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractSelectTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractSelectTest.java @@ -11,25 +11,18 @@ public abstract class AbstractSelectTest extends AbstractTest { protected static void executeAndExpect(Executable> query, Consumer block) { - List rows = connectAndExecute(true, query); - block.accept(new QueryTestContext(executor.getLogs(), rows)); - } - - private static List connectAndExecute(boolean rollback, Executable> query) { + List rows = null; try (Connection connection = DriverManager.getConnection(getJdbcURL())) { - connection.setAutoCommit(!rollback); try { - return query.execute(connection); + rows = query.execute(connection); } finally { - if (rollback) { - connection.rollback(); - } + connection.rollback(); } } catch (SQLException e) { Assertions.fail("Database threw an exception: " + e.getMessage()); } - return null; + block.accept(new QueryTestContext(executor.getLogs(), rows)); } protected static void insert(String tableName, String... values) { diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java index 0ee71546..55201fb0 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java @@ -120,8 +120,7 @@ protected static void createTable(String tableName, String typeName) { } protected static void dropTable(String tableName) { - executeSql( - "DROP TABLE " + tableName); + executeSql("DROP TABLE " + tableName); } protected static void executeSql(String sql) { diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java index 8e8a51f0..128fdc6d 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/QueryTestContext.java @@ -5,7 +5,6 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.babyfish.jimmer.jackson.ImmutableModule; import org.babyfish.jimmer.sql.ast.mutation.MutationResult; -import org.babyfish.jimmer.sql.collection.TypedList; import org.junit.jupiter.api.Assertions; import ydb.jimmer.dialect.sqlMonitor.QueryLog; diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/SelectTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/SelectTest.java index 188dac89..33ced625 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/SelectTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/SelectTest.java @@ -3,11 +3,9 @@ import org.junit.jupiter.api.Test; import ydb.jimmer.dialect.model.StudentTable; -import java.sql.SQLException; - public class SelectTest extends AbstractSelectTest { @Test - public void OneEntityTest() throws SQLException { + public void OneEntityTest() { initDatabase(); StudentTable table = StudentTable.$; @@ -16,11 +14,9 @@ public void OneEntityTest() throws SQLException { getYqlClient() .createQuery(table) .select(table), - cxt -> { - cxt.sql( - "select tb_1_.id, tb_1_.name, tb_1_.group " + - "from student tb_1_"); - } + cxt -> cxt.sql( + "select tb_1_.id, tb_1_.name, tb_1_.group " + + "from student tb_1_") ); } } diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertJsonTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertJsonTest.java index 659f86fe..32e219a4 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertJsonTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/InsertJsonTest.java @@ -8,8 +8,8 @@ import ydb.jimmer.dialect.model.type.ydbJson.YdbJsonTable; public class InsertJsonTest extends AbstractSelectTest { - private static final String tableName = "ydb_json"; - private static final String typeName = "Json"; + private static final String TABLE_NAME = "ydb_json"; + private static final String TYPE_NAME = "Json"; @Test public void insertJsonTest() { @@ -24,7 +24,7 @@ public void insertJsonTest() { YdbJsonTable table = YdbJsonTable.$; - createTable(tableName, typeName); + createTable(TABLE_NAME, TYPE_NAME); getIsolationClient().getEntities().saveCommand(YdbJsonDraft.$.produce(t -> { t.setId((Integer) variables[0]); @@ -33,13 +33,13 @@ public void insertJsonTest() { .setMode(SaveMode.INSERT_ONLY).execute(); executeAndExpect(getYqlClient().createQuery(table).select(table), cxt -> { - cxt.sql("insert into " + tableName + "(id, value) values(?, ?)"); + cxt.sql("insert into " + TABLE_NAME + "(id, value) values(?, ?)"); cxt.nextStatement(); - cxt.sql("select tb_1_.id, tb_1_.value from " + tableName + " tb_1_"); + cxt.sql("select tb_1_.id, tb_1_.value from " + TABLE_NAME + " tb_1_"); cxt.rows(expectedJson); } ); - dropTable(tableName); + dropTable(TABLE_NAME); } } diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/pagination/KeysetTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/pagination/KeysetTest.java index 105c7e70..3ed274c1 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/pagination/KeysetTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/pagination/KeysetTest.java @@ -12,7 +12,7 @@ public class KeysetTest extends AbstractSelectTest { private static final String TABLE_NAME = "simple_table"; - private static final String VALUE_TYPE_NAME = "Int32"; + private static final String TYPE_NAME = "Int32"; private static final int N = 100; private static final int LIMIT = 20; @@ -26,7 +26,7 @@ public class KeysetTest extends AbstractSelectTest { @Test public void simpleTest() { - createTable(TABLE_NAME, VALUE_TYPE_NAME); + createTable(TABLE_NAME, TYPE_NAME); insert(TABLE_NAME, VALUES); YdbKeysetPaginator paginator = new YdbKeysetPaginator(getIsolationClient()); diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/streaming/StreamingTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/streaming/StreamingTest.java index 589bbc80..66e71533 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/streaming/StreamingTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/streaming/StreamingTest.java @@ -11,20 +11,20 @@ import java.util.List; public class StreamingTest extends AbstractSelectTest { + private static final String TABLE_NAME = "ydb_streaming"; + private static final String TYPE_NAME = "Int32"; + @Test public void cursorTest() { - String tableName = "ydb_streaming"; - String typeName = "Int32"; AbstractTypedTable table = YdbStreamingTable.$; PropExpression prop = YdbStreamingTable.$.value(); - String[] valuesToInsert = new String[]{"11", "12", "21", "22"}; - String[] expectedValues = new String[]{"11", "12", "21", "22"}; + String[] values = new String[]{"11", "12", "21", "22"}; - createTable(tableName, typeName); + createTable(TABLE_NAME, TYPE_NAME); - insert(tableName, valuesToInsert); + insert(TABLE_NAME, values); - String json = buildJsonResponse(expectedValues); + String json = buildJsonResponse(values); executeAndExpect((Connection con) -> { List responses = new ArrayList<>(); @@ -37,7 +37,7 @@ public void cursorTest() { }, cxt -> { cxt.sql( - "select tb_1_.id, tb_1_.value from " + tableName + " tb_1_ order by tb_1_.value asc"); + "select tb_1_.id, tb_1_.value from " + TABLE_NAME + " tb_1_ order by tb_1_.value asc"); cxt.rows(json); } ); diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/AbstractTransactionTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/AbstractTransactionTest.java index e65ccb90..0bd9c35a 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/AbstractTransactionTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/AbstractTransactionTest.java @@ -12,29 +12,29 @@ import java.util.function.Supplier; public abstract class AbstractTransactionTest extends AbstractSelectTest { + private static final String TABLE_NAME = "ydb_transaction"; + private static final String TYPE_NAME = "Int32"; + protected static final IsolationEnabledSqlClient yqlClient = getIsolationClient(); protected void readTest(Function>, List> transaction) { - String tableName = "ydb_transaction"; - String typeName = "Int32"; - String[] valuesToInsert = new String[]{"-1", "0", "10"}; - String[] expectedValues = new String[]{"-1", "0", "10"}; + String[] values = new String[]{"-1", "0", "10"}; - createTable(tableName, typeName); + createTable(TABLE_NAME, TYPE_NAME); - insert(tableName, valuesToInsert); + insert(TABLE_NAME, values); List rows = transaction.apply(() -> yqlClient.getEntities().findAll(YdbTransaction.class) ); QueryTestContext cxt = new QueryTestContext(executor.getLogs(), rows); - cxt.sql("select tb_1_.id, tb_1_.value from " + tableName + " tb_1_"); + cxt.sql("select tb_1_.id, tb_1_.value from " + TABLE_NAME + " tb_1_"); - String json = buildJsonResponse(expectedValues); + String json = buildJsonResponse(values); cxt.rows(json); - dropTable(tableName); + dropTable(TABLE_NAME); } protected void writeTest(Function, MutationResult> transaction, boolean readOnly) { @@ -47,11 +47,9 @@ protected void writeTest(Function, MutationResult> tran } protected void writeTest(Function, MutationResult> transaction, String errorMessage) { - String tableName = "ydb_transaction"; - String typeName = "Int32"; Object[] variables = new Object[]{0, 10}; - createTable(tableName, typeName); + createTable(TABLE_NAME, TYPE_NAME); MutationResult result = null; Throwable throwable = null; @@ -69,10 +67,10 @@ protected void writeTest(Function, MutationResult> tran } QueryTestContext cxt = new QueryTestContext(executor.getLogs(), result, throwable); - cxt.sql("insert into " + tableName + "(id, value) values(?, ?)"); + cxt.sql("insert into " + TABLE_NAME + "(id, value) values(?, ?)"); cxt.variables(variables); cxt.error(errorMessage); - dropTable(tableName); + dropTable(TABLE_NAME); } } From d57b57894d90c426cb8d068733dfcc188f171ba2 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Thu, 30 Apr 2026 20:02:33 +0300 Subject: [PATCH 74/98] Renamed the custom SqlClient --- .../src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java | 4 ++-- .../{IsolationEnabledSqlClient.java => YqlClient.java} | 4 ++-- .../src/test/java/ydb/jimmer/dialect/AbstractTest.java | 6 +++--- .../jimmer/dialect/transaction/AbstractTransactionTest.java | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) rename jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/{IsolationEnabledSqlClient.java => YqlClient.java} (90%) diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java index 42e180c9..e2925d7d 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java @@ -3,7 +3,7 @@ import org.babyfish.jimmer.sql.JSqlClient; import org.babyfish.jimmer.sql.runtime.JSqlClientImplementor; import ydb.jimmer.dialect.scalar.DurationProvider; -import ydb.jimmer.dialect.transaction.IsolationEnabledSqlClient; +import ydb.jimmer.dialect.transaction.YqlClient; import ydb.jimmer.dialect.transaction.YdbTxConnectionManager; import javax.sql.DataSource; @@ -16,7 +16,7 @@ public static JSqlClient getYqlClient( DataSource dataSource, Function block ) { - return new IsolationEnabledSqlClient((JSqlClientImplementor) buildSqlClient(dataSource, block).build()); + return new YqlClient((JSqlClientImplementor) buildSqlClient(dataSource, block).build()); } private static JSqlClient.Builder buildSqlClient( diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/IsolationEnabledSqlClient.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YqlClient.java similarity index 90% rename from jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/IsolationEnabledSqlClient.java rename to jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YqlClient.java index ff17e178..61b3052c 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/IsolationEnabledSqlClient.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YqlClient.java @@ -7,10 +7,10 @@ import java.sql.Connection; import java.util.function.Supplier; -public class IsolationEnabledSqlClient extends AbstractJSqlClientDelegate { +public class YqlClient extends AbstractJSqlClientDelegate { private final JSqlClientImplementor delegate; - public IsolationEnabledSqlClient(JSqlClientImplementor delegate) { + public YqlClient(JSqlClientImplementor delegate) { this.delegate = delegate; } diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java index 55201fb0..44cb93e0 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java @@ -12,7 +12,7 @@ import tech.ydb.test.junit5.YdbHelperExtension; import ydb.jimmer.dialect.scalar.DurationProvider; import ydb.jimmer.dialect.sqlMonitor.ExecutorMonitor; -import ydb.jimmer.dialect.transaction.IsolationEnabledSqlClient; +import ydb.jimmer.dialect.transaction.YqlClient; import ydb.jimmer.dialect.transaction.YdbTxConnectionManager; import javax.sql.DataSource; @@ -53,9 +53,9 @@ protected static JSqlClient getYqlClientForBatch() { return yqlClientForBatch; } - protected static IsolationEnabledSqlClient getIsolationClient() { + protected static YqlClient getIsolationClient() { DataSource dataSource = new DriverManagerDataSource(getJdbcURL()); - return new IsolationEnabledSqlClient( + return new YqlClient( (JSqlClientImplementor) JSqlClient.newBuilder() .setConnectionManager(new YdbTxConnectionManager(dataSource)) .setExecutor(executor) diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/AbstractTransactionTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/AbstractTransactionTest.java index 0bd9c35a..45969413 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/AbstractTransactionTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/transaction/AbstractTransactionTest.java @@ -15,7 +15,7 @@ public abstract class AbstractTransactionTest extends AbstractSelectTest { private static final String TABLE_NAME = "ydb_transaction"; private static final String TYPE_NAME = "Int32"; - protected static final IsolationEnabledSqlClient yqlClient = getIsolationClient(); + protected static final YqlClient yqlClient = getIsolationClient(); protected void readTest(Function>, List> transaction) { String[] values = new String[]{"-1", "0", "10"}; From cb55a991321659d003d8f834c8d15daddb592d4c Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Thu, 30 Apr 2026 20:08:42 +0300 Subject: [PATCH 75/98] Added a simple README --- jimmer-dialect/README.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 jimmer-dialect/README.md diff --git a/jimmer-dialect/README.md b/jimmer-dialect/README.md new file mode 100644 index 00000000..a55f78e2 --- /dev/null +++ b/jimmer-dialect/README.md @@ -0,0 +1,34 @@ +# YDB Dialect for Jimmer + +## Overview + +This project contains a custom Jimmer dialect +for a simple integration between Jimmer ORM and Yandex Database (YDB). +For more thorough integration it is recommended to use the YqlClientBuilder class +for a custom JSqlClient. + + +### Features + +- Custom type mappings to utilize YDB's data types. +- Support for YDB-specific features and functions. +- Transaction modes and isolation levels. +- YDB keyset pagination. + +## Getting Started + +### Requirements + +To use this Hibernate YDB Dialect, you'll need: + +- Java 17 or above. +- Jimmer version 0.9.117 +- [YDB JDBC Driver](https://github.com/ydb-platform/ydb-jdbc-driver) +- Access to a YDB Database instance + +## Usage + +```java +DataSource dataSource = new DriverManagerDataSource("jdbc:ydb:grpc://localhost:2136/local"); +YqlClient yqlClient = getYqlClient(dataSource); +``` \ No newline at end of file From 3f26a0e059fd09ed0d85091b3539c03a5301d4da Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Thu, 30 Apr 2026 20:27:37 +0300 Subject: [PATCH 76/98] Fixed the return value for the YqlClientBuilder --- .../src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java index e2925d7d..19a6d93a 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java @@ -12,7 +12,7 @@ public final class YqlClientBuilder { private YqlClientBuilder() {} - public static JSqlClient getYqlClient( + public static YqlClient getYqlClient( DataSource dataSource, Function block ) { @@ -30,7 +30,7 @@ private static JSqlClient.Builder buildSqlClient( )); } - public static JSqlClient getYqlClient(DataSource dataSource) { + public static YqlClient getYqlClient(DataSource dataSource) { return getYqlClient(dataSource, x -> x); } From 83dc51637d8971547ea876aa19ebfd2a2986f597 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Fri, 1 May 2026 15:03:26 +0300 Subject: [PATCH 77/98] Added a simple left join test --- .../java/ydb/jimmer/dialect/JoinTest.java | 30 +++++++++++++++++++ .../java/ydb/jimmer/dialect/SelectTest.java | 3 +- 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 jimmer-dialect/src/test/java/ydb/jimmer/dialect/JoinTest.java diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/JoinTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/JoinTest.java new file mode 100644 index 00000000..037ba1f9 --- /dev/null +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/JoinTest.java @@ -0,0 +1,30 @@ +package ydb.jimmer.dialect; + +import org.babyfish.jimmer.sql.JoinType; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import ydb.jimmer.dialect.model.StudentTable; + +public class JoinTest extends AbstractSelectTest { + @BeforeEach + protected void setup() { + initDatabase(); + } + + @Test + public void leftJoinTest() { + StudentTable table = StudentTable.$; + executeAndExpect( + getYqlClient() + .createQuery(table) + .orderBy(table.group(JoinType.LEFT).name().asc()) + .select(table), + cxt -> cxt.sql( + "select tb_1_.id, tb_1_.name, tb_1_.group " + + "from student tb_1_ " + + "left join group tb_2_ on tb_1_.group = tb_2_.id " + + "order by tb_2_.name asc" + ) + ); + } +} diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/SelectTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/SelectTest.java index 33ced625..cb43b015 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/SelectTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/SelectTest.java @@ -16,7 +16,8 @@ public void OneEntityTest() { .select(table), cxt -> cxt.sql( "select tb_1_.id, tb_1_.name, tb_1_.group " + - "from student tb_1_") + "from student tb_1_" + ) ); } } From 7b776a494ab92ca78f76ec0b113e121171fba7b9 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Sat, 2 May 2026 01:53:23 +0300 Subject: [PATCH 78/98] Added more join types to the simple join test --- .../java/ydb/jimmer/dialect/JoinTest.java | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/JoinTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/JoinTest.java index 037ba1f9..a42b2b4a 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/JoinTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/JoinTest.java @@ -11,20 +11,39 @@ protected void setup() { initDatabase(); } - @Test - public void leftJoinTest() { + private void joinTest(JoinType joinType, String join) { StudentTable table = StudentTable.$; executeAndExpect( getYqlClient() .createQuery(table) - .orderBy(table.group(JoinType.LEFT).name().asc()) + .orderBy(table.group(joinType).name().asc()) .select(table), cxt -> cxt.sql( "select tb_1_.id, tb_1_.name, tb_1_.group " + "from student tb_1_ " + - "left join group tb_2_ on tb_1_.group = tb_2_.id " + + join + " join group tb_2_ on tb_1_.group = tb_2_.id " + "order by tb_2_.name asc" ) ); } + + @Test + public void leftJoinTest() { + joinTest(JoinType.LEFT, "left"); + } + + @Test + public void rightJoinTest() { + joinTest(JoinType.RIGHT, "right"); + } + + @Test + public void innerJoinTest() { + joinTest(JoinType.INNER, "inner"); + } + + @Test + public void fullJoinTest() { + joinTest(JoinType.FULL, "full"); + } } From 48be5b12e8c9195da3f30478b8c571115e456c7c Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Mon, 4 May 2026 12:58:22 +0300 Subject: [PATCH 79/98] Integrated transaction cache class into the client builder --- .../src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java | 1 + 1 file changed, 1 insertion(+) diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java index 19a6d93a..371111d9 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java @@ -27,6 +27,7 @@ private static JSqlClient.Builder buildSqlClient( JSqlClient.newBuilder() .setDialect(new YdbDialect()) .setConnectionManager(new YdbTxConnectionManager(dataSource)) + .setCacheOperator(new UuidTransactionCacheOperator()) )); } From 8434d6b8540184f0b24d143e343e132996ff653d Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Mon, 4 May 2026 14:20:37 +0300 Subject: [PATCH 80/98] Added javadoc comments --- .../ydb/jimmer/dialect/UuidTransactionCacheOperator.java | 3 +++ .../java/ydb/jimmer/dialect/constant/YdbClassMapping.java | 4 ++++ .../main/java/ydb/jimmer/dialect/constant/YdbConst.java | 4 ++++ .../java/ydb/jimmer/dialect/constant/YdbJdbcTypes.java | 4 ++++ .../ydb/jimmer/dialect/scalar/DumbYdbScalarProvider.java | 8 ++++++++ .../jimmer/dialect/transaction/TransactionContext.java | 4 ++++ .../dialect/transaction/YdbTxConnectionManager.java | 4 ++++ .../java/ydb/jimmer/dialect/transaction/YqlClient.java | 5 +++++ 8 files changed, 36 insertions(+) diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/UuidTransactionCacheOperator.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/UuidTransactionCacheOperator.java index 213bb14a..4fdfe2f7 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/UuidTransactionCacheOperator.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/UuidTransactionCacheOperator.java @@ -16,6 +16,9 @@ import java.util.Collections; import java.util.UUID; +/** + * Uses UUID for the ids in the {@link #TABLE_NAME} SQL table. + */ public class UuidTransactionCacheOperator extends TransactionCacheOperator { public static final String TABLE_NAME = "JIMMER_TRANS_CACHE_OPERATOR"; diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/constant/YdbClassMapping.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/constant/YdbClassMapping.java index 0da04d15..2d9a42fb 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/constant/YdbClassMapping.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/constant/YdbClassMapping.java @@ -14,6 +14,10 @@ import java.util.Map; import java.util.UUID; +/** + * Provides mappings from Java classes + * to the YDB and JDBC data types. + */ public final class YdbClassMapping { private YdbClassMapping() {} diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/constant/YdbConst.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/constant/YdbConst.java index 941f7f2b..00774de8 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/constant/YdbConst.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/constant/YdbConst.java @@ -1,5 +1,9 @@ package ydb.jimmer.dialect.constant; +/** + * Contains constants for the SQL types used in the YDB driver. + * The values are taken from /tech/ydb/jdbc/YdbConst.java in the YDB driver. + */ public final class YdbConst { private YdbConst() {} diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/constant/YdbJdbcTypes.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/constant/YdbJdbcTypes.java index 3674fff0..bb593505 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/constant/YdbJdbcTypes.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/constant/YdbJdbcTypes.java @@ -1,5 +1,9 @@ package ydb.jimmer.dialect.constant; +/** + * Contains constants of the SQL types used in the YDB driver. + * The values are taken from /tech/ydb/jdbc/common/YdbTypes.java in the YDB driver. + */ public final class YdbJdbcTypes { private YdbJdbcTypes() {} diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/scalar/DumbYdbScalarProvider.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/scalar/DumbYdbScalarProvider.java index 38ddafa8..a814f8b8 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/scalar/DumbYdbScalarProvider.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/scalar/DumbYdbScalarProvider.java @@ -7,6 +7,14 @@ import java.sql.ResultSet; import java.sql.SQLException; +/** + * Passes the given Java type (scalar) + * as a new Java type (SQL) without any changes. + * This class is used when the given Java type is supported by the JDBC driver, + * but is not supported by Jimmer. + * + * @param the class that needs to pass to the driver without any changes + */ public abstract class DumbYdbScalarProvider extends AbstractScalarProvider { private final Class clazz; diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/TransactionContext.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/TransactionContext.java index de5dfc69..2e14c8da 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/TransactionContext.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/TransactionContext.java @@ -1,5 +1,9 @@ package ydb.jimmer.dialect.transaction; +/** + * This class is used to pass transaction setting + * to the ConnectionManager. + */ public class TransactionContext { private static final ThreadLocal LOCAL_CONTEXT = new ThreadLocal<>(); diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YdbTxConnectionManager.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YdbTxConnectionManager.java index 51245225..90576720 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YdbTxConnectionManager.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YdbTxConnectionManager.java @@ -6,6 +6,10 @@ import java.sql.Connection; import java.sql.SQLException; +/** + * Sets transaction isolation level and read only mode + * to the connection at the start of a transaction. + */ public class YdbTxConnectionManager extends AbstractTxConnectionManager { private final DataSource dataSource; diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YqlClient.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YqlClient.java index 61b3052c..0193f472 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YqlClient.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YqlClient.java @@ -1,5 +1,6 @@ package ydb.jimmer.dialect.transaction; +import org.babyfish.jimmer.sql.JSqlClient; import org.babyfish.jimmer.sql.di.AbstractJSqlClientDelegate; import org.babyfish.jimmer.sql.runtime.JSqlClientImplementor; import ydb.jimmer.dialect.constant.YdbConst; @@ -7,6 +8,10 @@ import java.sql.Connection; import java.util.function.Supplier; +/** + * Provides methods for setting transaction isolation level + * to the {@link JSqlClient}. + */ public class YqlClient extends AbstractJSqlClientDelegate { private final JSqlClientImplementor delegate; From 827cf67c0b7b3856bd30ee9b211956d10b91b0eb Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Mon, 4 May 2026 14:31:26 +0300 Subject: [PATCH 81/98] Extracted types used in handleDateTime in select test to a new test --- .../dataTypeTest/SelectDataTypeTest.java | 80 +++++++++++-------- 1 file changed, 46 insertions(+), 34 deletions(-) diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java index 725eb849..63e62097 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/dataTypeTest/SelectDataTypeTest.java @@ -35,6 +35,8 @@ import ydb.jimmer.dialect.model.type.ydbUtf8.YdbStringTable; import ydb.jimmer.dialect.model.type.ydbUuid.YdbUuidTable; +import java.time.ZoneId; + public class SelectDataTypeTest extends AbstractSelectTest { private void typeTest(String tableName, String typeName, @@ -74,6 +76,48 @@ private void typeTest(String tableName, dropTable(tableName); } + /** + * {@link org.babyfish.jimmer.sql.ast.impl.Variables#handleDateTime(Object, ZoneId) handleDateTime(Object, ZoneId)} + * this Jimmer method is responsible for changing java types without any user input + */ + @Test + public void handleDateTimeJimmerTest() { + String[] values = new String[]{"Timestamp64(\"2017-11-27T13:24:00.123456Z\")"}; + String[] expectedValues = new String[]{"\"2017-11-27T13:24:00.123456Z\""}; + + typeTest("ydb_instant", "Timestamp64", + YdbInstantTable.$, YdbInstantTable.$.value(), + values, expectedValues); + + values = new String[]{"DateTime64(\"2017-11-27T13:24:00Z\")"}; + expectedValues = new String[]{"\"2017-11-27T13:24:00\""}; + + typeTest("ydb_local_date_time", "DateTime64", + YdbLocalDateTimeTable.$, YdbLocalDateTimeTable.$.value(), + values, expectedValues); + + values = new String[]{"Date32(\"144169-01-01\")"}; + expectedValues = new String[]{"\"+144169-01-01\""}; + + typeTest("ydb_local_date", "Date32", + YdbLocalDateTable.$, YdbLocalDateTable.$.value(), + values, expectedValues); + + values = new String[]{"-1", "0", "10"}; + expectedValues = new String[]{"\"02:59:59.999\"", "\"03:00:00\"", "\"03:00:00.01\""}; + + typeTest("ydb_local_time", "Int32", + YdbLocalTimeTable.$, YdbLocalTimeTable.$.value(), + values, expectedValues); + + values = new String[]{"Timestamp64(\"2017-11-27T13:24:00.123456Z\")"}; + expectedValues = new String[]{"\"2017-11-27\""}; + + typeTest("ydb_util_date", "Timestamp64", + YdbUtilDateTable.$, YdbUtilDateTable.$.value(), + values, expectedValues); + } + @Test public void boolTest() { String[] values = new String[]{"false", "true"}; @@ -95,22 +139,6 @@ public void date32Test() { typeTest("ydb_date", "Date32", YdbDateTable.$, YdbDateTable.$.value(), values, expectedValues); - - expectedValues = new String[]{"\"+144169-01-01\""}; - - typeTest("ydb_local_date", "Date32", - YdbLocalDateTable.$, YdbLocalDateTable.$.value(), - values, expectedValues); - } - - @Test - public void dateTime64Test() { - String[] values = new String[]{"DateTime64(\"2017-11-27T13:24:00Z\")"}; - String[] expectedValues = new String[]{"\"2017-11-27T13:24:00\""}; - - typeTest("ydb_local_date_time", "DateTime64", - YdbLocalDateTimeTable.$, YdbLocalDateTimeTable.$.value(), - values, expectedValues); } @Test @@ -198,14 +226,8 @@ public void int32Test() { YdbIntegerTable.$, YdbIntegerTable.$.value(), values); - String[] expectedValues = new String[]{"\"02:59:59.999\"", "\"03:00:00\"", "\"03:00:00.01\""}; - - typeTest("ydb_local_time", "Int32", - YdbLocalTimeTable.$, YdbLocalTimeTable.$.value(), - values, expectedValues); - values = new String[]{"0", "10"}; - expectedValues = new String[]{"\"00:00:00\"", "\"00:00:10\""}; + String[] expectedValues = new String[]{"\"00:00:00\"", "\"00:00:10\""}; typeTest("ydb_time", "Int32", YdbTimeTable.$, YdbTimeTable.$.value(), @@ -262,21 +284,11 @@ public void stringTest() { @Test public void timestamp64Test() { String[] values = new String[]{"Timestamp64(\"2017-11-27T13:24:00.123456Z\")"}; - String[] expectedValues = new String[]{"\"2017-11-27T13:24:00.123456Z\""}; - - typeTest("ydb_instant", "Timestamp64", - YdbInstantTable.$, YdbInstantTable.$.value(), - values, expectedValues); - - expectedValues = new String[]{"\"2017-11-27\""}; + String[] expectedValues = new String[]{"\"2017-11-27\""}; typeTest("ydb_timestamp", "Timestamp64", YdbTimestampTable.$, YdbTimestampTable.$.value(), values, expectedValues); - - typeTest("ydb_util_date", "Timestamp64", - YdbUtilDateTable.$, YdbUtilDateTable.$.value(), - values, expectedValues); } @Test From ee19b1adba06ac6ab18a257016fbace667d815b1 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Mon, 11 May 2026 01:58:56 +0300 Subject: [PATCH 82/98] Added a new Executor to fix the return for UPDATE --- .../java/ydb/jimmer/dialect/YdbExecutor.java | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 jimmer-dialect/src/main/java/ydb/jimmer/dialect/YdbExecutor.java diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YdbExecutor.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YdbExecutor.java new file mode 100644 index 00000000..2d6e37c9 --- /dev/null +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YdbExecutor.java @@ -0,0 +1,78 @@ +package ydb.jimmer.dialect; + +import org.babyfish.jimmer.sql.runtime.AbstractExecutorProxy; +import org.babyfish.jimmer.sql.runtime.ExecutionPurpose; +import org.babyfish.jimmer.sql.runtime.Executor; +import org.babyfish.jimmer.sql.runtime.SqlFunction; +import org.jetbrains.annotations.NotNull; + +import java.lang.reflect.Proxy; +import java.sql.PreparedStatement; +import java.sql.ResultSet; + +/** + * Takes the ResultSet returned by the "UPDATE" operator with "RETURNING" + * and returns the row count of the affected rows. + * By default, Jimmer does not support ResultSet for "UPDATE". + */ +public class YdbExecutor extends AbstractExecutorProxy { + public YdbExecutor(Executor raw) { + super(raw); + } + + @Override + public R execute(@NotNull Args args) { + if (args.purpose != ExecutionPurpose.MUTATE) { + return raw.execute(args); + } + + SqlFunction originalBlock = args.block; + Args newArgs = new Args<>( + args.sqlClient, + args.con, + args.sql, + args.variables, + args.variablePositions, + args.purpose, + args.getExceptionTranslator(), + args.statementFactory, + (stmt, a) -> originalBlock.apply(wrapStatement(stmt), a) + ); + return raw.execute(newArgs); + } + + private PreparedStatement wrapStatement(PreparedStatement stmt) { + return (PreparedStatement) Proxy.newProxyInstance( + stmt.getClass().getClassLoader(), + new Class[]{PreparedStatement.class}, + (proxy, method, methodArgs) -> { + if ("executeUpdate".equals(method.getName()) && (methodArgs == null || methodArgs.length == 0)) { + boolean hasResultSet = stmt.execute(); + if (hasResultSet) { + try (ResultSet rs = stmt.getResultSet()) { + int count = 0; + while (rs.next()) { + count++; + } + return count; + } + } + + return Math.max(stmt.getUpdateCount(), 0); + } + + return method.invoke(stmt, methodArgs); + } + ); + } + + @Override + protected AbstractExecutorProxy recreate(Executor raw) { + return new YdbExecutor(raw); + } + + @Override + protected Batch createBatch(BatchContext raw) { + return new AbstractExecutorProxy.Batch(raw) {}; + } +} From 1433ac061639ab4755a5b9c389c8bee085f2d635 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Mon, 11 May 2026 13:24:46 +0300 Subject: [PATCH 83/98] Added a test for optimistic locking using versioning --- .../java/ydb/jimmer/dialect/AbstractTest.java | 7 +- .../dialect/model/versioning/BookStore.java | 26 +++++++ .../sqlMonitor/BatchExecutorMonitor.java | 70 ------------------- .../dialect/sqlMonitor/ExecutorMonitor.java | 51 -------------- .../sqlMonitor/YdbExecutorMonitor.java | 68 ++++++++++++++++++ .../dialect/versioning/InsertVersionTest.java | 40 +++++++++++ 6 files changed, 139 insertions(+), 123 deletions(-) create mode 100644 jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/versioning/BookStore.java delete mode 100644 jimmer-dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/BatchExecutorMonitor.java delete mode 100644 jimmer-dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorMonitor.java create mode 100644 jimmer-dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/YdbExecutorMonitor.java create mode 100644 jimmer-dialect/src/test/java/ydb/jimmer/dialect/versioning/InsertVersionTest.java diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java index 44cb93e0..563de108 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java @@ -1,6 +1,7 @@ package ydb.jimmer.dialect; import org.babyfish.jimmer.sql.JSqlClient; +import org.babyfish.jimmer.sql.runtime.DefaultExecutor; import org.babyfish.jimmer.sql.runtime.JSqlClientImplementor; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.extension.RegisterExtension; @@ -11,7 +12,7 @@ import org.springframework.jdbc.datasource.init.ScriptUtils; import tech.ydb.test.junit5.YdbHelperExtension; import ydb.jimmer.dialect.scalar.DurationProvider; -import ydb.jimmer.dialect.sqlMonitor.ExecutorMonitor; +import ydb.jimmer.dialect.sqlMonitor.YdbExecutorMonitor; import ydb.jimmer.dialect.transaction.YqlClient; import ydb.jimmer.dialect.transaction.YdbTxConnectionManager; @@ -26,7 +27,9 @@ public abstract class AbstractTest { @RegisterExtension private static final YdbHelperExtension ydb = new YdbHelperExtension(); - protected static final ExecutorMonitor executor = new ExecutorMonitor(); + protected static final YdbExecutorMonitor executor = new YdbExecutorMonitor( + new YdbExecutor(DefaultExecutor.INSTANCE) + ); private static final JSqlClient yqlClient; private static final JSqlClient yqlClientForBatch; diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/versioning/BookStore.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/versioning/BookStore.java new file mode 100644 index 00000000..081ceda8 --- /dev/null +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/model/versioning/BookStore.java @@ -0,0 +1,26 @@ +package ydb.jimmer.dialect.model.versioning; + +import org.babyfish.jimmer.sql.Column; +import org.babyfish.jimmer.sql.Entity; +import org.babyfish.jimmer.sql.Id; +import org.babyfish.jimmer.sql.Key; +import org.babyfish.jimmer.sql.KeyUniqueConstraint; +import org.babyfish.jimmer.sql.Table; +import org.babyfish.jimmer.sql.Version; + +@Entity +//@KeyUniqueConstraint +@Table(name = "version_table") +public interface BookStore { + @Id + @Column(name = "id") + int id(); + +// @Key +// @Column(name = "name") +// String name(); + + @Version + @Column(name = "value") + int value(); +} diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/BatchExecutorMonitor.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/BatchExecutorMonitor.java deleted file mode 100644 index 1517a5e1..00000000 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/BatchExecutorMonitor.java +++ /dev/null @@ -1,70 +0,0 @@ -package ydb.jimmer.dialect.sqlMonitor; - -import org.babyfish.jimmer.sql.runtime.ExceptionTranslator; -import org.babyfish.jimmer.sql.runtime.ExecutionPurpose; -import org.babyfish.jimmer.sql.runtime.Executor; -import org.babyfish.jimmer.sql.runtime.ExecutorContext; -import org.babyfish.jimmer.sql.runtime.JSqlClientImplementor; - -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; -import java.util.function.BiFunction; - -public class BatchExecutorMonitor implements Executor.BatchContext { - private final List queryLogs; - private final Executor.BatchContext raw; - private final List> variablesList = new ArrayList<>(); - - public BatchExecutorMonitor(List queryLogs, Executor.BatchContext raw) { - this.queryLogs = queryLogs; - this.raw = raw; - } - - @Override - public JSqlClientImplementor sqlClient() { - return raw.sqlClient(); - } - - @Override - public String sql() { - return raw.sql(); - } - - @Override - public ExecutionPurpose purpose() { - return raw.purpose(); - } - - @Override - public ExecutorContext ctx() { - return raw.ctx(); - } - - @Override - public void add(List variables) { - raw.add(variables); - variablesList.add(variables); - } - - @Override - public int[] execute(BiFunction exceptionTranslator) { - queryLogs.add(new QueryLog(raw.sql(), raw.purpose(), variablesList)); - return raw.execute(exceptionTranslator); - } - - @Override - public Object[] generatedIds() { - return raw.generatedIds(); - } - - @Override - public void addExecutedListener(Runnable listener) { - raw.addExecutedListener(listener); - } - - @Override - public void close() { - raw.close(); - } -} diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorMonitor.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorMonitor.java deleted file mode 100644 index 32f37eb4..00000000 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/ExecutorMonitor.java +++ /dev/null @@ -1,51 +0,0 @@ -package ydb.jimmer.dialect.sqlMonitor; - -import org.babyfish.jimmer.meta.ImmutableProp; -import org.babyfish.jimmer.sql.runtime.DefaultExecutor; -import org.babyfish.jimmer.sql.runtime.ExecutionPurpose; -import org.babyfish.jimmer.sql.runtime.Executor; -import org.babyfish.jimmer.sql.runtime.JSqlClientImplementor; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.sql.Connection; -import java.util.ArrayList; -import java.util.List; - -public class ExecutorMonitor implements Executor { - private final Executor executor = DefaultExecutor.INSTANCE; - - private List queryLogs = new ArrayList<>(); - - @Override - public R execute(@NotNull Args args) { - queryLogs.add(QueryLog.simple(args.sql, args.purpose, args.variables)); - return executor.execute(args); - } - - @Override - public BatchContext executeBatch( - @NotNull Connection con, - @NotNull String sql, - @Nullable ImmutableProp generatedIdProp, - @NotNull ExecutionPurpose purpose, - @NotNull JSqlClientImplementor sqlClient - ) { - return new BatchExecutorMonitor( - queryLogs, - DefaultExecutor.INSTANCE.executeBatch( - con, - sql, - generatedIdProp, - purpose, - sqlClient - ) - ); - } - - public List getLogs() { - List tmp = queryLogs; - queryLogs = new ArrayList<>(); - return tmp; - } -} diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/YdbExecutorMonitor.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/YdbExecutorMonitor.java new file mode 100644 index 00000000..70cfa91d --- /dev/null +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/sqlMonitor/YdbExecutorMonitor.java @@ -0,0 +1,68 @@ +package ydb.jimmer.dialect.sqlMonitor; + +import org.babyfish.jimmer.sql.runtime.AbstractExecutorProxy; +import org.babyfish.jimmer.sql.runtime.ExceptionTranslator; +import org.babyfish.jimmer.sql.runtime.Executor; +import org.jetbrains.annotations.NotNull; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.function.BiFunction; + +public class YdbExecutorMonitor extends AbstractExecutorProxy { + private List queryLogs = new ArrayList<>(); + + public YdbExecutorMonitor(Executor raw) { + super(raw); + } + + public YdbExecutorMonitor(Executor raw, List queryLogs) { + super(raw); + this.queryLogs = queryLogs; + } + + public List getLogs() { + List tmp = queryLogs; + queryLogs = new ArrayList<>(); + return tmp; + } + + @Override + public R execute(@NotNull Args args) { + queryLogs.add(QueryLog.simple(args.sql, args.purpose, args.variables)); + return raw.execute(args); + } + + @Override + protected AbstractExecutorProxy recreate(Executor raw) { + return new YdbExecutorMonitor(raw, queryLogs); + } + + @Override + protected Batch createBatch(BatchContext raw) { + return new YdbBatch(raw, queryLogs); + } + + private static class YdbBatch extends AbstractExecutorProxy.Batch { + private final List queryLogs; + private final List> variablesList = new ArrayList<>(); + + protected YdbBatch(BatchContext raw, List queryLogs) { + super(raw); + this.queryLogs = queryLogs; + } + + @Override + public void add(List variables) { + raw.add(variables); + variablesList.add(variables); + } + + @Override + public int[] execute(BiFunction exceptionTranslator) { + queryLogs.add(new QueryLog(raw.sql(), raw.purpose(), variablesList)); + return raw.execute(exceptionTranslator); + } + } +} diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/versioning/InsertVersionTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/versioning/InsertVersionTest.java new file mode 100644 index 00000000..fc3d7070 --- /dev/null +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/versioning/InsertVersionTest.java @@ -0,0 +1,40 @@ +package ydb.jimmer.dialect.versioning; + +import org.babyfish.jimmer.sql.ast.mutation.SaveMode; +import org.junit.jupiter.api.Test; +import ydb.jimmer.dialect.AbstractInsertTest; +import ydb.jimmer.dialect.model.versioning.BookStoreDraft; + +public class InsertVersionTest extends AbstractInsertTest { + private static final String TABLE_NAME = "version_table"; + private static final String TYPE_NAME = "Int32"; + + @Test + public void simpleTest() { + createTable(TABLE_NAME, TYPE_NAME); + + getIsolationClient().getEntities().saveCommand( + BookStoreDraft.$.produce(version -> + version.setId(0).setValue(0) + ) + ).setMode(SaveMode.INSERT_ONLY).execute(); + + executeAndExpect( + getYqlClient().getEntities().saveCommand( + BookStoreDraft.$.produce(version -> + version.setId(0).setValue(2) + ) + ).setMode(SaveMode.UPDATE_ONLY), + ctx -> { + ctx.nextStatement(); + ctx.sql("UPDATE " + TABLE_NAME + " set value = value + 1 where id = ? and value = ? returning id"); + ctx.error("Save error caused by the path: \"\": " + + "Cannot update the entity whose type is " + + "\"ydb.jimmer.dialect.model.versioning.BookStore\" " + + "and id is \"0\" because of optimistic lock error"); + } + ); + + dropTable(TABLE_NAME); + } +} From 1589b133ac1468a9b6db205426efb6af2b97c096 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Mon, 11 May 2026 13:25:09 +0300 Subject: [PATCH 84/98] Added the new executor to the YqlClientBuilder --- .../src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java index 371111d9..75a04929 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YqlClientBuilder.java @@ -1,6 +1,7 @@ package ydb.jimmer.dialect; import org.babyfish.jimmer.sql.JSqlClient; +import org.babyfish.jimmer.sql.runtime.DefaultExecutor; import org.babyfish.jimmer.sql.runtime.JSqlClientImplementor; import ydb.jimmer.dialect.scalar.DurationProvider; import ydb.jimmer.dialect.transaction.YqlClient; @@ -28,6 +29,7 @@ private static JSqlClient.Builder buildSqlClient( .setDialect(new YdbDialect()) .setConnectionManager(new YdbTxConnectionManager(dataSource)) .setCacheOperator(new UuidTransactionCacheOperator()) + .setExecutor(new YdbExecutor(DefaultExecutor.INSTANCE)) )); } From 38e6d0db98cb0edd63cbfab694d6e0c7703d45c8 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Tue, 12 May 2026 02:45:14 +0300 Subject: [PATCH 85/98] Removed "--restart=always and --rm" conflict Removed "--rm" to mirror the docker-compose.yml file --- jimmer-dialect/src/test/resources/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jimmer-dialect/src/test/resources/install.sh b/jimmer-dialect/src/test/resources/install.sh index 7e4946d5..7ffa300d 100644 --- a/jimmer-dialect/src/test/resources/install.sh +++ b/jimmer-dialect/src/test/resources/install.sh @@ -1,6 +1,6 @@ docker run \ --restart=always \ - -d --rm \ + -d \ --name jimmer_test_ydb \ -h localhost \ --platform linux/amd64 \ From 2c30093cef24a6f2f29ddb27bf46099287de3548 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Tue, 12 May 2026 14:51:18 +0300 Subject: [PATCH 86/98] Added .setDialect(new YdbDialect()) to getIsolationClient() and fixed the con.setSavepoint() problem YDB JDBC driver doesn't support con.setSavepoint(). That's why isTransactionAbortedByError() in dialect was removed (it now returns false and doen't trigger setSavepoint()) --- .../src/main/java/ydb/jimmer/dialect/YdbDialect.java | 5 ----- .../src/test/java/ydb/jimmer/dialect/AbstractTest.java | 1 + 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java index a682c26c..f7a91fa7 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/YdbDialect.java @@ -82,11 +82,6 @@ public boolean isUpsertWithNullableKeySupported() { return true; } - @Override - public boolean isTransactionAbortedByError() { - return true; - } - @Override public void update(UpdateContext ctx) { ctx.sql("UPDATE ") diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java index 563de108..4a3737c8 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractTest.java @@ -61,6 +61,7 @@ protected static YqlClient getIsolationClient() { return new YqlClient( (JSqlClientImplementor) JSqlClient.newBuilder() .setConnectionManager(new YdbTxConnectionManager(dataSource)) + .setDialect(new YdbDialect()) .setExecutor(executor) .build()); } From e8c61e375c011c0dc9b544a2d9569d445930b643 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Tue, 12 May 2026 16:05:18 +0300 Subject: [PATCH 87/98] Made the maps in YdbClassMapping unmodifiable --- .../jimmer/dialect/constant/YdbClassMapping.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/constant/YdbClassMapping.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/constant/YdbClassMapping.java index 2d9a42fb..efa7126a 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/constant/YdbClassMapping.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/constant/YdbClassMapping.java @@ -21,8 +21,11 @@ public final class YdbClassMapping { private YdbClassMapping() {} - public static final Map, String> classToYdbType = new HashMap<>(); - public static final Map, Integer> classToJdbcType = new HashMap<>(); + public static final Map, String> classToYdbType; + public static final Map, Integer> classToJdbcType; + + private static final Map, String> classToYdbTypeBuilder = new HashMap<>(); + private static final Map, Integer> classToJdbcTypeBuilder = new HashMap<>(); static { add("Bool", YdbJdbcTypes.BOOL, boolean.class, Boolean.class); @@ -45,12 +48,15 @@ private YdbClassMapping() {} add("Datetime64", YdbJdbcTypes.DATETIME64, LocalDateTime.class); add("Timestamp64", YdbJdbcTypes.TIMESTAMP64, java.util.Date.class, Timestamp.class, Instant.class); add("Interval64", YdbJdbcTypes.INTERVAL64, Duration.class); + + classToYdbType = Map.copyOf(classToYdbTypeBuilder); + classToJdbcType = Map.copyOf(classToJdbcTypeBuilder); } private static void add(String ydbType, int jdbcType, Class... classes) { for (Class clazz : classes) { - classToYdbType.put(clazz, ydbType); - classToJdbcType.put(clazz, jdbcType); + classToYdbTypeBuilder.put(clazz, ydbType); + classToJdbcTypeBuilder.put(clazz, jdbcType); } } } From 358b75de00af0795a354f96b0fd640f599cfc762 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Tue, 12 May 2026 16:35:49 +0300 Subject: [PATCH 88/98] changed "compile" to "test" for liquibase-core in XML --- jimmer-dialect/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jimmer-dialect/pom.xml b/jimmer-dialect/pom.xml index 04bb4434..b5382607 100644 --- a/jimmer-dialect/pom.xml +++ b/jimmer-dialect/pom.xml @@ -75,7 +75,7 @@ org.liquibase liquibase-core 5.0.1 - compile + test From 7a878113674ad8425a848ebc10192c97363c4014 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Wed, 13 May 2026 02:30:45 +0300 Subject: [PATCH 89/98] delete calls are now separated into groups by batchSize Previously, only select calls were using the variable batchSize. Delete operators are now separated into groups to prevent memory pressure and to not exceed YDB's batch statement limits. --- .../dialect/UuidTransactionCacheOperator.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/UuidTransactionCacheOperator.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/UuidTransactionCacheOperator.java index 4fdfe2f7..b91918eb 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/UuidTransactionCacheOperator.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/UuidTransactionCacheOperator.java @@ -48,6 +48,8 @@ public class UuidTransactionCacheOperator extends TransactionCacheOperator { private final ObjectMapper mapper; + private final int batchSize; + public UuidTransactionCacheOperator() { this(null, 32); } @@ -71,6 +73,7 @@ public UuidTransactionCacheOperator(ObjectMapper mapper, int batchSize) { new ObjectMapper() .registerModule(new JavaTimeModule()) .registerModule(new ImmutableModule()); + this.batchSize = batchSize; } @Override @@ -105,6 +108,7 @@ private void save( sqlClient().getConnectionManager().execute(con -> { try { try (PreparedStatement stmt = con.prepareStatement(INSERT_WITH_UUID)) { + int count = 0; for (Object key : keys) { stmt.setString(1, UUID.randomUUID().toString()); stmt.setString(2, type != null ? type.toString() : null); @@ -112,8 +116,15 @@ private void save( stmt.setString(4, mapper.writeValueAsString(key)); stmt.setString(5, reason); stmt.addBatch(); + + if (++count % batchSize == 0) { + stmt.executeBatch(); + } + } + + if (count % batchSize != 0) { + stmt.executeBatch(); } - stmt.executeBatch(); } } catch (SQLException | JsonProcessingException ex) { throw new ExecutionException("Failed to save delayed cache deletion", ex); From b3fbcc4798d2432408d1f2c5cf33798e181f3c0b Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Wed, 13 May 2026 13:36:24 +0300 Subject: [PATCH 90/98] Fixed the problem where rollback() was useless in tests --- .../src/test/java/ydb/jimmer/dialect/AbstractInsertTest.java | 1 + .../src/test/java/ydb/jimmer/dialect/AbstractSelectTest.java | 1 + 2 files changed, 2 insertions(+) diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractInsertTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractInsertTest.java index 678c0436..bbae2c97 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractInsertTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractInsertTest.java @@ -14,6 +14,7 @@ protected void executeAndExpect(Executable query, Cons MutationResult result = null; Throwable throwable = null; try (Connection connection = DriverManager.getConnection(getJdbcURL())) { + connection.setAutoCommit(false); try { result = query.execute(connection); } catch (Throwable ex) { diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractSelectTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractSelectTest.java index 8a669227..849a0c33 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractSelectTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/AbstractSelectTest.java @@ -13,6 +13,7 @@ public abstract class AbstractSelectTest extends AbstractTest { protected static void executeAndExpect(Executable> query, Consumer block) { List rows = null; try (Connection connection = DriverManager.getConnection(getJdbcURL())) { + connection.setAutoCommit(false); try { rows = query.execute(connection); } finally { From d9d8208d81a4c6d076f42f04fe19b5b293b61483 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Fri, 15 May 2026 15:01:48 +0300 Subject: [PATCH 91/98] Combined propagation, isolation level and retries into 1 ConnectionManager --- .../dialect/RetryConnectionManager.java | 97 -------- .../transaction/YdbTxConnectionManager.java | 217 +++++++++++++++++- 2 files changed, 212 insertions(+), 102 deletions(-) delete mode 100644 jimmer-dialect/src/main/java/ydb/jimmer/dialect/RetryConnectionManager.java diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/RetryConnectionManager.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/RetryConnectionManager.java deleted file mode 100644 index 27a49e29..00000000 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/RetryConnectionManager.java +++ /dev/null @@ -1,97 +0,0 @@ -package ydb.jimmer.dialect; - -import org.babyfish.jimmer.sql.transaction.Propagation; -import org.babyfish.jimmer.sql.transaction.TxConnectionManager; -import org.jetbrains.annotations.Nullable; - -import javax.sql.DataSource; -import java.sql.Connection; -import java.sql.SQLException; -import java.sql.SQLTimeoutException; -import java.util.function.Function; - -/** - * Provides retry from abort/timeout for transactions. - * While using frameworks like spring this class is redundant. - * With spring the "@Retryable" annotation is preferable. - */ -public class RetryConnectionManager implements TxConnectionManager { - private final DataSource dataSource; - private final int maxRetries; - private final long retryDelayMs; - - public RetryConnectionManager(DataSource dataSource, int maxRetries, long retryDelayMs) { - this.dataSource = dataSource; - this.maxRetries = maxRetries; - this.retryDelayMs = retryDelayMs; - } - - @Override - public R executeTransaction(Propagation propagation, Function block) { - for (int i = 0; i < maxRetries; i++) { - try (Connection connection = dataSource.getConnection()) { - try { - connection.setAutoCommit(false); - R result = block.apply(connection); - connection.commit(); - return result; - } catch (SQLException ex) { - connection.rollback(); - if (i == maxRetries - 1 || !isRetryable(ex)) { - throw new RuntimeException(ex); - } - } - } catch (SQLException ex) { - if (i == maxRetries - 1 || !isRetryable(ex)) { - throw new RuntimeException(ex); - } - } - try { - Thread.sleep(retryDelayMs); - } catch (InterruptedException ie) { - Thread.currentThread().interrupt(); - throw new RuntimeException(ie); - } - } - - throw new RuntimeException("Max retries exceeded"); - } - - @Override - public R execute(@Nullable Connection con, Function block) { - if (con != null) { - return block.apply(con); - } - - for (int i = 0; i < maxRetries; i++) { - try (Connection connection = dataSource.getConnection()) { - return block.apply(connection); - } catch (SQLException ex) { - if (i == maxRetries - 1 || !isRetryable(ex)) { - throw new RuntimeException(ex); - } - try { - Thread.sleep(retryDelayMs); - } catch (InterruptedException ie) { - Thread.currentThread().interrupt(); - throw new RuntimeException(ie); - } - } - } - - throw new RuntimeException("Max retries exceeded"); - } - - private boolean isRetryable(Exception ex) { - return ex instanceof SQLTimeoutException || - (ex instanceof SQLException && isRetryableSqlState((SQLException) ex)); - } - - private boolean isRetryableSqlState(SQLException ex) { - String sqlState = ex.getSQLState(); - return sqlState != null && ( - sqlState.startsWith("40") || // Transaction rollback - "08S01".equals(sqlState) // Communication link failure - ); - } -} diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YdbTxConnectionManager.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YdbTxConnectionManager.java index 90576720..852dc4a2 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YdbTxConnectionManager.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YdbTxConnectionManager.java @@ -1,30 +1,132 @@ package ydb.jimmer.dialect.transaction; +import org.babyfish.jimmer.sql.exception.ExecutionException; import org.babyfish.jimmer.sql.transaction.AbstractTxConnectionManager; +import org.babyfish.jimmer.sql.transaction.Propagation; +import org.babyfish.jimmer.sql.transaction.TxConnectionManager; +import org.jetbrains.annotations.Nullable; import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; +import java.sql.SQLTimeoutException; +import java.util.function.Function; /** - * Sets transaction isolation level and read only mode - * to the connection at the start of a transaction. + * Provides propagation, isolation level, read only mode + * and retry from abort/timeout for transactions. + * This class is a modified version of {@link AbstractTxConnectionManager}. */ -public class YdbTxConnectionManager extends AbstractTxConnectionManager { +public class YdbTxConnectionManager implements TxConnectionManager { private final DataSource dataSource; + private final ThreadLocal scopeLocal = new ThreadLocal<>(); + + private final int maxAttempts; + private final long retryDelayMs; public YdbTxConnectionManager(DataSource dataSource) { this.dataSource = dataSource; + this.maxAttempts = 1; + this.retryDelayMs = 0; + } + + public YdbTxConnectionManager(DataSource dataSource, int maxAttempts, long retryDelayMs) { + this.dataSource = dataSource; + this.maxAttempts = maxAttempts; + this.retryDelayMs = retryDelayMs; + } + + @Override + public final R execute(@Nullable Connection con, Function block) { + if (con != null) { + return block.apply(con); + } + return execute(block); + } + + @Override + public final R execute(Function block) { + return executeTransaction(Propagation.SUPPORTS, block); + } + + @Override + public final R executeTransaction(Function block) { + Propagation propagation = Propagation.REQUIRED; + if (maxAttempts > 1) { + propagation = Propagation.REQUIRES_NEW; + } + return executeTransaction(propagation, block); } @Override + public final R executeTransaction(Propagation propagation, Function block) { + int maxAttempts = this.maxAttempts; + if (maxAttempts > 1 && propagation != Propagation.REQUIRES_NEW) { + maxAttempts = 1; + } + + for (int i = 0; i < maxAttempts; i++) { + try { + Scope parent = scopeLocal.get(); + Scope scope = createScope(parent, propagation); + scopeLocal.set(scope); + try { + R result; + try { + result = execute(scope.con, block); + } catch (RuntimeException | Error ex) { + scope.terminate(true); + throw ex; + } + scope.terminate(false); + return result; + } finally { + if (parent != null) { + scopeLocal.set(parent); + } else { + scopeLocal.remove(); + } + } + } catch (SQLException | RuntimeException ex) { + if (i == maxAttempts - 1 || !isRetryable(ex)) { + throw (ex instanceof RuntimeException re) ? re : new RuntimeException(ex); + } + } + + try { + Thread.sleep(retryDelayMs); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + throw new RuntimeException(ex); + } + } + + throw new RuntimeException("Max attempts exceeded"); + } + + private boolean isRetryable(Exception ex) { + return ex instanceof SQLTimeoutException || + (ex instanceof SQLException && isRetryableSqlState((SQLException) ex)); + } + + private boolean isRetryableSqlState(SQLException ex) { + String sqlState = ex.getSQLState(); + return sqlState != null && ( + sqlState.startsWith("40") || // Transaction rollback + "08S01".equals(sqlState) // Communication link failure + ); + } + protected Connection openConnection() throws SQLException { return dataSource.getConnection(); } - @Override + protected void closeConnection(Connection con) throws SQLException { + con.close(); + } + protected void startTransaction(Connection con) throws SQLException { - super.startTransaction(con); + con.setAutoCommit(false); TransactionContext.TransactionSettings settings = TransactionContext.getSettings(); if (settings != null) { @@ -34,4 +136,109 @@ protected void startTransaction(Connection con) throws SQLException { con.setReadOnly(settings.readOnly); } } + + protected void commitTransaction(Connection con) throws SQLException { + con.commit(); + } + + protected void rollbackTransaction(Connection con) throws SQLException { + con.rollback(); + } + + protected void abortTransaction(Connection con) throws SQLException { + con.setAutoCommit(true); + } + + private Scope createScope(Scope parent, Propagation propagation) throws SQLException { + return switch (propagation) { + case REQUIRES_NEW -> new Scope(parent, false, true); + case SUPPORTS -> new Scope(parent, true, parent != null && parent.withTransaction); + case NOT_SUPPORTED -> new Scope(parent, true, false); + case MANDATORY -> { + if (parent == null || !parent.withTransaction) { + throw new ExecutionException( + "The transaction propagation is \"MANDATORY\" but there is no transaction context" + ); + } + yield new Scope(parent, true, true); + } + case NEVER -> { + if (parent != null && parent.withTransaction) { + throw new ExecutionException( + "The transaction propagation is \"NEVER\" but there is already a transaction context" + ); + } + yield new Scope(parent, true, false); + } + default -> // REQUIRED + new Scope(parent, true, true); + }; + } + + private class Scope { + private final Connection con; + + private final boolean withTransaction; + private final boolean connectionOwner; + private final boolean transactionOwner; + + Scope(Scope parent, boolean borrowConnection, boolean withTransaction) throws SQLException { + if (parent != null && parent.withTransaction && !withTransaction) { + borrowConnection = false; + } + + Connection con; + if (parent != null && borrowConnection) { + con = parent.con; + this.connectionOwner = false; + } else { + con = openConnection(); + this.connectionOwner = true; + } + + this.withTransaction = withTransaction; + if (!withTransaction) { + transactionOwner = false; + } else if (connectionOwner) { + transactionOwner = true; + } else { + transactionOwner = !parent.withTransaction; + } + + if (transactionOwner) { + try { + startTransaction(con); + } catch (SQLException | RuntimeException | Error ex) { + closeConnection(con); + this.con = null; + throw ex; + } + } + this.con = con; + } + + void terminate(boolean error) throws SQLException { + Connection con = this.con; + if (con == null) { + return; + } + + try { + if (transactionOwner) { + if (error) { + rollbackTransaction(con); + } else { + commitTransaction(con); + } + if (!connectionOwner) { + abortTransaction(con); + } + } + } finally { + if (connectionOwner) { + closeConnection(con); + } + } + } + } } From 8911923f9cbd8a75d8f429d92af2932821b4cf5d Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Fri, 15 May 2026 17:45:18 +0300 Subject: [PATCH 92/98] Created a method in the Client class for the user to access retry functionality in the ConnectionManager --- .../transaction/YdbTxConnectionManager.java | 33 ++++++++----------- .../jimmer/dialect/transaction/YqlClient.java | 11 +++++++ 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YdbTxConnectionManager.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YdbTxConnectionManager.java index 852dc4a2..bc558ab0 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YdbTxConnectionManager.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YdbTxConnectionManager.java @@ -21,19 +21,8 @@ public class YdbTxConnectionManager implements TxConnectionManager { private final DataSource dataSource; private final ThreadLocal scopeLocal = new ThreadLocal<>(); - private final int maxAttempts; - private final long retryDelayMs; - public YdbTxConnectionManager(DataSource dataSource) { this.dataSource = dataSource; - this.maxAttempts = 1; - this.retryDelayMs = 0; - } - - public YdbTxConnectionManager(DataSource dataSource, int maxAttempts, long retryDelayMs) { - this.dataSource = dataSource; - this.maxAttempts = maxAttempts; - this.retryDelayMs = retryDelayMs; } @Override @@ -51,20 +40,24 @@ public final R execute(Function block) { @Override public final R executeTransaction(Function block) { - Propagation propagation = Propagation.REQUIRED; - if (maxAttempts > 1) { - propagation = Propagation.REQUIRES_NEW; - } - return executeTransaction(propagation, block); + return executeTransaction(Propagation.REQUIRED, block); + } + + public final R executeTransaction(int maxAttempts, long retryDelayMs, Function block) { + return executeTransaction(maxAttempts, retryDelayMs, Propagation.REQUIRES_NEW, block); } @Override public final R executeTransaction(Propagation propagation, Function block) { - int maxAttempts = this.maxAttempts; - if (maxAttempts > 1 && propagation != Propagation.REQUIRES_NEW) { - maxAttempts = 1; - } + return executeTransaction(1, 0, propagation, block); + } + public final R executeTransaction( + int maxAttempts, + long retryDelayMs, + Propagation propagation, + Function block + ) { for (int i = 0; i < maxAttempts; i++) { try { Scope parent = scopeLocal.get(); diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YqlClient.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YqlClient.java index 0193f472..1f379a16 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YqlClient.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YqlClient.java @@ -24,6 +24,17 @@ protected JSqlClientImplementor sqlClient() { return delegate; } + public R transaction(int maxAttempts, long retryDelayMs, Supplier block) { + if (getConnectionManager() instanceof YdbTxConnectionManager ydbCM) { + return ydbCM.executeTransaction(maxAttempts, retryDelayMs, con -> block.get()); + } + + throw new IllegalStateException( + "The connection manager does not support retries for transactions. " + + "Use YdbTxConnectionManager." + ); + } + public R withIsolation(int isolationLevel, boolean readOnly, Supplier block) { try { TransactionContext.setSettings(isolationLevel, readOnly); From c092fbbfa32fb7c2617ab6ce332d3222c4baaad3 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Mon, 18 May 2026 02:54:29 +0300 Subject: [PATCH 93/98] Added exponential wait to the retry logic for transactions --- .../ydb/jimmer/dialect/transaction/YdbTxConnectionManager.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YdbTxConnectionManager.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YdbTxConnectionManager.java index bc558ab0..95804e40 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YdbTxConnectionManager.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YdbTxConnectionManager.java @@ -21,6 +21,8 @@ public class YdbTxConnectionManager implements TxConnectionManager { private final DataSource dataSource; private final ThreadLocal scopeLocal = new ThreadLocal<>(); + private final int BACKOFF_MULTIPLIER = 2; + public YdbTxConnectionManager(DataSource dataSource) { this.dataSource = dataSource; } @@ -88,6 +90,7 @@ public final R executeTransaction( try { Thread.sleep(retryDelayMs); + retryDelayMs *= BACKOFF_MULTIPLIER; } catch (InterruptedException ex) { Thread.currentThread().interrupt(); throw new RuntimeException(ex); From c2b6ba76c1da6da872163b39d5fbcd0d9eca7013 Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Mon, 18 May 2026 15:37:47 +0300 Subject: [PATCH 94/98] extracted a constant for simplicity --- .../src/test/java/ydb/jimmer/dialect/batch/BatchTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/batch/BatchTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/batch/BatchTest.java index 71e0a9f7..28ce64b1 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/batch/BatchTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/batch/BatchTest.java @@ -13,6 +13,7 @@ public class BatchTest extends AbstractInsertTest { private static final String TABLE_NAME = "simple_table"; + private static final String TYPE_NAME = "Int32"; private void batchTest( SaveMode saveMode, @@ -45,7 +46,7 @@ private void batchTest( @BeforeEach void setup() { - createTable(TABLE_NAME, "Int32"); + createTable(TABLE_NAME, TYPE_NAME); } @AfterEach From bdd4ace31544e84a28775faa80b259597f07ebbc Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Mon, 18 May 2026 18:54:44 +0300 Subject: [PATCH 95/98] Fixed retires for transactions and cutdown on imports --- .../transaction/YdbTxConnectionManager.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YdbTxConnectionManager.java b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YdbTxConnectionManager.java index 95804e40..fd89ae2b 100644 --- a/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YdbTxConnectionManager.java +++ b/jimmer-dialect/src/main/java/ydb/jimmer/dialect/transaction/YdbTxConnectionManager.java @@ -1,7 +1,6 @@ package ydb.jimmer.dialect.transaction; import org.babyfish.jimmer.sql.exception.ExecutionException; -import org.babyfish.jimmer.sql.transaction.AbstractTxConnectionManager; import org.babyfish.jimmer.sql.transaction.Propagation; import org.babyfish.jimmer.sql.transaction.TxConnectionManager; import org.jetbrains.annotations.Nullable; @@ -15,7 +14,6 @@ /** * Provides propagation, isolation level, read only mode * and retry from abort/timeout for transactions. - * This class is a modified version of {@link AbstractTxConnectionManager}. */ public class YdbTxConnectionManager implements TxConnectionManager { private final DataSource dataSource; @@ -83,8 +81,13 @@ public final R executeTransaction( } } } catch (SQLException | RuntimeException ex) { - if (i == maxAttempts - 1 || !isRetryable(ex)) { - throw (ex instanceof RuntimeException re) ? re : new RuntimeException(ex); + RuntimeException e = new ExecutionException("JDBC error raised: " + ex.getMessage(), ex); + if (ex instanceof RuntimeException rex) { + e = rex; + } + + if (i == maxAttempts - 1 || !isRetryable(e.getCause())) { + throw e; } } @@ -100,7 +103,7 @@ public final R executeTransaction( throw new RuntimeException("Max attempts exceeded"); } - private boolean isRetryable(Exception ex) { + private boolean isRetryable(Throwable ex) { return ex instanceof SQLTimeoutException || (ex instanceof SQLException && isRetryableSqlState((SQLException) ex)); } @@ -109,7 +112,7 @@ private boolean isRetryableSqlState(SQLException ex) { String sqlState = ex.getSQLState(); return sqlState != null && ( sqlState.startsWith("40") || // Transaction rollback - "08S01".equals(sqlState) // Communication link failure + sqlState.startsWith("08") // Connection exception ); } From 363670eb655370a517895d200fbf02da3c958b6b Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Mon, 18 May 2026 19:59:58 +0300 Subject: [PATCH 96/98] Added chaos tests for transaction retries --- .../jimmer/dialect/chaosTests/AlwaysFail.java | 13 ++++ .../jimmer/dialect/chaosTests/FailFirstN.java | 36 ++++++++++ .../dialect/chaosTests/NotRetryableFail.java | 20 ++++++ .../jimmer/dialect/chaosTests/RetryTest.java | 70 +++++++++++++++++++ 4 files changed, 139 insertions(+) create mode 100644 jimmer-dialect/src/test/java/ydb/jimmer/dialect/chaosTests/AlwaysFail.java create mode 100644 jimmer-dialect/src/test/java/ydb/jimmer/dialect/chaosTests/FailFirstN.java create mode 100644 jimmer-dialect/src/test/java/ydb/jimmer/dialect/chaosTests/NotRetryableFail.java create mode 100644 jimmer-dialect/src/test/java/ydb/jimmer/dialect/chaosTests/RetryTest.java diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/chaosTests/AlwaysFail.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/chaosTests/AlwaysFail.java new file mode 100644 index 00000000..fd54b9b2 --- /dev/null +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/chaosTests/AlwaysFail.java @@ -0,0 +1,13 @@ +package ydb.jimmer.dialect.chaosTests; + +import org.babyfish.jimmer.sql.exception.ExecutionException; + +import java.sql.SQLTimeoutException; +import java.util.function.Supplier; + +public class AlwaysFail implements Supplier { + @Override + public R get() { + throw new ExecutionException("Persistent failure", new SQLTimeoutException()); + } +} diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/chaosTests/FailFirstN.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/chaosTests/FailFirstN.java new file mode 100644 index 00000000..cfcd274f --- /dev/null +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/chaosTests/FailFirstN.java @@ -0,0 +1,36 @@ +package ydb.jimmer.dialect.chaosTests; + +import org.babyfish.jimmer.sql.exception.ExecutionException; + +import java.sql.SQLTimeoutException; +import java.util.function.Supplier; + +public class FailFirstN implements Supplier { + private final int n; + private final R result; + + private int attempt; + + public FailFirstN(int n) { + this.n = n; + this.result = null; + } + + public FailFirstN(int n, R result) { + this.n = n; + this.result = result; + } + + public int getAttempt() { + return attempt; + } + + @Override + public R get() { + if (attempt++ < n) { + throw new ExecutionException("Expected failure number " + attempt, new SQLTimeoutException()); + } + + return result; + } +} diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/chaosTests/NotRetryableFail.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/chaosTests/NotRetryableFail.java new file mode 100644 index 00000000..c7e99447 --- /dev/null +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/chaosTests/NotRetryableFail.java @@ -0,0 +1,20 @@ +package ydb.jimmer.dialect.chaosTests; + +import org.babyfish.jimmer.sql.exception.ExecutionException; + +import java.sql.SQLException; +import java.util.function.Supplier; + +public class NotRetryableFail implements Supplier { + private int attempt; + + public int getAttempt() { + return attempt; + } + + @Override + public R get() { + attempt++; + throw new ExecutionException("Not retryable failure", new SQLException()); + } +} diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/chaosTests/RetryTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/chaosTests/RetryTest.java new file mode 100644 index 00000000..e866933a --- /dev/null +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/chaosTests/RetryTest.java @@ -0,0 +1,70 @@ +package ydb.jimmer.dialect.chaosTests; + +import org.babyfish.jimmer.sql.exception.ExecutionException; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import ydb.jimmer.dialect.AbstractSelectTest; + +public class RetryTest extends AbstractSelectTest { + @Test + public void succeedAfter1Failure() { + int maxAttempts = 2; + + FailFirstN chaosPolicy = new FailFirstN<>(maxAttempts - 1); + Assertions.assertDoesNotThrow(() -> + getIsolationClient().transaction( + maxAttempts, 0, + chaosPolicy + ) + ); + + Assertions.assertEquals(maxAttempts, chaosPolicy.getAttempt()); + } + + @Test + public void failAllAttempts() { + int maxAttempts = 3; + + Assertions.assertThrows( + ExecutionException.class, () -> + getIsolationClient().transaction( + maxAttempts, 0, + new AlwaysFail<>() + ) + ); + } + + @Test + public void failWithoutRetries() { + int maxAttempts = 3; + + NotRetryableFail chaosPolicy = new NotRetryableFail<>(); + Assertions.assertThrows( + ExecutionException.class, () -> + getIsolationClient().transaction( + maxAttempts, 0, + chaosPolicy + ) + ); + + Assertions.assertEquals(1, chaosPolicy.getAttempt()); + } + + @Test + public void exponentialBackoffTest() { + int maxAttempts = 3; + + FailFirstN chaosPolicy = new FailFirstN<>(maxAttempts - 1); + + long start = System.currentTimeMillis(); + Assertions.assertDoesNotThrow(() -> + getIsolationClient().transaction( + maxAttempts, 100, + chaosPolicy + ) + ); + long elapsed = System.currentTimeMillis() - start; + + Assertions.assertTrue(elapsed >= 300, "the backoff time is less than 100ms"); + } +} From 1b4ab64ea6ba2d12eabfb9a22bbbaf7d7bfc6e8a Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Wed, 20 May 2026 14:46:55 +0300 Subject: [PATCH 97/98] Added micro benchmarking tests CRUD, scan, join --- jimmer-dialect/pom.xml | 16 +- .../benchmark/CrudScanBenchmarkTest.java | 183 ++++++++++++++++++ .../dialect/benchmark/JoinBenchmarkTest.java | 127 ++++++++++++ 3 files changed, 322 insertions(+), 4 deletions(-) create mode 100644 jimmer-dialect/src/test/java/ydb/jimmer/dialect/benchmark/CrudScanBenchmarkTest.java create mode 100644 jimmer-dialect/src/test/java/ydb/jimmer/dialect/benchmark/JoinBenchmarkTest.java diff --git a/jimmer-dialect/pom.xml b/jimmer-dialect/pom.xml index b5382607..b4a893b0 100644 --- a/jimmer-dialect/pom.xml +++ b/jimmer-dialect/pom.xml @@ -12,6 +12,7 @@ 0.9.117 7.0.2 + 1.37 17 @@ -70,11 +71,18 @@ 2.3.29 test - + - org.liquibase - liquibase-core - 5.0.1 + org.openjdk.jmh + jmh-core + ${jmh.version} + test + + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh.version} test diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/benchmark/CrudScanBenchmarkTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/benchmark/CrudScanBenchmarkTest.java new file mode 100644 index 00000000..8f5efede --- /dev/null +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/benchmark/CrudScanBenchmarkTest.java @@ -0,0 +1,183 @@ +package ydb.jimmer.dialect.benchmark; + +import org.babyfish.jimmer.sql.JSqlClient; +import org.babyfish.jimmer.sql.ast.mutation.SaveMode; +import org.babyfish.jimmer.sql.runtime.ConnectionManager; +import org.junit.jupiter.api.Test; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.format.OutputFormat; +import org.openjdk.jmh.runner.format.OutputFormatFactory; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; +import org.openjdk.jmh.runner.options.VerboseMode; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import ydb.jimmer.dialect.AbstractSelectTest; +import ydb.jimmer.dialect.YdbDialect; +import ydb.jimmer.dialect.YqlClientBuilder; +import ydb.jimmer.dialect.model.Entity; +import ydb.jimmer.dialect.model.EntityDraft; +import ydb.jimmer.dialect.model.EntityTable; +import ydb.jimmer.dialect.transaction.YqlClient; + +import javax.sql.DataSource; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@State(Scope.Benchmark) +@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) +@Fork(0) +public class CrudScanBenchmarkTest extends AbstractSelectTest { + private static final String TABLE_NAME = "simple_table"; + private static final String TYPE_NAME = "Int32"; + + private static final int size = 1000; + + private static final String[] values; + private static final List existingEntities; + private static final List existingIds; + private static final List newEntities; + + static { + values = new String[size]; + existingEntities = new ArrayList<>(); + existingIds = new ArrayList<>(); + for (int i = 0; i < size; i++) { + int value = i; + values[i] = String.valueOf(value); + existingEntities.add(EntityDraft.$.produce(entity -> { + entity.setId(value); + entity.setValue(value); + })); + existingIds.add(value); + } + + newEntities = new ArrayList<>(); + for (int i = 0; i < size; i++) { + int value = size + i; + newEntities.add(EntityDraft.$.produce(entity -> { + entity.setId(value); + entity.setValue(value); + })); + } + } + + protected static JSqlClient sqlClient; + protected static YqlClient yqlClient; + + static { + DataSource dataSource = new DriverManagerDataSource(getJdbcURL()); + sqlClient = JSqlClient.newBuilder() + .setDialect(new YdbDialect()) + .setConnectionManager(ConnectionManager.simpleConnectionManager(dataSource)) + .build(); + yqlClient = YqlClientBuilder.getYqlClient(dataSource); + } + + @Setup(Level.Invocation) + public void setup() { + createTable(TABLE_NAME, TYPE_NAME); + + yqlClient.getEntities() + .saveEntitiesCommand(existingEntities) + .execute(); + } + + @TearDown(Level.Invocation) + public void tearDown() { + dropTable(TABLE_NAME); + } + + @Benchmark + public void benchmarkRead() { + yqlClient.snapshotReadOnly(() -> yqlClient.getEntities().findAll(Entity.class)); + } + + @Benchmark + public void benchmarkScan() { + EntityTable table = EntityTable.$; + yqlClient.createQuery(table) + .where(table.value().ge(size/2)) + .where(table.value().le(size)) + .select(table); + } + + @Benchmark + public void benchmarkScanDialectOnly() { + EntityTable table = EntityTable.$; + sqlClient.createQuery(table) + .where(table.value().ge(size/2)) + .where(table.value().le(size)) + .select(table); + } + + @Benchmark + public void benchmarkReadDialectOnly() { + sqlClient.getEntities().findAll(Entity.class); + } + + @Benchmark + public void benchmarkSave() { + yqlClient.getEntities() + .saveEntitiesCommand(newEntities) + .execute(); + } + + @Benchmark + public void benchmarkSaveDialectOnly() { + sqlClient.getEntities() + .saveEntitiesCommand(newEntities) + .execute(); + } + + @Benchmark + public void benchmarkUpdate() { + yqlClient.getEntities() + .saveEntitiesCommand(existingEntities) + .setMode(SaveMode.UPDATE_ONLY) + .execute(); + } + + @Benchmark + public void benchmarkDelete() { + yqlClient.getEntities().deleteAll(Entity.class, existingIds); + } + + @Benchmark + public void benchmarkDeleteDialectOnly() { + sqlClient.getEntities().deleteAll(Entity.class, existingIds); + } + + @Test + void runBenchmarks() throws RunnerException { + Options opts = new OptionsBuilder() + .include(CrudScanBenchmarkTest.class.getSimpleName()) + .shouldFailOnError(true) + .shouldDoGC(true) + .build(); + + OutputFormat out = OutputFormatFactory.createFormatInstance( + System.out, + VerboseMode.NORMAL + ); + + + new Runner(opts, out).run(); + } +} diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/benchmark/JoinBenchmarkTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/benchmark/JoinBenchmarkTest.java new file mode 100644 index 00000000..d56f773d --- /dev/null +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/benchmark/JoinBenchmarkTest.java @@ -0,0 +1,127 @@ +package ydb.jimmer.dialect.benchmark; + +import org.babyfish.jimmer.sql.JSqlClient; +import org.babyfish.jimmer.sql.JoinType; +import org.babyfish.jimmer.sql.runtime.ConnectionManager; +import org.junit.jupiter.api.Test; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.format.OutputFormat; +import org.openjdk.jmh.runner.format.OutputFormatFactory; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; +import org.openjdk.jmh.runner.options.VerboseMode; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import ydb.jimmer.dialect.AbstractSelectTest; +import ydb.jimmer.dialect.YdbDialect; +import ydb.jimmer.dialect.YqlClientBuilder; +import ydb.jimmer.dialect.model.Group; +import ydb.jimmer.dialect.model.GroupDraft; +import ydb.jimmer.dialect.model.Student; +import ydb.jimmer.dialect.model.StudentDraft; +import ydb.jimmer.dialect.model.StudentTable; +import ydb.jimmer.dialect.transaction.YqlClient; + +import javax.sql.DataSource; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@State(Scope.Benchmark) +@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) +@Fork(0) +public class JoinBenchmarkTest extends AbstractSelectTest { + private static final int size = 1000; + + private static final List students; + private static final List groups; + + static { + students = new ArrayList<>(); + groups = new ArrayList<>(); + for (int i = 0; i < size; i++) { + UUID value = UUID.randomUUID(); + Group group = GroupDraft.$.produce(g -> { + g.setId(value); + g.setName("name" + value); + }); + groups.add(group); + students.add(StudentDraft.$.produce(entity -> { + entity.setId(UUID.randomUUID()); + entity.setName("name1" + value); + entity.setGroup(group); + })); + students.add(StudentDraft.$.produce(entity -> { + entity.setId(UUID.randomUUID()); + entity.setName("name2" + value); + entity.setGroup(group); + })); + } + } + + protected static JSqlClient sqlClient; + protected static YqlClient yqlClient; + + static { + DataSource dataSource = new DriverManagerDataSource(getJdbcURL()); + sqlClient = JSqlClient.newBuilder() + .setDialect(new YdbDialect()) + .setConnectionManager(ConnectionManager.simpleConnectionManager(dataSource)) + .build(); + yqlClient = YqlClientBuilder.getYqlClient(dataSource); + } + + @Setup(Level.Invocation) + public void setup() { + initDatabase(); + + yqlClient.getEntities() + .saveEntitiesCommand(students) + .execute(); + + yqlClient.getEntities() + .saveEntitiesCommand(groups) + .execute(); + } + + @Benchmark + public void benchmarkLeft() { + StudentTable table = StudentTable.$; + getYqlClient() + .createQuery(table) + .orderBy(table.group(JoinType.LEFT).name().asc()) + .select(table); + } + + @Test + void runBenchmarks() throws RunnerException { + Options opts = new OptionsBuilder() + .include(JoinBenchmarkTest.class.getSimpleName()) + .shouldFailOnError(true) + .shouldDoGC(true) + .build(); + + OutputFormat out = OutputFormatFactory.createFormatInstance( + System.out, + VerboseMode.NORMAL + ); + + + new Runner(opts, out).run(); + } +} From d60d31d1045b06de547106b1e4525745a2645c4a Mon Sep 17 00:00:00 2001 From: Rinoyt Date: Wed, 20 May 2026 20:53:44 +0300 Subject: [PATCH 98/98] Fixed the join benchmarking test --- .../dialect/benchmark/JoinBenchmarkTest.java | 51 ++++++++++++++++++- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/benchmark/JoinBenchmarkTest.java b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/benchmark/JoinBenchmarkTest.java index d56f773d..e7780a01 100644 --- a/jimmer-dialect/src/test/java/ydb/jimmer/dialect/benchmark/JoinBenchmarkTest.java +++ b/jimmer-dialect/src/test/java/ydb/jimmer/dialect/benchmark/JoinBenchmarkTest.java @@ -101,10 +101,57 @@ public void setup() { @Benchmark public void benchmarkLeft() { + benchmarkJoin(JoinType.LEFT); + } + + @Benchmark + public void benchmarkLeftDialectOnly() { + benchmarkJoinDialectOnly(JoinType.LEFT); + } + + @Benchmark + public void benchmarkRight() { + benchmarkJoin(JoinType.RIGHT); + } + + @Benchmark + public void benchmarkRightDialectOnly() { + benchmarkJoinDialectOnly(JoinType.RIGHT); + } + + @Benchmark + public void benchmarkInner() { + benchmarkJoin(JoinType.INNER); + } + + @Benchmark + public void benchmarkInnerDialectOnly() { + benchmarkJoinDialectOnly(JoinType.INNER); + } + + @Benchmark + public void benchmarkFull() { + benchmarkJoin(JoinType.FULL); + } + + @Benchmark + public void benchmarkFullDialectOnly() { + benchmarkJoinDialectOnly(JoinType.FULL); + } + + private void benchmarkJoin(JoinType joinType) { + StudentTable table = StudentTable.$; + yqlClient + .createQuery(table) + .orderBy(table.group(joinType).name().asc()) + .select(table); + } + + private void benchmarkJoinDialectOnly(JoinType joinType) { StudentTable table = StudentTable.$; - getYqlClient() + sqlClient .createQuery(table) - .orderBy(table.group(JoinType.LEFT).name().asc()) + .orderBy(table.group(joinType).name().asc()) .select(table); }