dbt-adapters 1.4.1__py3-none-any.whl → 1.5.0__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.

Potentially problematic release.


This version of dbt-adapters might be problematic. Click here for more details.

dbt/adapters/__about__.py CHANGED
@@ -1 +1 @@
1
- version = "1.4.1"
1
+ version = "1.5.0"
dbt/adapters/base/impl.py CHANGED
@@ -24,6 +24,7 @@ from typing import (
24
24
  )
25
25
 
26
26
  import pytz
27
+ from dbt_common.behavior_flags import Behavior, BehaviorFlag
27
28
  from dbt_common.clients.jinja import CallableMacroGenerator
28
29
  from dbt_common.contracts.constraints import (
29
30
  ColumnLevelConstraint,
@@ -261,7 +262,7 @@ class BaseAdapter(metaclass=AdapterMeta):
261
262
 
262
263
  MAX_SCHEMA_METADATA_RELATIONS = 100
263
264
 
264
- # This static member variable can be overriden in concrete adapter
265
+ # This static member variable can be overridden in concrete adapter
265
266
  # implementations to indicate adapter support for optional capabilities.
266
267
  _capabilities = CapabilityDict({})
267
268
 
@@ -271,6 +272,7 @@ class BaseAdapter(metaclass=AdapterMeta):
271
272
  self.connections = self.ConnectionManager(config, mp_context)
272
273
  self._macro_resolver: Optional[MacroResolverProtocol] = None
273
274
  self._macro_context_generator: Optional[MacroContextGeneratorCallable] = None
275
+ self.behavior = [] # this will be updated to include global behavior flags once they exist
274
276
 
275
277
  ###
276
278
  # Methods to set / access a macro resolver
@@ -291,6 +293,27 @@ class BaseAdapter(metaclass=AdapterMeta):
291
293
  ) -> None:
292
294
  self._macro_context_generator = macro_context_generator
293
295
 
296
+ @property
297
+ def behavior(self) -> Behavior:
298
+ return self._behavior
299
+
300
+ @behavior.setter
301
+ def behavior(self, flags: List[BehaviorFlag]) -> None:
302
+ flags.extend(self._behavior_flags)
303
+ try:
304
+ # we don't always get project flags, for example during `dbt debug`
305
+ self._behavior = Behavior(flags, self.config.flags)
306
+ except AttributeError:
307
+ # in that case, don't load any behavior to avoid unexpected defaults
308
+ self._behavior = Behavior([], {})
309
+
310
+ @property
311
+ def _behavior_flags(self) -> List[BehaviorFlag]:
312
+ """
313
+ This method should be overwritten by adapter maintainers to provide platform-specific flags
314
+ """
315
+ return []
316
+
294
317
  ###
295
318
  # Methods that pass through to the connection manager
296
319
  ###
@@ -1,5 +1,6 @@
1
1
  from collections.abc import Hashable
2
2
  from dataclasses import dataclass, field
