sqlspec 0.63.0__py3-none-any.whl → 0.63.1__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.
- sqlspec/service/__init__.py +5 -0
- sqlspec/{service.py → service/_base.py} +28 -347
- sqlspec/service/_core.py +423 -0
- {sqlspec-0.63.0.dist-info → sqlspec-0.63.1.dist-info}/METADATA +1 -1
- {sqlspec-0.63.0.dist-info → sqlspec-0.63.1.dist-info}/RECORD +8 -6
- {sqlspec-0.63.0.dist-info → sqlspec-0.63.1.dist-info}/WHEEL +0 -0
- {sqlspec-0.63.0.dist-info → sqlspec-0.63.1.dist-info}/entry_points.txt +0 -0
- {sqlspec-0.63.0.dist-info → sqlspec-0.63.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,26 +1,29 @@
|
|
|
1
1
|
"""Service base classes for SQLSpec application services."""
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
from contextvars import ContextVar, Token
|
|
7
|
-
from threading import get_ident
|
|
8
|
-
from typing import TYPE_CHECKING, Any, Generic, Literal, cast, overload
|
|
9
|
-
|
|
10
|
-
from mypy_extensions import mypyc_attr
|
|
3
|
+
from contextlib import AbstractAsyncContextManager, AbstractContextManager, nullcontext
|
|
4
|
+
from typing import TYPE_CHECKING, Any, Generic, cast, overload
|
|
5
|
+
|
|
11
6
|
from typing_extensions import TypeVar
|
|
12
7
|
|
|
13
8
|
from sqlspec.core import OffsetPagination
|
|
14
|
-
from sqlspec.core.filters import LimitOffsetFilter
|
|
15
9
|
from sqlspec.driver._async import AsyncDriverAdapterBase
|
|
16
10
|
from sqlspec.driver._sync import SyncDriverAdapterBase
|
|
17
|
-
from sqlspec.exceptions import ImproperConfigurationError
|
|
11
|
+
from sqlspec.exceptions import ImproperConfigurationError
|
|
12
|
+
from sqlspec.service._core import (
|
|
13
|
+
_async_exists,
|
|
14
|
+
_async_get_one,
|
|
15
|
+
_async_paginate,
|
|
16
|
+
_AsyncBeginTransactionContext,
|
|
17
|
+
_sync_exists,
|
|
18
|
+
_sync_get_one,
|
|
19
|
+
_sync_paginate,
|
|
20
|
+
_SyncBeginTransactionContext,
|
|
21
|
+
_transaction_session,
|
|
22
|
+
_TransactionState,
|
|
23
|
+
)
|
|
18
24
|
from sqlspec.typing import SchemaT
|
|
19
|
-
from sqlspec.utils.logging import get_logger
|
|
20
25
|
|
|
21
26
|
if TYPE_CHECKING:
|
|
22
|
-
from types import TracebackType
|
|
23
|
-
|
|
24
27
|
from sqlspec.builder import QueryBuilder
|
|
25
28
|
from sqlspec.config import AsyncDatabaseConfig, NoPoolAsyncConfig, NoPoolSyncConfig, SyncDatabaseConfig
|
|
26
29
|
from sqlspec.core.filters import StatementFilter
|
|
@@ -34,36 +37,7 @@ __all__ = ("SQLSpecAsyncService", "SQLSpecSyncService")
|
|
|
34
37
|
AsyncDriverT = TypeVar("AsyncDriverT", bound=AsyncDriverAdapterBase, default=AsyncDriverAdapterBase)
|
|
35
38
|
SyncDriverT = TypeVar("SyncDriverT", bound=SyncDriverAdapterBase, default=SyncDriverAdapterBase)
|
|
36
39
|
|
|
37
|
-
logger = get_logger("sqlspec.service")
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def _execution_owner() -> tuple[int, object]:
|
|
41
|
-
try:
|
|
42
|
-
task = asyncio.current_task()
|
|
43
|
-
except RuntimeError:
|
|
44
|
-
task = None
|
|
45
|
-
return get_ident(), task
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def _owner_identity(owner: tuple[int, object]) -> tuple[int, int]:
|
|
49
|
-
return owner[0], id(owner[1])
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
class _TransactionState:
|
|
53
|
-
__slots__ = ("driver", "origin", "owner")
|
|
54
|
-
|
|
55
|
-
def __init__(self, driver: AsyncDriverAdapterBase | SyncDriverAdapterBase) -> None:
|
|
56
|
-
self.driver: AsyncDriverAdapterBase | SyncDriverAdapterBase | None = driver
|
|
57
|
-
self.owner = _execution_owner()
|
|
58
|
-
self.origin = _owner_identity(self.owner)
|
|
59
40
|
|
|
60
|
-
|
|
61
|
-
_TRANSACTIONS: ContextVar[dict[object, _TransactionState] | None] = ContextVar(
|
|
62
|
-
"sqlspec_service_transactions", default=None
|
|
63
|
-
)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
@mypyc_attr(allow_interpreted_subclasses=True)
|
|
67
41
|
class SQLSpecAsyncService(Generic[AsyncDriverT]):
|
|
68
42
|
"""Base class for asynchronous SQLSpec services.
|
|
69
43
|
|
|
@@ -194,27 +168,9 @@ class SQLSpecAsyncService(Generic[AsyncDriverT]):
|
|
|
194
168
|
Returns:
|
|
195
169
|
An OffsetPagination instance containing items and total count.
|
|
196
170
|
"""
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
items, total = await driver.select_with_total(
|
|
201
|
-
statement, *parameters, schema_type=schema_type, count_with_window=count_with_window, **kwargs
|
|
202
|
-
)
|
|
203
|
-
|
|
204
|
-
if schema_type is None:
|
|
205
|
-
return OffsetPagination(
|
|
206
|
-
items=cast("list[dict[str, Any]]", items),
|
|
207
|
-
limit=limit_offset.limit if limit_offset is not None else len(items),
|
|
208
|
-
offset=limit_offset.offset if limit_offset is not None else 0,
|
|
209
|
-
total=total,
|
|
210
|
-
)
|
|
211
|
-
|
|
212
|
-
return OffsetPagination(
|
|
213
|
-
items=cast("list[SchemaT]", items),
|
|
214
|
-
limit=limit_offset.limit if limit_offset is not None else len(items),
|
|
215
|
-
offset=limit_offset.offset if limit_offset is not None else 0,
|
|
216
|
-
total=total,
|
|
217
|
-
)
|
|
171
|
+
return await _async_paginate(
|
|
172
|
+
self.provide_session(session), statement, parameters, schema_type, count_with_window, kwargs
|
|
173
|
+
)
|
|
218
174
|
|
|
219
175
|
@overload
|
|
220
176
|
async def get_one(
|
|
@@ -283,11 +239,9 @@ class SQLSpecAsyncService(Generic[AsyncDriverT]):
|
|
|
283
239
|
Raises:
|
|
284
240
|
NotFoundError: If the query returns zero rows.
|
|
285
241
|
"""
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
raise NotFoundError(error_message or "Record not found")
|
|
290
|
-
return result
|
|
242
|
+
return await _async_get_one(
|
|
243
|
+
self.provide_session(session), statement, parameters, schema_type, error_message, kwargs
|
|
244
|
+
)
|
|
291
245
|
|
|
292
246
|
async def exists(
|
|
293
247
|
self,
|
|
@@ -308,8 +262,7 @@ class SQLSpecAsyncService(Generic[AsyncDriverT]):
|
|
|
308
262
|
Returns:
|
|
309
263
|
True if at least one row exists, False otherwise.
|
|
310
264
|
"""
|
|
311
|
-
|
|
312
|
-
return await driver.select_one_or_none(statement, *parameters, **kwargs) is not None
|
|
265
|
+
return await _async_exists(self.provide_session(session), statement, parameters, kwargs)
|
|
313
266
|
|
|
314
267
|
async def begin(self, *, session: AsyncDriverT | None = None) -> None:
|
|
315
268
|
"""Begin a database transaction on the underlying session.
|
|
@@ -346,7 +299,6 @@ class SQLSpecAsyncService(Generic[AsyncDriverT]):
|
|
|
346
299
|
return _AsyncBeginTransactionContext(self)
|
|
347
300
|
|
|
348
301
|
|
|
349
|
-
@mypyc_attr(allow_interpreted_subclasses=True)
|
|
350
302
|
class SQLSpecSyncService(Generic[SyncDriverT]):
|
|
351
303
|
"""Base class for synchronous SQLSpec services.
|
|
352
304
|
|
|
@@ -477,27 +429,9 @@ class SQLSpecSyncService(Generic[SyncDriverT]):
|
|
|
477
429
|
Returns:
|
|
478
430
|
An OffsetPagination instance containing items and total count.
|
|
479
431
|
"""
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
items, total = driver.select_with_total(
|
|
484
|
-
statement, *parameters, schema_type=schema_type, count_with_window=count_with_window, **kwargs
|
|
485
|
-
)
|
|
486
|
-
|
|
487
|
-
if schema_type is None:
|
|
488
|
-
return OffsetPagination(
|
|
489
|
-
items=cast("list[dict[str, Any]]", items),
|
|
490
|
-
limit=limit_offset.limit if limit_offset is not None else len(items),
|
|
491
|
-
offset=limit_offset.offset if limit_offset is not None else 0,
|
|
492
|
-
total=total,
|
|
493
|
-
)
|
|
494
|
-
|
|
495
|
-
return OffsetPagination(
|
|
496
|
-
items=cast("list[SchemaT]", items),
|
|
497
|
-
limit=limit_offset.limit if limit_offset is not None else len(items),
|
|
498
|
-
offset=limit_offset.offset if limit_offset is not None else 0,
|
|
499
|
-
total=total,
|
|
500
|
-
)
|
|
432
|
+
return _sync_paginate(
|
|
433
|
+
self.provide_session(session), statement, parameters, schema_type, count_with_window, kwargs
|
|
434
|
+
)
|
|
501
435
|
|
|
502
436
|
@overload
|
|
503
437
|
def get_one(
|
|
@@ -566,11 +500,7 @@ class SQLSpecSyncService(Generic[SyncDriverT]):
|
|
|
566
500
|
Raises:
|
|
567
501
|
NotFoundError: If the query returns zero rows.
|
|
568
502
|
"""
|
|
569
|
-
|
|
570
|
-
result = driver.select_one_or_none(statement, *parameters, schema_type=schema_type, **kwargs)
|
|
571
|
-
if result is None:
|
|
572
|
-
raise NotFoundError(error_message or "Record not found")
|
|
573
|
-
return result
|
|
503
|
+
return _sync_get_one(self.provide_session(session), statement, parameters, schema_type, error_message, kwargs)
|
|
574
504
|
|
|
575
505
|
def exists(
|
|
576
506
|
self,
|
|
@@ -591,8 +521,7 @@ class SQLSpecSyncService(Generic[SyncDriverT]):
|
|
|
591
521
|
Returns:
|
|
592
522
|
True if at least one row exists, False otherwise.
|
|
593
523
|
"""
|
|
594
|
-
|
|
595
|
-
return driver.select_one_or_none(statement, *parameters, **kwargs) is not None
|
|
524
|
+
return _sync_exists(self.provide_session(session), statement, parameters, kwargs)
|
|
596
525
|
|
|
597
526
|
def begin(self, *, session: SyncDriverT | None = None) -> None:
|
|
598
527
|
"""Begin a database transaction on the underlying session.
|
|
@@ -627,251 +556,3 @@ class SQLSpecSyncService(Generic[SyncDriverT]):
|
|
|
627
556
|
The underlying driver session bound to the active transaction.
|
|
628
557
|
"""
|
|
629
558
|
return _SyncBeginTransactionContext(self)
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
def _active_transaction(key: object) -> _TransactionState | None:
|
|
633
|
-
state = (_TRANSACTIONS.get() or {}).get(key)
|
|
634
|
-
if state is None:
|
|
635
|
-
return None
|
|
636
|
-
if state.driver is None:
|
|
637
|
-
if state.origin == _owner_identity(_execution_owner()):
|
|
638
|
-
_discard_transaction(state)
|
|
639
|
-
return None
|
|
640
|
-
msg = "The inherited service transaction is no longer active."
|
|
641
|
-
raise ImproperConfigurationError(msg)
|
|
642
|
-
if state.owner != _execution_owner():
|
|
643
|
-
msg = "A service transaction cannot be implicitly reused by another task or thread; pass session= explicitly."
|
|
644
|
-
raise ImproperConfigurationError(msg)
|
|
645
|
-
return state
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
def _live_transaction(key: object) -> _TransactionState | None:
|
|
649
|
-
current = _TRANSACTIONS.get()
|
|
650
|
-
state = None if current is None else current.get(key)
|
|
651
|
-
if state is None:
|
|
652
|
-
return None
|
|
653
|
-
if state.driver is None:
|
|
654
|
-
_discard_transaction(state)
|
|
655
|
-
return None
|
|
656
|
-
return _active_transaction(key)
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
def _discard_transaction(state: _TransactionState) -> None:
|
|
660
|
-
current = _TRANSACTIONS.get()
|
|
661
|
-
if current is not None and any(value is state for value in current.values()):
|
|
662
|
-
_TRANSACTIONS.set({key: value for key, value in current.items() if value is not state} or None)
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
def _session_transaction(state: _TransactionState | None) -> _TransactionState | None:
|
|
666
|
-
if state is None or state.driver is None:
|
|
667
|
-
return None
|
|
668
|
-
if state.owner != _execution_owner():
|
|
669
|
-
msg = (
|
|
670
|
-
"A service transaction is active in another task or thread; nested begin_transaction() blocks must "
|
|
671
|
-
"run in the task or thread that entered the outer block."
|
|
672
|
-
)
|
|
673
|
-
raise ImproperConfigurationError(msg)
|
|
674
|
-
return state
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
def _connection_in_transaction(driver: AsyncDriverAdapterBase | SyncDriverAdapterBase) -> bool:
|
|
678
|
-
try:
|
|
679
|
-
return driver._connection_in_transaction()
|
|
680
|
-
except NotImplementedError:
|
|
681
|
-
return False
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
def _transaction_session(key: object) -> AsyncDriverAdapterBase | SyncDriverAdapterBase | None:
|
|
685
|
-
state = _active_transaction(key)
|
|
686
|
-
return None if state is None else state.driver
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
def _bind_transaction(
|
|
690
|
-
key: object, driver: AsyncDriverAdapterBase | SyncDriverAdapterBase
|
|
691
|
-
) -> tuple[_TransactionState, Token[dict[object, _TransactionState] | None]]:
|
|
692
|
-
state = _TransactionState(driver)
|
|
693
|
-
token = _TRANSACTIONS.set({**(_TRANSACTIONS.get() or {}), key: state})
|
|
694
|
-
return state, token
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
def _release_transaction(state: _TransactionState, token: Token[dict[object, _TransactionState] | None]) -> None:
|
|
698
|
-
state.driver = None
|
|
699
|
-
state.owner = (0, None)
|
|
700
|
-
try:
|
|
701
|
-
_TRANSACTIONS.reset(token)
|
|
702
|
-
except ValueError:
|
|
703
|
-
_discard_transaction(state)
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
class _AsyncBeginTransactionContext(Generic[AsyncDriverT]):
|
|
707
|
-
__slots__ = ("_nested", "_service", "_stack", "_state")
|
|
708
|
-
|
|
709
|
-
def __init__(self, service: "SQLSpecAsyncService[AsyncDriverT]") -> None:
|
|
710
|
-
self._service = service
|
|
711
|
-
self._stack: AsyncExitStack | None = None
|
|
712
|
-
self._state: _TransactionState | None = None
|
|
713
|
-
self._nested: Any = None
|
|
714
|
-
|
|
715
|
-
async def __aenter__(self) -> AsyncDriverT:
|
|
716
|
-
service = self._service
|
|
717
|
-
if service._config is None:
|
|
718
|
-
active = _session_transaction(service._transaction_state)
|
|
719
|
-
session = service.session
|
|
720
|
-
if active is not None or session._transaction_depth > 0:
|
|
721
|
-
nested = session.transaction()
|
|
722
|
-
await nested.__aenter__()
|
|
723
|
-
self._nested = nested
|
|
724
|
-
return session
|
|
725
|
-
if not _connection_in_transaction(session):
|
|
726
|
-
await service.begin()
|
|
727
|
-
session._transaction_depth += 1
|
|
728
|
-
state = _TransactionState(session)
|
|
729
|
-
service._transaction_state = state
|
|
730
|
-
self._state = state
|
|
731
|
-
return session
|
|
732
|
-
key = service._transaction_key
|
|
733
|
-
live = _live_transaction(key)
|
|
734
|
-
if live is not None:
|
|
735
|
-
driver = cast("AsyncDriverT", live.driver)
|
|
736
|
-
nested = driver.transaction()
|
|
737
|
-
await nested.__aenter__()
|
|
738
|
-
self._nested = nested
|
|
739
|
-
return driver
|
|
740
|
-
stack = AsyncExitStack()
|
|
741
|
-
try:
|
|
742
|
-
driver = await stack.enter_async_context(service.provide_session())
|
|
743
|
-
await stack.enter_async_context(driver.transaction())
|
|
744
|
-
state, token = _bind_transaction(key, driver)
|
|
745
|
-
stack.callback(_release_transaction, state, token)
|
|
746
|
-
except BaseException:
|
|
747
|
-
await stack.__aexit__(*sys.exc_info())
|
|
748
|
-
raise
|
|
749
|
-
self._stack = stack
|
|
750
|
-
self._state = state
|
|
751
|
-
return driver
|
|
752
|
-
|
|
753
|
-
async def __aexit__(
|
|
754
|
-
self, exc_type: "type[BaseException] | None", exc: "BaseException | None", traceback: "TracebackType | None"
|
|
755
|
-
) -> "Literal[False]":
|
|
756
|
-
service = self._service
|
|
757
|
-
nested = self._nested
|
|
758
|
-
state = self._state
|
|
759
|
-
stack = self._stack
|
|
760
|
-
self._nested = None
|
|
761
|
-
self._state = None
|
|
762
|
-
self._stack = None
|
|
763
|
-
if nested is not None:
|
|
764
|
-
await nested.__aexit__(exc_type, exc, traceback)
|
|
765
|
-
return False
|
|
766
|
-
if stack is not None:
|
|
767
|
-
await stack.__aexit__(exc_type, exc, traceback)
|
|
768
|
-
return False
|
|
769
|
-
if state is None:
|
|
770
|
-
return False
|
|
771
|
-
session = cast("AsyncDriverAdapterBase", state.driver)
|
|
772
|
-
try:
|
|
773
|
-
if exc_type is not None:
|
|
774
|
-
await service.rollback()
|
|
775
|
-
return False
|
|
776
|
-
try:
|
|
777
|
-
await service.commit()
|
|
778
|
-
except BaseException:
|
|
779
|
-
try:
|
|
780
|
-
await service.rollback()
|
|
781
|
-
except Exception:
|
|
782
|
-
logger.debug("Rollback after a failed commit also failed", exc_info=True)
|
|
783
|
-
raise
|
|
784
|
-
return False
|
|
785
|
-
finally:
|
|
786
|
-
if session._transaction_depth > 0:
|
|
787
|
-
session._transaction_depth -= 1
|
|
788
|
-
state.driver = None
|
|
789
|
-
if service._transaction_state is state:
|
|
790
|
-
service._transaction_state = None
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
class _SyncBeginTransactionContext(Generic[SyncDriverT]):
|
|
794
|
-
__slots__ = ("_nested", "_service", "_stack", "_state")
|
|
795
|
-
|
|
796
|
-
def __init__(self, service: "SQLSpecSyncService[SyncDriverT]") -> None:
|
|
797
|
-
self._service = service
|
|
798
|
-
self._stack: ExitStack | None = None
|
|
799
|
-
self._state: _TransactionState | None = None
|
|
800
|
-
self._nested: Any = None
|
|
801
|
-
|
|
802
|
-
def __enter__(self) -> SyncDriverT:
|
|
803
|
-
service = self._service
|
|
804
|
-
if service._config is None:
|
|
805
|
-
active = _session_transaction(service._transaction_state)
|
|
806
|
-
session = service.session
|
|
807
|
-
if active is not None or session._transaction_depth > 0:
|
|
808
|
-
nested = session.transaction()
|
|
809
|
-
nested.__enter__()
|
|
810
|
-
self._nested = nested
|
|
811
|
-
return session
|
|
812
|
-
if not _connection_in_transaction(session):
|
|
813
|
-
service.begin()
|
|
814
|
-
session._transaction_depth += 1
|
|
815
|
-
state = _TransactionState(session)
|
|
816
|
-
service._transaction_state = state
|
|
817
|
-
self._state = state
|
|
818
|
-
return session
|
|
819
|
-
key = service._transaction_key
|
|
820
|
-
live = _live_transaction(key)
|
|
821
|
-
if live is not None:
|
|
822
|
-
driver = cast("SyncDriverT", live.driver)
|
|
823
|
-
nested = driver.transaction()
|
|
824
|
-
nested.__enter__()
|
|
825
|
-
self._nested = nested
|
|
826
|
-
return driver
|
|
827
|
-
stack = ExitStack()
|
|
828
|
-
try:
|
|
829
|
-
driver = stack.enter_context(service.provide_session())
|
|
830
|
-
stack.enter_context(driver.transaction())
|
|
831
|
-
state, token = _bind_transaction(key, driver)
|
|
832
|
-
stack.callback(_release_transaction, state, token)
|
|
833
|
-
except BaseException:
|
|
834
|
-
stack.__exit__(*sys.exc_info())
|
|
835
|
-
raise
|
|
836
|
-
self._stack = stack
|
|
837
|
-
self._state = state
|
|
838
|
-
return driver
|
|
839
|
-
|
|
840
|
-
def __exit__(
|
|
841
|
-
self, exc_type: "type[BaseException] | None", exc: "BaseException | None", traceback: "TracebackType | None"
|
|
842
|
-
) -> "Literal[False]":
|
|
843
|
-
service = self._service
|
|
844
|
-
nested = self._nested
|
|
845
|
-
state = self._state
|
|
846
|
-
stack = self._stack
|
|
847
|
-
self._nested = None
|
|
848
|
-
self._state = None
|
|
849
|
-
self._stack = None
|
|
850
|
-
if nested is not None:
|
|
851
|
-
nested.__exit__(exc_type, exc, traceback)
|
|
852
|
-
return False
|
|
853
|
-
if stack is not None:
|
|
854
|
-
stack.__exit__(exc_type, exc, traceback)
|
|
855
|
-
return False
|
|
856
|
-
if state is None:
|
|
857
|
-
return False
|
|
858
|
-
session = cast("SyncDriverAdapterBase", state.driver)
|
|
859
|
-
try:
|
|
860
|
-
if exc_type is not None:
|
|
861
|
-
service.rollback()
|
|
862
|
-
return False
|
|
863
|
-
try:
|
|
864
|
-
service.commit()
|
|
865
|
-
except BaseException:
|
|
866
|
-
try:
|
|
867
|
-
service.rollback()
|
|
868
|
-
except Exception:
|
|
869
|
-
logger.debug("Rollback after a failed commit also failed", exc_info=True)
|
|
870
|
-
raise
|
|
871
|
-
return False
|
|
872
|
-
finally:
|
|
873
|
-
if session._transaction_depth > 0:
|
|
874
|
-
session._transaction_depth -= 1
|
|
875
|
-
state.driver = None
|
|
876
|
-
if service._transaction_state is state:
|
|
877
|
-
service._transaction_state = None
|
sqlspec/service/_core.py
ADDED
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
"""Compiled query and transaction runtime for the Python service bases."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import sys
|
|
5
|
+
from contextlib import AbstractAsyncContextManager, AbstractContextManager, AsyncExitStack, ExitStack
|
|
6
|
+
from contextvars import ContextVar, Token
|
|
7
|
+
from threading import get_ident
|
|
8
|
+
from typing import TYPE_CHECKING, Any, Generic, Literal, cast
|
|
9
|
+
|
|
10
|
+
from typing_extensions import TypeVar
|
|
11
|
+
|
|
12
|
+
from sqlspec.core import OffsetPagination
|
|
13
|
+
from sqlspec.core.filters import LimitOffsetFilter
|
|
14
|
+
from sqlspec.driver._async import AsyncDriverAdapterBase
|
|
15
|
+
from sqlspec.driver._sync import SyncDriverAdapterBase
|
|
16
|
+
from sqlspec.exceptions import ImproperConfigurationError, NotFoundError
|
|
17
|
+
from sqlspec.utils.logging import get_logger
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from types import TracebackType
|
|
21
|
+
|
|
22
|
+
from sqlspec.builder import QueryBuilder
|
|
23
|
+
from sqlspec.core.filters import StatementFilter
|
|
24
|
+
from sqlspec.core.statement import Statement
|
|
25
|
+
from sqlspec.service import SQLSpecAsyncService, SQLSpecSyncService
|
|
26
|
+
from sqlspec.typing import SchemaT, StatementParameters
|
|
27
|
+
|
|
28
|
+
AsyncDriverT = TypeVar("AsyncDriverT", bound=AsyncDriverAdapterBase, default=AsyncDriverAdapterBase)
|
|
29
|
+
SyncDriverT = TypeVar("SyncDriverT", bound=SyncDriverAdapterBase, default=SyncDriverAdapterBase)
|
|
30
|
+
|
|
31
|
+
logger = get_logger("sqlspec.service")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _execution_owner() -> tuple[int, object]:
|
|
35
|
+
try:
|
|
36
|
+
task = asyncio.current_task()
|
|
37
|
+
except RuntimeError:
|
|
38
|
+
task = None
|
|
39
|
+
return get_ident(), task
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _owner_identity(owner: tuple[int, object]) -> tuple[int, int]:
|
|
43
|
+
return owner[0], id(owner[1])
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class _TransactionState:
|
|
47
|
+
__slots__ = ("driver", "origin", "owner")
|
|
48
|
+
|
|
49
|
+
def __init__(self, driver: AsyncDriverAdapterBase | SyncDriverAdapterBase) -> None:
|
|
50
|
+
self.driver: AsyncDriverAdapterBase | SyncDriverAdapterBase | None = driver
|
|
51
|
+
self.owner = _execution_owner()
|
|
52
|
+
self.origin = _owner_identity(self.owner)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
_TRANSACTIONS: ContextVar[dict[object, _TransactionState] | None] = ContextVar(
|
|
56
|
+
"sqlspec_service_transactions", default=None
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
async def _async_paginate(
|
|
61
|
+
context: AbstractAsyncContextManager[AsyncDriverAdapterBase],
|
|
62
|
+
statement: "Statement | QueryBuilder",
|
|
63
|
+
parameters: "tuple[StatementParameters | StatementFilter, ...]",
|
|
64
|
+
schema_type: "type[SchemaT] | None",
|
|
65
|
+
count_with_window: bool,
|
|
66
|
+
kwargs: dict[str, Any],
|
|
67
|
+
) -> "OffsetPagination[SchemaT] | OffsetPagination[dict[str, Any]]":
|
|
68
|
+
"""Execute the async service paginate operation in the supplied session context."""
|
|
69
|
+
async with context as driver:
|
|
70
|
+
limit_offset: LimitOffsetFilter | None = driver.find_filter(LimitOffsetFilter, parameters)
|
|
71
|
+
|
|
72
|
+
items, total = await driver.select_with_total(
|
|
73
|
+
statement, *parameters, schema_type=schema_type, count_with_window=count_with_window, **kwargs
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
if schema_type is None:
|
|
77
|
+
return OffsetPagination(
|
|
78
|
+
items=cast("list[dict[str, Any]]", items),
|
|
79
|
+
limit=limit_offset.limit if limit_offset is not None else len(items),
|
|
80
|
+
offset=limit_offset.offset if limit_offset is not None else 0,
|
|
81
|
+
total=total,
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
return OffsetPagination(
|
|
85
|
+
items=cast("list[SchemaT]", items),
|
|
86
|
+
limit=limit_offset.limit if limit_offset is not None else len(items),
|
|
87
|
+
offset=limit_offset.offset if limit_offset is not None else 0,
|
|
88
|
+
total=total,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
async def _async_get_one(
|
|
93
|
+
context: AbstractAsyncContextManager[AsyncDriverAdapterBase],
|
|
94
|
+
statement: "Statement | QueryBuilder",
|
|
95
|
+
parameters: "tuple[StatementParameters | StatementFilter, ...]",
|
|
96
|
+
schema_type: "type[SchemaT] | None",
|
|
97
|
+
error_message: str | None,
|
|
98
|
+
kwargs: dict[str, Any],
|
|
99
|
+
) -> "SchemaT | dict[str, Any]":
|
|
100
|
+
"""Execute the async service get_one operation in the supplied session context."""
|
|
101
|
+
async with context as driver:
|
|
102
|
+
result = await driver.select_one_or_none(statement, *parameters, schema_type=schema_type, **kwargs)
|
|
103
|
+
if result is None:
|
|
104
|
+
raise NotFoundError(error_message or "Record not found")
|
|
105
|
+
return result
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
async def _async_exists(
|
|
109
|
+
context: AbstractAsyncContextManager[AsyncDriverAdapterBase],
|
|
110
|
+
statement: "Statement | QueryBuilder",
|
|
111
|
+
parameters: "tuple[StatementParameters | StatementFilter, ...]",
|
|
112
|
+
kwargs: dict[str, Any],
|
|
113
|
+
) -> bool:
|
|
114
|
+
"""Execute the async service exists operation in the supplied session context."""
|
|
115
|
+
async with context as driver:
|
|
116
|
+
return await driver.select_one_or_none(statement, *parameters, **kwargs) is not None
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _sync_paginate(
|
|
120
|
+
context: AbstractContextManager[SyncDriverAdapterBase],
|
|
121
|
+
statement: "Statement | QueryBuilder",
|
|
122
|
+
parameters: "tuple[StatementParameters | StatementFilter, ...]",
|
|
123
|
+
schema_type: "type[SchemaT] | None",
|
|
124
|
+
count_with_window: bool,
|
|
125
|
+
kwargs: dict[str, Any],
|
|
126
|
+
) -> "OffsetPagination[SchemaT] | OffsetPagination[dict[str, Any]]":
|
|
127
|
+
"""Execute the sync service paginate operation in the supplied session context."""
|
|
128
|
+
with context as driver:
|
|
129
|
+
limit_offset: LimitOffsetFilter | None = driver.find_filter(LimitOffsetFilter, parameters)
|
|
130
|
+
|
|
131
|
+
items, total = driver.select_with_total(
|
|
132
|
+
statement, *parameters, schema_type=schema_type, count_with_window=count_with_window, **kwargs
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
if schema_type is None:
|
|
136
|
+
return OffsetPagination(
|
|
137
|
+
items=cast("list[dict[str, Any]]", items),
|
|
138
|
+
limit=limit_offset.limit if limit_offset is not None else len(items),
|
|
139
|
+
offset=limit_offset.offset if limit_offset is not None else 0,
|
|
140
|
+
total=total,
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
return OffsetPagination(
|
|
144
|
+
items=cast("list[SchemaT]", items),
|
|
145
|
+
limit=limit_offset.limit if limit_offset is not None else len(items),
|
|
146
|
+
offset=limit_offset.offset if limit_offset is not None else 0,
|
|
147
|
+
total=total,
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def _sync_get_one(
|
|
152
|
+
context: AbstractContextManager[SyncDriverAdapterBase],
|
|
153
|
+
statement: "Statement | QueryBuilder",
|
|
154
|
+
parameters: "tuple[StatementParameters | StatementFilter, ...]",
|
|
155
|
+
schema_type: "type[SchemaT] | None",
|
|
156
|
+
error_message: str | None,
|
|
157
|
+
kwargs: dict[str, Any],
|
|
158
|
+
) -> "SchemaT | dict[str, Any]":
|
|
159
|
+
"""Execute the sync service get_one operation in the supplied session context."""
|
|
160
|
+
with context as driver:
|
|
161
|
+
result = driver.select_one_or_none(statement, *parameters, schema_type=schema_type, **kwargs)
|
|
162
|
+
if result is None:
|
|
163
|
+
raise NotFoundError(error_message or "Record not found")
|
|
164
|
+
return result
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def _sync_exists(
|
|
168
|
+
context: AbstractContextManager[SyncDriverAdapterBase],
|
|
169
|
+
statement: "Statement | QueryBuilder",
|
|
170
|
+
parameters: "tuple[StatementParameters | StatementFilter, ...]",
|
|
171
|
+
kwargs: dict[str, Any],
|
|
172
|
+
) -> bool:
|
|
173
|
+
"""Execute the sync service exists operation in the supplied session context."""
|
|
174
|
+
with context as driver:
|
|
175
|
+
return driver.select_one_or_none(statement, *parameters, **kwargs) is not None
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def _active_transaction(key: object) -> _TransactionState | None:
|
|
179
|
+
state = (_TRANSACTIONS.get() or {}).get(key)
|
|
180
|
+
if state is None:
|
|
181
|
+
return None
|
|
182
|
+
if state.driver is None:
|
|
183
|
+
if state.origin == _owner_identity(_execution_owner()):
|
|
184
|
+
_discard_transaction(state)
|
|
185
|
+
return None
|
|
186
|
+
msg = "The inherited service transaction is no longer active."
|
|
187
|
+
raise ImproperConfigurationError(msg)
|
|
188
|
+
if state.owner != _execution_owner():
|
|
189
|
+
msg = "A service transaction cannot be implicitly reused by another task or thread; pass session= explicitly."
|
|
190
|
+
raise ImproperConfigurationError(msg)
|
|
191
|
+
return state
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def _live_transaction(key: object) -> _TransactionState | None:
|
|
195
|
+
current = _TRANSACTIONS.get()
|
|
196
|
+
state = None if current is None else current.get(key)
|
|
197
|
+
if state is None:
|
|
198
|
+
return None
|
|
199
|
+
if state.driver is None:
|
|
200
|
+
_discard_transaction(state)
|
|
201
|
+
return None
|
|
202
|
+
return _active_transaction(key)
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def _discard_transaction(state: _TransactionState) -> None:
|
|
206
|
+
current = _TRANSACTIONS.get()
|
|
207
|
+
if current is not None and any(value is state for value in current.values()):
|
|
208
|
+
_TRANSACTIONS.set({key: value for key, value in current.items() if value is not state} or None)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def _session_transaction(state: _TransactionState | None) -> _TransactionState | None:
|
|
212
|
+
if state is None or state.driver is None:
|
|
213
|
+
return None
|
|
214
|
+
if state.owner != _execution_owner():
|
|
215
|
+
msg = (
|
|
216
|
+
"A service transaction is active in another task or thread; nested begin_transaction() blocks must "
|
|
217
|
+
"run in the task or thread that entered the outer block."
|
|
218
|
+
)
|
|
219
|
+
raise ImproperConfigurationError(msg)
|
|
220
|
+
return state
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def _connection_in_transaction(driver: AsyncDriverAdapterBase | SyncDriverAdapterBase) -> bool:
|
|
224
|
+
try:
|
|
225
|
+
return driver._connection_in_transaction()
|
|
226
|
+
except NotImplementedError:
|
|
227
|
+
return False
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def _transaction_session(key: object) -> AsyncDriverAdapterBase | SyncDriverAdapterBase | None:
|
|
231
|
+
state = _active_transaction(key)
|
|
232
|
+
return None if state is None else state.driver
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def _bind_transaction(
|
|
236
|
+
key: object, driver: AsyncDriverAdapterBase | SyncDriverAdapterBase
|
|
237
|
+
) -> tuple[_TransactionState, Token[dict[object, _TransactionState] | None]]:
|
|
238
|
+
state = _TransactionState(driver)
|
|
239
|
+
token = _TRANSACTIONS.set({**(_TRANSACTIONS.get() or {}), key: state})
|
|
240
|
+
return state, token
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def _release_transaction(state: _TransactionState, token: Token[dict[object, _TransactionState] | None]) -> None:
|
|
244
|
+
state.driver = None
|
|
245
|
+
state.owner = (0, None)
|
|
246
|
+
try:
|
|
247
|
+
_TRANSACTIONS.reset(token)
|
|
248
|
+
except ValueError:
|
|
249
|
+
_discard_transaction(state)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
class _AsyncBeginTransactionContext(Generic[AsyncDriverT]):
|
|
253
|
+
__slots__ = ("_nested", "_service", "_stack", "_state")
|
|
254
|
+
|
|
255
|
+
def __init__(self, service: "SQLSpecAsyncService[AsyncDriverT]") -> None:
|
|
256
|
+
self._service = service
|
|
257
|
+
self._stack: AsyncExitStack | None = None
|
|
258
|
+
self._state: _TransactionState | None = None
|
|
259
|
+
self._nested: Any = None
|
|
260
|
+
|
|
261
|
+
async def __aenter__(self) -> AsyncDriverT:
|
|
262
|
+
service = self._service
|
|
263
|
+
if service._config is None:
|
|
264
|
+
active = _session_transaction(service._transaction_state)
|
|
265
|
+
session = service.session
|
|
266
|
+
if active is not None or session._transaction_depth > 0:
|
|
267
|
+
nested = session.transaction()
|
|
268
|
+
await nested.__aenter__()
|
|
269
|
+
self._nested = nested
|
|
270
|
+
return session
|
|
271
|
+
if not _connection_in_transaction(session):
|
|
272
|
+
await service.begin()
|
|
273
|
+
session._transaction_depth += 1
|
|
274
|
+
state = _TransactionState(session)
|
|
275
|
+
service._transaction_state = state
|
|
276
|
+
self._state = state
|
|
277
|
+
return session
|
|
278
|
+
key = service._transaction_key
|
|
279
|
+
live = _live_transaction(key)
|
|
280
|
+
if live is not None:
|
|
281
|
+
driver = cast("AsyncDriverT", live.driver)
|
|
282
|
+
nested = driver.transaction()
|
|
283
|
+
await nested.__aenter__()
|
|
284
|
+
self._nested = nested
|
|
285
|
+
return driver
|
|
286
|
+
stack = AsyncExitStack()
|
|
287
|
+
try:
|
|
288
|
+
driver = await stack.enter_async_context(service.provide_session())
|
|
289
|
+
await stack.enter_async_context(driver.transaction())
|
|
290
|
+
state, token = _bind_transaction(key, driver)
|
|
291
|
+
stack.callback(_release_transaction, state, token)
|
|
292
|
+
except BaseException:
|
|
293
|
+
await stack.__aexit__(*sys.exc_info())
|
|
294
|
+
raise
|
|
295
|
+
self._stack = stack
|
|
296
|
+
self._state = state
|
|
297
|
+
return driver
|
|
298
|
+
|
|
299
|
+
async def __aexit__(
|
|
300
|
+
self, exc_type: "type[BaseException] | None", exc: "BaseException | None", traceback: "TracebackType | None"
|
|
301
|
+
) -> "Literal[False]":
|
|
302
|
+
service = self._service
|
|
303
|
+
nested = self._nested
|
|
304
|
+
state = self._state
|
|
305
|
+
stack = self._stack
|
|
306
|
+
self._nested = None
|
|
307
|
+
self._state = None
|
|
308
|
+
self._stack = None
|
|
309
|
+
if nested is not None:
|
|
310
|
+
await nested.__aexit__(exc_type, exc, traceback)
|
|
311
|
+
return False
|
|
312
|
+
if stack is not None:
|
|
313
|
+
await stack.__aexit__(exc_type, exc, traceback)
|
|
314
|
+
return False
|
|
315
|
+
if state is None:
|
|
316
|
+
return False
|
|
317
|
+
session = cast("AsyncDriverAdapterBase", state.driver)
|
|
318
|
+
try:
|
|
319
|
+
if exc_type is not None:
|
|
320
|
+
await service.rollback()
|
|
321
|
+
return False
|
|
322
|
+
try:
|
|
323
|
+
await service.commit()
|
|
324
|
+
except BaseException:
|
|
325
|
+
try:
|
|
326
|
+
await service.rollback()
|
|
327
|
+
except Exception:
|
|
328
|
+
logger.debug("Rollback after a failed commit also failed", exc_info=True)
|
|
329
|
+
raise
|
|
330
|
+
return False
|
|
331
|
+
finally:
|
|
332
|
+
if session._transaction_depth > 0:
|
|
333
|
+
session._transaction_depth -= 1
|
|
334
|
+
state.driver = None
|
|
335
|
+
if service._transaction_state is state:
|
|
336
|
+
service._transaction_state = None
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
class _SyncBeginTransactionContext(Generic[SyncDriverT]):
|
|
340
|
+
__slots__ = ("_nested", "_service", "_stack", "_state")
|
|
341
|
+
|
|
342
|
+
def __init__(self, service: "SQLSpecSyncService[SyncDriverT]") -> None:
|
|
343
|
+
self._service = service
|
|
344
|
+
self._stack: ExitStack | None = None
|
|
345
|
+
self._state: _TransactionState | None = None
|
|
346
|
+
self._nested: Any = None
|
|
347
|
+
|
|
348
|
+
def __enter__(self) -> SyncDriverT:
|
|
349
|
+
service = self._service
|
|
350
|
+
if service._config is None:
|
|
351
|
+
active = _session_transaction(service._transaction_state)
|
|
352
|
+
session = service.session
|
|
353
|
+
if active is not None or session._transaction_depth > 0:
|
|
354
|
+
nested = session.transaction()
|
|
355
|
+
nested.__enter__()
|
|
356
|
+
self._nested = nested
|
|
357
|
+
return session
|
|
358
|
+
if not _connection_in_transaction(session):
|
|
359
|
+
service.begin()
|
|
360
|
+
session._transaction_depth += 1
|
|
361
|
+
state = _TransactionState(session)
|
|
362
|
+
service._transaction_state = state
|
|
363
|
+
self._state = state
|
|
364
|
+
return session
|
|
365
|
+
key = service._transaction_key
|
|
366
|
+
live = _live_transaction(key)
|
|
367
|
+
if live is not None:
|
|
368
|
+
driver = cast("SyncDriverT", live.driver)
|
|
369
|
+
nested = driver.transaction()
|
|
370
|
+
nested.__enter__()
|
|
371
|
+
self._nested = nested
|
|
372
|
+
return driver
|
|
373
|
+
stack = ExitStack()
|
|
374
|
+
try:
|
|
375
|
+
driver = stack.enter_context(service.provide_session())
|
|
376
|
+
stack.enter_context(driver.transaction())
|
|
377
|
+
state, token = _bind_transaction(key, driver)
|
|
378
|
+
stack.callback(_release_transaction, state, token)
|
|
379
|
+
except BaseException:
|
|
380
|
+
stack.__exit__(*sys.exc_info())
|
|
381
|
+
raise
|
|
382
|
+
self._stack = stack
|
|
383
|
+
self._state = state
|
|
384
|
+
return driver
|
|
385
|
+
|
|
386
|
+
def __exit__(
|
|
387
|
+
self, exc_type: "type[BaseException] | None", exc: "BaseException | None", traceback: "TracebackType | None"
|
|
388
|
+
) -> "Literal[False]":
|
|
389
|
+
service = self._service
|
|
390
|
+
nested = self._nested
|
|
391
|
+
state = self._state
|
|
392
|
+
stack = self._stack
|
|
393
|
+
self._nested = None
|
|
394
|
+
self._state = None
|
|
395
|
+
self._stack = None
|
|
396
|
+
if nested is not None:
|
|
397
|
+
nested.__exit__(exc_type, exc, traceback)
|
|
398
|
+
return False
|
|
399
|
+
if stack is not None:
|
|
400
|
+
stack.__exit__(exc_type, exc, traceback)
|
|
401
|
+
return False
|
|
402
|
+
if state is None:
|
|
403
|
+
return False
|
|
404
|
+
session = cast("SyncDriverAdapterBase", state.driver)
|
|
405
|
+
try:
|
|
406
|
+
if exc_type is not None:
|
|
407
|
+
service.rollback()
|
|
408
|
+
return False
|
|
409
|
+
try:
|
|
410
|
+
service.commit()
|
|
411
|
+
except BaseException:
|
|
412
|
+
try:
|
|
413
|
+
service.rollback()
|
|
414
|
+
except Exception:
|
|
415
|
+
logger.debug("Rollback after a failed commit also failed", exc_info=True)
|
|
416
|
+
raise
|
|
417
|
+
return False
|
|
418
|
+
finally:
|
|
419
|
+
if session._transaction_depth > 0:
|
|
420
|
+
session._transaction_depth -= 1
|
|
421
|
+
state.driver = None
|
|
422
|
+
if service._transaction_state is state:
|
|
423
|
+
service._transaction_state = None
|
|
@@ -9,7 +9,6 @@ sqlspec/exceptions.py,sha256=RjCfh90cUJuh4wmAgSzb6KvKhCMknM6a--Xsffq8OkM,16194
|
|
|
9
9
|
sqlspec/loader.py,sha256=CsyQrkRplxmMLVKW1WeGMKUlGZftk_JyW-wrP8CAexo,65609
|
|
10
10
|
sqlspec/protocols.py,sha256=Yyag7aGdyUi6JDSDJwbt-rMrooy3ezQ1PjsJm0UVjgE,33966
|
|
11
11
|
sqlspec/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
-
sqlspec/service.py,sha256=GeHviEoJxWraMnIvONGbcsUvYcZBcWJWoNqdU5Hvnvg,33295
|
|
13
12
|
sqlspec/typing.py,sha256=L3AhW4Xr0uYuaIlghGzcgznwEto8UGy6Qbnb9yrf6-k,6380
|
|
14
13
|
sqlspec/adapters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
14
|
sqlspec/adapters/adbc/__init__.py,sha256=iwWnfPYTR0c0uFQZAKbeVt0-W-9soyuhSd7On8QomEo,410
|
|
@@ -635,6 +634,9 @@ sqlspec/observability/_formatters/_aws.py,sha256=ZVIc3s2JI7Gpgwcpa3NtXVZf2GSDMaj
|
|
|
635
634
|
sqlspec/observability/_formatters/_azure.py,sha256=Om13FLalqhtlDJjVUdHQnTzDBP0cVdJp3TXlCraF0mM,2498
|
|
636
635
|
sqlspec/observability/_formatters/_base.py,sha256=a0Th_NkyAB0iBH61tXHyvVZPrj4RMLJ9_ADvCpuzMgo,1202
|
|
637
636
|
sqlspec/observability/_formatters/_gcp.py,sha256=Nek2Nt8kqJ4fDy6qwPcHUMPITtDa6xLQA6VxotmCeFk,4067
|
|
637
|
+
sqlspec/service/__init__.py,sha256=aRsQimIvairp_rUJPNevlRpCKAr17FClxKYwyQanLhY,212
|
|
638
|
+
sqlspec/service/_base.py,sha256=6Lqp8Mq394p61uIK20rbwmHdk65424ArHomx2HerZ-Y,20992
|
|
639
|
+
sqlspec/service/_core.py,sha256=l-G57o3iV-ZIfqEz7AFDZxP4ICEAam_Dfh8SHpEcckc,16211
|
|
638
640
|
sqlspec/storage/__init__.py,sha256=KXu6tW_7WCM-djHPXPSgmiUPROxsCxO1W4G17tUdnU8,1281
|
|
639
641
|
sqlspec/storage/_arrow_payload.py,sha256=kAt7ciGlFZFeuWFF4ddkSPrKWIZ2MQc3y2PRvjqnPnM,2738
|
|
640
642
|
sqlspec/storage/_arrow_stream.py,sha256=pwjTfpiAKyPB9LGyx6anGUl5TKj0qdFwZAjlajHl6Dw,2117
|
|
@@ -669,8 +671,8 @@ sqlspec/utils/serializers/__init__.py,sha256=X99t8YMHVGmKwrqPxumnSXu4JMJL8SpKoU7
|
|
|
669
671
|
sqlspec/utils/serializers/_json.py,sha256=5PBan5kHoDAGqbOqT33SdEK17VZzNjzZKneWI_BnDzY,18136
|
|
670
672
|
sqlspec/utils/serializers/_numpy.py,sha256=_LllCtVn_gyLrRG2naHM7Unjtpot86BPTvGPlZuAGRw,1742
|
|
671
673
|
sqlspec/utils/serializers/_schema.py,sha256=kN8lW8GJa08yMi_qN_x8A7XpO7V6aAaoYqKq72rxaCk,11416
|
|
672
|
-
sqlspec-0.63.
|
|
673
|
-
sqlspec-0.63.
|
|
674
|
-
sqlspec-0.63.
|
|
675
|
-
sqlspec-0.63.
|
|
676
|
-
sqlspec-0.63.
|
|
674
|
+
sqlspec-0.63.1.dist-info/METADATA,sha256=wdAq669tcEN-ef6HgWYOfDuHE088KHXaP3ipj31WeTY,9080
|
|
675
|
+
sqlspec-0.63.1.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
|
|
676
|
+
sqlspec-0.63.1.dist-info/entry_points.txt,sha256=Odw9xs3HsdFEuJXZ_GE0iemkXwkPQzn1w16PuIYDpqc,459
|
|
677
|
+
sqlspec-0.63.1.dist-info/licenses/LICENSE,sha256=MdujfZ6l5HuLz4mElxlu049itenOR3gnhN1_Nd3nVcM,1078
|
|
678
|
+
sqlspec-0.63.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|