YAML and SQL specs¶
A spec can be written two ways, and a project can mix them freely: each file is one table, view or function.
- YAML (
.yml,.yaml) is stevin's own format. It can say everything stevin manages — including its hints, likerenamed_fromandusing, which have no SQL spelling. Writing a spec covers it. - SQL (
.sql) is aCREATE TABLE,CREATE VIEWorCREATE FUNCTIONstatement, in Databricks SQL, optionally followed byALTER … SET TAGSandGRANTstatements about the same object.
Both are read into the same model, so a SQL spec and the YAML spec that says the same
thing plan identically. stevin import -f sql writes SQL specs for what's already
there.
CREATE TABLE ${catalog}.sales.customers (
id BIGINT NOT NULL COMMENT 'Surrogate key',
name STRING,
created_at TIMESTAMP,
CONSTRAINT customers_pk PRIMARY KEY (id)
)
COMMENT 'One row per customer'
CLUSTER BY (id);
ALTER TABLE ${catalog}.sales.customers SET TAGS ('domain' = 'sales');
GRANT SELECT ON TABLE ${catalog}.sales.customers TO `analysts`;
How SQL specs are read¶
SQL specs are parsed with sqlglot's Databricks dialect, and the rule is strict: what sqlglot parses into structure, a SQL spec can use; what it can't, a SQL spec can't — even when Databricks itself accepts it. Such a spec is refused with the line it's on, and the feature is written in YAML instead. As sqlglot learns more of Databricks SQL, this list grows.
- The statement is a declaration, never run as written:
CREATE,CREATE OR REPLACEandIF NOT EXISTSall mean the same thing. stevin plans its own statements from the difference with the live object, as for YAML. ${catalog}and friends work as in YAML, and so does the bundle spelling${var.catalog}.- A view's query and a function's body are kept exactly as written. Column-level
expressions —
CHECK,GENERATED ALWAYS AS,DEFAULT— are taken the way sqlglot renders them, which may differ from what you wrote in spacing and case. - A
CHECKconstraint needs a name:CONSTRAINT positive_amount CHECK (amount > 0).
What each format supports¶
| Feature | YAML | SQL | Notes | |
|---|---|---|---|---|
| Tables | Columns and types, nested included | ✓ | ✓ | struct, array, map, decimal, char/varchar, timestamp_ntz, variant |
| NOT NULL, on nested fields too | ✓ | ✓ | ||
| Column comments | ✓ | ✓ | ||
| Table comment | ✓ | ✓ | ||
| Liquid clustering keys | ✓ | ✓ | ||
| Automatic liquid clustering | ✓ | ✓ | cluster_by: auto in YAML |
|
| Table properties | ✓ | ✓ | ||
| Primary key | ✓ | ✓ | ||
| Foreign keys | ✓ | ✓ | ||
| CHECK constraints | ✓ | ✓ | named: CONSTRAINT <name> CHECK (…) |
|
| Identity columns | ✓ | ✓ | ||
| Generated columns | ✓ | ✓ | ||
| Column defaults | ✓ | ✓ | ||
| Table tags | ✓ | ✓ | an ALTER TABLE … SET TAGS after the CREATE |
|
| Grants | ✓ | ✓ | GRANT statements after the CREATE |
|
| Column tags | ✓ | — | sqlglot passes ALTER COLUMN … SET TAGS through as unparsed text |
|
| Column masks | ✓ | — | sqlglot can't parse MASK |
|
| Row filters | ✓ | — | sqlglot passes WITH ROW FILTER through as unparsed text |
|
| Owner | ✓ | — | sqlglot passes ALTER … OWNER TO through as unparsed text |
|
Removing a tag or property (null) |
✓ | — | a SQL spec says what is there; pii: null in YAML says what isn't |
|
Column renames (renamed_from) |
✓ | — | a stevin hint; SQL has no way to say it | |
Table renames (renamed_from) |
✓ | — | a stevin hint; SQL has no way to say it | |
Conversions and backfills (using) |
✓ | — | a stevin hint; SQL has no way to say it | |
| Hooks | ✓ | — | stevin's own; SQL has no way to say it | |
| Seeds (reference data) | ✓ | — | a stevin hint; a CSV beside the spec, or rows written out in it | |
| Partitioning | ✓ | ✓ | or liquid clustering, not both; left out, a table's partitioning stays | |
| Schemas | Schemas: comment and grants | ✓ | ✓ | never dropped |
| Schema tags | ✓ | — | sqlglot passes ALTER SCHEMA … SET TAGS through as unparsed text |
|
| Volumes | Managed volumes: comment, tags, grants | ✓ | — | sqlglot passes CREATE VOLUME and GRANT … ON VOLUME through as unparsed text; never dropped |
| Views | Views: query, comment, properties | ✓ | ✓ | the query is kept exactly as written |
| View tags and grants | ✓ | ✓ | ||
| Functions | SQL functions: parameters, return type, body, comment | ✓ | ✓ | the body is kept exactly as written |
| Function grants | ✓ | ✓ |
Every row with a ✓ under SQL is a test that loads a SQL spec using it; every — is a test that such a spec is refused.