Skip to content

feat(remote): add BigQuery data source - #1066

Open
DoubleCore wants to merge 6 commits into
antvis:oss-camp2026from
DoubleCore:task-1013-bigquery
Open

DoubleCore wants to merge 6 commits into
antvis:oss-camp2026from
DoubleCore:task-1013-bigquery

Conversation

@DoubleCore

Copy link
Copy Markdown
Contributor

Google BigQuery 数据源

为 AVA v4 增加 Google BigQuery 只读数据源(Issue #1013)。

实现要点

  • BigQueryEngine(src/remote/bigquery/engine.ts):通过 QueryConnector 完成 schema 发现、只读 GoogleSQL 执行与 profile。只读双重保障:本地 validateReadOnlyBigQuery 拒绝多语句/非 SELECT/DDL/DML/EXPORT DATA/scripting;生产连接以 useLegacySql: false 运行 query job。
  • 生产 driver @google-cloud/bigquery(bigquery-connector.ts):运行时 require,包缺失不影响类型检查与测试;支持 service-account credentials(对象或 JSON 字符串)、clientEmail+privateKey、location、maxBytesBilled、defaultRowLimit。
  • 内置 mock 适配器(mock.ts):纯内存的只读 GoogleSQL 子集解释器(SELECT/WHERE/GROUP BY/HAVING/ORDER BY/LIMIT/聚合、dataset.INFORMATION_SCHEMA 视图),无需真实 GCP 账号即可跑通 schema/查询/profile/错误处理,供测试与文档示例复现。
  • Schema 发现通过 BigQuery 小写列名的 dataset 级 INFORMATION_SCHEMA.TABLES/.COLUMNS/.KEY_COLUMN_USAGE。
  • 结果限制/异常:limitedBigQuerySql 用 SELECT * FROM (…) LIMIT N 包一层限制行数;maxRows 默认 200、maxResultBytes 默认 1 MiB;查询错误与缺失表透传清晰错误。

注册链路(与 sqlserver 同构)

src/index.ts、src/engines.ts、src/remote/index.ts、src/duckdb/loaders/index.ts(guard)、src/cli/session/protocol.ts(zod source + engineTypeSchema)、src/cli/session/datasets.ts(自动选择 engine)、src/cli/commands/source.ts(帮助文本)、src/types.ts(BigQuerySourceOptions、MockTableSeed、SourceType/EngineConfig)。

文档

  • 站点 site/content/docs/data/sources.mdx(连接字段表 + adapters + 2 个自然语言分析示例)与 engines/remote.mdx
  • 模块 src/remote/bigquery/README.md
  • CLI skill 参考 skills/ava/references/sources.md
  • site/public/logos/bigquery.svg

测试

__tests__/remote/bigquery.test.ts — 31 个 vitest 用例全部通过(schema 发现、profile、只读校验、行数上限/截断、错误传播、dispose、AVA 端到端集成、mock connector)。tsc --noEmit 与仓库 eslint 均通过。全套测试仅有 3 个 Windows 平台既有失败(cli-session win32 guard 与 feishu HOME env),与本 PR 无关。

尽力/mock 模式:未联调真实 GCP。生产 driver 已在代码中,安装 @google-cloud/bigquery 即可真实连接,测试与示例使用内置 mock。

@DoubleCore
DoubleCore force-pushed the task-1013-bigquery branch 2 times, most recently from 2ec231d to 3b4a6e7 Compare November 3, 2026 10:49
@yvonneyx
yvonneyx requested a balanced review from Copilot November 3, 2026 11:05

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved critical defects cause production queries to return empty results, break ESM loading and profiling, and allow the mock tokenizer to hang indefinitely.

19 open issues
What changed in this PR

Adds Google BigQuery as a remote data source for AVA, extending the SDK and CLI toward the read-only query and analysis workflow requested in #1013.

Changes:

  • Introduces a BigQuery engine, production connector, schema discovery, profiling, and GoogleSQL validation.
  • Adds an in-memory mock adapter, sales fixtures, and automated tests.
  • Registers BigQuery in SDK/CLI configuration and documents connection options and analysis examples.
File Description
src/​types.ts Defines BigQuery source options and mock seed types.
src/​remote/​index.ts Exports the BigQuery engine.
src/​remote/​bigquery/​schema.ts Discovers tables, columns, and key metadata.
src/​remote/​bigquery/​README.md Documents architecture, setup, and examples.
src/​remote/​bigquery/​profile.ts Generates profiling queries and parses metrics.
src/​remote/​bigquery/​mock.ts Implements the in-memory query adapter.
src/​remote/​bigquery/​index.ts Exports BigQuery module utilities.
src/​remote/​bigquery/​examples.ts Supplies sample sales and customer data.
src/​remote/​bigquery/​engine.ts Implements the remote analysis engine lifecycle.
src/​remote/​bigquery/​connector.ts Defines connector contracts and adapter selection.
src/​remote/​bigquery/​bigquery-connector.ts Integrates the optional Google Cloud driver.
src/​query/​bigquery.ts Adds query generation, validation, and row limiting.
src/​index.ts Registers BigQuery and exports source types.
src/​index.browser.ts Exports BigQuery-related types for browser consumers.
src/​engines.ts Updates engine availability guidance.
src/​duckdb/​loaders/​index.ts Rejects BigQuery sources in DuckDB.
src/​cli/​session/​protocol.ts Validates BigQuery configuration and engine selection.
src/​cli/​session/​datasets.ts Automatically selects BigQuery for CLI sources.
src/​cli/​commands/​source.ts Adds BigQuery help and configuration examples.
skills/​ava/​references/​sources.md Documents the CLI source workflow.
site/​public/​logos/​bigquery.svg Adds the BigQuery logo.
site/​content/​docs/​en/​engines/​remote.mdx Documents BigQuery among remote engines.
site/​content/​docs/​en/​data/​sources.mdx Adds connection fields and analysis examples.
__tests__/​remote/​bigquery.test.ts Adds mock execution, schema, validation, and profiling tests.

Review effort: Balanced

if (cachedModule !== undefined) return cachedModule;
try {
// eslint-disable-next-line @typescript-eslint/no-var-requires
cachedModule = require('@google-cloud/bigquery') as BigQueryModule;
async query<T extends QueryResultRow = QueryResultRow>(sql: string): Promise<QueryResult & { rows: T[] }> {
await this.connect();
const client = this.client!;
const [, rowsResponse] = await client.createQueryJob({
await this.connect();
const client = this.client!;
const [, rowsResponse] = await client.createQueryJob({
query: sql,
Comment thread src/remote/bigquery/mock.ts Outdated
i = j;
continue;
}
if (/[a-zA-Z_"]/.test(ch)) {
Comment thread src/remote/bigquery/profile.ts Outdated
Comment on lines +8 to +11
import { sqlIdentifier } from '../../util/sql';

import type { MetricField } from '../../util/profile';
import type { LogicalType, Metric, ParsedProfileOptions, Profile, Schema } from '../../types';
Comment thread src/remote/bigquery/profile.ts Outdated
)
)
return 'numeric';
if (/^(string|bytes|json|array|struct)$/.test(base)) return 'string';
Comment thread src/remote/bigquery/profile.ts Outdated
Comment on lines +40 to +42
if (/^date$/.test(base)) return `UNIX_MILLIS(CAST(${column} AS TIMESTAMP))`;
if (/^time$/.test(base)) return `EXTRACT(microsecond FROM ${column}) / 1000`;
return `UNIX_MILLIS(${column})`;
Comment thread src/remote/bigquery/profile.ts Outdated
const value = `CAST(${column!} AS STRING)`;
return `CASE WHEN COUNT(DISTINCT ${value}) > COUNT(*) * ${maxDistinctRatio}
THEN NULL ELSE (
SELECT TO_JSON_STRING(ARRAY_AGG(STRUCT(value, count)) )
Comment thread src/remote/bigquery/schema.ts Outdated

const [columnRows, keyRows] = await Promise.all([
runQuery(`SELECT ${columnsProjection}\nFROM ${ds}.INFORMATION_SCHEMA.COLUMNS\nORDER BY table_name, ordinal_position`) as Promise<unknown>,
runQuery(`SELECT table_name, column_name, ordinal_position\nFROM ${ds}.INFORMATION_SCHEMA.KEY_COLUMN_USAGE\nORDER BY table_name, ordinal_position`) as Promise<unknown>,
Comment thread src/types.ts
Comment on lines +546 to +547
/** BigQuery connection/query timeout in milliseconds (default 60000). */
timeoutMs?: number;
@DoubleCore

Copy link
Copy Markdown
Contributor Author

修复已推送 0732e0ea。按文件聚合处理:

  • mock.ts:双引号 tokenizer 死循环(P1)已修并加 1s timeout 回归;HAVING 按组求值;AND 优先于 OR;NULL 比较按 UNKNOWN;默认 profiling 表达式可在 mock 上跑通。
  • profile.ts:标识符改用反引号(GoogleSQL),更新断言。
  • bigquery-connector.ts:裸 require() 改为惰性动态 import(ESM/CJS 均可用);await job.getQueryResults() 并从 schema.fields 取列元数据;defaultDataset 传给 job options。
  • query/bigquery.ts:GoogleSQL 字面量扫描(双引号 + 反斜杠转义 + doubled delimiter),语句结尾分号 + 尾随注释规范化,execute() 层覆盖。
    验证:vitest run __tests__/remote/bigquery.test.ts → 31 passed;tsc --noEmit rc=0。
    live BigQuery 未验证,仅 mock 驱动 + 单测(本机无 GCP 项目)。

@Keikeikm

Keikeikm commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

@yvonneyx hello,请问可否提供相关账号来进行开发测试?目前google cloud的BigQuery功能使用需要国际信用卡认证,尝试过用虚拟卡visa,但无法认证成功。

@DoubleCore

Copy link
Copy Markdown
Contributor Author

#1013

Add a read-only BigQuery engine and CLI/SDK registration for AVA v4. Uses
the @google-cloud/bigquery driver (runtime require) with a built-in in-memory
mock adapter that needs no GCP project, covering authentication, dataset/table
schema discovery, read-only SELECT with row caps, and error handling.

- src/remote/bigquery/: engine + connector (production driver + mock) +
  schema (dataset INFORMATION_SCHEMA) + per-column profile + seed examples
- src/query/bigquery.ts: GoogleSQL dialect, read-only validation, LIMIT wrapper
- Register bigquery engine/source across src/index, engines, remote/index,
  duckdb loader guard, and CLI session protocol/datasets/source
- Docs: site sources.mdx + remote.mdx, module README, skill reference with two
  natural-language analysis examples; types for BigQuerySourceOptions
- 31 vitest tests against the mock adapter (schema, profile, read-only,
  bounds, errors, dispose, AVA integration)
…mantics, ESM-safe driver load and job results

Signed-off-by: DoubleCore <doublecore@users.noreply.github.com>
@DoubleCore

DoubleCore commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor Author

本轮续修已推送原 PR head 34a83ba4f5e62825e00a60b17ea5bb6d08090a9d,PR 由 CONFLICTING 恢复 MERGEABLE(base=oss-camp2026,changed_files=24)。

  • rebase 到最新 oss-camp2026,共享注册/文档同时保留上游 SQL Server、Tencent Docs 与 BigQuery;相对最新 upstream 的 diff 仅为 BigQuery 范围。
  • 补齐 public mock seed 导出链与相应 mock 测试/README,解决 rebase 后发现的 mock 数据源解析问题。
  • 实跑 npx tsc --noEmit:通过。
  • 实跑 npx vitest run __tests__/remote/bigquery.test.ts:1 file / 35 tests passed。
  • git diff upstream/oss-camp2026...HEAD --check:通过。

本机没有 GCP 项目,仍是 mock 契约验证,不声称真实 BigQuery live 验证。fork PR 的 Actions 仍需维护者触发/批准。

最终 SHA 核验:同 tick 的元数据 amend 将原 PR head 更新为 34a83ba4f5e62825e00a60b17ea5bb6d08090a9d;已核对与上述已测试提交的 tree 完全相同,工作区干净,API 复核仍为 MERGEABLE/base=oss-camp2026。

Preserve Snowflake registrations and current source documentation. Adapt BigQuery to the shared dialect interface and cover CLI engine selection.
@yvonneyx

yvonneyx commented Nov 8, 2026 •

Copy link
Copy Markdown
Contributor

@DoubleCore,基于提交 f76d9f88,这个 BigQuery 接入给 52/100,暂不建议验收。注册和基础链路已经接上,主要缺口在生产 SDK 调用、结果保真和真实接入证据。

评估范围是本分支新增的 BigQuery 实现及其直接影响,仓库既有问题和其他 PR 的实现不计入。首版可以限定一个 project/dataset;完整交付要求这个范围内能正确连接、读取结构、查询和分析,不要求补齐 BigQuery 的所有功能。

项目 得分 依据
技术库选择与依赖集成 11/15 官方 SDK 合适,但未声明依赖和版本,手写类型掩盖了调用错误。
认证与连接 6/10 有 ADC、服务账号入口,缺少实际认证和数据集访问记录。
元数据发现 6/15 有表、列和主键,project/dataset/table 映射需要修正。
查询与作业生命周期 9/15 有执行、超时取消,行数参数位置错误,分页和清理还需验证。
结果类型与列信息 3/15 缺少无损转换,列元数据丢失,空结果没有 schema。
只读、费用与资源限制 6/10 有本地校验和限制选项,读取预算、原生校验及权限说明不足。
数据画像 3/5 指标已接入,但部分类型生成的 SQL 不合法。
SDK / CLI 集成 5/5 注册、配置、路由和会话链路可用。
测试与验收证据 2/8 主要验证自建 mock,缺少真实 GCP 和自然语言结果对照。
文档与可复现示例 1/2 已有示例,配置、导入路径和真实运行步骤需要校正。
合计 52/100

技术选型建议保留官方 @google-cloud/bigquery,把驱动正式接好。 声明支持版本和安装方式,使用官方类型,懒加载可以保留。生产代码里维护 SQL mock 解释器的收益不大;优先在测试中模拟 SDK 请求和响应,让断言覆盖实际生产路径。

验收前重点处理这几项:

  1. 修正 SDK 调用和结果转换。 maxResults 目前传进了作业配置,应按 SDK 的结果读取接口处理。使用 SDK 9.6.0 的本地转换检查已复现:9007199254740993 变为 9007199254740992,日期返回包装对象。需要设置无损读取、明确输出格式,并保留驱动列名和类型;空结果也应有 schema。
  2. 修正元数据和画像。 project、dataset、table 的层级要准确;JSON 列 duplicate_count 等指标应按实际类型决定是否适用。首版只支持普通表也可以,视图、关系和复杂类型按本次声明范围处理,未支持的写清限制,不能静默丢值。
  3. 把只读、费用和读取预算分别落实。 useLegacySql: false 只选择方言,不能证明只读。建议结合原生 dry run 和最小权限;行数、字节、扫描费用、超时取消及执行中 dispose 要各自有效,不能拉完全部数据才截断。
  4. 用真实接入证明生产路径。 按 【2026 开源轻训营专属 Issue】为 AVA 增加 BigQuery 数据源支持 #1013 提供可复现的 ADC/服务账号配置、最小权限和 SDK/CLI 运行记录,至少两个自然语言问题与直接 SQL 逐项对照。当前没有真实 GCP 验证证据。AI 使用报告简要说明参与方式和人工核验内容即可。

测试优先补在现有 __tests__/remote/bigquery.test.ts,覆盖上述关键反例;真实验收复用一个示例脚本,附命令、断言和脱敏结果即可。不要求按问题新建测试文件,也不要求另搭 live 测试套件。项目检查只需处理本分支引入的失败。

…tQueryResults, enforce dry-run budget and lossless decoding

- package.json: declare @google-cloud/bigquery ^9.6.0 in optionalDependencies; the lazy dynamic import and SDK .d.ts types stay (tsc now catches call-site errors)
- bigquery-connector.ts: maxResults/wrapIntegers/autoPaginate moved to the result-read interface (Job#getQueryResults), not the job config; first page only, never pull-all-then-truncate
- budget: dry-run estimate checked against maxBytesBilled before any billable job; the job itself carries server-side maximumBytesBilled; useLegacySql stays a dialect flag only
- lossless decoding: INT64 exact digits via BigQueryInt (regression 9007199254740993->9007199254740992 fixed), DATE/DATETIME/TIME server format strings, TIMESTAMP ISO 8601 UTC, NUMERIC exact decimal string, BYTES base64, STRUCT/ARRAY recursive; column names/types from driver schema; empty results fall back to job-metadata schema
- schema: tableReference maps project (catalog) / dataset (schema) / table; catalog/schema read from INFORMATION_SCHEMA rows; mock INFORMATION_SCHEMA reports the project id like the live views
- profile: duplicate_count-style metrics only for numeric/string/boolean/date columns (JSON/ARRAY/STRUCT stay unknown, no fabricated metrics)
- docs: README + skills/ava/references/sources.md updated (install steps, options, value formats, unsupported views/relationships/complex types)
- tests: SDK request/response stubs covering row-bound placement, budget rejection, lossless values incl. bigint regression, empty-result schema, timeout cancel; mock JSON-column profiling
@DoubleCore

Copy link
Copy Markdown
Contributor Author

已按评审意见修复,head 推进到 b1edc26。逐条对应:

1. 依赖与类型:@google-cloud/bigquery ^9.6.0 已加进 package.json 的 optionalDependencies(保留懒加载),生产代码改用官方 import type,不再手写类型掩盖调用错误。

2. maxResults 位置修正:从作业配置里移除,改放到 getQueryResults 的结果读取选项里;分页与行数上限以 SDK 读取接口为准。

3. 结果无损转换:INT64 用字符串保留精度(9007199254740993 不再变形),DATE/TIMESTAMP/NUMERIC 明确输出格式,保留驱动列名与类型;空结果也从 job metadata 取 schema。

4. 元数据/画像:project / dataset / table 三层映射修正;JSON 列的 duplicate_count 等指标只在类型适用时生成。

5. 只读/费用/读取预算:加 maximumBytesBilled 与 dry run 预算校验(超预算直接拒绝),行数/字节/超时取消/dispose 各自生效;不再先拉全量再截断。

6. 测试:__tests__/remote/bigquery.test.ts 扩到 48 passed,覆盖大整数不变形、空结果 schema、预算拒绝、dispose 清理、超时取消等关键反例。

7. 文档:README 与 examples 的配置、导入路径、真实运行步骤已与实现一致;未支持的视图/关系/复杂类型写清限制。

实跑验证:

  • npx tsc --noEmit 全绿
  • npx vitest run __tests__/remote/bigquery.test.ts → 48 passed
  • npx eslint --ext .ts src/remote/bigquery __tests__/remote/bigquery.test.ts 全绿

未覆盖:本机无 GCP 凭证,真实 BigQuery 接入(ADC/服务账号、最小权限、自然语言与直接 SQL 对照)未实跑验证。

@DoubleCore

DoubleCore commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor Author

感谢 @yvonneyx 的评审,本轮按你列出的缺口逐条修了(commit 705b45e + b1edc26,只动 BigQuery 相关文件)。实跑结果:npx tsc --noEmit 通过;npx vitest run __tests__/remote/bigquery.test.ts 48/48 通过;npx eslint --ext .ts src/remote/bigquery __tests__/remote/bigquery.test.ts 0 error。

1. 依赖与类型:@google-cloud/bigquery(^9.6.0,你验证过的版本)已声明进 package.json 的 optionalDependencies,懒加载 dynamic import 保留;src/remote/bigquery/* 里手写的结构类型全部换成 SDK 官方类型(import type { BigQuery, Job, Query, QueryResultsOptions, TableField, ... } from '@google-cloud/bigquery',type-only,运行时仍是懒加载),tsc 现在能检查调用点。注意:本仓库 .gitignore 第 72 行忽略了 package-lock.json(HEAD 里本来就没有这个文件),所以 lockfile 变更没法提交;安装实测用 npm install --no-audit --no-fund --legacy-peer-deps 成功装上 9.6.0(不加 --legacy-peer-deps 会撞上 base 自带的 vitest 4.1.11 / @vitest/coverage-v8 4.1.12 peer 冲突,这两个与 BigQuery 无关,未处理)。

2. SDK 调用位置:maxResults 已从作业配置里移除,改在结果读取接口 Job#getQueryResults({ maxResults, wrapIntegers: true, autoPaginate: false })(选项类型 QueryResultsOptions / jobs.IGetQueryResultsParams,以安装的 9.6.0 .d.ts 为准)。autoPaginate: false 意味着只取第一页、绝不自动翻完整页——不会先拉全量再截断;行数上限仍由 server-side SELECT * FROM (…) LIMIT N 兜底(测试断言了 maxResults 只出现在 getQueryResults、不在 createQueryJob 请求里)。

3. 结果无损转换:decodeValue 按列 schema 解码——INT64 走 wrapIntegers: true 的 BigQueryInt,保留精确数字字符串(补了 9007199254740993 不变成 9007199254740992 的回归断言);DATE/DATETIME/TIME 输出服务端格式字符串(2023-01-02 / 2023-01-02 10:00:00);TIMESTAMP 输出 ISO 8601 UTC 字符串;NUMERIC/BIGNUMERIC 输出精确十进制字符串;BYTES 输出 base64;BOOLEAN/FLOAT64 保持原生值;STRUCT/ARRAY 递归处理。列名与类型一律来自驱动返回的 schema;空结果会从 job metadata(statistics.query.schema)兜底取 schema(即空结果也有 schema;两处都取不到会显式报错而不是静默吞掉)。

4. 元数据/画像:tableReference 现在按 project(catalog)/ dataset(schema)/ table 三层映射,catalog/schema 值直接取自 dataset 级 INFORMATION_SCHEMA 返回行(mock 的 INFORMATION_SCHEMA 视图同步生成 "table_catalog": projectId,与真实视图一致);profile 的 duplicate_count、distinct_count、top_values 等只在列类型适用(numeric/string/boolean/date)时生成,JSON/ARRAY/STRUCT 等未知类型只保留 null_count 这类类型无关指标,不再对全列硬造(补了 mock 与 SQL 两条路径的断言)。

5. 只读 / 费用 / 读取预算分层:useLegacySql:false 只当方言选择(注释+文档明确它不构成只读证明);预算:配置 maxBytesBilled 时先 dry run 取 statistics.query.totalBytesProcessed,超预算直接拒绝、不启动计费作业,同时作业配置仍带 maximumBytesBilled(服务端兜底);行数(LIMIT + maxResults)、超时(timeout 后 job.cancel())、dispose/close(取消所有 in-flight job 并释放 client)各自生效,各有测试。

6. 测试:集中在现有 __tests__/remote/bigquery.test.ts(48 个用例),生产连接器改为 stub SDK 请求/响应(createQueryJob/getQueryResults/getMetadata/cancel),不再扩写手写 SQL mock 解释器;覆盖了上面所有反例(bigint 回归、预算拒绝、空结果 schema、行界归属、超时取消、close 取消)。

7. 文档/示例:src/remote/bigquery/README.md、skills/ava/references/sources.md、site/content/docs/en/data/sources.mdx 与实现对齐:options 表(含 maxBytesBilled/defaultRowLimit/timeoutMs 语义)、值格式表、安装与真实运行步骤。未支持项已写明:视图/物化视图不进 schema(只认 BASE TABLE)、跨表关系返回空、BigQuery 无强制主键(KEY_COLUMN_USAGE 只作观察)、JSON/ARRAY/STRUCT 列不参与分型指标。

未覆盖 / 未验证:本机无 GCP 凭证,真实 BigQuery 接入未验证(含 dry run/maximumBytesBilled 的线上行为、真实 INT64/DATE/TIMESTAMP 行返解码只对照了 SDK 9.6.0 源码与 .d.ts,未跑 live);全量测试套件里 __tests__/cli.test.ts 一例与 __tests__/duckdb/util/file.test.ts 一例在 base(f76d9f88)上本来就红(Windows 环境相关),与本次改动无关,未处理。

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants