在 Dataform 中使用 JavaScript

本文档可帮助您了解如何使用 JavaScript 在 Dataform 中开发工作流。本文档还介绍了如何使用 JavaScript 创建工作流操作,以及如何创建 JavaScript include 以在 Dataform 中重用代码。

借助 Dataform 核心,您可以使用 SQLX 和 JavaScript 创建工作流操作。虽然是可选的,但您可以使用 JavaScript 和 SQLX 在工作流程中重复创建类似元素。例如,您可以使用 JavaScript 创建工作流中每个表的视图,并移除特定用户 ID。您还可以完全使用 JavaScript 开发工作流操作。

准备工作

  1. 在 Google Cloud 控制台中,前往 Dataform 页面。

    前往 Dataform

  2. 选择或创建代码库

  3. 选择或创建开发工作区

此外,您还必须熟悉 JavaScript 语法和以下 JavaScript 概念:

  • 变量
  • 数组
  • 条件语句
  • For 循环
  • 地图
  • 函数
  • 对象
  • 导出和导入模块

所需的角色

如需获得使用 JavaScript 开发工作流以及通过 JavaScript 包含项重用代码所需的权限,请让您的管理员为您授予工作区的 Dataform Editor (roles/dataform.editor) IAM 角色。如需详细了解如何授予角色,请参阅管理对项目、文件夹和组织的访问权限

您也可以通过自定义角色或其他预定义角色来获取所需的权限。

向 SQLX 文件添加 JavaScript 代码

您可以通过两种方式将 JavaScript 代码添加到 SQLX 文件中:内嵌或在 JavaScript 块内。

您可以使用 JavaScript 块在 SQLX 文件中定义函数或常量。您可以使用内嵌 JavaScript 动态修改 SQLX 或 SQL 查询。

以下代码示例展示了内联添加到 SQLX 文件中 post_operations 块的 self Dataform 核心内置 JavaScript 函数:

config {type: "table"}

SELECT * FROM ...

post_operations {
  GRANT `roles/bigquery.dataViewer`
  ON
  TABLE ${self()}
  TO "group:allusers@example.com", "user:otheruser@example.com"
}

以下代码示例展示了在 JavaScript 块中定义的常量,以及如何在 SQLX 文件中的查询内联使用该常量:

js {
  const columnName = "foo";
}

SELECT 1 AS ${columnName} FROM "..."

通过 JavaScript 封装在单个 SQLX 文件中重用代码

您可以重复使用 JavaScript 代码,从而简化 Dataform 中的开发流程。 如需在单个 SQLX 文件中重复使用 JavaScript 常量和函数,您可以将它们封装在 JavaScript 块中。如需在单个 Dataform 代码库中重复使用 JavaScript 代码,您可以创建 include。 如需在多个 Dataform 代码库中重复使用 JavaScript 代码,您可以创建或导入软件包。

如需创建可在单个 SQLX 文件中重复使用的 SQL 代码,您可以将函数和常量封装在 JavaScript 块中。您只能在定义 JavaScript 代码块的 SQLX 文件内重用该代码块中定义的代码。如需了解详情,请参阅 Dataform Core

以下代码示例展示了在 JavaScript 块中定义并在 SQLX 文件中的查询内联使用的常量和函数:

js {
 const foo = 1;
 function bar(number){
     return number+1;
 }
}

select
 ${foo} as one,
 ${bar(foo)} as two

通过包含在单个代码库中重复使用代码

Include 是指您的代码库中的全局 JavaScript 常量或函数。您可以在代码库的 includes 目录中定义包含项。然后,您可以在 JavaScript 和 SQLX 文件中跨代码库重复使用这些变量。

以下代码示例展示了 includes/constants.js 文件中 launch_date 常量的定义:

// filename is includes/constants.js
const launch_date = "11.11.2011";
module.exports = { launch_date };

以下代码示例展示了 SQLX 文件中的表定义查询中引用的 launch_date 常量:

config {type: "table"}

SELECT * FROM source_table WHERE date > ${constants.launch_date}

为包含项创建 JavaScript 文件

如需在 includes/ 目录中创建新的 JavaScript 文件,请按以下步骤操作:

  1. 文件窗格中,点击 includes/ 旁边的 更多

  2. 点击创建文件

  3. 创建新文件窗格中,执行以下操作:

    1. 添加文件路径字段中,在 includes/ 后面输入文件名,然后输入 .js。例如 includes/constants.js

      文件名只能包含数字、字母、连字符和下划线。

    2. 点击创建文件

