SlideShare a Scribd company logo
Requery
Coupang Catalog Platform & Quality

debop@coupang.com
Agenda
• Requery Overview 

• Why Requery

• Requery Build process

• Define Mapping

• Usage EntityDataStore

• EntityDataStore for Kotlin (Coroutines)

• Introduction of Spring Data Requery
Requery Overview
• ORM Library for Java, Kotlin, Android

• No Reflection (vs Hibernate proxy)

• Typed Query language (vs Hibernate Criteria)

• Upsert/Partial objects refresh

• Compile time entity/query validation (vs Hibernate)

• Entity is stateless (vs Hibernate stateful)

• Thread 에 제한 받지 않음 (JPA EntityManager)

• Support RxJava, Async Operations, Java 8
Why Requery
• Provide benefit of ORM

• Entity Mapping

• Schema Generation

• Compile time error detecting

• Performance 

• When bulk job, max 100x than JPA

• REST API - 2~10x throughput

• Support Upsert, Lazy loading …
Requery Build Process - Java
Define Entity Annotation Processing
buildscript {
repositories {
jcenter()
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
// for Java apt
classpath "net.ltgt.gradle:gradle-apt-plugin:0.15"
}
}
// lombok을 gradle 에서 사용하기 위한 plugin
plugins {
id 'io.franzbecker.gradle-lombok' version '1.14'
}
// lombok을 gradle 에서 사용하기 위해 annotation process를 설정해주어야 합니다.
compileOnly "org.projectlombok:lombok"
annotationProcessor "org.projectlombok:lombok"
testAnnotationProcessor "org.projectlombok:lombok"
annotationProcessor "io.requery:requery-processor"
testAnnotationProcessor "io.requery:requery-processor"
EntityDataStore<Object>
Requery Build Process - Kotlin
Define Entity Annotation Processing KotlinEntityDataStore<Any>
// for kotlin entity
kapt "io.requery:requery-processor"
kaptTest "io.requery:requery-processor"
IntelliJ IDEA Settings
IDEA 상에서 테스트 작업 시 자동으로
apt task를 먼저 수행해 준다.
Define Entity - Java
@Getter
@Entity(name = "BasicUser", copyable = true)
@Table(name = "basic_user")
public abstract class AbstractBasicUser extends AuditableLongEntity {
@Key
@Generated
protected Long id;
protected String name;
protected String email;
protected LocalDate birthday;
protected Integer age;
@ForeignKey
@OneToOne
protected AbstractBasicLocation address;
@ManyToMany(mappedBy = "members")
protected Set<AbstractBasicGroup> groups;
@Column(unique = true)
protected UUID uuid;
@Override
public int hashCode() {
return Objects.hash(name, email, birthday);
}
@Transient
@Override
protected @NotNull ToStringBuilder buildStringHelper() {
return super.buildStringHelper()
.add("name", name)
.add("email", email)
.add("birthday", birthday);
}
private static final long serialVersionUID = -2693264826800934057L;
}
Define Entity - Kotlin
@Entity(model = "functional")
interface Person: Persistable {
@get:Key
@get:Generated
val id: Long
@get:Index(value = ["idx_person_name_email"])
var name: String
@get:Index(value = ["idx_person_name_email", "idx_person_email"])
var email: String
var birthday: LocalDate
@get:Column(value = "'empty'")
var description: String?
@get:Nullable
var age: Int?
@get:ForeignKey
@get:OneToOne(mappedBy = "person", cascade = [CascadeAction.DELETE, CascadeAction.SAVE])
var address: Address?
@get:OneToMany(mappedBy = "owner", cascade = [CascadeAction.DELETE, CascadeAction.SAVE])
val phoneNumbers: MutableSet<Phone>
@get:OneToMany
val phoneNumberList: MutableList<Phone>
@get:ManyToMany(mappedBy = "members")
val groups: MutableResult<Group>
@get:ManyToMany(mappedBy = "owners")
val ownedGroups: MutableResult<Group>
@get:ManyToMany(mappedBy = "id")
@get:JunctionTable
val friends: MutableSet<Person>
@get:Lazy
var about: String?
@get:Column(unique = true)
var uuid: UUID
var homepage: URL
var picture: String
}
EntityDataStore<Object>
• findByKey

• select / insert / update / upsert / delete 

• where / eq, lte, lt, gt, gte, like, in, not …

