在 Dataform 中使用 JavaScript

本文档可帮助您了解如何使用 JavaScript 在 Dataform 中开发工作流。本文档还介绍了如何使用 JavaScript 创建工作流操作,以及如何创建 JavaScript 包含项以在 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 代码,您可以创建包含文件。如需在多个 Dataform 代码库中重复使用 JavaScript 代码,您可以创建或导入软件包。

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

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

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

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

使用包含文件在单个代码库中重复使用代码

包含项是仓库的全局 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 文件中引用包含文件

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

在 SQLX 文件中引用顶级包含文件

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

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

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

在 SQLX 文件中引用嵌套的包含文件

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

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

  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 函数搭配使用,您需要将 ref 作为 SQLX 文件中 JavaScript include 函数的参数传递。

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

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 中使用缓慢变化的维度

若要在 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. 在开发工作区中,展开 Files 窗格中的 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 中的包含文件,请参阅本文档的使用包含文件在单个代码库中重复使用代码部分。

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

引用顶级包含

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

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

  const {serviceName, serviceId} = service;

引用嵌套的 include

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

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

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

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

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

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

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

  2. 选择一个 JavaScript 文件。

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

  4. 在该方法中,输入可上下文的 ctx 参数。

  5. 可选:如果您使用的是 JavaScript 模板字符串,请将可上下文参数括在反引号 `` 中。

  6. 在可接受上下文的参数中,输入查询函数及其作为上下文对象的参数。

  7. 可选:点击格式

以下代码示例展示了封装在 publish 方法的上下文可用参数中的 ref 查询函数:

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

使用 JavaScript 声明工作流数据源

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

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

  1. 在开发工作区中的 Files 窗格中,展开 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. 在开发工作区中的 Files 窗格中,展开 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 assert JavaScript 方法在 JavaScript 文件中创建手动 SQL 断言。如需详细了解断言方法,请参阅 Dataform 核心参考文档

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

如需详细了解 Dataform 中的断言,请参阅使用断言测试表

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

  1. 在开发工作区中的 Files 窗格中,展开 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 操作,请参阅添加自定义 SQL 操作

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

  1. 在开发工作区中的 Files 窗格中,展开 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)");

后续步骤