创建 JavaScript 常量

如需创建可在整个项目中重复使用的常量,请按以下步骤操作:

  1. 前往您的开发工作区。

  2. 文件窗格中,展开 includes/

  3. 创建或选择一个扩展名为 .js 的 JavaScript 文件。

  4. 在文件中输入以下代码段:

     const CONSTANT_NAME = CONSTANT_VALUE;
     module.exports = { CONSTANT_NAME };
    

    替换以下内容:

    • CONSTANT_NAME:常量的名称
    • CONSTANT_VALUE:常量的值
  5. 可选:点击格式

以下代码示例在 includes/constants.js 文件中定义了 PROJECT_ID 常量:

  // filename is includes/constants.js
  const PROJECT_ID = "my_project_name";
  module.exports = { PROJECT_ID };

以下代码示例在 SQLX 文件中的表定义查询中引用了 PROJECT_ID 常量:

  config { type: "table" }
  SELECT * FROM ${constants.PROJECT_ID}.my_schema_name.my_table_name

以下代码示例展示了编译为 SQL 的之前的 Dataform 核心表定义查询:

  SELECT * FROM my_project_name.my_schema_name.my_table_name

创建自定义 JavaScript 函数

如需创建可在整个项目中重复使用的自定义 JavaScript 函数,请按照以下步骤操作:

  1. 前往您的开发工作区。

  2. 文件窗格中,展开 includes/

  3. 创建或选择一个扩展名为 .js 的 JavaScript 文件。

  4. 在该文件中,编写自定义 JavaScript 函数。

  5. 在文件中输入以下代码段:

     module.exports = { FUNCTION_NAME }
    

    FUNCTION_NAME 替换为您的函数的名称。

  6. 可选:点击格式

以下代码示例展示了一个名为 renderScript 且存储在 includes/functions.js 文件中的自定义 JavaScript 函数。该函数会生成一个 SQL 脚本:

  function renderScript(table, dimensions, metrics) {
    return `
        select
        ${dimensions.map(field => `${field} as ${field}`).join(",")},
        ${metrics.map(field => `sum(${field}) as ${field}`).join(",\n")}
        from ${table}
        group by ${dimensions.map((field, i) => `${i + 1}`).join(", ")}
      `;
  }

  module.exports = { renderScript };

以下代码示例展示了如何在 Dataform 核心表定义查询中使用自定义 renderScript JavaScript 函数:

  config {
      type: "table",
      tags: ["advanced", "hourly"],
      disabled: true
  }

  ${functions.renderScript(ref("source_table"),
                                ["country", "device_type"],
                                ["revenue", "pageviews", "sessions"]
                                )}

以下代码示例展示了之前编译为 SQL 的 Dataform 核心表定义查询:

  select
    country as country,
    device_type as device_type,
    sum(revenue) as revenue,
    sum(pageviews) as pageviews,
    sum(sessions) as sessions

  from "dataform"."source_table"

  group by 1, 2

在 SQLX 文件中引用 include

您可以在 SQLX 文件中引用任何 include 函数或常量。引用包含文件的语法取决于包含文件的位置。顶级 include 文件直接位于 includes/ 目录中。 嵌套的 include 文件位于 includes/ 的子目录中。

在 SQLX 文件中引用顶级 include

  • 如需在 Dataform 核心查询中引用顶级 include 函数或常量,请输入 include 定义文件名(不含 .js 扩展名),后跟导出的对象名称。

以下代码示例在表定义 SQLX 文件中引用了 includes/constants.js 文件中定义的 firstDate 常量:

  config {type: "table"}
  select * from source_table where date > ${constants.firstDate}

在 SQLX 文件中引用嵌套的 include

如需引用位于 definitions 子目录中的 include,请使用 JavaScript require 函数和 js {} 块导入 include。

如需使用 require JavaScript 函数引用嵌套的 include,请按以下步骤操作:

  1. 前往您的开发工作区。

  2. 文件窗格中,展开 definitions/

  3. 选择一个 SQLX 文件。

  4. config 块中,输入以下代码段:

     js {
       var { VARIABLE_NAME } = require("SUBDIRECTORY_INCLUDE");
     }
    

    替换以下内容:

    • VARIABLE_NAME:要导入的常量或函数的名称
    • SUBDIRECTORY_INCLUDE:嵌套 includes 文件的路径
  5. 可选:点击格式

