dbt data class column 简单说明

以前有简单介绍过dbt的 data class里边实际上包含了relation 以及column 一些方便的api 可以直接在macro 中调用
relation 比较常用,column 直接使用的并不是特别多,以下简单说明下

内部包装

与dbt context 对象一样属于一个包装

  • 参考定义
@contextproperty()
def api(self) -> Dict[str, Any]:
   # Relation 使用了包装的Relation,
   # Column 使用了adapter 提供的Column,注意此Column 在adapter 中会有使用到
    return {
        "Relation": self.db_wrapper.Relation,
        "Column": self.adapter.Column,
    }

api.Column 的使用

关于Relation的我就不介绍了,主要说明下Column的

  • 提供的方法

如下,数据数据类型的使用的比较多,还有就是一个translate_type,比如dbt_artifacts 就使用了此方法,进行类型映射,create 也会有使用到

  • adapter 内部的使用
    get_column_schema_from_query 方法使用,包含了create ,create 内部会使用translate_type,get_column_schema_from_query 同时也会
    包装为一个macro ,内部就是调用的此方法
@available.parse(lambda *a, **k: [])
def get_column_schema_from_query(self, sql: str) -> List[BaseColumn]:
    """Get a list of the Columns with names and data types from the given sql."""
    _, cursor = self.connections.add_select_query(sql)
    columns = [
        self.Column.create(
            column_name, self.connections.data_type_code_to_name(column_type_code)
        )
        # https://peps.python.org/pep-0249/#description
        for column_name, column_type_code, *_ in cursor.description
    ]
    return columns

get_column_schema_from_query macro 定义

{% macro get_column_schema_from_query(select_sql, select_sql_header=none) -%}
    {% set columns = [] %}
    {# -- Using an 'empty subquery' here to get the same schema as the given select_sql statement, without necessitating a data scan.#}
    {% set sql = get_empty_subquery_sql(select_sql, select_sql_header) %}
    {% set column_schema = adapter.get_column_schema_from_query(sql) %}
    {{ return(column_schema) }}
{% endmacro %}

get_column_schema_from_query macro 的使用
在adapter 提供的columns_spec_ddl 中使用的到,主要是进行类型check 的,在实际创建view 以及table 的时候会也间接调用此方法

{% macro assert_columns_equivalent(sql) %}
 
  {#-- First ensure the user has defined 'columns' in yaml specification --#}
  {%- set user_defined_columns = model['columns'] -%}
  {%- if not user_defined_columns -%}
      {{ exceptions.raise_contract_error([], []) }}
  {%- endif -%}
 
  {#-- Obtain the column schema provided by sql file. #}
  {%- set sql_file_provided_columns = get_column_schema_from_query(sql, config.get('sql_header', none)) -%}
  {#--Obtain the column schema provided by the schema file by generating an 'empty schema' query from the model's columns. #}
  {%- set schema_file_provided_columns = get_column_schema_from_query(get_empty_schema_sql(user_defined_columns)) -%}
 
  {#-- create dictionaries with name and formatted data type and strings for exception #}
  {%- set sql_columns = format_columns(sql_file_provided_columns) -%}
  {%- set yaml_columns = format_columns(schema_file_provided_columns)  -%}
 
  {%- if sql_columns|length != yaml_columns|length -%}
    {%- do exceptions.raise_contract_error(yaml_columns, sql_columns) -%}
  {%- endif -%}
 
  {%- for sql_col in sql_columns -%}
    {%- set yaml_col = [] -%}
    {%- for this_col in yaml_columns -%}
      {%- if this_col['name'] == sql_col['name'] -%}
        {%- do yaml_col.append(this_col) -%}
        {%- break -%}
      {%- endif -%}
    {%- endfor -%}
    {%- if not yaml_col -%}
      {#-- Column with name not found in yaml #}
      {%- do exceptions.raise_contract_error(yaml_columns, sql_columns) -%}
    {%- endif -%}
    {%- if sql_col['formatted'] != yaml_col[0]['formatted'] -%}
      {#-- Column data types don't match #}
      {%- do exceptions.raise_contract_error(yaml_columns, sql_columns) -%}
    {%- endif -%}
  {%- endfor -%}
 
{% endmacro %}

说明

以上是一个简单介绍,可以方便更好的使用dbt 的api.cloumn data class 能力

参考资料

dbt/adapters/base/column.py
dbt/include/global_project/macros/relations/column/columns_spec_ddl.sql
https://docs.getdbt.com/reference/dbt-classes

posted on 2024-06-17 08:00  荣锋亮  阅读(7)  评论(0编辑  收藏  举报

导航