Skip to content

Commit e5410a1

Browse files
authored
feat(spring-data): add tarantool-spring-data-40 module
1 parent 94f49a0 commit e5410a1

File tree

96 files changed

+10089
-2
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

96 files changed

+10089
-2
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## [Unreleased]
44

5+
### Spring-data
6+
7+
- Add `tarantool-spring-data-40` module with support for Spring Boot 4.0.x and Spring Data 4.0.x
8+
59
## [1.6.0] - 2026-04-01
610

711
### BOM Module

tarantool-spring-data/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
<module>tarantool-spring-data-33</module>
2525
<module>tarantool-spring-data-34</module>
2626
<module>tarantool-spring-data-35</module>
27+
<module>tarantool-spring-data-40</module>
2728
</modules>
2829

2930
<properties>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<name>tarantool-spring-data-40</name>
8+
<description>Minimalistic java connector for Tarantool versions 2.11+ based on Netty framework</description>
9+
<url>https://tarantool.io</url>
10+
11+
<parent>
12+
<groupId>io.tarantool</groupId>
13+
<artifactId>tarantool-spring-data</artifactId>
14+
<version>2.0.0-SNAPSHOT</version>
15+
</parent>
16+
17+
<artifactId>tarantool-spring-data-40</artifactId>
18+
<packaging>jar</packaging>
19+
20+
<properties>
21+
<!-- Recommended Java version is 25, minimal version is 17 -->
22+
<maven.compiler.release>17</maven.compiler.release>
23+
<spring.boot.version>4.0.4</spring.boot.version>
24+
<shared.dir>${project.parent.parent.basedir}/tarantool-shared-resources/</shared.dir>
25+
<license.header.file>${project.parent.parent.basedir}/LICENSE_HEADER.txt</license.header.file>
26+
<!-- Spring Framework 7.x uses JUnit 6 -->
27+
<junit.version>6.0.3</junit.version>
28+
</properties>
29+
30+
<dependencies>
31+
<dependency>
32+
<groupId>io.tarantool</groupId>
33+
<artifactId>tarantool-spring-data-core</artifactId>
34+
</dependency>
35+
</dependencies>
36+
</project>
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Copyright (c) 2025 VK DIGITAL TECHNOLOGIES LIMITED LIABILITY COMPANY
3+
* All Rights Reserved.
4+
*/
5+
6+
package io.tarantool.spring.data40;
7+
8+
import java.util.Map;
9+
10+
import org.jspecify.annotations.NonNull;
11+
import org.springframework.data.keyvalue.core.AbstractKeyValueAdapter;
12+
import org.springframework.data.util.CloseableIterator;
13+
14+
import io.tarantool.client.box.TarantoolBoxClient;
15+
import io.tarantool.spring.data.ProxyTarantoolBoxKeyValueAdapter;
16+
17+
public class TarantoolBoxKeyValueAdapter extends AbstractKeyValueAdapter {
18+
19+
private final ProxyTarantoolBoxKeyValueAdapter adapter;
20+
21+
public TarantoolBoxKeyValueAdapter(@NonNull TarantoolBoxClient tarantoolBoxClient) {
22+
adapter = new ProxyTarantoolBoxKeyValueAdapter(tarantoolBoxClient);
23+
}
24+
25+
@Override
26+
public Object put(@NonNull Object id, @NonNull Object item, @NonNull String keyspace) {
27+
return adapter.put(id, item, keyspace);
28+
}
29+
30+
@Override
31+
public boolean contains(@NonNull Object id, @NonNull String keyspace) {
32+
return adapter.contains(id, keyspace);
33+
}
34+
35+
@Override
36+
public Object get(@NonNull Object id, @NonNull String keyspace) {
37+
return adapter.get(id, keyspace);
38+
}
39+
40+
@Override
41+
public Object delete(@NonNull Object id, @NonNull String keyspace) {
42+
return adapter.delete(id, keyspace);
43+
}
44+
45+
@Override
46+
@NonNull
47+
public Iterable<Object> getAllOf(@NonNull String keyspace) {
48+
return adapter.getAllOf(keyspace);
49+
}
50+
51+
@Override
52+
public void deleteAllOf(@NonNull String keyspace) {
53+
adapter.deleteAllOf(keyspace);
54+
}
55+
56+
@Override
57+
public void clear() {
58+
adapter.clear();
59+
}
60+
61+
@Override
62+
public long count(@NonNull String keyspace) {
63+
return adapter.count(keyspace);
64+
}
65+
66+
@Override
67+
public void destroy() throws Exception {
68+
adapter.destroy();
69+
}
70+
71+
@Override
72+
@NonNull
73+
public CloseableIterator<Map.Entry<Object, Object>> entries(@NonNull String keyspace) {
74+
throw new UnsupportedOperationException("Not implemented yet");
75+
}
76+
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
* Copyright (c) 2025 VK DIGITAL TECHNOLOGIES LIMITED LIABILITY COMPANY
3+
* All Rights Reserved.
4+
*/
5+
6+
package io.tarantool.spring.data40;
7+
8+
import java.util.Collections;
9+
import java.util.Map.Entry;
10+
11+
import com.fasterxml.jackson.annotation.JsonFormat;
12+
import org.jspecify.annotations.NonNull;
13+
import org.springframework.core.annotation.AnnotatedElementUtils;
14+
import org.springframework.data.keyvalue.core.AbstractKeyValueAdapter;
15+
import org.springframework.data.util.CloseableIterator;
16+
17+
import io.tarantool.client.crud.TarantoolCrudClient;
18+
import io.tarantool.spring.data.ProxyTarantoolCrudKeyValueAdapter;
19+
import io.tarantool.spring.data.mapping.model.CompositeKey;
20+
21+
public class TarantoolCrudKeyValueAdapter extends AbstractKeyValueAdapter {
22+
23+
private final ProxyTarantoolCrudKeyValueAdapter adapter;
24+
25+
public TarantoolCrudKeyValueAdapter(@NonNull TarantoolCrudClient client) {
26+
super(new TarantoolQueryEngine(client));
27+
this.adapter = new ProxyTarantoolCrudKeyValueAdapter(client);
28+
}
29+
30+
@Override
31+
public Object put(@NonNull Object id, @NonNull Object item, @NonNull String keyspace) {
32+
return adapter.put(convertId(id), item, keyspace);
33+
}
34+
35+
@Override
36+
public boolean contains(@NonNull Object id, @NonNull String keyspace) {
37+
return adapter.contains(convertId(id), keyspace);
38+
}
39+
40+
@Override
41+
public Object get(@NonNull Object id, @NonNull String keyspace) {
42+
return adapter.get(convertId(id), keyspace);
43+
}
44+
45+
@Override
46+
public <T> T get(@NonNull Object id, @NonNull String keyspace, @NonNull Class<T> type) {
47+
return adapter.get(convertId(id), keyspace, type);
48+
}
49+
50+
@Override
51+
public Object delete(@NonNull Object id, @NonNull String keyspace) {
52+
return adapter.delete(convertId(id), keyspace);
53+
}
54+
55+
@Override
56+
public <T> T delete(@NonNull Object id, @NonNull String keyspace, @NonNull Class<T> type) {
57+
return adapter.delete(convertId(id), keyspace, type);
58+
}
59+
60+
@Override
61+
@NonNull
62+
public Iterable<Object> getAllOf(@NonNull String keyspace) {
63+
return adapter.getAllOf(keyspace);
64+
}
65+
66+
@Override
67+
public void deleteAllOf(String keyspace) {
68+
adapter.deleteAllOf(keyspace);
69+
}
70+
71+
@Override
72+
public void clear() {
73+
adapter.clear();
74+
}
75+
76+
@Override
77+
public void destroy() throws Exception {
78+
adapter.destroy();
79+
}
80+
81+
@Override
82+
public long count(String keyspace) {
83+
return adapter.count(keyspace);
84+
}
85+
86+
@Override
87+
public CloseableIterator<Entry<Object, Object>> entries(String keyspace) {
88+
throw new UnsupportedOperationException("Not implemented yet");
89+
}
90+
91+
/**
92+
* Convert the identifier to the form required by the tarantool-java-sdk driver.
93+
*
94+
* @param id identifier object
95+
* @return identifier in the required form
96+
*/
97+
private Object convertId(Object id) {
98+
if (id instanceof CompositeKey || hasJsonFormatArrayAnnotation(id)) {
99+
return id;
100+
}
101+
return Collections.singletonList(id);
102+
}
103+
104+
/**
105+
* Determine whether the identifier type is annotated with the {@link JsonFormat} annotation.
106+
*
107+
* @param id identifier object
108+
* @return return true if the annotation is present, false otherwise
109+
*/
110+
private boolean hasJsonFormatArrayAnnotation(Object id) {
111+
final JsonFormat jsonFormatAnnotation =
112+
AnnotatedElementUtils.findMergedAnnotation(id.getClass(), JsonFormat.class);
113+
114+
return jsonFormatAnnotation != null
115+
&& JsonFormat.Shape.ARRAY.equals(jsonFormatAnnotation.shape());
116+
}
117+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* Copyright (c) 2025 VK DIGITAL TECHNOLOGIES LIMITED LIABILITY COMPANY
3+
* All Rights Reserved.
4+
*/
5+
6+
package io.tarantool.spring.data40;
7+
8+
import java.util.Collection;
9+
import java.util.Comparator;
10+
import java.util.Map.Entry;
11+
12+
import org.jspecify.annotations.NonNull;
13+
import org.jspecify.annotations.Nullable;
14+
import org.springframework.data.keyvalue.core.QueryEngine;
15+
16+
import io.tarantool.client.crud.TarantoolCrudClient;
17+
import io.tarantool.spring.data.ProxyTarantoolQueryEngine;
18+
import io.tarantool.spring.data.query.TarantoolCriteria;
19+
import io.tarantool.spring.data40.query.TarantoolCriteriaAccessor;
20+
import io.tarantool.spring.data40.query.TarantoolSortAccessor;
21+
22+
/**
23+
* Implementation of {@code findBy*()} and {@code countBy*{}} queries.
24+
*
25+
* @author Artyom Dubinin
26+
*/
27+
public class TarantoolQueryEngine
28+
extends QueryEngine<TarantoolCrudKeyValueAdapter, TarantoolCriteria, Comparator<Entry<?, ?>>> {
29+
30+
private final ProxyTarantoolQueryEngine engine;
31+
32+
public TarantoolQueryEngine(TarantoolCrudClient client) {
33+
super(new TarantoolCriteriaAccessor(), new TarantoolSortAccessor());
34+
this.engine = new ProxyTarantoolQueryEngine(client);
35+
}
36+
37+
@Override
38+
@NonNull
39+
public Collection<?> execute(
40+
@Nullable final TarantoolCriteria criteria,
41+
@Nullable final Comparator<Entry<?, ?>> sort,
42+
final long offset,
43+
final int rows,
44+
@NonNull final String keyspace) {
45+
return engine.execute(criteria, sort, offset, rows, keyspace);
46+
}
47+
48+
/**
49+
* Construct the final query predicate for Tarantool to execute, from the base query plus any
50+
* paging and sorting.
51+
*
52+
* <p>Variations here allow the base query predicate to be omitted, sorting to be omitted, and
53+
* paging to be omitted.
54+
*
55+
* @param criteria Search criteria, null means match everything
56+
* @param sort Possibly null collation
57+
* @param offset Start point of returned page, -1 if not used
58+
* @param rows Size of page, -1 if not used
59+
* @param keyspace The map name
60+
* @return Results from Tarantool
61+
*/
62+
@Override
63+
@NonNull
64+
public <T> Collection<T> execute(
65+
@Nullable final TarantoolCriteria criteria,
66+
@Nullable final Comparator<Entry<?, ?>> sort,
67+
final long offset,
68+
final int rows,
69+
@NonNull final String keyspace,
70+
@NonNull Class<T> type) {
71+
return engine.execute(criteria, sort, offset, rows, keyspace, type);
72+
}
73+
74+
/**
75+
* Execute {@code countBy*()} queries against a Tarantool space.
76+
*
77+
* @param criteria Predicate to use, not null
78+
* @param keyspace The map name
79+
* @return Results from Tarantool
80+
*/
81+
@Override
82+
public long count(@Nullable final TarantoolCriteria criteria, @NonNull final String keyspace) {
83+
return engine.count(criteria, keyspace);
84+
}
85+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright (c) 2025 VK DIGITAL TECHNOLOGIES LIMITED LIABILITY COMPANY
3+
* All Rights Reserved.
4+
*/
5+
6+
package io.tarantool.spring.data40.config;
7+
8+
import org.springframework.beans.factory.ObjectProvider;
9+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
10+
import org.springframework.context.annotation.Bean;
11+
import org.springframework.context.annotation.Configuration;
12+
13+
import static io.tarantool.spring.data.TarantoolBeanNames.DEFAULT_TARANTOOL_BOX_CLIENT_BEAN_REF;
14+
import static io.tarantool.spring.data.TarantoolBeanNames.DEFAULT_TARANTOOL_BOX_KEY_VALUE_ADAPTER_REF;
15+
import io.tarantool.client.box.TarantoolBoxClient;
16+
import io.tarantool.client.factory.TarantoolBoxClientBuilder;
17+
import io.tarantool.spring.data.config.BaseTarantoolBoxConfiguration;
18+
import io.tarantool.spring.data40.TarantoolBoxKeyValueAdapter;
19+
import io.tarantool.spring.data40.config.properties.TarantoolProperties;
20+
21+
@Configuration(proxyBeanMethods = false)
22+
public class TarantoolBoxConfiguration extends BaseTarantoolBoxConfiguration {
23+
24+
public TarantoolBoxConfiguration(
25+
ObjectProvider<TarantoolProperties> properties,
26+
ObjectProvider<TarantoolBoxClientBuilder> tarantoolBoxClientBuilder) {
27+
super(properties.getIfAvailable(), tarantoolBoxClientBuilder.getIfAvailable());
28+
}
29+
30+
@Bean(name = DEFAULT_TARANTOOL_BOX_KEY_VALUE_ADAPTER_REF)
31+
@ConditionalOnMissingBean(TarantoolBoxKeyValueAdapter.class)
32+
public TarantoolBoxKeyValueAdapter tarantoolCrudKeyValueAdapter(
33+
TarantoolBoxClient tarantoolBoxClient) {
34+
return new TarantoolBoxKeyValueAdapter(tarantoolBoxClient);
35+
}
36+
37+
@Bean(name = DEFAULT_TARANTOOL_BOX_CLIENT_BEAN_REF)
38+
@ConditionalOnMissingBean(TarantoolBoxClient.class)
39+
public TarantoolBoxClient tarantoolBoxClient() throws Exception {
40+
return super.tarantoolBoxClient();
41+
}
42+
43+
@Override
44+
public TarantoolBoxClientBuilder getClientBuilder() {
45+
return super.getClientBuilder();
46+
}
47+
}

0 commit comments

Comments
 (0)