以下代码示例在表定义 SQLX 文件中引用了嵌套 includes/allConstants/constants.js 文件中定义的 firstDate 常量:

  config {type: "table"}
  js {
    var { firstDate } = require("includes/allConstants/constants");
  }
  select * from source_table where date > ${firstDate}

将 JavaScript include 函数与 Dataform 核心 ref 函数搭配使用

如需将 JavaScript include 函数与 Dataform 核心 ref 函数搭配使用,您需要在 SQLX 文件中将 ref 作为 JavaScript include 函数的实参进行传递。

以下代码示例展示了 includes/script_builder.js 文件,其中包含使用 SUM 汇总指标并按维度对指标进行分组的 renderScript JavaScript 函数:

function renderScript(table, dimensions, metrics) {
  return `
      SELECT
      ${dimensions.map((field) => `${field} AS ${field}`).join(",\\n")},
      ${metrics.map((field) => `SUM(${field}) AS ${field}`).join(",\\n")}
      FROM ${table}
      GROUP BY ${dimensions.map((field, i) => `${i + 1}`).join(", ")}
    `;
}
module.exports = { renderScript };

以下代码示例展示了 definitions/stats_per_country_and_device.sqlx 文件中使用的 renderScript JavaScript 函数,其中 Dataform 核心 ref 函数作为实参传递:

${script_builder.renderScript(
  ref("source_table"),
  ["country", "device_type"],
  ["revenue", "pageviews", "sessions"])}

以下代码示例展示了编译为 SQL 的 definitions/stats_per_country_and_device.sqlx 查询:

SELECT country AS country,
       device_type AS device_type,
       SUM(revenue) AS revenue,
       SUM(pageviews) AS pageviews,
       SUM(sessions) AS sessions
FROM my_schema.source_table
GROUP BY 1, 2

如需详细了解 Dataform 核心 ref 函数,请参阅 Dataform 核心

通过软件包在多个代码库中重复使用代码

软件包是 JavaScript 代码的集合,您可以在多个 Dataform 代码库中导入和使用这些代码,以简化工作流开发。

您可以在 Dataform 中创建自己的自定义软件包,也可以使用 GitHub 开源 Dataform 页面上提供的开源 Dataform 软件包。

如需在 Dataform 中使用软件包的内容,您需要在 Dataform 代码库中安装该软件包,然后将其导入到您要使用该软件包的各个 JavaScript 或 SQLX 文件中。如需了解详情,请参阅安装软件包

如需在 Dataform 代码库中安装私有 NPM 软件包,您需要对该软件包进行身份验证

完全使用 JavaScript 创建工作流

本部分介绍了如何使用 JavaScript 在 Dataform 中创建工作流操作。您可能希望使用 JavaScript 而不是 Dataform 核心来在工作流程中重复创建类似元素。

除了使用 SQLX 或 SQLX 与 JavaScript 相结合来开发工作流之外,您还可以仅使用 JavaScript 在 .js 文件中创建工作流操作。您可以使用 Dataform 全局方法和任意 JavaScript ES5 代码(例如循环和常量)在一个 JavaScript 文件中创建多个工作流操作。每个 Dataform 全局 JavaScript 方法都包含可用于配置所创建对象的属性。

您可以在 Dataform 中仅使用 JavaScript 创建以下工作流操作:

  • 数据源声明
  • 手动断言
  • 自定义 SQL 操作

借助 JavaScript,您可以在工作流中重复创建类似的操作。例如,您可以创建工作流中每个表的视图,并移除某些用户 ID。

以下 JavaScript 代码示例可让您创建每个表的视图,其中 user_id 字段的值与 blocked_user_ids 列表中的值不对应:

  const tableNames = ["user_events", "user_settings", "user_logs"];

  tableNames.forEach(tableName => {
    publish(tableName + "_blocked_removed").query(
      ctx => `
        SELECT * FROM ${ctx.ref(tableName)}
        WHERE user_id NOT IN (
          SELECT user_id
          FROM ${ctx.ref("blocked_user_ids")}
        )`
    );
  });

