|
5 | 5 | import functools
|
6 | 6 | import logging
|
7 | 7 | from abc import ABC, abstractmethod
|
8 |
| -from typing import Any, Callable, Iterable, List, Mapping, MutableMapping, Optional, Protocol, Tuple |
| 8 | +from typing import ( |
| 9 | + Any, |
| 10 | + Callable, |
| 11 | + Iterable, |
| 12 | + List, |
| 13 | + Mapping, |
| 14 | + MutableMapping, |
| 15 | + Optional, |
| 16 | + Protocol, |
| 17 | + Tuple, |
| 18 | + Union, |
| 19 | +) |
9 | 20 |
|
10 | 21 | from airbyte_cdk.sources.connector_state_manager import ConnectorStateManager
|
11 | 22 | from airbyte_cdk.sources.message import MessageRepository
|
@@ -175,7 +186,9 @@ def __init__(
|
175 | 186 | self.start, self._concurrent_state = self._get_concurrent_state(stream_state)
|
176 | 187 | self._lookback_window = lookback_window
|
177 | 188 | self._slice_range = slice_range
|
178 |
| - self._most_recent_cursor_value_per_partition: MutableMapping[StreamSlice, Any] = {} |
| 189 | + self._most_recent_cursor_value_per_partition: MutableMapping[ |
| 190 | + Union[StreamSlice, Mapping[str, Any], None], Any |
| 191 | + ] = {} |
179 | 192 | self._has_closed_at_least_one_slice = False
|
180 | 193 | self._cursor_granularity = cursor_granularity
|
181 | 194 | # Flag to track if the logger has been triggered (per stream)
|
@@ -216,10 +229,13 @@ def observe(self, record: Record) -> None:
|
216 | 229 | most_recent_cursor_value = self._most_recent_cursor_value_per_partition.get(
|
217 | 230 | record.associated_slice
|
218 | 231 | )
|
219 |
| - cursor_value = self._extract_cursor_value(record) |
| 232 | + try: |
| 233 | + cursor_value = self._extract_cursor_value(record) |
220 | 234 |
|
221 |
| - if most_recent_cursor_value is None or most_recent_cursor_value < cursor_value: |
222 |
| - self._most_recent_cursor_value_per_partition[record.associated_slice] = cursor_value |
| 235 | + if most_recent_cursor_value is None or most_recent_cursor_value < cursor_value: |
| 236 | + self._most_recent_cursor_value_per_partition[record.associated_slice] = cursor_value |
| 237 | + except ValueError: |
| 238 | + self._log_for_record_without_cursor_value() |
223 | 239 |
|
224 | 240 | def _extract_cursor_value(self, record: Record) -> Any:
|
225 | 241 | return self._connector_state_converter.parse_value(self._cursor_field.extract_value(record))
|
@@ -459,10 +475,13 @@ def should_be_synced(self, record: Record) -> bool:
|
459 | 475 | try:
|
460 | 476 | record_cursor_value: CursorValueType = self._extract_cursor_value(record) # type: ignore # cursor_field is converted to an InterpolatedString in __post_init__
|
461 | 477 | except ValueError:
|
462 |
| - if not self._should_be_synced_logger_triggered: |
463 |
| - LOGGER.warning( |
464 |
| - f"Could not find cursor field `{self.cursor_field.cursor_field_key}` in record. The incremental sync will assume it needs to be synced" |
465 |
| - ) |
466 |
| - self._should_be_synced_logger_triggered = True |
| 478 | + self._log_for_record_without_cursor_value() |
467 | 479 | return True
|
468 | 480 | return self.start <= record_cursor_value <= self._end_provider()
|
| 481 | + |
| 482 | + def _log_for_record_without_cursor_value(self) -> None: |
| 483 | + if not self._should_be_synced_logger_triggered: |
| 484 | + LOGGER.warning( |
| 485 | + f"Could not find cursor field `{self.cursor_field.cursor_field_key}` in record for stream {self._stream_name}. The incremental sync will assume it needs to be synced" |
| 486 | + ) |
| 487 | + self._should_be_synced_logger_triggered = True |
0 commit comments