如何将dbt宏传入模型配置并在自定义物化中执行?
问题描述
我尝试按如下方式将dbt宏传入模型配置:
{{ config( custom_macro=my_macro ) }}
其中my_macro定义在/macros/my_macro.sql文件中。
随后我尝试在自定义物化中运行该宏:
{% if config.get("custom_macro", None) %} {% do my_macro('foo') %} {% endif %}
但在编译阶段出现错误:
TypeError: can not serialize 'MacroGenerator' object
之后我尝试传入宏名称字符串,并使用adapter.dispatch或ref()等方法,但均未成功。
请问如何正确传递宏对象,或如何按宏名称动态执行宏?
解决方案
方式一:通过上下文对象动态获取宏执行
在模型配置里传入宏的名称字符串:
{{ config( custom_macro='my_macro' ) }}
在自定义物化中,利用dbt全局context对象获取宏实例并执行:
{% set macro_name = config.get("custom_macro") %} {% if macro_name %} {% set target_macro = context.get(macro_name) %} {% do target_macro('foo') %} {% endif %}
context可以直接通过宏名称字符串匹配到对应的MacroGenerator实例,避开序列化问题。
方式二:使用adapter.dispatch(官方推荐多场景方案)
如果需要适配多数据平台,优先用这种方式:
- 先定义带dispatch标识的宏(
/macros/my_macro.sql):
{% macro my_macro(arg) %} {{ return(adapter.dispatch('my_macro')(arg)) }} {% endmacro %} -- 默认平台实现示例 {% macro default__my_macro(arg) %} {{ log('执行my_macro,参数:' ~ arg, info=True) }} {% endmacro %}
- 模型配置传入宏名称:
{{ config( custom_macro='my_macro' ) }}
- 自定义物化中调用:
{% set macro_name = config.get("custom_macro") %} {% if macro_name %} {% do adapter.dispatch(macro_name)('foo') %} {% endif %}
该方式天然支持多平台适配,符合dbt最佳实践。
错误原因说明
dbt编译时会序列化模型配置,MacroGenerator是dbt内部的宏对象,无法被序列化成可存储格式,因此直接传入宏对象会触发序列化错误,必须传递字符串名称再动态获取执行。
内容的提问来源于stack exchange,提问作者rustohero
相关产品推荐
相关产品推荐

