@bonnard/cli 0.1.2 → 0.1.4
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/dist/bin/bon.mjs +1892 -97
- package/dist/bin/models-IsV2sX74.mjs +76 -0
- package/dist/bin/{validate-Bd1D39Bj.mjs → validate-C4EHvJzJ.mjs} +47 -4
- package/dist/docs/README.md +82 -0
- package/dist/docs/_index.md +69 -0
- package/dist/docs/topics/cubes.data-source.md +96 -0
- package/dist/docs/topics/cubes.dimensions.format.md +199 -0
- package/dist/docs/topics/cubes.dimensions.md +188 -0
- package/dist/docs/topics/cubes.dimensions.primary-key.md +110 -0
- package/dist/docs/topics/cubes.dimensions.sub-query.md +178 -0
- package/dist/docs/topics/cubes.dimensions.time.md +115 -0
- package/dist/docs/topics/cubes.dimensions.types.md +111 -0
- package/dist/docs/topics/cubes.extends.md +153 -0
- package/dist/docs/topics/cubes.hierarchies.md +178 -0
- package/dist/docs/topics/cubes.joins.md +119 -0
- package/dist/docs/topics/cubes.md +121 -0
- package/dist/docs/topics/cubes.measures.calculated.md +103 -0
- package/dist/docs/topics/cubes.measures.drill-members.md +162 -0
- package/dist/docs/topics/cubes.measures.filters.md +90 -0
- package/dist/docs/topics/cubes.measures.format.md +157 -0
- package/dist/docs/topics/cubes.measures.md +166 -0
- package/dist/docs/topics/cubes.measures.rolling.md +123 -0
- package/dist/docs/topics/cubes.measures.types.md +126 -0
- package/dist/docs/topics/cubes.public.md +176 -0
- package/dist/docs/topics/cubes.refresh-key.md +157 -0
- package/dist/docs/topics/cubes.segments.md +125 -0
- package/dist/docs/topics/cubes.sql.md +65 -0
- package/dist/docs/topics/pre-aggregations.md +130 -0
- package/dist/docs/topics/pre-aggregations.rollup.md +166 -0
- package/dist/docs/topics/syntax.context-variables.md +157 -0
- package/dist/docs/topics/syntax.md +137 -0
- package/dist/docs/topics/syntax.references.md +178 -0
- package/dist/docs/topics/views.cubes.md +166 -0
- package/dist/docs/topics/views.folders.md +158 -0
- package/dist/docs/topics/views.includes.md +143 -0
- package/dist/docs/topics/views.md +142 -0
- package/dist/docs/topics/workflow.deploy.md +132 -0
- package/dist/docs/topics/workflow.md +151 -0
- package/dist/docs/topics/workflow.query.md +203 -0
- package/dist/docs/topics/workflow.validate.md +156 -0
- package/dist/templates/claude/rules/bonnard.md +15 -0
- package/dist/templates/claude/settings.json +7 -0
- package/dist/templates/claude/skills/bonnard-cli/SKILL.md +59 -0
- package/dist/templates/claude/skills/bonnard-queries/SKILL.md +68 -0
- package/dist/templates/cursor/rules/bonnard-cli.mdc +47 -0
- package/dist/templates/cursor/rules/bonnard-queries.mdc +49 -0
- package/dist/templates/cursor/rules/bonnard.mdc +20 -0
- package/dist/templates/shared/bonnard.md +81 -0
- package/package.json +8 -3
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# pre-aggregations
|
|
2
|
+
|
|
3
|
+
> Materialize query results for faster analytics performance.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Pre-aggregations are materialized tables that store pre-computed query results. They dramatically improve query performance by avoiding repeated aggregation of raw data.
|
|
8
|
+
|
|
9
|
+
## Example
|
|
10
|
+
|
|
11
|
+
```yaml
|
|
12
|
+
cubes:
|
|
13
|
+
- name: orders
|
|
14
|
+
sql_table: orders
|
|
15
|
+
|
|
16
|
+
measures:
|
|
17
|
+
- name: count
|
|
18
|
+
type: count
|
|
19
|
+
|
|
20
|
+
- name: total_revenue
|
|
21
|
+
type: sum
|
|
22
|
+
sql: amount
|
|
23
|
+
|
|
24
|
+
dimensions:
|
|
25
|
+
- name: status
|
|
26
|
+
type: string
|
|
27
|
+
sql: status
|
|
28
|
+
|
|
29
|
+
- name: created_at
|
|
30
|
+
type: time
|
|
31
|
+
sql: created_at
|
|
32
|
+
|
|
33
|
+
pre_aggregations:
|
|
34
|
+
- name: orders_by_day
|
|
35
|
+
measures:
|
|
36
|
+
- count
|
|
37
|
+
- total_revenue
|
|
38
|
+
dimensions:
|
|
39
|
+
- status
|
|
40
|
+
time_dimension: created_at
|
|
41
|
+
granularity: day
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Pre-Aggregation Types
|
|
45
|
+
|
|
46
|
+
### rollup (default)
|
|
47
|
+
Summarizes data into aggregated form. Most effective for performance.
|
|
48
|
+
|
|
49
|
+
```yaml
|
|
50
|
+
pre_aggregations:
|
|
51
|
+
- name: main
|
|
52
|
+
type: rollup
|
|
53
|
+
measures:
|
|
54
|
+
- count
|
|
55
|
+
- total_revenue
|
|
56
|
+
dimensions:
|
|
57
|
+
- status
|
|
58
|
+
time_dimension: created_at
|
|
59
|
+
granularity: day
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### original_sql
|
|
63
|
+
Persists the cube's SQL query without aggregation. Useful for complex SQL.
|
|
64
|
+
|
|
65
|
+
```yaml
|
|
66
|
+
pre_aggregations:
|
|
67
|
+
- name: base_data
|
|
68
|
+
type: original_sql
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### rollup_join
|
|
72
|
+
Joins pre-aggregations from different data sources (preview feature).
|
|
73
|
+
|
|
74
|
+
### rollup_lambda
|
|
75
|
+
Combines real-time and historical data (advanced).
|
|
76
|
+
|
|
77
|
+
## Key Properties
|
|
78
|
+
|
|
79
|
+
| Property | Description |
|
|
80
|
+
|----------|-------------|
|
|
81
|
+
| `name` | Unique identifier |
|
|
82
|
+
| `type` | `rollup`, `original_sql`, `rollup_join`, `rollup_lambda` |
|
|
83
|
+
| `measures` | Measures to include |
|
|
84
|
+
| `dimensions` | Dimensions to include |
|
|
85
|
+
| `time_dimension` | Time dimension for partitioning |
|
|
86
|
+
| `granularity` | Time granularity: `day`, `week`, `month`, etc. |
|
|
87
|
+
| `partition_granularity` | How to partition data |
|
|
88
|
+
| `refresh_key` | When to refresh |
|
|
89
|
+
| `scheduled_refresh` | Auto-refresh (default: true) |
|
|
90
|
+
|
|
91
|
+
## Additive vs Non-Additive
|
|
92
|
+
|
|
93
|
+
**Additive measures** (count, sum, min, max) can be combined from pre-aggregated data:
|
|
94
|
+
|
|
95
|
+
```yaml
|
|
96
|
+
# These work efficiently with rollups
|
|
97
|
+
measures:
|
|
98
|
+
- name: count
|
|
99
|
+
type: count
|
|
100
|
+
- name: total
|
|
101
|
+
type: sum
|
|
102
|
+
sql: amount
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**Non-additive measures** (count_distinct, avg) may require the original data:
|
|
106
|
+
|
|
107
|
+
```yaml
|
|
108
|
+
# count_distinct needs special handling
|
|
109
|
+
measures:
|
|
110
|
+
- name: unique_users
|
|
111
|
+
type: count_distinct
|
|
112
|
+
sql: user_id
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Best Practices
|
|
116
|
+
|
|
117
|
+
1. **Start with common queries** — pre-aggregate your most frequent access patterns
|
|
118
|
+
2. **Include all needed members** — queries must match the pre-aggregation exactly
|
|
119
|
+
3. **Use partitioning** — for large datasets, partition by time
|
|
120
|
+
4. **Monitor refresh** — ensure data stays current
|
|
121
|
+
|
|
122
|
+
## See Also
|
|
123
|
+
|
|
124
|
+
- pre-aggregations.rollup
|
|
125
|
+
- cubes.measures
|
|
126
|
+
- cubes.dimensions.time
|
|
127
|
+
|
|
128
|
+
## More Information
|
|
129
|
+
|
|
130
|
+
https://cube.dev/docs/reference/data-model/pre-aggregations
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# pre-aggregations.rollup
|
|
2
|
+
|
|
3
|
+
> Create summarized data tables for high-performance queries.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Rollup pre-aggregations summarize raw data into aggregated tables, grouped by specified dimensions. They're the most effective way to improve query performance.
|
|
8
|
+
|
|
9
|
+
## Example
|
|
10
|
+
|
|
11
|
+
```yaml
|
|
12
|
+
pre_aggregations:
|
|
13
|
+
- name: orders_daily
|
|
14
|
+
type: rollup
|
|
15
|
+
measures:
|
|
16
|
+
- count
|
|
17
|
+
- total_revenue
|
|
18
|
+
dimensions:
|
|
19
|
+
- status
|
|
20
|
+
- category
|
|
21
|
+
time_dimension: created_at
|
|
22
|
+
granularity: day
|
|
23
|
+
partition_granularity: month
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Time-Based Rollups
|
|
27
|
+
|
|
28
|
+
### Basic Time Rollup
|
|
29
|
+
|
|
30
|
+
```yaml
|
|
31
|
+
- name: daily_orders
|
|
32
|
+
measures:
|
|
33
|
+
- count
|
|
34
|
+
time_dimension: created_at
|
|
35
|
+
granularity: day
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Partitioned Rollup
|
|
39
|
+
|
|
40
|
+
Partition large datasets for efficient refreshes:
|
|
41
|
+
|
|
42
|
+
```yaml
|
|
43
|
+
- name: orders_monthly_partitioned
|
|
44
|
+
measures:
|
|
45
|
+
- count
|
|
46
|
+
- total_revenue
|
|
47
|
+
time_dimension: created_at
|
|
48
|
+
granularity: day
|
|
49
|
+
partition_granularity: month
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Granularity Options
|
|
53
|
+
|
|
54
|
+
| Granularity | Description |
|
|
55
|
+
|-------------|-------------|
|
|
56
|
+
| `second` | Per-second aggregation |
|
|
57
|
+
| `minute` | Per-minute aggregation |
|
|
58
|
+
| `hour` | Hourly aggregation |
|
|
59
|
+
| `day` | Daily aggregation |
|
|
60
|
+
| `week` | Weekly aggregation |
|
|
61
|
+
| `month` | Monthly aggregation |
|
|
62
|
+
| `quarter` | Quarterly aggregation |
|
|
63
|
+
| `year` | Yearly aggregation |
|
|
64
|
+
|
|
65
|
+
## Refresh Strategies
|
|
66
|
+
|
|
67
|
+
### Time-Based Refresh
|
|
68
|
+
|
|
69
|
+
```yaml
|
|
70
|
+
- name: orders_hourly
|
|
71
|
+
measures:
|
|
72
|
+
- count
|
|
73
|
+
time_dimension: created_at
|
|
74
|
+
granularity: hour
|
|
75
|
+
refresh_key:
|
|
76
|
+
every: 1 hour
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Incremental Refresh
|
|
80
|
+
|
|
81
|
+
Only refresh recent partitions:
|
|
82
|
+
|
|
83
|
+
```yaml
|
|
84
|
+
- name: orders_incremental
|
|
85
|
+
measures:
|
|
86
|
+
- count
|
|
87
|
+
- total_revenue
|
|
88
|
+
time_dimension: created_at
|
|
89
|
+
granularity: day
|
|
90
|
+
partition_granularity: month
|
|
91
|
+
refresh_key:
|
|
92
|
+
every: 1 day
|
|
93
|
+
incremental: true
|
|
94
|
+
update_window: 7 day
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### SQL-Based Refresh
|
|
98
|
+
|
|
99
|
+
Refresh when data changes:
|
|
100
|
+
|
|
101
|
+
```yaml
|
|
102
|
+
- name: orders_on_change
|
|
103
|
+
measures:
|
|
104
|
+
- count
|
|
105
|
+
refresh_key:
|
|
106
|
+
sql: SELECT MAX(updated_at) FROM orders
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Indexes
|
|
110
|
+
|
|
111
|
+
Add indexes for better query performance:
|
|
112
|
+
|
|
113
|
+
```yaml
|
|
114
|
+
- name: orders_by_status
|
|
115
|
+
measures:
|
|
116
|
+
- count
|
|
117
|
+
dimensions:
|
|
118
|
+
- status
|
|
119
|
+
- category
|
|
120
|
+
indexes:
|
|
121
|
+
- name: status_idx
|
|
122
|
+
columns:
|
|
123
|
+
- status
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Query Matching
|
|
127
|
+
|
|
128
|
+
A query uses a rollup if:
|
|
129
|
+
1. All requested measures are in the rollup
|
|
130
|
+
2. All requested dimensions are in the rollup
|
|
131
|
+
3. Time dimension granularity is compatible
|
|
132
|
+
4. Filters match the rollup's data
|
|
133
|
+
|
|
134
|
+
```yaml
|
|
135
|
+
# This rollup...
|
|
136
|
+
- name: orders_daily
|
|
137
|
+
measures:
|
|
138
|
+
- count
|
|
139
|
+
- total_revenue
|
|
140
|
+
dimensions:
|
|
141
|
+
- status
|
|
142
|
+
time_dimension: created_at
|
|
143
|
+
granularity: day
|
|
144
|
+
|
|
145
|
+
# ...matches queries like:
|
|
146
|
+
# - orders.count by day
|
|
147
|
+
# - orders.total_revenue by status by week (day rolls up to week)
|
|
148
|
+
# - orders.count where status = 'completed' by month
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Best Practices
|
|
152
|
+
|
|
153
|
+
1. **Match your queries** — design rollups around common access patterns
|
|
154
|
+
2. **Use incremental refresh** — for large time-series data
|
|
155
|
+
3. **Partition wisely** — monthly partitions work well for most cases
|
|
156
|
+
4. **Add indexes** — for high-cardinality dimension filters
|
|
157
|
+
|
|
158
|
+
## See Also
|
|
159
|
+
|
|
160
|
+
- pre-aggregations
|
|
161
|
+
- cubes.dimensions.time
|
|
162
|
+
- cubes.measures
|
|
163
|
+
|
|
164
|
+
## More Information
|
|
165
|
+
|
|
166
|
+
https://cube.dev/docs/reference/data-model/pre-aggregations#rollup
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# syntax.context-variables
|
|
2
|
+
|
|
3
|
+
> Access runtime context in SQL expressions.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Context variables provide access to runtime information within cube definitions. Use them for dynamic SQL generation, filter handling, and security context.
|
|
8
|
+
|
|
9
|
+
## Context Variables
|
|
10
|
+
|
|
11
|
+
### {CUBE}
|
|
12
|
+
|
|
13
|
+
References the current cube without repeating its name:
|
|
14
|
+
|
|
15
|
+
```yaml
|
|
16
|
+
cubes:
|
|
17
|
+
- name: orders
|
|
18
|
+
dimensions:
|
|
19
|
+
- name: status
|
|
20
|
+
type: string
|
|
21
|
+
sql: "{CUBE}.status" # Same as "{orders}.status"
|
|
22
|
+
|
|
23
|
+
measures:
|
|
24
|
+
- name: completed_count
|
|
25
|
+
type: count
|
|
26
|
+
filters:
|
|
27
|
+
- sql: "{CUBE}.status = 'completed'"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Essential when using `extends` so SQL works in child cubes.
|
|
31
|
+
|
|
32
|
+
### FILTER_PARAMS
|
|
33
|
+
|
|
34
|
+
Access filter values from queries during SQL generation:
|
|
35
|
+
|
|
36
|
+
```yaml
|
|
37
|
+
cubes:
|
|
38
|
+
- name: orders
|
|
39
|
+
sql: >
|
|
40
|
+
SELECT * FROM orders
|
|
41
|
+
WHERE {FILTER_PARAMS.orders.created_at.filter('created_at')}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Useful for:
|
|
45
|
+
- Partition pruning in data warehouses
|
|
46
|
+
- Predicate pushdown optimization
|
|
47
|
+
- Dynamic table selection
|
|
48
|
+
|
|
49
|
+
Syntax: `{FILTER_PARAMS.cube_name.member_name.filter('sql_expression')}`
|
|
50
|
+
|
|
51
|
+
### FILTER_GROUP
|
|
52
|
+
|
|
53
|
+
Wraps multiple FILTER_PARAMS when combining with OR:
|
|
54
|
+
|
|
55
|
+
```yaml
|
|
56
|
+
sql: >
|
|
57
|
+
SELECT * FROM orders
|
|
58
|
+
WHERE {FILTER_GROUP(
|
|
59
|
+
FILTER_PARAMS.orders.status.filter('status'),
|
|
60
|
+
FILTER_PARAMS.orders.type.filter('type')
|
|
61
|
+
)}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Prevents incorrect SQL when filters use OR logic.
|
|
65
|
+
|
|
66
|
+
### COMPILE_CONTEXT
|
|
67
|
+
|
|
68
|
+
Evaluated once per deployment context. Access via Jinja syntax:
|
|
69
|
+
|
|
70
|
+
```yaml
|
|
71
|
+
cubes:
|
|
72
|
+
- name: orders
|
|
73
|
+
sql_table: "{{ COMPILE_CONTEXT.schema }}.orders"
|
|
74
|
+
|
|
75
|
+
public: "{{ 'true' if COMPILE_CONTEXT.role == 'admin' else 'false' }}"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Common uses:
|
|
79
|
+
- Multi-tenant table names
|
|
80
|
+
- Environment-specific configuration
|
|
81
|
+
- Role-based visibility
|
|
82
|
+
|
|
83
|
+
### SQL_UTILS
|
|
84
|
+
|
|
85
|
+
Helper functions for SQL generation:
|
|
86
|
+
|
|
87
|
+
```yaml
|
|
88
|
+
dimensions:
|
|
89
|
+
- name: created_at_local
|
|
90
|
+
type: time
|
|
91
|
+
sql: "{SQL_UTILS.convertTz('created_at', 'UTC', 'America/New_York')}"
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**convertTz()**: Converts timestamps between timezones.
|
|
95
|
+
|
|
96
|
+
Note: Don't use SQL_UTILS dimensions as `timeDimensions` in queries to avoid double conversion.
|
|
97
|
+
|
|
98
|
+
## Examples
|
|
99
|
+
|
|
100
|
+
### Partition Filtering (Snowflake/BigQuery)
|
|
101
|
+
|
|
102
|
+
```yaml
|
|
103
|
+
cubes:
|
|
104
|
+
- name: events
|
|
105
|
+
sql: >
|
|
106
|
+
SELECT * FROM events
|
|
107
|
+
WHERE {FILTER_PARAMS.events.timestamp.filter('timestamp')}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
When querying with a date filter, this pushes the filter to the partition column for efficient pruning.
|
|
111
|
+
|
|
112
|
+
### Multi-Tenant Tables
|
|
113
|
+
|
|
114
|
+
```yaml
|
|
115
|
+
cubes:
|
|
116
|
+
- name: orders
|
|
117
|
+
sql_table: "{{ COMPILE_CONTEXT.tenant_schema }}.orders"
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Dynamic Visibility
|
|
121
|
+
|
|
122
|
+
```yaml
|
|
123
|
+
cubes:
|
|
124
|
+
- name: sensitive_data
|
|
125
|
+
public: "{{ 'true' if COMPILE_CONTEXT.user_role in ['admin', 'analyst'] else 'false' }}"
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Timezone Conversion
|
|
129
|
+
|
|
130
|
+
```yaml
|
|
131
|
+
dimensions:
|
|
132
|
+
- name: created_at_et
|
|
133
|
+
type: time
|
|
134
|
+
sql: "{SQL_UTILS.convertTz('created_at', 'UTC', 'America/New_York')}"
|
|
135
|
+
title: "Created At (ET)"
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Best Practices
|
|
139
|
+
|
|
140
|
+
1. **Use {CUBE}** in extendable cubes — never hardcode cube names
|
|
141
|
+
2. **Use FILTER_PARAMS** for partition pruning — improves query performance
|
|
142
|
+
3. **Use COMPILE_CONTEXT** for deployment config — not for per-query logic
|
|
143
|
+
4. **Test filter pushdown** — verify FILTER_PARAMS generates expected SQL
|
|
144
|
+
|
|
145
|
+
## Deprecated: SECURITY_CONTEXT
|
|
146
|
+
|
|
147
|
+
`SECURITY_CONTEXT` is deprecated. Use `query_rewrite` for security filtering instead.
|
|
148
|
+
|
|
149
|
+
## See Also
|
|
150
|
+
|
|
151
|
+
- syntax
|
|
152
|
+
- syntax.references
|
|
153
|
+
- cubes.extends
|
|
154
|
+
|
|
155
|
+
## More Information
|
|
156
|
+
|
|
157
|
+
https://cube.dev/docs/reference/data-model/context-variables
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# syntax
|
|
2
|
+
|
|
3
|
+
> YAML syntax and conventions for Cube data models.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Cube data models are defined in YAML files. Understanding the syntax conventions helps you write correct and maintainable models.
|
|
8
|
+
|
|
9
|
+
## File Structure
|
|
10
|
+
|
|
11
|
+
### Cubes File
|
|
12
|
+
|
|
13
|
+
```yaml
|
|
14
|
+
cubes:
|
|
15
|
+
- name: orders
|
|
16
|
+
sql_table: public.orders
|
|
17
|
+
|
|
18
|
+
measures:
|
|
19
|
+
- name: count
|
|
20
|
+
type: count
|
|
21
|
+
|
|
22
|
+
dimensions:
|
|
23
|
+
- name: id
|
|
24
|
+
type: number
|
|
25
|
+
sql: id
|
|
26
|
+
primary_key: true
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Views File
|
|
30
|
+
|
|
31
|
+
```yaml
|
|
32
|
+
views:
|
|
33
|
+
- name: orders_overview
|
|
34
|
+
cubes:
|
|
35
|
+
- join_path: orders
|
|
36
|
+
includes:
|
|
37
|
+
- count
|
|
38
|
+
- status
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Naming Conventions
|
|
42
|
+
|
|
43
|
+
### Cube and View Names
|
|
44
|
+
|
|
45
|
+
- Use `snake_case`
|
|
46
|
+
- Be descriptive: `user_orders`, not `uo`
|
|
47
|
+
- Use plural for collections: `orders`, `users`
|
|
48
|
+
|
|
49
|
+
```yaml
|
|
50
|
+
cubes:
|
|
51
|
+
- name: orders # Good
|
|
52
|
+
- name: user_activity # Good
|
|
53
|
+
- name: Orders # Bad - use lowercase
|
|
54
|
+
- name: userOrders # Bad - use snake_case
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Member Names
|
|
58
|
+
|
|
59
|
+
- Use `snake_case`
|
|
60
|
+
- Be descriptive but concise
|
|
61
|
+
|
|
62
|
+
```yaml
|
|
63
|
+
measures:
|
|
64
|
+
- name: count # Good
|
|
65
|
+
- name: total_revenue # Good
|
|
66
|
+
- name: average_order_value # Good
|
|
67
|
+
- name: aov # Bad - unclear abbreviation
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## SQL Expressions
|
|
71
|
+
|
|
72
|
+
### Inline SQL
|
|
73
|
+
|
|
74
|
+
```yaml
|
|
75
|
+
dimensions:
|
|
76
|
+
- name: full_name
|
|
77
|
+
type: string
|
|
78
|
+
sql: "CONCAT(first_name, ' ', last_name)"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Multi-line SQL
|
|
82
|
+
|
|
83
|
+
Use YAML block scalar for complex SQL:
|
|
84
|
+
|
|
85
|
+
```yaml
|
|
86
|
+
cubes:
|
|
87
|
+
- name: orders
|
|
88
|
+
sql: >
|
|
89
|
+
SELECT
|
|
90
|
+
o.*,
|
|
91
|
+
u.name as user_name
|
|
92
|
+
FROM orders o
|
|
93
|
+
LEFT JOIN users u ON o.user_id = u.id
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Common Patterns
|
|
97
|
+
|
|
98
|
+
### Quoting
|
|
99
|
+
|
|
100
|
+
Quote SQL expressions with special characters:
|
|
101
|
+
|
|
102
|
+
```yaml
|
|
103
|
+
# Quoted - required for expressions
|
|
104
|
+
sql: "{CUBE}.amount * 0.1"
|
|
105
|
+
|
|
106
|
+
# Unquoted - simple column reference
|
|
107
|
+
sql: amount
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Arrays
|
|
111
|
+
|
|
112
|
+
```yaml
|
|
113
|
+
# Inline array
|
|
114
|
+
includes: [count, total_revenue]
|
|
115
|
+
|
|
116
|
+
# Block array
|
|
117
|
+
includes:
|
|
118
|
+
- count
|
|
119
|
+
- total_revenue
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Booleans
|
|
123
|
+
|
|
124
|
+
```yaml
|
|
125
|
+
primary_key: true
|
|
126
|
+
public: false
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## See Also
|
|
130
|
+
|
|
131
|
+
- syntax.references
|
|
132
|
+
- cubes
|
|
133
|
+
- views
|
|
134
|
+
|
|
135
|
+
## More Information
|
|
136
|
+
|
|
137
|
+
https://cube.dev/docs/product/data-modeling/syntax
|