此代码示例会创建三个名为 user_events_blocked_removeduser_settings_blocked_removeduser_logs_blocked_removed 的视图,这些视图不包含任何被屏蔽的用户 ID。

您可以使用 Dataform 全局方法和任意 JavaScript ES5 代码(例如循环和常量)在一个 JavaScript 文件中创建多个操作。

您可以在 Dataform 中使用 JavaScript 定义以下操作:

创建 JavaScript 文件

将用于定义和数据源声明的 JavaScript 文件存储在 definitions/ 目录中。如需在 definitions/ 目录中创建新的 JavaScript 文件,请按以下步骤操作:

  1. 文件窗格中,点击 definitions/ 旁边的 更多

  2. 点击创建文件

  3. 创建新文件窗格中,执行以下操作:

    1. 添加文件路径字段中,在 definitions/ 后面输入文件名,然后输入 .js。例如 definitions/definitions.js

      文件名只能包含数字、字母、连字符和下划线。

    2. 点击创建文件

使用 JavaScript 设置工作流操作属性

您可以使用以下 Dataform 全局方法通过 Dataform 创建 SQL 工作流操作:

  • declare。用于声明数据源。
  • publish。用于定义表。
  • assert。用于创建断言。
  • operate。用于定义自定义 SQL 操作。

每个全局方法都包含可用于配置所创建对象的属性。如需详细了解全局方法及其属性,请参阅 Dataform 核心参考文档

在创建表的 publish() 方法中,您可以通过将表属性作为第二个方法实参传递来设置表属性。

如需将表格属性作为 publish() 的第二个实参传递,请按以下步骤操作:

  1. 在开发工作区的文件窗格中,展开 definitions/

  2. 选择一个 JavaScript 文件。

  3. 在该文件中,以以下格式向 publish() 方法添加表格属性:

     method("first_method_argument", {
       property1: "property1_value",
       property2: "property2_value",
       property3: "property3_value",
     });
    
  4. 可选:点击格式

以下代码示例展示了如何通过将属性作为方法的第二个实参传递给 publish() 方法来设置属性:

  publish("table1", {
    type: "table",
    dependencies: ["other_table"],
    description: {
      "Value is 1"
    }
  }).query(ctx => "SELECT 1 AS test");

在 JavaScript 文件中包含引用

您可以在 JavaScript 文件中引用任何包含函数、宏或常量。如需详细了解 Dataform 中的 include,请参阅本文档的使用 include 在单个代码库中重用代码部分。

在 JavaScript 文件中引用包含文件的语法取决于包含文件的位置。Dataform 会将此类文件存储在 includes 目录中。

参考顶级包括

  • 如需引用顶级包含文件,请在声明变量时引用文件名。

以下代码示例引用了 includes/service.js 文件中的 serviceNameserviceId 变量:

  const {serviceName, serviceId} = service;

引用嵌套的 include

如需引用嵌套的包含文件,请在 JavaScript require 函数中输入文件名。

以下代码示例引用了 includes/allServices/service.js 文件中的 serviceNameserviceId 变量:

  const {serviceName, serviceId} = require("includes/allServices/service.js");

在 JavaScript 方法中使用 Dataform 查询函数

Dataform 提供了许多可在查询中使用的内置函数,例如 refself。如需详细了解 Dataform 内置函数,请参阅 Dataform API 参考文档

如需在 JavaScript 方法中使用内置查询函数,请按照以下步骤操作:

  1. 在开发工作区的文件窗格中,展开 definitions/

  2. 选择一个 JavaScript 文件。

  3. 在该文件中,输入一个全局 Dataform JavaScript 方法。

  4. 在该方法中,输入一个可上下文相关的 ctx 实参。

  5. 可选:如果您使用的是 JavaScript 模板字符串,请将可设置上下文的实参用反引号 `` 括起来。

  6. 在可上下文相关参数中,输入查询函数,并将其参数作为上下文对象。

  7. 可选:点击格式

以下代码示例展示了封装在发布方法的 contextable 实参中的 ref 查询函数:

  publish("example").query(ctx => `SELECT * FROM ${ctx.ref("other_table")}`);

使用 JavaScript 声明工作流数据源

您可以使用 Dataform 的 JavaScript 方法 declare 在一个 JavaScript 声明文件中声明多个数据源。如需详细了解声明方法,请参阅 Dataform 核心参考文档。如需详细了解 Dataform 中的数据源,请参阅声明数据源

