dbt-adapters 1.22.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dbt/adapters/__about__.py +1 -0
- dbt/adapters/__init__.py +8 -0
- dbt/adapters/base/README.md +13 -0
- dbt/adapters/base/__init__.py +16 -0
- dbt/adapters/base/column.py +173 -0
- dbt/adapters/base/connections.py +429 -0
- dbt/adapters/base/impl.py +2036 -0
- dbt/adapters/base/meta.py +150 -0
- dbt/adapters/base/plugin.py +32 -0
- dbt/adapters/base/query_headers.py +106 -0
- dbt/adapters/base/relation.py +648 -0
- dbt/adapters/cache.py +521 -0
- dbt/adapters/capability.py +63 -0
- dbt/adapters/catalogs/__init__.py +14 -0
- dbt/adapters/catalogs/_client.py +54 -0
- dbt/adapters/catalogs/_constants.py +1 -0
- dbt/adapters/catalogs/_exceptions.py +39 -0
- dbt/adapters/catalogs/_integration.py +113 -0
- dbt/adapters/clients/__init__.py +0 -0
- dbt/adapters/clients/jinja.py +24 -0
- dbt/adapters/contracts/__init__.py +0 -0
- dbt/adapters/contracts/connection.py +229 -0
- dbt/adapters/contracts/macros.py +11 -0
- dbt/adapters/contracts/relation.py +160 -0
- dbt/adapters/events/README.md +51 -0
- dbt/adapters/events/__init__.py +0 -0
- dbt/adapters/events/adapter_types_pb2.py +2 -0
- dbt/adapters/events/base_types.py +36 -0
- dbt/adapters/events/logging.py +83 -0
- dbt/adapters/events/types.py +436 -0
- dbt/adapters/exceptions/__init__.py +40 -0
- dbt/adapters/exceptions/alias.py +24 -0
- dbt/adapters/exceptions/cache.py +68 -0
- dbt/adapters/exceptions/compilation.py +269 -0
- dbt/adapters/exceptions/connection.py +16 -0
- dbt/adapters/exceptions/database.py +51 -0
- dbt/adapters/factory.py +264 -0
- dbt/adapters/protocol.py +150 -0
- dbt/adapters/py.typed +0 -0
- dbt/adapters/record/__init__.py +2 -0
- dbt/adapters/record/base.py +291 -0
- dbt/adapters/record/cursor/cursor.py +69 -0
- dbt/adapters/record/cursor/description.py +37 -0
- dbt/adapters/record/cursor/execute.py +39 -0
- dbt/adapters/record/cursor/fetchall.py +69 -0
- dbt/adapters/record/cursor/fetchmany.py +23 -0
- dbt/adapters/record/cursor/fetchone.py +23 -0
- dbt/adapters/record/cursor/rowcount.py +23 -0
- dbt/adapters/record/handle.py +55 -0
- dbt/adapters/record/serialization.py +115 -0
- dbt/adapters/reference_keys.py +39 -0
- dbt/adapters/relation_configs/README.md +25 -0
- dbt/adapters/relation_configs/__init__.py +12 -0
- dbt/adapters/relation_configs/config_base.py +46 -0
- dbt/adapters/relation_configs/config_change.py +26 -0
- dbt/adapters/relation_configs/config_validation.py +57 -0
- dbt/adapters/sql/__init__.py +2 -0
- dbt/adapters/sql/connections.py +263 -0
- dbt/adapters/sql/impl.py +286 -0
- dbt/adapters/utils.py +69 -0
- dbt/include/__init__.py +3 -0
- dbt/include/global_project/__init__.py +4 -0
- dbt/include/global_project/dbt_project.yml +7 -0
- dbt/include/global_project/docs/overview.md +43 -0
- dbt/include/global_project/macros/adapters/apply_grants.sql +167 -0
- dbt/include/global_project/macros/adapters/columns.sql +144 -0
- dbt/include/global_project/macros/adapters/freshness.sql +32 -0
- dbt/include/global_project/macros/adapters/indexes.sql +41 -0
- dbt/include/global_project/macros/adapters/metadata.sql +105 -0
- dbt/include/global_project/macros/adapters/persist_docs.sql +33 -0
- dbt/include/global_project/macros/adapters/relation.sql +84 -0
- dbt/include/global_project/macros/adapters/schema.sql +20 -0
- dbt/include/global_project/macros/adapters/show.sql +26 -0
- dbt/include/global_project/macros/adapters/timestamps.sql +52 -0
- dbt/include/global_project/macros/adapters/validate_sql.sql +10 -0
- dbt/include/global_project/macros/etc/datetime.sql +62 -0
- dbt/include/global_project/macros/etc/statement.sql +52 -0
- dbt/include/global_project/macros/generic_test_sql/accepted_values.sql +27 -0
- dbt/include/global_project/macros/generic_test_sql/not_null.sql +9 -0
- dbt/include/global_project/macros/generic_test_sql/relationships.sql +23 -0
- dbt/include/global_project/macros/generic_test_sql/unique.sql +12 -0
- dbt/include/global_project/macros/get_custom_name/get_custom_alias.sql +36 -0
- dbt/include/global_project/macros/get_custom_name/get_custom_database.sql +32 -0
- dbt/include/global_project/macros/get_custom_name/get_custom_schema.sql +60 -0
- dbt/include/global_project/macros/materializations/configs.sql +21 -0
- dbt/include/global_project/macros/materializations/functions/aggregate.sql +65 -0
- dbt/include/global_project/macros/materializations/functions/function.sql +20 -0
- dbt/include/global_project/macros/materializations/functions/helpers.sql +20 -0
- dbt/include/global_project/macros/materializations/functions/scalar.sql +69 -0
- dbt/include/global_project/macros/materializations/hooks.sql +35 -0
- dbt/include/global_project/macros/materializations/models/clone/can_clone_table.sql +7 -0
- dbt/include/global_project/macros/materializations/models/clone/clone.sql +67 -0
- dbt/include/global_project/macros/materializations/models/clone/create_or_replace_clone.sql +7 -0
- dbt/include/global_project/macros/materializations/models/incremental/column_helpers.sql +80 -0
- dbt/include/global_project/macros/materializations/models/incremental/incremental.sql +99 -0
- dbt/include/global_project/macros/materializations/models/incremental/is_incremental.sql +13 -0
- dbt/include/global_project/macros/materializations/models/incremental/merge.sql +120 -0
- dbt/include/global_project/macros/materializations/models/incremental/on_schema_change.sql +159 -0
- dbt/include/global_project/macros/materializations/models/incremental/strategies.sql +92 -0
- dbt/include/global_project/macros/materializations/models/materialized_view.sql +121 -0
- dbt/include/global_project/macros/materializations/models/table.sql +64 -0
- dbt/include/global_project/macros/materializations/models/view.sql +72 -0
- dbt/include/global_project/macros/materializations/seeds/helpers.sql +128 -0
- dbt/include/global_project/macros/materializations/seeds/seed.sql +60 -0
- dbt/include/global_project/macros/materializations/snapshots/helpers.sql +345 -0
- dbt/include/global_project/macros/materializations/snapshots/snapshot.sql +109 -0
- dbt/include/global_project/macros/materializations/snapshots/snapshot_merge.sql +34 -0
- dbt/include/global_project/macros/materializations/snapshots/strategies.sql +184 -0
- dbt/include/global_project/macros/materializations/tests/helpers.sql +44 -0
- dbt/include/global_project/macros/materializations/tests/test.sql +66 -0
- dbt/include/global_project/macros/materializations/tests/unit.sql +40 -0
- dbt/include/global_project/macros/materializations/tests/where_subquery.sql +15 -0
- dbt/include/global_project/macros/python_model/python.sql +114 -0
- dbt/include/global_project/macros/relations/column/columns_spec_ddl.sql +89 -0
- dbt/include/global_project/macros/relations/create.sql +23 -0
- dbt/include/global_project/macros/relations/create_backup.sql +17 -0
- dbt/include/global_project/macros/relations/create_intermediate.sql +17 -0
- dbt/include/global_project/macros/relations/drop.sql +41 -0
- dbt/include/global_project/macros/relations/drop_backup.sql +14 -0
- dbt/include/global_project/macros/relations/materialized_view/alter.sql +55 -0
- dbt/include/global_project/macros/relations/materialized_view/create.sql +10 -0
- dbt/include/global_project/macros/relations/materialized_view/drop.sql +14 -0
- dbt/include/global_project/macros/relations/materialized_view/refresh.sql +9 -0
- dbt/include/global_project/macros/relations/materialized_view/rename.sql +10 -0
- dbt/include/global_project/macros/relations/materialized_view/replace.sql +10 -0
- dbt/include/global_project/macros/relations/rename.sql +35 -0
- dbt/include/global_project/macros/relations/rename_intermediate.sql +14 -0
- dbt/include/global_project/macros/relations/replace.sql +50 -0
- dbt/include/global_project/macros/relations/schema.sql +8 -0
- dbt/include/global_project/macros/relations/table/create.sql +60 -0
- dbt/include/global_project/macros/relations/table/drop.sql +14 -0
- dbt/include/global_project/macros/relations/table/rename.sql +10 -0
- dbt/include/global_project/macros/relations/table/replace.sql +10 -0
- dbt/include/global_project/macros/relations/view/create.sql +27 -0
- dbt/include/global_project/macros/relations/view/drop.sql +14 -0
- dbt/include/global_project/macros/relations/view/rename.sql +10 -0
- dbt/include/global_project/macros/relations/view/replace.sql +66 -0
- dbt/include/global_project/macros/unit_test_sql/get_fixture_sql.sql +107 -0
- dbt/include/global_project/macros/utils/any_value.sql +9 -0
- dbt/include/global_project/macros/utils/array_append.sql +8 -0
- dbt/include/global_project/macros/utils/array_concat.sql +7 -0
- dbt/include/global_project/macros/utils/array_construct.sql +12 -0
- dbt/include/global_project/macros/utils/bool_or.sql +9 -0
- dbt/include/global_project/macros/utils/cast.sql +7 -0
- dbt/include/global_project/macros/utils/cast_bool_to_text.sql +7 -0
- dbt/include/global_project/macros/utils/concat.sql +7 -0
- dbt/include/global_project/macros/utils/data_types.sql +129 -0
- dbt/include/global_project/macros/utils/date.sql +10 -0
- dbt/include/global_project/macros/utils/date_spine.sql +75 -0
- dbt/include/global_project/macros/utils/date_trunc.sql +7 -0
- dbt/include/global_project/macros/utils/dateadd.sql +14 -0
- dbt/include/global_project/macros/utils/datediff.sql +14 -0
- dbt/include/global_project/macros/utils/equals.sql +14 -0
- dbt/include/global_project/macros/utils/escape_single_quotes.sql +8 -0
- dbt/include/global_project/macros/utils/except.sql +9 -0
- dbt/include/global_project/macros/utils/generate_series.sql +53 -0
- dbt/include/global_project/macros/utils/hash.sql +7 -0
- dbt/include/global_project/macros/utils/intersect.sql +9 -0
- dbt/include/global_project/macros/utils/last_day.sql +15 -0
- dbt/include/global_project/macros/utils/length.sql +11 -0
- dbt/include/global_project/macros/utils/listagg.sql +30 -0
- dbt/include/global_project/macros/utils/literal.sql +7 -0
- dbt/include/global_project/macros/utils/position.sql +11 -0
- dbt/include/global_project/macros/utils/replace.sql +14 -0
- dbt/include/global_project/macros/utils/right.sql +12 -0
- dbt/include/global_project/macros/utils/safe_cast.sql +9 -0
- dbt/include/global_project/macros/utils/split_part.sql +26 -0
- dbt/include/global_project/tests/generic/builtin.sql +30 -0
- dbt/include/py.typed +0 -0
- dbt_adapters-1.22.2.dist-info/METADATA +124 -0
- dbt_adapters-1.22.2.dist-info/RECORD +173 -0
- dbt_adapters-1.22.2.dist-info/WHEEL +4 -0
- dbt_adapters-1.22.2.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
from typing import Any, List, Mapping
|
|
2
|
+
|
|
3
|
+
from dbt_common.exceptions import CompilationError, DbtDatabaseError
|
|
4
|
+
from dbt_common.ui import line_wrap_message
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class MissingConfigError(CompilationError):
|
|
8
|
+
def __init__(self, unique_id: str, name: str):
|
|
9
|
+
self.unique_id = unique_id
|
|
10
|
+
self.name = name
|
|
11
|
+
msg = (
|
|
12
|
+
f"Model '{self.unique_id}' does not define a required config parameter '{self.name}'."
|
|
13
|
+
)
|
|
14
|
+
super().__init__(msg=msg)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class MultipleDatabasesNotAllowedError(CompilationError):
|
|
18
|
+
def __init__(self, databases):
|
|
19
|
+
self.databases = databases
|
|
20
|
+
super().__init__(msg=self.get_message())
|
|
21
|
+
|
|
22
|
+
def get_message(self) -> str:
|
|
23
|
+
msg = str(self.databases)
|
|
24
|
+
return msg
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ApproximateMatchError(CompilationError):
|
|
28
|
+
def __init__(self, target, relation):
|
|
29
|
+
self.target = target
|
|
30
|
+
self.relation = relation
|
|
31
|
+
super().__init__(msg=self.get_message())
|
|
32
|
+
|
|
33
|
+
def get_message(self) -> str:
|
|
34
|
+
msg = (
|
|
35
|
+
"When searching for a relation, dbt found an approximate match. "
|
|
36
|
+
"Instead of guessing \nwhich relation to use, dbt will move on. "
|
|
37
|
+
f"Please delete {self.relation}, or rename it to be less ambiguous."
|
|
38
|
+
f"\nSearched for: {self.target}\nFound: {self.relation}"
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
return msg
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class SnapshotTargetIncompleteError(CompilationError):
|
|
45
|
+
def __init__(self, extra: List, missing: List):
|
|
46
|
+
self.extra = extra
|
|
47
|
+
self.missing = missing
|
|
48
|
+
super().__init__(msg=self.get_message())
|
|
49
|
+
|
|
50
|
+
def get_message(self) -> str:
|
|
51
|
+
msg = (
|
|
52
|
+
'Snapshot target has ("{}") but not ("{}") - is it an '
|
|
53
|
+
"unmigrated previous version archive?".format(
|
|
54
|
+
'", "'.join(self.extra), '", "'.join(self.missing)
|
|
55
|
+
)
|
|
56
|
+
)
|
|
57
|
+
return msg
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class DuplicateMacroInPackageError(CompilationError):
|
|
61
|
+
def __init__(self, macro, macro_mapping: Mapping):
|
|
62
|
+
self.macro = macro
|
|
63
|
+
self.macro_mapping = macro_mapping
|
|
64
|
+
super().__init__(msg=self.get_message())
|
|
65
|
+
|
|
66
|
+
def get_message(self) -> str:
|
|
67
|
+
other_path = self.macro_mapping[self.macro.unique_id].original_file_path
|
|
68
|
+
# subtract 2 for the "Compilation Error" indent
|
|
69
|
+
# note that the line wrap eats newlines, so if you want newlines,
|
|
70
|
+
# this is the result :(
|
|
71
|
+
msg = line_wrap_message(
|
|
72
|
+
f"""\
|
|
73
|
+
dbt found two macros named "{self.macro.name}" in the project
|
|
74
|
+
"{self.macro.package_name}".
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
To fix this error, rename or remove one of the following
|
|
78
|
+
macros:
|
|
79
|
+
|
|
80
|
+
- {self.macro.original_file_path}
|
|
81
|
+
|
|
82
|
+
- {other_path}
|
|
83
|
+
""",
|
|
84
|
+
subtract=2,
|
|
85
|
+
)
|
|
86
|
+
return msg
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class DuplicateMaterializationNameError(CompilationError):
|
|
90
|
+
def __init__(self, macro, other_macro):
|
|
91
|
+
self.macro = macro
|
|
92
|
+
self.other_macro = other_macro
|
|
93
|
+
super().__init__(msg=self.get_message())
|
|
94
|
+
|
|
95
|
+
def get_message(self) -> str:
|
|
96
|
+
macro_name = self.macro.name
|
|
97
|
+
macro_package_name = self.macro.package_name
|
|
98
|
+
other_package_name = self.other_macro.macro.package_name
|
|
99
|
+
|
|
100
|
+
msg = (
|
|
101
|
+
f"Found two materializations with the name {macro_name} (packages "
|
|
102
|
+
f"{macro_package_name} and {other_package_name}). dbt cannot resolve "
|
|
103
|
+
"this ambiguity"
|
|
104
|
+
)
|
|
105
|
+
return msg
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class ColumnTypeMissingError(CompilationError):
|
|
109
|
+
def __init__(self, column_names: List):
|
|
110
|
+
self.column_names = column_names
|
|
111
|
+
super().__init__(msg=self.get_message())
|
|
112
|
+
|
|
113
|
+
def get_message(self) -> str:
|
|
114
|
+
msg = (
|
|
115
|
+
"Contracted models require data_type to be defined for each column. "
|
|
116
|
+
"Please ensure that the column name and data_type are defined within "
|
|
117
|
+
f"the YAML configuration for the {self.column_names} column(s)."
|
|
118
|
+
)
|
|
119
|
+
return msg
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class MacroNotFoundError(CompilationError):
|
|
123
|
+
def __init__(self, node, target_macro_id: str):
|
|
124
|
+
self.node = node
|
|
125
|
+
self.target_macro_id = target_macro_id
|
|
126
|
+
msg = f"'{self.node.unique_id}' references macro '{self.target_macro_id}' which is not defined!"
|
|
127
|
+
|
|
128
|
+
super().__init__(msg=msg)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class MissingMaterializationError(CompilationError):
|
|
132
|
+
def __init__(self, materialization, adapter_type):
|
|
133
|
+
self.materialization = materialization
|
|
134
|
+
self.adapter_type = adapter_type
|
|
135
|
+
super().__init__(msg=self.get_message())
|
|
136
|
+
|
|
137
|
+
def get_message(self) -> str:
|
|
138
|
+
valid_types = "'default'"
|
|
139
|
+
|
|
140
|
+
if self.adapter_type != "default":
|
|
141
|
+
valid_types = f"'default' and '{self.adapter_type}'"
|
|
142
|
+
|
|
143
|
+
msg = f"No materialization '{self.materialization}' was found for adapter {self.adapter_type}! (searched types {valid_types})"
|
|
144
|
+
return msg
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class SnapshotTargetNotSnapshotTableError(CompilationError):
|
|
148
|
+
def __init__(self, missing: List):
|
|
149
|
+
self.missing = missing
|
|
150
|
+
super().__init__(msg=self.get_message())
|
|
151
|
+
|
|
152
|
+
def get_message(self) -> str:
|
|
153
|
+
missing = '", "'.join(self.missing)
|
|
154
|
+
msg = (
|
|
155
|
+
f'Snapshot target is missing configured columns (missing "{missing}"). '
|
|
156
|
+
"See https://docs.getdbt.com/docs/build/snapshots#snapshot-meta-fields for more information."
|
|
157
|
+
)
|
|
158
|
+
return msg
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class NullRelationDropAttemptedError(CompilationError):
|
|
162
|
+
def __init__(self, name: str):
|
|
163
|
+
self.name = name
|
|
164
|
+
self.msg = f"Attempted to drop a null relation for {self.name}"
|
|
165
|
+
super().__init__(msg=self.msg)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
class NullRelationCacheAttemptedError(CompilationError):
|
|
169
|
+
def __init__(self, name: str):
|
|
170
|
+
self.name = name
|
|
171
|
+
self.msg = f"Attempted to cache a null relation for {self.name}"
|
|
172
|
+
super().__init__(msg=self.msg)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
class RelationTypeNullError(CompilationError):
|
|
176
|
+
def __init__(self, relation):
|
|
177
|
+
self.relation = relation
|
|
178
|
+
self.msg = f"Tried to drop relation {self.relation}, but its type is null."
|
|
179
|
+
super().__init__(msg=self.msg)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
class MaterializationNotAvailableError(CompilationError):
|
|
183
|
+
def __init__(self, materialization, adapter_type: str):
|
|
184
|
+
self.materialization = materialization
|
|
185
|
+
self.adapter_type = adapter_type
|
|
186
|
+
super().__init__(msg=self.get_message())
|
|
187
|
+
|
|
188
|
+
def get_message(self) -> str:
|
|
189
|
+
msg = f"Materialization '{self.materialization}' is not available for {self.adapter_type}!"
|
|
190
|
+
return msg
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
class RelationReturnedMultipleResultsError(CompilationError):
|
|
194
|
+
def __init__(self, kwargs: Mapping[str, Any], matches: List):
|
|
195
|
+
self.kwargs = kwargs
|
|
196
|
+
self.matches = matches
|
|
197
|
+
super().__init__(msg=self.get_message())
|
|
198
|
+
|
|
199
|
+
def get_message(self) -> str:
|
|
200
|
+
msg = (
|
|
201
|
+
"get_relation returned more than one relation with the given args. "
|
|
202
|
+
"Please specify a database or schema to narrow down the result set."
|
|
203
|
+
f"\n{self.kwargs}\n\n{self.matches}"
|
|
204
|
+
)
|
|
205
|
+
return msg
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
class UnexpectedNonTimestampError(DbtDatabaseError):
|
|
209
|
+
def __init__(self, field_name: str, source, dt: Any):
|
|
210
|
+
self.field_name = field_name
|
|
211
|
+
self.source = source
|
|
212
|
+
self.type_name = type(dt).__name__
|
|
213
|
+
msg = (
|
|
214
|
+
f"Expected a timestamp value when querying field '{self.field_name}' of table "
|
|
215
|
+
f"{self.source} but received value of type '{self.type_name}' instead"
|
|
216
|
+
)
|
|
217
|
+
super().__init__(msg)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
class RenameToNoneAttemptedError(CompilationError):
|
|
221
|
+
def __init__(self, src_name: str, dst_name: str, name: str):
|
|
222
|
+
self.src_name = src_name
|
|
223
|
+
self.dst_name = dst_name
|
|
224
|
+
self.name = name
|
|
225
|
+
self.msg = f"Attempted to rename {self.src_name} to {self.dst_name} for {self.name}"
|
|
226
|
+
super().__init__(msg=self.msg)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
class QuoteConfigTypeError(CompilationError):
|
|
230
|
+
def __init__(self, quote_config: Any):
|
|
231
|
+
self.quote_config = quote_config
|
|
232
|
+
super().__init__(msg=self.get_message())
|
|
233
|
+
|
|
234
|
+
def get_message(self) -> str:
|
|
235
|
+
msg = (
|
|
236
|
+
'The seed configuration value of "quote_columns" has an '
|
|
237
|
+
f"invalid type {type(self.quote_config)}"
|
|
238
|
+
)
|
|
239
|
+
return msg
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
class RelationWrongTypeError(CompilationError):
|
|
243
|
+
def __init__(self, relation, expected_type, model=None):
|
|
244
|
+
self.relation = relation
|
|
245
|
+
self.expected_type = expected_type
|
|
246
|
+
self.model = model
|
|
247
|
+
super().__init__(msg=self.get_message())
|
|
248
|
+
|
|
249
|
+
def get_message(self) -> str:
|
|
250
|
+
msg = (
|
|
251
|
+
f"Trying to create {self.expected_type} {self.relation}, "
|
|
252
|
+
f"but it currently exists as a {self.relation.type}. Either "
|
|
253
|
+
f"drop {self.relation} manually, or run dbt with "
|
|
254
|
+
"`--full-refresh` and dbt will drop it for you."
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
return msg
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
class InvalidRelationConfigError(CompilationError):
|
|
261
|
+
def __init__(self, relation, config, msg):
|
|
262
|
+
self.relation = relation
|
|
263
|
+
self.config = config
|
|
264
|
+
self.msg = msg
|
|
265
|
+
super().__init__(msg=self.get_message())
|
|
266
|
+
|
|
267
|
+
def get_message(self) -> str:
|
|
268
|
+
msg = f"Invalid relation config: {self.config}"
|
|
269
|
+
return msg
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
from dbt_common.exceptions import DbtDatabaseError, DbtRuntimeError
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class InvalidConnectionError(DbtRuntimeError):
|
|
7
|
+
def __init__(self, thread_id, known: List) -> None:
|
|
8
|
+
self.thread_id = thread_id
|
|
9
|
+
self.known = known
|
|
10
|
+
super().__init__(
|
|
11
|
+
msg=f"connection never acquired for thread {self.thread_id}, have {self.known}"
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class FailedToConnectError(DbtDatabaseError):
|
|
16
|
+
pass
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from dbt_common.exceptions import CompilationError, NotImplementedError
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class UnexpectedDbReferenceError(NotImplementedError):
|
|
7
|
+
def __init__(self, adapter, database, expected):
|
|
8
|
+
self.adapter = adapter
|
|
9
|
+
self.database = database
|
|
10
|
+
self.expected = expected
|
|
11
|
+
super().__init__(msg=self.get_message())
|
|
12
|
+
|
|
13
|
+
def get_message(self) -> str:
|
|
14
|
+
msg = f"Cross-db references not allowed in {self.adapter} ({self.database} vs {self.expected})"
|
|
15
|
+
return msg
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class CrossDbReferenceProhibitedError(CompilationError):
|
|
19
|
+
def __init__(self, adapter, exc_msg: str):
|
|
20
|
+
self.adapter = adapter
|
|
21
|
+
self.exc_msg = exc_msg
|
|
22
|
+
super().__init__(msg=self.get_message())
|
|
23
|
+
|
|
24
|
+
def get_message(self) -> str:
|
|
25
|
+
msg = f"Cross-db references not allowed in adapter {self.adapter}: Got {self.exc_msg}"
|
|
26
|
+
return msg
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class IndexConfigNotDictError(CompilationError):
|
|
30
|
+
def __init__(self, raw_index: Any):
|
|
31
|
+
self.raw_index = raw_index
|
|
32
|
+
super().__init__(msg=self.get_message())
|
|
33
|
+
|
|
34
|
+
def get_message(self) -> str:
|
|
35
|
+
msg = (
|
|
36
|
+
f"Invalid index config:\n"
|
|
37
|
+
f" Got: {self.raw_index}\n"
|
|
38
|
+
f' Expected a dictionary with at minimum a "columns" key'
|
|
39
|
+
)
|
|
40
|
+
return msg
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class IndexConfigError(CompilationError):
|
|
44
|
+
def __init__(self, exc: TypeError):
|
|
45
|
+
self.exc = exc
|
|
46
|
+
super().__init__(msg=self.get_message())
|
|
47
|
+
|
|
48
|
+
def get_message(self) -> str:
|
|
49
|
+
validator_msg = self.validator_error_message(self.exc)
|
|
50
|
+
msg = f"Could not parse index config: {validator_msg}"
|
|
51
|
+
return msg
|
dbt/adapters/factory.py
ADDED
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
from contextlib import contextmanager
|
|
2
|
+
from importlib import import_module
|
|
3
|
+
from multiprocessing.context import SpawnContext
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
import threading
|
|
6
|
+
import traceback
|
|
7
|
+
from typing import Any, Dict, List, Optional, Set, Type
|
|
8
|
+
|
|
9
|
+
from dbt_common.events.functions import fire_event
|
|
10
|
+
from dbt_common.events.base_types import EventLevel
|
|
11
|
+
from dbt_common.exceptions import DbtInternalError, DbtRuntimeError
|
|
12
|
+
from dbt_common.semver import VersionSpecifier
|
|
13
|
+
|
|
14
|
+
from dbt.adapters.base.plugin import AdapterPlugin
|
|
15
|
+
from dbt.adapters.contracts.connection import AdapterRequiredConfig, Credentials
|
|
16
|
+
from dbt.adapters.events.types import (
|
|
17
|
+
AdapterImportError,
|
|
18
|
+
PluginLoadError,
|
|
19
|
+
AdapterRegistered,
|
|
20
|
+
)
|
|
21
|
+
from dbt.include.global_project import (
|
|
22
|
+
PACKAGE_PATH as GLOBAL_PROJECT_PATH,
|
|
23
|
+
PROJECT_NAME as GLOBAL_PROJECT_NAME,
|
|
24
|
+
)
|
|
25
|
+
from dbt.adapters.protocol import AdapterConfig, AdapterProtocol, RelationProtocol
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
Adapter = AdapterProtocol
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class AdapterContainer:
|
|
32
|
+
def __init__(self) -> None:
|
|
33
|
+
self.lock = threading.Lock()
|
|
34
|
+
self.adapters: Dict[str, Adapter] = {}
|
|
35
|
+
self.plugins: Dict[str, AdapterPlugin] = {}
|
|
36
|
+
# map package names to their include paths
|
|
37
|
+
self.packages: Dict[str, Path] = {
|
|
38
|
+
GLOBAL_PROJECT_NAME: Path(GLOBAL_PROJECT_PATH),
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
def get_plugin_by_name(self, name: str) -> AdapterPlugin:
|
|
42
|
+
with self.lock:
|
|
43
|
+
if name in self.plugins:
|
|
44
|
+
return self.plugins[name]
|
|
45
|
+
names = ", ".join(self.plugins.keys())
|
|
46
|
+
|
|
47
|
+
message = f"Invalid adapter type {name}! Must be one of {names}"
|
|
48
|
+
raise DbtRuntimeError(message)
|
|
49
|
+
|
|
50
|
+
def get_adapter_class_by_name(self, name: str) -> Type[Adapter]:
|
|
51
|
+
plugin = self.get_plugin_by_name(name)
|
|
52
|
+
return plugin.adapter
|
|
53
|
+
|
|
54
|
+
def get_relation_class_by_name(self, name: str) -> Type[RelationProtocol]:
|
|
55
|
+
adapter = self.get_adapter_class_by_name(name)
|
|
56
|
+
return adapter.Relation
|
|
57
|
+
|
|
58
|
+
def get_config_class_by_name(self, name: str) -> Type[AdapterConfig]:
|
|
59
|
+
adapter = self.get_adapter_class_by_name(name)
|
|
60
|
+
return adapter.AdapterSpecificConfigs
|
|
61
|
+
|
|
62
|
+
def load_plugin(self, name: str) -> Type[Credentials]:
|
|
63
|
+
# this doesn't need a lock: in the worst case we'll overwrite packages
|
|
64
|
+
# and adapter_type entries with the same value, as they're all
|
|
65
|
+
# singletons
|
|
66
|
+
try:
|
|
67
|
+
# mypy doesn't think modules have any attributes.
|
|
68
|
+
mod: Any = import_module("." + name, "dbt.adapters")
|
|
69
|
+
except ModuleNotFoundError as exc:
|
|
70
|
+
# if we failed to import the target module in particular, inform
|
|
71
|
+
# the user about it via a runtime error
|
|
72
|
+
if exc.name == "dbt.adapters." + name:
|
|
73
|
+
fire_event(AdapterImportError(exc=str(exc)))
|
|
74
|
+
raise DbtRuntimeError(f"Could not find adapter type {name}!")
|
|
75
|
+
# otherwise, the error had to have come from some underlying
|
|
76
|
+
# library. Log the stack trace.
|
|
77
|
+
|
|
78
|
+
fire_event(PluginLoadError(exc_info=traceback.format_exc()))
|
|
79
|
+
raise
|
|
80
|
+
plugin: AdapterPlugin = mod.Plugin
|
|
81
|
+
plugin_type = plugin.adapter.type()
|
|
82
|
+
|
|
83
|
+
if plugin_type != name:
|
|
84
|
+
raise DbtRuntimeError(
|
|
85
|
+
f"Expected to find adapter with type named {name}, got "
|
|
86
|
+
f"adapter with type {plugin_type}"
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
with self.lock:
|
|
90
|
+
# things do hold the lock to iterate over it so we need it to add
|
|
91
|
+
self.plugins[name] = plugin
|
|
92
|
+
|
|
93
|
+
self.packages[plugin.project_name] = Path(plugin.include_path)
|
|
94
|
+
|
|
95
|
+
for dep in plugin.dependencies:
|
|
96
|
+
self.load_plugin(dep)
|
|
97
|
+
|
|
98
|
+
return plugin.credentials
|
|
99
|
+
|
|
100
|
+
def register_adapter(
|
|
101
|
+
self,
|
|
102
|
+
config: AdapterRequiredConfig,
|
|
103
|
+
mp_context: SpawnContext,
|
|
104
|
+
adapter_registered_log_level: Optional[EventLevel] = EventLevel.INFO,
|
|
105
|
+
) -> None:
|
|
106
|
+
adapter_name = config.credentials.type
|
|
107
|
+
adapter_type = self.get_adapter_class_by_name(adapter_name)
|
|
108
|
+
adapter_version = self._adapter_version(adapter_name)
|
|
109
|
+
fire_event(
|
|
110
|
+
AdapterRegistered(adapter_name=adapter_name, adapter_version=adapter_version),
|
|
111
|
+
level=adapter_registered_log_level,
|
|
112
|
+
)
|
|
113
|
+
with self.lock:
|
|
114
|
+
if adapter_name in self.adapters:
|
|
115
|
+
# this shouldn't really happen...
|
|
116
|
+
return
|
|
117
|
+
|
|
118
|
+
adapter: Adapter = adapter_type(config, mp_context) # type: ignore
|
|
119
|
+
self.adapters[adapter_name] = adapter
|
|
120
|
+
|
|
121
|
+
def _adapter_version(self, adapter_name: str) -> str:
|
|
122
|
+
try:
|
|
123
|
+
raw_version = import_module(f".{adapter_name}.__about__", "dbt.adapters").version
|
|
124
|
+
except ModuleNotFoundError:
|
|
125
|
+
raw_version = import_module(f".{adapter_name}.__version__", "dbt.adapters").version
|
|
126
|
+
return self._validate_version(raw_version)
|
|
127
|
+
|
|
128
|
+
def _validate_version(self, raw_version: str) -> str:
|
|
129
|
+
return VersionSpecifier.from_version_string(raw_version).to_version_string()
|
|
130
|
+
|
|
131
|
+
def lookup_adapter(self, adapter_name: str) -> Adapter:
|
|
132
|
+
return self.adapters[adapter_name]
|
|
133
|
+
|
|
134
|
+
def reset_adapters(self):
|
|
135
|
+
"""Clear the adapters. This is useful for tests, which change configs."""
|
|
136
|
+
with self.lock:
|
|
137
|
+
for adapter in self.adapters.values():
|
|
138
|
+
adapter.cleanup_connections()
|
|
139
|
+
self.adapters.clear()
|
|
140
|
+
|
|
141
|
+
def cleanup_connections(self):
|
|
142
|
+
"""Only clean up the adapter connections list without resetting the
|
|
143
|
+
actual adapters.
|
|
144
|
+
"""
|
|
145
|
+
with self.lock:
|
|
146
|
+
for adapter in self.adapters.values():
|
|
147
|
+
adapter.cleanup_connections()
|
|
148
|
+
|
|
149
|
+
def get_adapter_plugins(self, name: Optional[str]) -> List[AdapterPlugin]:
|
|
150
|
+
"""Iterate over the known adapter plugins. If a name is provided,
|
|
151
|
+
iterate in dependency order over the named plugin and its dependencies.
|
|
152
|
+
"""
|
|
153
|
+
if name is None:
|
|
154
|
+
return list(self.plugins.values())
|
|
155
|
+
|
|
156
|
+
plugins: List[AdapterPlugin] = []
|
|
157
|
+
seen: Set[str] = set()
|
|
158
|
+
plugin_names: List[str] = [name]
|
|
159
|
+
while plugin_names:
|
|
160
|
+
plugin_name = plugin_names[0]
|
|
161
|
+
plugin_names = plugin_names[1:]
|
|
162
|
+
try:
|
|
163
|
+
plugin = self.plugins[plugin_name]
|
|
164
|
+
except KeyError:
|
|
165
|
+
raise DbtInternalError(f"No plugin found for {plugin_name}") from None
|
|
166
|
+
plugins.append(plugin)
|
|
167
|
+
seen.add(plugin_name)
|
|
168
|
+
for dep in plugin.dependencies:
|
|
169
|
+
if dep not in seen:
|
|
170
|
+
plugin_names.append(dep)
|
|
171
|
+
return plugins
|
|
172
|
+
|
|
173
|
+
def get_adapter_package_names(self, name: Optional[str]) -> List[str]:
|
|
174
|
+
package_names: List[str] = [p.project_name for p in self.get_adapter_plugins(name)]
|
|
175
|
+
package_names.append(GLOBAL_PROJECT_NAME)
|
|
176
|
+
return package_names
|
|
177
|
+
|
|
178
|
+
def get_include_paths(self, name: Optional[str]) -> List[Path]:
|
|
179
|
+
paths = []
|
|
180
|
+
for package_name in self.get_adapter_package_names(name):
|
|
181
|
+
try:
|
|
182
|
+
path = self.packages[package_name]
|
|
183
|
+
except KeyError:
|
|
184
|
+
raise DbtInternalError(f"No internal package listing found for {package_name}")
|
|
185
|
+
paths.append(path)
|
|
186
|
+
return paths
|
|
187
|
+
|
|
188
|
+
def get_adapter_type_names(self, name: Optional[str]) -> List[str]:
|
|
189
|
+
return [p.adapter.type() for p in self.get_adapter_plugins(name)]
|
|
190
|
+
|
|
191
|
+
def get_adapter_constraint_support(self, name: Optional[str]) -> Dict[str, str]:
|
|
192
|
+
return self.lookup_adapter(name).CONSTRAINT_SUPPORT # type: ignore
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
FACTORY: AdapterContainer = AdapterContainer()
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def register_adapter(
|
|
199
|
+
config: AdapterRequiredConfig,
|
|
200
|
+
mp_context: SpawnContext,
|
|
201
|
+
adapter_registered_log_level: Optional[EventLevel] = EventLevel.INFO,
|
|
202
|
+
) -> None:
|
|
203
|
+
FACTORY.register_adapter(config, mp_context, adapter_registered_log_level)
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def get_adapter(config: AdapterRequiredConfig):
|
|
207
|
+
return FACTORY.lookup_adapter(config.credentials.type)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def get_adapter_by_type(adapter_type):
|
|
211
|
+
return FACTORY.lookup_adapter(adapter_type)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def reset_adapters():
|
|
215
|
+
"""Clear the adapters. This is useful for tests, which change configs."""
|
|
216
|
+
FACTORY.reset_adapters()
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def cleanup_connections():
|
|
220
|
+
"""Only clean up the adapter connections list without resetting the actual
|
|
221
|
+
adapters.
|
|
222
|
+
"""
|
|
223
|
+
FACTORY.cleanup_connections()
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def get_adapter_class_by_name(name: str) -> Type[AdapterProtocol]:
|
|
227
|
+
return FACTORY.get_adapter_class_by_name(name)
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def get_config_class_by_name(name: str) -> Type[AdapterConfig]:
|
|
231
|
+
return FACTORY.get_config_class_by_name(name)
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def get_relation_class_by_name(name: str) -> Type[RelationProtocol]:
|
|
235
|
+
return FACTORY.get_relation_class_by_name(name)
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def load_plugin(name: str) -> Type[Credentials]:
|
|
239
|
+
return FACTORY.load_plugin(name)
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def get_include_paths(name: Optional[str]) -> List[Path]:
|
|
243
|
+
return FACTORY.get_include_paths(name)
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def get_adapter_package_names(name: Optional[str]) -> List[str]:
|
|
247
|
+
return FACTORY.get_adapter_package_names(name)
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def get_adapter_type_names(name: Optional[str]) -> List[str]:
|
|
251
|
+
return FACTORY.get_adapter_type_names(name)
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def get_adapter_constraint_support(name: Optional[str]) -> Dict[str, str]:
|
|
255
|
+
return FACTORY.get_adapter_constraint_support(name)
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
@contextmanager
|
|
259
|
+
def adapter_management():
|
|
260
|
+
reset_adapters()
|
|
261
|
+
try:
|
|
262
|
+
yield
|
|
263
|
+
finally:
|
|
264
|
+
cleanup_connections()
|