3
+ from datetime import datetime
3
4
  from typing import (
4
5
  Any,
5
6
  Dict,
@@ -36,6 +37,13 @@ Self = TypeVar("Self", bound="BaseRelation")
36
37
  SerializableIterable = Union[Tuple, FrozenSet]
37
38
 
38
39
 
40
+ @dataclass(frozen=True, eq=False, repr=False)
41
+ class EventTimeFilter(FakeAPIObject, Hashable):
42
+ field_name: str
43
+ start: Optional[datetime] = None
44
+ end: Optional[datetime] = None
45
+
46
+
39
47
  @dataclass(frozen=True, eq=False, repr=False)
40
48
  class BaseRelation(FakeAPIObject, Hashable):
41
49
  path: Path
@@ -47,6 +55,7 @@ class BaseRelation(FakeAPIObject, Hashable):
47
55
  quote_policy: Policy = field(default_factory=lambda: Policy())
48
56
  dbt_created: bool = False
49
57
  limit: Optional[int] = None
58
+ event_time_filter: Optional[EventTimeFilter] = None
50
59
  require_alias: bool = (
51
60
  True # used to govern whether to add an alias when render_limited is called
52
61
  )
@@ -208,14 +217,19 @@ class BaseRelation(FakeAPIObject, Hashable):
208
217
  # if there is nothing set, this will return the empty string.
209
218
  return ".".join(part for _, part in self._render_iterator() if part is not None)
210
219
 
211
- def _render_limited_alias(self) -> str:
220
+ def _render_subquery_alias(self, namespace: str) -> str:
212
221
  """Some databases require an alias for subqueries (postgres, mysql) for all others we want to avoid adding
213
222
  an alias as it has the potential to introduce issues with the query if the user also defines an alias.
214
223
  """
215
224
  if self.require_alias:
216
- return f" _dbt_limit_subq_{self.table}"
225
+ return f" _dbt_{namespace}_subq_{self.table}"
217
226
  return ""
218
227
 
228
+ def _render_limited_alias(
229
+ self,
230
+ ) -> str:
231
+ return self._render_subquery_alias(namespace="limit")
232
+
219
233
  def render_limited(self) -> str:
220
234
  rendered = self.render()
221
235
  if self.limit is None:
@@ -225,6 +239,31 @@ class BaseRelation(FakeAPIObject, Hashable):
225
239
  else:
226
240
  return f"(select * from {rendered} limit {self.limit}){self._render_limited_alias()}"
227
241
 
242
+ def render_event_time_filtered(self, rendered: Optional[str] = None) -> str:
243
+ rendered = rendered or self.render()
244
+ if self.event_time_filter is None:
245
+ return rendered
246
+
247
+ filter = self._render_event_time_filtered(self.event_time_filter)
248
+ if not filter:
249
+ return rendered
250
+
251
+ return f"(select * from {rendered} where {filter}){self._render_subquery_alias(namespace='et_filter')}"
252
+
253
+ def _render_event_time_filtered(self, event_time_filter: EventTimeFilter) -> str:
254
+ """
255
+ Returns "" if start and end are both None
256
+ """
257
+ filter = ""
258
+ if event_time_filter.start and event_time_filter.end:
259
+ filter = f"{event_time_filter.field_name} >= '{event_time_filter.start}' and {event_time_filter.field_name} < '{event_time_filter.end}'"
260
+ elif event_time_filter.start:
261
+ filter = f"{event_time_filter.field_name} >= '{event_time_filter.start}'"
262
+ elif event_time_filter.end:
263
+ filter = f"{event_time_filter.field_name} < '{event_time_filter.end}'"
264
+
265
+ return filter
266
+
228
267
  def quoted(self, identifier):
229
268
  return "{quote_char}{identifier}{quote_char}".format(
230
269
  quote_char=self.quote_character,
@@ -240,6 +279,7 @@ class BaseRelation(FakeAPIObject, Hashable):
240
279
  cls: Type[Self],
241
280
  relation_config: RelationConfig,
242
281
  limit: Optional[int] = None,
282
+ event_time_filter: Optional[EventTimeFilter] = None,
243
283
  ) -> Self:
244
284
  # Note that ephemeral models are based on the identifier, which will
245
285
  # point to the model's alias if one exists and otherwise fall back to
@@ -250,6 +290,7 @@ class BaseRelation(FakeAPIObject, Hashable):
250
290
  type=cls.CTE,
251
291
  identifier=identifier,
252
292
  limit=limit,
293
+ event_time_filter=event_time_filter,
253
294
  ).quote(identifier=False)
254
295
 
255
296
  @classmethod
@@ -315,7 +356,14 @@ class BaseRelation(FakeAPIObject, Hashable):
315
356
  return hash(self.render())
316
357
 
317
358
  def __str__(self) -> str:
