Skip to content

Commit 0c2df1e

Browse files
authored
Add Ydb repository interfaces; support Ydb specific types; enhance and add new tests (#133)
1 parent 7561c9b commit 0c2df1e

35 files changed

+497
-249
lines changed

spring-data-dialect/pom.xml

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>tech.ydb.dialects</groupId>
88
<artifactId>spring-data-ydb-dialect</artifactId>
9-
<version>0.9.0-SNAPSHOT</version>
9+
<version>0.9.1-SNAPSHOT</version>
1010

1111
<name>Spring Data YDB Dialect</name>
1212
<description>Support Spring Data JDBC YDB (YQL) Dialect</description>
@@ -62,7 +62,6 @@
6262
<groupId>tech.ydb.jdbc</groupId>
6363
<artifactId>ydb-jdbc-driver-shaded</artifactId>
6464
<version>${ydb.jdbc.version}</version>
65-
<scope>test</scope>
6665
</dependency>
6766
<dependency>
6867
<groupId>tech.ydb.test</groupId>
@@ -103,6 +102,7 @@
103102
<groupId>org.liquibase</groupId>
104103
<artifactId>liquibase-core</artifactId>
105104
<version>${liquibase.version}</version>
105+
<scope>test</scope>
106106
</dependency>
107107
</dependencies>
108108
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package tech.ydb.data.core.convert;
2+
3+
import java.sql.SQLType;
4+
5+
import tech.ydb.jdbc.YdbConst;
6+
import tech.ydb.table.values.PrimitiveType;
7+
8+
/**
9+
* @author Madiyar Nurgazin
10+
*/
11+
public record YQLType(PrimitiveType type) implements SQLType {
12+
@Override
13+
public String getName() {
14+
return type.name();
15+
}
16+
17+
@Override
18+
public String getVendor() {
19+
return "YDB";
20+
}
21+
22+
@Override
23+
public Integer getVendorTypeNumber() {
24+
return YdbConst.SQL_KIND_PRIMITIVE + type.ordinal();
25+
}
26+
}

spring-data-dialect/src/main/java/tech/ydb/data/core/convert/YdbMappingJdbcConverter.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
1212
import org.springframework.data.util.TypeInformation;
1313
import org.springframework.lang.Nullable;
14-
import tech.ydb.data.support.YdbJdbcUtil;
14+
import tech.ydb.data.repository.support.YdbJdbcUtil;
1515

1616
/**
1717
* @author Madiyar Nurgazin
@@ -24,6 +24,9 @@ public YdbMappingJdbcConverter(RelationalMappingContext context, RelationResolve
2424

2525
@Override
2626
public SQLType getTargetSqlType(RelationalPersistentProperty property) {
27+
if (property.isAnnotationPresent(YdbType.class)) {
28+
return new YQLType(property.getRequiredAnnotation(YdbType.class).value());
29+
}
2730
return YdbJdbcUtil.targetSqlTypeFor(getColumnType(property));
2831
}
2932

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package tech.ydb.data.core.convert;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Retention;
5+
import java.lang.annotation.RetentionPolicy;
6+
import java.lang.annotation.Target;
7+
8+
import tech.ydb.table.values.PrimitiveType;
9+
10+
/**
11+
* @author Madiyar Nurgazin
12+
*/
13+
@Retention(RetentionPolicy.RUNTIME)
14+
@Target(ElementType.FIELD)
15+
public @interface YdbType {
16+
PrimitiveType value();
17+
}

spring-data-dialect/src/main/java/tech/ydb/data/core/dialect/YdbDialect.java

+1-3
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
* @author Madiyar Nurgazin
1616
*/
1717
public class YdbDialect extends AbstractDialect {
18-
1918
public static final YdbDialect INSTANCE = new YdbDialect();
2019

2120
private static final LimitClause LIMIT_CLAUSE = new LimitClause() {
@@ -43,7 +42,7 @@ public Position getClausePosition() {
4342

4443
private static final LockClause LOCK_CLAUSE = new LockClause() {
4544
public String getLock(LockOptions lockOptions) {
46-
throw new UnsupportedOperationException("YDB don't support FOR UPDATE statement");
45+
throw new UnsupportedOperationException("YDB don't support pessimistic locks");
4746
}
4847

4948
public LockClause.Position getClausePosition() {
@@ -85,5 +84,4 @@ public InsertRenderContext getInsertRenderContext() {
8584
public OrderByNullPrecedence orderByNullHandling() {
8685
return OrderByNullPrecedence.NONE;
8786
}
88-
8987
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package tech.ydb.data.repository;
2+
3+
import org.springframework.data.repository.CrudRepository;
4+
import org.springframework.data.repository.NoRepositoryBean;
5+
6+
/**
7+
* @author Madiyar Nurgazin
8+
*/
9+
@NoRepositoryBean
10+
public interface YdbCrudRepository<T, ID> extends YdbRepository<T, ID>, CrudRepository<T, ID> {
11+
<S extends T> Iterable<S> insertAll(Iterable<S> entities);
12+
13+
<S extends T> Iterable<S> updateAll(Iterable<S> entities);
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package tech.ydb.data.repository;
2+
3+
import java.util.List;
4+
5+
import org.springframework.data.repository.ListCrudRepository;
6+
import org.springframework.data.repository.NoRepositoryBean;
7+
8+
/**
9+
* @author Madiyar Nurgazin
10+
*/
11+
@NoRepositoryBean
12+
public interface YdbListCrudRepository<T, ID> extends YdbRepository<T, ID>, ListCrudRepository<T, ID> {
13+
<S extends T> List<S> insertAll(Iterable<S> entities);
14+
15+
<S extends T> List<S> updateAll(Iterable<S> entities);
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package tech.ydb.data.repository;
2+
3+
import org.springframework.data.repository.ListPagingAndSortingRepository;
4+
import org.springframework.data.repository.NoRepositoryBean;
5+
6+
/**
7+
* @author Madiyar Nurgazin
8+
*/
9+
@NoRepositoryBean
10+
public interface YdbListPagingAndSortingRepository<T, ID> extends YdbRepository<T, ID>,
11+
ListPagingAndSortingRepository<T, ID> {
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package tech.ydb.data.repository;
2+
3+
import org.springframework.data.repository.NoRepositoryBean;
4+
import org.springframework.data.repository.PagingAndSortingRepository;
5+
6+
/**
7+
* @author Madiyar Nurgazin
8+
*/
9+
@NoRepositoryBean
10+
public interface YdbPagingAndSortingRepository<T, ID> extends YdbRepository<T, ID>, PagingAndSortingRepository<T, ID> {
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package tech.ydb.data.repository;
2+
3+
import org.springframework.data.repository.NoRepositoryBean;
4+
import org.springframework.data.repository.Repository;
5+
6+
/**
7+
* @author Madiyar Nurgazin
8+
*/
9+
@NoRepositoryBean
10+
public interface YdbRepository<T, ID> extends Repository<T, ID> {
11+
<S extends T> S insert(S entity);
12+
13+
<S extends T> S update(S entity);
14+
}

spring-data-dialect/src/main/java/tech/ydb/data/config/AbstractYdbJdbcConfiguration.java renamed to spring-data-dialect/src/main/java/tech/ydb/data/repository/config/AbstractYdbJdbcConfiguration.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package tech.ydb.data.config;
1+
package tech.ydb.data.repository.config;
22

33
import org.springframework.context.annotation.Configuration;
44
import org.springframework.context.annotation.Lazy;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package tech.ydb.data.repository.config;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Retention;
5+
import java.lang.annotation.RetentionPolicy;
6+
import java.lang.annotation.Target;
7+
8+
import org.springframework.data.jdbc.repository.config.EnableJdbcRepositories;
9+
import tech.ydb.data.repository.support.SimpleYdbJdbcRepository;
10+
11+
/**
12+
* @author Madiyar Nurgazin
13+
*/
14+
@Target(ElementType.TYPE)
15+
@Retention(RetentionPolicy.RUNTIME)
16+
@EnableJdbcRepositories(repositoryBaseClass = SimpleYdbJdbcRepository.class)
17+
public @interface EnableYdbRepositories {
18+
}

spring-data-dialect/src/main/java/tech/ydb/data/config/YdbDialectProvider.java renamed to spring-data-dialect/src/main/java/tech/ydb/data/repository/config/YdbDialectProvider.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package tech.ydb.data.config;
1+
package tech.ydb.data.repository.config;
22

33
import java.sql.Connection;
44
import java.sql.SQLException;
@@ -16,11 +16,11 @@
1616
* @author Madiyar Nurgazin
1717
*/
1818
public class YdbDialectProvider extends DialectResolver.DefaultDialectProvider {
19-
2019
@Override
2120
public Optional<Dialect> getDialect(JdbcOperations operations) {
2221
Optional<Dialect> ydbDialect = Optional.ofNullable(
23-
operations.execute((ConnectionCallback<Dialect>) YdbDialectProvider::getDialect));
22+
operations.execute((ConnectionCallback<Dialect>) YdbDialectProvider::getDialect)
23+
);
2424

2525
if (ydbDialect.isPresent()) {
2626
return ydbDialect;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package tech.ydb.data.repository.support;
2+
3+
import org.springframework.data.jdbc.core.JdbcAggregateOperations;
4+
import org.springframework.data.jdbc.core.convert.JdbcConverter;
5+
import org.springframework.data.jdbc.repository.support.SimpleJdbcRepository;
6+
import org.springframework.data.mapping.PersistentEntity;
7+
import org.springframework.transaction.annotation.Transactional;
8+
import tech.ydb.data.repository.YdbCrudRepository;
9+
import tech.ydb.data.repository.YdbPagingAndSortingRepository;
10+
11+
/**
12+
* @author Madiyar Nurgazin
13+
*/
14+
@Transactional(readOnly = true)
15+
public class SimpleYdbJdbcRepository<T, ID> extends SimpleJdbcRepository<T, ID>
16+
implements YdbCrudRepository<T, ID>, YdbPagingAndSortingRepository<T, ID> {
17+
private final JdbcAggregateOperations entityOperations;
18+
19+
public SimpleYdbJdbcRepository(
20+
JdbcAggregateOperations entityOperations, PersistentEntity<T, ?> entity, JdbcConverter converter
21+
) {
22+
super(entityOperations, entity, converter);
23+
this.entityOperations = entityOperations;
24+
}
25+
26+
@Transactional
27+
@Override
28+
public <S extends T> S insert(S entity) {
29+
return entityOperations.insert(entity);
30+
}
31+
32+
@Transactional
33+
@Override
34+
public <S extends T> S update(S entity) {
35+
return entityOperations.update(entity);
36+
}
37+
38+
@Transactional
39+
@Override
40+
public <S extends T> Iterable<S> insertAll(Iterable<S> entities) {
41+
return entityOperations.insertAll(entities);
42+
}
43+
44+
@Transactional
45+
@Override
46+
public <S extends T> Iterable<S> updateAll(Iterable<S> entities) {
47+
return entityOperations.updateAll(entities);
48+
}
49+
}

spring-data-dialect/src/main/java/tech/ydb/data/support/YdbJdbcUtil.java renamed to spring-data-dialect/src/main/java/tech/ydb/data/repository/support/YdbJdbcUtil.java

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package tech.ydb.data.support;
1+
package tech.ydb.data.repository.support;
22

33
import java.sql.JDBCType;
44
import java.sql.SQLType;
@@ -15,12 +15,12 @@
1515
* @author Madiyar Nurgazin
1616
*/
1717
public final class YdbJdbcUtil {
18-
private static final Map<Class<?>, SQLType> sqlTypeMappings = new HashMap<>();
18+
private static final Map<Class<?>, SQLType> sqlTypeByClass = new HashMap<>();
1919

2020
static {
21-
sqlTypeMappings.put(LocalDateTime.class, JDBCType.TIME);
22-
sqlTypeMappings.put(LocalDate.class, JDBCType.DATE);
23-
sqlTypeMappings.put(Instant.class, JDBCType.TIMESTAMP);
21+
sqlTypeByClass.put(LocalDateTime.class, JDBCType.TIME);
22+
sqlTypeByClass.put(LocalDate.class, JDBCType.DATE);
23+
sqlTypeByClass.put(Instant.class, JDBCType.TIMESTAMP);
2424
}
2525

2626
private YdbJdbcUtil() {
@@ -30,10 +30,10 @@ private YdbJdbcUtil() {
3030
public static SQLType targetSqlTypeFor(Class<?> type) {
3131
Assert.notNull(type, "Type must not be null");
3232

33-
return sqlTypeMappings.keySet().stream() //
33+
return sqlTypeByClass.keySet().stream() //
3434
.filter(k -> k.isAssignableFrom(type)) //
3535
.findFirst() //
36-
.map(sqlTypeMappings::get) //
36+
.map(sqlTypeByClass::get) //
3737
.orElse(JdbcUtil.targetSqlTypeFor(type));
3838
}
3939
}
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
org.springframework.data.jdbc.repository.config.DialectResolver$JdbcDialectProvider=tech.ydb.data.config.YdbDialectProvider
1+
org.springframework.data.jdbc.repository.config.DialectResolver$JdbcDialectProvider=tech.ydb.data.repository.config.YdbDialectProvider

spring-data-dialect/src/test/java/tech/ydb/data/YdbBaseTest.java

+2
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@
55
import org.springframework.boot.test.context.SpringBootTest;
66
import org.springframework.test.context.DynamicPropertyRegistry;
77
import org.springframework.test.context.DynamicPropertySource;
8+
import org.springframework.transaction.annotation.Transactional;
89
import tech.ydb.test.junit5.YdbHelperExtension;
910

1011
/**
1112
* @author Madiyar Nurgazin
1213
*/
1314
@SpringBootTest(classes = YdbJdbcConfiguration.class)
1415
@AutoConfigureDataJdbc
16+
@Transactional
1517
public abstract class YdbBaseTest {
1618
@RegisterExtension
1719
private static final YdbHelperExtension ydb = new YdbHelperExtension();

0 commit comments

Comments
 (0)