Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/concepts/models/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ Model files may contain SQL comments in a format supported in the model's SQL di

Some SQL engines support registering comments as metadata associated with a table or view. They may support table-level comments (e.g., "Revenue data for each customer") and/or column-level comments (e.g., "Customer's unique ID").

SQLMesh will automatically register comments if the engine supports it and the [gateway's connection `register_comments` configuration](../../reference/configuration.md#connection) is `true` (`true` by default for all engines other than Snowflake). Engines vary in their support for comments - see [tables below](#engine-comment-support).
SQLMesh will automatically register comments if the engine supports it and the [gateway's connection `register_comments` configuration](../../reference/configuration.md#connection) is `true` (`true` by default). Engines vary in their support for comments - see [tables below](#engine-comment-support).

#### Model comments

Expand Down
2 changes: 1 addition & 1 deletion docs/integrations/dbt.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ Note that the `--config` option is specified between the word `sqlmesh` and the

#### Registering comments

SQLMesh automatically registers model descriptions and column comments with the target SQL engine, as described in the [Models Overview documentation](../concepts/models/overview#model-description-and-comments). Comment registration is on by default for all engines that support it (but off by default for Snowflake).
SQLMesh automatically registers model descriptions and column comments with the target SQL engine, as described in the [Models Overview documentation](../concepts/models/overview#model-description-and-comments). Comment registration is on by default for all engines that support it.

dbt offers similar comment registration functionality via its [`persist_docs` model configuration parameter](https://docs.getdbt.com/reference/resource-configs/persist_docs), specified by model. SQLMesh comment registration is configured at the project level, so it does not use dbt's model-specific `persist_docs` configuration.

Expand Down
2 changes: 1 addition & 1 deletion docs/reference/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ Most parameters are specific to the connection engine `type` - see [below](#engi
| ------------------- | --------------------------------------------------------------------------------------------------------------------------- | :--: | :------: |
| `type` | The engine type name, listed in engine-specific configuration pages below. | str | Y |
| `concurrent_tasks` | The maximum number of concurrent tasks that will be run by SQLMesh. (Default: 4 for engines that support concurrent tasks.) | int | N |
| `register_comments` | Whether SQLMesh should register model comments with the SQL engine (if the engine supports it). (Default: `true`; `false` for Snowflake engine.) | bool | N |
| `register_comments` | Whether SQLMesh should register model comments with the SQL engine (if the engine supports it). (Default: `true`.) | bool | N |

#### Engine-specific

Expand Down
2 changes: 1 addition & 1 deletion sqlmesh/core/config/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ class SnowflakeConnectionConfig(ConnectionConfig):
private_key_passphrase: t.Optional[str] = None

concurrent_tasks: int = 4
register_comments: bool = False
register_comments: bool = True

type_: Literal["snowflake"] = Field(alias="type", default="snowflake")

Expand Down
2 changes: 1 addition & 1 deletion sqlmesh/core/engine_adapter/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ def __init__(
cursor_init: t.Optional[t.Callable[[t.Any], None]] = None,
default_catalog: t.Optional[str] = None,
execute_log_level: int = logging.DEBUG,
register_comments: bool = False,
register_comments: bool = True,
**kwargs: t.Any,
):
self.dialect = dialect.lower() or self.DIALECT
Expand Down
11 changes: 1 addition & 10 deletions sqlmesh/core/engine_adapter/shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,17 +108,13 @@ class CommentCreationView(Enum):
and in post-creation commands
IN_SCHEMA_DEF_NO_COMMANDS = all comments can be registered in CREATE VIEW schema definitions,
but not in post-creation commands
IN_SCHEMA_DEF_NO_COLUMN_COMMAND = all comments can be registered in CREATE VIEW schema definitions,
view comments can be registered in post-creation commands,
column comments cannot be registered in post-creation commands
COMMENT_COMMAND_ONLY = comments can only be registered via a post-creation command like `COMMENT` or `ALTER`
"""

UNSUPPORTED = 1
IN_SCHEMA_DEF_AND_COMMANDS = 2
IN_SCHEMA_DEF_NO_COMMANDS = 3
IN_SCHEMA_DEF_NO_COLUMN_COMMAND = 4
COMMENT_COMMAND_ONLY = 5
COMMENT_COMMAND_ONLY = 4

@property
def is_unsupported(self) -> bool:
Expand All @@ -132,10 +128,6 @@ def is_in_schema_def_and_commands(self) -> bool:
def is_in_schema_def_no_commands(self) -> bool:
return self == CommentCreationView.IN_SCHEMA_DEF_NO_COMMANDS

@property
def is_in_schema_def_no_column_command(self) -> bool:
return self == CommentCreationView.IN_SCHEMA_DEF_NO_COLUMN_COMMAND

@property
def is_comment_command_only(self) -> bool:
return self == CommentCreationView.COMMENT_COMMAND_ONLY
Expand All @@ -149,7 +141,6 @@ def supports_schema_def(self) -> bool:
return self in (
CommentCreationView.IN_SCHEMA_DEF_AND_COMMANDS,
CommentCreationView.IN_SCHEMA_DEF_NO_COMMANDS,
CommentCreationView.IN_SCHEMA_DEF_NO_COLUMN_COMMAND,
)

@property
Expand Down
10 changes: 8 additions & 2 deletions sqlmesh/core/engine_adapter/snowflake.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
from sqlmesh.core.engine_adapter.mixins import GetCurrentCatalogFromFunctionMixin
from sqlmesh.core.engine_adapter.shared import (
CatalogSupport,
CommentCreationView,
DataObject,
DataObjectType,
SourceQuery,
Expand Down Expand Up @@ -41,7 +40,6 @@ class SnowflakeEngineAdapter(GetCurrentCatalogFromFunctionMixin):
SUPPORTS_CLONING = True
CATALOG_SUPPORT = CatalogSupport.FULL_SUPPORT
CURRENT_CATALOG_EXPRESSION = exp.func("current_database")
COMMENT_CREATION_VIEW = CommentCreationView.IN_SCHEMA_DEF_NO_COLUMN_COMMAND

@contextlib.contextmanager
def session(self, properties: SessionProperties) -> t.Iterator[None]:
Expand Down Expand Up @@ -189,3 +187,11 @@ def _get_data_objects(

def set_current_catalog(self, catalog: str) -> None:
self.execute(exp.Use(this=exp.to_identifier(catalog)))

def _build_create_comment_column_exp(
self, table: exp.Table, column_name: str, column_comment: str, table_kind: str = "TABLE"
) -> exp.Comment | str:
table_sql = table.sql(dialect=self.dialect, identify=True)
column_sql = exp.column(column_name).sql(dialect=self.dialect, identify=True)

return f"ALTER {table_kind} {table_sql} ALTER COLUMN {column_sql} COMMENT '{self._truncate_column_comment(column_comment)}'"
8 changes: 0 additions & 8 deletions tests/core/engine_adapter/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ gateways:
catalogs:
memory: ':memory:'
testing: 'testing.duckdb'
register_comments: true
inttest_trino:
connection:
type: trino
Expand All @@ -15,7 +14,6 @@ gateways:
catalog: datalake
http_scheme: http
retries: 20
register_comments: true
state_connection:
type: duckdb
inttest_trino_iceberg:
Expand All @@ -27,7 +25,6 @@ gateways:
catalog: datalake_iceberg
http_scheme: http
retries: 20
register_comments: true
state_connection:
type: duckdb
inttest_trino_delta:
Expand All @@ -39,15 +36,13 @@ gateways:
catalog: datalake_delta
http_scheme: http
retries: 20
register_comments: true
state_connection:
type: duckdb
inttest_spark:
connection:
type: spark
config:
spark.remote: sc://localhost
register_comments: true
state_connection:
type: duckdb
inttest_mssql:
Expand All @@ -56,7 +51,6 @@ gateways:
host: localhost
user: sa
password: 1StrongPwd@@
register_comments: true
inttest_postgres:
connection:
type: postgres
Expand All @@ -66,7 +60,6 @@ gateways:
host: localhost
port: 5432
concurrent_tasks: 1
register_comments: true
inttest_mysql:
connection:
type: mysql
Expand All @@ -75,7 +68,6 @@ gateways:
password: mysql
port: 3306
charset: utf8
register_comments: true

model_defaults:
dialect: duckdb
48 changes: 47 additions & 1 deletion tests/core/engine_adapter/test_snowflake.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import pytest
from pytest_mock.plugin import MockerFixture
from sqlglot import exp
from sqlglot import exp, parse_one

from sqlmesh.core.dialect import normalize_model_name
from sqlmesh.core.engine_adapter import SnowflakeEngineAdapter
Expand Down Expand Up @@ -97,3 +97,49 @@ def test_session(
)

assert to_sql_calls(adapter) == expected_calls


def test_comments(make_mocked_engine_adapter: t.Callable, mocker: MockerFixture):
adapter = make_mocked_engine_adapter(SnowflakeEngineAdapter)

adapter.create_table(
"test_table",
{"a": exp.DataType.build("INT"), "b": exp.DataType.build("INT")},
table_description="table description",
column_descriptions={"a": "a column description"},
)

adapter.ctas(
"test_table",
parse_one("SELECT a, b FROM source_table"),
{"a": exp.DataType.build("INT"), "b": exp.DataType.build("INT")},
table_description="table description",
column_descriptions={"a": "a column description"},
)

adapter.create_view(
"test_view",
parse_one("SELECT a, b FROM source_table"),
table_description="table description",
column_descriptions={"a": "a column description"},
)

adapter._create_table_comment(
"test_table",
"table description",
)

adapter._create_column_comments(
"test_table",
{"a": "a column description"},
)

sql_calls = to_sql_calls(adapter)
assert sql_calls == [
"""CREATE TABLE IF NOT EXISTS "test_table" ("a" INT COMMENT 'a column description', "b" INT) COMMENT='table description'""",
"""CREATE TABLE IF NOT EXISTS "test_table" ("a" INT COMMENT 'a column description', "b" INT) COMMENT='table description' AS SELECT "a", "b" FROM "source_table\"""",
"""CREATE OR REPLACE VIEW "test_view" COMMENT='table description' AS SELECT "a", "b" FROM "source_table\"""",
"""ALTER VIEW "test_view" ALTER COLUMN "a" COMMENT 'a column description'""",
"""COMMENT ON TABLE "test_table" IS 'table description'""",
"""ALTER TABLE "test_table" ALTER COLUMN "a" COMMENT 'a column description'""",
]