Repository: dbt-labs/dbt-core

Issue:
Migrate to using `Mergeable` from `dbt-common
### Housekeeping

- [X] I am a maintainer of dbt-core

### Short description

We're currently in the process of moving the "data resource" portion on nodes to `dbt/artifacts`. Some of those artifacts depend on `Mergeable` which has been defined on core. In order to move the data resources to `dbt/artifacts`, we thus need to move `Mergeable` upstream of core. We moved `Mergeable` to [dbt-common](https://github.com/dbt-labs/dbt-common) in https://github.com/dbt-labs/dbt-common/pull/59, and released this change in [dbt-common 0.1.3](https://pypi.org/project/dbt-common/0.1.3/). As such as, in order to unblock some of the `dbt/artifacts` migration work, we first need to update references to `Mergeable` in core to use the `dbt-common` definition.

### Acceptance criteria

All uses of `Mergeable` in core use the definition in `dbt-common`

### Suggested Tests

None

### Impact to Other Teams

None

### Will backports be required?

No

### Context

_No response_


Discussion:

Resolving patch:
diff --git a/core/dbt/contracts/graph/unparsed.py b/core/dbt/contracts/graph/unparsed.py
--- a/core/dbt/contracts/graph/unparsed.py
+++ b/core/dbt/contracts/graph/unparsed.py
@@ -7,6 +7,7 @@
     AdditionalPropertiesAllowed,
     AdditionalPropertiesMixin,
 )
+from dbt_common.contracts.util import Mergeable
 from dbt_common.exceptions import DbtInternalError, CompilationError
 from dbt_common.dataclass_schema import (
     dbtClassMixin,
@@ -22,10 +23,7 @@
     MaturityType,
     MeasureAggregationParameters,
 )
-from dbt.contracts.util import (
-    Mergeable,
-    Replaceable,
-)
+from dbt.contracts.util import Replaceable
 
 # trigger the PathEncoder
 import dbt_common.helper_types  # noqa:F401
diff --git a/core/dbt/contracts/project.py b/core/dbt/contracts/project.py
--- a/core/dbt/contracts/project.py
+++ b/core/dbt/contracts/project.py
@@ -1,7 +1,8 @@
 from dbt import deprecations
-from dbt.contracts.util import Replaceable, Mergeable, list_str, Identifier
+from dbt.contracts.util import Replaceable, list_str, Identifier
 from dbt.adapters.contracts.connection import QueryComment
 from dbt_common.helper_types import NoValue
+from dbt_common.contracts.util import Mergeable
 from dbt_common.dataclass_schema import (
     dbtClassMixin,
     ValidationError,
diff --git a/core/dbt/contracts/util.py b/core/dbt/contracts/util.py
--- a/core/dbt/contracts/util.py
+++ b/core/dbt/contracts/util.py
@@ -1,8 +1,9 @@
-import dataclasses
 from typing import List, Any, Tuple
 
 from dbt_common.dataclass_schema import ValidatedStringMixin, ValidationError
-from dbt_common.contracts.util import Replaceable
+
+# Leave imports of `Mergeable` and `Replaceable` to preserve import paths
+from dbt_common.contracts.util import Mergeable, Replaceable  # noqa:F401
 
 
 SourceKey = Tuple[str, str]
@@ -24,22 +25,6 @@ class Foo:
     return []
 
 
-class Mergeable(Replaceable):
-    def merged(self, *args):
-        """Perform a shallow merge, where the last non-None write wins. This is
-        intended to merge dataclasses that are a collection of optional values.
-        """
-        replacements = {}
-        cls = type(self)
-        for arg in args:
-            for field in dataclasses.fields(cls):
-                value = getattr(arg, field.name)
-                if value is not None:
-                    replacements[field.name] = value
-
-        return self.replace(**replacements)
-
-
 class Identifier(ValidatedStringMixin):
     """Our definition of a valid Identifier is the same as what's valid for an unquoted database table name.
 


Test patch: