Skip to content

Commit 7a9cb3e

Browse files
authored
Merge pull request #929 from InfuseAI/feature/sc-32598/piperider-support-dbt-1-7
[Feature] Support dbt 1.7
2 parents ad3ce42 + 2ca7a73 commit 7a9cb3e

File tree

12 files changed

+161
-27
lines changed

12 files changed

+161
-27
lines changed

.github/workflows/dbt-compatible-tests.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
fail-fast: false
1717
matrix:
1818
version: [ '3.8', '3.9', '3.10', '3.11' ]
19-
dbt: [ ">=1.3,<1.4", ">=1.4,<1.5", ">=1.5,<1.6", ">=1.6,<1.7" ]
19+
dbt: [ ">=1.3,<1.4", ">=1.4,<1.5", ">=1.5,<1.6", ">=1.6,<1.7", ">=1.7,<1.8" ]
2020

2121
steps:
2222
- uses: actions/checkout@v2

piperider_cli/dbt/list_task.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def load_full_manifest(target_path: str, project_dir: str = None):
3434
register_adapter(runtime_config)
3535

3636
v = dbt_version
37-
if v == '1.5' or v == '1.6':
37+
if v == '1.5' or v == '1.6' or v == '1.7':
3838
return ManifestLoader.get_full_manifest(
3939
runtime_config, write_perf_info=False
4040
)
@@ -56,7 +56,7 @@ def load_manifest(manifest: Dict):
5656
if v == '1.5':
5757
return _load_manifest_version_15(manifest)
5858

59-
if v == '1.6':
59+
if v == '1.6' or v == '1.7':
6060
return _load_manifest_version_16(manifest)
6161

6262
raise NotImplementedError(f'dbt-core version: {v} is not supported')
@@ -114,12 +114,7 @@ def patched_get_manifest_schema_version(dct: dict) -> int:
114114
return int(match.group(1))
115115
raise ValueError("Manifest doesn't have schema version")
116116

117-
import dbt.contracts.graph.manifest
118-
origin_function = dbt.contracts.graph.manifest.get_manifest_schema_version
119-
dbt.contracts.graph.manifest.get_manifest_schema_version = patched_get_manifest_schema_version
120-
121117
result = WritableManifest.upgrade_schema_version(data)
122-
dbt.contracts.graph.manifest.get_manifest_schema_version = origin_function
123118
return result
124119

125120

@@ -265,7 +260,7 @@ def _get_v15_runtime_config(flags):
265260
setattr(flags, "target", None)
266261

267262
v = dbt_version
268-
if v == '1.5' or v == '1.6':
263+
if v == '1.5' or v == '1.6' or v == '1.7':
269264
return _get_v15_runtime_config(flags)
270265
elif v == '1.4':
271266
return _get_v14_runtime_config(flags)
@@ -362,6 +357,13 @@ def has_field(field_name):
362357
if has_field('packages_specified_path'):
363358
data['packages_specified_path'] = "packages.yml"
364359

360+
# dbt 1.7
361+
if has_field('semantic_models'):
362+
data['semantic_models'] = {}
363+
364+
if has_field('saved_queries'):
365+
data['saved_queries'] = {}
366+
365367
super().__init__(args=None, **data)
366368

367369
def validate(self):

piperider_cli/dbtutil.py

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -468,20 +468,39 @@ def _create_metric(name, filter=None, alias=None, root_name=None):
468468
primary_entity = None
469469
metric_filter = []
470470
if metric.get('filter') is not None:
471-
f = get_metric_filter(root_name, metric.get('filter'))
472-
if f is not None:
473-
metric_filter.append(f)
471+
# in dbt 1.7, there's an additional layer of 'where_filters'
472+
if 'where_filters' in metric.get('filter'):
473+
for where_filter in metric.get('filter').get('where_filters', []):
474+
f = get_metric_filter(root_name, where_filter)
475+
if f is not None:
476+
metric_filter.append(f)
477+
else:
478+
statistics.add_field_one('nosupport')
479+
return None
474480
else:
475-
statistics.add_field_one('nosupport')
476-
return None
481+
f = get_metric_filter(root_name, metric.get('filter'))
482+
if f is not None:
483+
metric_filter.append(f)
484+
else:
485+
statistics.add_field_one('nosupport')
486+
return None
477487

