Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CT-705] Review dbt_utils "helper" methods: _is_relation + _is_ephemeral #5316

Open
jtcohen6 opened this issue Jun 1, 2022 · 2 comments
Open
Labels
tech_debt Behind-the-scenes changes, with little direct impact on end-user functionality utils Cross-database building blocks

Comments

@jtcohen6
Copy link
Contributor

jtcohen6 commented Jun 1, 2022

Many dbt_utils macros need to access information about an underlying table, by running adapter.get_columns_in_relation or a custom query.

Those macros expect to be passed a ref, source, or other Relation object, and for it to represent an object that really exists in the database. To ensure that's the case, and raise a helpful error if it isn't, they first call "internal helper" macros, _is_relation and _is_ephemeral, to check that the passed argument (a) really is a Relation, (b) isn't ephemeral (= exists as a database object, assuming it's already been run).

Because this is Jinja, we can't just call isinstance, or classmethods. We have to check meta properties.

dbt_utils._is_relation

{% macro _is_relation(obj, macro) %}
    {%- if not (obj is mapping and obj.get('metadata', {}).get('type', '').endswith('Relation')) -%}
        {%- do exceptions.raise_compiler_error("Macro " ~ macro ~ " expected a Relation but received the value: " ~ obj) -%}
    {%- endif -%}
{% endmacro %}

dbt_utils._is_ephemeral

There is a node method, is_ephemeral, but nothing available on the actual Relation object returned by ref... except the is_cte property:

{% macro _is_ephemeral(obj, macro) %}
    {%- if obj.is_cte -%}
        {% set ephemeral_prefix = api.Relation.add_ephemeral_prefix('') %}
        {% if obj.name.startswith(ephemeral_prefix) %}
            {% set model_name = obj.name[(ephemeral_prefix|length):] %}
        {% else %}
            {% set model_name = obj.name %}
        {%- endif -%}
        {% set error_message %}
The `{{ macro }}` macro cannot be used with ephemeral models, as it relies on the information schema.

`{{ model_name }}` is an ephemeral model. Consider making it a view or table instead.
        {% endset %}
        {%- do exceptions.raise_compiler_error(error_message) -%}
    {%- endif -%}
{% endmacro %}

Questions

  • Is there a better way to write these? Are there better properties / classmethods we could expose on the Relation object, to make it accessible in the Jinja layer?
  • Should these checks actually be happening within adapter methods like adapter.get_columns_in_relation?
@jtcohen6 jtcohen6 added tech_debt Behind-the-scenes changes, with little direct impact on end-user functionality Team:Language labels Jun 1, 2022
@github-actions github-actions bot changed the title Review dbt_utils "helper" methods: _is_relation + _is_ephemeral [CT-705] Review dbt_utils "helper" methods: _is_relation + _is_ephemeral Jun 1, 2022
@nathaniel-may
Copy link
Contributor

Would we consider exposing a python type function like isinstance() or type() to the jinja context directly?

@jtcohen6 jtcohen6 added the utils Cross-database building blocks label Jul 25, 2022
@whisperstream
Copy link

Chiming in here - I would find isinstance/type useful for a use case I have. I'm processing data in macro that comes from the config/meta dictionaries and being able to understand the the data type of the value in the dictionary would be useful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
tech_debt Behind-the-scenes changes, with little direct impact on end-user functionality utils Cross-database building blocks
Projects
None yet
Development

No branches or pull requests

3 participants