sqlspec 0.26.0__py3-none-any.whl → 0.27.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 (197) hide show
  1. sqlspec/__init__.py +7 -15
  2. sqlspec/_serialization.py +55 -25
  3. sqlspec/_typing.py +62 -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 +870 -0
  7. sqlspec/adapters/adbc/config.py +62 -12
  8. sqlspec/adapters/adbc/data_dictionary.py +52 -2
  9. sqlspec/adapters/adbc/driver.py +144 -45
  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 +527 -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 +493 -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 +450 -0
  36. sqlspec/adapters/asyncpg/config.py +57 -36
  37. sqlspec/adapters/asyncpg/data_dictionary.py +41 -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 +576 -0
  44. sqlspec/adapters/bigquery/config.py +25 -11
  45. sqlspec/adapters/bigquery/data_dictionary.py +42 -2
  46. sqlspec/adapters/bigquery/driver.py +352 -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 +553 -0
  53. sqlspec/adapters/duckdb/config.py +79 -21
  54. sqlspec/adapters/duckdb/data_dictionary.py +41 -2
  55. sqlspec/adapters/duckdb/driver.py +138 -43
  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 +1745 -0
  64. sqlspec/adapters/oracledb/config.py +120 -36
  65. sqlspec/adapters/oracledb/data_dictionary.py +87 -20
  66. sqlspec/adapters/oracledb/driver.py +292 -84
  67. sqlspec/adapters/oracledb/litestar/__init__.py +5 -0
  68. sqlspec/adapters/oracledb/litestar/store.py +767 -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 +482 -0
  75. sqlspec/adapters/psqlpy/config.py +45 -19
  76. sqlspec/adapters/psqlpy/data_dictionary.py +41 -2
  77. sqlspec/adapters/psqlpy/driver.py +101 -31
  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 +944 -0
  85. sqlspec/adapters/psycopg/config.py +65 -37
  86. sqlspec/adapters/psycopg/data_dictionary.py +77 -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 +572 -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 +231 -60
  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 +37 -37
  121. sqlspec/core/hashing.py +9 -9
  122. sqlspec/core/parameters.py +76 -45
  123. sqlspec/core/result.py +102 -46
  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 +95 -161
  129. sqlspec/driver/_common.py +133 -80
  130. sqlspec/driver/_sync.py +95 -162
  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 +73 -53
  142. sqlspec/extensions/litestar/__init__.py +21 -4
  143. sqlspec/extensions/litestar/cli.py +54 -10
  144. sqlspec/extensions/litestar/config.py +59 -266
  145. sqlspec/extensions/litestar/handlers.py +46 -17
  146. sqlspec/extensions/litestar/migrations/0001_create_session_table.py +137 -0
  147. sqlspec/extensions/litestar/migrations/__init__.py +3 -0
  148. sqlspec/extensions/litestar/plugin.py +324 -223
  149. sqlspec/extensions/litestar/providers.py +25 -25
  150. sqlspec/extensions/litestar/store.py +265 -0
  151. sqlspec/loader.py +30 -49
  152. sqlspec/migrations/base.py +200 -76
  153. sqlspec/migrations/commands.py +591 -62
  154. sqlspec/migrations/context.py +6 -9
  155. sqlspec/migrations/fix.py +199 -0
  156. sqlspec/migrations/loaders.py +47 -19
  157. sqlspec/migrations/runner.py +241 -75
  158. sqlspec/migrations/tracker.py +237 -21
  159. sqlspec/migrations/utils.py +51 -3
  160. sqlspec/migrations/validation.py +177 -0
  161. sqlspec/protocols.py +66 -36
  162. sqlspec/storage/_utils.py +98 -0
  163. sqlspec/storage/backends/fsspec.py +134 -106
  164. sqlspec/storage/backends/local.py +78 -51
  165. sqlspec/storage/backends/obstore.py +278 -162
  166. sqlspec/storage/registry.py +75 -39
  167. sqlspec/typing.py +14 -84
  168. sqlspec/utils/config_resolver.py +6 -6
  169. sqlspec/utils/correlation.py +4 -5
  170. sqlspec/utils/data_transformation.py +3 -2
  171. sqlspec/utils/deprecation.py +9 -8
  172. sqlspec/utils/fixtures.py +4 -4
  173. sqlspec/utils/logging.py +46 -6
  174. sqlspec/utils/module_loader.py +2 -2
  175. sqlspec/utils/schema.py +288 -0
  176. sqlspec/utils/serializers.py +3 -3
  177. sqlspec/utils/sync_tools.py +21 -17
  178. sqlspec/utils/text.py +1 -2
  179. sqlspec/utils/type_guards.py +111 -20
  180. sqlspec/utils/version.py +433 -0
  181. {sqlspec-0.26.0.dist-info → sqlspec-0.27.0.dist-info}/METADATA +40 -21
  182. sqlspec-0.27.0.dist-info/RECORD +207 -0
  183. sqlspec/builder/mixins/__init__.py +0 -55
  184. sqlspec/builder/mixins/_cte_and_set_ops.py +0 -253
  185. sqlspec/builder/mixins/_delete_operations.py +0 -50
  186. sqlspec/builder/mixins/_insert_operations.py +0 -282
  187. sqlspec/builder/mixins/_merge_operations.py +0 -698
  188. sqlspec/builder/mixins/_order_limit_operations.py +0 -145
  189. sqlspec/builder/mixins/_pivot_operations.py +0 -157
  190. sqlspec/builder/mixins/_select_operations.py +0 -930
  191. sqlspec/builder/mixins/_update_operations.py +0 -199
  192. sqlspec/builder/mixins/_where_clause.py +0 -1298
  193. sqlspec-0.26.0.dist-info/RECORD +0 -157
  194. sqlspec-0.26.0.dist-info/licenses/NOTICE +0 -29
  195. {sqlspec-0.26.0.dist-info → sqlspec-0.27.0.dist-info}/WHEEL +0 -0
  196. {sqlspec-0.26.0.dist-info → sqlspec-0.27.0.dist-info}/entry_points.txt +0 -0
  197. {sqlspec-0.26.0.dist-info → sqlspec-0.27.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,281 @@
1
+ """AioSQLite session store for Litestar integration."""
2
+
3
+ from datetime import datetime, timedelta, timezone
4
+ from typing import TYPE_CHECKING
5
+
6
+ from sqlspec.extensions.litestar.store import BaseSQLSpecStore
7
+ from sqlspec.utils.logging import get_logger
8
+
9
+ if TYPE_CHECKING:
10
+ from sqlspec.adapters.aiosqlite.config import AiosqliteConfig
11
+
12
+ logger = get_logger("adapters.aiosqlite.litestar.store")
13
+
14
+ SECONDS_PER_DAY = 86400.0
15
+ JULIAN_EPOCH = 2440587.5
16
+
17
+ __all__ = ("AiosqliteStore",)
18
+
19
+
20
+ class AiosqliteStore(BaseSQLSpecStore["AiosqliteConfig"]):
21
+ """SQLite session store using AioSQLite driver.
22
+
23
+ Implements server-side session storage for Litestar using SQLite
24
+ via the AioSQLite driver. Provides efficient session management with:
25
+ - Native async SQLite operations
26
+ - INSERT OR REPLACE for UPSERT functionality
27
+ - Automatic expiration handling
28
+ - Efficient cleanup of expired sessions
29
+
30
+ Args:
31
+ config: AiosqliteConfig instance.
32
+
33
+ Example:
34
+ from sqlspec.adapters.aiosqlite import AiosqliteConfig
35
+ from sqlspec.adapters.aiosqlite.litestar.store import AiosqliteStore
36
+
37
+ config = AiosqliteConfig(database=":memory:")
38
+ store = AiosqliteStore(config)
39
+ await store.create_table()
40
+ """
41
+
42
+ __slots__ = ()
43
+
44
+ def __init__(self, config: "AiosqliteConfig") -> None:
45
+ """Initialize AioSQLite session store.
46
+
47
+ Args:
48
+ config: AiosqliteConfig instance.
49
+
50
+ Notes:
51
+ Table name is read from config.extension_config["litestar"]["session_table"].
52
+ """
53
+ super().__init__(config)
54
+
55
+ def _get_create_table_sql(self) -> str:
56
+ """Get SQLite CREATE TABLE SQL.
57
+
58
+ Returns:
59
+ SQL statement to create the sessions table with proper indexes.
60
+
61
+ Notes:
62
+ - Uses REAL type for expires_at (stores Julian Day number)
63
+ - Julian Day enables direct comparison with julianday('now')
64
+ - Partial index WHERE expires_at IS NOT NULL reduces index size
65
+ - This approach ensures the index is actually used by query optimizer
66
+ - Table name is internally controlled, not user input (S608 suppressed)
67
+ """
68
+ return f"""
69
+ CREATE TABLE IF NOT EXISTS {self._table_name} (
70
+ session_id TEXT PRIMARY KEY,
71
+ data BLOB NOT NULL,
72
+ expires_at REAL
73
+ );
74
+ CREATE INDEX IF NOT EXISTS idx_{self._table_name}_expires_at
75
+ ON {self._table_name}(expires_at) WHERE expires_at IS NOT NULL;
76
+ """
77
+
78
+ def _get_drop_table_sql(self) -> "list[str]":
79
+ """Get SQLite DROP TABLE SQL statements.
80
+
81
+ Returns:
82
+ List of SQL statements to drop indexes and table.
83
+ """
84
+ return [f"DROP INDEX IF EXISTS idx_{self._table_name}_expires_at", f"DROP TABLE IF EXISTS {self._table_name}"]
85
+
86
+ def _datetime_to_julian(self, dt: "datetime | None") -> "float | None":
87
+ """Convert datetime to Julian Day number for SQLite storage.
88
+
89
+ Args:
90
+ dt: Datetime to convert (must be UTC-aware).
91
+
92
+ Returns:
93
+ Julian Day number as REAL, or None if dt is None.
94
+
95
+ Notes:
96
+ Julian Day number is days since November 24, 4714 BCE (proleptic Gregorian).
97
+ This enables direct comparison with julianday('now') in SQL queries.
98
+ """
99
+ if dt is None:
100
+ return None
101
+
102
+ epoch = datetime(1970, 1, 1, tzinfo=timezone.utc)
103
+ delta_days = (dt - epoch).total_seconds() / SECONDS_PER_DAY
104
+ return JULIAN_EPOCH + delta_days
105
+
106
+ def _julian_to_datetime(self, julian: "float | None") -> "datetime | None":
107
+ """Convert Julian Day number back to datetime.
108
+
109
+ Args:
110
+ julian: Julian Day number.
111
+
112
+ Returns:
113
+ UTC-aware datetime, or None if julian is None.
114
+ """
115
+ if julian is None:
116
+ return None
117
+
118
+ days_since_epoch = julian - JULIAN_EPOCH
119
+ timestamp = days_since_epoch * SECONDS_PER_DAY
120
+ return datetime.fromtimestamp(timestamp, tz=timezone.utc)
121
+
122
+ async def create_table(self) -> None:
123
+ """Create the session table if it doesn't exist."""
124
+ sql = self._get_create_table_sql()
125
+ async with self._config.provide_session() as driver:
126
+ await driver.execute_script(sql)
127
+ logger.debug("Created session table: %s", self._table_name)
128
+
129
+ async def get(self, key: str, renew_for: "int | timedelta | None" = None) -> "bytes | None":
130
+ """Get a session value by key.
131
+
132
+ Args:
133
+ key: Session ID to retrieve.
134
+ renew_for: If given, renew the expiry time for this duration.
135
+
136
+ Returns:
137
+ Session data as bytes if found and not expired, None otherwise.
138
+ """
139
+ sql = f"""
140
+ SELECT data, expires_at FROM {self._table_name}
141
+ WHERE session_id = ?
142
+ AND (expires_at IS NULL OR julianday(expires_at) > julianday('now'))
143
+ """
144
+
145
+ async with self._config.provide_connection() as conn:
146
+ async with conn.execute(sql, (key,)) as cursor:
147
+ row = await cursor.fetchone()
148
+
149
+ if row is None:
150
+ return None
151
+
152
+ data, expires_at_julian = row
153
+
154
+ if renew_for is not None and expires_at_julian is not None:
155
+ new_expires_at = self._calculate_expires_at(renew_for)
156
+ new_expires_at_julian = self._datetime_to_julian(new_expires_at)
157
+ if new_expires_at_julian is not None:
158
+ update_sql = f"""
159
+ UPDATE {self._table_name}
160
+ SET expires_at = ?
161
+ WHERE session_id = ?
162
+ """
163
+ await conn.execute(update_sql, (new_expires_at_julian, key))
164
+ await conn.commit()
165
+
166
+ return bytes(data)
167
+
168
+ async def set(self, key: str, value: "str | bytes", expires_in: "int | timedelta | None" = None) -> None:
169
+ """Store a session value.
170
+
171
+ Args:
172
+ key: Session ID.
173
+ value: Session data.
174
+ expires_in: Time until expiration.
175
+
176
+ Notes:
177
+ Stores expires_at as Julian Day number (REAL) for optimal index usage.
178
+ """
179
+ data = self._value_to_bytes(value)
180
+ expires_at = self._calculate_expires_at(expires_in)
181
+ expires_at_julian = self._datetime_to_julian(expires_at)
182
+
183
+ sql = f"""
184
+ INSERT OR REPLACE INTO {self._table_name} (session_id, data, expires_at)
185
+ VALUES (?, ?, ?)
186
+ """
187
+
188
+ async with self._config.provide_connection() as conn:
189
+ await conn.execute(sql, (key, data, expires_at_julian))
190
+ await conn.commit()
191
+
192
+ async def delete(self, key: str) -> None:
193
+ """Delete a session by key.
194
+
195
+ Args:
196
+ key: Session ID to delete.
197
+ """
198
+ sql = f"DELETE FROM {self._table_name} WHERE session_id = ?"
199
+
200
+ async with self._config.provide_connection() as conn:
201
+ await conn.execute(sql, (key,))
202
+ await conn.commit()
203
+
204
+ async def delete_all(self) -> None:
205
+ """Delete all sessions from the store."""
206
+ sql = f"DELETE FROM {self._table_name}"
207
+
208
+ async with self._config.provide_connection() as conn:
209
+ await conn.execute(sql)
210
+ await conn.commit()
211
+ logger.debug("Deleted all sessions from table: %s", self._table_name)
212
+
213
+ async def exists(self, key: str) -> bool:
214
+ """Check if a session key exists and is not expired.
215
+
216
+ Args:
217
+ key: Session ID to check.
218
+
219
+ Returns:
220
+ True if the session exists and is not expired.
221
+ """
222
+ sql = f"""
223
+ SELECT 1 FROM {self._table_name}
224
+ WHERE session_id = ?
225
+ AND (expires_at IS NULL OR julianday(expires_at) > julianday('now'))
226
+ """
227
+
228
+ async with self._config.provide_connection() as conn, conn.execute(sql, (key,)) as cursor:
229
+ result = await cursor.fetchone()
230
+ return result is not None
231
+
232
+ async def expires_in(self, key: str) -> "int | None":
233
+ """Get the time in seconds until the session expires.
234
+
235
+ Args:
236
+ key: Session ID to check.
237
+
238
+ Returns:
239
+ Seconds until expiration, or None if no expiry or key doesn't exist.
240
+ """
241
+ sql = f"""
242
+ SELECT expires_at FROM {self._table_name}
243
+ WHERE session_id = ?
244
+ """
245
+
246
+ async with self._config.provide_connection() as conn:
247
+ async with conn.execute(sql, (key,)) as cursor:
248
+ row = await cursor.fetchone()
249
+
250
+ if row is None or row[0] is None:
251
+ return None
252
+
253
+ expires_at_julian = row[0]
254
+ expires_at = self._julian_to_datetime(expires_at_julian)
255
+
256
+ if expires_at is None:
257
+ return None
258
+
259
+ now = datetime.now(timezone.utc)
260
+
261
+ if expires_at <= now:
262
+ return 0
263
+
264
+ delta = expires_at - now
265
+ return int(delta.total_seconds())
266
+
267
+ async def delete_expired(self) -> int:
268
+ """Delete all expired sessions.
269
+
270
+ Returns:
271
+ Number of sessions deleted.
272
+ """
273
+ sql = f"DELETE FROM {self._table_name} WHERE julianday(expires_at) <= julianday('now')"
274
+
275
+ async with self._config.provide_connection() as conn:
276
+ cursor = await conn.execute(sql)
277
+ await conn.commit()
278
+ count = cursor.rowcount
279
+ if count > 0:
280
+ logger.debug("Cleaned up %d expired sessions", count)
281
+ return count
@@ -5,7 +5,7 @@ import logging
5
5
  import time
6
6
  import uuid
7
7
  from contextlib import asynccontextmanager, suppress
8
- from typing import TYPE_CHECKING, Any, Optional, Union
8
+ from typing import TYPE_CHECKING, Any
9
9
 
10
10
  import aiosqlite
11
11
 
@@ -48,7 +48,7 @@ class AiosqlitePoolConnection:
48
48
  """
49
49
  self.id = uuid.uuid4().hex
50
50
  self.connection = connection
51
- self.idle_since: Optional[float] = None
51
+ self.idle_since: float | None = None
52
52
  self._closed = False
53
53
 
54
54
  @property
@@ -160,12 +160,12 @@ class AiosqliteConnectionPool:
160
160
  self._operation_timeout = operation_timeout
161
161
 
162
162
  self._connection_registry: dict[str, AiosqlitePoolConnection] = {}
163
- self._tracked_threads: set[Union[threading.Thread, AiosqliteConnection]] = set()
163
+ self._tracked_threads: set[threading.Thread | AiosqliteConnection] = set()
164
164
  self._wal_initialized = False
165
165
 
166
- self._queue_instance: Optional[asyncio.Queue[AiosqlitePoolConnection]] = None
167
- self._lock_instance: Optional[asyncio.Lock] = None
168
- self._closed_event_instance: Optional[asyncio.Event] = None
166
+ self._queue_instance: asyncio.Queue[AiosqlitePoolConnection] | None = None
167
+ self._lock_instance: asyncio.Lock | None = None
168
+ self._closed_event_instance: asyncio.Event | None = None
169
169
 
170
170
  @property
171
171
  def _queue(self) -> "asyncio.Queue[AiosqlitePoolConnection]":
@@ -312,7 +312,7 @@ class AiosqliteConnectionPool:
312
312
  except asyncio.TimeoutError:
313
313
  logger.warning("Connection %s close timed out during retirement", connection.id)
314
314
 
315
- async def _try_provision_new_connection(self) -> "Optional[AiosqlitePoolConnection]":
315
+ async def _try_provision_new_connection(self) -> "AiosqlitePoolConnection | None":
316
316
  """Try to create a new connection if under capacity.
317
317
 
318
318
  Returns:
@@ -1,5 +1,10 @@
1
1
  from sqlspec.adapters.asyncmy._types import AsyncmyConnection
2
- from sqlspec.adapters.asyncmy.config import AsyncmyConfig, AsyncmyConnectionParams, AsyncmyPoolParams
2
+ from sqlspec.adapters.asyncmy.config import (
3
+ AsyncmyConfig,
4
+ AsyncmyConnectionParams,
5
+ AsyncmyDriverFeatures,
6
+ AsyncmyPoolParams,
7
+ )
3
8
  from sqlspec.adapters.asyncmy.driver import (
4
9
  AsyncmyCursor,
5
10
  AsyncmyDriver,
@@ -13,6 +18,7 @@ __all__ = (
13
18
  "AsyncmyConnectionParams",
14
19
  "AsyncmyCursor",
15
20
  "AsyncmyDriver",
21
+ "AsyncmyDriverFeatures",
16
22
  "AsyncmyExceptionHandler",
17
23
  "AsyncmyPoolParams",
18
24
  "asyncmy_statement_config",
@@ -3,7 +3,7 @@ from typing import TYPE_CHECKING
3
3
  from asyncmy import Connection # pyright: ignore
4
4
 
5
5
  if TYPE_CHECKING:
6
- from typing_extensions import TypeAlias
6
+ from typing import TypeAlias
7
7
 
8
8
  AsyncmyConnection: TypeAlias = Connection
9
9
  else:
@@ -0,0 +1,5 @@
1
+ """AsyncMy ADK store for Google Agent Development Kit."""
2
+
3
+ from sqlspec.adapters.asyncmy.adk.store import AsyncmyADKStore
4
+
5
+ __all__ = ("AsyncmyADKStore",)