Skip to content

Commit b8ebc80

Browse files
Fix: normalize rows_affected to handle string values from dbt-databricks (#915)
* Fix: normalize rows_affected to handle string values from dbt-databricks When using dbt-databricks with view_update_via_alter enabled, skipped views return rows_affected as a string '-1' instead of an integer. This causes Spark's VALUES clause to fail with INVALID_INLINE_TABLE.INCOMPATIBLE_TYPES_IN_INLINE_TABLE when building bulk INSERTs for dbt_run_results. The fix adds a normalize_rows_affected macro that: - Converts string '-1' to null (skipped operations have no meaningful row count) - Converts other string numbers to integers (defensive handling) - Passes through normal integers unchanged Fixes: elementary-data/elementary#2089 Linear: CORE-267 Co-Authored-By: Yosef Arbiv <yosef.arbiv@gmail.com> * Add unit test for normalize_rows_affected macro Tests the following cases: - None input returns None - Integer inputs pass through unchanged (123, 0, -1) - String '-1' returns None (skipped operations) - Other string numbers are converted to integers ('123', '0', '456') Co-Authored-By: Yosef Arbiv <yosef.arbiv@gmail.com> * Fix test macro to not double-encode JSON results The log_macro_results helper already applies tojson() to the result, so the test macro should return the raw value instead of tojson(result). Co-Authored-By: Yosef Arbiv <yosef.arbiv@gmail.com> * Fix test to handle None return values from macro When the macro returns None, log_macro_results doesn't log anything, so run_operation returns an empty list. The test now handles this case by checking if the result list is empty before parsing. Co-Authored-By: Yosef Arbiv <yosef.arbiv@gmail.com> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Yosef Arbiv <yosef.arbiv@gmail.com>
1 parent 2396f71 commit b8ebc80

3 files changed

Lines changed: 54 additions & 1 deletion

File tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{% macro test_normalize_rows_affected(rows_affected) %}
2+
{% set result = elementary.normalize_rows_affected(rows_affected) %}
3+
{{ return(result) }}
4+
{% endmacro %}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import json
2+
3+
import pytest
4+
from dbt_project import DbtProject
5+
6+
7+
@pytest.mark.parametrize(
8+
"input_value,expected_output",
9+
[
10+
(None, None),
11+
(123, 123),
12+
(0, 0),
13+
(-1, -1),
14+
("123", 123),
15+
("0", 0),
16+
("-1", None),
17+
("456", 456),
18+
],
19+
)
20+
def test_normalize_rows_affected(dbt_project: DbtProject, input_value, expected_output):
21+
result = dbt_project.dbt_runner.run_operation(
22+
"elementary_tests.test_normalize_rows_affected",
23+
macro_args={"rows_affected": input_value},
24+
)
25+
# When the macro returns None, log_macro_results doesn't log anything,
26+
# so run_operation returns an empty list
27+
if not result:
28+
actual_output = None
29+
else:
30+
actual_output = json.loads(result[0])
31+
assert actual_output == expected_output, (
32+
f"normalize_rows_affected({input_value!r}) returned {actual_output!r}, "
33+
f"expected {expected_output!r}"
34+
)

macros/edr/dbt_artifacts/upload_run_results.sql

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,33 @@
3737
{{ return(dbt_run_results_empty_table_query) }}
3838
{% endmacro %}
3939

40+
{% macro normalize_rows_affected(rows_affected) %}
41+
{% if rows_affected is none %}
42+
{{ return(none) }}
43+
{% elif rows_affected is string %}
44+
{% if rows_affected == '-1' %}
45+
{{ return(none) }}
46+
{% else %}
47+
{{ return(rows_affected | int) }}
48+
{% endif %}
49+
{% else %}
50+
{{ return(rows_affected) }}
51+
{% endif %}
52+
{% endmacro %}
53+
4054
{% macro flatten_run_result(run_result) %}
4155
{% set run_result_dict = elementary.get_run_result_dict(run_result) %}
4256
{% set node = elementary.safe_get_with_default(run_result_dict, 'node', {}) %}
4357
{% set config_dict = elementary.safe_get_with_default(node, 'config', {}) %}
58+
{% set raw_rows_affected = run_result_dict.get('adapter_response', {}).get('rows_affected') %}
4459
{% set flatten_run_result_dict = {
4560
'model_execution_id': elementary.get_node_execution_id(node),
4661
'invocation_id': invocation_id,
4762
'unique_id': node.get('unique_id'),
4863
'name': node.get('name'),
4964
'message': run_result_dict.get('message'),
5065
'generated_at': elementary.datetime_now_utc_as_string(),
51-
'rows_affected': run_result_dict.get('adapter_response', {}).get('rows_affected'),
66+
'rows_affected': elementary.normalize_rows_affected(raw_rows_affected),
5267
'execution_time': run_result_dict.get('execution_time'),
5368
'status': run_result_dict.get('status'),
5469
'resource_type': node.get('resource_type'),

0 commit comments

Comments
 (0)