dbt macro tips advent calendar 2022 day 18 - hookの実装のdeep-dive
便利なデータ変換ツールである dbt の中のmacroに関するtipsを書いていく dbt macro tips Advent Calendar 2022 18日目です。
先日は table
の実装から persist_docs
の実装を覗いてみました。
今度はhook
の実装を覗いてみましょう。
hookの実装を覗いてみよう
hook
はどうやら run_hooks
というmacroで実装されてるようです。
このmacroの中身を覗いてみましょう。
何やら気になる記述がいくつかありますね。
render(hook.get('sql'))
というこの記述、どうやらhookに書かれたSQLをJinjaテンプレートとして解釈して描画しているようです。
さて、ではこのrenderという実態は一体何処にあるのでしょうか?
探っていくと、次のコードにたどり着きます。
Pythonのコードですね。同じ階層にあるREADME.mdを読んでみましょう。
なんと、こちらはコンテキストの実装が書かれたPythonコードなのでした。
コンテキストとはdbtの実行の最中にJinjaテンプレートの描画を行うときに使うもので、設定やbuiltinのmacroやら何やらたくさん書かれているものです。
つまり、コンテキストの謎を深ぼっていくと、どこで何が使えるのか?という理解が進むわけなのです。
さて、話は戻して、render()
というのは、ProviderContext
に紐付いているコンテキストmethodのようです。この ProviderContext
というのは MacroContext
, ModelContext
, TestContext
の親コンテキストということらしいです。つまり、render()
は我々が触る範疇では基本的にはどこでも使えるということですね。 (ただし、yamlは除く)
よし、render()
というのはわかった。 selectattr
などはJinjaのfilter関数だ。
length
とかも同様だ。 call
は前に見た。
あと不明なのは、いきなり呼び出し側で参照されている pre_hooks
, post_hooks
だろう。
コレは一体何なんだ!
答えは、 ModelContext
のコンテキスト変数でした。
中身を見てみると、 modelのconfigのpre_hookやpost_hookをそれぞれto_dictしたものようです。
この辺はPythonコードですね。
では、この self.model.config
が何者なのかを探りましょう。
self.model
は どうやら ManifestNode
というものらしいですね。
そうなんです。pre_hooksやpost_hooksというのは実は深く深くたどっていくとマニフェスト由来の値が入っているのです。
此処から先をたどっていくとPythonのコードのもっと奥深くに潜ることになるので、一旦割愛して結論だけいうと
{
"pre_hooks": [
{
"sql: "SELECT ...",
"transaction": false
},
{
"sql: "SELECT ...",
"transaction": true
}
]
}
な感じの内容が手に入ります。
ここまで、わかればなんとなくhookがどのように動いているか?というのは見えてきたのではないでしょうか。
ところで、ここで覚えておいてほしいのは
- コンテキストなる概念がある。 その実装は pythonのコードを読めばなんとなく
- コンテキストにはドキュメントにはされていない
render()
なるメソッドがあったりする。
ということです。
19日目は続けて、コンテキストの中にある便利なものを紹介します。
Discussion