• groupBy / having / limit / offset

• support SQL Functions

• count, sum, avg, upper, lower …

• raw query
@Test
fun `insert user`() {
val user = RandomData.randomUser()
withDb(Models.DEFAULT) {
insert(user)
assertThat(user.id).isGreaterThan(0)
val loaded = select(User::class) where (User::id eq user.id) limit 10
assertThat(loaded.get().first()).isEqualTo(user)
}
}
val result = select(Location::class)
.join(User::class).on(User::location eq Location::id)
.where(User::id eq user.id)
.orderBy(Location::city.desc())
.get()
val result = raw(User::class, "SELECT * FROM Users")
val rowCount = update(UserEntity::class)
.set(UserEntity.ABOUT, "nothing")
.set(UserEntity.AGE, 50)
.where(UserEntity.AGE eq 100)
.get()
.value()
val count = insert(PersonEntity::class, PersonEntity.NAME, PersonEntity.DESCRIPTION)
.query(select(GroupEntity.NAME, GroupEntity.DESCRIPTION))
.get()
.first()
.count()
CoroutineEntityDataStore
val store = CoroutineEntityStore(this)
runBlocking {
val users = store.insert(RandomData.randomUsers(10))
users.await().forEach { user ->
assertThat(user.id).isGreaterThan(0)
}
store
.count(UserEntity::class)
.get()
.toDeferred()
.await()
.let {
assertThat(it).isEqualTo(10)
}
}
with(coroutineTemplate) {
val user = randomUser()
// can replace with `withContext { }`
async { insert(user) }.await()
assertThat(user.id).isNotNull()
val group = RandomData.randomGroup()
group.members.add(user)
async { insert(group) }.await()
assertThat(user.groups).hasSize(1)
assertThat(group.members).hasSize(1)
}
spring-data-requery
• RequeryOperations

• Wrap EntityDataStore

• RequeryTransactionManager for
PlatformTransactionManager

•
spring-data-requery
• Repository built in SQL

• ByPropertyName Auto generation methods

• @Query for raw SQL Query

• Query By Example

• Not Supported

• Association Path (not specified join method)

• Named parameter in @Query (just use `?`)
Setup spring-data-requery
@Configuration
@EnableTransactionManagement
public class RequeryTestConfiguration extends AbstractRequeryConfiguration {
@Override
@Bean
public EntityModel getEntityModel() {
return Models.DEFAULT;
}
@Override
public TableCreationMode getTableCreationMode() {
return TableCreationMode.CREATE_NOT_EXISTS;
}
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.build();
}
}
Provided Beans
@Bean
public io.requery.sql.Configuration requeryConfiguration() {
return new ConfigurationBuilder(dataSource, getEntityModel())
// .useDefaultLogging()
.setEntityCache(new EmptyEntityCache())
.setStatementCacheSize(1024)
.setBatchUpdateSize(100)
.addStatementListener(new LogbackListener())
.build();
}
@Bean
public EntityDataStore<Object> entityDataStore() {
log.info("Create EntityDataStore instance.");
return new EntityDataStore<>(requeryConfiguration());
}
@Bean
public RequeryOperations requeryOperations() {
log.info("Create RequeryTemplate instance.");
return new RequeryTemplate(entityDataStore(), requeryMappingContext());
}
EntityCache 설정Tip :
개발 시에는 EmptyEntityCache,
운영 시에는 Cache2kEntityCache 사용
Use @Query in Repository
interface DeclaredQueryRepository extends RequeryRepository<BasicUser, Long> {
@Query("select * from basic_user u where u.email = ?")
BasicUser findByAnnotatedQuery(String email);
@Query("select * from basic_user u where u.email like ?")
List<BasicUser> findAllByEmailMatches(String email);
@Query("select * from basic_user u limit ?")
List<BasicUser> findWithLimits(int limit);
@Query("select * from basic_user u where u.name=? and u.email=? limit 1")
BasicUser findAllBy(String name, String email);
@Query("select u.id, u.name from basic_user u where u.email=?")
List<Tuple> findAllIds(String email);
@Query("select * from basic_user u where u.birthday = ?")
List<BasicUser> findByBirthday(LocalDate birthday);
}
Query By Example
BasicUser user = RandomData.randomUser();
user.setName("example");
requeryTemplate.insert(user);
BasicUser exampleUser = new BasicUser();
exampleUser.setName("EXA");
ExampleMatcher matcher = matching()
.withMatcher("name", startsWith().ignoreCase())
.withIgnoreNullValues();
Example<BasicUser> example = Example.of(exampleUser, matcher);
Return<? extends Result<BasicUser>> query = buildQueryByExample(example);
BasicUser foundUser = query.get().firstOrNull();
assertThat(foundUser).isNotNull().isEqualTo(user);
Query by Property - Not Yet
List<User> findByFirstnameOrLastname(@Param("lastname") String lastname, @Param("firstname") String firstname);
List<User> findByLastnameLikeOrderByFirstnameDesc(String lastname);
List<User> findByLastnameNotLike(String lastname);
List<User> findByLastnameNot(String lastname);
List<User> findByManagerLastname(String name);
List<User> findByColleaguesLastname(String lastname);
List<User> findByLastnameNotNull();
@Query("select u.lastname from SD_User u group by u.lastname")
Page<String> findByLastnameGrouped(Pageable pageable);
long countByLastname(String lastname);
int countUsersByFirstname(String firstname);
boolean existsByLastname(String lastname);
Note:Association Path is not supported
Note:Association Path is not supported
Resources
• requery.io 