478488
if filter is not None:
479-
f = get_metric_filter(root_name, filter)
480-
if f is not None:
481-
metric_filter.append(f)
489+
if 'where_filters' in filter:
490+
for where_filter in filter.get('where_filters', []):
491+
f = get_metric_filter(root_name, where_filter)
492+
if f is not None:
493+
metric_filter.append(f)
494+
else:
495+
statistics.add_field_one('nosupport')
496+
return None
482497
else:
483-
statistics.add_field_one('nosupport')
484-
return None
498+
f = get_metric_filter(root_name, filter)
499+
if f is not None:
500+
metric_filter.append(f)
501+
else:
502+
statistics.add_field_one('nosupport')
503+
return None
485504

486505
nodes = metric.get('depends_on').get('nodes', [])
487506
depends_on = nodes[0]

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def _get_version():
4545
'requests>=2.28.1',
4646
'requests_toolbelt>=0.9.1',
4747
'deepmerge',
48-
'dbt-core>=1.3,<1.7'
48+
'dbt-core>=1.3'
4949
],
5050
tests_require=['pytest'],
5151
extras_require={

tests/mock_dbt_data/compatible/dbt-duckdb-1.7.0-manifest.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

tests/mock_dbt_data/jaffle_shop_base_1_7.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

tests/mock_dbt_data/jaffle_shop_target_1_7.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

tests/test_dbt_integeration.py

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,13 @@ def base_run_1_6(self):
6161
def target_run_1_6(self):
6262
return self.run_object("jaffle_shop_target_1_6.json")
6363

64+
def base_run_1_7(self):
65+
return self.run_object("jaffle_shop_base_1_7.json")
66+
67+
def target_run_1_7(self):
68+
return self.run_object("jaffle_shop_target_1_7.json")
69+
70+
6471
def base_31587(self):
6572
return self.run_object("sc-31587-base.json")
6673

@@ -187,6 +194,60 @@ def test_list_all_resources_16(self):
187194

188195
self.assertDbtResources(expected, all_results)
189196

197+
@pytest.mark.skipif(dbt_version < 'v1.7', reason='skip manifest test before dbt-core 1.7')
198+
def test_list_all_resources_17(self):
199+
expected = [
200+
"metric.jaffle_shop.average_order_amount",
201+
"metric.jaffle_shop.expenses",
202+
"metric.jaffle_shop.profit",
203+
"metric.jaffle_shop.revenue",
204+
"model.jaffle_shop.int_customer_order_history_joined",
205+
"model.jaffle_shop.int_order_payments_pivoted",
206+
"model.jaffle_shop.metricflow_time_spine",
207+
"model.jaffle_shop.orders",
208+
"model.jaffle_shop.stg_customers",
209+
"model.jaffle_shop.stg_orders",
210+
"model.jaffle_shop.stg_payments",
211+
"seed.jaffle_shop.raw_customers",
212+
"seed.jaffle_shop.raw_orders",
213+
"seed.jaffle_shop.raw_payments",
214+
"semantic_model.jaffle_shop.orders",
215+
"test.jaffle_shop.accepted_values_int_order_payments_pivoted_status__placed__shipped__completed__return_pending__returned.0ccdff53e8",
216+
"test.jaffle_shop.accepted_values_orders_status__placed__shipped__completed__return_pending__returned.be6b5b5ec3",
217+
"test.jaffle_shop.accepted_values_stg_orders_status__placed__shipped__completed__return_pending__returned.080fb20aad",
218+
"test.jaffle_shop.accepted_values_stg_payments_payment_method__credit_card__coupon__bank_transfer__gift_card.3c3820f278",
219+
"test.jaffle_shop.not_null_int_customer_order_history_joined_customer_id.5eeb8cdf92",
220+
"test.jaffle_shop.not_null_int_order_payments_pivoted_amount.b7598e0e3b",
221+
"test.jaffle_shop.not_null_int_order_payments_pivoted_bank_transfer_amount.1a9e62933b",
222+
"test.jaffle_shop.not_null_int_order_payments_pivoted_coupon_amount.2532b538c2",
223+
"test.jaffle_shop.not_null_int_order_payments_pivoted_credit_card_amount.ae9c42d967",
224+
"test.jaffle_shop.not_null_int_order_payments_pivoted_customer_id.3db59c6de4",
225+
"test.jaffle_shop.not_null_int_order_payments_pivoted_gift_card_amount.710d789cc0",
226+
"test.jaffle_shop.not_null_int_order_payments_pivoted_order_id.787ba994a8",
227+
"test.jaffle_shop.not_null_orders_amount.106140f9fd",
228+
"test.jaffle_shop.not_null_orders_bank_transfer_amount.7743500c49",
229+
"test.jaffle_shop.not_null_orders_coupon_amount.ab90c90625",
230+
"test.jaffle_shop.not_null_orders_credit_card_amount.d3ca593b59",
231+
"test.jaffle_shop.not_null_orders_customer_id.c5f02694af",
232+
"test.jaffle_shop.not_null_orders_gift_card_amount.413a0d2d7a",
233+
"test.jaffle_shop.not_null_orders_order_id.cf6c17daed",
234+
"test.jaffle_shop.not_null_stg_customers_customer_id.e2cfb1f9aa",
235+
"test.jaffle_shop.not_null_stg_orders_order_id.81cfe2fe64",
236+
"test.jaffle_shop.not_null_stg_payments_payment_id.c19cc50075",
237+
"test.jaffle_shop.relationships_int_order_payments_pivoted_customer_id__customer_id__ref_int_customer_order_history_joined_.654a1aa35d",
238+
"test.jaffle_shop.unique_int_customer_order_history_joined_customer_id.995635f7d9",
239+
"test.jaffle_shop.unique_int_order_payments_pivoted_order_id.34a0f3307d",
240+
"test.jaffle_shop.unique_orders_order_id.fed79b3a6e",
241+
"test.jaffle_shop.unique_stg_customers_customer_id.c7614daada",
242+
"test.jaffle_shop.unique_stg_orders_order_id.e3b841c71a",
243+
"test.jaffle_shop.unique_stg_payments_payment_id.3744510712"
244+
]
245+
246+
manifest = load_manifest(_load_manifest('dbt-duckdb-1.7.0-manifest.json'))
247+
all_results = list_resources_unique_id_from_manifest(manifest)
248+
249+
self.assertDbtResources(expected, all_results)
250+
190251
def test_compare_with_manifests(self):
191252
without_downstream = compare_models_between_manifests(
192253
self.base_manifest(), self.target_manifest()
@@ -209,9 +270,15 @@ def test_list_explicit_changes(self):
209270
expected = ["model.jaffle_shop.customers", "model.jaffle_shop.orders"]
210271
changes = c.list_explicit_changes()
211272
self.assertDbtResources(changes, expected)
212-
else:
273+
elif dbt_version < '1.7':
213274
c = GraphDataChangeSet(self.base_run_1_6(), self.target_run_1_6())
214275

276+
expected = ["model.jaffle_shop.orders"]
277+
changes = c.list_explicit_changes()
278+
self.assertDbtResources(changes, expected)
279+
elif dbt_version < '1.8':
280+
c = GraphDataChangeSet(self.base_run_1_7(), self.target_run_1_7())
281+
215282
expected = ["model.jaffle_shop.orders"]
216283
changes = c.list_explicit_changes()
217284
self.assertDbtResources(changes, expected)
@@ -266,7 +333,7 @@ def test_list_changes_metrics_case(self):
266333
changes,
267334
["metric.jaffle_shop.average_order_amount", "model.jaffle_shop.orders"],
268335
)
269-
else:
336+
elif dbt_version < '1.7':
270337
c = GraphDataChangeSet(self.base_run_1_6(), self.target_run_1_6())
271338
expected = ["model.jaffle_shop.orders"]
272339
changes = c.list_explicit_changes()
@@ -277,6 +344,12 @@ def test_list_changes_metrics_case(self):
277344
changes,
278345
["metric.jaffle_shop.average_order_amount", "model.jaffle_shop.orders"],
279346
)
347+
elif dbt_version < '1.8':
348+
c = GraphDataChangeSet(self.base_run_1_7(), self.target_run_1_7())
349+
350+
expected = ["model.jaffle_shop.orders"]
351+
changes = c.list_explicit_changes()
352+
self.assertDbtResources(changes, expected)
280353

