JavaScriptSQLテストsqlxDataform

Dataform の Unit test で UNION ALL を書くのが辛くて JavaScript の wrapper を書いた話

はじめに

Dataform には unit test を記述出来ます。 ただし、テストに用いるデータは SQL で書く必要があり冗長なものになりがちです。 Dataform は JavaScript を記述、読込みできるので wrapper を書きました。

Dataform の Unit test について

Dataform の Unit test はこのように記述できます。 example_originals table からデータを参照する example.sqlx があったとします。

config {
  type: "view",
  name: "example_tables"
}

SELECT
  id,
  title
FROM
  ${ref("example_originals")}

この example.sqlx に対する Unit test を用意すると以下のようになります。

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 ALLjoin するだけの簡単な処理です。

:::note warn エスケープ処理等いくつか省略しています。 :::

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 ファイルから処理を呼び出す場合は以下のように記載します。

${
  sql.build([
    { id: 1, title: "title1" },
    { id: 2, title: "title2" }
  ])
}

すると以下のような SQL に変換します。

SELECT
  1 as id,
  "title1" as title
UNION ALL
SELECT
  2 as id,
  "title2" as title

最後に

今回記事を書くために記載したテストデータの件数は3件程でした。 Dataform で処理するデータ次第ですが、テストデータの件数はもっと多くなるはず。

ちょっとした JavaScript を書くだけで、すこしメンテナンスしやすなります。 いい塩梅が求められる部分なので、やり過ぎは禁物です。

References