• kotlinx-data-requery in coupang gitlab

• spring-data-requery in coupang gitlab
Q&A
Thank you!

More Related Content

What's hot (20)

PDF
Http4s, Doobie and Circe: The Functional Web Stack
GaryCoady
 
PPTX
BASTA 2013: Custom OData Provider
Rainer Stropek
 
PDF
Scala @ TechMeetup Edinburgh
Stuart Roebuck
 
PDF
#살아있다 #자프링외길12년차 #코프링2개월생존기
Arawn Park
 
PPTX
Demystifying Oak Search
Justin Edelson
 
PPT
55 New Features in Java 7
Boulder Java User's Group
 
PDF
Scala coated JVM
Stuart Roebuck
 
PPTX
Kotlin is charming; The reasons Java engineers should start Kotlin.
JustSystems Corporation
 
PDF
Scala active record
鉄平 土佐
 
PPTX
Getting started with Elasticsearch and .NET
Tomas Jansson
 
PPTX
Scoobi - Scala for Startups
bmlever
 
KEY
Python在豆瓣的应用
Qiangning Hong
 
PPTX
Akka Actor presentation
Gene Chang
 
PDF
Scalding for Hadoop
Chicago Hadoop Users Group
 
PDF
How and Where in GLORP
ESUG
 
PDF
Squeak DBX
ESUG
 
PDF
Ajax tutorial
Kat Roque
 
PPTX
ElasticSearch for .NET Developers
Ben van Mol
 
PDF
Scala at HUJI PL Seminar 2008
Yardena Meymann
 
PPTX
The CoFX Data Model
Rainer Stropek
 
Http4s, Doobie and Circe: The Functional Web Stack
GaryCoady
 
BASTA 2013: Custom OData Provider
Rainer Stropek
 
Scala @ TechMeetup Edinburgh
Stuart Roebuck
 
#살아있다 #자프링외길12년차 #코프링2개월생존기
Arawn Park
 
Demystifying Oak Search
Justin Edelson
 
55 New Features in Java 7
Boulder Java User's Group
 
Scala coated JVM
Stuart Roebuck
 
Kotlin is charming; The reasons Java engineers should start Kotlin.
JustSystems Corporation
 
Scala active record
鉄平 土佐
 
Getting started with Elasticsearch and .NET
Tomas Jansson
 
Scoobi - Scala for Startups
bmlever
 
Python在豆瓣的应用
Qiangning Hong
 
Akka Actor presentation
Gene Chang
 
Scalding for Hadoop
Chicago Hadoop Users Group
 
How and Where in GLORP
ESUG
 
Squeak DBX
ESUG
 
Ajax tutorial
Kat Roque
 
ElasticSearch for .NET Developers
Ben van Mol
 
Scala at HUJI PL Seminar 2008
Yardena Meymann
 
The CoFX Data Model
Rainer Stropek
 

Similar to Requery overview (20)

PDF
Painless Persistence in a Disconnected World
Christian Melchior
 
PDF
Understanding backbonejs
Nick Lee
 
PDF
New Features of JSR 317 (JPA 2.0)
Markus Eisele
 
