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.
Files changed (173) hide show
  1. dbt/adapters/__about__.py +1 -0
  2. dbt/adapters/__init__.py +8 -0
  3. dbt/adapters/base/README.md +13 -0
  4. dbt/adapters/base/__init__.py +16 -0
  5. dbt/adapters/base/column.py +173 -0
  6. dbt/adapters/base/connections.py +429 -0
  7. dbt/adapters/base/impl.py +2036 -0
  8. dbt/adapters/base/meta.py +150 -0
  9. dbt/adapters/base/plugin.py +32 -0
  10. dbt/adapters/base/query_headers.py +106 -0
  11. dbt/adapters/base/relation.py +648 -0
  12. dbt/adapters/cache.py +521 -0
  13. dbt/adapters/capability.py +63 -0
  14. dbt/adapters/catalogs/__init__.py +14 -0
  15. dbt/adapters/catalogs/_client.py +54 -0
  16. dbt/adapters/catalogs/_constants.py +1 -0
  17. dbt/adapters/catalogs/_exceptions.py +39 -0
  18. dbt/adapters/catalogs/_integration.py +113 -0
  19. dbt/adapters/clients/__init__.py +0 -0
  20. dbt/adapters/clients/jinja.py +24 -0
  21. dbt/adapters/contracts/__init__.py +0 -0
  22. dbt/adapters/contracts/connection.py +229 -0
  23. dbt/adapters/contracts/macros.py +11 -0
  24. dbt/adapters/contracts/relation.py +160 -0
  25. dbt/adapters/events/README.md +51 -0
  26. dbt/adapters/events/__init__.py +0 -0
  27. dbt/adapters/events/adapter_types_pb2.py +2 -0
  28. dbt/adapters/events/base_types.py +36 -0
  29. dbt/adapters/events/logging.py +83 -0
  30. dbt/adapters/events/types.py +436 -0
  31. dbt/adapters/exceptions/__init__.py +40 -0
  32. dbt/adapters/exceptions/alias.py +24 -0
  33. dbt/adapters/exceptions/cache.py +68 -0
  34. dbt/adapters/exceptions/compilation.py +269 -0
  35. dbt/adapters/exceptions/connection.py +16 -0
  36. dbt/adapters/exceptions/database.py +51 -0
  37. dbt/adapters/factory.py +264 -0
  38. dbt/adapters/protocol.py +150 -0
  39. dbt/adapters/py.typed +0 -0
  40. dbt/adapters/record/__init__.py +2 -0
  41. dbt/adapters/record/base.py +291 -0
  42. dbt/adapters/record/cursor/cursor.py +69 -0
  43. dbt/adapters/record/cursor/description.py +37 -0
  44. dbt/adapters/record/cursor/execute.py +39 -0
  45. dbt/adapters/record/cursor/fetchall.py +69 -0
  46. dbt/adapters/record/cursor/fetchmany.py +23 -0
  47. dbt/adapters/record/cursor/fetchone.py +23 -0
  48. dbt/adapters/record/cursor/rowcount.py +23 -0
  49. dbt/adapters/record/handle.py +55 -0
  50. dbt/adapters/record/serialization.py +115 -0
  51. dbt/adapters/reference_keys.py +39 -0
  52. dbt/adapters/relation_configs/README.md +25 -0
  53. dbt/adapters/relation_configs/__init__.py +12 -0
  54. dbt/adapters/relation_configs/config_base.py +46 -0
  55. dbt/adapters/relation_configs/config_change.py +26 -0
  56. dbt/adapters/relation_configs/config_validation.py +57 -0
  57. dbt/adapters/sql/__init__.py +2 -0
  58. dbt/adapters/sql/connections.py +263 -0
  59. dbt/adapters/sql/impl.py +286 -0
  60. dbt/adapters/utils.py +69 -0
  61. dbt/include/__init__.py +3 -0
  62. dbt/include/global_project/__init__.py +4 -0
  63. dbt/include/global_project/dbt_project.yml +7 -0
  64. dbt/include/global_project/docs/overview.md +43 -0
  65. dbt/include/global_project/macros/adapters/apply_grants.sql +167 -0
  66. dbt/include/global_project/macros/adapters/columns.sql +144 -0
  67. dbt/include/global_project/macros/adapters/freshness.sql +32 -0
  68. dbt/include/global_project/macros/adapters/indexes.sql +41 -0
  69. dbt/include/global_project/macros/adapters/metadata.sql +105 -0
  70. dbt/include/global_project/macros/adapters/persist_docs.sql +33 -0
  71. dbt/include/global_project/macros/adapters/relation.sql +84 -0
  72. dbt/include/global_project/macros/adapters/schema.sql +20 -0
  73. dbt/include/global_project/macros/adapters/show.sql +26 -0
  74. dbt/include/global_project/macros/adapters/timestamps.sql +52 -0
  75. dbt/include/global_project/macros/adapters/validate_sql.sql +10 -0
  76. dbt/include/global_project/macros/etc/datetime.sql +62 -0
  77. dbt/include/global_project/macros/etc/statement.sql +52 -0
  78. dbt/include/global_project/macros/generic_test_sql/accepted_values.sql +27 -0
  79. dbt/include/global_project/macros/generic_test_sql/not_null.sql +9 -0
  80. dbt/include/global_project/macros/generic_test_sql/relationships.sql +23 -0
  81. dbt/include/global_project/macros/generic_test_sql/unique.sql +12 -0
  82. dbt/include/global_project/macros/get_custom_name/get_custom_alias.sql +36 -0
  83. dbt/include/global_project/macros/get_custom_name/get_custom_database.sql +32 -0
  84. dbt/include/global_project/macros/get_custom_name/get_custom_schema.sql +60 -0
  85. dbt/include/global_project/macros/materializations/configs.sql +21 -0
  86. dbt/include/global_project/macros/materializations/functions/aggregate.sql +65 -0
  87. dbt/include/global_project/macros/materializations/functions/function.sql +20 -0
  88. dbt/include/global_project/macros/materializations/functions/helpers.sql +20 -0
  89. dbt/include/global_project/macros/materializations/functions/scalar.sql +69 -0
  90. dbt/include/global_project/macros/materializations/hooks.sql +35 -0
  91. dbt/include/global_project/macros/materializations/models/clone/can_clone_table.sql +7 -0
  92. dbt/include/global_project/macros/materializations/models/clone/clone.sql +67 -0
  93. dbt/include/global_project/macros/materializations/models/clone/create_or_replace_clone.sql +7 -0
  94. dbt/include/global_project/macros/materializations/models/incremental/column_helpers.sql +80 -0
  95. dbt/include/global_project/macros/materializations/models/incremental/incremental.sql +99 -0
  96. dbt/include/global_project/macros/materializations/models/incremental/is_incremental.sql +13 -0
  97. dbt/include/global_project/macros/materializations/models/incremental/merge.sql +120 -0
  98. dbt/include/global_project/macros/materializations/models/incremental/on_schema_change.sql +159 -0
  99. dbt/include/global_project/macros/materializations/models/incremental/strategies.sql +92 -0
  100. dbt/include/global_project/macros/materializations/models/materialized_view.sql +121 -0
  101. dbt/include/global_project/macros/materializations/models/table.sql +64 -0
  102. dbt/include/global_project/macros/materializations/models/view.sql +72 -0
  103. dbt/include/global_project/macros/materializations/seeds/helpers.sql +128 -0
  104. dbt/include/global_project/macros/materializations/seeds/seed.sql +60 -0
  105. dbt/include/global_project/macros/materializations/snapshots/helpers.sql +345 -0
  106. dbt/include/global_project/macros/materializations/snapshots/snapshot.sql +109 -0
  107. dbt/include/global_project/macros/materializations/snapshots/snapshot_merge.sql +34 -0
  108. dbt/include/global_project/macros/materializations/snapshots/strategies.sql +184 -0
  109. dbt/include/global_project/macros/materializations/tests/helpers.sql +44 -0
  110. dbt/include/global_project/macros/materializations/tests/test.sql +66 -0
  111. dbt/include/global_project/macros/materializations/tests/unit.sql +40 -0
  112. dbt/include/global_project/macros/materializations/tests/where_subquery.sql +15 -0
  113. dbt/include/global_project/macros/python_model/python.sql +114 -0
  114. dbt/include/global_project/macros/relations/column/columns_spec_ddl.sql +89 -0
  115. dbt/include/global_project/macros/relations/create.sql +23 -0
  116. dbt/include/global_project/macros/relations/create_backup.sql +17 -0
  117. dbt/include/global_project/macros/relations/create_intermediate.sql +17 -0
  118. dbt/include/global_project/macros/relations/drop.sql +41 -0
  119. dbt/include/global_project/macros/relations/drop_backup.sql +14 -0
  120. dbt/include/global_project/macros/relations/materialized_view/alter.sql +55 -0
  121. dbt/include/global_project/macros/relations/materialized_view/create.sql +10 -0
  122. dbt/include/global_project/macros/relations/materialized_view/drop.sql +14 -0
  123. dbt/include/global_project/macros/relations/materialized_view/refresh.sql +9 -0
  124. dbt/include/global_project/macros/relations/materialized_view/rename.sql +10 -0
  125. dbt/include/global_project/macros/relations/materialized_view/replace.sql +10 -0
  126. dbt/include/global_project/macros/relations/rename.sql +35 -0
  127. dbt/include/global_project/macros/relations/rename_intermediate.sql +14 -0
  128. dbt/include/global_project/macros/relations/replace.sql +50 -0
  129. dbt/include/global_project/macros/relations/schema.sql +8 -0
  130. dbt/include/global_project/macros/relations/table/create.sql +60 -0
  131. dbt/include/global_project/macros/relations/table/drop.sql +14 -0
  132. dbt/include/global_project/macros/relations/table/rename.sql +10 -0
  133. dbt/include/global_project/macros/relations/table/replace.sql +10 -0
  134. dbt/include/global_project/macros/relations/view/create.sql +27 -0
  135. dbt/include/global_project/macros/relations/view/drop.sql +14 -0
  136. dbt/include/global_project/macros/relations/view/rename.sql +10 -0
  137. dbt/include/global_project/macros/relations/view/replace.sql +66 -0
  138. dbt/include/global_project/macros/unit_test_sql/get_fixture_sql.sql +107 -0
  139. dbt/include/global_project/macros/utils/any_value.sql +9 -0
  140. dbt/include/global_project/macros/utils/array_append.sql +8 -0
  141. dbt/include/global_project/macros/utils/array_concat.sql +7 -0
  142. dbt/include/global_project/macros/utils/array_construct.sql +12 -0
  143. dbt/include/global_project/macros/utils/bool_or.sql +9 -0
  144. dbt/include/global_project/macros/utils/cast.sql +7 -0
  145. dbt/include/global_project/macros/utils/cast_bool_to_text.sql +7 -0
  146. dbt/include/global_project/macros/utils/concat.sql +7 -0
  147. dbt/include/global_project/macros/utils/data_types.sql +129 -0
  148. dbt/include/global_project/macros/utils/date.sql +10 -0
  149. dbt/include/global_project/macros/utils/date_spine.sql +75 -0
  150. dbt/include/global_project/macros/utils/date_trunc.sql +7 -0
  151. dbt/include/global_project/macros/utils/dateadd.sql +14 -0
  152. dbt/include/global_project/macros/utils/datediff.sql +14 -0
  153. dbt/include/global_project/macros/utils/equals.sql +14 -0
  154. dbt/include/global_project/macros/utils/escape_single_quotes.sql +8 -0
  155. dbt/include/global_project/macros/utils/except.sql +9 -0
  156. dbt/include/global_project/macros/utils/generate_series.sql +53 -0
  157. dbt/include/global_project/macros/utils/hash.sql +7 -0
  158. dbt/include/global_project/macros/utils/intersect.sql +9 -0
  159. dbt/include/global_project/macros/utils/last_day.sql +15 -0
  160. dbt/include/global_project/macros/utils/length.sql +11 -0
  161. dbt/include/global_project/macros/utils/listagg.sql +30 -0
  162. dbt/include/global_project/macros/utils/literal.sql +7 -0
  163. dbt/include/global_project/macros/utils/position.sql +11 -0
  164. dbt/include/global_project/macros/utils/replace.sql +14 -0
  165. dbt/include/global_project/macros/utils/right.sql +12 -0
  166. dbt/include/global_project/macros/utils/safe_cast.sql +9 -0
  167. dbt/include/global_project/macros/utils/split_part.sql +26 -0
  168. dbt/include/global_project/tests/generic/builtin.sql +30 -0
  169. dbt/include/py.typed +0 -0
  170. dbt_adapters-1.22.2.dist-info/METADATA +124 -0
  171. dbt_adapters-1.22.2.dist-info/RECORD +173 -0
  172. dbt_adapters-1.22.2.dist-info/WHEEL +4 -0
  173. dbt_adapters-1.22.2.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,150 @@
