-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #138 from mziyut/create-pull-request/patch-pull-ar…
…ticles Pull articles
- Loading branch information
Showing
1 changed file
with
154 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
--- | ||
title: Dataform の Unit test で UNION ALL を書くのが辛くて JavaScript の wrapper を書いた話 | ||
tags: | ||
- JavaScript | ||
- SQL | ||
- テスト | ||
- sqlx | ||
- Dataform | ||
private: false | ||
updated_at: '2023-10-13T18:41:54+09:00' | ||
id: ccf2c58ae44c49a34b04 | ||
organization_url_name: qiita-inc | ||
slide: false | ||
ignorePublish: false | ||
--- | ||
|
||
## はじめに | ||
|
||
Dataform には unit test を記述出来ます。 | ||
ただし、テストに用いるデータは SQL で書く必要があり冗長なものになりがちです。 | ||
Dataform は JavaScript を記述、読込みできるので wrapper を書きました。 | ||
|
||
## Dataform の Unit test について | ||
|
||
Dataform の Unit test はこのように記述できます。 | ||
`example_originals` table からデータを参照する `example.sqlx` があったとします。 | ||
|
||
```sqlx:foo/example.sqlx | ||
config { | ||
type: "view", | ||
name: "example_tables" | ||
} | ||
SELECT | ||
id, | ||
title | ||
FROM | ||
${ref("example_originals")} | ||
``` | ||
|
||
この `example.sqlx` に対する Unit test を用意すると以下のようになります。 | ||
|
||
```sqlx:foo/test_example.sqlx | ||
config { | ||
type: "test", | ||
dataset: "example_tables" | ||
} | ||
SELECT | ||
1 AS id, | ||
"title1" AS title | ||
UNION ALL | ||
SELECT | ||
2 AS id, | ||
"title2" AS title | ||
UNION ALL | ||
SELECT | ||
3 AS id, | ||
"title3" AS title | ||
input "example_originals" { | ||
SELECT | ||
1 AS id, | ||
"title1" AS title | ||
UNION ALL | ||
SELECT | ||
2 AS id, | ||
"title2" AS title | ||
UNION ALL | ||
SELECT | ||
3 AS id, | ||
"title3" AS title | ||
} | ||
``` | ||
|
||
test データを用意したいだけですが、 `UNION ALL` を何度も記載する必要があります。 | ||
面倒で寿司、可読性も悪い状態になってしまいます。 | ||
|
||
苦し紛れではありますが、JavaScript を用いて `UNION ALL` のラッパー関数を作成しました。 | ||
|
||
## JavaScript の wrapper を書いた | ||
|
||
Dataform は `includes` 以下の ディレクトリに JavaScript ファイルを置くことで、 | ||
SQLX 内から JavaScript に記載した処理を呼び出すことができます。 | ||
|
||
作成した JavaScript はこちらです。 | ||
渡されたデータを `UNION ALL` で `join` するだけの簡単な処理です。 | ||
|
||
:::note warn | ||
エスケープ処理等いくつか省略しています。 | ||
::: | ||
|
||
```js:includes/sql.js | ||
function build(data) { | ||
if (data.length === 0) { | ||
return ""; | ||
} | ||
|
||
const keys = Object.keys(data[0]); | ||
return data.map((item) => { | ||
const values = keys.map((key) => { | ||
if (typeof item[key] !== "string") { | ||
return `${item[key]} AS ${key}`; | ||
} | ||
return `'${item[key]}' AS ${key}`; | ||
}); | ||
|
||
return `SELECT ${values.join(", ")}`; | ||
}).join(" UNION ALL "); | ||
} | ||
|
||
module.exports = { | ||
build, | ||
}; | ||
``` | ||
|
||
SQLX ファイルから処理を呼び出す場合は以下のように記載します。 | ||
|
||
```sqlx:foo/bar.sqlx | ||
${ | ||
sql.build([ | ||
{ id: 1, title: "title1" }, | ||
{ id: 2, title: "title2" } | ||
]) | ||
} | ||
``` | ||
|
||
すると以下のような SQL に変換します。 | ||
|
||
```sql | ||
SELECT | ||
1 as id, | ||
"title1" as title | ||
UNION ALL | ||
SELECT | ||
2 as id, | ||
"title2" as title | ||
``` | ||
|
||
## 最後に | ||
|
||
今回記事を書くために記載したテストデータの件数は3件程でした。 | ||
Dataform で処理するデータ次第ですが、テストデータの件数はもっと多くなるはず。 | ||
|
||
ちょっとした JavaScript を書くだけで、すこしメンテナンスしやすなります。 | ||
いい塩梅が求められる部分なので、やり過ぎは禁物です。 | ||
|
||
## References | ||
|
||
https://docs.dataform.co/guides/tests | ||
|
||
https://cloud.google.com/blog/ja/topics/data-warehousing/learn-how-to-use-the-dataform-cli-tool-to-unit-test-udfs?hl=ja | ||
|
||
https://cloud.google.com/blog/topics/data-warehousing/learn-how-to-use-the-dataform-cli-tool-to-unit-test-udfs/ |