PDF
Annotation processing and code gen
koji lin
 
PDF
Jpa
vantinhkhuc
 
PDF
Dropwizard
Scott Leberknight
 
PPTX
Data Access Options in SharePoint 2010
Rob Windsor
 
PPTX
Full Stack Development with Node.js and NoSQL
All Things Open
 
PPTX
Full stack development with node and NoSQL - All Things Open - October 2017
Matthew Groves
 
PDF
ERRest
WO Community
 
PDF
Local data storage for mobile apps
Ivano Malavolta
 
PDF
Data access 2.0? Please welcome: Spring Data!
Oliver Gierke
 
PPTX
Crafting Evolvable Api Responses
darrelmiller71
 
PDF
Testdrevet javautvikling på objektorienterte skinner
Truls Jørgensen
 
PPT
比XML更好用的Java Annotation
javatwo2011
 
PDF
Jersey
Yung-Lin Ho
 
PPT
Hibernate
Sunil OS
 
PPTX
Bare-knuckle web development
Johannes Brodwall
 
PDF
The Future of Plugin Dev
Brandon Kelly
 
PDF
Intro to Sail.js
Nicholas McClay
 
Painless Persistence in a Disconnected World
Christian Melchior
 
Understanding backbonejs
Nick Lee
 
New Features of JSR 317 (JPA 2.0)
Markus Eisele
 
Annotation processing and code gen
koji lin
 
Dropwizard
Scott Leberknight
 
Data Access Options in SharePoint 2010
Rob Windsor
 
Full Stack Development with Node.js and NoSQL
All Things Open
 
Full stack development with node and NoSQL - All Things Open - October 2017
Matthew Groves
 
ERRest
WO Community
 
Local data storage for mobile apps
Ivano Malavolta
 
Data access 2.0? Please welcome: Spring Data!
Oliver Gierke
 
Crafting Evolvable Api Responses
darrelmiller71
 
Testdrevet javautvikling på objektorienterte skinner
Truls Jørgensen
 
比XML更好用的Java Annotation
javatwo2011
 
Jersey
Yung-Lin Ho
 
Hibernate
Sunil OS
 
Bare-knuckle web development
Johannes Brodwall
 
The Future of Plugin Dev
Brandon Kelly
 
Intro to Sail.js
Nicholas McClay
 
Ad

More from Sunghyouk Bae (10)

PDF
Introduction of failsafe
Sunghyouk Bae
 
PDF
measure metrics
Sunghyouk Bae
 
PPTX
Java naming strategy (자바 명명 전략)
Sunghyouk Bae
 
PPTX
테스트자동화와 TDD
Sunghyouk Bae
 
PPTX
SpringBoot with MyBatis, Flyway, QueryDSL
Sunghyouk Bae
 
PPTX
JUnit & AssertJ
Sunghyouk Bae
 
PPTX
좋은 개발자 되기
Sunghyouk Bae
 
PDF
Using AdoRepository
Sunghyouk Bae
 
PDF
Multithread pattern 소개
Sunghyouk Bae
 
PDF
Strategy Maps
Sunghyouk Bae
 
Introduction of failsafe
Sunghyouk Bae
 
measure metrics
Sunghyouk Bae
 
Java naming strategy (자바 명명 전략)
Sunghyouk Bae
 
테스트자동화와 TDD
Sunghyouk Bae
 
SpringBoot with MyBatis, Flyway, QueryDSL
Sunghyouk Bae
 
JUnit & AssertJ
Sunghyouk Bae
 
좋은 개발자 되기
Sunghyouk Bae
 
Using AdoRepository
Sunghyouk Bae
 
Multithread pattern 소개
Sunghyouk Bae
 
Strategy Maps
Sunghyouk Bae
 
Ad

Recently uploaded (20)

PPT
Brief History of Python by Learning Python in three hours
adanechb21
 
PPTX
Presentation about variables and constant.pptx
kr2589474
 
PDF
AWS_Agentic_AI_in_Indian_BFSI_A_Strategic_Blueprint_for_Customer.pdf
siddharthnetsavvies
 
PPTX
Presentation about Database and Database Administrator
abhishekchauhan86963
 
PPTX
ASSIGNMENT_1[1][1][1][1][1] (1) variables.pptx
kr2589474
 
PDF
advancepresentationskillshdhdhhdhdhdhhfhf
jasmenrojas249
 