1
+ from dataclasses import dataclass
2
+ from typing import (
3
+ Any,
4
+ ContextManager,
5
+ Dict,
6
+ Generic,
7
+ Hashable,
8
+ List,
9
+ Optional,
10
+ Type,
11
+ TypeVar,
12
+ Tuple,
13
+ TYPE_CHECKING,
14
+ )
15
+ from typing_extensions import Protocol
16
+
17
+ from dbt_common.clients.jinja import MacroProtocol
18
+ from dbt_common.contracts.config.base import BaseConfig
19
+
20
+ from dbt.adapters.contracts.connection import (
21
+ AdapterRequiredConfig,
22
+ AdapterResponse,
23
+ Connection,
24
+ )
25
+ from dbt.adapters.contracts.macros import MacroResolverProtocol
26
+ from dbt.adapters.contracts.relation import HasQuoting, Policy, RelationConfig
27
+
28
+ if TYPE_CHECKING:
29
+ import agate
30
+
31
+
32
+ @dataclass
33
+ class AdapterConfig(BaseConfig):
34
+ pass
35
+
36
+
37
+ class ConnectionManagerProtocol(Protocol):
38
+ TYPE: str
39
+
40
+
41
+ class ColumnProtocol(Protocol):
42
+ pass
43
+
44
+
45
+ Self = TypeVar("Self", bound="RelationProtocol")
46
+
47
+
48
+ class RelationProtocol(Protocol):
49
+ @classmethod
50
+ def get_default_quote_policy(cls) -> Policy: ...
51
+
52
+ @classmethod
53
+ def create_from(
54
+ cls: Type[Self],
55
+ quoting: HasQuoting,
56
+ relation_config: RelationConfig,
57
+ **kwargs: Any,
58
+ ) -> Self: ...
59
+
60
+
61
+ AdapterConfig_T = TypeVar("AdapterConfig_T", bound=AdapterConfig)
62
+ ConnectionManager_T = TypeVar("ConnectionManager_T", bound=ConnectionManagerProtocol)
63
+ Relation_T = TypeVar("Relation_T", bound=RelationProtocol)
64
+ Column_T = TypeVar("Column_T", bound=ColumnProtocol)
65
+
66
+
67
+ class MacroContextGeneratorCallable(Protocol):
68
+ def __call__(
69
+ self,
70
+ macro_protocol: MacroProtocol,
71
+ config: AdapterRequiredConfig,
72
+ macro_resolver: MacroResolverProtocol,
73
+ package_name: Optional[str],
74
+ ) -> Dict[str, Any]: ...
75
+
76
+
77
+ # TODO CT-211
78
+ class AdapterProtocol(
79
+ Protocol,
80
+ Generic[
81
+ AdapterConfig_T,
82
+ ConnectionManager_T,
83
+ Relation_T,
84
+ Column_T,
85
+ ],
86
+ ):
87
+ # N.B. Technically these are ClassVars, but mypy doesn't support putting type vars in a
88
+ # ClassVar due to the restrictiveness of PEP-526
89
+ # See: https://github.com/python/mypy/issues/5144
90
+ AdapterSpecificConfigs: Type[AdapterConfig_T]
91
+ Column: Type[Column_T]
92
+ Relation: Type[Relation_T]
93
+ ConnectionManager: Type[ConnectionManager_T]
94
+ connections: ConnectionManager_T
95
+
96
+ def __init__(self, config: AdapterRequiredConfig) -> None: ...
97
+
98
+ def set_macro_resolver(self, macro_resolver: MacroResolverProtocol) -> None: ...
99
+
100
+ def get_macro_resolver(self) -> Optional[MacroResolverProtocol]: ...
101
+
102
+ def clear_macro_resolver(self) -> None: ...
103
+
104
+ def set_macro_context_generator(
105
+ self,
106
+ macro_context_generator: MacroContextGeneratorCallable,
107
+ ) -> None: ...
108
+
109
+ @classmethod
110
+ def type(cls) -> str:
111
+ pass
112
+
113
+ def set_query_header(self, query_header_context: Dict[str, Any]) -> None: ...
114
+
115
+ @staticmethod
116
+ def get_thread_identifier() -> Hashable: ...
117
+
118
+ def get_thread_connection(self) -> Connection: ...
119
+
120
+ def set_thread_connection(self, conn: Connection) -> None: ...
121
+
122
+ def get_if_exists(self) -> Optional[Connection]: ...
123
+
124
+ def clear_thread_connection(self) -> None: ...
125
+
126
+ def clear_transaction(self) -> None: ...
127
+
128
+ def exception_handler(self, sql: str) -> ContextManager: ...
129
+
130
+ def set_connection_name(self, name: Optional[str] = None) -> Connection: ...
131
+
132
+ def cancel_open(self) -> Optional[List[str]]: ...
133
+
134
+ def open(cls, connection: Connection) -> Connection: ...
135
+
136
+ def release(self) -> None: ...
137
+
138
+ def cleanup_all(self) -> None: ...
139
+
140
+ def begin(self) -> None: ...
141
+
142
+ def commit(self) -> None: ...
143
+
144
+ def close(cls, connection: Connection) -> Connection: ...
145
+
146
+ def commit_if_has_connection(self) -> None: ...
147
+
148
+ def execute(
149
+ self, sql: str, auto_begin: bool = False, fetch: bool = False
150
+ ) -> Tuple[AdapterResponse, "agate.Table"]: ...
dbt/adapters/py.typed ADDED
File without changes
@@ -0,0 +1,2 @@
1
+ from dbt.adapters.record.handle import RecordReplayHandle
2
+ from dbt.adapters.record.cursor.cursor import RecordReplayCursor
@@ -0,0 +1,291 @@
1
+ """Implementations of record/replay classes for the base adapter implementation."""
2
+
3
+ import dataclasses
4
+
5
+ from typing import Optional, Tuple, Dict, Any, TYPE_CHECKING, List
6
+
7
+ from dbt.adapters.contracts.connection import AdapterResponse
8
+ from dbt.adapters.record.serialization import serialize_agate_table, serialize_bindings
9
+ from dbt_common.record import Record, Recorder
10
+
11
+ if TYPE_CHECKING:
12
+ from agate import Table
13
+ from dbt.adapters.base.relation import BaseRelation
14
+ from dbt.adapters.base.column import Column as BaseColumn
15
+
16
+
17
+ @dataclasses.dataclass
18
+ class AdapterExecuteParams:
19
+ thread_id: str
20
+ sql: str
21
+ auto_begin: bool = False
22
+ fetch: bool = False
23
+ limit: Optional[int] = None
24
+
25
+
26
+ @dataclasses.dataclass
27
+ class AdapterExecuteResult:
28
+ return_val: Tuple[AdapterResponse, "Table"]
29
+
30
+ def _to_dict(self):
31
+ adapter_response = self.return_val[0]
32
+ table = self.return_val[1]
33
+ return {
34
+ "return_val": {
35
+ "adapter_response": adapter_response.to_dict(),
36
+ "table": serialize_agate_table(table),
37
+ }
38
+ }
39
+
40
+ def _from_dict(self, data: Dict[str, Any]):
41
+ # We will need this for replay, but it is not a priority at time of writing.
42
+ raise NotImplementedError()
43
+
44
+
45
+ @Recorder.register_record_type
46
+ class AdapterExecuteRecord(Record):
47
+ """Implements record/replay support for the BaseAdapter.execute() method."""
48
+
49
+ params_cls = AdapterExecuteParams
50
+ result_cls = AdapterExecuteResult
51
+ group = "Available"
52
+
53
+
54
+ @dataclasses.dataclass
55
+ class AdapterTestSqlResult:
56
+ return_val: str
57
+
58
+
59
+ @dataclasses.dataclass
60
+ class AdapterTestSqlParams:
61
+ thread_id: str
62
+ sql: str
63
+ fetch: str
64
+ conn: Any
65
+
66
+ def _to_dict(self):
67
+ return {
68
+ "thread_id": self.thread_id,
69
+ "sql": self.sql,
70
+ "fetch": self.fetch,
71
+ "conn": "conn",
72
+ }
73
+
74
+
75
+ @Recorder.register_record_type
76
+ class AdapterTestSqlRecord(Record):
77
+ """Implements record/replay support for the BaseAdapter.execute() method."""
78
+
79
+ params_cls = AdapterTestSqlParams
80
+ result_cls = AdapterTestSqlResult
81
+ group = "Available"
82
+
83
+
84
+ @dataclasses.dataclass
85
+ class AdapterGetPartitionsMetadataParams:
86
+ thread_id: str
87
+ table: str
88
+
89
+
90
+ @dataclasses.dataclass
91
+ class AdapterGetPartitionsMetadataResult:
92
+ return_val: tuple["Table"]
93
+
94
+ def _to_dict(self):
95
+ return list(map(serialize_agate_table, self.return_val))
96
+
97
+ def _from_dict(self, data: Dict[str, Any]):
98
+ # We will need this for replay, but it is not a priority at time of writing.
99
+ raise NotImplementedError()
100
+
101
+
102
+ @Recorder.register_record_type
103
+ class AdapterGetPartitionsMetadataRecord(Record):
104
+ """Implements record/replay support for the BaseAdapter.get_partitions_metadata() method."""
105
+
106
+ params_cls = AdapterGetPartitionsMetadataParams
107
+ result_cls = AdapterGetPartitionsMetadataResult
108
+ group = "Available"
109
+
110
+
111
+ @dataclasses.dataclass
112
+ class AdapterConvertTypeParams:
113
+ thread_id: str
114
+ table: "Table"
115
+ col_idx: int
116
+
117
+ def _to_dict(self):
118
+ return {
119
+ "thread_id": self.thread_id,
120
+ "table": serialize_agate_table(self.table),
121
+ "col_idx": self.col_idx,
122
+ }
123
+
124
+ def _from_dict(self, data: Dict[str, Any]):
125
+ # We will need this for replay, but it is not a priority at time of writing.
126
+ raise NotImplementedError()
127
+
128
+
129
+ @dataclasses.dataclass
130
+ class AdapterConvertTypeResult:
131
+ return_val: Optional[str]
132
+
133
+
134
+ @Recorder.register_record_type
135
+ class AdapterConvertTypeRecord(Record):
136
+ """Implements record/replay support for the BaseAdapter.convert_type() method."""
137
+
138
+ params_cls = AdapterConvertTypeParams
139
+ result_cls = AdapterConvertTypeResult
140
+ group = "Available"
141
+
142
+
143
+ @dataclasses.dataclass
144
+ class AdapterStandardizeGrantsDictParams:
145
+ thread_id: str
146
+ table: "Table"
147
+
148
+ def _to_dict(self):
149
+ return {"thread_id": self.thread_id, "table": serialize_agate_table(self.table)}
150
+
151
+ def _from_dict(self, data: Dict[str, Any]):
152
+ # We will need this for replay, but it is not a priority at time of writing.
153
+ raise NotImplementedError()
154
+
155
+
156
+ @dataclasses.dataclass
157
+ class AdapterStandardizeGrantsDictResult:
158
+ return_val: dict
159
+
160
+
161
+ @Recorder.register_record_type
162
+ class AdapterStandardizeGrantsDictRecord(Record):
163
+ params_cls = AdapterStandardizeGrantsDictParams
164
+ result_cls = AdapterStandardizeGrantsDictResult
165
+ group = "Available"
166
+
167
+
168
+ @dataclasses.dataclass
169
+ class AdapterAddQueryParams:
170
+ thread_id: str
171
+ sql: str
172
+ auto_begin: bool = True
173
+ bindings: Optional[Any] = None
174
+ abridge_sql_log: bool = False
175
+
176
+ def _to_dict(self):
177
+ return {
178
+ "thread_id": self.thread_id,
179
+ "sql": self.sql,
180
+ "auto_begin": self.auto_begin,
181
+ "bindings": serialize_bindings(self.bindings),
182
+ "abridge_sql_log": self.abridge_sql_log,
183
+ }
184
+
185
+
186
+ @dataclasses.dataclass
187
+ class AdapterAddQueryResult:
188
+ return_val: Tuple[str, str]
189
+
190
+ def _to_dict(self):
191
+ return {
192
+ "return_val": {
193
+ "conn": "conn",
194
+ "cursor": "cursor",
195
+ }
196
+ }
197
+
198
+
199
+ @Recorder.register_record_type
200
+ class AdapterAddQueryRecord(Record):
201
+ params_cls = AdapterAddQueryParams
202
+ result_cls = AdapterAddQueryResult
203
+ group = "Available"
204
+
205
+
206
+ @dataclasses.dataclass
207
+ class AdapterListRelationsWithoutCachingParams:
208
+ thread_id: str
209
+ schema_relation: "BaseRelation"
210
+
211
+ def _to_dict(self):
212
+ from dbt.adapters.record.serialization import serialize_base_relation
213
+
214
+ return {
215
+ "thread_id": self.thread_id,
216
+ "schema_relation": serialize_base_relation(self.schema_relation),
217
+ }
218
+
219
+ def _from_dict(self, data: Dict[str, Any]):
220
+ from dbt.adapters.record.serialization import deserialize_base_relation
221
+
222
+ self.thread_id = data["thread_id"]
223
+ self.schema_relation = deserialize_base_relation(data["schema_relation"])
224
+
225
+
226
+ @dataclasses.dataclass
227
+ class AdapterListRelationsWithoutCachingResult:
228
+ return_val: List["BaseRelation"]
229
+
230
+ def _to_dict(self):
231
+ from dbt.adapters.record.serialization import serialize_base_relation_list
232
+
233
+ return {"return_val": serialize_base_relation_list(self.return_val)}
234
+
235
+ def _from_dict(self, data: Dict[str, Any]):
236
+ from dbt.adapters.record.serialization import deserialize_base_relation_list
237
+
238
+ self.return_val = deserialize_base_relation_list(data["return_val"])
239
+
240
+
241
+ @Recorder.register_record_type
242
+ class AdapterListRelationsWithoutCachingRecord(Record):
243
+ """Implements record/replay support for the BaseAdapter.list_relations_without_caching() method."""
244
+
245
+ params_cls = AdapterListRelationsWithoutCachingParams
246
+ result_cls = AdapterListRelationsWithoutCachingResult
247
+ group = "Available"
248
+
249
+
250
+ @dataclasses.dataclass
251
+ class AdapterGetColumnsInRelationParams:
252
+ thread_id: str
253
+ relation: "BaseRelation"
254
+
255
+ def _to_dict(self):
256
+ from dbt.adapters.record.serialization import serialize_base_relation
257
+
258
+ return {
259
+ "thread_id": self.thread_id,
260
+ "relation": serialize_base_relation(self.relation),
261
+ }
262
+
263
+ def _from_dict(self, data: Dict[str, Any]):
264
+ from dbt.adapters.record.serialization import deserialize_base_relation
265
+
266
+ self.thread_id = data["thread_id"]
267
+ self.relation = deserialize_base_relation(data["relation"])
268
+
269
+
270
+ @dataclasses.dataclass
271
+ class AdapterGetColumnsInRelationResult:
272
+ return_val: List["BaseColumn"]
273
+
274
+ def _to_dict(self):
275
+ from dbt.adapters.record.serialization import serialize_base_column_list
276
+
277
+ return {"return_val": serialize_base_column_list(self.return_val)}
278
+
279
+ def _from_dict(self, data: Dict[str, Any]):
280
+ from dbt.adapters.record.serialization import deserialize_base_column_list
281
+
282
+ self.return_val = deserialize_base_column_list(data["return_val"])
283
+
284
+
285
+ @Recorder.register_record_type
286
+ class AdapterGetColumnsInRelationRecord(Record):
287
+ """Implements record/replay support for the BaseAdapter.get_columns_in_relation() method."""
288
+
289
+ params_cls = AdapterGetColumnsInRelationParams
290
+ result_cls = AdapterGetColumnsInRelationResult
291
+ group = "Available"
@@ -0,0 +1,69 @@
1
+ from typing import Any, Optional
2
+
3
+ from dbt_common.events.base_types import BaseEvent
4
+ from dbt_common.events.functions import fire_event
5
+ from dbt_common.events.types import RecordReplayIssue
6
+ from dbt_common.record import record_function
7
+
8
+ from dbt.adapters.contracts.connection import Connection
9
+ from dbt.adapters.record.cursor.description import CursorGetDescriptionRecord
10
+ from dbt.adapters.record.cursor.execute import CursorExecuteRecord
11
+ from dbt.adapters.record.cursor.fetchone import CursorFetchOneRecord
12
+ from dbt.adapters.record.cursor.fetchmany import CursorFetchManyRecord
13
+ from dbt.adapters.record.cursor.fetchall import CursorFetchAllRecord
14
+ from dbt.adapters.record.cursor.rowcount import CursorGetRowCountRecord
15
+
16
+
17
+ class RecordReplayCursor:
18
+ """A proxy object used to wrap native database cursors under record/replay
19
+ modes. In record mode, this proxy notes the parameters and return values
20
+ of the methods and properties it implements, which closely match the Python
21
+ DB API 2.0 cursor methods used by many dbt adapters to interact with the
22
+ database or DWH. In replay mode, it mocks out those calls using previously
23
+ recorded calls, so that no interaction with a database actually occurs."""
24
+
25
+ def __init__(self, native_cursor: Any, connection: Connection) -> None:
26
+ self.native_cursor = native_cursor
27
+ self.connection = connection
28
+
29
+ @record_function(CursorExecuteRecord, method=True, id_field_name="connection_name")
30
+ def execute(self, operation, parameters=None) -> None:
31
+ self.native_cursor.execute(operation, parameters)
32
+
33
+ @record_function(CursorFetchOneRecord, method=True, id_field_name="connection_name")
34
+ def fetchone(self) -> Any:
35
+ return self.native_cursor.fetchone()
36
+
37
+ @record_function(CursorFetchManyRecord, method=True, id_field_name="connection_name")
38
+ def fetchmany(self, size: int) -> Any:
39
+ return self.native_cursor.fetchmany(size)
40
+
41
+ @record_function(CursorFetchAllRecord, method=True, id_field_name="connection_name")
42
+ def fetchall(self) -> Any:
43
+ return self.native_cursor.fetchall()
44
+
45
+ @property
46
+ def connection_name(self) -> Optional[str]:
47
+ return self.connection.name
48
+
49
+ @property
50
+ @record_function(CursorGetRowCountRecord, method=True, id_field_name="connection_name")
51
+ def rowcount(self) -> int:
52
+ return self.native_cursor.rowcount
53
+
54
+ @property
55
+ @record_function(CursorGetDescriptionRecord, method=True, id_field_name="connection_name")
56
+ def description(self) -> str:
57
+ return self.native_cursor.description
58
+
59
+ def _fire_event(self, evt: BaseEvent) -> None:
60
+ """Wraps fire_event for easier test mocking."""
61
+ fire_event(evt)
62
+
63
+ def __getattr__(self, name: str) -> Any:
64
+ self._fire_event(
65
+ RecordReplayIssue(
66
+ msg=f"Unexpected attribute '{name}' accessed on {self.__class__.__name__}"
67
+ )
68
+ )
69
+ return getattr(self.native_cursor, name)
@@ -0,0 +1,37 @@
1
+ import dataclasses
2
+ from typing import Any, Iterable, Mapping
3
+
4
+ from dbt_common.record import Record, Recorder
5
+
6
+
7
+ @dataclasses.dataclass
8
+ class CursorGetDescriptionParams:
9
+ connection_name: str
10
+
11
+
12
+ @dataclasses.dataclass
13
+ class CursorGetDescriptionResult:
14
+ columns: Iterable[Any]
15
+
16
+ def _to_dict(self) -> Any:
17
+ column_dicts = []
18
+ for c in self.columns:
19
+ # This captures the mandatory column information, but we might need
20
+ # more for some adapters.
21
+ # See https://peps.python.org/pep-0249/#description
22
+ column_dicts.append((c[0], c[1]))
23
+
24
+ return {"columns": column_dicts}
25
+
26
+ @classmethod
27
+ def _from_dict(cls, dct: Mapping) -> "CursorGetDescriptionResult":
28
+ return CursorGetDescriptionResult(columns=dct["columns"])
29
+
30
+
31
+ @Recorder.register_record_type
32
+ class CursorGetDescriptionRecord(Record):
33
+ """Implements record/replay support for the cursor.description property."""
34
+
35
+ params_cls = CursorGetDescriptionParams
36
+ result_cls = CursorGetDescriptionResult
37
+ group = "Database"
@@ -0,0 +1,39 @@
1
+ import dataclasses
2
+ from typing import Any, Iterable, Union, Mapping, Optional
3
+
4
+ from dbt.adapters.record.cursor.fetchall import CursorFetchAllResult
5
+ from dbt_common.record import Record, Recorder
6
+
7
+
8
+ @dataclasses.dataclass
9
+ class CursorExecuteParams:
10
+ connection_name: str
11
+ operation: str
12
+ parameters: Optional[Union[Iterable[Any], Mapping[str, Any]]] = None
13
+
14
+ def _to_dict(self):
15
+ p = self.parameters
16
+ if isinstance(self.parameters, dict):
17
+ p = {(k, CursorFetchAllResult._process_value(v)) for k, v in self.parameters.items()}
18
+ elif isinstance(self.parameters, list) or isinstance(self.parameters, tuple):
19
+ p = [CursorFetchAllResult._process_value(v) for v in self.parameters]
20
+
21
+ return {
22
+ "connection_name": self.connection_name,
23
+ "operation": self.operation,
24
+ "parameters": p,
25
+ }
26
+
27
+ def _from_dict(cls, data):
28
+ # NOTE: This will be needed for replay, but is not needed at time
29
+ # of writing.
30
+ raise NotImplementedError()
31
+
32
+
33
+ @Recorder.register_record_type
34
+ class CursorExecuteRecord(Record):
35
+ """Implements record/replay support for the cursor.execute() method."""
36
+
37
+ params_cls = CursorExecuteParams
38
+ result_cls = None
39
+ group = "Database"
@@ -0,0 +1,69 @@
1
+ import dataclasses
2
+ import datetime
3
+ import decimal
4
+ from typing import Any, Dict, List, Mapping
5
+
6
+ from dbt_common.record import Record, Recorder
7
+
8
+
9
+ @dataclasses.dataclass
10
+ class CursorFetchAllParams:
11
+ connection_name: str
12
+
13
+
14
+ @dataclasses.dataclass
15
+ class CursorFetchAllResult:
16
+ results: List[Any]
17
+
18
+ def _to_dict(self) -> Dict[str, Any]:
19
+ processed_results = []
20
+ for result in self.results:
21
+ result = tuple(map(self._process_value, result))
22
+ processed_results.append(result)
23
+
24
+ return {"results": processed_results}
25
+
26
+ @classmethod
27
+ def _from_dict(cls, dct: Mapping) -> "CursorFetchAllResult":
28
+ unprocessed_results = []
29
+ for result in dct["results"]:
30
+ result = tuple(map(cls._unprocess_value, result))
31
+ unprocessed_results.append(result)
32
+
33
+ return CursorFetchAllResult(unprocessed_results)
34
+
35
+ @classmethod
36
+ def _process_value(cls, value: Any) -> Any:
37
+ if type(value) is datetime.date:
38
+ return {"type": "date", "value": value.isoformat()}
39
+ elif type(value) is datetime.datetime:
40
+ return {"type": "datetime", "value": value.isoformat()}
41
+ elif type(value) is decimal.Decimal:
42
+ return float(value)
43
+ else:
44
+ return value
45
+
46
+ @classmethod
47
+ def _unprocess_value(cls, value: Any) -> Any:
48
+ if type(value) is dict:
49
+ value_type = value.get("type")
50
+ if value_type == "date":
51
+ date_string = value.get("value")
52
+ assert isinstance(date_string, str)
53
+ return datetime.date.fromisoformat(date_string)
54
+ elif value_type == "datetime":
55
+ date_string = value.get("value")
56
+ assert isinstance(date_string, str)
57
+ return datetime.datetime.fromisoformat(date_string)
58
+ return value
59
+ else:
60
+ return value
61
+
62
+
63
+ @Recorder.register_record_type
64
+ class CursorFetchAllRecord(Record):
65
+ """Implements record/replay support for the cursor.fetchall() method."""
66
+
67
+ params_cls = CursorFetchAllParams
68
+ result_cls = CursorFetchAllResult
69
+ group = "Database"
@@ -0,0 +1,23 @@
1
+ import dataclasses
2
+ from typing import Any, List
3
+
4
+ from dbt_common.record import Record, Recorder
5
+
6
+
7
+ @dataclasses.dataclass
8
+ class CursorFetchManyParams:
9
+ connection_name: str
10
+
11
+
12
+ @dataclasses.dataclass
13
+ class CursorFetchManyResult:
14
+ results: List[Any]
15
+
16
+
17
+ @Recorder.register_record_type
18
+ class CursorFetchManyRecord(Record):
19
+ """Implements record/replay support for the cursor.fetchmany() method."""
20
+
21
+ params_cls = CursorFetchManyParams
22
+ result_cls = CursorFetchManyResult
23
+ group = "Database"