|
13 | 13 | import sqlmesh.core.dialect as d |
14 | 14 | from sqlmesh.core.engine_adapter import BigQueryEngineAdapter |
15 | 15 | from sqlmesh.core.engine_adapter.bigquery import select_partitions_expr |
16 | | -from sqlmesh.core.engine_adapter.mixins import TableAlterDropClusterKeyOperation |
| 16 | +from sqlmesh.core.engine_adapter.mixins import ( |
| 17 | + TableAlterClusterByOperation, |
| 18 | + TableAlterDropClusterKeyOperation, |
| 19 | +) |
17 | 20 | from sqlmesh.core.engine_adapter.shared import DataObject, DataObjectType |
18 | 21 | from sqlmesh.core.schema_diff import TableAlterDropColumnOperation |
19 | 22 | from sqlmesh.core.node import IntervalUnit |
@@ -1487,3 +1490,53 @@ def test_bigquery_no_column_change_clustering_drop_only( |
1487 | 1490 |
|
1488 | 1491 | assert len(operations) == 1 |
1489 | 1492 | assert isinstance(operations[0], TableAlterDropClusterKeyOperation) |
| 1493 | + |
| 1494 | + |
| 1495 | +def test_unchanged_clustering_key_is_not_altered_when_column_added( |
| 1496 | + adapter: BigQueryEngineAdapter, mocker: MockerFixture |
| 1497 | +): |
| 1498 | + # Adding a column to a clustered table must not emit a clustering change when the key |
| 1499 | + # itself is unchanged. BigQuery applies a new key by rewriting the clustered columns. |
| 1500 | + current_columns = {"c1": exp.DataType.build("INT64", dialect="bigquery")} |
| 1501 | + target_columns = { |
| 1502 | + **current_columns, |
| 1503 | + "c2": exp.DataType.build("INT64", dialect="bigquery"), |
| 1504 | + } |
| 1505 | + |
| 1506 | + def columns(table_name: str, include_pseudo_columns: bool = False) -> t.Dict[str, exp.DataType]: |
| 1507 | + if exp.to_table(table_name).name == "current_table": |
| 1508 | + return current_columns |
| 1509 | + return target_columns |
| 1510 | + |
| 1511 | + mocker.patch.object(adapter, "columns", side_effect=columns) |
| 1512 | + |
| 1513 | + def get_data_objects( |
| 1514 | + schema_name: exp.Table, |
| 1515 | + object_names: t.Optional[t.Set[str]] = None, |
| 1516 | + safe_to_cache: bool = False, |
| 1517 | + ) -> t.List[DataObject]: |
| 1518 | + assert object_names is not None |
| 1519 | + return [ |
| 1520 | + DataObject( |
| 1521 | + schema=schema_name.db, |
| 1522 | + name=next(iter(object_names)), |
| 1523 | + type=DataObjectType.TABLE, |
| 1524 | + clustering_key="(c1)", |
| 1525 | + ) |
| 1526 | + ] |
| 1527 | + |
| 1528 | + mocker.patch.object(adapter, "get_data_objects", side_effect=get_data_objects) |
| 1529 | + # Let a wrongly emitted clustering change surface as the column-rewrite UPDATE. |
| 1530 | + mocker.patch.object(adapter, "_get_table", return_value=mocker.Mock()) |
| 1531 | + mocker.patch.object(adapter, "_db_call") |
| 1532 | + |
| 1533 | + operations = adapter.get_alter_operations( |
| 1534 | + "test_schema.current_table", "test_schema.target_table" |
| 1535 | + ) |
| 1536 | + assert not any(isinstance(operation, TableAlterClusterByOperation) for operation in operations) |
| 1537 | + |
| 1538 | + adapter.alter_table(operations) |
| 1539 | + |
| 1540 | + assert _to_sql_calls(adapter) == [ |
| 1541 | + "ALTER TABLE `test_schema`.`current_table` ADD COLUMN `c2` INT64" |
| 1542 | + ] |
0 commit comments