Skip to content

Commit 29f2cfc

Browse files
authored
CT 2510 Throw error for duplicate versioned and non versioned model names (dbt-labs#7577)
* Check for versioned/unversioned duplicates * Add new exception DuplicateVersionedUnversionedError * Changie * Handle packages when finding versioned and unversioned duplicates
1 parent 43d949c commit 29f2cfc

File tree

4 files changed

+55
-1
lines changed

4 files changed

+55
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
kind: Fixes
2+
body: Throw error for duplicated versioned and unversioned models
3+
time: 2023-05-09T16:50:07.530882-04:00
4+
custom:
5+
Author: gshank
6+
Issue: "7487"

core/dbt/exceptions.py

+20
Original file line numberDiff line numberDiff line change
@@ -2200,6 +2200,26 @@ def get_message(self) -> str:
22002200
return msg
22012201

22022202

2203+
class DuplicateVersionedUnversionedError(ParsingError):
2204+
def __init__(self, versioned_node, unversioned_node):
2205+
self.versioned_node = versioned_node
2206+
self.unversioned_node = unversioned_node
2207+
super().__init__(msg=self.get_message())
2208+
2209+
def get_message(self) -> str:
2210+
msg = f"""
2211+
dbt found versioned and unversioned models with the name "{self.versioned_node.name}".
2212+
2213+
Since these resources have the same name, dbt will be unable to find the correct resource
2214+
when looking for ref('{self.versioned_node.name}').
2215+
2216+
To fix this, change the name of the unversioned resource
2217+
{self.unversioned_node.unique_id} ({self.unversioned_node.original_file_path})
2218+
or add the unversioned model to the versions in {self.versioned_node.patch_path}
2219+
""".strip()
2220+
return msg
2221+
2222+
22032223
class PropertyYMLError(CompilationError):
22042224
def __init__(self, path: str, issue: str):
22052225
self.path = path

core/dbt/parser/manifest.py

+20
Original file line numberDiff line numberDiff line change
@@ -1267,11 +1267,19 @@ def _check_resource_uniqueness(
12671267
config: RuntimeConfig,
12681268
) -> None:
12691269
alias_resources: Dict[str, ManifestNode] = {}
1270+
name_resources: Dict[str, Dict] = {}
12701271

12711272
for resource, node in manifest.nodes.items():
12721273
if not node.is_relational:
12731274
continue
12741275

1276+
if node.package_name not in name_resources:
1277+
name_resources[node.package_name] = {"ver": {}, "unver": {}}
1278+
if node.is_versioned:
1279+
name_resources[node.package_name]["ver"][node.name] = node
1280+
else:
1281+
name_resources[node.package_name]["unver"][node.name] = node
1282+
12751283
# the full node name is really defined by the adapter's relation
12761284
relation_cls = get_relation_class_by_name(config.credentials.type)
12771285
relation = relation_cls.create_from(config=config, node=node)
@@ -1285,6 +1293,18 @@ def _check_resource_uniqueness(
12851293

12861294
alias_resources[full_node_name] = node
12871295

1296+
for ver_unver_dict in name_resources.values():
1297+
versioned_names = ver_unver_dict["ver"].keys()
1298+
unversioned_names = ver_unver_dict["unver"].keys()
1299+
intersection_versioned = set(versioned_names).intersection(set(unversioned_names))
1300+
if intersection_versioned:
1301+
for name in intersection_versioned:
1302+
versioned_node = ver_unver_dict["ver"][name]
1303+
unversioned_node = ver_unver_dict["unver"][name]
1304+
raise dbt.exceptions.DuplicateVersionedUnversionedError(
1305+
versioned_node, unversioned_node
1306+
)
1307+
12881308

12891309
def _warn_for_unused_resource_config_paths(manifest: Manifest, config: RuntimeConfig) -> None:
12901310
resource_fqns: Mapping[str, PathSet] = manifest.get_resource_fqns()

tests/functional/partial_parsing/test_partial_parsing.py

+9-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171
groups_schema_yml_two_groups_private_orders_invalid_access,
7272
)
7373

74-
from dbt.exceptions import CompilationError, ParsingError
74+
from dbt.exceptions import CompilationError, ParsingError, DuplicateVersionedUnversionedError
7575
from dbt.contracts.files import ParseFileType
7676
from dbt.contracts.results import TestStatus
7777
import re
@@ -358,6 +358,14 @@ def test_pp_versioned_models(self, project):
358358
write_file(model_two_sql, project.project_root, "models", "model_one_different.sql")
359359
results = run_dbt(["--partial-parse", "run"])
360360
assert len(results) == 3
361+
manifest = get_manifest(project.project_root)
362+
assert len(manifest.nodes) == 3
363+
print(f"--- nodes: {manifest.nodes.keys()}")
364+
365+
# create a new model_one in model_one.sql and re-parse
366+
write_file(model_one_sql, project.project_root, "models", "model_one.sql")
367+
with pytest.raises(DuplicateVersionedUnversionedError):
368+
run_dbt(["parse"])
361369

362370

363371
class TestSources:

0 commit comments

Comments
 (0)