Skip to content

Commit f7eff6f

Browse files
committed
feat!: add on_additive_change support
1 parent 31763bf commit f7eff6f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+4340
-1102
lines changed

.circleci/continue_config.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -310,10 +310,10 @@ workflows:
310310
- athena
311311
- fabric
312312
- gcp-postgres
313-
filters:
314-
branches:
315-
only:
316-
- main
313+
# filters:
314+
# branches:
315+
# only:
316+
# - main
317317
- ui_style
318318
- ui_test
319319
- vscode_test

docs/concepts/models/overview.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -513,9 +513,12 @@ Some properties are only available in specific model kinds - see the [model conf
513513

514514
Must be one of the following values: `allow`, `warn`, `error` (default), or `ignore`.
515515

516-
!!! warning "Ignore is Dangerous"
516+
### on_additive_change
517+
: What should happen when a change to a [forward-only model](../../guides/incremental_time.md#forward-only-models) or incremental model in a [forward-only plan](../plans.md#forward-only-plans) causes an additive modification to the table schema (i.e., adding new columns, modifying column data types in compatible ways, ect.).
517518

518-
`ignore` is dangerous since it can result in error or data loss. It likely should never be used but could be useful as an "escape-hatch" or a way to workaround unexpected behavior.
519+
SQLMesh checks for additive changes at plan time based on the model definition and run time based on the model's underlying physical tables.
520+
521+
Must be one of the following values: `allow` (default), `warn`, `error`, or `ignore`.
519522

520523
### disable_restatement
521524
: Set this to true to indicate that [data restatement](../plans.md#restatement-plans) is disabled for this model.

docs/concepts/plans.md

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -355,9 +355,25 @@ Some model changes destroy existing data in a table. SQLMesh automatically detec
355355
356356
Forward-only plans treats all of the plan's model changes as forward-only. In these plans, SQLMesh will check all modified incremental models for destructive schema changes, not just forward-only models.
357357
358-
SQLMesh determines what to do for each model based on this setting hierarchy: the [model's `on_destructive_change` value](../guides/incremental_time.md#destructive-changes) (if present), the `on_destructive_change` [model defaults](../reference/model_configuration.md#model-defaults) value (if present), and the SQLMesh global default of `error`.
358+
SQLMesh determines what to do for each model based on this setting hierarchy:
359359
360-
If you want to temporarily allow destructive changes to models that don't allow them, use the `plan` command's `--allow-destructive-model` selector to specify which models. Learn more about model selectors [here](../guides/model_selection.md).
360+
- **For destructive changes**: the [model's `on_destructive_change` value](../guides/incremental_time.md#schema-changes) (if present), the `on_destructive_change` [model defaults](../reference/model_configuration.md#model-defaults) value (if present), and the SQLMesh global default of `error`
361+
- **For additive changes**: the [model's `on_additive_change` value](../guides/incremental_time.md#schema-changes) (if present), the `on_additive_change` [model defaults](../reference/model_configuration.md#model-defaults) value (if present), and the SQLMesh global default of `allow`
362+
363+
If you want to temporarily allow destructive changes to models that don't allow them, use the `plan` command's `--allow-destructive-model` selector to specify which models.
364+
Similarly, if you want to temporarily allow additive changes to models configured with `on_additive_change=error`, use the `--allow-additive-model` selector.
365+
366+
For example, to allow additive changes to all models in the `analytics` schema:
367+
```bash
368+
sqlmesh plan --forward-only --allow-additive-model "analytics.*"
369+
```
370+
371+
Or to allow additive changes to multiple specific models:
372+
```bash
373+
sqlmesh plan --forward-only --allow-additive-model "sales.revenue_model" --allow-additive-model "marketing.campaign_model"
374+
```
375+
376+
Learn more about model selectors [here](../guides/model_selection.md).
361377
362378
### Effective date
363379
Changes that are part of the forward-only plan can also be applied retroactively to the production environment by specifying the effective date:

docs/guides/incremental_time.md

Lines changed: 122 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -159,24 +159,49 @@ WHERE
159159

160160
Alternatively, all the changes contained in a *specific plan* can be classified as forward-only with a flag: `sqlmesh plan --forward-only`. A subsequent plan that did not include the forward-only flag would fully refresh the model's physical table. Learn more about forward-only plans [here](../concepts/plans.md#forward-only-plans).
161161

162-
### Destructive changes
162+
### Schema changes
163163

164-
Some model changes destroy existing data in a table. Dropping a column from the model is the most direct cause, but changing a column's data type (such as casting a column from a `STRING` to `INTEGER`) can also require a drop. (Whether or not a specific change requires dropping a column may differ across SQL engines.)
164+
When SQLMesh processes forward-only changes to incremental models, it compares the model's new schema with the existing physical table schema to detect potential data loss or compatibility issues. SQLMesh categorizes schema changes into two types:
165165

166-
Forward-only models are used to retain existing data. Before executing forward-only changes to incremental models, SQLMesh performs a check to determine if existing data will be destroyed.
166+
#### Destructive changes
167167

168-
The check is performed at plan time based on the model definition. SQLMesh may not be able to resolve all of a model's column data types and complete the check, so the check is performed again at run time based on the physical tables underlying the model.
168+
Some model changes destroy existing data in a table. Examples include:
169+
170+
- **Dropping a column** from the model
171+
- **Renaming a column** without proper aliasing
172+
- **Modifying column constraints** in ways that could cause data loss
173+
174+
Whether a specific change is destructive may differ across SQL engines based on their schema evolution capabilities.
175+
176+
#### Additive changes
177+
178+
Additive changes are any changes that aren't categorized as destructive. A simple examples would be adding a column to a table.
179+
180+
SQLMesh performs schema change detection at plan time based on the model definition. If SQLMesh cannot resolve all of a model's column data types at plan time, the check is performed again at run time based on the physical tables underlying the model.
169181

170182
#### Changes to forward-only models
171183

172-
A model's `on_destructive_change` [configuration setting](../reference/model_configuration.md#incremental-models) determines what happens when SQLMesh detects a destructive change.
184+
SQLMesh provides two configuration settings to control how schema changes are handled:
185+
186+
- **`on_destructive_change`** - Controls behavior for destructive schema changes
187+
- **`on_additive_change`** - Controls behavior for additive schema changes
188+
189+
##### Configuration options
190+
191+
Both properties support four values:
173192

174-
By default, SQLMesh will error so no data is lost. You can set `on_destructive_change` to `warn` or `allow` in the model's `MODEL` block to allow destructive changes.
175-
`ignore` can be used to not perform the schema change and allow the table's definition to diverge from the model definition.
193+
- **`error`** (default for `on_destructive_change`): Stop execution and raise an error
194+
- **`warn`**: Log a warning but proceed with the change
195+
- **`allow`** (default for `on_additive_change`): Silently proceed with the change
196+
- **`ignore`**: Skip the schema change check entirely for this change type
176197

177198
!!! warning "Ignore is Dangerous"
178199

179-
`ignore` is dangerous since it can result in error or data loss. It likely should never be used but could be useful as an "escape-hatch" or a way to workaround unexpected behavior.
200+
`ignore` is dangerous since it can result in error or data loss. It likely should never be used but could be useful as an "escape-hatch" or a way to workaround unexpected behavior.
201+
202+
##### Destructive change handling
203+
204+
The `on_destructive_change` [configuration setting](../reference/model_configuration.md#incremental-models) determines what happens when SQLMesh detects a destructive change. By default, SQLMesh will error so no data is lost.
180205

181206
This example configures a model to silently `allow` destructive changes:
182207

@@ -191,12 +216,97 @@ MODEL (
191216
);
192217
```
193218

194-
A default `on_destructive_change` value can be set for all incremental models that do not specify it themselves in the [model defaults configuration](../reference/model_configuration.md#model-defaults).
219+
##### Additive change handling
220+
221+
The `on_additive_change` configuration setting determines what happens when SQLMesh detects an additive change like adding new columns. By default, SQLMesh allows these changes since they don't destroy existing data.
222+
223+
This example configures a model to raise an error for additive changes (useful for strict schema control):
224+
225+
``` sql linenums="1"
226+
MODEL (
227+
name sqlmesh_example.new_model,
228+
kind INCREMENTAL_BY_TIME_RANGE (
229+
time_column model_time_column,
230+
forward_only true,
231+
on_additive_change error
232+
),
233+
);
234+
```
235+
236+
##### Combining both settings
237+
238+
You can configure both settings together to have fine-grained control over schema evolution:
239+
240+
``` sql linenums="1"
241+
MODEL (
242+
name sqlmesh_example.new_model,
243+
kind INCREMENTAL_BY_TIME_RANGE (
244+
time_column model_time_column,
245+
forward_only true,
246+
on_destructive_change warn, -- Warn but allow destructive changes
247+
on_additive_change allow -- Silently allow new columns
248+
),
249+
);
250+
```
251+
252+
!!! warning "Unusual combinations"
253+
254+
SQLMesh will warn about unusual combinations such as allowing destructive changes while erroring on additive changes, since this indicates a potentially inconsistent schema change policy.
255+
256+
##### Model defaults
257+
258+
Default values for both `on_destructive_change` and `on_additive_change` can be set for all incremental models in the [model defaults configuration](../reference/model_configuration.md#model-defaults).
259+
260+
##### Common use cases
261+
262+
Here are some common patterns for configuring schema change handling:
263+
264+
**Strict schema control** - Prevent any schema changes:
265+
```sql linenums="1"
266+
MODEL (
267+
name sqlmesh_example.strict_model,
268+
kind INCREMENTAL_BY_TIME_RANGE (
269+
time_column event_date,
270+
forward_only true,
271+
on_destructive_change error, -- Block destructive changes
272+
on_additive_change error -- Block even new columns
273+
),
274+
);
275+
```
276+
277+
**Permissive development model** - Allow all schema changes:
278+
```sql linenums="1"
279+
MODEL (
280+
name sqlmesh_example.dev_model,
281+
kind INCREMENTAL_BY_TIME_RANGE (
282+
time_column event_date,
283+
forward_only true,
284+
on_destructive_change allow, -- Allow dropping columns
285+
on_additive_change allow -- Allow new columns
286+
),
287+
);
288+
```
289+
290+
**Production safety** - Allow safe changes, warn about risky ones:
291+
```sql linenums="1"
292+
MODEL (
293+
name sqlmesh_example.production_model,
294+
kind INCREMENTAL_BY_TIME_RANGE (
295+
time_column event_date,
296+
forward_only true,
297+
on_destructive_change warn, -- Warn about destructive changes
298+
on_additive_change allow -- Silently allow new columns
299+
),
300+
);
301+
```
195302

196303
#### Changes in forward-only plans
197304

198-
The SQLMesh `plan` [`--forward-only` option](../concepts/plans.md#forward-only-plans) treats all the plan's model changes as forward-only. When this option is specified, SQLMesh will check all modified incremental models for destructive schema changes, not just models configured with `forward_only true`.
305+
The SQLMesh `plan` [`--forward-only` option](../concepts/plans.md#forward-only-plans) treats all the plan's model changes as forward-only. When this option is specified, SQLMesh will check all modified incremental models for both destructive and additive schema changes, not just models configured with `forward_only true`.
306+
307+
SQLMesh determines what to do for each model based on this setting hierarchy:
199308

200-
SQLMesh determines what to do for each model based on this setting hierarchy: the model's `on_destructive_change` value (if present), the `on_destructive_change` [model defaults](../reference/model_configuration.md#model-defaults) value (if present), and the SQLMesh global default of `error`.
309+
- **For destructive changes**: the model's `on_destructive_change` value (if present), the `on_destructive_change` [model defaults](../reference/model_configuration.md#model-defaults) value (if present), and the SQLMesh global default of `error`
310+
- **For additive changes**: the model's `on_additive_change` value (if present), the `on_additive_change` [model defaults](../reference/model_configuration.md#model-defaults) value (if present), and the SQLMesh global default of `allow`
201311

202-
If you want to temporarily allow destructive changes to models that don't allow them, use the `plan` command's [`--allow-destructive-model` selector](../concepts/plans.md#destructive-changes) to specify which models. Learn more about model selectors [here](../guides/model_selection.md).
312+
If you want to temporarily allow destructive changes to models that don't allow them, use the `plan` command's [`--allow-destructive-model` selector](../concepts/plans.md#destructive-changes) to specify which models. Similarly, if you want to temporarily allow additive changes to models configured with `on_additive_change=error`, use the [`--allow-additive-model` selector](../concepts/plans.md#destructive-changes). Learn more about model selectors [here](../guides/model_selection.md).

docs/guides/model_selection.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
This guide describes how to select specific models to include in a SQLMesh plan, which can be useful when modifying a subset of the models in a SQLMesh project.
44

5-
Note: the selector syntax described below is also used for the SQLMesh `plan` [`--allow-destructive-model` selector](../concepts/plans.md#destructive-changes) and for the `table_diff` command to [diff a selection of models](./tablediff.md#diffing-multiple-models-across-environments).
5+
Note: the selector syntax described below is also used for the SQLMesh `plan` [`--allow-destructive-model` and `--allow-additive-model` selectors](../concepts/plans.md#destructive-changes) and for the `table_diff` command to [diff a selection of models](./tablediff.md#diffing-multiple-models-across-environments).
66

77
## Background
88

docs/integrations/dbt.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -273,18 +273,18 @@ Similarly, the [allow_partials](../concepts/models/overview.md#allow_partials) p
273273

274274
#### on_schema_change
275275

276-
SQLMesh automatically detects destructive schema changes to [forward-only incremental models](../guides/incremental_time.md#forward-only-models) and to all incremental models in [forward-only plans](../concepts/plans.md#destructive-changes).
276+
SQLMesh automatically detects both destructive and additive schema changes to [forward-only incremental models](../guides/incremental_time.md#forward-only-models) and to all incremental models in [forward-only plans](../concepts/plans.md#destructive-changes).
277277

278-
A model's [`on_destructive_change` setting](../guides/incremental_time.md#destructive-changes) determines whether it errors (default), warns, or silently allows the changes. SQLMesh always allows non-destructive forward-only schema changes, such as adding or casting a column in place.
278+
A model's [`on_destructive_change` and `on_additive_change` settings](../guides/incremental_time.md#schema-changes) determine whether it errors, warns, silently allows, or ignores the changes. SQLMesh provides fine-grained control over both destructive changes (like dropping columns) and additive changes (like adding new columns).
279279

280-
`on_schema_change` configuration values are mapped to these SQLMesh `on_destructive_change` values:
280+
`on_schema_change` configuration values are mapped to these SQLMesh settings:
281281

282-
| `on_schema_change` | SQLMesh `on_destructive_change` |
283-
| ------------------ | ------------------------------- |
284-
| ignore | warn |
285-
| append_new_columns | warn |
286-
| sync_all_columns | allow |
287-
| fail | error |
282+
| `on_schema_change` | SQLMesh `on_destructive_change` | SQLMesh `on_additive_change` |
283+
|--------------------|---------------------------------|------------------------------|
284+
| ignore | ignore | ignore |
285+
| fail | error | error |
286+
| append_new_columns | ignore | allow |
287+
| sync_all_columns | allow | allow |
288288

289289

290290
## Snapshot support

docs/reference/cli.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,8 @@ Options:
367367
--forward-only Create a plan for forward-only changes.
368368
--allow-destructive-model TEXT Allow destructive forward-only changes to
369369
models whose names match the expression.
370+
--allow-additive-model TEXT Allow additive forward-only changes to
371+
models whose names match the expression.
370372
--effective-from TEXT The effective date from which to apply
371373
forward-only changes on production.
372374
--no-prompts Disable interactive prompts for the backfill

0 commit comments

Comments
 (0)