318
- return self.render() if self.limit is None else self.render_limited()
359
+ rendered = self.render() if self.limit is None else self.render_limited()
360
+
361
+ # Limited subquery is wrapped by the event time filter subquery, and not the other way around.
362
+ # This is because in the context of resolving limited refs, we care more about performance than reliably producing a sample of a certain size.
363
+ if self.event_time_filter:
364
+ rendered = self.render_event_time_filtered(rendered)
365
+
366
+ return rendered
319
367
 
320
368
  @property
321
369
  def database(self) -> Optional[str]:
dbt/adapters/factory.py CHANGED
@@ -188,7 +188,7 @@ class AdapterContainer:
188
188
  def get_adapter_type_names(self, name: Optional[str]) -> List[str]:
189
189
  return [p.adapter.type() for p in self.get_adapter_plugins(name)]
190
190
 
191
- def get_adapter_constraint_support(self, name: Optional[str]) -> List[str]:
191
+ def get_adapter_constraint_support(self, name: Optional[str]) -> Dict[str, str]:
192
192
  return self.lookup_adapter(name).CONSTRAINT_SUPPORT # type: ignore
193
193
 
194
194
 
@@ -251,7 +251,7 @@ def get_adapter_type_names(name: Optional[str]) -> List[str]:
251
251
  return FACTORY.get_adapter_type_names(name)
252
252
 
253
253
 
254
- def get_adapter_constraint_support(name: Optional[str]) -> List[str]:
254
+ def get_adapter_constraint_support(name: Optional[str]) -> Dict[str, str]:
255
255
  return FACTORY.get_adapter_constraint_support(name)
256
256
 
257
257
 
@@ -15,6 +15,14 @@
15
15
  {{ current_timestamp() }}
16
16
  {% endmacro %}
17
17
 
18
+ {% macro get_snapshot_get_time_data_type() %}
19
+ {% set snapshot_time = adapter.dispatch('snapshot_get_time', 'dbt')() %}
20
+ {% set time_data_type_sql = 'select ' ~ snapshot_time ~ ' as dbt_snapshot_time' %}
21
+ {% set snapshot_time_column_schema = get_column_schema_from_query(time_data_type_sql) %}
22
+ {% set time_data_type = snapshot_time_column_schema[0].dtype %}
23
+ {{ return(time_data_type or none) }}
24
+ {% endmacro %}
25
+
18
26
  ---------------------------------------------
19
27
 
