sqlspec 0.26.0__py3-none-any.whl → 0.28.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 sqlspec might be problematic. Click here for more details.

Files changed (212) hide show
  1. sqlspec/__init__.py +7 -15
  2. sqlspec/_serialization.py +55 -25
  3. sqlspec/_typing.py +155 -52
  4. sqlspec/adapters/adbc/_types.py +1 -1
  5. sqlspec/adapters/adbc/adk/__init__.py +5 -0
  6. sqlspec/adapters/adbc/adk/store.py +880 -0
  7. sqlspec/adapters/adbc/config.py +62 -12
  8. sqlspec/adapters/adbc/data_dictionary.py +74 -2
  9. sqlspec/adapters/adbc/driver.py +226 -58
  10. sqlspec/adapters/adbc/litestar/__init__.py +5 -0
  11. sqlspec/adapters/adbc/litestar/store.py +504 -0
  12. sqlspec/adapters/adbc/type_converter.py +44 -50
  13. sqlspec/adapters/aiosqlite/_types.py +1 -1
  14. sqlspec/adapters/aiosqlite/adk/__init__.py +5 -0
  15. sqlspec/adapters/aiosqlite/adk/store.py +536 -0
  16. sqlspec/adapters/aiosqlite/config.py +86 -16
  17. sqlspec/adapters/aiosqlite/data_dictionary.py +34 -2
  18. sqlspec/adapters/aiosqlite/driver.py +127 -38
  19. sqlspec/adapters/aiosqlite/litestar/__init__.py +5 -0
  20. sqlspec/adapters/aiosqlite/litestar/store.py +281 -0
  21. sqlspec/adapters/aiosqlite/pool.py +7 -7
  22. sqlspec/adapters/asyncmy/__init__.py +7 -1
  23. sqlspec/adapters/asyncmy/_types.py +1 -1
  24. sqlspec/adapters/asyncmy/adk/__init__.py +5 -0
  25. sqlspec/adapters/asyncmy/adk/store.py +503 -0
  26. sqlspec/adapters/asyncmy/config.py +59 -17
  27. sqlspec/adapters/asyncmy/data_dictionary.py +41 -2
  28. sqlspec/adapters/asyncmy/driver.py +293 -62
  29. sqlspec/adapters/asyncmy/litestar/__init__.py +5 -0
  30. sqlspec/adapters/asyncmy/litestar/store.py +296 -0
  31. sqlspec/adapters/asyncpg/__init__.py +2 -1
  32. sqlspec/adapters/asyncpg/_type_handlers.py +71 -0
  33. sqlspec/adapters/asyncpg/_types.py +11 -7
  34. sqlspec/adapters/asyncpg/adk/__init__.py +5 -0
  35. sqlspec/adapters/asyncpg/adk/store.py +460 -0
  36. sqlspec/adapters/asyncpg/config.py +57 -36
  37. sqlspec/adapters/asyncpg/data_dictionary.py +48 -2
  38. sqlspec/adapters/asyncpg/driver.py +153 -23
  39. sqlspec/adapters/asyncpg/litestar/__init__.py +5 -0
  40. sqlspec/adapters/asyncpg/litestar/store.py +253 -0
  41. sqlspec/adapters/bigquery/_types.py +1 -1
  42. sqlspec/adapters/bigquery/adk/__init__.py +5 -0
  43. sqlspec/adapters/bigquery/adk/store.py +585 -0
  44. sqlspec/adapters/bigquery/config.py +36 -11
  45. sqlspec/adapters/bigquery/data_dictionary.py +42 -2
  46. sqlspec/adapters/bigquery/driver.py +489 -144
  47. sqlspec/adapters/bigquery/litestar/__init__.py +5 -0
  48. sqlspec/adapters/bigquery/litestar/store.py +327 -0
  49. sqlspec/adapters/bigquery/type_converter.py +55 -23
  50. sqlspec/adapters/duckdb/_types.py +2 -2
  51. sqlspec/adapters/duckdb/adk/__init__.py +14 -0
  52. sqlspec/adapters/duckdb/adk/store.py +563 -0
  53. sqlspec/adapters/duckdb/config.py +79 -21
  54. sqlspec/adapters/duckdb/data_dictionary.py +41 -2
  55. sqlspec/adapters/duckdb/driver.py +225 -44
  56. sqlspec/adapters/duckdb/litestar/__init__.py +5 -0
  57. sqlspec/adapters/duckdb/litestar/store.py +332 -0
  58. sqlspec/adapters/duckdb/pool.py +5 -5
  59. sqlspec/adapters/duckdb/type_converter.py +51 -21
  60. sqlspec/adapters/oracledb/_numpy_handlers.py +133 -0
  61. sqlspec/adapters/oracledb/_types.py +20 -2
  62. sqlspec/adapters/oracledb/adk/__init__.py +5 -0
  63. sqlspec/adapters/oracledb/adk/store.py +1628 -0
  64. sqlspec/adapters/oracledb/config.py +120 -36
  65. sqlspec/adapters/oracledb/data_dictionary.py +87 -20
  66. sqlspec/adapters/oracledb/driver.py +475 -86
  67. sqlspec/adapters/oracledb/litestar/__init__.py +5 -0
  68. sqlspec/adapters/oracledb/litestar/store.py +765 -0
  69. sqlspec/adapters/oracledb/migrations.py +316 -25
  70. sqlspec/adapters/oracledb/type_converter.py +91 -16
  71. sqlspec/adapters/psqlpy/_type_handlers.py +44 -0
  72. sqlspec/adapters/psqlpy/_types.py +2 -1
  73. sqlspec/adapters/psqlpy/adk/__init__.py +5 -0
  74. sqlspec/adapters/psqlpy/adk/store.py +483 -0
  75. sqlspec/adapters/psqlpy/config.py +45 -19
  76. sqlspec/adapters/psqlpy/data_dictionary.py +48 -2
  77. sqlspec/adapters/psqlpy/driver.py +108 -41
  78. sqlspec/adapters/psqlpy/litestar/__init__.py +5 -0
  79. sqlspec/adapters/psqlpy/litestar/store.py +272 -0
  80. sqlspec/adapters/psqlpy/type_converter.py +40 -11
  81. sqlspec/adapters/psycopg/_type_handlers.py +80 -0
  82. sqlspec/adapters/psycopg/_types.py +2 -1
  83. sqlspec/adapters/psycopg/adk/__init__.py +5 -0
  84. sqlspec/adapters/psycopg/adk/store.py +962 -0
  85. sqlspec/adapters/psycopg/config.py +65 -37
  86. sqlspec/adapters/psycopg/data_dictionary.py +91 -3
  87. sqlspec/adapters/psycopg/driver.py +200 -78
  88. sqlspec/adapters/psycopg/litestar/__init__.py +5 -0
  89. sqlspec/adapters/psycopg/litestar/store.py +554 -0
  90. sqlspec/adapters/sqlite/__init__.py +2 -1
  91. sqlspec/adapters/sqlite/_type_handlers.py +86 -0
  92. sqlspec/adapters/sqlite/_types.py +1 -1
  93. sqlspec/adapters/sqlite/adk/__init__.py +5 -0
  94. sqlspec/adapters/sqlite/adk/store.py +582 -0
  95. sqlspec/adapters/sqlite/config.py +85 -16
  96. sqlspec/adapters/sqlite/data_dictionary.py +34 -2
  97. sqlspec/adapters/sqlite/driver.py +120 -52
  98. sqlspec/adapters/sqlite/litestar/__init__.py +5 -0
  99. sqlspec/adapters/sqlite/litestar/store.py +318 -0
  100. sqlspec/adapters/sqlite/pool.py +5 -5
  101. sqlspec/base.py +45 -26
  102. sqlspec/builder/__init__.py +73 -4
  103. sqlspec/builder/_base.py +91 -58
  104. sqlspec/builder/_column.py +5 -5
  105. sqlspec/builder/_ddl.py +98 -89
  106. sqlspec/builder/_delete.py +5 -4
  107. sqlspec/builder/_dml.py +388 -0
  108. sqlspec/{_sql.py → builder/_factory.py} +41 -44
  109. sqlspec/builder/_insert.py +5 -82
  110. sqlspec/builder/{mixins/_join_operations.py → _join.py} +145 -143
  111. sqlspec/builder/_merge.py +446 -11
  112. sqlspec/builder/_parsing_utils.py +9 -11
  113. sqlspec/builder/_select.py +1313 -25
  114. sqlspec/builder/_update.py +11 -42
  115. sqlspec/cli.py +76 -69
  116. sqlspec/config.py +331 -62
  117. sqlspec/core/__init__.py +5 -4
  118. sqlspec/core/cache.py +18 -18
  119. sqlspec/core/compiler.py +6 -8
  120. sqlspec/core/filters.py +55 -47
  121. sqlspec/core/hashing.py +9 -9
  122. sqlspec/core/parameters.py +76 -45
  123. sqlspec/core/result.py +234 -47
  124. sqlspec/core/splitter.py +16 -17
  125. sqlspec/core/statement.py +32 -31
  126. sqlspec/core/type_conversion.py +3 -2
  127. sqlspec/driver/__init__.py +1 -3
  128. sqlspec/driver/_async.py +183 -160
  129. sqlspec/driver/_common.py +197 -109
  130. sqlspec/driver/_sync.py +189 -161
  131. sqlspec/driver/mixins/_result_tools.py +20 -236
  132. sqlspec/driver/mixins/_sql_translator.py +4 -4
  133. sqlspec/exceptions.py +70 -7
  134. sqlspec/extensions/adk/__init__.py +53 -0
  135. sqlspec/extensions/adk/_types.py +51 -0
  136. sqlspec/extensions/adk/converters.py +172 -0
  137. sqlspec/extensions/adk/migrations/0001_create_adk_tables.py +144 -0
  138. sqlspec/extensions/adk/migrations/__init__.py +0 -0
  139. sqlspec/extensions/adk/service.py +181 -0
  140. sqlspec/extensions/adk/store.py +536 -0
  141. sqlspec/extensions/aiosql/adapter.py +69 -61
  142. sqlspec/extensions/fastapi/__init__.py +21 -0
  143. sqlspec/extensions/fastapi/extension.py +331 -0
  144. sqlspec/extensions/fastapi/providers.py +543 -0
  145. sqlspec/extensions/flask/__init__.py +36 -0
  146. sqlspec/extensions/flask/_state.py +71 -0
  147. sqlspec/extensions/flask/_utils.py +40 -0
  148. sqlspec/extensions/flask/extension.py +389 -0
  149. sqlspec/extensions/litestar/__init__.py +21 -4
  150. sqlspec/extensions/litestar/cli.py +54 -10
  151. sqlspec/extensions/litestar/config.py +56 -266
  152. sqlspec/extensions/litestar/handlers.py +46 -17
  153. sqlspec/extensions/litestar/migrations/0001_create_session_table.py +137 -0
  154. sqlspec/extensions/litestar/migrations/__init__.py +3 -0
  155. sqlspec/extensions/litestar/plugin.py +349 -224
  156. sqlspec/extensions/litestar/providers.py +25 -25
  157. sqlspec/extensions/litestar/store.py +265 -0
  158. sqlspec/extensions/starlette/__init__.py +10 -0
  159. sqlspec/extensions/starlette/_state.py +25 -0
  160. sqlspec/extensions/starlette/_utils.py +52 -0
  161. sqlspec/extensions/starlette/extension.py +254 -0
  162. sqlspec/extensions/starlette/middleware.py +154 -0
  163. sqlspec/loader.py +30 -49
  164. sqlspec/migrations/base.py +200 -76
  165. sqlspec/migrations/commands.py +591 -62
  166. sqlspec/migrations/context.py +6 -9
  167. sqlspec/migrations/fix.py +199 -0
  168. sqlspec/migrations/loaders.py +47 -19
  169. sqlspec/migrations/runner.py +241 -75
  170. sqlspec/migrations/tracker.py +237 -21
  171. sqlspec/migrations/utils.py +51 -3
  172. sqlspec/migrations/validation.py +177 -0
  173. sqlspec/protocols.py +106 -36
  174. sqlspec/storage/_utils.py +85 -0
  175. sqlspec/storage/backends/fsspec.py +133 -107
  176. sqlspec/storage/backends/local.py +78 -51
  177. sqlspec/storage/backends/obstore.py +276 -168
  178. sqlspec/storage/registry.py +75 -39
  179. sqlspec/typing.py +30 -84
  180. sqlspec/utils/__init__.py +25 -4
  181. sqlspec/utils/arrow_helpers.py +81 -0
  182. sqlspec/utils/config_resolver.py +6 -6
  183. sqlspec/utils/correlation.py +4 -5
  184. sqlspec/utils/data_transformation.py +3 -2
  185. sqlspec/utils/deprecation.py +9 -8
  186. sqlspec/utils/fixtures.py +4 -4
  187. sqlspec/utils/logging.py +46 -6
  188. sqlspec/utils/module_loader.py +205 -5
  189. sqlspec/utils/portal.py +311 -0
  190. sqlspec/utils/schema.py +288 -0
  191. sqlspec/utils/serializers.py +113 -4
  192. sqlspec/utils/sync_tools.py +36 -22
  193. sqlspec/utils/text.py +1 -2
  194. sqlspec/utils/type_guards.py +136 -20
  195. sqlspec/utils/version.py +433 -0
  196. {sqlspec-0.26.0.dist-info → sqlspec-0.28.0.dist-info}/METADATA +41 -22
  197. sqlspec-0.28.0.dist-info/RECORD +221 -0
  198. sqlspec/builder/mixins/__init__.py +0 -55
  199. sqlspec/builder/mixins/_cte_and_set_ops.py +0 -253
  200. sqlspec/builder/mixins/_delete_operations.py +0 -50
  201. sqlspec/builder/mixins/_insert_operations.py +0 -282
  202. sqlspec/builder/mixins/_merge_operations.py +0 -698
  203. sqlspec/builder/mixins/_order_limit_operations.py +0 -145
  204. sqlspec/builder/mixins/_pivot_operations.py +0 -157
  205. sqlspec/builder/mixins/_select_operations.py +0 -930
  206. sqlspec/builder/mixins/_update_operations.py +0 -199
  207. sqlspec/builder/mixins/_where_clause.py +0 -1298
  208. sqlspec-0.26.0.dist-info/RECORD +0 -157
  209. sqlspec-0.26.0.dist-info/licenses/NOTICE +0 -29
  210. {sqlspec-0.26.0.dist-info → sqlspec-0.28.0.dist-info}/WHEEL +0 -0
  211. {sqlspec-0.26.0.dist-info → sqlspec-0.28.0.dist-info}/entry_points.txt +0 -0
  212. {sqlspec-0.26.0.dist-info → sqlspec-0.28.0.dist-info}/licenses/LICENSE +0 -0
