Initial publish of dbt_f2dq (f2dq) package v0.12.1.

Clean package repo for Gitea installs via packages.yml git URL.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
M7XBeast
2026-10-11 17:37:40 +03:00
co-authored by Cursor
commit ff096b51b5
188 changed files with 5251 additions and 0 deletions
+20
View File
@@ -0,0 +1,20 @@
{% macro row_value(agate_row, column) %}
{{ return (agate_row[f2dq.name_in_db(column)]) }}
{% endmacro %}
{% macro agate_to_list(table) %}
{% set col_names = table.column_names %}
{% set query_result = [] %}
{% for row in table.rows %}
{% set pairs = [] %}
{% for col_name in col_names %}
{% set value = row.get(col_name) | string %}
{% do pairs.append('"' ~ (col_name | lower) ~ '":' ~ '"' ~ (value | replace('"', '\\\"') | replace('\n', '\\n') ) ~ '"') %}
{% endfor %}
{% set joined_pairs = '{' ~ (pairs | join(',')) ~ '}' %}
{% do query_result.append(joined_pairs) %}
{% endfor %}
{% set query_result = '[' ~ (query_result | join(',')) ~ ']' %}
{{ return (query_result) }}
{% endmacro %}
+8
View File
@@ -0,0 +1,8 @@
{% macro bool_to_string(column) %}
(
case when {{ column }} = true then 'true'
when {{ column }} = false then 'false'
end
) as {{ column }}
{% endmacro %}
+102
View File
@@ -0,0 +1,102 @@
{% macro get_column_type(column) %}
{% set result = adapter.dispatch('get_column_type', 'f2dq')(column) %}
{{ return(result) }}
{% endmacro %}
{% macro default__get_column_type(column) %}
{% if column.data_type in [
'character varying',
'varchar',
'character',
'char',
'text'
] %}
{{ return('text') }}
{% elif column.data_type in [
'smallint',
'integer',
'bigint',
'decimal',
'numeric',
'real',
'double precision',
'enum',
] %}
{{ return('numeric') }}
{% elif column.data_type in [ 'boolean', 'bool' ] %}
{{ return('boolean') }}
{% else %}
{{ return('unknown') }}
{% endif %}
{% endmacro %}
{% macro snowflake__get_column_type(column) %}
{% if column.DATA_TYPE in [
'VARCHAR',
'CHAR',
'CHARACTER',
'STRING',
'TEXT'
] %}
{{ return('text') }}
{% elif column.DATA_TYPE in [
'NUMBER',
'DECIMAL',
'NUMERIC',
'INT',
'INTEGER',
'BIGINT',
'SMALLINT',
'TINYINT',
'BYTEINT',
'FLOAT',
'FLOAT4',
'FLOAT8',
'DOUBLE',
'DOUBLE PRECISION',
'REAL',
] %}
{{ return('numeric') }}
{% elif column.data_type in [ 'BOOLEAN' ] %}
{{ return('boolean') }}
{% else %}
{{ return('unknown') }}
{% endif %}
{% endmacro %}
{% macro bigquery__get_column_type(column) %}
{% if column.data_type in [ 'STRING' ] %}
{{ return('text') }}
{% elif column.data_type in [ "INT64", "NUMERIC", "BIGNUMERIC", "FLOAT64", "INTEGER"] %}
{{ return('numeric') }}
{% elif column.data_type in [ "BOOLEAN", "BOOL"] %}
{{ return('boolean') }}
{% else %}
{{ return('unknown') }}
{% endif %}
{% endmacro %}
+5
View File
@@ -0,0 +1,5 @@
{% macro comma_delimited_list(args) %}
{%- for arg in args %}
{{- arg -}} {{- ", " if not loop.last else "" -}}
{% endfor %}
{% endmacro %}
+5
View File
@@ -0,0 +1,5 @@
{% macro comparison_text(a, b) %}
case when {{a}} > {{b}} then 'greater than'
when {{a}} = {{b}} then 'equal to'
else 'less than' end
{% endmacro %}
+58
View File
@@ -0,0 +1,58 @@
{# Dual-read helpers for migrating from re_data → f2dq without breaking
projects that still use re_data_* config keys or re_data:* vars. #}
{% macro f2dq_var(name, default=none) %}
{# Prefer f2dq:<name>; fall back to re_data:<name>; then default.
For booleans, either namespace set to true wins (so a project that
still sets re_data:store_table_samples: true keeps working even
though the package default for f2dq:store_table_samples is false). #}
{% set fkey = 'f2dq:' ~ name %}
{% set rkey = 're_data:' ~ name %}
{% set fval = var(fkey) if var.has_var(fkey) else none %}
{% set rval = var(rkey) if var.has_var(rkey) else none %}
{% if fval is sameas true or rval is sameas true %}
{{ return(true) }}
{% elif fval is sameas false and rval is sameas false %}
{{ return(false) }}
{% elif fval is not none and fval is not sameas false %}
{{ return(fval) }}
{% elif rval is not none and rval is not sameas false %}
{{ return(rval) }}
{% elif fval is not none %}
{{ return(fval) }}
{% elif rval is not none %}
{{ return(rval) }}
{% else %}
{{ return(default) }}
{% endif %}
{% endmacro %}
{% macro f2dq_node_config(el, key, default=none) %}
{# Read f2dq_<key> / re_data_<key> from node config, then config.meta /
node.meta (dbt 1.12 CustomKeyInConfigDeprecation migration path).
`key` is the suffix without package prefix, e.g. 'monitored',
'time_filter', 'metrics_groups'. #}
{% set keys = ['f2dq_' ~ key, 're_data_' ~ key] %}
{% for k in keys %}
{% if el.config is mapping and el.config.get(k) is not none %}
{{ return(el.config.get(k)) }}
{% endif %}
{% endfor %}
{% set conf_meta = el.config.get('meta', {}) if el.config is mapping else {} %}
{% if conf_meta is mapping %}
{% for k in keys %}
{% if conf_meta.get(k) is not none %}
{{ return(conf_meta.get(k)) }}
{% endif %}
{% endfor %}
{% endif %}
{% set node_meta = el.get('meta', {}) if el is mapping else {} %}
{% if node_meta is mapping %}
{% for k in keys %}
{% if node_meta.get(k) is not none %}
{{ return(node_meta.get(k)) }}
{% endif %}
{% endfor %}
{% endif %}
{{ return(default) }}
{% endmacro %}
@@ -0,0 +1,13 @@
{% macro add_duplication_context(relation, unique_cols, sort_columns) %}
select {{ dbt_utils.star(from=relation) }}
, count(*) over (
partition by {{ f2dq.comma_delimited_list(unique_cols) }}
) as f2dq_duplicate_group_row_count
, row_number() over (
partition by {{ f2dq.comma_delimited_list(unique_cols) }} {% if sort_columns %} order by {{ f2dq.comma_delimited_list(sort_columns) }} {% endif %}
) as f2dq_duplicate_group_row_number
from {{ relation }}
{% endmacro %}
+6
View File
@@ -0,0 +1,6 @@
{% macro generate_depends(used_tables) %}
{% for t in used_tables %}
-- depends_on: {{ ref(t) }}
{% endfor %}
{% endmacro %}
+14
View File
@@ -0,0 +1,14 @@
{% macro dict_from_list(el_list) %}
{% if el_list is none %}
{{ return (none) }}
{% endif %}
{% set for_cols_dict = {} %}
{% for col in el_list %}
{% do for_cols_dict.update({col: True})%}
{% endfor %}
{% do return(for_cols_dict) %}
{% endmacro %}
@@ -0,0 +1,40 @@
{#
# This file contains significant part of code derived from
# https://github.com/fivetran/dbt_fivetran_utils/tree/v0.4.0 which is licensed under Apache License 2.0.
#}
{% macro json_extract(string, string_path) -%}
{{ adapter.dispatch('json_extract','f2dq') (string, string_path) }}
{%- endmacro %}
{% macro default__json_extract(string, string_path) %}
json_extract_path_text({{string}}, {{ "'" ~ string_path ~ "'" }} )
{% endmacro %}
{% macro snowflake__json_extract(string, string_path) %}
json_extract_path_text(try_parse_json( {{string}} ), {{ "'" ~ string_path ~ "'" }} )
{% endmacro %}
{% macro redshift__json_extract(string, string_path) %}
case when is_valid_json( {{string}} ) then json_extract_path_text({{string}}, {{ "'" ~ string_path ~ "'" }} ) else null end
{% endmacro %}
{% macro bigquery__json_extract(string, string_path) %}
json_extract_scalar({{string}}, {{ "'$." ~ string_path ~ "'" }} )
{% endmacro %}
{% macro postgres__json_extract(string, string_path) %}
{{string}}::json->>{{"'" ~ string_path ~ "'" }}
{% endmacro %}
@@ -0,0 +1,60 @@
{#
# This file contains significant part of code derived from
# https://github.com/fivetran/dbt_fivetran_utils/tree/v0.4.0 which is licensed under Apache License 2.0.
#}
{% macro percentile(percentile_field, partition_field, percent) -%}
{{ adapter.dispatch('percentile','f2dq') (percentile_field, partition_field, percent) }}
{%- endmacro %}
--percentile calculation specific to Redshift
{% macro default__percentile(percentile_field, partition_field, percent) %}
percentile_cont(
{{ percent }} )
within group ( order by {{ percentile_field }} )
over ( partition by {{ partition_field }} )
{% endmacro %}
--percentile calculation specific to Redshift
{% macro redshift__percentile(percentile_field, partition_field, percent) %}
percentile_cont(
{{ percent }} )
within group ( order by {{ percentile_field }} )
over ( partition by {{ partition_field }} )
{% endmacro %}
--percentile calculation specific to BigQuery
{% macro bigquery__percentile(percentile_field, partition_field, percent) %}
percentile_cont(
{{ percentile_field }},
{{ percent }})
over (partition by {{ partition_field }}
)
{% endmacro %}
{% macro postgres__percentile(percentile_field, partition_field, percent) %}
percentile_cont(
{{ percent }} )
within group ( order by {{ percentile_field }} )
/* have to group by partition field */
{% endmacro %}
{% macro spark__percentile(percentile_field, partition_field, percent) %}
percentile(
{{ percentile_field }},
{{ percent }})
over (partition by {{ partition_field }}
)
{% endmacro %}
+4
View File
@@ -0,0 +1,4 @@
{% macro print_list(l) %}
{% for el in l %}{{el}}{% if not loop.last %},{% endif %}{% endfor %}
{% endmacro %}
+10
View File
@@ -0,0 +1,10 @@
{% macro percentage_formula(summation, total) %}
abs(
(
cast({{ summation }} as {{ numeric_type() }})
) /
nullif(
cast( {{ total }} as {{ numeric_type() }} )
, 0) * 100.0
)
{% endmacro %}
+65
View File
@@ -0,0 +1,65 @@
{% macro generate_anomaly_message(column_name, metric, last_value, last_avg) -%}
{{ return(adapter.dispatch('generate_anomaly_message', 'f2dq')(column_name, metric, last_value, last_avg)) }}
{%- endmacro %}
{% macro default__generate_anomaly_message(column_name, metric, last_value, last_avg) %}
case when {{ column_name }} != '' then metric || '(' || column_name || ')'
else metric
end
|| ' is ' ||
{{ to_2dp( percentage_formula('last_value - last_avg', last_avg) ) }}
|| '% ' ||
{{ comparison_text(last_value, last_avg) }}
|| ' average.'
{% endmacro %}
{% macro to_2dp(val) %}
{{ adapter.dispatch('to_2dp', 'f2dq')(val) }}
{% endmacro %}
{% macro default__to_2dp(val) %}
trim(to_char({{ val }}, '9999999999999999990D00'))
{% endmacro %}
{% macro bigquery__to_2dp(val) %}
format('%.2f', {{ val }})
{% endmacro %}
{% macro seconds_to_hours(val) %}
cast({{ val }} as {{ numeric_type() }}) / 3600
{% endmacro %}
{% macro generate_metric_value_text(metric, value) %}
case
when {{ metric }} = 'freshness'
then cast({{ to_2dp(seconds_to_hours(value)) }} as {{ string_type() }}) || ' hours'
when {{ regex_match_expression(metric, 'percent') }}
then cast({{ to_2dp(value) }} as {{ string_type() }}) || '%'
when {{ regex_match_expression(metric, 'count') }}
then cast({{ value }} as {{ string_type() }})
else cast({{ to_2dp(value) }} as {{ string_type() }})
end
{% endmacro %}
{% macro generate_schema_change_message(operation, column_name, prev_column_name, prev_data_type, data_type, detected_time) %}
case
when {{ operation }} = 'column_added'
then 'column ' || {{ column_name }} || ' of type ' || {{ data_type }} || ' was added.'
when {{ operation }} = 'column_removed'
then 'column ' || {{ prev_column_name }} || ' of type ' || {{ prev_data_type }} || ' was removed.'
when {{ operation }} = 'type_change'
then {{ column_name }} || ' column data type was changed from ' || {{ prev_data_type }} || ' to ' || {{ data_type }} || '.'
else ''
end
{% endmacro %}
{% macro generate_failed_test_message(test_name, column_name) %}
case
when {{ column_name }} is null
then 'Test ' || {{ test_name }} || ' failed.'
else
'Test ' || {{ test_name }} || ' failed for column ' || {{ column_name }} || '.'
end
{% endmacro %}
+16
View File
@@ -0,0 +1,16 @@
{% macro get_target_database() %}
{{- adapter.dispatch('get_target_database', 'f2dq')() -}}
{% endmacro %}
{% macro default__get_target_database() %}
{{- return (target.dbname) -}}
{% endmacro %}
{% macro bigquery__get_target_database() %}
{{- return (target.project) -}}
{% endmacro %}
{% macro snowflake__get_target_database() %}
{{- return (target.database) -}}
{% endmacro %}
+16
View File
@@ -0,0 +1,16 @@
{% macro in_compile() %}
{%- call statement('in_compile', fetch_result=True) -%}
select * from {{ ref('f2dq_run_started_at') }}
{%- endcall -%}
{% if execute %}
{%- set result = load_result('in_compile')['data'][0][0] -%}
{% if result == run_started_at.timestamp() * 1000000 %}
{{ return(False) }}
{% else %}
{{ return(True) }}
{% endif %}
{% endif %}
{% endmacro %}
+7
View File
@@ -0,0 +1,7 @@
{% macro is_list(obj) %}
{% if not obj %}
{{ return (False) }}
{% endif %}
{% set check = obj is iterable and (obj is not string and obj is not mapping) %}
{{ return (check) }}
{% endmacro %}
+22
View File
@@ -0,0 +1,22 @@
{% macro to_json_string_value_or_null(column) %}
(
case
when {{ column }} is null then 'null'
else '"' ||
regexp_replace(
replace(cast({{ column }} as {{ string_type() }}), '"', {{ escape_seq_for_json('"') }}),
'\n', {{ quote_new_line() }} {% if target.type in postgres_type_db() %}, 'g' {% endif %}
) || '"'
end
)
{% endmacro %}
{% macro to_single_json(columns) %}
'{' ||
{%- for column in columns %}
'"{{ column }}": ' ||
{{ to_json_string_value_or_null(column) }}
{%- if not loop.last %} || ',' || {%- endif %}
{%- endfor %}
|| '}'
{% endmacro %}
+67
View File
@@ -0,0 +1,67 @@
{% macro all_types_select() %}
with types_table as (
select
cast (null as {{ string_type() }}) as string_type,
cast (null as {{ long_string_type() }}) as long_string_type,
cast (1 as {{ numeric_type() }}) as numeric_type,
cast ('2000-01-10' as {{ timestamp_type() }}) as timestamp_type,
cast (true as {{ boolean_type() }}) as boolean_type
)
{% endmacro %}
{% macro empty_table_generic(list) %}
{{ f2dq.all_types_select() }}
select
{% for name, type in list %}
{{ type }}_type as {{ name }}
{%- if not loop.last %}, {%- endif %}
{% endfor %}
from types_table
where string_type is not null
{% endmacro %}
{% macro empty_last_base_metrics() %}
{{
f2dq.empty_table_generic([
('table_name', 'string'),
('column_name', 'string'),
('metric', 'string'),
('value', 'numeric')
])
}}
{% endmacro %}
{% macro empty_last_table_samples() %}
{{
f2dq.empty_table_generic([
('table_name', 'string'),
('sample_data', 'string')
])
}}
{% endmacro %}
{% macro empty_columns_table() %}
{{
f2dq.empty_table_generic([
('name', 'string'),
('schema', 'string'),
('database', 'string'),
('column_name', 'string'),
('data_type', 'string'),
('is_nullable', 'boolean'),
('time_filter', 'string'),
('computed_on', 'timestamp')
])
}}
{% endmacro %}
{% macro empty_table() %}
{{
f2dq.empty_table_generic([
('name', 'string')
])
}}
{% endmacro %}
+38
View File
@@ -0,0 +1,38 @@
{% macro columns_in_db(columns) %}
{% set translated = [] %}
{% if columns is none %}
{{ return (none) }}
{% endif %}
{% for col in columns %}
{% do translated.append(f2dq.name_in_db(col))%}
{% endfor %}
{{ return (translated) }}
{% endmacro %}
{% macro metrics_in_db(metrics) %}
{% set translated = metrics %}
{% set column_metrics = {} %}
{% for col in metrics.column %}
{% do column_metrics.update({f2dq.name_in_db(col): metrics.column[col]}) %}
{% endfor %}
{% if column_metrics %}
{% do metrics.update({'column': column_metrics}) %}
{% endif %}
{{ return (metrics) }}
{% endmacro %}
{% macro final_metrics(metrics_groups, additional_metrics) %}
{% set final_metrics_dict = dict([('group', {}), ('additional', {})]) %}
{% set all_metrics_groups = f2dq.f2dq_var('metrics_groups') %}
{% for group in metrics_groups %}
{% set value = all_metrics_groups.get(group) %}
{% do final_metrics_dict['group'].update(value) %}
{% endfor %}
{% do final_metrics_dict['additional'].update(additional_metrics) %}
{{ return (final_metrics_dict) }}
{% endmacro %}
+13
View File
@@ -0,0 +1,13 @@
{% macro quote_column(col_name) %}
{{ adapter.dispatch('quote_column', 'f2dq')(col_name) }}
{% endmacro %}
{% macro default__quote_column(col_name) %}
"{{ col_name }}"
{% endmacro %}
{% macro bigquery__quote_column(col_name) %}
`{{ col_name }}`
{% endmacro %}
+15
View File
@@ -0,0 +1,15 @@
{% macro regex_match_expression(column_name, pattern) %}
{{ adapter.dispatch('regex_match_expression', 'f2dq')(column_name, pattern) }}
{% endmacro %}
{% macro default__regex_match_expression(column_name, pattern) %}
({{column_name}} ~ '{{pattern}}')
{% endmacro %}
{% macro bigquery__regex_match_expression(column_name, pattern) %}
regexp_contains({{column_name}}, r'{{pattern}}')
{% endmacro %}
{% macro snowflake__regex_match_expression(column_name, pattern) %}
regexp_like({{column_name | upper}}, '{{pattern}}')
{% endmacro %}
+100
View File
@@ -0,0 +1,100 @@
{% macro time_window_start() %}
cast('{{- f2dq.f2dq_var('time_window_start') -}}' as timestamp)
{% endmacro %}
{% macro time_window_end() %}
cast('{{- f2dq.f2dq_var('time_window_end') -}}' as timestamp)
{% endmacro %}
{% macro anamaly_detection_time_window_start() %}
{{ adapter.dispatch('anamaly_detection_time_window_start', 'f2dq')() }}
{% endmacro %}
{% macro default__anamaly_detection_time_window_start() %}
{{ time_window_start() }} - interval '{{ f2dq.f2dq_var('anomaly_detection_look_back_days') }} days'
{% endmacro %}
{% macro bigquery__anamaly_detection_time_window_start() %}
DATE_ADD({{ time_window_start() }}, INTERVAL -{{ f2dq.f2dq_var('anomaly_detection_look_back_days') }} DAY)
{% endmacro %}
{% macro snowflake__anamaly_detection_time_window_start() %}
DATEADD('DAY', -{{- f2dq.f2dq_var('anomaly_detection_look_back_days') -}}, {{ time_window_start() }})
{% endmacro %}
{% macro interval_length_sec(start_timestamp, end_timestamp) %}
{{ adapter.dispatch('interval_length_sec', 'f2dq')(start_timestamp, end_timestamp) }}
{% endmacro %}
{% macro default__interval_length_sec(start_timestamp, end_timestamp) %}
EXTRACT(EPOCH FROM ({{ end_timestamp }} - {{ start_timestamp }} ))
{% endmacro %}
{% macro bigquery__interval_length_sec(start_timestamp, end_timestamp) %}
TIMESTAMP_DIFF ({{ end_timestamp }}, {{ start_timestamp }}, SECOND)
{% endmacro %}
{% macro snowflake__interval_length_sec(start_timestamp, end_timestamp) %}
timediff(second, {{ start_timestamp }}, {{ end_timestamp }})
{% endmacro %}
{% macro redshift__interval_length_sec(start_timestamp, end_timestamp) %}
DATEDIFF(second, {{ start_timestamp }}, {{ end_timestamp }})
{% endmacro %}
{%- macro in_time_window(time_column) %}
{# /* If not time_filter is specified, we compute the metric over the entire table else we filter for the time frame */ #}
{% if time_column is none %}
true
{% else %}
{{ adapter.dispatch('in_time_window', 'f2dq')(time_column) }}
{% endif %}
{% endmacro -%}
{% macro default__in_time_window(time_column) %}
{{time_column}} >= {{ time_window_start() }} and
{{time_column}} < {{ time_window_end() }}
{% endmacro %}
{% macro bigquery__in_time_window(time_column) %}
cast({{time_column}} as timestamp) >= {{ time_window_start() }} and
cast({{time_column}} as timestamp) < {{ time_window_end() }}
{% endmacro %}
{% macro format_timestamp(column_name) %}
{{ adapter.dispatch('format_timestamp', 'f2dq')(column_name) }}
{% endmacro %}
{% macro default__format_timestamp(column_name) %}
to_char({{column_name}}, 'YYYY-MM-DD HH24:MI:SS')
{% endmacro %}
{% macro bigquery__format_timestamp(column_name) %}
FORMAT_TIMESTAMP('%Y-%m-%d %H:%I:%S', {{column_name}})
{% endmacro %}
/*
provide a common way to compare time vs a range: start_date <= target <= end_date
if start_date is none: target <= end_date
if end_date is none: target >= start_date
think none as infinity
*/
{%- macro in_date_window(target, start_date, end_date) %}
{{ adapter.dispatch('in_date_window','f2dq')(target, start_date, end_date) }}
{% endmacro -%}
{% macro default__in_date_window(target, start_date, end_date) %}
{% if start_date is not none and end_date is not none %}
date({{target}}) between '{{start_date}}' and '{{end_date}}'
{% elif start_date is none %}
date({{target}}) <= '{{end_date}}'
{% elif end_date is none %}
date({{target}}) >= '{{start_date}}'
{% endif %}
{% endmacro %}
+100
View File
@@ -0,0 +1,100 @@
{% macro timestamp_type() %}
{{ adapter.dispatch('timestamp_type', 'f2dq')() }}
{% endmacro %}
{% macro default__timestamp_type() %}
timestamp without time zone
{% endmacro %}
{% macro redshift__timestamp_type() %}
TIMESTAMP
{% endmacro %}
{% macro bigquery__timestamp_type() %}
TIMESTAMP
{% endmacro %}
{% macro snowflake__timestamp_type() %}
TIMESTAMP_NTZ
{% endmacro %}
{% macro string_type() %}
{{ adapter.dispatch('string_type', 'f2dq')() }}
{% endmacro %}
{% macro default__string_type() %}
text
{% endmacro %}
{% macro redshift__string_type() %}
varchar(2047)
{% endmacro %}
{% macro bigquery__string_type() %}
STRING
{% endmacro %}
{% macro snowflake__string_type() %}
STRING
{% endmacro %}
{% macro long_string_type() %}
{{ adapter.dispatch('long_string_type', 'f2dq')() }}
{% endmacro %}
{% macro default__long_string_type() %}
{{ f2dq.string_type() }}
{% endmacro %}
{% macro redshift__long_string_type() %}
varchar(65535)
{% endmacro %}
{% macro integer_type() %}
INTEGER
{% endmacro %}
{% macro boolean_type() %}
{{ adapter.dispatch('boolean_type', 'f2dq')() }}
{% endmacro %}
{% macro default__boolean_type() %}
BOOLEAN
{% endmacro %}
{% macro redshift__boolean_type() %}
boolean
{% endmacro %}
{% macro bigquery__boolean_type() %}
BOOLEAN
{% endmacro %}
{% macro snowflake__boolean_type() %}
BOOLEAN
{% endmacro %}
{% macro numeric_type() %}
{{ adapter.dispatch('numeric_type', 'f2dq')() }}
{% endmacro %}
{% macro default__numeric_type() %}
double precision
{% endmacro %}
{% macro redshift__numeric_type() %}
DOUBLE PRECISION
{% endmacro %}
{% macro bigquery__numeric_type() %}
FLOAT64
{% endmacro %}
{% macro snowflake__numeric_type() %}
FLOAT
{% endmacro %}