@revos/cli 0.2.0 → 0.2.2
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/LICENSE +9 -0
- package/README.md +286 -41
- package/dist/adapters/oclif/commands/action-runs/get.mjs +1 -1
- package/dist/adapters/oclif/commands/action-runs/list.mjs +8 -2
- package/dist/adapters/oclif/commands/actions/get-input-schema.mjs +2 -2
- package/dist/adapters/oclif/commands/actions/get-params-schema.mjs +2 -2
- package/dist/adapters/oclif/commands/actions/get.mjs +1 -1
- package/dist/adapters/oclif/commands/actions/list.mjs +8 -4
- package/dist/adapters/oclif/commands/ai-instructions/create.mjs +1 -1
- package/dist/adapters/oclif/commands/ai-instructions/delete.mjs +1 -1
- package/dist/adapters/oclif/commands/ai-instructions/get.mjs +1 -1
- package/dist/adapters/oclif/commands/ai-instructions/list.mjs +8 -2
- package/dist/adapters/oclif/commands/ai-instructions/update.mjs +1 -1
- package/dist/adapters/oclif/commands/api.d.mts +11 -0
- package/dist/adapters/oclif/commands/api.mjs +112 -0
- package/dist/adapters/oclif/commands/apply.d.mts +28 -0
- package/dist/adapters/oclif/commands/apply.mjs +77 -0
- package/dist/adapters/oclif/commands/auth/login.d.mts +5 -4
- package/dist/adapters/oclif/commands/auth/login.mjs +22 -11
- package/dist/adapters/oclif/commands/auth/logout.d.mts +1 -1
- package/dist/adapters/oclif/commands/auth/logout.mjs +7 -3
- package/dist/adapters/oclif/commands/auth/status.d.mts +2 -2
- package/dist/adapters/oclif/commands/auth/status.mjs +2 -2
- package/dist/adapters/oclif/commands/connections/create.d.mts +6 -0
- package/dist/adapters/oclif/commands/connections/create.mjs +8 -0
- package/dist/adapters/oclif/commands/connections/delete.d.mts +6 -0
- package/dist/adapters/oclif/commands/connections/delete.mjs +8 -0
- package/dist/adapters/oclif/commands/connections/get.d.mts +6 -0
- package/dist/adapters/oclif/commands/connections/get.mjs +8 -0
- package/dist/adapters/oclif/commands/connections/list.d.mts +6 -0
- package/dist/adapters/oclif/commands/connections/list.mjs +14 -0
- package/dist/adapters/oclif/commands/connections/update.d.mts +6 -0
- package/dist/adapters/oclif/commands/connections/update.mjs +8 -0
- package/dist/adapters/oclif/commands/cubes/create.d.mts +6 -0
- package/dist/adapters/oclif/commands/cubes/create.mjs +8 -0
- package/dist/adapters/oclif/commands/cubes/delete.d.mts +6 -0
- package/dist/adapters/oclif/commands/cubes/delete.mjs +8 -0
- package/dist/adapters/oclif/commands/cubes/get.d.mts +6 -0
- package/dist/adapters/oclif/commands/cubes/get.mjs +8 -0
- package/dist/adapters/oclif/commands/cubes/list.d.mts +6 -0
- package/dist/adapters/oclif/commands/cubes/list.mjs +13 -0
- package/dist/adapters/oclif/commands/cubes/update.d.mts +6 -0
- package/dist/adapters/oclif/commands/cubes/update.mjs +8 -0
- package/dist/adapters/oclif/commands/diff.d.mts +27 -0
- package/dist/adapters/oclif/commands/diff.mjs +66 -0
- package/dist/adapters/oclif/commands/gservice-account-keys/get.mjs +1 -1
- package/dist/adapters/oclif/commands/gservice-account-keys/reveal.mjs +2 -2
- package/dist/adapters/oclif/commands/gservice-accounts/create.mjs +1 -1
- package/dist/adapters/oclif/commands/gservice-accounts/delete.mjs +1 -1
- package/dist/adapters/oclif/commands/gservice-accounts/get.mjs +1 -1
- package/dist/adapters/oclif/commands/gservice-accounts/list.mjs +7 -2
- package/dist/adapters/oclif/commands/init.d.mts +2 -1
- package/dist/adapters/oclif/commands/init.mjs +28 -24
- package/dist/adapters/oclif/commands/org/create.mjs +1 -1
- package/dist/adapters/oclif/commands/org/current.d.mts +2 -2
- package/dist/adapters/oclif/commands/org/current.mjs +2 -2
- package/dist/adapters/oclif/commands/org/get.mjs +1 -1
- package/dist/adapters/oclif/commands/org/list.d.mts +3 -11
- package/dist/adapters/oclif/commands/org/list.mjs +26 -26
- package/dist/adapters/oclif/commands/org/switch.d.mts +3 -2
- package/dist/adapters/oclif/commands/org/switch.mjs +13 -5
- package/dist/adapters/oclif/commands/pull.d.mts +28 -0
- package/dist/adapters/oclif/commands/pull.mjs +88 -0
- package/dist/adapters/oclif/commands/score-groups/create.mjs +3 -2
- package/dist/adapters/oclif/commands/score-groups/delete.mjs +1 -1
- package/dist/adapters/oclif/commands/score-groups/get.mjs +1 -1
- package/dist/adapters/oclif/commands/score-groups/list.mjs +3 -2
- package/dist/adapters/oclif/commands/score-groups/update.mjs +1 -1
- package/dist/adapters/oclif/commands/scores/create.mjs +3 -2
- package/dist/adapters/oclif/commands/scores/delete.mjs +1 -1
- package/dist/adapters/oclif/commands/scores/list.mjs +3 -2
- package/dist/adapters/oclif/commands/scores/update.mjs +1 -1
- package/dist/adapters/oclif/commands/segments/create.mjs +1 -1
- package/dist/adapters/oclif/commands/segments/delete.mjs +1 -1
- package/dist/adapters/oclif/commands/segments/evaluate.mjs +2 -2
- package/dist/adapters/oclif/commands/segments/get-evaluation-history.mjs +2 -2
- package/dist/adapters/oclif/commands/segments/get-version.mjs +2 -2
- package/dist/adapters/oclif/commands/segments/get.mjs +1 -1
- package/dist/adapters/oclif/commands/segments/list-versions.mjs +16 -5
- package/dist/adapters/oclif/commands/segments/list.mjs +9 -2
- package/dist/adapters/oclif/commands/segments/restore-version.mjs +2 -2
- package/dist/adapters/oclif/commands/segments/update.mjs +1 -1
- package/dist/adapters/oclif/commands/sources/create.d.mts +11 -0
- package/dist/adapters/oclif/commands/sources/create.mjs +16 -0
- package/dist/adapters/oclif/commands/sources/delete.d.mts +6 -0
- package/dist/adapters/oclif/commands/sources/delete.mjs +8 -0
- package/dist/adapters/oclif/commands/sources/get.d.mts +6 -0
- package/dist/adapters/oclif/commands/sources/get.mjs +8 -0
- package/dist/adapters/oclif/commands/sources/list-streams.d.mts +6 -0
- package/dist/adapters/oclif/commands/sources/list-streams.mjs +31 -0
- package/dist/adapters/oclif/commands/sources/list.d.mts +6 -0
- package/dist/adapters/oclif/commands/sources/list.mjs +13 -0
- package/dist/adapters/oclif/commands/sources/update.d.mts +15 -0
- package/dist/adapters/oclif/commands/sources/update.mjs +21 -0
- package/dist/adapters/oclif/commands/status.d.mts +26 -0
- package/dist/adapters/oclif/commands/status.mjs +77 -0
- package/dist/adapters/oclif/commands/table-views/create.mjs +3 -2
- package/dist/adapters/oclif/commands/table-views/delete.mjs +1 -1
- package/dist/adapters/oclif/commands/table-views/list.mjs +3 -2
- package/dist/adapters/oclif/commands/table-views/update.mjs +1 -1
- package/dist/adapters/oclif/commands/tables/create.mjs +1 -1
- package/dist/adapters/oclif/commands/tables/delete.mjs +1 -1
- package/dist/adapters/oclif/commands/tables/get.mjs +1 -1
- package/dist/adapters/oclif/commands/tables/list.mjs +3 -2
- package/dist/adapters/oclif/commands/tables/update.mjs +1 -1
- package/dist/{base.command-d7VW6WTp.d.mts → base.command-D7X3ZNtY.d.mts} +0 -1
- package/dist/{base.command-DlVQ9Cqa.mjs → base.command-cV5d65r8.mjs} +15 -12
- package/dist/chunk-CfYAbeIz.mjs +13 -0
- package/dist/core-CMrP5BQS.mjs +2378 -0
- package/dist/{factory-D9sR_S_g.mjs → factory-C6XLqhT9.mjs} +44 -10
- package/dist/iac-render-BSZZEP0n.mjs +17 -0
- package/dist/index-BqKwXXAo.d.mts +598 -0
- package/dist/index.d.mts +3 -4
- package/dist/index.mjs +2 -2
- package/dist/{presets-Cvazkjmu.mjs → presets-CJbFbHlw.mjs} +35 -8
- package/dist/templates/.claude/settings.json +39 -0
- package/dist/templates/.devcontainer/devcontainer.json +2 -2
- package/dist/templates/.devcontainer/setup.sh +3 -0
- package/dist/templates/AGENTS.md +36 -13
- package/dist/templates/dbt/dbt_project.yml +2 -2
- package/dist/templates/skills/create-connections/SKILL.md +210 -0
- package/dist/templates/skills/create-connections/references/mappers.md +152 -0
- package/dist/templates/skills/{create-semantic-model → create-cubes}/SKILL.md +28 -26
- package/dist/templates/skills/create-cubes/references/bq-pk-fk-conventions.md +183 -0
- package/dist/templates/skills/{create-semantic-model → create-cubes}/references/cube-examples.md +85 -7
- package/dist/templates/skills/create-cubes/references/hubspot-entities.md +289 -0
- package/dist/templates/skills/create-cubes/references/jira-entities.md +201 -0
- package/dist/templates/skills/create-cubes/references/netsuite-entities.md +121 -0
- package/dist/templates/skills/create-cubes/references/stripe-entities.md +114 -0
- package/dist/templates/skills/create-dbt-transformations/SKILL.md +62 -33
- package/dist/templates/skills/create-dbt-transformations/references/edge-cases.md +21 -3
- package/dist/templates/skills/create-dbt-transformations/references/schema-conventions.md +21 -7
- package/dist/templates/skills/create-dbt-transformations/references/sql-templates.md +34 -20
- package/dist/templates/skills/explore-lakehouse/SKILL.md +8 -4
- package/dist/templates/skills/load-sample-data/SKILL.md +119 -0
- package/dist/templates/skills/visualize-semantic-model/SKILL.md +159 -0
- package/dist/templates/skills/visualize-semantic-model/scripts/render_graph.py +186 -0
- package/dist/{types-Y_ht_ja5.d.mts → types-CGjxcj4L.d.mts} +3 -0
- package/package.json +48 -6
- package/dist/adapters/oclif/commands/overlays/diff.d.mts +0 -19
- package/dist/adapters/oclif/commands/overlays/diff.mjs +0 -80
- package/dist/adapters/oclif/commands/overlays/pull.d.mts +0 -15
- package/dist/adapters/oclif/commands/overlays/pull.mjs +0 -44
- package/dist/adapters/oclif/commands/overlays/push.d.mts +0 -18
- package/dist/adapters/oclif/commands/overlays/push.mjs +0 -59
- package/dist/adapters/oclif/commands/overlays/status.d.mts +0 -18
- package/dist/adapters/oclif/commands/overlays/status.mjs +0 -53
- package/dist/core-gKJ_V-K5.mjs +0 -973
- package/dist/index-KAzwt5vr.d.mts +0 -190
- package/dist/types-C_p_6rkj.d.mts +0 -69
- /package/dist/templates/skills/{create-semantic-model → create-cubes}/references/key-patterns.md +0 -0
- /package/dist/templates/skills/{create-semantic-model → create-cubes}/references/validation-queries.md +0 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Stripe Entities Reference
|
|
2
|
+
|
|
3
|
+
## Table naming
|
|
4
|
+
|
|
5
|
+
Airbyte syncs Stripe tables with a configurable prefix (default: `stripe_`).
|
|
6
|
+
Inspect the BigQuery dataset to confirm:
|
|
7
|
+
|
|
8
|
+
```sql
|
|
9
|
+
SELECT table_name FROM `<dataset>.INFORMATION_SCHEMA.TABLES`
|
|
10
|
+
WHERE table_name LIKE '%customers%' OR table_name LIKE '%invoices%'
|
|
11
|
+
ORDER BY table_name LIMIT 20;
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Throughout this document `<prefix>` is a placeholder for that prefix.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Primary entities
|
|
19
|
+
|
|
20
|
+
| Cube name | BigQuery table | PK | Notes |
|
|
21
|
+
| ----------------------- | ----------------------- | ---- | -------------------------------- |
|
|
22
|
+
| `<prefix>customers` | `<prefix>customers` | `id` | `name` is display name |
|
|
23
|
+
| `<prefix>subscriptions` | `<prefix>subscriptions` | `id` | FK `customer` (→ customers.id) |
|
|
24
|
+
| `<prefix>invoices` | `<prefix>invoices` | `id` | FK `customer`, FK `subscription` |
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Relationship graph
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
customers ──< subscriptions ──< invoices
|
|
32
|
+
└────────────────────────< invoices
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
- customer → subscriptions: `one_to_many` via `subscriptions.customer = customers.id`
|
|
36
|
+
- customer → invoices: `one_to_many` via `invoices.customer = customers.id`
|
|
37
|
+
- subscription → invoices: `one_to_many` via `invoices.subscription = subscriptions.id`
|
|
38
|
+
- subscription → latest_invoice: `many_to_one` via `subscriptions.latest_invoice = latest_invoice.id`
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Standard cube definitions
|
|
43
|
+
|
|
44
|
+
### customers
|
|
45
|
+
|
|
46
|
+
```yaml
|
|
47
|
+
name: <prefix>customers
|
|
48
|
+
sql_table: "`<dataset>.<prefix>customers`"
|
|
49
|
+
joins:
|
|
50
|
+
<prefix>subscriptions:
|
|
51
|
+
relationship: one_to_many
|
|
52
|
+
sql: "${CUBE}.id = ${<prefix>subscriptions.customer}"
|
|
53
|
+
<prefix>invoices:
|
|
54
|
+
relationship: one_to_many
|
|
55
|
+
sql: "${CUBE}.id = ${<prefix>invoices.customer}"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### subscriptions
|
|
59
|
+
|
|
60
|
+
```yaml
|
|
61
|
+
name: <prefix>subscriptions
|
|
62
|
+
sql_table: "`<dataset>.<prefix>subscriptions`"
|
|
63
|
+
joins:
|
|
64
|
+
<prefix>customers:
|
|
65
|
+
relationship: many_to_one
|
|
66
|
+
sql: "${CUBE}.customer = ${<prefix>customers.id}"
|
|
67
|
+
<prefix>invoices:
|
|
68
|
+
relationship: one_to_many
|
|
69
|
+
sql: "${CUBE}.id = ${<prefix>invoices.subscription}"
|
|
70
|
+
<prefix>latest_invoice:
|
|
71
|
+
relationship: many_to_one
|
|
72
|
+
sql: "${CUBE}.latest_invoice = ${<prefix>latest_invoice.id}"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### invoices
|
|
76
|
+
|
|
77
|
+
```yaml
|
|
78
|
+
name: <prefix>invoices
|
|
79
|
+
sql_table: "`<dataset>.<prefix>invoices`"
|
|
80
|
+
joins:
|
|
81
|
+
<prefix>customers:
|
|
82
|
+
relationship: many_to_one
|
|
83
|
+
sql: "${CUBE}.customer = ${<prefix>customers.id}"
|
|
84
|
+
<prefix>subscriptions:
|
|
85
|
+
relationship: many_to_one
|
|
86
|
+
sql: "${CUBE}.subscription = ${<prefix>subscriptions.id}"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Special cube: latest_invoice
|
|
92
|
+
|
|
93
|
+
`latest_invoice` is an alias for the `invoices` table (public: false) used
|
|
94
|
+
exclusively for the `subscriptions.latest_invoice` FK join. Needed because
|
|
95
|
+
Cube.js does not support two joins to the same table under the same cube name.
|
|
96
|
+
|
|
97
|
+
```yaml
|
|
98
|
+
name: <prefix>latest_invoice
|
|
99
|
+
sql_table: "`<dataset>.<prefix>invoices`"
|
|
100
|
+
public: false
|
|
101
|
+
joins:
|
|
102
|
+
<prefix>subscriptions:
|
|
103
|
+
relationship: one_to_many
|
|
104
|
+
sql: "${CUBE}.id = ${<prefix>subscriptions.latest_invoice}"
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Common pitfalls
|
|
110
|
+
|
|
111
|
+
1. **`latest_invoice` must be a separate cube** — subscriptions needs both `invoices` (for all invoices) and `latest_invoice` (for the most recent one). Same physical table, different cube names.
|
|
112
|
+
2. **FK column names without suffix** — `subscriptions.customer` is the raw Stripe customer ID (not `customer_id`). Same for `invoices.subscription` and `invoices.customer`. Check actual column names in INFORMATION_SCHEMA.
|
|
113
|
+
3. **Stripe IDs are strings** — all IDs start with a prefix (`cus_`, `sub_`, `in_`, etc.). No casting needed.
|
|
114
|
+
4. **Timestamps** — Stripe tables from Airbyte use `_airbyte_extracted_at` as the sync timestamp. Use it for `refresh_key`.
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: create-dbt-transformations
|
|
3
|
-
description: Create new dbt transformations (
|
|
3
|
+
description: Create new dbt transformations (silver/gold models) in the RevOS dbt project. Use when asked to create a dbt model, build a transformation, add a new layer model, declare a raw source, or register a new raw table. Bronze is source-declarations only — no SQL files. Covers dbt project conventions, sources, materialization, schema.yml, and validation commands.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Create dbt Transformations
|
|
7
7
|
|
|
8
|
-
Use this skill to generate SQL models, declare sources, update `schema.yml`, and validate models with `
|
|
8
|
+
Use this skill to generate SQL models, declare sources, update `schema.yml`, and validate models with `dbt run` / `dbt test`.
|
|
9
9
|
|
|
10
10
|
For BigQuery exploration (listing datasets, inspecting raw tables, previewing rows, null rates), load the `explore-lakehouse` skill. If that skill is not installed, fall back to:
|
|
11
11
|
|
|
@@ -22,32 +22,35 @@ Warn the user: "The `explore-lakehouse` skill is not installed — using `bq sho
|
|
|
22
22
|
## Layer Conventions
|
|
23
23
|
|
|
24
24
|
- **gold** — business-ready models exposed for reporting or downstream consumption.
|
|
25
|
-
- **silver** — cleaned, deduplicated, type-conformed intermediates.
|
|
26
|
-
- **bronze** —
|
|
25
|
+
- **silver** — cleaned, deduplicated, type-conformed intermediates. Lowest SQL layer; reads raw data via `{{ source('bronze', '<table>') }}`.
|
|
26
|
+
- **bronze** — **not a SQL layer**. Holds only `dbt/models/bronze/schema.yml`, which declares raw tables as dbt sources. No `.sql` files belong under `dbt/models/bronze/`.
|
|
27
27
|
|
|
28
28
|
When layer is not obvious from context, ask (see Checkpoint 1).
|
|
29
29
|
|
|
30
30
|
## Sources (bronze layer)
|
|
31
31
|
|
|
32
|
-
Raw tables
|
|
32
|
+
Raw tables loaded into the warehouse by your ingestion pipeline are not dbt models. Declare them as dbt sources so silver models can reference them with `{{ source() }}`.
|
|
33
33
|
|
|
34
34
|
Sources are declared in `dbt/models/bronze/schema.yml` under a `sources:` block using `schema` (the BigQuery dataset):
|
|
35
35
|
|
|
36
36
|
```yaml
|
|
37
37
|
sources:
|
|
38
|
-
- name:
|
|
38
|
+
- name: bronze
|
|
39
39
|
schema: "{{ env_var('REVOS_BQ_DATASET') }}"
|
|
40
40
|
tables:
|
|
41
41
|
- name: hubspot_contacts
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
Reference in
|
|
44
|
+
Reference in silver SQL:
|
|
45
45
|
|
|
46
46
|
```sql
|
|
47
|
-
|
|
47
|
+
-- dbt/models/silver/silver_hubspot_contacts.sql
|
|
48
|
+
SELECT * FROM {{ source('bronze', 'hubspot_contacts') }}
|
|
48
49
|
```
|
|
49
50
|
|
|
50
|
-
|
|
51
|
+
`{{ source('bronze', 'hubspot_contacts') }}` resolves to `${REVOS_BQ_DATASET}.hubspot_contacts` — the same dataset where raw tables live — so silver has direct access without a bronze SQL view in between.
|
|
52
|
+
|
|
53
|
+
See [schema-conventions.md](references/schema-conventions.md) for the full declaration pattern.
|
|
51
54
|
|
|
52
55
|
## Materialization
|
|
53
56
|
|
|
@@ -63,24 +66,24 @@ Materialized table lives at: `$REVOS_BQ_DATASET.<model_name>`
|
|
|
63
66
|
|
|
64
67
|
**When to use `{{ ref() }}` vs. `{{ source() }}`:**
|
|
65
68
|
|
|
66
|
-
| Context
|
|
67
|
-
|
|
|
68
|
-
| dbt SQL → other dbt model
|
|
69
|
-
| dbt SQL → raw
|
|
69
|
+
| Context | Use |
|
|
70
|
+
| -------------------------------------------------- | ----------------------------------- |
|
|
71
|
+
| dbt SQL → other dbt model | `{{ ref('<model>') }}` |
|
|
72
|
+
| dbt SQL → raw table (silver reading from `bronze`) | `{{ source('bronze', '<table>') }}` |
|
|
73
|
+
|
|
74
|
+
Silver is the lowest SQL layer — `{{ source('bronze', ...) }}` is used in silver only. Gold reads from silver via `{{ ref() }}`. There are no SQL files in `dbt/models/bronze/`.
|
|
70
75
|
|
|
71
76
|
Always declare raw tables as sources before referencing them. Do not use bare fully qualified names — that bypasses dbt's dependency graph and source freshness tracking.
|
|
72
77
|
|
|
73
78
|
## Standard dbt Commands
|
|
74
79
|
|
|
75
|
-
Always use the `revos` wrapper:
|
|
76
|
-
|
|
77
80
|
```bash
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
dbt parse # validate syntax (no warehouse)
|
|
82
|
+
dbt compile --select <model> # resolve refs, produce compiled SQL
|
|
83
|
+
dbt run --select <model> # execute against warehouse
|
|
84
|
+
dbt test --select <model> # run tests
|
|
85
|
+
dbt build --select <model> # run + test
|
|
86
|
+
dbt build --select path:models/<layer> # entire layer
|
|
84
87
|
```
|
|
85
88
|
|
|
86
89
|
---
|
|
@@ -91,16 +94,16 @@ revos dbt build --select path:models/<layer> # entire layer
|
|
|
91
94
|
|
|
92
95
|
For each transformation (one at a time — do not batch):
|
|
93
96
|
|
|
94
|
-
1. Determine the target layer (Checkpoint 1 if unclear).
|
|
97
|
+
1. Determine the target layer — **silver** or **gold** only (Checkpoint 1 if unclear). Refuse bronze SQL models (see Checkpoint 4).
|
|
95
98
|
2. Determine the model name.
|
|
96
99
|
3. Check if that model already exists (Checkpoint 2 if yes).
|
|
97
100
|
4. Gather source data and transformation logic. For bridge models, apply the bridge template ([sql-templates.md](references/sql-templates.md)).
|
|
98
|
-
5.
|
|
99
|
-
6. Generate `dbt/models/<
|
|
101
|
+
5. If the model reads raw data, ensure each raw table is declared under the `bronze` source in `dbt/models/bronze/schema.yml`; add it if missing.
|
|
102
|
+
6. Generate `dbt/models/<silver|gold>/<model_name>.sql`. **Never** generate `.sql` files under `dbt/models/bronze/`.
|
|
100
103
|
7. Detect the primary key (Checkpoint 3 if ambiguous).
|
|
101
104
|
8. Add model entry to `dbt/models/<layer>/schema.yml` with PK and FK tests. See [schema-conventions.md](references/schema-conventions.md).
|
|
102
|
-
9. Run `
|
|
103
|
-
10. Run `
|
|
105
|
+
9. Run `dbt run --select <model_name>` and report result.
|
|
106
|
+
10. Run `dbt test --select <model_name>` and report result.
|
|
104
107
|
11. Summarize (see Final Response Format).
|
|
105
108
|
|
|
106
109
|
For multiple transformations in one request: repeat steps 1–11 per model in order.
|
|
@@ -117,8 +120,9 @@ Ask if the layer is not obvious:
|
|
|
117
120
|
Which layer should this transformation live in?
|
|
118
121
|
|
|
119
122
|
- gold: business-ready, exposed for reporting or downstream consumption
|
|
120
|
-
- silver: cleaned/intermediate,
|
|
121
|
-
|
|
123
|
+
- silver: cleaned/intermediate, reads raw via `{{ source('bronze', ...) }}`
|
|
124
|
+
|
|
125
|
+
(bronze is not a SQL layer — it only holds `schema.yml` source declarations.)
|
|
122
126
|
```
|
|
123
127
|
|
|
124
128
|
Layer is obvious when the user explicitly names it.
|
|
@@ -150,6 +154,21 @@ I could not unambiguously detect the primary key. Candidates:
|
|
|
150
154
|
Which column(s) should be the primary key?
|
|
151
155
|
```
|
|
152
156
|
|
|
157
|
+
### Checkpoint 4: Bronze SQL Model Refused
|
|
158
|
+
|
|
159
|
+
If the user explicitly asks to create a bronze SQL model:
|
|
160
|
+
|
|
161
|
+
```text
|
|
162
|
+
Bronze is not a SQL layer in this project — it only holds source
|
|
163
|
+
declarations in `dbt/models/bronze/schema.yml`. Silver reads raw data
|
|
164
|
+
directly via `{{ source('bronze', '<raw_table>') }}`.
|
|
165
|
+
|
|
166
|
+
Would you like to create this as a silver model instead?
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Do not generate any file under `dbt/models/bronze/` other than
|
|
170
|
+
`schema.yml`.
|
|
171
|
+
|
|
153
172
|
---
|
|
154
173
|
|
|
155
174
|
## Primary Key Detection
|
|
@@ -169,12 +188,22 @@ If none produce a clear answer → Checkpoint 3.
|
|
|
169
188
|
|
|
170
189
|
A column is a FK candidate if it matches `<entity>_id` where `<entity>` ≠ model's own entity, is not part of the PK, and is not nullable by design. Add `not_null` test only (no `relationships` tests by default).
|
|
171
190
|
|
|
191
|
+
## Timestamp Column Propagation (Gold Models)
|
|
192
|
+
|
|
193
|
+
Every gold model **must** propagate at least one timestamp column so downstream cubes can use SQL-based `refresh_key` (see `create-cubes` skill). Priority:
|
|
194
|
+
|
|
195
|
+
1. An ingestion-time column on the raw table (e.g. Airbyte writes `_airbyte_extracted_at`) — propagate when present.
|
|
196
|
+
2. `updated_at` / `modified_at` — CDC-friendly streams.
|
|
197
|
+
3. `created_at` — insert-only fact tables.
|
|
198
|
+
|
|
199
|
+
If the upstream source has none of these, document it in a SQL comment: `-- no timestamp column available from source`.
|
|
200
|
+
|
|
172
201
|
## SQL File Generation
|
|
173
202
|
|
|
174
203
|
See [sql-templates.md](references/sql-templates.md) for:
|
|
175
204
|
|
|
176
|
-
-
|
|
177
|
-
- Standard
|
|
205
|
+
- Standard silver model template (reads raw via `{{ source('bronze', ...) }}`)
|
|
206
|
+
- Standard gold model template (reads silver via `{{ ref() }}`)
|
|
178
207
|
- Bridge model (JSON array) template with concrete example
|
|
179
208
|
- Bridge model naming convention and SQL content rules
|
|
180
209
|
|
|
@@ -193,7 +222,7 @@ See [edge-cases.md](references/edge-cases.md) for: missing SQL details, missing
|
|
|
193
222
|
```text
|
|
194
223
|
Created dbt transformation: <model_name>
|
|
195
224
|
|
|
196
|
-
Layer: <
|
|
225
|
+
Layer: <silver | gold>
|
|
197
226
|
File: dbt/models/<layer>/<model_name>.sql
|
|
198
227
|
Materialization: <inherited: table | overridden: <type>>
|
|
199
228
|
Primary key: <pk_column> (or composite: <col_1>, <col_2>)
|
|
@@ -206,8 +235,8 @@ Tests:
|
|
|
206
235
|
- not_null on <fk>: added
|
|
207
236
|
|
|
208
237
|
Validation:
|
|
209
|
-
-
|
|
210
|
-
-
|
|
238
|
+
- dbt run: passed | failed
|
|
239
|
+
- dbt test: passed | failed
|
|
211
240
|
|
|
212
241
|
Physical table after run:
|
|
213
242
|
`<resolved_dataset>.<model_name>`
|
|
@@ -26,15 +26,33 @@ The transformation you described references `<missing_model>`, which does not
|
|
|
26
26
|
exist in dbt/models/. Should I create that model first?
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
## Source is a raw
|
|
29
|
+
## Source is a raw table not yet declared as a dbt source
|
|
30
30
|
|
|
31
|
-
Declare it
|
|
31
|
+
Declare it under `sources: - name: bronze` in `dbt/models/bronze/schema.yml`
|
|
32
|
+
first (see [schema-conventions.md](schema-conventions.md)), then reference it
|
|
33
|
+
with `{{ source('bronze', '<table>') }}` in the silver model SQL. Do not use
|
|
34
|
+
fully qualified BigQuery names directly — that bypasses dbt's dependency
|
|
35
|
+
graph and source freshness tracking.
|
|
36
|
+
|
|
37
|
+
## User asks to create a bronze SQL model
|
|
38
|
+
|
|
39
|
+
Refuse and redirect:
|
|
40
|
+
|
|
41
|
+
```text
|
|
42
|
+
Bronze is not a SQL layer in this project — `dbt/models/bronze/` only
|
|
43
|
+
contains `schema.yml` declaring raw tables as sources. Silver reads raw
|
|
44
|
+
data directly via `{{ source('bronze', '<raw_table>') }}`.
|
|
45
|
+
|
|
46
|
+
Should I create this as a silver model instead?
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Do not generate any file under `dbt/models/bronze/` other than `schema.yml`.
|
|
32
50
|
|
|
33
51
|
## run fails
|
|
34
52
|
|
|
35
53
|
1. Show the error verbatim — do not paraphrase warehouse errors.
|
|
36
54
|
2. Offer to fix the SQL based on the error message.
|
|
37
|
-
3. Do not proceed to `
|
|
55
|
+
3. Do not proceed to `dbt test` until run succeeds.
|
|
38
56
|
|
|
39
57
|
## test fails
|
|
40
58
|
|
|
@@ -10,9 +10,14 @@
|
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
-
Each layer has one shared `schema.yml` at
|
|
13
|
+
Each SQL layer (silver, gold) has one shared `schema.yml` at
|
|
14
|
+
`dbt/models/<layer>/schema.yml`. Append new models; do not create per-model
|
|
15
|
+
files.
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
The bronze directory is **not** a SQL layer — its `schema.yml` contains only
|
|
18
|
+
source declarations, no `models:` block.
|
|
19
|
+
|
|
20
|
+
If a layer's `schema.yml` does not exist, create it with:
|
|
16
21
|
|
|
17
22
|
```yaml
|
|
18
23
|
version: 2
|
|
@@ -22,7 +27,9 @@ models:
|
|
|
22
27
|
|
|
23
28
|
## Declaring Sources (bronze layer)
|
|
24
29
|
|
|
25
|
-
|
|
30
|
+
`dbt/models/bronze/schema.yml` is the only file in `dbt/models/bronze/`. It
|
|
31
|
+
declares raw tables as dbt sources so that silver models can reference them
|
|
32
|
+
with `{{ source('bronze', '<table>') }}`.
|
|
26
33
|
|
|
27
34
|
`schema` maps to the BigQuery dataset (`REVOS_BQ_DATASET`):
|
|
28
35
|
|
|
@@ -30,23 +37,30 @@ Raw tables must be declared as dbt sources before they can be referenced with `{
|
|
|
30
37
|
version: 2
|
|
31
38
|
|
|
32
39
|
sources:
|
|
33
|
-
- name:
|
|
40
|
+
- name: bronze
|
|
34
41
|
schema: "{{ env_var('REVOS_BQ_DATASET') }}"
|
|
35
42
|
tables:
|
|
36
43
|
- name: hubspot_contacts
|
|
37
44
|
- name: hubspot_deals
|
|
38
45
|
- name: stripe_charges
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The corresponding silver model entry lives in `dbt/models/silver/schema.yml`:
|
|
49
|
+
|
|
50
|
+
```yaml
|
|
51
|
+
version: 2
|
|
39
52
|
|
|
40
53
|
models:
|
|
41
|
-
- name:
|
|
54
|
+
- name: silver_hubspot_contacts
|
|
42
55
|
...
|
|
43
56
|
```
|
|
44
57
|
|
|
45
58
|
Rules:
|
|
46
59
|
|
|
47
|
-
- Use `
|
|
48
|
-
- Each raw table referenced in
|
|
60
|
+
- Use `bronze` as the source name for all raw tables.
|
|
61
|
+
- Each raw table referenced in silver SQL needs a corresponding entry under `tables:`.
|
|
49
62
|
- If the source block already exists, append to the `tables:` list only.
|
|
63
|
+
- Do **not** add a `models:` block to `dbt/models/bronze/schema.yml` — bronze contains source declarations only.
|
|
50
64
|
|
|
51
65
|
## Standard Model Entry
|
|
52
66
|
|
|
@@ -1,61 +1,74 @@
|
|
|
1
1
|
# SQL Templates
|
|
2
2
|
|
|
3
|
-
## Bronze
|
|
3
|
+
## Bronze: no SQL
|
|
4
4
|
|
|
5
|
-
Bronze
|
|
5
|
+
Bronze is **not** a SQL layer. `dbt/models/bronze/` contains only `schema.yml`,
|
|
6
|
+
which declares raw tables as dbt sources. See
|
|
7
|
+
[schema-conventions.md](schema-conventions.md). Silver models read raw data
|
|
8
|
+
directly via `{{ source('bronze', '<raw_table_name>') }}`.
|
|
9
|
+
|
|
10
|
+
## Silver Model (reads raw via source)
|
|
6
11
|
|
|
7
12
|
```sql
|
|
8
13
|
SELECT
|
|
9
14
|
<pk_column>,
|
|
10
15
|
<business_columns>,
|
|
11
|
-
|
|
12
|
-
FROM {{ source('
|
|
16
|
+
<ingestion_timestamp_column>
|
|
17
|
+
FROM {{ source('bronze', '<raw_table_name>') }}
|
|
18
|
+
WHERE <filtering_conditions>
|
|
13
19
|
```
|
|
14
20
|
|
|
15
|
-
|
|
21
|
+
The raw table must be declared under `sources: - name: bronze` in
|
|
22
|
+
`dbt/models/bronze/schema.yml` first (see
|
|
23
|
+
[schema-conventions.md](schema-conventions.md)).
|
|
16
24
|
|
|
17
|
-
##
|
|
25
|
+
## Gold Model (reads silver via ref)
|
|
18
26
|
|
|
19
27
|
```sql
|
|
20
28
|
SELECT
|
|
21
29
|
<pk_column>,
|
|
22
30
|
<business_columns>,
|
|
23
|
-
|
|
24
|
-
FROM {{ ref('<
|
|
31
|
+
<ingestion_timestamp_column>
|
|
32
|
+
FROM {{ ref('<silver_model>') }}
|
|
25
33
|
WHERE <filtering_conditions>
|
|
26
34
|
```
|
|
27
35
|
|
|
28
36
|
## Bridge Model (JSON Array)
|
|
29
37
|
|
|
30
|
-
When unpacking a JSON array into a many-to-many bridge table
|
|
38
|
+
When unpacking a JSON array into a many-to-many bridge table, read from the
|
|
39
|
+
silver model that owns the array column:
|
|
31
40
|
|
|
32
41
|
```sql
|
|
33
42
|
SELECT DISTINCT
|
|
34
43
|
d.id AS <entity_a>_id,
|
|
35
44
|
<entity_b>_id,
|
|
36
|
-
d
|
|
37
|
-
FROM {{ ref('<
|
|
45
|
+
d.<ingestion_timestamp_column>
|
|
46
|
+
FROM {{ ref('<silver_source_model>') }} d,
|
|
38
47
|
UNNEST(JSON_VALUE_ARRAY(d.<json_array_column>)) AS <entity_b>_id
|
|
39
48
|
WHERE d.<json_array_column> IS NOT NULL
|
|
40
49
|
```
|
|
41
50
|
|
|
42
|
-
Concrete example (`gold_deals_companies.sql`, unpacking `companies` array
|
|
51
|
+
Concrete example (`gold_deals_companies.sql`, unpacking the `companies` array
|
|
52
|
+
on `silver_hubspot_deals`):
|
|
43
53
|
|
|
44
54
|
```sql
|
|
45
55
|
SELECT DISTINCT
|
|
46
56
|
d.id AS deal_id,
|
|
47
57
|
company_id,
|
|
48
58
|
d._airbyte_extracted_at
|
|
49
|
-
FROM {{ ref('
|
|
59
|
+
FROM {{ ref('silver_hubspot_deals') }} d,
|
|
50
60
|
UNNEST(JSON_VALUE_ARRAY(d.companies)) AS company_id
|
|
51
61
|
WHERE d.companies IS NOT NULL
|
|
52
62
|
```
|
|
53
63
|
|
|
64
|
+
If the silver model for the upstream entity does not exist yet, create it
|
|
65
|
+
first (see edge case: missing upstream model in `edge-cases.md`).
|
|
66
|
+
|
|
54
67
|
Notes:
|
|
55
68
|
|
|
56
|
-
1. `SELECT DISTINCT` — a single source row can produce duplicate combinations under some
|
|
69
|
+
1. `SELECT DISTINCT` — a single source row can produce duplicate combinations under some sync patterns.
|
|
57
70
|
2. `WHERE d.<json_array_column> IS NOT NULL` is required — `UNNEST(JSON_VALUE_ARRAY(NULL))` is unsafe.
|
|
58
|
-
3.
|
|
71
|
+
3. Preserve the ingestion timestamp column from upstream for downstream freshness checks.
|
|
59
72
|
4. Composite PK: `(<entity_a>_id, <entity_b>_id)`.
|
|
60
73
|
|
|
61
74
|
## Bridge Model Naming
|
|
@@ -66,8 +79,9 @@ Examples: `gold_deals_companies`, `gold_deals_contacts`, `gold_companies_contact
|
|
|
66
79
|
|
|
67
80
|
## SQL Content Rules
|
|
68
81
|
|
|
69
|
-
1. No `{{ config(materialized=...) }}` unless user asks to override the layer default.
|
|
70
|
-
2. `{{ source('
|
|
71
|
-
3. `{{ ref('<model>') }}` for references to other dbt models.
|
|
72
|
-
4.
|
|
73
|
-
5.
|
|
82
|
+
1. No `{{ config(materialized=...) }}` unless the user asks to override the layer default.
|
|
83
|
+
2. `{{ source('bronze', '<table>') }}` for raw tables — used **only** in silver models.
|
|
84
|
+
3. `{{ ref('<model>') }}` for references to other dbt models (gold reads silver this way).
|
|
85
|
+
4. Never write `.sql` files in `dbt/models/bronze/`.
|
|
86
|
+
5. Named CTEs for non-trivial logic, explicit column lists where practical.
|
|
87
|
+
6. Preserve the ingestion timestamp column from raw (e.g. `_airbyte_extracted_at` if Airbyte loaded it) when present.
|
|
@@ -4,7 +4,7 @@ description: >
|
|
|
4
4
|
Inspect the RevOS BigQuery lakehouse: list datasets and tables, introspect table schemas
|
|
5
5
|
and column types, preview sample rows, assess data layers (bronze/silver/gold), and check
|
|
6
6
|
data completeness and null rates. Required companion skill for create-dbt-transformations
|
|
7
|
-
and create-
|
|
7
|
+
and create-cubes — load before generating dbt models or cube definitions to
|
|
8
8
|
introspect warehouse columns and types. Use when asked to: explore the lakehouse, list
|
|
9
9
|
BigQuery tables, inspect a table schema, preview data, check raw source tables, assess data
|
|
10
10
|
quality, check null rates, understand available data, or perform BigQuery schema introspection.
|
|
@@ -85,9 +85,13 @@ FROM \`$GOOGLE_CLOUD_PROJECT.$REVOS_BQ_DATASET.<table>\`
|
|
|
85
85
|
### "What's in my database?" / general overview
|
|
86
86
|
|
|
87
87
|
1. List tables in the org's dataset: `bq ls $REVOS_BQ_DATASET`
|
|
88
|
-
2.
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
2. If the dataset is empty (no tables), tell the user:
|
|
89
|
+
- They can add data sources by running `revos sources create` to open the RevOS UI
|
|
90
|
+
- They can view existing sources with `revos sources list`
|
|
91
|
+
- Stop here — no further exploration is possible without data
|
|
92
|
+
3. Infer the data source and domain from table name prefixes (e.g. `salesforce_*`, `stripe_*`, `hubspot_*`)
|
|
93
|
+
4. Group tables by source/domain
|
|
94
|
+
5. Return: sources found, table count per source, table types (TABLE/VIEW), one-line description per group
|
|
91
95
|
|
|
92
96
|
### "What layer is this data?" / bronze–silver–gold assessment
|
|
93
97
|
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: load-sample-data
|
|
3
|
+
description: >
|
|
4
|
+
Populate a BigQuery dataset with sample data from public datasets using bq cp.
|
|
5
|
+
Use when asked to: load sample data, populate the lakehouse, add demo data, seed the dataset,
|
|
6
|
+
get started with sample tables, or when the user needs data to explore.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Load Sample Data
|
|
10
|
+
|
|
11
|
+
Copy sample tables from `bigquery-public-data` into the user's dataset using `bq cp`. All copied tables are prefixed with `sample_` so they can be easily identified and cleaned up later.
|
|
12
|
+
|
|
13
|
+
## Environment
|
|
14
|
+
|
|
15
|
+
Verify env vars before running any command. If either is empty, ask the user to set it.
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
echo "Project: $GOOGLE_CLOUD_PROJECT"
|
|
19
|
+
echo "Dataset: $REVOS_BQ_DATASET"
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
- `$GOOGLE_CLOUD_PROJECT` — BQ project ID
|
|
23
|
+
- `$REVOS_BQ_DATASET` — target dataset
|
|
24
|
+
|
|
25
|
+
## Step 1: Check Existing Tables
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
bq ls $REVOS_BQ_DATASET
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
If tables exist, list them. They will be relevant in Step 3 for collision handling.
|
|
32
|
+
|
|
33
|
+
## Step 2: Present Sample Dataset Catalog
|
|
34
|
+
|
|
35
|
+
```text
|
|
36
|
+
Available sample datasets:
|
|
37
|
+
|
|
38
|
+
1. thelook_ecommerce (default) — B2C e-commerce data
|
|
39
|
+
Tables: sample_users, sample_orders, sample_order_items, sample_products, sample_events, sample_inventory_items, sample_distribution_centers
|
|
40
|
+
Rows: ~100K users, ~300K orders
|
|
41
|
+
Good for: customer analytics, purchase funnels, product performance
|
|
42
|
+
|
|
43
|
+
2. google_analytics_sample — Web analytics session data
|
|
44
|
+
Tables: sample_ga_sessions (single table, one day snapshot)
|
|
45
|
+
Rows: ~900K sessions
|
|
46
|
+
Good for: web traffic analysis, user behavior, channel attribution
|
|
47
|
+
|
|
48
|
+
3. austin_bikeshare — Bikeshare trip and station data
|
|
49
|
+
Tables: sample_bikeshare_trips, sample_bikeshare_stations
|
|
50
|
+
Rows: ~1.3M trips
|
|
51
|
+
Good for: geospatial analysis, demand forecasting, utilization metrics
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Step 3: Copy Tables
|
|
55
|
+
|
|
56
|
+
If any table names from the chosen sample dataset collide with existing tables (from Step 1), ask the user whether to **overwrite** or **skip** each collision before copying. Skip collisions the user chose not to overwrite.
|
|
57
|
+
|
|
58
|
+
### thelook_ecommerce
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
for table in users orders order_items products events inventory_items distribution_centers; do
|
|
62
|
+
echo "Copying sample_$table..."
|
|
63
|
+
bq cp -f bigquery-public-data:thelook_ecommerce.$table \
|
|
64
|
+
$GOOGLE_CLOUD_PROJECT:$REVOS_BQ_DATASET.sample_$table
|
|
65
|
+
done
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### google_analytics_sample
|
|
69
|
+
|
|
70
|
+
The `ga_sessions` table is date-sharded. Copy a representative day:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
echo "Copying sample_ga_sessions..."
|
|
74
|
+
bq cp -f bigquery-public-data:google_analytics_sample.ga_sessions_20170801 \
|
|
75
|
+
$GOOGLE_CLOUD_PROJECT:$REVOS_BQ_DATASET.sample_ga_sessions
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### austin_bikeshare
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
for table in bikeshare_trips bikeshare_stations; do
|
|
82
|
+
echo "Copying sample_$table..."
|
|
83
|
+
bq cp -f bigquery-public-data:austin_bikeshare.$table \
|
|
84
|
+
$GOOGLE_CLOUD_PROJECT:$REVOS_BQ_DATASET.sample_$table
|
|
85
|
+
done
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Step 4: Verify
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
for table in <copied_tables>; do
|
|
92
|
+
echo -n "$table: "
|
|
93
|
+
bq query --nouse_legacy_sql --format=csv \
|
|
94
|
+
"SELECT COUNT(*) FROM \`$GOOGLE_CLOUD_PROJECT.$REVOS_BQ_DATASET.$table\`" 2>/dev/null | tail -1
|
|
95
|
+
done
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Final Response
|
|
99
|
+
|
|
100
|
+
```text
|
|
101
|
+
Sample data loaded into $REVOS_BQ_DATASET.
|
|
102
|
+
|
|
103
|
+
Source: bigquery-public-data:<dataset_name>
|
|
104
|
+
Tables copied:
|
|
105
|
+
- <table_1>: <row_count> rows
|
|
106
|
+
- <table_2>: <row_count> rows
|
|
107
|
+
|
|
108
|
+
Next steps:
|
|
109
|
+
- Run "explore lakehouse" to inspect the data
|
|
110
|
+
- Run "create dbt transformations" to build bronze/silver/gold models
|
|
111
|
+
- Run "create cube" to generate Cube.dev semantic models
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Rules
|
|
115
|
+
|
|
116
|
+
- Use `bq cp -f` (not `CREATE TABLE AS SELECT`) — faster, no query costs, preserves schema. The `-f` flag is required to avoid cross-region confirmation prompts that block non-interactive shells.
|
|
117
|
+
- Show progress for each table being copied.
|
|
118
|
+
- Report any failures clearly with the `bq` error message.
|
|
119
|
+
- Always prefix destination tables with `sample_` — this allows easy identification and cleanup of sample data.
|