diff --git a/dbt/include/clickhouse/macros/persist_docs.sql b/dbt/include/clickhouse/macros/persist_docs.sql index 442ae2be..f32be890 100644 --- a/dbt/include/clickhouse/macros/persist_docs.sql +++ b/dbt/include/clickhouse/macros/persist_docs.sql @@ -10,29 +10,45 @@ alter table {{ relation }} {{ on_cluster_clause(relation) }} modify comment '{{ comment }}' {% endmacro %} -{% macro clickhouse__persist_docs(relation, model, for_relation, for_columns) %} - {%- set alter_comments = [] %} - +{% macro clickhouse__persist_docs(relation, model, for_relation, for_columns) -%} + {# Persist table comment if enabled and description provided #} {%- if for_relation and config.persist_relation_docs() and model.description -%} - {% set escaped_comment = clickhouse_escape_comment(model.description) %} - {% do alter_comments.append("modify comment {comment}".format(comment=escaped_comment)) %} + {{ _persist_table_comment(relation, model.description) }} {%- endif -%} + {#- Persist column comments if enabled and columns defined -#} {%- if for_columns and config.persist_column_docs() and model.columns -%} - {% set existing_columns = adapter.get_columns_in_relation(relation) | map(attribute="name") | list %} - {% for column_name in model.columns if (column_name in existing_columns) %} - {%- set comment = model.columns[column_name]['description'] -%} - {%- if comment %} - {% set escaped_comment = clickhouse_escape_comment(comment) %} - {% do alter_comments.append("comment column `{column_name}` {comment}".format(column_name=column_name, comment=escaped_comment)) %} - {%- endif %} - {%- endfor -%} + {{ _persist_column_comments(relation, model.columns) }} {%- endif -%} +{%- endmacro %} + +{#- Helper macro: persist the table comment for a ClickHouse relation. -#} +{% macro _persist_table_comment(relation, description) -%} + {#- Escape the description to be safe for ClickHouse #} + {%- set escaped_comment = clickhouse_escape_comment(description) -%} + {#- Build and run the ALTER TABLE ... MODIFY COMMENT statement -#} + {%- set sql = "modify comment {comment}".format(comment=escaped_comment) -%} + {{ run_query(one_alter_relation(relation, sql)) }} +{%- endmacro %} - {%- if alter_comments | length > 0 -%} - {% do run_query(one_alter_relation(relation, alter_comments|join(', '))) %} +{#- Helper macro: persist comments for multiple columns on a ClickHouse table. + relation: target table relation + columns: dict mapping column names to metadata (including 'description') -#} +{% macro _persist_column_comments(relation, columns) -%} + {#- Gather existing columns in the relation to avoid altering non-existent ones -#} + {%- set existing_columns = adapter.get_columns_in_relation(relation) | map(attribute="name") | list -%} + {#- Collect ALTER statements for each column with a description -#} + {%- set alterations = [] -%} + {%- for column_name, info in columns.items() if info.description and column_name in existing_columns -%} + {%- set escaped_comment = clickhouse_escape_comment(info.description) -%} + {%- do alterations.append("\ncomment column `{column_name}` {comment}".format(column_name=column_name, comment=escaped_comment)) -%} + {%- endfor -%} + {#- Execute a single ALTER TABLE statement for all column comments -#} + {%- if alterations -%} + {{ run_query(one_alter_relation(relation, alterations | join(", "))) }} {%- endif -%} -{% endmacro %} +{%- endmacro %} + {# By using dollar-quoting like this, users can embed anything they want into their comments diff --git a/tests/integration/adapter/clickhouse/test_clickhouse_comments.py b/tests/integration/adapter/clickhouse/test_clickhouse_comments.py index 5179954a..d82224fc 100644 --- a/tests/integration/adapter/clickhouse/test_clickhouse_comments.py +++ b/tests/integration/adapter/clickhouse/test_clickhouse_comments.py @@ -18,6 +18,21 @@ """ +ref_models__replicated_table_comment_sql = """ +{{ + config( + materialized = "table", + persist_docs = {"relation": true, "columns": true}, + engine="ReplicatedMergeTree('/clickhouse/tables/{uuid}/one-shard', '{replica}' )" + ) +}} + +select + 'foo' as first_name, + 'bar' as second_name + +""" + ref_models__view_comment_sql = """ {{ config( @@ -43,6 +58,13 @@ description: "XXX first description" - name: second_name description: "XXX second description" + - name: replicated_table_comment + description: "YYY table" + columns: + - name: first_name + description: "XXX first description" + - name: second_name + description: "XXX second description" - name: view_comment description: "YYY view" columns: @@ -59,12 +81,13 @@ def models(self): return { "schema.yml": ref_models__schema_yml, "table_comment.sql": ref_models__table_comment_sql, + "replicated_table_comment.sql": ref_models__replicated_table_comment_sql, "view_comment.sql": ref_models__view_comment_sql, } @pytest.mark.parametrize( 'model_name', - ['table_comment', 'view_comment'], + ["table_comment", "replicated_table_comment", "view_comment"], ) def test_comment(self, project, model_name): if os.environ.get('DBT_CH_TEST_CLOUD', '').lower() in ('1', 'true', 'yes'):