PPT
Activate_Methodology_Summary presentatio
annapureddyn
 
PDF
WatchTraderHub - Watch Dealer software with inventory management and multi-ch...
WatchDealer Pavel
 
PDF
What companies do with Pharo (ESUG 2025)
ESUG
 
PDF
Summary Of Odoo 18.1 to 18.4 : The Way For Odoo 19
CandidRoot Solutions Private Limited
 
PDF
AI Image Enhancer: Revolutionizing Visual Quality”
docmasoom
 
PPTX
Contractor Management Platform and Software Solution for Compliance
SHEQ Network Limited
 
PDF
New Download MiniTool Partition Wizard Crack Latest Version 2025
imang66g
 
PDF
Using licensed Data Loss Prevention (DLP) as a strategic proactive data secur...
Q-Advise
 
PPTX
GALILEO CRS SYSTEM | GALILEO TRAVEL SOFTWARE
philipnathen82
 
PDF
SAP GUI Installation Guide for Windows | Step-by-Step Setup for SAP Access
SAP Vista, an A L T Z E N Company
 
PPTX
Farrell__10e_ch04_PowerPoint.pptx Programming Logic and Design slides
bashnahara11
 
PPTX
Employee salary prediction using Machine learning Project template.ppt
bhanuk27082004
 
PDF
Infrastructure planning and resilience - Keith Hastings.pptx.pdf
Safe Software
 
PDF
New Download FL Studio Crack Full Version [Latest 2025]
imang66g
 
Brief History of Python by Learning Python in three hours
adanechb21
 
Presentation about variables and constant.pptx
kr2589474
 
AWS_Agentic_AI_in_Indian_BFSI_A_Strategic_Blueprint_for_Customer.pdf
siddharthnetsavvies
 
Presentation about Database and Database Administrator
abhishekchauhan86963
 
ASSIGNMENT_1[1][1][1][1][1] (1) variables.pptx
kr2589474
 
advancepresentationskillshdhdhhdhdhdhhfhf
jasmenrojas249
 
Activate_Methodology_Summary presentatio
annapureddyn
 
WatchTraderHub - Watch Dealer software with inventory management and multi-ch...
WatchDealer Pavel
 
What companies do with Pharo (ESUG 2025)
ESUG
 
Summary Of Odoo 18.1 to 18.4 : The Way For Odoo 19
CandidRoot Solutions Private Limited
 
AI Image Enhancer: Revolutionizing Visual Quality”
docmasoom
 
Contractor Management Platform and Software Solution for Compliance
SHEQ Network Limited
 
New Download MiniTool Partition Wizard Crack Latest Version 2025
imang66g
 
Using licensed Data Loss Prevention (DLP) as a strategic proactive data secur...
Q-Advise
 
GALILEO CRS SYSTEM | GALILEO TRAVEL SOFTWARE
philipnathen82
 
SAP GUI Installation Guide for Windows | Step-by-Step Setup for SAP Access
SAP Vista, an A L T Z E N Company
 
Farrell__10e_ch04_PowerPoint.pptx Programming Logic and Design slides
bashnahara11
 
Employee salary prediction using Machine learning Project template.ppt
bhanuk27082004
 
Infrastructure planning and resilience - Keith Hastings.pptx.pdf
Safe Software
 
New Download FL Studio Crack Full Version [Latest 2025]
imang66g
 

