Skip to content

Commit

Permalink
(#1269) Allow duplicated model names across packages
Browse files Browse the repository at this point in the history
  • Loading branch information
drewbanin committed Feb 5, 2021
1 parent 2b48152 commit 5536d48
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 5 deletions.
18 changes: 18 additions & 0 deletions core/dbt/contracts/graph/manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,14 @@ def search(self, haystack: Iterable[N]) -> Optional[N]:
return model
return None

def search_many(self, haystack: Iterable[N]) -> List[N]:
"""Find multiple entries in the given iterable by name."""
found = []
for model in haystack:
if self._matches(model):
found.append(model)
return found


D = TypeVar('D')

Expand Down Expand Up @@ -515,6 +523,16 @@ def build_flat_graph(self):
}
}

def find_nodes_by_name(
self, name: str, package: Optional[str] = None
) -> Optional[ManifestNode]:
searcher: NameSearcher = NameSearcher(
name, package, NodeType.refable()
)

result = searcher.search_many(self.nodes.values())
return result

def find_disabled_by_name(
self, name: str, package: Optional[str] = None
) -> Optional[ManifestNode]:
Expand Down
15 changes: 15 additions & 0 deletions core/dbt/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,21 @@ def raise_duplicate_macro_name(node_1, node_2, namespace) -> NoReturn:
)


def raise_ambiguous_ref(node_1, node_2):
duped_name = node_1.name
get_func = f'{{{{ ref("{duped_name}") }}}}'

raise_compiler_error(
f'The reference {get_func} is ambiguous because there are two nodes '
f'with the name "{duped_name}". To fix this, either change the name '
'of one of these nodes, or use the two-argument version of ref() '
'to specify the package that contains the intended node. Found nodes:\n'
f'- {node_1.unique_id} ({node_1.original_file_path})\n'
f'- {node_2.unique_id} ({node_2.original_file_path})\n\n'
f'Example: {{{{ ref("{node_1.package_name}", "{node_1.name}") }}}}'
)


def raise_duplicate_resource_name(node_1, node_2):
duped_name = node_1.name

Expand Down
21 changes: 16 additions & 5 deletions core/dbt/parser/manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -522,11 +522,22 @@ def _check_resource_uniqueness(
relation = relation_cls.create_from(config=config, node=node)
full_node_name = str(relation)

existing_node = names_resources.get(name)
if existing_node is not None:
dbt.exceptions.raise_duplicate_resource_name(
existing_node, node
)
# Check refs - is there an unqualified ref to a
# model that exists in two different packages?
for ref in node.refs:
if len(ref) == 1:
matched = manifest.find_nodes_by_name(ref[0])
else:
# two-arg refs are namespaced, so no need
# to check for duplicates. Nodes must still
# have unique names within a package
continue

if len(matched) > 1:
dbt.exceptions.raise_ambiguous_ref(
matched[0],
matched[1]
)

existing_alias = alias_resources.get(full_node_name)
if existing_alias is not None:
Expand Down

0 comments on commit 5536d48

Please sign in to comment.