Custom DSL
DSL
Jpql
ํด๋์ค๋ฅผ ์์ํ๊ณ ๋๋ง์ ํจ์๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ผ๋ก ๋๋ง์ DSL์ ๋ง๋ค ์ ์์ต๋๋ค.
Jpql
์ Kotlin JDSL์ด ์ ๊ณตํ๋ ๋ชจ๋ ๊ธฐ๋ณธ DSL ํจ์๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค. ์ด๋ฅผ ์ด์ฉํด ๋๋ง์ ํจ์๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ Expression
ํน์ Predicate
๋ฅผ ๊ตฌํํ ๋๋ง์ Model
ํด๋์ค๋ฅผ ๋ง๋ค๊ณ , ์ด๋ฅผ ๋ฐํํ๋ ํจ์๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค. ์ด ๊ฒฝ์ฐ JpqlSerializer
๋ฅผ ๊ตฌํํ์ฌ Model
์ String์ผ๋ก ๋๋๋งํ๋ ๋ฐฉ๋ฒ์ Kotlin JDSL์๊ฒ ์๋ ค์ค ์ ์์ต๋๋ค.
์ด๋ ๊ฒ ๋ง๋ค์ด์ง ๋๋ง์ DSL์ jpql()
์ ์ ๋ฌํ๊ธฐ ์ํ ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ด ์์ต๋๋ค. ์ฒซ ๋ฒ์งธ๋ DSL ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ JpqlDsl.Constructor
๋ฅผ companion object๋ก ๊ตฌํํ๋ ๊ฒ์ด๊ณ , ๋ ๋ฒ์งธ๋ DSL ์ธ์คํด์ค๋ฅผ ์์ฑํ๋ ๊ฒ์
๋๋ค.
JpqlDsl.Constructor
์ด ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๋ฉด ํด๋์ค๋ง ์ ์ธํด ์ฌ์ฉํ ์ ์์ผ๋ฉฐ ์ฟผ๋ฆฌ ์์ฑ ์๋ง๋ค ์๋ก์ด ์ธ์คํด์ค๋ฅผ ์๋์ผ๋ก ์์ฑํฉ๋๋ค.
class MyJpql : Jpql() {
companion object Constructor : JpqlDsl.Constructor<MyJpql> {
override fun newInstance(): MyJpql = MyJpql()
}
fun myFunction(value: String): Expression<String> {
return function(String::class, "myFunction", listOf(value(value)))
}
fun Expressionable<String>.regexLike(value: String): Predicate {
return MyRegexLike(this.toExpression(), value)
}
}
val query = jpql(MyJpql) {
select(
entity(Book::class)
).from(
entity(Book::class)
).where(
myFunction("test").regexLike(".*")
)
}
Jpql Instance
์ด ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๋ฉด ์ฟผ๋ฆฌ ์์ฑ์ ํ๋์ ์ธ์คํด์ค๋ฅผ ์ฌํ์ฉํ ์ ์์ผ๋ฉฐ ์์กด์ฑ ์ฃผ์ ์ ํ์ฉํ ์ ์์ต๋๋ค.
class MyJpql(
private val encryptor: Encryptor,
) : Jpql() {
fun Path<String>.equalToEncrypted(value: String): Predicate {
val encrypted = encryptor.encrypt(value)
return this.equal(encrypted)
}
}
val encryptor = Encryptor()
val instance = MyJpql(encryptor)
val query = jpql(instance) {
select(
entity(Book::class)
).from(
entity(Book::class)
).where(
path(Book::title).equalToEncrypted("plain")
)
}
Serializer
๋๋ง์ Model
์ String์ผ๋ก ๋๋๋งํ๊ธฐ ์ํด JpqlSerializer
๋ฅผ ๊ตฌํํ๊ณ ์ด๋ฅผ RenderContext
์ ์ถ๊ฐํด์ผ ํฉ๋๋ค.
JpqlSerializer
๋ ๋๋๋ง ๋ก์ง์ ๊ตฌํํ ์ ์๋๋ก JpqlWriter
์ RenderContext
๋ฅผ ์ ๊ณตํฉ๋๋ค. RenderContext
๋ฅผ ํตํด JpqlRenderSerializer
๋ฅผ ์ป์ด ๋์ Model
์ด ๊ฐ์ง๊ณ ์๋ ๋ค๋ฅธ Model
์ ๋๋๋งํ ์ ์์ต๋๋ค. ๋ RenderContext
๋ฅผ ํตํด JpqlRenderStatement
์ JpqlRenderClause
๋ฅผ ์ป์ด ํ์ฌ ์ด๋ค statement์ clause ์์์ ๋๋๋งํ๊ณ ์๋์ง ์ ์ ์์ต๋๋ค. ์ด๊ฒ๋ค์ ์ด์ฉํด์ ๋๋ง์ Model
์ String์ผ๋ก ๋๋๋งํ ์ ์์ต๋๋ค.
class MyRegexLikeSerializer : JpqlSerializer<MyRegexLike> {
override fun handledType(): KClass<MyRegexLike> {
return MyRegexLike::class
}
override fun serialize(part: MyRegexLike, writer: JpqlWriter, context: RenderContext) {
val delegate = context.getValue(JpqlRenderSerializer)
// val statement = context.getValue(JpqlRenderStatement)
// val clause = context.getValue(JpqlRenderClause)
//
// statement.isSelect()
// clause.isWhere()
writer.write("REGEXP_LIKE")
writer.writeParentheses {
delegate.serialize(part.expr, writer, context)
writer.write(", ")
delegate.serialize(part.pattern, writer, context)
}
}
}
JpqlRenderContext
๋ JpqlSerializer
๊ตฌํ์ฒด๋ฅผ ์ถ๊ฐํ ์ ์๋๋ก registerModule()
๋ฅผ ์ ๊ณตํฉ๋๋ค.
val myModule = object : JpqlRenderModule {
override fun setupModule(context: JpqlRenderModule.SetupContext) {
context.addSerializer(MyRegexLikeSerializer())
}
}
val myContext = JpqlRenderContext().registerModule(myModule)
val jpqQuery = entityManager.createQuery(query, myContext)
Last updated