Requery overview

  • 2. Agenda • Requery Overview • Why Requery • Requery Build process • Define Mapping • Usage EntityDataStore • EntityDataStore for Kotlin (Coroutines) • Introduction of Spring Data Requery
  • 3. Requery Overview • ORM Library for Java, Kotlin, Android • No Reflection (vs Hibernate proxy) • Typed Query language (vs Hibernate Criteria) • Upsert/Partial objects refresh • Compile time entity/query validation (vs Hibernate) • Entity is stateless (vs Hibernate stateful) • Thread 에 제한 받지 않음 (JPA EntityManager) • Support RxJava, Async Operations, Java 8
  • 4. Why Requery • Provide benefit of ORM • Entity Mapping • Schema Generation • Compile time error detecting • Performance • When bulk job, max 100x than JPA • REST API - 2~10x throughput • Support Upsert, Lazy loading …
  • 5. Requery Build Process - Java Define Entity Annotation Processing buildscript { repositories { jcenter() maven { url "https://plugins.gradle.org/m2/" } } dependencies { // for Java apt classpath "net.ltgt.gradle:gradle-apt-plugin:0.15" } } // lombok을 gradle 에서 사용하기 위한 plugin plugins { id 'io.franzbecker.gradle-lombok' version '1.14' } // lombok을 gradle 에서 사용하기 위해 annotation process를 설정해주어야 합니다. compileOnly "org.projectlombok:lombok" annotationProcessor "org.projectlombok:lombok" testAnnotationProcessor "org.projectlombok:lombok" annotationProcessor "io.requery:requery-processor" testAnnotationProcessor "io.requery:requery-processor" EntityDataStore<Object>
  • 6. Requery Build Process - Kotlin Define Entity Annotation Processing KotlinEntityDataStore<Any> // for kotlin entity kapt "io.requery:requery-processor" kaptTest "io.requery:requery-processor"
  • 7. IntelliJ IDEA Settings IDEA 상에서 테스트 작업 시 자동으로 apt task를 먼저 수행해 준다.
  • 8. Define Entity - Java @Getter @Entity(name = "BasicUser", copyable = true) @Table(name = "basic_user") public abstract class AbstractBasicUser extends AuditableLongEntity { @Key @Generated protected Long id; protected String name; protected String email; protected LocalDate birthday; protected Integer age; @ForeignKey @OneToOne protected AbstractBasicLocation address; @ManyToMany(mappedBy = "members") protected Set<AbstractBasicGroup> groups; @Column(unique = true) protected UUID uuid; @Override public int hashCode() { return Objects.hash(name, email, birthday); } @Transient @Override protected @NotNull ToStringBuilder buildStringHelper() { return super.buildStringHelper() .add("name", name) .add("email", email) .add("birthday", birthday); } private static final long serialVersionUID = -2693264826800934057L; }
  • 9. Define Entity - Kotlin @Entity(model = "functional") interface Person: Persistable { @get:Key @get:Generated val id: Long @get:Index(value = ["idx_person_name_email"]) var name: String @get:Index(value = ["idx_person_name_email", "idx_person_email"]) var email: String var birthday: LocalDate @get:Column(value = "'empty'") var description: String? @get:Nullable var age: Int? @get:ForeignKey @get:OneToOne(mappedBy = "person", cascade = [CascadeAction.DELETE, CascadeAction.SAVE]) var address: Address? @get:OneToMany(mappedBy = "owner", cascade = [CascadeAction.DELETE, CascadeAction.SAVE]) val phoneNumbers: MutableSet<Phone> @get:OneToMany val phoneNumberList: MutableList<Phone> @get:ManyToMany(mappedBy = "members") val groups: MutableResult<Group> @get:ManyToMany(mappedBy = "owners") val ownedGroups: MutableResult<Group> @get:ManyToMany(mappedBy = "id") @get:JunctionTable val friends: MutableSet<Person> @get:Lazy var about: String? @get:Column(unique = true) var uuid: UUID var homepage: URL var picture: String }
  • 10. EntityDataStore<Object> • findByKey • select / insert / update / upsert / delete • where / eq, lte, lt, gt, gte, like, in, not … • groupBy / having / limit / offset • support SQL Functions • count, sum, avg, upper, lower … • raw query
  • 11. @Test fun `insert user`() { val user = RandomData.randomUser() withDb(Models.DEFAULT) { insert(user) assertThat(user.id).isGreaterThan(0) val loaded = select(User::class) where (User::id eq user.id) limit 10 assertThat(loaded.get().first()).isEqualTo(user) } } val result = select(Location::class) .join(User::class).on(User::location eq Location::id) .where(User::id eq user.id) .orderBy(Location::city.desc()) .get() val result = raw(User::class, "SELECT * FROM Users") val rowCount = update(UserEntity::class) .set(UserEntity.ABOUT, "nothing") .set(UserEntity.AGE, 50) .where(UserEntity.AGE eq 100) .get() .value() val count = insert(PersonEntity::class, PersonEntity.NAME, PersonEntity.DESCRIPTION) .query(select(GroupEntity.NAME, GroupEntity.DESCRIPTION)) .get() .first() .count()
  • 12. CoroutineEntityDataStore val store = CoroutineEntityStore(this) runBlocking { val users = store.insert(RandomData.randomUsers(10)) users.await().forEach { user -> assertThat(user.id).isGreaterThan(0) } store .count(UserEntity::class) .get() .toDeferred() .await() .let { assertThat(it).isEqualTo(10) } } with(coroutineTemplate) { val user = randomUser() // can replace with `withContext { }` async { insert(user) }.await() assertThat(user.id).isNotNull() val group = RandomData.randomGroup() group.members.add(user) async { insert(group) }.await() assertThat(user.groups).hasSize(1) assertThat(group.members).hasSize(1) }
  • 13. spring-data-requery • RequeryOperations • Wrap EntityDataStore • RequeryTransactionManager for PlatformTransactionManager •
  • 14. spring-data-requery • Repository built in SQL • ByPropertyName Auto generation methods • @Query for raw SQL Query • Query By Example • Not Supported • Association Path (not specified join method) • Named parameter in @Query (just use `?`)
  • 15. Setup spring-data-requery @Configuration @EnableTransactionManagement public class RequeryTestConfiguration extends AbstractRequeryConfiguration { @Override @Bean public EntityModel getEntityModel() { return Models.DEFAULT; } @Override public TableCreationMode getTableCreationMode() { return TableCreationMode.CREATE_NOT_EXISTS; } @Bean public DataSource dataSource() { return new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.H2) .build(); } }
  • 16. Provided Beans @Bean public io.requery.sql.Configuration requeryConfiguration() { return new ConfigurationBuilder(dataSource, getEntityModel()) // .useDefaultLogging() .setEntityCache(new EmptyEntityCache()) .setStatementCacheSize(1024) .setBatchUpdateSize(100) .addStatementListener(new LogbackListener()) .build(); } @Bean public EntityDataStore<Object> entityDataStore() { log.info("Create EntityDataStore instance."); return new EntityDataStore<>(requeryConfiguration()); } @Bean public RequeryOperations requeryOperations() { log.info("Create RequeryTemplate instance."); return new RequeryTemplate(entityDataStore(), requeryMappingContext()); } EntityCache 설정Tip : 개발 시에는 EmptyEntityCache, 운영 시에는 Cache2kEntityCache 사용
  • 17. Use @Query in Repository interface DeclaredQueryRepository extends RequeryRepository<BasicUser, Long> { @Query("select * from basic_user u where u.email = ?") BasicUser findByAnnotatedQuery(String email); @Query("select * from basic_user u where u.email like ?") List<BasicUser> findAllByEmailMatches(String email); @Query("select * from basic_user u limit ?") List<BasicUser> findWithLimits(int limit); @Query("select * from basic_user u where u.name=? and u.email=? limit 1") BasicUser findAllBy(String name, String email); @Query("select u.id, u.name from basic_user u where u.email=?") List<Tuple> findAllIds(String email); @Query("select * from basic_user u where u.birthday = ?") List<BasicUser> findByBirthday(LocalDate birthday); }
  • 18. Query By Example BasicUser user = RandomData.randomUser(); user.setName("example"); requeryTemplate.insert(user); BasicUser exampleUser = new BasicUser(); exampleUser.setName("EXA"); ExampleMatcher matcher = matching() .withMatcher("name", startsWith().ignoreCase()) .withIgnoreNullValues(); Example<BasicUser> example = Example.of(exampleUser, matcher); Return<? extends Result<BasicUser>> query = buildQueryByExample(example); BasicUser foundUser = query.get().firstOrNull(); assertThat(foundUser).isNotNull().isEqualTo(user);
  • 19. Query by Property - Not Yet List<User> findByFirstnameOrLastname(@Param("lastname") String lastname, @Param("firstname") String firstname); List<User> findByLastnameLikeOrderByFirstnameDesc(String lastname); List<User> findByLastnameNotLike(String lastname); List<User> findByLastnameNot(String lastname); List<User> findByManagerLastname(String name); List<User> findByColleaguesLastname(String lastname); List<User> findByLastnameNotNull(); @Query("select u.lastname from SD_User u group by u.lastname") Page<String> findByLastnameGrouped(Pageable pageable); long countByLastname(String lastname); int countUsersByFirstname(String firstname); boolean existsByLastname(String lastname); Note:Association Path is not supported Note:Association Path is not supported
  • 20. Resources • requery.io • kotlinx-data-requery in coupang gitlab • spring-data-requery in coupang gitlab
  • 21. Q&A