281354
@unittest.skipIf(
282355
dbt_version < version.parse("1.4"),

tests/test_dbt_manifest_compatible.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ def manifest_from_1_6():
3434
return _load_manifest('dbt-duckdb-1.6.0-manifest.json')
3535

3636

37+
@pytest.fixture()
38+
def manifest_from_1_7():
39+
return _load_manifest('dbt-duckdb-1.7.0-manifest.json')
40+
41+
3742
def check_manifest_type(m):
3843
from dbt.contracts.graph.manifest import Manifest, WritableManifest
3944
assert isinstance(m, Manifest) or isinstance(m, WritableManifest)
@@ -62,6 +67,12 @@ def test_load_manifest_10(manifest_from_1_6):
6267
check_manifest_type(m)
6368

6469

70+
@pytest.mark.skipif(dbt_version < version.parse('v1.7'), reason='skip manifest test before dbt-core 1.7')
71+
def test_load_manifest_11(manifest_from_1_7):
72+
m = load_manifest(manifest_from_1_7)
73+
check_manifest_type(m)
74+
75+
6576
def test_log_functions():
6677
with disable_dbt_compile_stats():
6778
# make sure this not breaking in all dbt versions

tests/test_dbt_util.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,30 @@ def test_get_dbt_state_metrics_16(self, _get_state_manifest):
252252
metrics = dbtutil.get_dbt_state_metrics_16(self.dbt_state_dir, dbt_tag=None, dbt_resources=None)
253253
self.assertEqual(len(metrics), 0)
254254

255+
@pytest.mark.skipif(dbt_version < '1.7', reason="only for dbt 1.7")
256+
@mock.patch('piperider_cli.dbtutil._get_state_manifest')
257+
def test_get_dbt_state_metrics_17(self, _get_state_manifest):
258+
_get_state_manifest.return_value = _load_manifest('dbt-duckdb-1.7.0-manifest.json')
259+
metrics = dbtutil.get_dbt_state_metrics_16(self.dbt_state_dir, dbt_tag=None, dbt_resources=None)
260+
261+
self.assertEqual(len(metrics), 4)
262+
263+
# average_order_amount
264+
self.assertEqual(metrics[0].model.table, 'orders')
265+
self.assertEqual(metrics[0].model.timestamp, 'order_date')
266+
self.assertEqual(metrics[0].model.expression, 'amount')
267+
268+
# profit
269+
self.assertEqual(metrics[1].model, None)
270+
self.assertEqual(metrics[1].calculation_method, 'derived')
271+
self.assertEqual(metrics[1].expression, 'revenue - expenses')
272+
273+
# expenses
274+
self.assertEqual(metrics[2].name, 'expenses')
275+
276+
# revenue
277+
self.assertEqual(metrics[3].calculation_method, 'sum')
278+
255279
@mock.patch('pathlib.Path.cwd',
256280
return_value=Path(os.path.join(os.path.dirname(__file__), 'mock_dbt_project', 'dir_1', 'dir_2')))
257281
def test_search_dbt_project_path(self, *args):
@@ -284,7 +308,9 @@ def test_is_ready(self):
284308
def test_load_dbt_resources(self, get_dbt_manifest):
285309
v = dbt_version
286310
target_path = os.path.join(os.path.dirname(__file__), 'mock_dbt_data')
287-
if v == '1.6':
311+
if v == '1.7':
312+
get_dbt_manifest.return_value = _load_manifest('dbt-duckdb-1.7.0-manifest.json')
313+
elif v == '1.6':
288314
get_dbt_manifest.return_value = _load_manifest('dbt-duckdb-1.6.0-manifest.json')
289315
elif v == '1.5':
290316
get_dbt_manifest.return_value = _load_manifest('dbt-duckdb-1.5.1-manifest.json')

0 commit comments

Comments
 (0)