sqlspec/__init__.py CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  from sqlspec import adapters, base, builder, core, driver, exceptions, extensions, loader, migrations, typing, utils
4
4
  from sqlspec.__metadata__ import __version__
5
- from sqlspec._sql import SQLFactory, sql
6
5
  from sqlspec.base import SQLSpec
7
6
  from sqlspec.builder import (
8
7
  Column,
@@ -15,7 +14,9 @@ from sqlspec.builder import (
15
14
  Merge,
16
15
  QueryBuilder,
17
16
  Select,
17
+ SQLFactory,
18
18
  Update,
19
+ sql,
19
20
  )
20
21
  from sqlspec.config import AsyncDatabaseConfig, SyncDatabaseConfig
21
22
  from sqlspec.core import (
@@ -34,16 +35,10 @@ from sqlspec.core import (
34
35
  from sqlspec.core import filters as filters
35
36
  from sqlspec.driver import AsyncDriverAdapterBase, ExecutionResult, SyncDriverAdapterBase
36
37
  from sqlspec.loader import SQLFile, SQLFileLoader
37
- from sqlspec.typing import (
38
- ConnectionT,
39
- DictRow,
40
- ModelDTOT,
41
- ModelT,
42
- PoolT,
43
- RowT,
44
- StatementParameters,
45
- SupportedSchemaModel,
46
- )
38
+ from sqlspec.typing import ConnectionT, PoolT, SchemaT, StatementParameters, SupportedSchemaModel
39
+ from sqlspec.utils.logging import suppress_erroneous_sqlglot_log_messages
40
+
41
+ suppress_erroneous_sqlglot_log_messages()
47
42
 
48
43
  __all__ = (
49
44
  "SQL",
@@ -57,26 +52,23 @@ __all__ = (
57
52
  "ConnectionT",
58
53
  "CreateTable",
59
54
  "Delete",
60
- "DictRow",
61
55
  "DropTable",
62
56
  "ExecutionResult",
63
57
  "FunctionColumn",
64
58
  "Insert",
65
59
  "Merge",
66
- "ModelDTOT",
67
- "ModelT",
68
60
  "ParameterConverter",
69
61
  "ParameterProcessor",
70
62
  "ParameterStyle",
71
63
  "ParameterStyleConfig",
72
64
  "PoolT",
73
65
  "QueryBuilder",
74
- "RowT",
75
66
  "SQLFactory",
76
67
  "SQLFile",
77
68
  "SQLFileLoader",
78
69
  "SQLResult",
79
70
  "SQLSpec",
71
+ "SchemaT",
80
72
  "Select",
81
73
  "Statement",
82
74
  "StatementConfig",
sqlspec/_serialization.py CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  Provides a Protocol-based serialization system that users can extend.
4
4
  Supports msgspec, orjson, and standard library JSON with automatic fallback.
5
+
6
+ Features optional numpy array serialization when numpy is installed.
7
+ Arrays are automatically converted to lists during JSON encoding.
5
8
  """
6
9
 
7
10
  import contextlib
@@ -9,19 +12,25 @@ import datetime
9
12
  import enum
10
13
  import json
11
14
  from abc import ABC, abstractmethod
12
- from typing import Any, Final, Literal, Optional, Protocol, Union, overload
15
+ from typing import Any, Final, Literal, Protocol, overload
13
16
 
17
+ from sqlspec._typing import NUMPY_INSTALLED
14
18
  from sqlspec.typing import MSGSPEC_INSTALLED, ORJSON_INSTALLED, PYDANTIC_INSTALLED, BaseModel
15
19
 
16
20
 
17
- def _type_to_string(value: Any) -> str: # pragma: no cover
21
+ def _type_to_string(value: Any) -> Any: # pragma: no cover
18
22
  """Convert special types to strings for JSON serialization.
19
23
 
24
+ Handles datetime, date, enums, Pydantic models, and numpy arrays.
25
+
20
26
  Args:
21
27
  value: Value to convert.
22
28
 
23
29
  Returns:
24
- String representation of the value.
30
+ Serializable representation of the value (string, list, dict, etc.).
31
+
32
+ Raises:
33
+ TypeError: If value cannot be serialized.
25
34
  """
26
35
  if isinstance(value, datetime.datetime):
27
36
  return convert_datetime_to_gmt_iso(value)
@@ -31,10 +40,16 @@ def _type_to_string(value: Any) -> str: # pragma: no cover
31
40
  return str(value.value)
32
41
  if PYDANTIC_INSTALLED and isinstance(value, BaseModel):
33
42
  return value.model_dump_json()
43
+ if NUMPY_INSTALLED:
44
+ import numpy as np
45
+
46
+ if isinstance(value, np.ndarray):
47
+ return value.tolist()
34
48
  try:
35
49
  return str(value)
36
50
  except Exception as exc:
37
- raise TypeError from exc
51
+ msg = f"Cannot serialize {type(value).__name__}"
52
+ raise TypeError(msg) from exc
38
53
 
39
54
 
40
55
  class JSONSerializer(Protocol):
@@ -43,7 +58,7 @@ class JSONSerializer(Protocol):
43
58
  Users can implement this protocol to create custom serializers.
44
59
  """
45
60
 
46
- def encode(self, data: Any, *, as_bytes: bool = False) -> Union[str, bytes]:
61
+ def encode(self, data: Any, *, as_bytes: bool = False) -> str | bytes:
47
62
  """Encode data to JSON.
48
63
 
49
64
  Args:
@@ -55,7 +70,7 @@ class JSONSerializer(Protocol):
55
70
  """
56
71
  ...
57
72
 
58
- def decode(self, data: Union[str, bytes], *, decode_bytes: bool = True) -> Any:
73
+ def decode(self, data: str | bytes, *, decode_bytes: bool = True) -> Any:
59
74
  """Decode from JSON.
60
75
 
61
76
  Args:
@@ -74,18 +89,18 @@ class BaseJSONSerializer(ABC):
74
89
  __slots__ = ()
75
90
 
76
91
  @abstractmethod
77
- def encode(self, data: Any, *, as_bytes: bool = False) -> Union[str, bytes]:
92
+ def encode(self, data: Any, *, as_bytes: bool = False) -> str | bytes:
78
93
  """Encode data to JSON."""
79
94
  ...
80
95
 
81
96
  @abstractmethod
82
- def decode(self, data: Union[str, bytes], *, decode_bytes: bool = True) -> Any:
97
+ def decode(self, data: str | bytes, *, decode_bytes: bool = True) -> Any:
83
98
  """Decode from JSON."""
84
99
  ...
85
100
 
86
101
 
87
102
  class MsgspecSerializer(BaseJSONSerializer):
88
- """Msgspec-based JSON serializer for optimal performance."""
103
+ """Msgspec-based JSON serializer."""
89
104
 
90
105
  __slots__ = ("_decoder", "_encoder")
91
106
 
@@ -96,7 +111,7 @@ class MsgspecSerializer(BaseJSONSerializer):
96
111
  self._encoder: Final[Encoder] = Encoder(enc_hook=_type_to_string)
97
112
  self._decoder: Final[Decoder] = Decoder()
98
113
 
99
- def encode(self, data: Any, *, as_bytes: bool = False) -> Union[str, bytes]:
114
+ def encode(self, data: Any, *, as_bytes: bool = False) -> str | bytes:
100
115
  """Encode data using msgspec."""
101
116
  try:
102
117
  if as_bytes:
@@ -107,7 +122,7 @@ class MsgspecSerializer(BaseJSONSerializer):
107
122
  return OrjsonSerializer().encode(data, as_bytes=as_bytes)
108
123
  return StandardLibSerializer().encode(data, as_bytes=as_bytes)
109
124
 
110
- def decode(self, data: Union[str, bytes], *, decode_bytes: bool = True) -> Any:
125
+ def decode(self, data: str | bytes, *, decode_bytes: bool = True) -> Any:
111
126
  """Decode data using msgspec."""
112
127
  if isinstance(data, bytes):
113
128
  if decode_bytes:
@@ -128,25 +143,40 @@ class MsgspecSerializer(BaseJSONSerializer):
128
143
 
129
144
 
130
145
  class OrjsonSerializer(BaseJSONSerializer):
131
- """Orjson-based JSON serializer with native datetime/UUID support."""
146
+ """Orjson-based JSON serializer with native datetime/UUID support.
147
+
148
+ Automatically enables numpy serialization if numpy is installed.
149
+ """
132
150
 
133
151
  __slots__ = ()
134
152
 
135
- def encode(self, data: Any, *, as_bytes: bool = False) -> Union[str, bytes]:
136
- """Encode data using orjson."""
153
+ def encode(self, data: Any, *, as_bytes: bool = False) -> str | bytes:
154
+ """Encode data using orjson.
155
+
156
+ Args:
157
+ data: Data to encode.
158
+ as_bytes: Whether to return bytes instead of string.
159
+
160
+ Returns:
161
+ JSON string or bytes depending on as_bytes parameter.
162
+ """
137
163
  from orjson import (
138
164
  OPT_NAIVE_UTC, # pyright: ignore[reportUnknownVariableType]
139
- OPT_SERIALIZE_NUMPY, # pyright: ignore[reportUnknownVariableType]
140
165
  OPT_SERIALIZE_UUID, # pyright: ignore[reportUnknownVariableType]
141
166
  )
142
167
  from orjson import dumps as _orjson_dumps # pyright: ignore[reportMissingImports]
143
168
 
144
- result = _orjson_dumps(
145
- data, default=_type_to_string, option=OPT_SERIALIZE_NUMPY | OPT_NAIVE_UTC | OPT_SERIALIZE_UUID
146
- )
169
+ options = OPT_NAIVE_UTC | OPT_SERIALIZE_UUID
170
+
171
+ if NUMPY_INSTALLED:
172
+ from orjson import OPT_SERIALIZE_NUMPY # pyright: ignore[reportUnknownVariableType]
173
+
174
+ options |= OPT_SERIALIZE_NUMPY
175
+
176
+ result = _orjson_dumps(data, default=_type_to_string, option=options)
147
177
  return result if as_bytes else result.decode("utf-8")
148
178
 
149
- def decode(self, data: Union[str, bytes], *, decode_bytes: bool = True) -> Any:
179
+ def decode(self, data: str | bytes, *, decode_bytes: bool = True) -> Any:
150
180
  """Decode data using orjson."""
151
181
  from orjson import loads as _orjson_loads # pyright: ignore[reportMissingImports]
152
182
 
@@ -162,12 +192,12 @@ class StandardLibSerializer(BaseJSONSerializer):
162
192
 
163
193
  __slots__ = ()
164
194
 
165
- def encode(self, data: Any, *, as_bytes: bool = False) -> Union[str, bytes]:
195
+ def encode(self, data: Any, *, as_bytes: bool = False) -> str | bytes:
166
196
  """Encode data using standard library json."""
167
197
  json_str = json.dumps(data, default=_type_to_string)
168
198
  return json_str.encode("utf-8") if as_bytes else json_str
169
199
 
170
- def decode(self, data: Union[str, bytes], *, decode_bytes: bool = True) -> Any:
200
+ def decode(self, data: str | bytes, *, decode_bytes: bool = True) -> Any:
171
201
  """Decode data using standard library json."""
172
202
  if isinstance(data, bytes):
173
203
  if decode_bytes:
@@ -176,7 +206,7 @@ class StandardLibSerializer(BaseJSONSerializer):
176
206
  return json.loads(data)
177
207
 
178
208
 
179
- _default_serializer: Optional[JSONSerializer] = None
209
+ _default_serializer: JSONSerializer | None = None
180
210
 
181
211
 
182
212
  def get_default_serializer() -> JSONSerializer:
@@ -213,8 +243,8 @@ def encode_json(data: Any, *, as_bytes: Literal[False] = ...) -> str: ... # pra
213
243
  def encode_json(data: Any, *, as_bytes: Literal[True]) -> bytes: ... # pragma: no cover
214
244
 
215
245
 
216
- def encode_json(data: Any, *, as_bytes: bool = False) -> Union[str, bytes]:
217
- """Encode to JSON, optionally returning bytes for optimal performance.
246
+ def encode_json(data: Any, *, as_bytes: bool = False) -> str | bytes:
247
+ """Encode to JSON, optionally returning bytes.
218
248
 
219
249
  Args:
220
250
  data: The data to encode.
@@ -226,7 +256,7 @@ def encode_json(data: Any, *, as_bytes: bool = False) -> Union[str, bytes]:
226
256
  return get_default_serializer().encode(data, as_bytes=as_bytes)
227
257
 
228
258
 
229
- def decode_json(data: Union[str, bytes], *, decode_bytes: bool = True) -> Any:
259
+ def decode_json(data: str | bytes, *, decode_bytes: bool = True) -> Any:
230
260
  """Decode from JSON string or bytes efficiently.
231
261
 
232
262
  Args:
sqlspec/_typing.py CHANGED
@@ -6,9 +6,9 @@ from collections.abc import Iterable, Mapping
6
6
  from dataclasses import dataclass
7
7
  from enum import Enum
8
8
  from importlib.util import find_spec
9
- from typing import Any, ClassVar, Final, Optional, Protocol, Union, cast, runtime_checkable
9
+ from typing import Any, ClassVar, Final, Literal, Protocol, cast, runtime_checkable
10
10
 
11
- from typing_extensions import Literal, TypeVar, dataclass_transform
11
+ from typing_extensions import TypeVar, dataclass_transform
12
12
 
13
13
 
14
14
  @runtime_checkable
@@ -38,15 +38,15 @@ class BaseModelStub:
38
38
  self,
39
39
  /,
40
40
  *,
41
- include: "Optional[Any]" = None, # noqa: ARG002
42
- exclude: "Optional[Any]" = None, # noqa: ARG002
43
- context: "Optional[Any]" = None, # noqa: ARG002
41
+ include: "Any | None" = None, # noqa: ARG002
42
+ exclude: "Any | None" = None, # noqa: ARG002
43
+ context: "Any | None" = None, # noqa: ARG002
44
44
  by_alias: bool = False, # noqa: ARG002
45
45
  exclude_unset: bool = False, # noqa: ARG002
46
46
  exclude_defaults: bool = False, # noqa: ARG002
47
47
  exclude_none: bool = False, # noqa: ARG002
48
48
  round_trip: bool = False, # noqa: ARG002
49
- warnings: "Union[bool, Literal['none', 'warn', 'error']]" = True, # noqa: ARG002
49
+ warnings: "bool | Literal['none', 'warn', 'error']" = True, # noqa: ARG002
50
50
  serialize_as_any: bool = False, # noqa: ARG002
51
51
  ) -> "dict[str, Any]":
52
52
  """Placeholder implementation."""
@@ -56,15 +56,15 @@ class BaseModelStub:
56
56
  self,
57
57
  /,
58
58
  *,
59
- include: "Optional[Any]" = None, # noqa: ARG002
60
- exclude: "Optional[Any]" = None, # noqa: ARG002
61
- context: "Optional[Any]" = None, # noqa: ARG002
59
+ include: "Any | None" = None, # noqa: ARG002
60
+ exclude: "Any | None" = None, # noqa: ARG002
61
+ context: "Any | None" = None, # noqa: ARG002
62
62
  by_alias: bool = False, # noqa: ARG002
63
63
  exclude_unset: bool = False, # noqa: ARG002
64
64
  exclude_defaults: bool = False, # noqa: ARG002
65
65
  exclude_none: bool = False, # noqa: ARG002
66
66
  round_trip: bool = False, # noqa: ARG002
67
- warnings: "Union[bool, Literal['none', 'warn', 'error']]" = True, # noqa: ARG002
67
+ warnings: "bool | Literal['none', 'warn', 'error']" = True, # noqa: ARG002
68
68
  serialize_as_any: bool = False, # noqa: ARG002
69
69
  ) -> str:
70
70
  """Placeholder implementation."""
@@ -78,9 +78,9 @@ class TypeAdapterStub:
78
78
  self,
79
79
  type: Any, # noqa: A002
80
80
  *,
81
- config: "Optional[Any]" = None, # noqa: ARG002
81
+ config: "Any | None" = None, # noqa: ARG002
82
82
  _parent_depth: int = 2, # noqa: ARG002
83
- module: "Optional[str]" = None, # noqa: ARG002
83
+ module: "str | None" = None, # noqa: ARG002
84
84
  ) -> None:
85
85
  """Initialize."""
86
86
  self._type = type
@@ -90,10 +90,10 @@ class TypeAdapterStub:
90
90
  object: Any,
91
91
  /,
92
92
  *,
93
- strict: "Optional[bool]" = None, # noqa: ARG002
94
- from_attributes: "Optional[bool]" = None, # noqa: ARG002
95
- context: "Optional[dict[str, Any]]" = None, # noqa: ARG002
96
- experimental_allow_partial: "Union[bool, Literal['off', 'on', 'trailing-strings']]" = False, # noqa: ARG002
93
+ strict: "bool | None" = None, # noqa: ARG002
94
+ from_attributes: "bool | None" = None, # noqa: ARG002
95
+ context: "dict[str, Any] | None" = None, # noqa: ARG002
96
+ experimental_allow_partial: "bool | Literal['off', 'on', 'trailing-strings']" = False, # noqa: ARG002
97
97
  ) -> Any:
98
98
  """Validate Python object."""
99
99
  return object
@@ -143,8 +143,8 @@ def convert_stub( # noqa: PLR0913
143
143
  *,
144
144
  strict: bool = True, # noqa: ARG001
145
145
  from_attributes: bool = False, # noqa: ARG001
146
- dec_hook: "Optional[Any]" = None, # noqa: ARG001
147
- builtin_types: "Optional[Any]" = None, # noqa: ARG001
146
+ dec_hook: "Any | None" = None, # noqa: ARG001
147
+ builtin_types: "Any | None" = None, # noqa: ARG001
148
148
  str_keys: bool = False, # noqa: ARG001
149
149
  ) -> Any:
150
150
  """Placeholder implementation."""
@@ -308,7 +308,7 @@ class EmptyEnum(Enum):
308
308
  EMPTY = 0
309
309
 
310
310
 
311
- EmptyType = Union[Literal[EmptyEnum.EMPTY], UnsetType]
311
+ EmptyType = Literal[EmptyEnum.EMPTY] | UnsetType
312
312
  Empty: Final = EmptyEnum.EMPTY
313
313
 
314
314
 
@@ -336,18 +336,18 @@ class ArrowTableResult(Protocol):
336
336
  def from_arrays(
337
337
  self,
338
338
  arrays: list[Any],
339
- names: "Optional[list[str]]" = None,
340
- schema: "Optional[Any]" = None,
341
- metadata: "Optional[Mapping[str, Any]]" = None,
339
+ names: "list[str] | None" = None,
340
+ schema: "Any | None" = None,
341
+ metadata: "Mapping[str, Any] | None" = None,
342
342
  ) -> Any:
343
343
  return None
344
344
 
345
345
  def from_pydict(
346
- self, mapping: dict[str, Any], schema: "Optional[Any]" = None, metadata: "Optional[Mapping[str, Any]]" = None
346
+ self, mapping: dict[str, Any], schema: "Any | None" = None, metadata: "Mapping[str, Any] | None" = None
347
347
  ) -> Any:
348
348
  return None
349
349
 
350
- def from_batches(self, batches: Iterable[Any], schema: Optional[Any] = None) -> Any:
350
+ def from_batches(self, batches: Iterable[Any], schema: Any | None = None) -> Any:
351
351
  return None
352
352
 
353
353
 
@@ -373,22 +373,123 @@ class ArrowRecordBatchResult(Protocol):
373
373
  def column(self, i: int) -> Any:
374
374
  return None
375
375
 
376
- def slice(self, offset: int = 0, length: "Optional[int]" = None) -> Any:
376
+ def slice(self, offset: int = 0, length: "int | None" = None) -> Any:
377
377
  return None
378
378
 
379
379
 
380
+ @runtime_checkable
381
+ class ArrowSchemaProtocol(Protocol):
382
+ """Typed shim for pyarrow.Schema."""
383
+
384
+ def field(self, i: int) -> Any:
385
+ """Get field by index."""
386
+ ...
387
+
388
+ @property
389
+ def names(self) -> "list[str]":
390
+ """Get list of field names."""
391
+ ...
392
+
393
+ def __len__(self) -> int:
394
+ """Get number of fields."""
395
+ return 0
396
+
397
+
398
+ @runtime_checkable
399
+ class ArrowRecordBatchReaderProtocol(Protocol):
400
+ """Typed shim for pyarrow.RecordBatchReader."""
401
+
402
+ def read_all(self) -> Any:
403
+ """Read all batches into a table."""
404
+ ...
405
+
406
+ def read_next_batch(self) -> Any:
407
+ """Read next batch."""
408
+ ...
409
+
410
+ def __iter__(self) -> "Iterable[Any]":
411
+ """Iterate over batches."""
412
+ ...
413
+
414
+
380
415
  try:
381
416
  from pyarrow import RecordBatch as ArrowRecordBatch
417
+ from pyarrow import RecordBatchReader as ArrowRecordBatchReader
418
+ from pyarrow import Schema as ArrowSchema
382
419
  from pyarrow import Table as ArrowTable
383
420
 
384
421
  PYARROW_INSTALLED = True
385
422
  except ImportError:
386
423
  ArrowTable = ArrowTableResult # type: ignore[assignment,misc]
387
424
  ArrowRecordBatch = ArrowRecordBatchResult # type: ignore[assignment,misc]
425
+ ArrowSchema = ArrowSchemaProtocol # type: ignore[assignment,misc]
426
+ ArrowRecordBatchReader = ArrowRecordBatchReaderProtocol # type: ignore[assignment,misc]
388
427
 
389
428
  PYARROW_INSTALLED = False # pyright: ignore[reportConstantRedefinition]
390
429
 
391
430
 
431
+ @runtime_checkable
432
+ class PandasDataFrameProtocol(Protocol):
433
+ """Typed shim for pandas.DataFrame."""
434
+
435
+ def __len__(self) -> int:
436
+ """Get number of rows."""
437
+ ...
438
+
439
+ def __getitem__(self, key: Any) -> Any:
440
+ """Get column or row."""
441
+ ...
442
+
443
+
444
+ @runtime_checkable
445
+ class PolarsDataFrameProtocol(Protocol):
446
+ """Typed shim for polars.DataFrame."""
447
+
448
+ def __len__(self) -> int:
449
+ """Get number of rows."""
450
+ ...
451
+
452
+ def __getitem__(self, key: Any) -> Any:
453
+ """Get column or row."""
454
+ ...
455
+
456
+
457
+ try:
458
+ from pandas import DataFrame as PandasDataFrame
459
+
460
+ PANDAS_INSTALLED = True
461
+ except ImportError:
462
+ PandasDataFrame = PandasDataFrameProtocol # type: ignore[assignment,misc]
463
+ PANDAS_INSTALLED = False
464
+
465
+
466
+ try:
467
+ from polars import DataFrame as PolarsDataFrame
468
+
469
+ POLARS_INSTALLED = True
470
+ except ImportError:
471
+ PolarsDataFrame = PolarsDataFrameProtocol # type: ignore[assignment,misc]
472
+ POLARS_INSTALLED = False
473
+
474
+
475
+ @runtime_checkable
476
+ class NumpyArrayStub(Protocol):
477
+ """Protocol stub for numpy.ndarray when numpy is not installed.
478
+
479
+ Provides minimal interface for type checking and serialization support.
480
+ """
481
+
482
+ def tolist(self) -> "list[Any]":
483
+ """Convert array to Python list."""
484
+ ...
485
+
486
+
487
+ try:
488
+ from numpy import ndarray as NumpyArray # noqa: N812
489
+ except ImportError:
490
+ NumpyArray = NumpyArrayStub # type: ignore[assignment,misc]
491
+
492
+
392
493
  try:
393
494
  from opentelemetry import trace # pyright: ignore[reportMissingImports, reportAssignmentType]
394
495
  from opentelemetry.trace import ( # pyright: ignore[reportMissingImports, reportAssignmentType]
@@ -409,16 +510,16 @@ except ImportError:
409
510
  def record_exception(
410
511
  self,
411
512
  exception: "Exception",
412
- attributes: "Optional[Mapping[str, Any]]" = None,
413
- timestamp: "Optional[int]" = None,
513
+ attributes: "Mapping[str, Any] | None" = None,
514
+ timestamp: "int | None" = None,
414
515
  escaped: bool = False,
415
516
  ) -> None:
416
517
  return None
417
518
 
418
- def set_status(self, status: Any, description: "Optional[str]" = None) -> None:
519
+ def set_status(self, status: Any, description: "str | None" = None) -> None:
419
520
  return None
420
521
 
421
- def end(self, end_time: "Optional[int]" = None) -> None:
522
+ def end(self, end_time: "int | None" = None) -> None:
422
523
  return None
423
524
 
424
525
  def __enter__(self) -> "Span":
@@ -445,8 +546,8 @@ except ImportError:
445
546
  def get_tracer(
446
547
  self,
447
548
  instrumenting_module_name: str,
448
- instrumenting_library_version: "Optional[str]" = None,
449
- schema_url: "Optional[str]" = None,
549
+ instrumenting_library_version: "str | None" = None,
550
+ schema_url: "str | None" = None,
450
551
  tracer_provider: Any = None,
451
552
  ) -> Tracer:
452
553
  return Tracer() # type: ignore[abstract] # pragma: no cover
@@ -522,9 +623,6 @@ try:
522
623
  from aiosql.types import ( # pyright: ignore[reportMissingImports, reportAssignmentType]
523
624
  AsyncDriverAdapterProtocol as AiosqlAsyncProtocol, # pyright: ignore[reportMissingImports, reportAssignmentType]
524
625
  )
525
- from aiosql.types import ( # pyright: ignore[reportMissingImports, reportAssignmentType]
526
- DriverAdapterProtocol as AiosqlProtocol, # pyright: ignore[reportMissingImports, reportAssignmentType]
527
- )
528
626
  from aiosql.types import ParamType as AiosqlParamType # pyright: ignore[reportMissingImports, reportAssignmentType]
529
627
  from aiosql.types import (
530
628
  SQLOperationType as AiosqlSQLOperationType, # pyright: ignore[reportMissingImports, reportAssignmentType]
@@ -553,7 +651,7 @@ except ImportError:
553
651
  aiosql = _AiosqlShim() # type: ignore[assignment]
554
652
 
555
653
  # Placeholder types for aiosql protocols
556
- AiosqlParamType = Union[dict[str, Any], list[Any], tuple[Any, ...], None] # type: ignore[misc]
654
+ AiosqlParamType = Any # type: ignore[misc]
557
655
 
558
656
  class AiosqlSQLOperationType(Enum): # type: ignore[no-redef]
559
657
  """Enumeration of aiosql operation types."""
@@ -566,12 +664,6 @@ except ImportError:
566
664
  SELECT_ONE = 5
567
665
  SELECT_VALUE = 6
568
666
 
569
- @runtime_checkable
570
- class AiosqlProtocol(Protocol): # type: ignore[no-redef]
571
- """Placeholder for aiosql DriverAdapterProtocol"""
572
-
573
- def process_sql(self, query_name: str, op_type: Any, sql: str) -> str: ...
574
-
575
667
  @runtime_checkable
576
668
  class AiosqlSyncProtocol(Protocol): # type: ignore[no-redef]
577
669
  """Placeholder for aiosql SyncDriverAdapterProtocol"""
@@ -580,16 +672,16 @@ except ImportError:
580
672
 
581
673
  def process_sql(self, query_name: str, op_type: Any, sql: str) -> str: ...
582
674
  def select(
583
- self, conn: Any, query_name: str, sql: str, parameters: Any, record_class: "Optional[Any]" = None
675
+ self, conn: Any, query_name: str, sql: str, parameters: Any, record_class: "Any | None" = None
584
676
  ) -> Any: ...
585
677
  def select_one(
586
- self, conn: Any, query_name: str, sql: str, parameters: Any, record_class: "Optional[Any]" = None
587
- ) -> "Optional[Any]": ...
588
- def select_value(self, conn: Any, query_name: str, sql: str, parameters: Any) -> "Optional[Any]": ...
678
+ self, conn: Any, query_name: str, sql: str, parameters: Any, record_class: "Any | None" = None
679
+ ) -> "Any | None": ...
680
+ def select_value(self, conn: Any, query_name: str, sql: str, parameters: Any) -> "Any | None": ...
589
681
  def select_cursor(self, conn: Any, query_name: str, sql: str, parameters: Any) -> Any: ...
590
682
  def insert_update_delete(self, conn: Any, query_name: str, sql: str, parameters: Any) -> int: ...
591
683
  def insert_update_delete_many(self, conn: Any, query_name: str, sql: str, parameters: Any) -> int: ...
592
- def insert_returning(self, conn: Any, query_name: str, sql: str, parameters: Any) -> "Optional[Any]": ...
684
+ def insert_returning(self, conn: Any, query_name: str, sql: str, parameters: Any) -> "Any | None": ...
593
685
 
594
686
  @runtime_checkable
595
687
  class AiosqlAsyncProtocol(Protocol): # type: ignore[no-redef]
@@ -599,16 +691,16 @@ except ImportError:
599
691
 
600
692
  def process_sql(self, query_name: str, op_type: Any, sql: str) -> str: ...
601
693
  async def select(
602
- self, conn: Any, query_name: str, sql: str, parameters: Any, record_class: "Optional[Any]" = None
694
+ self, conn: Any, query_name: str, sql: str, parameters: Any, record_class: "Any | None" = None
603
695
  ) -> Any: ...
604
696
  async def select_one(
605
- self, conn: Any, query_name: str, sql: str, parameters: Any, record_class: "Optional[Any]" = None
606
- ) -> "Optional[Any]": ...
607
- async def select_value(self, conn: Any, query_name: str, sql: str, parameters: Any) -> "Optional[Any]": ...
697
+ self, conn: Any, query_name: str, sql: str, parameters: Any, record_class: "Any | None" = None
698
+ ) -> "Any | None": ...
699
+ async def select_value(self, conn: Any, query_name: str, sql: str, parameters: Any) -> "Any | None": ...
608
700
  async def select_cursor(self, conn: Any, query_name: str, sql: str, parameters: Any) -> Any: ...
609
701
  async def insert_update_delete(self, conn: Any, query_name: str, sql: str, parameters: Any) -> None: ...
610
702
  async def insert_update_delete_many(self, conn: Any, query_name: str, sql: str, parameters: Any) -> None: ...
611
- async def insert_returning(self, conn: Any, query_name: str, sql: str, parameters: Any) -> "Optional[Any]": ...
703
+ async def insert_returning(self, conn: Any, query_name: str, sql: str, parameters: Any) -> "Any | None": ...
612
704
 
613
705
  AIOSQL_INSTALLED = False # pyright: ignore[reportConstantRedefinition] # pyright: ignore[reportConstantRedefinition]
614
706
 
@@ -630,7 +722,9 @@ __all__ = (
630
722
  "OBSTORE_INSTALLED",
631
723
  "OPENTELEMETRY_INSTALLED",
632
724
  "ORJSON_INSTALLED",
725
+ "PANDAS_INSTALLED",
633
726
  "PGVECTOR_INSTALLED",
727
+ "POLARS_INSTALLED",
634
728
  "PROMETHEUS_INSTALLED",
635
729
  "PYARROW_INSTALLED",
636
730
  "PYDANTIC_INSTALLED",
@@ -638,11 +732,14 @@ __all__ = (
638
732
  "UNSET_STUB",
639
733
  "AiosqlAsyncProtocol",
640
734
  "AiosqlParamType",
641
- "AiosqlProtocol",
642
735
  "AiosqlSQLOperationType",
643
736
  "AiosqlSyncProtocol",
644
737
  "ArrowRecordBatch",
738
+ "ArrowRecordBatchReader",
739
+ "ArrowRecordBatchReaderProtocol",
645
740
  "ArrowRecordBatchResult",
741
+ "ArrowSchema",
742
+ "ArrowSchemaProtocol",
646
743
  "ArrowTable",
647
744
  "ArrowTableResult",
648
745
  "AttrsInstance",
@@ -660,6 +757,12 @@ __all__ = (
660
757
  "FailFastStub",
661
758
  "Gauge",
662
759
  "Histogram",
760
+ "NumpyArray",
761
+ "NumpyArrayStub",
762
+ "PandasDataFrame",
763
+ "PandasDataFrameProtocol",
764
+ "PolarsDataFrame",
765
+ "PolarsDataFrameProtocol",
663
766
  "Span",
664
767
  "Status",
665
768
  "StatusCode",
@@ -4,7 +4,7 @@ from typing import TYPE_CHECKING
4
4
  from adbc_driver_manager.dbapi import Connection
5
5
 
6
6
  if TYPE_CHECKING:
7
- from typing_extensions import TypeAlias
7
+ from typing import TypeAlias
8
8
 
9
9
  AdbcConnection: TypeAlias = Connection
10
10
  else:
@@ -0,0 +1,5 @@
1
+ """ADBC ADK integration for Google Agent Development Kit."""
2
+
3
+ from sqlspec.adapters.adbc.adk.store import AdbcADKStore
4
+
5
+ __all__ = ("AdbcADKStore",)