{{ Today_date_milliseconds() }} - 是我在项目中的宏。如何将此宏重定向为参数,以便默认情况下我可以在 yml 中编写另一个宏?
{% test valid_date(model, column_name, exclude_condition = '1=1') %}
SELECT {{ column_name }}
FROM {{ model }}
WHERE (CAST( {{ column_name }} AS BIGINT) < {{ today_date_milliseconds() }}
AND {{ exclude_condition }}
{% endtest %}
Run Code Online (Sandbox Code Playgroud)
在 yml 中它看起来像
- name: date_3
description: column for third date
tests:
- valid_date:
lower_bound: 'name of another macro'
Run Code Online (Sandbox Code Playgroud)
我喜欢这个问题——我刚刚学到了一些研究它的东西(我想在另一个项目中做到这一点,所以我很高兴我做到了!)。
首先,需要注意的是,这是没有记录的,可能不鼓励,并且可能随时崩溃。
好消息是,未绑定的宏就像 python 函数一样,因此您可以将它们分配给 jinja 中的变量并稍后执行它们。举个例子,我有两个宏,它们只将一个单词记录到标准输出:
-- log_one.sql
{% macro log_one() %}
{{ log("one", info=True) }}
{% endmacro %}
-- log_two.sql
{% macro log_two() %}
{{ log("two", info=True) }}
{% endmacro %}
Run Code Online (Sandbox Code Playgroud)
在模型中,我可以将这两个宏之一分配给一个变量,然后执行该变量,如下所示:
-- this model will print `one` to the console when it is built
{% if execute %}
{% set bound_macro = log_one %}
{{ bound_macro() }}
{% endif %}
select 1
Run Code Online (Sandbox Code Playgroud)
请注意,周围没有引号log_one,因此我将对宏的实际引用传递到名为 的变量中bound_macro,这就是它起作用的原因。
但这对于您的用例来说还不够,因为您的配置将以字符串形式输入 jinja 上下文,而不是对宏的引用。在 Python 中,您可以使用eval()将字符串计算为代码,但 jinja 不允许这样做。
(这是未记录的部分,将来可能会损坏,但适用于 dbt v1.2)幸运的是,在每个 dbt 宏中,您都可以访问名为 的全局对象context。context就像字典一样,您可以使用上下文的方法访问所有宏、内置函数等,get其工作方式就像 Python 字典的get. 因此,您可以使用宏的名称作为字符串,通过使用 来获取对宏本身的引用context.get("macro_name")。就像字典一样,如果第一个参数不存在于context.
-- this will print `two` when the model is built
{% if execute %}
{% set macro_name = "log_two" %}
{% set bound_macro = context.get(macro_name, log_one) %}
{{ bound_macro() }}
{% endif %}
select 1
Run Code Online (Sandbox Code Playgroud)
-- this will print `one` when the model is built, since macro_name is not defined
{% if execute %}
{% set bound_macro = context.get(macro_name, log_one) %}
{{ bound_macro() }}
{% endif %}
select 1
Run Code Online (Sandbox Code Playgroud)
为了清楚起见进行编辑:
上下文只会在解析后填充,因此每次访问上下文时,都应该将其包装在一个{% if execute %}块中,如上面的示例所示。
对于您的具体示例,我将添加一个调用lower_bound到您的测试的参数,并为其指定一个默认值(字符串!),然后用于context检索正确的宏。为了更安全一点,您还可以向 提供默认参数get,尽管这可能会使调试配置中的拼写错误变得更加困难:
{% test valid_date(model, column_name, exclude_condition = '1=1', lower_bound="today_date_milliseconds") %}
{% set lower_bound_macro = context.get(lower_bound, today_date_milliseconds) %}
SELECT {{ column_name }}
FROM {{ model }}
WHERE (CAST( {{ column_name }} AS BIGINT) < {{ lower_bound_macro() }}
AND {{ exclude_condition }}
{% endtest %}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5554 次 |
| 最近记录: |