seratch's weblog in Japanese

About Scala, Java and Ruby programming in Japaense. If you need English information, go to http://blog.seratch.net/

ScalikeJDBC での SQL デバッグログのフォーマット機能

ScalikeJDBC 1.4.7 をリリースしました。

http://notes.implicit.ly/post/44143927672/scalikejdbc-1-4-7

https://github.com/seratch/scalikejdbc

目玉となる SQLSyntaxSupport という機能を説明する記事を書くのは少し時間がかかるので、まずは小ネタから。

SQLSyntaxSupport を使うようになるとこれまでよりも複数の join をしたり、サブクエリを使ったりするのが楽になるのですが、その分生成された SQL は人間が読むのは大変です。

そういうときは hibernate-core 4.x を依存関係に追加して

libraryDependencies += "org.hibernate" % "hibernate-core" % "4.1.9.Final"

以下のようなクラスを作り

package com.example
class HibernateSQLFormatter extends SQLFormatter {
  private val formatter = new org.hibernate.engine.jdbc.internal.BasicFormatterImpl()
  def format(sql: String) = formatter.format(sql)
}

そのクラス名を GlobalSettings に指定しましょう。

GlobalSettings.sqlFormatter = SQLFormatterSettings("com.example.HibernateSQLFormatter")

そうするとこれまで

00:05:49.817 [pool-7-thread-1] DEBUG s.StatementExecutor$$anon$1 - SQL execution completed

  [Executed SQL]
   select C.ID as I_ON_C, C.NAME as N_ON_C, C.GROUP_ID as GI_ON_C, x.i_on_o as i_on_o_on_x, x.ci_on_o as ci_on_o_on_x, x.pi_on_o as pi_on_o_on_x, x.oa_on_o as oa_on_o_on_x, x.i_on_p as i_on_p_on_x, x.n_on_p as n_on_p_on_x from customers C inner join (select o.id as i_on_o, o.customer_id as ci_on_o, o.product_id as pi_on_o, o.ordered_at as oa_on_o, p.id as i_on_p, p.name as n_on_p from orders o inner join products p on o.product_id = p.id ) x on C.ID = x.ci_on_o order by C.ID; (0 ms)

  [Stack Trace]
    ...
    scala.util.control.Exception$Catch.apply(Exception.scala:102)
    scalikejdbc.DB$$anonfun$localTx$2.apply(DB.scala:612)

のようにベタに出力されていた SQL が、以下のようにフォーマットされて人間が読めるものになっています。

00:14:58.811 [pool-8-thread-3] DEBUG s.StatementExecutor$$anon$1 - SQL execution completed

  [Executed SQL]
   
    select
        C.ID as I_ON_C,
        C.NAME as N_ON_C,
        C.GROUP_ID as GI_ON_C,
        x.i_on_o as i_on_o_on_x,
        x.ci_on_o as ci_on_o_on_x,
        x.pi_on_o as pi_on_o_on_x,
        x.oa_on_o as oa_on_o_on_x,
        x.i_on_p as i_on_p_on_x,
        x.n_on_p as n_on_p_on_x 
    from
        customers C 
    inner join
        (
            select
                o.id as i_on_o,
                o.customer_id as ci_on_o,
                o.product_id as pi_on_o,
                o.ordered_at as oa_on_o,
                p.id as i_on_p,
                p.name as n_on_p 
            from
                orders o 
            inner join
                products p 
                    on o.product_id = p.id 
            ) x 
                on C.ID = x.ci_on_o 
        order by
            C.ID; (2 ms)

  [Stack Trace]
    ...
    scala.util.control.Exception$Catch.apply(Exception.scala:102)
    scalikejdbc.DB$$anonfun$localTx$2.apply(DB.scala:612)

これは便利な機能だとは思いますが ScalikeJDBC 自体が Hibernate に依存したくなかったので、本体としては拡張ポイントのみの提供となっています。将来的には、内部で独自の SQL フォーマッタを提供するようになるかもしれませんが、今のところ未定です。

ぜひご利用ください。