20
28
  /* {#
@@ -179,3 +179,28 @@
179
179
 
180
180
  {% do return(temp_relation) %}
181
181
  {% endmacro %}
182
+
183
+
184
+ {% macro get_updated_at_column_data_type(snapshot_sql) %}
185
+ {% set snapshot_sql_column_schema = get_column_schema_from_query(snapshot_sql) %}
186
+ {% set dbt_updated_at_data_type = null %}
187
+ {% set ns = namespace() -%} {#-- handle for-loop scoping with a namespace --#}
188
+ {% set ns.dbt_updated_at_data_type = null -%}
189
+ {% for column in snapshot_sql_column_schema %}
190
+ {% if ((column.column == 'dbt_updated_at') or (column.column == 'DBT_UPDATED_AT')) %}
191
+ {% set ns.dbt_updated_at_data_type = column.dtype %}
192
+ {% endif %}
193
+ {% endfor %}
194
+ {{ return(ns.dbt_updated_at_data_type or none) }}
195
+ {% endmacro %}
196
+
197
+
198
+ {% macro check_time_data_types(sql) %}
199
+ {% set dbt_updated_at_data_type = get_updated_at_column_data_type(sql) %}
200
+ {% set snapshot_get_time_data_type = get_snapshot_get_time_data_type() %}
201
+ {% if snapshot_get_time_data_type is not none and dbt_updated_at_data_type is not none and snapshot_get_time_data_type != dbt_updated_at_data_type %}
202
+ {% if exceptions.warn_snapshot_timestamp_data_types %}
203
+ {{ exceptions.warn_snapshot_timestamp_data_types(snapshot_get_time_data_type, dbt_updated_at_data_type) }}
204
+ {% endif %}
205
+ {% endif %}
206
+ {% endmacro %}
@@ -29,12 +29,14 @@
29
29
  {% if not target_relation_exists %}
30
30
 
31
31
  {% set build_sql = build_snapshot_table(strategy, model['compiled_code']) %}
32
+ {% set build_or_select_sql = build_sql %}
32
33
  {% set final_sql = create_table_as(False, target_relation, build_sql) %}
33
34
 
34
35
  {% else %}
35
36
 
36
37
  {{ adapter.valid_snapshot_target(target_relation) }}
37
38
 
39
+ {% set build_or_select_sql = snapshot_staging_table(strategy, sql, target_relation) %}
38
40
  {% set staging_table = build_snapshot_staging_table(strategy, sql, target_relation) %}
39
41
 
40
42
  -- this may no-op if the database does not require column expansion
@@ -71,6 +73,9 @@
71
73
 
72
74
  {% endif %}
73
75
 
76
+
77
+ {{ check_time_data_types(build_or_select_sql) }}
78
+
74
79
  {% call statement('main') %}
75
80
  {{ final_sql }}
76
81
  {% endcall %}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: dbt-adapters
3
- Version: 1.4.1
3
+ Version: 1.5.0
4
4
  Summary: The set of adapter protocols and base functionality that supports integration with dbt-core
5
5
  Project-URL: Homepage, https://github.com/dbt-labs/dbt-adapters
6
6
  Project-URL: Documentation, https://docs.getdbt.com
@@ -23,7 +23,7 @@ Classifier: Programming Language :: Python :: 3.11
23
23
  Classifier: Programming Language :: Python :: 3.12
24
24
  Requires-Python: >=3.8.0
25
25
  Requires-Dist: agate<2.0,>=1.0
26
- Requires-Dist: dbt-common<2.0,>=1.6
26
+ Requires-Dist: dbt-common<2.0,>=1.8
27
27
  Requires-Dist: mashumaro[msgpack]<4.0,>=3.0
28
28
  Requires-Dist: protobuf<5.0,>=3.0
29
29
  Requires-Dist: pytz>=2015.7
@@ -1,9 +1,9 @@
1
1
  dbt/__init__.py,sha256=iY4jdvOxcDhkdr5FiyOTZPHadKtMZDQ-qC6Fw6_EHPM,277
2
- dbt/adapters/__about__.py,sha256=_v6nQd_J3JWKdN0EM5pVQyKX6Gw4fD9xA2Uxl7be_eg,18
2
+ dbt/adapters/__about__.py,sha256=Wgohrh7g_peUNIz0Cro4w7u88rZU94fNypIcm9oMWgQ,18
3
3
  dbt/adapters/__init__.py,sha256=3noHsg-64qI0_Pw6OR9F7l1vU2_qrJvinq8POTtuaZM,252
4
4
  dbt/adapters/cache.py,sha256=WGy4ewnz-J13LverTACBW2iFhGswrWLgm-wiBrQnMzo,20084
5
5
  dbt/adapters/capability.py,sha256=-Mbej2AL_bjQatHpFWUgsQ8z0zwnotyE9Y5DYHnX7NE,2364
6
- dbt/adapters/factory.py,sha256=JxNxhMqemZ6ARWbROQZhkhJehiIenuR9ZQYS8gvzbDg,9368
6
+ dbt/adapters/factory.py,sha256=9N-LjTnyqBKqK7KARjJdAPdQIRXQbVRfd2cBNDtU4Dc,9378
7
7
  dbt/adapters/protocol.py,sha256=qRsEFAKjUMVnoBspAiCUTICez1ckson-dFS04dTXSco,3818
8
8
  dbt/adapters/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  dbt/adapters/reference_keys.py,sha256=lRN3gPdQD6Qciy-BAGx_rz3CFlbS7zMSZ43pZ_9ondE,1046
@@ -12,11 +12,11 @@ dbt/adapters/base/README.md,sha256=muHQntC07Lh6L1XfVgwKhV5RltOPBLYPdQqd8_7l34c,5
12
12
  dbt/adapters/base/__init__.py,sha256=KGGGbj8jGMjAFJdQ5YHcOpApMMVZ_6Xuni1swhpkqRY,423
13
13
  dbt/adapters/base/column.py,sha256=Uj20UixoxCn2rlv4QDNONyys6CDkDFyG3anCXKf0T2c,5350
14
14
  dbt/adapters/base/connections.py,sha256=-C5dOwGgMKH8n_v6wjwOxV7chBdS0GjOGwNQCUbhhWc,16951
15
- dbt/adapters/base/impl.py,sha256=oRkaEUjLWLlisyLpxpjddDj7j0mjh5OWXwVgT0h6y14,69552
15
+ dbt/adapters/base/impl.py,sha256=WIYEIX_RhB3C4R1nkSjVuOaBQggYXwI0Tlovlinn30o,70444
16
16
  dbt/adapters/base/meta.py,sha256=MMqL2xBqdvoacNs9JcL0E38NZIhCP4RH4OD_z_jo7GQ,4644
17
17
  dbt/adapters/base/plugin.py,sha256=rm0GjNHnWM2mn0GJOjciZLwn-02xlzWCoMT9u-epwP0,1076
18
18
  dbt/adapters/base/query_headers.py,sha256=UluGd9IYCYkoMiDi5Yx_lnrCOSjWppjwRro4SIGgx8I,3496
19
- dbt/adapters/base/relation.py,sha256=oRaR8TtcngzUPE_BOORkgYcNg0aJ5_a_jcxYvlK01LE,16401
19
+ dbt/adapters/base/relation.py,sha256=96IbXN1j9w8fZkcojCkJwFaMMMdv74VRoSFVQqkUPK0,18409
20
20
  dbt/adapters/clients/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
21
  dbt/adapters/clients/jinja.py,sha256=NsZOiBpOLunS46hRL5OcX1MpY3Ih6_87Vgz4qd_PNbc,768
22
22
  dbt/adapters/contracts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -67,7 +67,7 @@ dbt/include/global_project/macros/adapters/persist_docs.sql,sha256=TUazJHSaMIDlE
67
67
  dbt/include/global_project/macros/adapters/relation.sql,sha256=18lE088vj0JZW8af2byoGLFhxYxekyXKTrX7Dj-B-E0,2809
68
68
  dbt/include/global_project/macros/adapters/schema.sql,sha256=XElo0cfvdEipI5hpulLXLBEXP_YnilG-1kRwDMqDD5I,594
69
69
  dbt/include/global_project/macros/adapters/show.sql,sha256=mFDQZxvvDzafTeh9v90ttks-VCjUUxbrw_YA02MV1Jk,785
70
- dbt/include/global_project/macros/adapters/timestamps.sql,sha256=V_vM-UWyKGGs7rP4DumBgZrbb-TkucIFEvMn69Zpaxg,1482
70
+ dbt/include/global_project/macros/adapters/timestamps.sql,sha256=FvPwWkmM00r9rs2DjR5wrI-U9ah3-8VMIwk5wRRzuPw,1910
71
71
  dbt/include/global_project/macros/adapters/validate_sql.sql,sha256=IC-HEVv8Cl8nd7dic_U4hyqlrkdO6plPbH914OdM_WE,285
72
72
  dbt/include/global_project/macros/etc/datetime.sql,sha256=HwNxXw0xHHLVKFBlbbc4wqTdYe6_smku1EwWGM7G-6g,2185
73
73
  dbt/include/global_project/macros/etc/statement.sql,sha256=lkm6T6kCIPGkCuHVS6VuVqsAX8zV9CI7iTIOnPOZnw8,1819
@@ -94,8 +94,8 @@ dbt/include/global_project/macros/materializations/models/incremental/on_schema_
94
94
  dbt/include/global_project/macros/materializations/models/incremental/strategies.sql,sha256=1QKXoCm47g_JAmWypjSUHU8ACmXFgaBoWUG3HPCN7wA,2251
95
95
  dbt/include/global_project/macros/materializations/seeds/helpers.sql,sha256=Y15ej-D3gm1ExIOMNT208q43gRk8d985WQBuGSooNL0,3920
96
96
  dbt/include/global_project/macros/materializations/seeds/seed.sql,sha256=YSoGzVO3iIUiOKIUM9G7yApGLFH4O9bv_d4KjHo3p4Q,2155
97
- dbt/include/global_project/macros/materializations/snapshots/helpers.sql,sha256=O0aCMTPUrFONwEamKu7AMuUP6Tp0-NegJf6aZnS1018,4816
98
- dbt/include/global_project/macros/materializations/snapshots/snapshot.sql,sha256=q-Uaz9B2070fpruz5HEJiCqPUJNgXl7dsM5a0_v0fkg,3680
97
+ dbt/include/global_project/macros/materializations/snapshots/helpers.sql,sha256=rLnopom7nEzbQ12C9O9yIMh4C8poshYqlVTnmE4gLh0,6012
98
+ dbt/include/global_project/macros/materializations/snapshots/snapshot.sql,sha256=q_LzkaeJCXGemzPvHnCWYTUS7ODaS747cYN_zXZHb7k,3874
99
99
  dbt/include/global_project/macros/materializations/snapshots/snapshot_merge.sql,sha256=Lu3Yq3fEQuOGoDY0NFfruTAuvOEF3wXuo3SF_dK7uqY,858
100
100
  dbt/include/global_project/macros/materializations/snapshots/strategies.sql,sha256=ahWDMnD-Q_fTGKSjvm5ZwvypmNC6BDVguk-LNk-nHhU,6286
101
101
  dbt/include/global_project/macros/materializations/tests/helpers.sql,sha256=rxUxDZm4EvrDbi0H_ePghE34_QLmxGEY2o_LTMc9CU0,1731
@@ -157,7 +157,7 @@ dbt/include/global_project/macros/utils/right.sql,sha256=EwNG98CAFIwNDmarwopf7Rk
157
157
  dbt/include/global_project/macros/utils/safe_cast.sql,sha256=1mswwkDACmIi1I99JKb_-vq3kjMe4HhMRV70mW8Bt4Y,298
158
158
  dbt/include/global_project/macros/utils/split_part.sql,sha256=fXEIS0oIiYR7-4lYbb0QbZdG-q2TpV63AFd1ky4I5UM,714
159
159
  dbt/include/global_project/tests/generic/builtin.sql,sha256=p94xdyPwb2TlxgLBqCfrcRfJ1QNgsjPvBm8f0Q5eqZM,1022
160
- dbt_adapters-1.4.1.dist-info/METADATA,sha256=tyOBq9sBta4UHrnz6x5Q4FP0mFfiO8b2HXnx5tJH8P4,2547
161
- dbt_adapters-1.4.1.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
162
- dbt_adapters-1.4.1.dist-info/licenses/LICENSE,sha256=9yjigiJhWcCZvQjdagGKDwrRph58QWc5P2bVSQwXo6s,11344
163
- dbt_adapters-1.4.1.dist-info/RECORD,,
160
+ dbt_adapters-1.5.0.dist-info/METADATA,sha256=rVUPUa1VjVs3l8j2Ur7mQa7ROHwhE3w4-Ok0dCZyIn8,2547
161
+ dbt_adapters-1.5.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
162
+ dbt_adapters-1.5.0.dist-info/licenses/LICENSE,sha256=9yjigiJhWcCZvQjdagGKDwrRph58QWc5P2bVSQwXo6s,11344
163
+ dbt_adapters-1.5.0.dist-info/RECORD,,