@sqlanvil/cli 1.20.1 → 1.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +59 -39
- package/bundle.js +154 -40
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**SQL workflow tool for BigQuery, Postgres, Supabase, and MySQL/MariaDB.**
|
|
4
4
|
|
|
5
|
-
SQLAnvil is an open-source fork of [Dataform OSS](https://github.com/dataform-co/dataform) (Apache 2.0), extended with first-class PostgreSQL
|
|
5
|
+
SQLAnvil is an open-source fork of [Dataform OSS](https://github.com/dataform-co/dataform) (Apache 2.0), extended with first-class PostgreSQL, Supabase, and MySQL/MariaDB support. Define your data transformations in SQLX, have SQLAnvil compile them to idiomatic SQL for your warehouse, and run, validate, and document the whole DAG from one CLI.
|
|
6
6
|
|
|
7
7
|
> **SQLAnvil is not affiliated with or endorsed by Google.** The Dataform name and related marks are trademarks of Google LLC. See [NOTICE](NOTICE) for attribution.
|
|
8
8
|
|
|
@@ -10,10 +10,21 @@ SQLAnvil is an open-source fork of [Dataform OSS](https://github.com/dataform-co
|
|
|
10
10
|
|
|
11
11
|
## Features
|
|
12
12
|
|
|
13
|
-
- **
|
|
14
|
-
|
|
15
|
-
- **
|
|
16
|
-
- **
|
|
13
|
+
**Four first-class warehouses** — each adapter generates its warehouse's own idiomatic SQL, not translated BigQuery:
|
|
14
|
+
|
|
15
|
+
- **PostgreSQL** — native partitioning (RANGE/LIST/HASH), `INSERT … ON CONFLICT` upserts, btree/hash/gin/gist/brin indexes (unique, partial, `INCLUDE`, opclasses), tablespaces, fillfactor, materialized views with in-place refresh policies
|
|
16
|
+
- **Supabase** — everything Postgres, plus RLS policies, Realtime publications, pgvector indexes, and Supabase Wrappers (FDW) as declarative actions
|
|
17
|
+
- **MySQL / MariaDB** — one adapter validated against both engines: CTAS tables, `ON DUPLICATE KEY UPDATE` incremental upserts, the full `mysql: {}` config block (engine/charset/collation/rowFormat, secondary indexes incl. `FULLTEXT`/`SPATIAL` and prefix lengths, native partitioning), materialized-view emulation
|
|
18
|
+
- **BigQuery** — full upstream support: partitioning, clustering, labels, materialized views, `MERGE`-based incremental upserts
|
|
19
|
+
|
|
20
|
+
**Beyond transformation** — the pieces most SQL workflow tools leave outside the pipeline:
|
|
21
|
+
|
|
22
|
+
- **Cross-warehouse sources** — read BigQuery or MySQL/MariaDB from a Postgres/Supabase warehouse via named `connections:`: a live FDW bridge (Supabase Wrappers) or **runner-extract** (the CLI reads the source at run time and materializes a plain `ref()`-able table — keyless BigQuery supported). `sqlanvil introspect` scaffolds the declarations
|
|
23
|
+
- **File imports & exports** — `type: "import"` loads Parquet/CSV/JSON from `s3://`/`gs://`/local into a `ref()`-able table (DuckDB bridge on Postgres/Supabase, native `LOAD DATA` on BigQuery); `type: "export"` writes query results back out to files
|
|
24
|
+
- **Python script actions** — `python:` in `actions.yaml` runs file-staging and glue scripts as first-class DAG nodes: ordered by dependencies, covered by run history, no warehouse credentials injected (scripts stage files; `import` loads them). SQLAnvil validates the declared environment — interpreter version, `requirements.txt` vs installed packages, syntax — and never installs anything
|
|
25
|
+
- **`sqlanvil validate`** — EXPLAIN/dry-run the *whole DAG* against the live warehouse without executing: an isolated shadow schema of empty stubs lets every downstream `ref()` resolve; results classify as PASS / FAIL / BLOCKED so one real error doesn't cascade
|
|
26
|
+
- **Queryable artifacts** — every compile/run writes a Parquet catalog + run history under `target/`; `sqlanvil query` runs SQL over them, `sqlanvil inspect` summarizes, `sqlanvil docs` renders a self-contained HTML catalog
|
|
27
|
+
- **Release-artifact runs** — `sqlanvil run --graph <file>` executes a stored `compile --json` output exactly as compiled; **named environments** (`--environment`) give per-env schema suffixes and vars
|
|
17
28
|
- **SQLX + YAML + JS** — three authoring modes: SQL with config blocks, `actions.yaml` bulk definitions, or the JavaScript API
|
|
18
29
|
|
|
19
30
|
---
|
|
@@ -24,23 +35,32 @@ SQLAnvil is an open-source fork of [Dataform OSS](https://github.com/dataform-co
|
|
|
24
35
|
npm install -g @sqlanvil/cli
|
|
25
36
|
sqlanvil init my-project
|
|
26
37
|
cd my-project
|
|
27
|
-
# edit workflow_settings.yaml
|
|
38
|
+
# edit workflow_settings.yaml + .df-credentials.json (see below)
|
|
28
39
|
sqlanvil compile
|
|
29
40
|
sqlanvil run
|
|
30
41
|
```
|
|
31
42
|
|
|
32
|
-
**`workflow_settings.yaml`
|
|
43
|
+
**`workflow_settings.yaml` (Postgres/Supabase):** the warehouse is a flat string; connection
|
|
44
|
+
secrets never live here.
|
|
33
45
|
|
|
34
46
|
```yaml
|
|
35
|
-
warehouse:
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
47
|
+
warehouse: postgres # bigquery | postgres | supabase | mysql
|
|
48
|
+
defaultDataset: public # the Postgres schema
|
|
49
|
+
defaultAssertionDataset: sqlanvil_assertions
|
|
50
|
+
sqlanvilCoreVersion: 1.20.1
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**`.df-credentials.json`** (gitignored) holds the connection:
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"host": "localhost",
|
|
58
|
+
"port": 5432,
|
|
59
|
+
"database": "analytics",
|
|
60
|
+
"user": "sqlanvil_writer",
|
|
61
|
+
"password": "...",
|
|
62
|
+
"sslMode": "disable"
|
|
63
|
+
}
|
|
44
64
|
```
|
|
45
65
|
|
|
46
66
|
**First action (`definitions/my_view.sqlx`):**
|
|
@@ -58,23 +78,29 @@ SELECT 1 AS id, 'hello' AS greeting
|
|
|
58
78
|
|
|
59
79
|
## Documentation
|
|
60
80
|
|
|
61
|
-
Full documentation at **[sqlanvil.com](https://sqlanvil.com)**.
|
|
81
|
+
Full documentation at **[sqlanvil.com/docs](https://sqlanvil.com/docs/)**.
|
|
82
|
+
|
|
83
|
+
- [Getting Started](https://sqlanvil.com/docs/getting-started/)
|
|
84
|
+
- Warehouses: [PostgreSQL](https://sqlanvil.com/docs/guides/postgres/) · [Supabase](https://sqlanvil.com/docs/guides/supabase/) · [MySQL/MariaDB](https://sqlanvil.com/docs/guides/mysql/) · [BigQuery](https://sqlanvil.com/docs/guides/bigquery/)
|
|
85
|
+
- [Cross-warehouse sources](https://sqlanvil.com/docs/guides/foreign-wrappers/) · [File Imports](https://sqlanvil.com/docs/guides/imports/) · [File Exports](https://sqlanvil.com/docs/guides/exports/) · [Python Script Actions](https://sqlanvil.com/docs/guides/python-actions/)
|
|
86
|
+
- [Validate](https://sqlanvil.com/docs/guides/validate/) · [Named Environments](https://sqlanvil.com/docs/guides/environments/) · [Artifacts & Catalog](https://sqlanvil.com/docs/guides/artifacts/)
|
|
87
|
+
- [Configs Reference](https://sqlanvil.com/docs/reference/configs/) · [What's New](https://sqlanvil.com/docs/whats-new/)
|
|
62
88
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
- [Supabase Guide](https://sqlanvil.com/guides/supabase/)
|
|
67
|
-
- [Configs Reference](https://sqlanvil.com/reference/configs/)
|
|
89
|
+
Writing sqlanvil projects with an AI agent? Point it at [`AGENTS.md`](AGENTS.md) — it corrects
|
|
90
|
+
the Dataform/BigQuery priors that otherwise produce broken sqlanvil code. Contributor/design
|
|
91
|
+
docs live in the separate [`sqlanvil/docs`](https://github.com/sqlanvil/docs) repo.
|
|
68
92
|
|
|
69
93
|
---
|
|
70
94
|
|
|
71
95
|
## Project layout
|
|
72
96
|
|
|
73
97
|
```
|
|
74
|
-
core/ Compiler + action types (table/view/incremental/assertion/operation/
|
|
75
|
-
cli/ CLI entrypoint and per-adapter glue (cli/api/dbadapters/)
|
|
98
|
+
core/ Compiler + action types (table/view/incremental/assertion/operation/declaration/import/export/script/…)
|
|
99
|
+
cli/ CLI entrypoint and per-adapter glue (cli/api/dbadapters/ — bigquery, postgres, supabase, mysql)
|
|
76
100
|
protos/ Protobuf definitions for core/configs/execution/db_adapter
|
|
77
|
-
|
|
101
|
+
tests/ Integration specs against real warehouses (Postgres, Supabase, MySQL/MariaDB, BigQuery)
|
|
102
|
+
tools/ Bazel rules + Docker fixtures for the integration databases
|
|
103
|
+
examples/ Sample SQLAnvil projects (see examples/supabase_bigquery_mailing_list)
|
|
78
104
|
scripts/ ./scripts/run is the CLI entrypoint wrapper
|
|
79
105
|
```
|
|
80
106
|
|
|
@@ -82,28 +108,22 @@ scripts/ ./scripts/run is the CLI entrypoint wrapper
|
|
|
82
108
|
|
|
83
109
|
## Building from source
|
|
84
110
|
|
|
85
|
-
SQLAnvil uses [Bazel](https://bazel.build) (via Bazelisk). Native Bazel works on
|
|
86
|
-
and Linux
|
|
111
|
+
SQLAnvil uses [Bazel](https://bazel.build) 7 with bzlmod (via Bazelisk). Native Bazel works on
|
|
112
|
+
macOS and Linux:
|
|
87
113
|
|
|
88
114
|
```bash
|
|
89
|
-
# Build the proto layer
|
|
90
|
-
bazel build //protos:sqlanvil_proto
|
|
91
|
-
|
|
92
115
|
# Run the CLI
|
|
93
116
|
./scripts/run help
|
|
94
117
|
|
|
95
118
|
# Run tests
|
|
96
119
|
bazel test //core/... //cli/...
|
|
97
|
-
```
|
|
98
120
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
---
|
|
103
|
-
|
|
104
|
-
## Documentation
|
|
121
|
+
# Integration tests against a local Docker Postgres
|
|
122
|
+
./tools/postgres/run-postgres-db.sh
|
|
123
|
+
```
|
|
105
124
|
|
|
106
|
-
|
|
125
|
+
A Docker-based build container (`./scripts/docker-bazel`) remains available as an optional
|
|
126
|
+
hermetic environment. See [contributing.md](contributing.md) for full instructions.
|
|
107
127
|
|
|
108
128
|
---
|
|
109
129
|
|
|
@@ -111,4 +131,4 @@ Reference docs and design documents live in the separate [`sqlanvil/docs`](https
|
|
|
111
131
|
|
|
112
132
|
Apache License 2.0. See [LICENSE](LICENSE) and [NOTICE](NOTICE).
|
|
113
133
|
|
|
114
|
-
SQLAnvil is a derivative of Dataform OSS (originally developed by Dataform Co and contributed to by Google LLC). It has been fully renamed and extended with first-class PostgreSQL/Supabase support. Licensed under Apache License 2.0.
|
|
134
|
+
SQLAnvil is a derivative of Dataform OSS (originally developed by Dataform Co and contributed to by Google LLC). It has been fully renamed and extended with first-class PostgreSQL/Supabase/MySQL support. Licensed under Apache License 2.0.
|
package/bundle.js
CHANGED
|
@@ -49392,11 +49392,11 @@ function setOrValidateTableEnumType(table) {
|
|
|
49392
49392
|
function prune(compiledGraph, runConfig) {
|
|
49393
49393
|
compiledGraph.tables.forEach(setOrValidateTableEnumType);
|
|
49394
49394
|
const includedActionNames = computeIncludedActionNames(compiledGraph, runConfig);
|
|
49395
|
-
return Object.assign(Object.assign({}, compiledGraph), { tables: compiledGraph.tables.filter(action => includedActionNames.has(targetAsReadableString(action.target))), assertions: compiledGraph.assertions.filter(action => includedActionNames.has(targetAsReadableString(action.target))), operations: compiledGraph.operations.filter(action => includedActionNames.has(targetAsReadableString(action.target))), exports: compiledGraph.exports.filter(action => includedActionNames.has(targetAsReadableString(action.target))), imports: compiledGraph.imports.filter(action => includedActionNames.has(targetAsReadableString(action.target))), scripts: (compiledGraph.scripts || []).filter(action => includedActionNames.has(targetAsReadableString(action.target))) });
|
|
49395
|
+
return Object.assign(Object.assign({}, compiledGraph), { tables: compiledGraph.tables.filter(action => includedActionNames.has(targetAsReadableString(action.target))), assertions: compiledGraph.assertions.filter(action => includedActionNames.has(targetAsReadableString(action.target))), operations: compiledGraph.operations.filter(action => includedActionNames.has(targetAsReadableString(action.target))), exports: compiledGraph.exports.filter(action => includedActionNames.has(targetAsReadableString(action.target))), imports: compiledGraph.imports.filter(action => includedActionNames.has(targetAsReadableString(action.target))), extracts: (compiledGraph.extracts || []).filter(action => includedActionNames.has(targetAsReadableString(action.target))), scripts: (compiledGraph.scripts || []).filter(action => includedActionNames.has(targetAsReadableString(action.target))) });
|
|
49396
49396
|
}
|
|
49397
49397
|
function computeIncludedActionNames(compiledGraph, runConfig) {
|
|
49398
49398
|
var _a, _b, _c;
|
|
49399
|
-
const allActions = [].concat(compiledGraph.tables, compiledGraph.operations, compiledGraph.assertions, compiledGraph.exports, compiledGraph.imports, compiledGraph.scripts || []);
|
|
49399
|
+
const allActions = [].concat(compiledGraph.tables, compiledGraph.operations, compiledGraph.assertions, compiledGraph.exports, compiledGraph.imports, compiledGraph.extracts || [], compiledGraph.scripts || []);
|
|
49400
49400
|
const allActionNames = new Set(allActions.map(action => targetAsReadableString(action.target)));
|
|
49401
49401
|
const allActionsByName = new Map(allActions.map(action => [targetAsReadableString(action.target), action]));
|
|
49402
49402
|
const hasActionSelector = ((_a = runConfig.actions) === null || _a === void 0 ? void 0 : _a.length) > 0;
|
|
@@ -50606,7 +50606,7 @@ function collectEvaluationQueries(queryOrAction, concatenate, queryModifier = (q
|
|
|
50606
50606
|
.filter(validationQuery => !!validationQuery.query);
|
|
50607
50607
|
}
|
|
50608
50608
|
|
|
50609
|
-
const version = "1.
|
|
50609
|
+
const version = "1.21.0";
|
|
50610
50610
|
const dataformVersion = "3.0.61";
|
|
50611
50611
|
|
|
50612
50612
|
async function build(compiledGraph, runConfig, dbadapter) {
|
|
@@ -50995,10 +50995,10 @@ node_modules/
|
|
|
50995
50995
|
function postgresCredentialsTemplate(warehouse) {
|
|
50996
50996
|
const isSupabase = warehouse === "supabase";
|
|
50997
50997
|
const template = {
|
|
50998
|
-
host: isSupabase ? "
|
|
50998
|
+
host: isSupabase ? "aws-1-<region>.pooler.supabase.com" : "localhost",
|
|
50999
50999
|
port: 5432,
|
|
51000
51000
|
database: "postgres",
|
|
51001
|
-
user: "postgres",
|
|
51001
|
+
user: isSupabase ? "postgres.<your-project-ref>" : "postgres",
|
|
51002
51002
|
password: "",
|
|
51003
51003
|
sslMode: isSupabase ? "require" : "disable",
|
|
51004
51004
|
defaultSchema: "public"
|
|
@@ -51041,7 +51041,9 @@ async function init(projectDir, projectConfig) {
|
|
|
51041
51041
|
workflowSettings.defaultProject = projectConfig.defaultDatabase;
|
|
51042
51042
|
workflowSettings.defaultLocation = projectConfig.defaultLocation;
|
|
51043
51043
|
}
|
|
51044
|
-
|
|
51044
|
+
const isPostgresLike = warehouse === "postgres" || warehouse === "supabase";
|
|
51045
|
+
workflowSettings.defaultDataset =
|
|
51046
|
+
projectConfig.defaultSchema || (isPostgresLike ? "public" : "sqlanvil");
|
|
51045
51047
|
workflowSettings.defaultAssertionDataset =
|
|
51046
51048
|
projectConfig.assertionSchema || "sqlanvil_assertions";
|
|
51047
51049
|
if (isBigQuery && projectConfig.defaultIcebergConfig) {
|
|
@@ -51062,6 +51064,17 @@ async function init(projectDir, projectConfig) {
|
|
|
51062
51064
|
if (projectConfig.builtinAssertionNamePrefix) {
|
|
51063
51065
|
workflowSettings.builtinAssertionNamePrefix = projectConfig.builtinAssertionNamePrefix;
|
|
51064
51066
|
}
|
|
51067
|
+
if (isPostgresLike) {
|
|
51068
|
+
workflowSettings.connections = {
|
|
51069
|
+
bigquery_public: sqlanvil.ConnectionConfig.create({
|
|
51070
|
+
platform: "bigquery",
|
|
51071
|
+
project: "bigquery-public-data",
|
|
51072
|
+
dataset: "geo_us_boundaries",
|
|
51073
|
+
billingProject: "REPLACE_WITH_YOUR_GCP_PROJECT",
|
|
51074
|
+
mode: "runner-extract"
|
|
51075
|
+
})
|
|
51076
|
+
};
|
|
51077
|
+
}
|
|
51065
51078
|
fs__namespace$1.writeFileSync(workflowSettingsYamlPath, jsYaml.dump(workflowSettings));
|
|
51066
51079
|
filesWritten.push(workflowSettingsYamlPath);
|
|
51067
51080
|
fs__namespace$1.writeFileSync(gitignorePath, gitIgnoreContents);
|
|
@@ -51070,39 +51083,140 @@ async function init(projectDir, projectConfig) {
|
|
|
51070
51083
|
fs__namespace$1.writeFileSync(path__namespace.join(projectDir, CREDENTIALS_FILENAME), warehouse === "mysql" ? mysqlCredentialsTemplate() : postgresCredentialsTemplate(warehouse));
|
|
51071
51084
|
filesWritten.push(path__namespace.join(projectDir, CREDENTIALS_FILENAME));
|
|
51072
51085
|
}
|
|
51073
|
-
const
|
|
51074
|
-
|
|
51075
|
-
|
|
51076
|
-
|
|
51077
|
-
|
|
51078
|
-
|
|
51079
|
-
const
|
|
51080
|
-
|
|
51081
|
-
|
|
51082
|
-
|
|
51083
|
-
|
|
51084
|
-
|
|
51085
|
-
const
|
|
51086
|
-
|
|
51087
|
-
|
|
51088
|
-
const
|
|
51089
|
-
|
|
51090
|
-
|
|
51091
|
-
const
|
|
51092
|
-
|
|
51093
|
-
|
|
51094
|
-
|
|
51095
|
-
|
|
51096
|
-
|
|
51097
|
-
|
|
51098
|
-
|
|
51099
|
-
|
|
51100
|
-
|
|
51101
|
-
|
|
51102
|
-
|
|
51103
|
-
|
|
51104
|
-
|
|
51105
|
-
|
|
51086
|
+
const mkdir = (...segments) => {
|
|
51087
|
+
const dir = path__namespace.join(projectDir, ...segments);
|
|
51088
|
+
fs__namespace$1.mkdirSync(dir, { recursive: true });
|
|
51089
|
+
dirsCreated.push(dir);
|
|
51090
|
+
return dir;
|
|
51091
|
+
};
|
|
51092
|
+
const write = (filePath, contents) => {
|
|
51093
|
+
fs__namespace$1.writeFileSync(filePath, contents);
|
|
51094
|
+
filesWritten.push(filePath);
|
|
51095
|
+
};
|
|
51096
|
+
const keep = (dir) => write(path__namespace.join(dir, ".gitkeep"), "");
|
|
51097
|
+
mkdir("definitions");
|
|
51098
|
+
const sourcesDir = mkdir("definitions", "sources");
|
|
51099
|
+
const intermediateDir = mkdir("definitions", "intermediate");
|
|
51100
|
+
const salesDir = mkdir("definitions", "outputs", "sales");
|
|
51101
|
+
const reportingDir = mkdir("definitions", "outputs", "reporting");
|
|
51102
|
+
const testDir = mkdir("definitions", "test");
|
|
51103
|
+
keep(mkdir("includes"));
|
|
51104
|
+
const withBigQuerySource = warehouse !== "mysql";
|
|
51105
|
+
write(path__namespace.join(sourcesDir, "app_orders.sqlx"), `-- A declaration: a table that already exists in your warehouse (created by your
|
|
51106
|
+
-- application, an import, or another pipeline). Point name/dataset at a real table —
|
|
51107
|
+
-- downstream models read it with \${ref("app_orders")}.
|
|
51108
|
+
config {
|
|
51109
|
+
type: "declaration",
|
|
51110
|
+
name: "app_orders",
|
|
51111
|
+
description: "Raw orders table owned by the application — replace with one of your tables."
|
|
51112
|
+
}
|
|
51113
|
+
`);
|
|
51114
|
+
write(path__namespace.join(intermediateDir, "stg_app_orders.sqlx"), `config {
|
|
51115
|
+
type: "view",
|
|
51116
|
+
description: "Staging view over the raw orders: rename, cast, and filter here — downstream models only read staged data."
|
|
51117
|
+
}
|
|
51118
|
+
|
|
51119
|
+
SELECT
|
|
51120
|
+
order_id,
|
|
51121
|
+
product,
|
|
51122
|
+
quantity,
|
|
51123
|
+
amount,
|
|
51124
|
+
postal_code,
|
|
51125
|
+
ordered_at
|
|
51126
|
+
FROM \${ref("app_orders")}
|
|
51127
|
+
WHERE amount IS NOT NULL
|
|
51128
|
+
`);
|
|
51129
|
+
write(path__namespace.join(salesDir, "daily_sales.sqlx"), `config {
|
|
51130
|
+
type: "table",
|
|
51131
|
+
description: "Sales by day and product, built from the staged orders."
|
|
51132
|
+
}
|
|
51133
|
+
|
|
51134
|
+
SELECT
|
|
51135
|
+
CAST(ordered_at AS DATE) AS sale_date,
|
|
51136
|
+
product,
|
|
51137
|
+
SUM(quantity) AS units_sold,
|
|
51138
|
+
SUM(amount) AS revenue
|
|
51139
|
+
FROM \${ref("stg_app_orders")}
|
|
51140
|
+
GROUP BY CAST(ordered_at AS DATE), product
|
|
51141
|
+
`);
|
|
51142
|
+
write(path__namespace.join(reportingDir, "product_revenue.sqlx"), `config {
|
|
51143
|
+
type: "view",
|
|
51144
|
+
description: "Revenue by product, straight off the staged orders."
|
|
51145
|
+
}
|
|
51146
|
+
|
|
51147
|
+
SELECT
|
|
51148
|
+
product,
|
|
51149
|
+
SUM(quantity) AS units_sold,
|
|
51150
|
+
SUM(amount) AS revenue
|
|
51151
|
+
FROM \${ref("stg_app_orders")}
|
|
51152
|
+
GROUP BY product
|
|
51153
|
+
`);
|
|
51154
|
+
write(path__namespace.join(testDir, "assert_sales_amounts_positive.sqlx"), `config {
|
|
51155
|
+
type: "assertion",
|
|
51156
|
+
description: "Business rule: every sales row has positive units and revenue."
|
|
51157
|
+
}
|
|
51158
|
+
|
|
51159
|
+
-- An assertion FAILS when its query returns rows — select the violations.
|
|
51160
|
+
SELECT *
|
|
51161
|
+
FROM \${ref("daily_sales")}
|
|
51162
|
+
WHERE units_sold <= 0 OR revenue <= 0
|
|
51163
|
+
`);
|
|
51164
|
+
if (withBigQuerySource) {
|
|
51165
|
+
write(path__namespace.join(sourcesDir, "bigquery_zip_codes.sqlx"), isBigQuery
|
|
51166
|
+
? `-- A declaration for a table in another project: Google's public ZIP geo data.
|
|
51167
|
+
-- BigQuery reads it natively — \${ref("zip_codes")} resolves to the full name.
|
|
51168
|
+
config {
|
|
51169
|
+
type: "declaration",
|
|
51170
|
+
database: "bigquery-public-data",
|
|
51171
|
+
schema: "geo_us_boundaries",
|
|
51172
|
+
name: "zip_codes",
|
|
51173
|
+
description: "US ZIP codes from BigQuery public data."
|
|
51174
|
+
}
|
|
51175
|
+
`
|
|
51176
|
+
: `-- A cross-warehouse source: Google's public ZIP geo data in BigQuery, read through
|
|
51177
|
+
-- the "bigquery_public" connection (see workflow_settings.yaml). With
|
|
51178
|
+
-- mode: runner-extract the CLI reads BigQuery at run time and materializes the rows
|
|
51179
|
+
-- as a plain table here — \${ref("zip_codes")} works like any other source.
|
|
51180
|
+
-- Scaffold real sources with: sqlanvil introspect bigquery_public <dataset.table>
|
|
51181
|
+
config {
|
|
51182
|
+
type: "declaration",
|
|
51183
|
+
connection: "bigquery_public",
|
|
51184
|
+
name: "zip_codes",
|
|
51185
|
+
description: "US ZIP codes from BigQuery public data, materialized by runner-extract.",
|
|
51186
|
+
columnTypes: {
|
|
51187
|
+
zip_code: "text",
|
|
51188
|
+
city: "text",
|
|
51189
|
+
state_code: "text"
|
|
51190
|
+
}
|
|
51191
|
+
}
|
|
51192
|
+
`);
|
|
51193
|
+
write(path__namespace.join(intermediateDir, "stg_zip_codes.sqlx"), `config {
|
|
51194
|
+
type: "view",
|
|
51195
|
+
description: "Staged ZIP geography from the BigQuery source."
|
|
51196
|
+
}
|
|
51197
|
+
|
|
51198
|
+
SELECT
|
|
51199
|
+
zip_code,
|
|
51200
|
+
city,
|
|
51201
|
+
state_code
|
|
51202
|
+
FROM \${ref("zip_codes")}
|
|
51203
|
+
`);
|
|
51204
|
+
write(path__namespace.join(reportingDir, "orders_by_region.sqlx"), `config {
|
|
51205
|
+
type: "table",
|
|
51206
|
+
description: "Orders and revenue by state/city — joins both staged sources."
|
|
51207
|
+
}
|
|
51208
|
+
|
|
51209
|
+
SELECT
|
|
51210
|
+
z.state_code,
|
|
51211
|
+
z.city,
|
|
51212
|
+
COUNT(*) AS orders,
|
|
51213
|
+
SUM(o.amount) AS revenue
|
|
51214
|
+
FROM \${ref("stg_app_orders")} o
|
|
51215
|
+
JOIN \${ref("stg_zip_codes")} z
|
|
51216
|
+
ON z.zip_code = o.postal_code
|
|
51217
|
+
GROUP BY z.state_code, z.city
|
|
51218
|
+
`);
|
|
51219
|
+
}
|
|
51106
51220
|
return {
|
|
51107
51221
|
filesWritten,
|
|
51108
51222
|
dirsCreated
|
|
@@ -56125,7 +56239,7 @@ function runCli() {
|
|
|
56125
56239
|
{
|
|
56126
56240
|
format: `init [${projectDirOption.name}] [${ProjectConfigOptions.defaultDatabase.name}]` +
|
|
56127
56241
|
` [${ProjectConfigOptions.defaultLocation.name}]`,
|
|
56128
|
-
description: "Create a new sqlanvil project (BigQuery, Postgres, or
|
|
56242
|
+
description: "Create a new sqlanvil project (BigQuery, Postgres, Supabase, or MySQL/MariaDB).",
|
|
56129
56243
|
positionalOptions: [
|
|
56130
56244
|
projectDirOption,
|
|
56131
56245
|
positionalOption(ProjectConfigOptions.defaultDatabase.name, {
|