diff --git a/.github/workflows/ci-spring-data-jdbc.yaml b/.github/workflows/ci-spring-data-jdbc.yaml
new file mode 100644
index 0000000..29503c9
--- /dev/null
+++ b/.github/workflows/ci-spring-data-jdbc.yaml
@@ -0,0 +1,61 @@
+name: Spring Data JDBC YDB Dialect CI with Maven
+
+on:
+ push:
+ paths:
+ - 'spring-data-dialect/**'
+ branches:
+ - main
+ pull_request:
+ paths:
+ - 'spring-data-dialect/**'
+
+env:
+ MAVEN_ARGS: --batch-mode --update-snapshots -Dstyle.color=always
+
+jobs:
+ build:
+ name: Spring Data JDBC YDB Dialect
+ runs-on: ubuntu-latest
+
+ strategy:
+ matrix:
+ java: [ '17', '21' ]
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Set up JDK ${{matrix.java}}
+ uses: actions/setup-java@v4
+ with:
+ java-version: ${{matrix.java}}
+ distribution: 'temurin'
+ cache: maven
+
+ - name: Extract spring-data-jdbc YDB dialect version
+ working-directory: ./spring-data-dialect
+ run: |
+ VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
+ echo "SPRING_DATA_JDBC_DIALECT_VERSION=$VERSION" >> "$GITHUB_ENV"
+
+ - name: Download spring-data-jdbc YDB dialect dependencies
+ working-directory: ./spring-data-dialect
+ run: mvn $MAVEN_ARGS dependency:go-offline
+
+ - name: Build spring-data-jdbc YDB dialect
+ working-directory: ./spring-data-dialect
+ run: mvn $MAVEN_ARGS install
+
+# - uses: actions/checkout@v4
+# with:
+# repository: ydb-platform/ydb-java-examples
+# ref: master
+# path: examples
+#
+# - name: Download dependencies
+# working-directory: ./examples/jdbc/spring-data-jpa-v5
+# run: mvn $MAVEN_ARGS -Dspring.data.jdbc.ydb.dialect.version=$SPRING_DATA_JDBC_DIALECT_VERSION dependency:go-offline
+#
+# - name: Test examples with Maven
+# working-directory: ./examples/jdbc/spring-data-jpa-v5
+# run: mvn $MAVEN_ARGS -Dspring.data.jdbc.ydb.dialect.version=$SPRING_DATA_JDBC_DIALECT_VERSION test
diff --git a/.github/workflows/publish-spring-data-jdbc-dialect.yaml b/.github/workflows/publish-spring-data-jdbc-dialect.yaml
new file mode 100644
index 0000000..f117035
--- /dev/null
+++ b/.github/workflows/publish-spring-data-jdbc-dialect.yaml
@@ -0,0 +1,85 @@
+name: Publish Spring Data JDBC YDB Dialect
+
+on:
+ push:
+ tags:
+ - 'spring-data-jdbc-ydb/v[0-9]+.[0-9]+.[0-9]+'
+
+env:
+ MAVEN_ARGS: --batch-mode --no-transfer-progress -Dstyle.color=always
+
+jobs:
+ validate:
+ name: Validate Spring Data JDBC YDB Dialect
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Extract spring-data-jdbc YDB dialect version
+ run: |
+ cd spring-data-dialect
+ SPRING_DATA_JDBC_DIALECT_VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
+ echo "SPRING_DATA_JDBC_DIALECT_VERSION=SPRING_DATA_JDBC_DIALECT_VERSION" >> "$GITHUB_ENV"
+
+ - name: Fail workflow if version is snapshot
+ if: endsWith(env.SPRING_DATA_JDBC_DIALECT_VERSION, 'SNAPSHOT')
+ uses: actions/github-script@v6
+ with:
+ script: core.setFailed('SNAPSHOT version cannot be published')
+
+ - name: Fail workflow if version is not equal to tag name
+ if: format('spring-data-jdbc-ydb/v{0}', env.SPRING_DATA_JDBC_DIALECT_VERSION) != github.ref_name
+ uses: actions/github-script@v6
+ with:
+ script: core.setFailed('Release name must be equal to project version')
+
+ - name: Set up JDK
+ uses: actions/setup-java@v4
+ with:
+ java-version: 17
+ distribution: 'temurin'
+ cache: 'maven'
+
+ - name: Download dependencies
+ run: |
+ cd spring-data-dialect
+ mvn $MAVEN_ARGS dependency:go-offline
+
+ - name: Build with Maven
+ run: |
+ cd spring-data-dialect
+ mvn $MAVEN_ARGS package
+
+ publish:
+ name: Publish Spring Data JDBC YDB Dialect
+ runs-on: ubuntu-latest
+ needs: validate
+
+ steps:
+ - name: Install gpg secret key
+ run: |
+ # Install gpg secret key
+ cat <(echo -e "${{ secrets.MAVEN_OSSRH_GPG_SECRET_KEY }}") | gpg --batch --import
+ # Verify gpg secret key
+ gpg --list-secret-keys --keyid-format LONG
+
+ - uses: actions/checkout@v4
+
+ - name: Set up Maven Central Repository
+ uses: actions/setup-java@v4
+ with:
+ java-version: 17
+ distribution: 'temurin'
+ cache: 'maven'
+ server-id: ossrh-s01
+ server-username: MAVEN_USERNAME
+ server-password: MAVEN_PASSWORD
+
+ - name: Publish package
+ run: |
+ cd spring-data-dialect
+ mvn $MAVEN_ARGS -Possrh-s01 -Dgpg.passphrase=${{ secrets.MAVEN_OSSRH_GPG_PASSWORD }} clean deploy
+ env:
+ MAVEN_USERNAME: ${{ secrets.MAVEN_OSSRH_USERNAME }}
+ MAVEN_PASSWORD: ${{ secrets.MAVEN_OSSRH_TOKEN }}
diff --git a/jooq-dialect/src/test/java/tech/ydb/jooq/InsertTest.java b/jooq-dialect/src/test/java/tech/ydb/jooq/InsertTest.java
index 497e4ff..d399261 100644
--- a/jooq-dialect/src/test/java/tech/ydb/jooq/InsertTest.java
+++ b/jooq-dialect/src/test/java/tech/ydb/jooq/InsertTest.java
@@ -1,5 +1,8 @@
package tech.ydb.jooq;
+import java.util.List;
+import static jooq.generated.ydb.default_schema.Tables.HARD_TABLE;
+import static jooq.generated.ydb.default_schema.Tables.SERIES;
import jooq.generated.ydb.default_schema.tables.records.HardTableRecord;
import jooq.generated.ydb.default_schema.tables.records.SeriesRecord;
import org.jooq.JSON;
@@ -7,15 +10,11 @@
import org.jooq.Result;
import org.jooq.exception.DataAccessException;
import org.jooq.types.ULong;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test;
import tech.ydb.jooq.value.YSON;
-import java.util.List;
-
-import static jooq.generated.ydb.default_schema.Tables.HARD_TABLE;
-import static jooq.generated.ydb.default_schema.Tables.SERIES;
-import static org.junit.jupiter.api.Assertions.*;
-
public class InsertTest extends BaseTest {
@Test
diff --git a/spring-data-dialect/pom.xml b/spring-data-dialect/pom.xml
index 123bf82..734124c 100644
--- a/spring-data-dialect/pom.xml
+++ b/spring-data-dialect/pom.xml
@@ -8,10 +8,12 @@
spring-data-ydb-dialect
0.9.1-SNAPSHOT
- Spring Data YDB Dialect
+ Spring Data JDBC YDB Dialect
Support Spring Data JDBC YDB (YQL) Dialect
https://github.com/ydb-platform/ydb-java-dialects
+ jar
+
Madiyar Nurgazin
@@ -19,25 +21,41 @@
YDB
https://ydb.tech/
+
+ Kirill Kurdyukov
+ kurdyukov-kir@ydb.tech
+ YDB
+ https://ydb.tech/
+
+
+ https://github.com/ydb-platform/ydb-java-dialects
+ scm:git:https://github.com/ydb-platform/ydb-java-dialects.git
+ scm:git:https://github.com/ydb-platform/ydb-java-dialects.git
+
+
+
+
+ Apache License, Version 2.0
+ https://www.apache.org/licenses/LICENSE-2.0
+
+
+
UTF-8
17
-
17
17
- 3.2.4
-
5.10.2
1.18.30
- 3.2.3
+ 3.2.1
4.24.0
- 2.2.6
- 2.1.5
+ 2.2.9
+ 2.2.3
0.9.7
@@ -50,6 +68,13 @@
pom
import
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${spring.version}
+ import
+ pom
+
@@ -57,14 +82,15 @@
org.springframework.data
spring-data-jdbc
- ${springdata.jdbc.version}
provided
tech.ydb.jdbc
- ydb-jdbc-driver-shaded
+ ydb-jdbc-driver
${ydb.jdbc.version}
+ provided
+
tech.ydb.test
ydb-junit5-support
@@ -73,7 +99,6 @@
org.junit.jupiter
junit-jupiter-api
- ${junit5.version}
test
@@ -85,13 +110,11 @@
org.springframework.boot
spring-boot-starter-test
- ${spring.boot.version}
test
org.springframework.boot
spring-boot-starter-jdbc
- ${spring.boot.version}
test
@@ -107,4 +130,90 @@
test
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 3.5.0
+
+ 17
+
+
+
+ attach-javadocs
+
+ jar
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+ 3.2.1
+
+
+ attach-sources
+
+ jar-no-fork
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 3.1.0
+
+
+ true
+
+
+
+
+
+
+
+ ossrh-s01
+
+ false
+
+
+
+
+ org.apache.maven.plugins
+ maven-gpg-plugin
+ 1.6
+
+
+ sign-artifacts
+ verify
+
+ sign
+
+
+
+
+
+ --pinentry-mode
+ loopback
+
+
+
+
+ org.sonatype.plugins
+ nexus-staging-maven-plugin
+ 1.6.8
+ true
+
+ ossrh-s01
+ https://s01.oss.sonatype.org/
+ false
+
+
+
+
+
+
diff --git a/spring-data-dialect/src/main/java/tech/ydb/data/core/convert/YQLType.java b/spring-data-dialect/src/main/java/tech/ydb/data/core/convert/YQLType.java
index 7ed33c0..778d597 100644
--- a/spring-data-dialect/src/main/java/tech/ydb/data/core/convert/YQLType.java
+++ b/spring-data-dialect/src/main/java/tech/ydb/data/core/convert/YQLType.java
@@ -1,7 +1,6 @@
package tech.ydb.data.core.convert;
import java.sql.SQLType;
-
import tech.ydb.jdbc.YdbConst;
import tech.ydb.table.values.PrimitiveType;
diff --git a/spring-data-dialect/src/main/java/tech/ydb/data/core/convert/YdbJdbcColumnTypes.java b/spring-data-dialect/src/main/java/tech/ydb/data/core/convert/YdbJdbcColumnTypes.java
deleted file mode 100644
index f46cf12..0000000
--- a/spring-data-dialect/src/main/java/tech/ydb/data/core/convert/YdbJdbcColumnTypes.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package tech.ydb.data.core.convert;
-
-import java.sql.Timestamp;
-import java.time.Instant;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.OffsetDateTime;
-import java.time.ZonedDateTime;
-import java.time.temporal.Temporal;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import org.springframework.util.ClassUtils;
-
-/**
- * @author Madiyar Nurgazin
- */
-public enum YdbJdbcColumnTypes {
- INSTANCE {
- @SuppressWarnings({ "unchecked", "rawtypes" })
- public Class> resolvePrimitiveType(Class> type) {
- return javaToDbType.entrySet().stream() //
- .filter(e -> e.getKey().isAssignableFrom(type)) //
- .map(e -> (Class>) e.getValue()) //
- .findFirst() //
- .orElseGet(() -> (Class) ClassUtils.resolvePrimitiveIfNecessary(type));
- }
- };
-
- private static final Map, Class>> javaToDbType = new LinkedHashMap<>();
-
- static {
- javaToDbType.put(Enum.class, String.class);
- javaToDbType.put(ZonedDateTime.class, String.class);
- javaToDbType.put(OffsetDateTime.class, OffsetDateTime.class);
- javaToDbType.put(LocalDateTime.class, LocalDateTime.class);
- javaToDbType.put(LocalDate.class, LocalDate.class);
- javaToDbType.put(Instant.class, Instant.class);
- javaToDbType.put(Temporal.class, Timestamp.class);
- }
-
- public abstract Class> resolvePrimitiveType(Class> type);
-}
diff --git a/spring-data-dialect/src/main/java/tech/ydb/data/core/convert/YdbMappingJdbcConverter.java b/spring-data-dialect/src/main/java/tech/ydb/data/core/convert/YdbMappingJdbcConverter.java
index d0348f8..7d8c8ea 100644
--- a/spring-data-dialect/src/main/java/tech/ydb/data/core/convert/YdbMappingJdbcConverter.java
+++ b/spring-data-dialect/src/main/java/tech/ydb/data/core/convert/YdbMappingJdbcConverter.java
@@ -1,85 +1,27 @@
package tech.ydb.data.core.convert;
import java.sql.SQLType;
-
import org.springframework.data.convert.CustomConversions;
import org.springframework.data.jdbc.core.convert.JdbcTypeFactory;
import org.springframework.data.jdbc.core.convert.MappingJdbcConverter;
import org.springframework.data.jdbc.core.convert.RelationResolver;
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
-import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
-import org.springframework.data.util.TypeInformation;
-import org.springframework.lang.Nullable;
-import tech.ydb.data.repository.support.YdbJdbcUtil;
+import tech.ydb.table.values.PrimitiveType;
/**
* @author Madiyar Nurgazin
*/
public class YdbMappingJdbcConverter extends MappingJdbcConverter {
public YdbMappingJdbcConverter(RelationalMappingContext context, RelationResolver relationResolver,
- CustomConversions conversions, JdbcTypeFactory typeFactory) {
+ CustomConversions conversions, JdbcTypeFactory typeFactory) {
super(context, relationResolver, conversions, typeFactory);
}
@Override
public SQLType getTargetSqlType(RelationalPersistentProperty property) {
- if (property.isAnnotationPresent(YdbType.class)) {
- return new YQLType(property.getRequiredAnnotation(YdbType.class).value());
- }
-
- return YdbJdbcUtil.targetSqlTypeFor(getColumnType(property));
- }
-
- @Override
- public Class> getColumnType(RelationalPersistentProperty property) {
- if (property.isAssociation()) {
- return getReferenceColumnType(property);
- }
-
- if (property.isEntity()) {
- Class> columnType = getEntityColumnType(property.getTypeInformation().getActualType());
-
- if (columnType != null) {
- return columnType;
- }
- }
-
- Class> componentColumnType = YdbJdbcColumnTypes.INSTANCE.resolvePrimitiveType(property.getActualType());
-
- while (componentColumnType.isArray()) {
- componentColumnType = componentColumnType.getComponentType();
- }
-
- if (property.isCollectionLike() && !property.isEntity()) {
- return java.lang.reflect.Array.newInstance(componentColumnType, 0).getClass();
- }
-
- return componentColumnType;
- }
-
- private Class> getReferenceColumnType(RelationalPersistentProperty property) {
-
- Class> componentType = property.getTypeInformation().getRequiredComponentType().getType();
- RelationalPersistentEntity> referencedEntity = getMappingContext().getRequiredPersistentEntity(componentType);
-
- return getColumnType(referencedEntity.getRequiredIdProperty());
- }
-
- @Nullable
- private Class> getEntityColumnType(TypeInformation> type) {
-
- RelationalPersistentEntity> persistentEntity = getMappingContext().getPersistentEntity(type);
-
- if (persistentEntity == null) {
- return null;
- }
-
- RelationalPersistentProperty idProperty = persistentEntity.getIdProperty();
-
- if (idProperty == null) {
- return null;
- }
- return getColumnType(idProperty);
+ return property.isAnnotationPresent(YdbType.class) ?
+ new YQLType(PrimitiveType.valueOf(property.getRequiredAnnotation(YdbType.class).value())) :
+ super.getTargetSqlType(property);
}
}
diff --git a/spring-data-dialect/src/main/java/tech/ydb/data/core/convert/YdbType.java b/spring-data-dialect/src/main/java/tech/ydb/data/core/convert/YdbType.java
index a700cb5..1bdeafc 100644
--- a/spring-data-dialect/src/main/java/tech/ydb/data/core/convert/YdbType.java
+++ b/spring-data-dialect/src/main/java/tech/ydb/data/core/convert/YdbType.java
@@ -5,13 +5,11 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-import tech.ydb.table.values.PrimitiveType;
-
/**
* @author Madiyar Nurgazin
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface YdbType {
- PrimitiveType value();
+ String value();
}
diff --git a/spring-data-dialect/src/main/java/tech/ydb/data/core/convert/package-info.java b/spring-data-dialect/src/main/java/tech/ydb/data/core/convert/package-info.java
new file mode 100644
index 0000000..dca92f1
--- /dev/null
+++ b/spring-data-dialect/src/main/java/tech/ydb/data/core/convert/package-info.java
@@ -0,0 +1,4 @@
+@NonNullApi
+package tech.ydb.data.core.convert;
+
+import org.springframework.lang.NonNullApi;
\ No newline at end of file
diff --git a/spring-data-dialect/src/main/java/tech/ydb/data/core/dialect/YdbDialect.java b/spring-data-dialect/src/main/java/tech/ydb/data/core/dialect/YdbDialect.java
index 84eef5d..3dd1738 100644
--- a/spring-data-dialect/src/main/java/tech/ydb/data/core/dialect/YdbDialect.java
+++ b/spring-data-dialect/src/main/java/tech/ydb/data/core/dialect/YdbDialect.java
@@ -1,8 +1,7 @@
package tech.ydb.data.core.dialect;
-import java.util.Collections;
-import java.util.Set;
-
+import java.util.function.Function;
+import org.springframework.aop.interceptor.ExposeInvocationInterceptor;
import org.springframework.data.relational.core.dialect.AbstractDialect;
import org.springframework.data.relational.core.dialect.InsertRenderContext;
import org.springframework.data.relational.core.dialect.LimitClause;
@@ -10,6 +9,8 @@
import org.springframework.data.relational.core.dialect.OrderByNullPrecedence;
import org.springframework.data.relational.core.sql.IdentifierProcessing;
import org.springframework.data.relational.core.sql.LockOptions;
+import org.springframework.data.relational.core.sql.Select;
+import tech.ydb.data.repository.ViewIndex;
/**
* @author Madiyar Nurgazin
@@ -50,6 +51,28 @@ public LockClause.Position getClausePosition() {
}
};
+ @Override
+ protected Function