Skip to content

Commit cd26958

Browse files
feat: simple app spring data jdbc (#38)
1 parent a4aa8ab commit cd26958

File tree

10 files changed

+517
-0
lines changed

10 files changed

+517
-0
lines changed

jdbc/pom.xml

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
<module>spring-flyway-app</module>
5252
<module>spring-liquibase-app</module>
5353
<module>shedlock</module>
54+
<module>spring-data-jdbc</module>
5455
</modules>
5556
</profile>
5657
</profiles>

jdbc/spring-data-jdbc/pom.xml

+155
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
2+
<modelVersion>4.0.0</modelVersion>
3+
<parent>
4+
<groupId>tech.ydb.jdbc.examples</groupId>
5+
<artifactId>ydb-jdbc-examples</artifactId>
6+
<version>1.1.0-SNAPSHOT</version>
7+
</parent>
8+
<dependencyManagement>
9+
<dependencies>
10+
<dependency>
11+
<groupId>org.springframework.boot</groupId>
12+
<artifactId>spring-boot-dependencies</artifactId>
13+
<version>3.2.1</version>
14+
<scope>import</scope>
15+
<type>pom</type>
16+
</dependency>
17+
</dependencies>
18+
</dependencyManagement>
19+
<artifactId>spring-data-jdbc</artifactId>
20+
<name>Spring Data JDBC Example</name>
21+
<description>Basic example for Spring Boot JDBC</description>
22+
<properties>
23+
<maven.compiler.release>17</maven.compiler.release>
24+
<kotlin.version>1.9.22</kotlin.version>
25+
<spring.data.jdbc.ydb.version>0.9.1</spring.data.jdbc.ydb.version>
26+
<spring.boot.version>3.2.1</spring.boot.version>
27+
<flyway.version>10.7.1</flyway.version>
28+
</properties>
29+
<dependencies>
30+
<dependency>
31+
<groupId>org.springframework.data</groupId>
32+
<artifactId>spring-data-jdbc</artifactId>
33+
</dependency>
34+
<dependency>
35+
<groupId>org.springframework.boot</groupId>
36+
<artifactId>spring-boot-autoconfigure</artifactId>
37+
</dependency>
38+
<dependency>
39+
<groupId>org.flywaydb</groupId>
40+
<artifactId>flyway-core</artifactId>
41+
<version>${flyway.version}</version>
42+
</dependency>
43+
<dependency>
44+
<groupId>tech.ydb.dialects</groupId>
45+
<artifactId>flyway-ydb-dialect</artifactId>
46+
<version>1.0.0-RC0</version>
47+
</dependency>
48+
<dependency>
49+
<groupId>org.springframework.boot</groupId>
50+
<artifactId>spring-boot-starter-jdbc</artifactId>
51+
</dependency>
52+
<dependency>
53+
<groupId>org.jetbrains.kotlin</groupId>
54+
<artifactId>kotlin-reflect</artifactId>
55+
<version>${kotlin.version}</version>
56+
</dependency>
57+
<dependency>
58+
<groupId>org.jetbrains.kotlin</groupId>
59+
<artifactId>kotlin-stdlib</artifactId>
60+
<version>${kotlin.version}</version>
61+
</dependency>
62+
<dependency>
63+
<groupId>tech.ydb.dialects</groupId>
64+
<artifactId>spring-data-jdbc-ydb</artifactId>
65+
<version>${spring.data.jdbc.ydb.version}</version>
66+
</dependency>
67+
<dependency>
68+
<groupId>tech.ydb.jdbc</groupId>
69+
<artifactId>ydb-jdbc-driver</artifactId>
70+
</dependency>
71+
<dependency>
72+
<groupId>com.github.javafaker</groupId>
73+
<artifactId>javafaker</artifactId>
74+
<version>1.0.2</version>
75+
</dependency>
76+
<dependency>
77+
<groupId>org.jetbrains.kotlinx</groupId>
78+
<artifactId>kotlinx-coroutines-core</artifactId>
79+
<version>1.7.3</version>
80+
</dependency>
81+
82+
<dependency>
83+
<groupId>org.springframework.boot</groupId>
84+
<artifactId>spring-boot-starter-test</artifactId>
85+
<version>${spring.boot.version}</version>
86+
<scope>test</scope>
87+
</dependency>
88+
<dependency>
89+
<groupId>tech.ydb.test</groupId>
90+
<artifactId>ydb-junit5-support</artifactId>
91+
<scope>test</scope>
92+
</dependency>
93+
</dependencies>
94+
<build>
95+
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
96+
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
97+
<plugins>
98+
<plugin>
99+
<groupId>org.apache.maven.plugins</groupId>
100+
<artifactId>maven-surefire-plugin</artifactId>
101+
<configuration>
102+
<environmentVariables>
103+
<TESTCONTAINERS_REUSE_ENABLE>true</TESTCONTAINERS_REUSE_ENABLE>
104+
</environmentVariables>
105+
</configuration>
106+
</plugin>
107+
<plugin>
108+
<groupId>org.springframework.boot</groupId>
109+
<artifactId>spring-boot-maven-plugin</artifactId>
110+
<version>${spring.boot.version}</version>
111+
</plugin>
112+
<plugin>
113+
<groupId>org.jetbrains.kotlin</groupId>
114+
<artifactId>kotlin-maven-plugin</artifactId>
115+
<version>${kotlin.version}</version>
116+
<executions>
117+
<execution>
118+
<id>compile</id>
119+
<phase>compile</phase>
120+
<goals>
121+
<goal>compile</goal>
122+
</goals>
123+
</execution>
124+
<execution>
125+
<id>test-compile</id>
126+
<goals>
127+
<goal>test-compile</goal>
128+
</goals>
129+
</execution>
130+
</executions>
131+
<configuration>
132+
<args>
133+
<arg>-Xjsr305=strict</arg>
134+
</args>
135+
<compilerPlugins>
136+
<plugin>spring</plugin>
137+
<plugin>jpa</plugin>
138+
</compilerPlugins>
139+
</configuration>
140+
<dependencies>
141+
<dependency>
142+
<groupId>org.jetbrains.kotlin</groupId>
143+
<artifactId>kotlin-maven-allopen</artifactId>
144+
<version>${kotlin.version}</version>
145+
</dependency>
146+
<dependency>
147+
<groupId>org.jetbrains.kotlin</groupId>
148+
<artifactId>kotlin-maven-noarg</artifactId>
149+
<version>${kotlin.version}</version>
150+
</dependency>
151+
</dependencies>
152+
</plugin>
153+
</plugins>
154+
</build>
155+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package tech.ydb.jdbc.simple
2+
3+
import org.springframework.data.domain.Limit
4+
import org.springframework.data.domain.Pageable
5+
import org.springframework.data.domain.Slice
6+
import org.springframework.data.domain.Sort
7+
import org.springframework.data.jdbc.repository.query.Query
8+
import org.springframework.data.repository.ListCrudRepository
9+
import tech.ydb.data.repository.ViewIndex
10+
11+
/**
12+
* Simple repository interface for {@link User} instances. The interface is used to declare the so-called query methods,
13+
* i.e. methods to retrieve single entities or collections of them.
14+
*/
15+
interface SimpleUserRepository : ListCrudRepository<User, Long> {
16+
17+
/**
18+
* Uses {@link Optional} as return and parameter type.
19+
*
20+
* @param username
21+
*/
22+
@ViewIndex(indexName = "username_index")
23+
fun findByUsername(username: String): User?
24+
25+
/**
26+
* Find all users with the given lastname. This method will be translated into a query by constructing it directly
27+
* from the method name as there is no other query declared.
28+
*
29+
* @param lastname
30+
*/
31+
fun findByLastname(lastname: String): List<User>
32+
33+
/**
34+
* Find at most the number of users defined via maxResults with the given lastname.
35+
* This method will be translated into a query by constructing it directly from the method name as there is no other
36+
* query declared.
37+
*
38+
* @param lastname
39+
* @param maxResults the maximum number of results returned.
40+
*/
41+
42+
fun findByLastname(lastname: String, maxResults: Limit): List<User>
43+
44+
/**
45+
* Returns at most the number of users defined via {@link Limit} with the given firstname. This method will be
46+
* translated into a query using the one declared in the {@link Query} annotation declared one.
47+
*
48+
* @param firstname
49+
* @param maxResults the maximum number of results returned.
50+
*/
51+
fun findByFirstname(firstname: String, maxResults: Limit): List<User>
52+
53+
/**
54+
* Returns all users with the given name as first- or lastname. This makes the query to method relation much more
55+
* refactoring-safe as the order of the method parameters is completely irrelevant.
56+
*
57+
* @param name
58+
*/
59+
@Query("select * from Users u where u.firstname = :name or u.lastname = :name")
60+
fun findByFirstnameOrLastname(name: String): List<User>
61+
62+
/**
63+
* Returns a {@link Slice} counting a maximum number of {@link Pageable#getPageSize()} users matching given criteria
64+
* starting at {@link Pageable#getOffset()} without prior count of the total number of elements available.
65+
*
66+
* @param lastname
67+
* @param page
68+
*/
69+
fun findByLastnameOrderByUsernameAsc(lastname: String, page: Pageable): Slice<User>
70+
71+
/**
72+
* Return the first 2 users ordered by their lastname asc.
73+
*
74+
* <pre>
75+
* Example for findFirstK / findTopK functionality.
76+
* </pre>
77+
*/
78+
fun findFirst2ByOrderByLastnameAsc(): List<User>
79+
80+
/**
81+
* Return the first 2 users ordered by the given {@code sort} definition.
82+
*
83+
* <pre>
84+
* This variant is very flexible because one can ask for the first K results when a ASC ordering
85+
* is used as well as for the last K results when a DESC ordering is used.
86+
* </pre>
87+
*
88+
* @param sort
89+
*/
90+
fun findTop2By(sort: Sort): List<User>
91+
92+
/**
93+
* Return all the users with the given firstname or lastname. Makes use of SpEL (Spring Expression Language).
94+
*
95+
* @param user
96+
*/
97+
@Query("select * from Users u where u.firstname = :#{#user.firstname} or u.lastname = :#{#user.lastname}")
98+
fun findByFirstnameOrLastname(user: User): Iterable<User>
99+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package tech.ydb.jdbc.simple
2+
3+
import org.springframework.data.annotation.Id
4+
import org.springframework.data.annotation.Transient
5+
import org.springframework.data.domain.Persistable
6+
import org.springframework.data.relational.core.mapping.Table
7+
import org.springframework.data.util.ProxyUtils
8+
import java.util.concurrent.ThreadLocalRandom
9+
10+
@Table(name = "Users")
11+
class User : Persistable<Long> {
12+
13+
@Id
14+
var id: Long = ThreadLocalRandom.current().nextLong()
15+
16+
lateinit var username: String
17+
18+
lateinit var firstname: String
19+
20+
lateinit var lastname: String
21+
22+
@Transient
23+
var new = true
24+
25+
override fun equals(other: Any?): Boolean {
26+
if (null == other) {
27+
return false
28+
}
29+
30+
if (this === other) {
31+
return true
32+
}
33+
34+
if (javaClass != ProxyUtils.getUserClass(other)) {
35+
return false
36+
}
37+
38+
val that: User = other as User
39+
40+
return this.id == that.id
41+
}
42+
43+
override fun hashCode(): Int {
44+
var hashCode = 17
45+
46+
hashCode += id.hashCode() * 31
47+
48+
return hashCode
49+
}
50+
51+
override fun getId() = id
52+
override fun isNew() = new
53+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package tech.ydb.jdbc.simple
2+
3+
import org.springframework.boot.autoconfigure.SpringBootApplication
4+
import org.springframework.data.jdbc.repository.config.EnableJdbcRepositories
5+
6+
/**
7+
* @author Kirill Kurdyukov
8+
*/
9+
@EnableJdbcRepositories
10+
@SpringBootApplication
11+
class UserApplication
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
spring.datasource.driver-class-name=tech.ydb.jdbc.YdbDriver
2+
spring.datasource.url=jdbc:ydb:grpc://localhost:2136/local
3+
4+
logging.level.org.springframework.jdbc.core.JdbcTemplate=debug
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package tech.ydb.jdbc
2+
3+
import org.junit.jupiter.api.extension.RegisterExtension
4+
import org.springframework.test.context.ActiveProfiles
5+
import org.springframework.test.context.DynamicPropertyRegistry
6+
import org.springframework.test.context.DynamicPropertySource
7+
import tech.ydb.test.junit5.YdbHelperExtension
8+
9+
/**
10+
* @author Kirill Kurdyukov
11+
*/
12+
@ActiveProfiles("test", "ydb")
13+
abstract class YdbDockerTest {
14+
15+
companion object {
16+
@JvmField
17+
@RegisterExtension
18+
val ydb = YdbHelperExtension()
19+
20+
@JvmStatic
21+
@DynamicPropertySource
22+
fun propertySource(registry: DynamicPropertyRegistry) {
23+
registry.add("spring.datasource.url") {
24+
"jdbc:ydb:${if (ydb.useTls()) "grpcs://" else "grpc://"}" +
25+
"${ydb.endpoint()}${ydb.database()}${ydb.authToken()?.let { "?token=$it" } ?: ""}"
26+
}
27+
}
28+
}
29+
}

0 commit comments

Comments
 (0)