{% macro drop_function( func_name, signature ) %} DROP FUNCTION IF EXISTS {{ func_name }}({{ compile_signature(signature, drop_ = True) }}); {% endmacro %} {%- macro construct_api_route(route) -%} 'https://{{ var("REST_API_PREFIX_PROD") | lower if target.name == "prod" else var("REST_API_PREFIX_DEV") | lower }}{{ route }}' {%- endmacro -%} {%- macro compile_signature( params, drop_ = False ) -%} {% for p in params -%} {%- set name = p.0 -%} {%- set data_type = p.1 -%} {% if drop_ %} {{ data_type -}} {% else %} {{ name ~ " " ~ data_type -}} {%- endif -%} {%-if not loop.last -%}, {%- endif -%} {% endfor -%} {%- endmacro -%} {% macro create_sql_function( name_, signature, return_type, sql_, api_integration = none, options = none, func_type = none ) %} CREATE OR REPLACE {{ func_type }} FUNCTION {{ name_ }}( {{- compile_signature(signature) }} ) COPY GRANTS RETURNS {{ return_type }} {% if options -%} {{ options }} {% endif %} {%- if api_integration -%} api_integration = {{ api_integration }} AS {{ construct_api_route(sql_) ~ ";" }} {% else -%} AS $$ {{ sql_ }} $$; {%- endif -%} {%- endmacro -%} {%- macro create_or_drop_function_from_config( config, drop_ = False ) -%} {% set name_ = config ["name"] %} {% set signature = config ["signature"] %} {% set return_type = config ["return_type"] if config ["return_type"] is string else config ["return_type"][0] %} {% set sql_ = config ["sql"] %} {% set options = config ["options"] %} {% set api_integration = config ["api_integration"] %} {% set func_type = config ["func_type"] %} {% if not drop_ -%} {{ create_sql_function( name_ = name_, signature = signature, return_type = return_type, sql_ = sql_, options = options, api_integration = api_integration, func_type = func_type ) }} {%- else -%} {{ drop_function( name_, signature = signature, ) }} {%- endif %} {% endmacro %} {% macro crud_udfs(config_func, schema, drop_) %} {# Generate create or drop statements for a list of udf configs for a given schema config_func: function that returns a list of udf configs drop_: whether to drop or create the udfs #} {% set udfs = fromyaml(config_func())%} {%- for udf in udfs -%} {% if udf["name"].split(".") | first == schema %} CREATE SCHEMA IF NOT EXISTS {{ schema }}; {{- create_or_drop_function_from_config(udf, drop_=drop_) -}} {%- endif -%} {%- endfor -%} {%- endmacro -%} {% macro ephemeral_deploy_core(config) %} {# This macro is used to deploy functions using ephemeral models. It should only be used within an ephemeral model. #} {% if execute and (var("UPDATE_EPHEMERAL_UDFS") or var("DROP_UDFS_AND_SPS")) and model.unique_id in selected_resources %} {% set sql %} {{- crud_udfs(config, this.schema, var("DROP_UDFS_AND_SPS")) -}} {%- endset -%} {%- if var("DROP_UDFS_AND_SPS") -%} {%- do log("Drop core udfs: " ~ this.database ~ "." ~ this.schema, true) -%} {%- else -%} {%- do log("Deploy core udfs: " ~ this.database ~ "." ~ this.schema, true) -%} {%- endif -%} {%- do run_query(sql ~ apply_grants_by_schema(this.schema)) -%} {% else -%} SELECT '{{ model.schema }}' as schema_ {%- endif -%} {%- endmacro -%} {% macro apply_grants_by_schema(schema) %} {# Generates SQL to grant permissions to roles for a given schema. This gets run automatically when a deployment is made to prod. This can be manually run to grant permissions to a new schema: `dbt run-operation apply_grants_by_schema --args '{"schema": "my_schema"}'` #} {% if target.name == "prod" %} {%- set outer = namespace(sql="") -%} {% for role in [ "INTERNAL_DEV", "BI_ANALYTICS_READER"] %} {% set sql -%} {% if schema.startswith("_") %} REVOKE USAGE ON SCHEMA {{ target.database }}.{{ schema }} FROM {{ role }}; REVOKE USAGE ON ALL FUNCTIONS IN SCHEMA {{ target.database }}.{{ schema }} FROM {{ role }}; {%- else -%} GRANT USAGE ON SCHEMA {{ target.database }}.{{ schema }} TO {{ role }}; GRANT USAGE ON ALL FUNCTIONS IN SCHEMA {{ target.database }}.{{ schema }} TO {{ role }}; GRANT SELECT ON ALL TABLES IN SCHEMA {{ target.database }}.{{ schema }} TO {{ role }}; GRANT SELECT ON ALL VIEWS IN SCHEMA {{ target.database }}.{{ schema }} TO {{ role }}; {%- endif -%} {%- endset -%} {%- set outer.sql = outer.sql ~ sql -%} {%- endfor -%} {{ outer.sql }} {%- endif -%} {%- endmacro -%}