クエリの合成

概要

クエリは合成をサポートします。

合成関数

Komapperにおいて、クエリは以下のクラスのいずれかもしくは両方で表現されます。

org.komapper.core.dsl.query.Query<T>
JdbcDatabaseもしくはR2dbcDatabaseインスタンスを介して実行するとデータベースにアクセスしT型の値を返すクエリ。
org.komapper.core.dsl.query.FlowQuery<T>
R2dbcDatabaseインスタンスを介して実行するとkotlinx.coroutines.flow.Flow<T>型の値を返すクエリ。データベースアクセスはFlowcollectされたときに初めて行われます。

これらのうち、合成をサポートしているのはQuery<T>のみです。 下記では、Query<T>に対して実行できる合成関数を説明します。

andThen

andThen関数を使うと、まとめて実行して最後の結果を返すクエリを構築できます。

val q1: Query<Address> = QueryDsl.insert(a).single(Address(16, "STREET 16", 0))
val q2: Query<Address> = QueryDsl.insert(a).single(Address(17, "STREET 17", 0))
val q3: Query<List<Address>> = QueryDsl.from(a).where { a.addressId inList listOf(16, 17) }
val query: Query<List<Address>> = q1.andThen(q2).andThen(q3)
val list: List<Address> = db.runQuery { query }
/*
insert into ADDRESS (ADDRESS_ID, STREET, VERSION) values (?, ?, ?)
insert into ADDRESS (ADDRESS_ID, STREET, VERSION) values (?, ?, ?)
select t0_.ADDRESS_ID, t0_.STREET, t0_.VERSION from ADDRESS as t0_ where t0_.ADDRESS_ID in (?, ?)
*/

map

map関数を使うと、クエリ結果に変更を加えるクエリを構築できます。

val query: Query<List<Address>> = QueryDsl.from(a).map { 
  it.map { address -> address.copy(version = 100) }
}
/*
select t0_.ADDRESS_ID, t0_.STREET, t0_.VERSION from ADDRESS as t0_ 
*/

zip

zip関数を使うと、2つのクエリ結果をPair型で返すクエリを構築できます。

val q1 = QueryDsl.insert(a).single(Address(16, "STREET 16", 0))
val q2 = QueryDsl.from(a)
val query: Query<Pair<Address, List<Address>>> = q1.zip(q2)
/*
insert into ADDRESS (ADDRESS_ID, STREET, VERSION) values (?, ?, ?)
select t0_.ADDRESS_ID, t0_.STREET, t0_.VERSION from ADDRESS as t0_
*/

flatMap

flatMap関数を使うと、1番目のクエリの実行結果を受け取って2番目のクエリを実行し2番目の結果を返すクエリを構築できます。

val q1: Query<Address> = QueryDsl.insert(a).single(Address(16, "STREET 16", 0)) // 1st query
val query: Query<List<Employee>> = q1.flatMap { newAddress ->
    QueryDsl.from(e).where { e.addressId less newAddress.addressId } // 2nd query
}
val list: List<Employee> = db.runQuery { query }
/*
insert into ADDRESS (ADDRESS_ID, STREET, VERSION) values (?, ?, ?)
select t0_.EMPLOYEE_ID, t0_.EMPLOYEE_NO, t0_.EMPLOYEE_NAME, t0_.MANAGER_ID, t0_.HIREDATE, t0_.SALARY, t0_.DEPARTMENT_ID, t0_.ADDRESS_ID, t0_.VERSION from EMPLOYEE as t0_ where t0_.ADDRESS_ID < ?
*/

flatZip

flatZip関数を使うと、1番目のクエリの実行結果を受け取って2番目のクエリを実行し1番目と2番目の結果をPair型で返すクエリを構築できます。

val q1: Query<Address> = QueryDsl.insert(a).single(Address(16, "STREET 16", 0)) // 1st query
val query: Query<Pair<Address, List<Employee>>> = q1.flatZip { newAddress ->
    QueryDsl.from(e).where { e.addressId less newAddress.addressId } // 2nd query
}
val pair: Pair<Address, List<Employee>> = db.runQuery { query }
/*
insert into ADDRESS (ADDRESS_ID, STREET, VERSION) values (?, ?, ?)
select t0_.EMPLOYEE_ID, t0_.EMPLOYEE_NO, t0_.EMPLOYEE_NAME, t0_.MANAGER_ID, t0_.HIREDATE, t0_.SALARY, t0_.DEPARTMENT_ID, t0_.ADDRESS_ID, t0_.VERSION from EMPLOYEE as t0_ where t0_.ADDRESS_ID < ?
*/