如需在 JavaScript 文件中声明数据源,请按以下步骤操作:

  1. 在开发工作区的文件窗格中,展开 definitions/

  2. 选择一个 JavaScript 文件。

  3. 在文件中输入以下代码段:

     declare({
       database: "DATABASE_PROJECT_ID",
       schema: "BIGQUERY_SCHEMA",
       name: "RELATION_NAME",
     });
    

    替换以下内容:

    • DATABASE_PROJECT_ID:包含数据源的项目的 ID
    • BIGQUERY_SCHEMA:外部关系所在的 BigQuery 数据集
    • RELATION_NAME:您之后可在 Dataform 中用于引用数据源的关系的名称
  4. 如需在同一文件中声明其他数据源,请向该文件添加额外的 declare 块。

  5. 可选:点击格式

使用 JavaScript 定义表格

您可以使用 Dataform JavaScript publish 方法创建表。如需详细了解发布方法,请参阅 Dataform 核心参考文档

您可以定义以下类型的表格:

  • 增量表
  • 查看

如需详细了解如何在 Dataform 中定义表,请参阅创建表

如需在 JavaScript 文件中定义表格,请按以下步骤操作:

  1. 在开发工作区的文件窗格中,展开 definitions/

  2. 选择一个 JavaScript 文件。

  3. 在文件中输入以下代码段:

     publish("TABLE_NAME").query(ctx => "SELECT_QUERY");
    

    替换以下内容:

    • TABLE_NAME:表的名称
    • SELECT_QUERY:用于定义表的 SQL SELECT 语句
  4. 如需设置表格类型、添加表格依赖项和添加表格说明,请设置 publish 方法的对象属性

  5. 如需在同一文件中定义其他表格,请重复执行第 3 步和第 4 步。

  6. 可选:点击格式

使用 JavaScript 定义手动断言

您可以使用 Dataform 断言 JavaScript 方法在 JavaScript 文件中创建手动 SQL 断言。如需详细了解断言方法,请参阅 Dataform 核心参考文档

手动断言 SQL 查询必须返回零行。如果查询在运行时返回行,则断言失败。您可以在一个 JavaScript 文件中创建多个断言。

如需详细了解 Dataform 中的断言,请参阅测试数据质量

如需在 JavaScript 文件中创建手动断言,请按以下步骤操作:

  1. 在开发工作区的文件窗格中,展开 definitions/

  2. 选择一个 JavaScript 文件。

  3. 在文件中输入以下代码段:

     assert("ASSERTION_NAME").query(ctx => "CUSTOM_ASSERTION_QUERY");
    

    替换以下内容:

    • ASSERTION_NAME:自定义断言的名称
    • CUSTOM_ASSERTION_QUERY:您的 SQL 断言查询
  4. 如需在同一文件中创建其他断言,请重复执行第 3 步。

  5. 可选:点击格式

以下代码示例展示了一个 JavaScript 断言,该断言用于断言 source_table 中没有值为 NULL

  assert("assertion1").query(ctx => "SELECT * FROM source_table WHERE value IS NULL");

使用 JavaScript 定义自定义 SQL 操作

您可以使用 Dataform 的 operate JavaScript 方法在 JavaScript 文件中定义自定义 SQL 操作。如需详细了解 Dataform 中的自定义 SQL 操作,请参阅创建操作

如需使用 JavaScript 定义自定义 SQL 操作,请按以下步骤操作:

  1. 在开发工作区的文件窗格中,展开 definitions/

  2. 选择一个 JavaScript 文件。

  3. 在文件中输入以下代码段:

     operate("OPERATION_NAME").queries(ctx => "CUSTOM_SQL_QUERY");
    

    替换以下内容:

    • OPERATION_NAME:自定义操作的名称
    • CUSTOM_SQL_QUERY:您的自定义 SQL 查询
  4. 如需在同一文件中定义其他自定义 SQL 操作,请重复执行第 3 步。

  5. 可选:点击格式

以下代码示例展示了 JavaScript 文件中的自定义 SQL 操作,该操作可将单个新行插入 some_table 并将新行的 test_column 设置为 2

  operate("operation1").queries("INSERT INTO some_table (test_column) VALUES (2)");

后续步骤