sqlspec 0.25.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 (199) hide show
  1. sqlspec/__init__.py +7 -15
  2. sqlspec/_serialization.py +256 -24
  3. sqlspec/_typing.py +71 -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 +69 -12
  8. sqlspec/adapters/adbc/data_dictionary.py +340 -0
  9. sqlspec/adapters/adbc/driver.py +266 -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 +153 -0
  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 +88 -15
  17. sqlspec/adapters/aiosqlite/data_dictionary.py +149 -0
  18. sqlspec/adapters/aiosqlite/driver.py +143 -40
  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 +2 -2
  24. sqlspec/adapters/asyncmy/adk/__init__.py +5 -0
  25. sqlspec/adapters/asyncmy/adk/store.py +493 -0
  26. sqlspec/adapters/asyncmy/config.py +68 -23
  27. sqlspec/adapters/asyncmy/data_dictionary.py +161 -0
  28. sqlspec/adapters/asyncmy/driver.py +313 -58
  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 +59 -35
  37. sqlspec/adapters/asyncpg/data_dictionary.py +173 -0
  38. sqlspec/adapters/asyncpg/driver.py +170 -25
  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 +27 -10
  45. sqlspec/adapters/bigquery/data_dictionary.py +149 -0
  46. sqlspec/adapters/bigquery/driver.py +368 -142
  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 +125 -0
  50. sqlspec/adapters/duckdb/_types.py +1 -1
  51. sqlspec/adapters/duckdb/adk/__init__.py +14 -0
  52. sqlspec/adapters/duckdb/adk/store.py +553 -0
  53. sqlspec/adapters/duckdb/config.py +80 -20
  54. sqlspec/adapters/duckdb/data_dictionary.py +163 -0
  55. sqlspec/adapters/duckdb/driver.py +167 -45
  56. sqlspec/adapters/duckdb/litestar/__init__.py +5 -0
  57. sqlspec/adapters/duckdb/litestar/store.py +332 -0
  58. sqlspec/adapters/duckdb/pool.py +4 -4
  59. sqlspec/adapters/duckdb/type_converter.py +133 -0
  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 +122 -32
  65. sqlspec/adapters/oracledb/data_dictionary.py +509 -0
  66. sqlspec/adapters/oracledb/driver.py +353 -91
  67. sqlspec/adapters/oracledb/litestar/__init__.py +5 -0
  68. sqlspec/adapters/oracledb/litestar/store.py +767 -0
  69. sqlspec/adapters/oracledb/migrations.py +348 -73
  70. sqlspec/adapters/oracledb/type_converter.py +207 -0
  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 +46 -17
  76. sqlspec/adapters/psqlpy/data_dictionary.py +172 -0
  77. sqlspec/adapters/psqlpy/driver.py +123 -209
  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 +102 -0
  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 +69 -35
  86. sqlspec/adapters/psycopg/data_dictionary.py +331 -0
  87. sqlspec/adapters/psycopg/driver.py +238 -81
  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 +87 -15
  96. sqlspec/adapters/sqlite/data_dictionary.py +149 -0
  97. sqlspec/adapters/sqlite/driver.py +137 -54
  98. sqlspec/adapters/sqlite/litestar/__init__.py +5 -0
  99. sqlspec/adapters/sqlite/litestar/store.py +318 -0
  100. sqlspec/adapters/sqlite/pool.py +18 -9
  101. sqlspec/base.py +45 -26
  102. sqlspec/builder/__init__.py +73 -4
  103. sqlspec/builder/_base.py +162 -89
  104. sqlspec/builder/_column.py +62 -29
  105. sqlspec/builder/_ddl.py +180 -121
  106. sqlspec/builder/_delete.py +5 -4
  107. sqlspec/builder/_dml.py +388 -0
  108. sqlspec/{_sql.py → builder/_factory.py} +53 -94
  109. sqlspec/builder/_insert.py +32 -131
  110. sqlspec/builder/_join.py +375 -0
  111. sqlspec/builder/_merge.py +446 -11
  112. sqlspec/builder/_parsing_utils.py +111 -17
  113. sqlspec/builder/_select.py +1457 -24
  114. sqlspec/builder/_update.py +11 -42
  115. sqlspec/cli.py +307 -194
  116. sqlspec/config.py +252 -67
  117. sqlspec/core/__init__.py +5 -4
  118. sqlspec/core/cache.py +17 -17
  119. sqlspec/core/compiler.py +62 -9
  120. sqlspec/core/filters.py +37 -37
  121. sqlspec/core/hashing.py +9 -9
  122. sqlspec/core/parameters.py +83 -48
  123. sqlspec/core/result.py +102 -46
  124. sqlspec/core/splitter.py +16 -17
  125. sqlspec/core/statement.py +36 -30
  126. sqlspec/core/type_conversion.py +235 -0
  127. sqlspec/driver/__init__.py +7 -6
  128. sqlspec/driver/_async.py +188 -151
  129. sqlspec/driver/_common.py +285 -80
  130. sqlspec/driver/_sync.py +188 -152
  131. sqlspec/driver/mixins/_result_tools.py +20 -236
  132. sqlspec/driver/mixins/_sql_translator.py +4 -4
  133. sqlspec/exceptions.py +75 -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/__init__.py +4 -3
  153. sqlspec/migrations/base.py +302 -39
  154. sqlspec/migrations/commands.py +611 -144
  155. sqlspec/migrations/context.py +142 -0
  156. sqlspec/migrations/fix.py +199 -0
  157. sqlspec/migrations/loaders.py +68 -23
  158. sqlspec/migrations/runner.py +543 -107
  159. sqlspec/migrations/tracker.py +237 -21
  160. sqlspec/migrations/utils.py +51 -3
  161. sqlspec/migrations/validation.py +177 -0
  162. sqlspec/protocols.py +66 -36
  163. sqlspec/storage/_utils.py +98 -0
  164. sqlspec/storage/backends/fsspec.py +134 -106
  165. sqlspec/storage/backends/local.py +78 -51
  166. sqlspec/storage/backends/obstore.py +278 -162
  167. sqlspec/storage/registry.py +75 -39
  168. sqlspec/typing.py +16 -84
  169. sqlspec/utils/config_resolver.py +153 -0
  170. sqlspec/utils/correlation.py +4 -5
  171. sqlspec/utils/data_transformation.py +3 -2
  172. sqlspec/utils/deprecation.py +9 -8
  173. sqlspec/utils/fixtures.py +4 -4
  174. sqlspec/utils/logging.py +46 -6
  175. sqlspec/utils/module_loader.py +2 -2
  176. sqlspec/utils/schema.py +288 -0
  177. sqlspec/utils/serializers.py +50 -2
  178. sqlspec/utils/sync_tools.py +21 -17
  179. sqlspec/utils/text.py +1 -2
  180. sqlspec/utils/type_guards.py +111 -20
  181. sqlspec/utils/version.py +433 -0
  182. {sqlspec-0.25.0.dist-info → sqlspec-0.27.0.dist-info}/METADATA +40 -21
  183. sqlspec-0.27.0.dist-info/RECORD +207 -0
  184. sqlspec/builder/mixins/__init__.py +0 -55
  185. sqlspec/builder/mixins/_cte_and_set_ops.py +0 -254
  186. sqlspec/builder/mixins/_delete_operations.py +0 -50
  187. sqlspec/builder/mixins/_insert_operations.py +0 -282
  188. sqlspec/builder/mixins/_join_operations.py +0 -389
  189. sqlspec/builder/mixins/_merge_operations.py +0 -592
  190. sqlspec/builder/mixins/_order_limit_operations.py +0 -152
  191. sqlspec/builder/mixins/_pivot_operations.py +0 -157
  192. sqlspec/builder/mixins/_select_operations.py +0 -936
  193. sqlspec/builder/mixins/_update_operations.py +0 -218
  194. sqlspec/builder/mixins/_where_clause.py +0 -1304
  195. sqlspec-0.25.0.dist-info/RECORD +0 -139
  196. sqlspec-0.25.0.dist-info/licenses/NOTICE +0 -29
  197. {sqlspec-0.25.0.dist-info → sqlspec-0.27.0.dist-info}/WHEEL +0 -0
  198. {sqlspec-0.25.0.dist-info → sqlspec-0.27.0.dist-info}/entry_points.txt +0 -0
  199. {sqlspec-0.25.0.dist-info → sqlspec-0.27.0.dist-info}/licenses/LICENSE +0 -0
sqlspec/config.py CHANGED
@@ -1,5 +1,7 @@
1
1
  from abc import ABC, abstractmethod
2
- from typing import TYPE_CHECKING, Any, Callable, ClassVar, Generic, Optional, TypeVar, Union
2
+ from collections.abc import Callable
3
+ from pathlib import Path
4
+ from typing import TYPE_CHECKING, Any, ClassVar, Generic, Literal, TypeVar, cast
3
5
 
4
6
  from typing_extensions import NotRequired, TypedDict
5
7
 
@@ -11,20 +13,21 @@ from sqlspec.utils.logging import get_logger
11
13
  if TYPE_CHECKING:
12
14
  from collections.abc import Awaitable
13
15
  from contextlib import AbstractAsyncContextManager, AbstractContextManager
14
- from pathlib import Path
15
16
 
16
17
  from sqlspec.driver import AsyncDriverAdapterBase, SyncDriverAdapterBase
17
18
  from sqlspec.loader import SQLFileLoader
18
- from sqlspec.migrations.commands import MigrationCommands
19
+ from sqlspec.migrations.commands import AsyncMigrationCommands, SyncMigrationCommands
19
20
 
20
21
 
21
22
  __all__ = (
23
+ "ADKConfig",
22
24
  "AsyncConfigT",
23
25
  "AsyncDatabaseConfig",
24
26
  "ConfigT",
25
27
  "DatabaseConfigProtocol",
26
28
  "DriverT",
27
29
  "LifecycleConfig",
30
+ "LitestarConfig",
28
31
  "MigrationConfig",
29
32
  "NoPoolAsyncConfig",
30
33
  "NoPoolSyncConfig",
@@ -32,22 +35,22 @@ __all__ = (
32
35
  "SyncDatabaseConfig",
33
36
  )
34
37
 
35
- AsyncConfigT = TypeVar("AsyncConfigT", bound="Union[AsyncDatabaseConfig[Any, Any, Any], NoPoolAsyncConfig[Any, Any]]")
36
- SyncConfigT = TypeVar("SyncConfigT", bound="Union[SyncDatabaseConfig[Any, Any, Any], NoPoolSyncConfig[Any, Any]]")
38
+ AsyncConfigT = TypeVar("AsyncConfigT", bound="AsyncDatabaseConfig[Any, Any, Any] | NoPoolAsyncConfig[Any, Any]")
39
+ SyncConfigT = TypeVar("SyncConfigT", bound="SyncDatabaseConfig[Any, Any, Any] | NoPoolSyncConfig[Any, Any]")
37
40
  ConfigT = TypeVar(
38
41
  "ConfigT",
39
- bound="Union[Union[AsyncDatabaseConfig[Any, Any, Any], NoPoolAsyncConfig[Any, Any]], SyncDatabaseConfig[Any, Any, Any], NoPoolSyncConfig[Any, Any]]",
42
+ bound="AsyncDatabaseConfig[Any, Any, Any] | NoPoolAsyncConfig[Any, Any] | SyncDatabaseConfig[Any, Any, Any] | NoPoolSyncConfig[Any, Any]",
40
43
  )
41
44
 
42
45
  # Define TypeVars for Generic classes
43
46
  ConnectionT = TypeVar("ConnectionT")
44
47
  PoolT = TypeVar("PoolT")
45
- DriverT = TypeVar("DriverT", bound="Union[SyncDriverAdapterBase, AsyncDriverAdapterBase]")
48
+ DriverT = TypeVar("DriverT", bound="SyncDriverAdapterBase | AsyncDriverAdapterBase")
46
49
 
47
50
  logger = get_logger("config")
48
51
 
49
52
 
50
- class LifecycleConfig(TypedDict, total=False):
53
+ class LifecycleConfig(TypedDict):
51
54
  """Lifecycle hooks for database adapters.
52
55
 
53
56
  Each hook accepts a list of callables to support multiple handlers.
@@ -64,14 +67,14 @@ class LifecycleConfig(TypedDict, total=False):
64
67
  on_error: NotRequired[list[Callable[[Exception, str, dict], None]]]
65
68
 
66
69
 
67
- class MigrationConfig(TypedDict, total=False):
70
+ class MigrationConfig(TypedDict):
68
71
  """Configuration options for database migrations.
69
72
 
70
73
  All fields are optional with default values.
71
74
  """
72
75
 
73
- script_location: NotRequired[str]
74
- """Path to the migrations directory. Defaults to 'migrations'."""
76
+ script_location: NotRequired["str | Path"]
77
+ """Path to the migrations directory. Accepts string or Path object. Defaults to 'migrations'."""
75
78
 
76
79
  version_table_name: NotRequired[str]
77
80
  """Name of the table used to track applied migrations. Defaults to 'sqlspec_migrations'."""
@@ -82,6 +85,164 @@ class MigrationConfig(TypedDict, total=False):
82
85
  enabled: NotRequired[bool]
83
86
  """Whether this configuration should be included in CLI operations. Defaults to True."""
84
87
 
88
+ auto_sync: NotRequired[bool]
89
+ """Enable automatic version reconciliation during upgrade. When enabled (default), SQLSpec automatically updates database tracking when migrations are renamed from timestamp to sequential format. Defaults to True."""
90
+
91
+ strict_ordering: NotRequired[bool]
92
+ """Enforce strict migration ordering. When enabled, prevents out-of-order migrations from being applied. Defaults to False."""
93
+
94
+ include_extensions: NotRequired["list[str]"]
95
+ """List of extension names whose migrations should be included. Extension migrations maintain separate versioning and are prefixed with 'ext_{name}_'."""
96
+
97
+ transactional: NotRequired[bool]
98
+ """Wrap migrations in transactions when supported. When enabled (default for adapters that support it), each migration runs in a transaction that is committed on success or rolled back on failure. This prevents partial migrations from leaving the database in an inconsistent state. Requires adapter support for transactional DDL. Defaults to True for PostgreSQL, SQLite, and DuckDB; False for MySQL, Oracle, and BigQuery. Individual migrations can override this with a '-- transactional: false' comment."""
99
+
100
+
101
+ class LitestarConfig(TypedDict):
102
+ """Configuration options for Litestar SQLSpec plugin.
103
+
104
+ All fields are optional with sensible defaults.
105
+ """
106
+
107
+ connection_key: NotRequired[str]
108
+ """Key for storing connection in ASGI scope. Default: 'db_connection'"""
109
+
110
+ pool_key: NotRequired[str]
111
+ """Key for storing connection pool in application state. Default: 'db_pool'"""
112
+
113
+ session_key: NotRequired[str]
114
+ """Key for storing session in ASGI scope. Default: 'db_session'"""
115
+
116
+ commit_mode: NotRequired[Literal["manual", "autocommit", "autocommit_include_redirect"]]
117
+ """Transaction commit mode. Default: 'manual'"""
118
+
119
+ enable_correlation_middleware: NotRequired[bool]
120
+ """Enable request correlation ID middleware. Default: True"""
121
+
122
+ extra_commit_statuses: NotRequired[set[int]]
123
+ """Additional HTTP status codes that trigger commit. Default: set()"""
124
+
125
+ extra_rollback_statuses: NotRequired[set[int]]
126
+ """Additional HTTP status codes that trigger rollback. Default: set()"""
127
+
128
+
129
+ class ADKConfig(TypedDict):
130
+ """Configuration options for ADK session store extension.
131
+
132
+ All fields are optional with sensible defaults. Use in extension_config["adk"]:
133
+
134
+ Example:
135
+ from sqlspec.adapters.asyncpg import AsyncpgConfig
136
+
137
+ config = AsyncpgConfig(
138
+ pool_config={"dsn": "postgresql://localhost/mydb"},
139
+ extension_config={
140
+ "adk": {
141
+ "session_table": "my_sessions",
142
+ "events_table": "my_events",
143
+ "owner_id_column": "tenant_id INTEGER REFERENCES tenants(id)"
144
+ }
145
+ }
146
+ )
147
+
148
+ Notes:
149
+ This TypedDict provides type safety for extension config but is not required.
150
+ You can use plain dicts as well.
151
+ """
152
+
153
+ session_table: NotRequired[str]
154
+ """Name of the sessions table. Default: 'adk_sessions'
155
+
156
+ Examples:
157
+ "agent_sessions"
158
+ "my_app_sessions"
159
+ "tenant_acme_sessions"
160
+ """
161
+
162
+ events_table: NotRequired[str]
163
+ """Name of the events table. Default: 'adk_events'
164
+
165
+ Examples:
166
+ "agent_events"
167
+ "my_app_events"
168
+ "tenant_acme_events"
169
+ """
170
+
171
+ owner_id_column: NotRequired[str]
172
+ """Optional owner ID column definition to link sessions to a user, tenant, team, or other entity.
173
+
174
+ Format: "column_name TYPE [NOT NULL] REFERENCES table(column) [options...]"
175
+
176
+ The entire definition is passed through to DDL verbatim. We only parse
177
+ the column name (first word) for use in INSERT/SELECT statements.
178
+
179
+ Supports:
180
+ - Foreign key constraints: REFERENCES table(column)
181
+ - Nullable or NOT NULL
182
+ - CASCADE options: ON DELETE CASCADE, ON UPDATE CASCADE
183
+ - Dialect-specific options (DEFERRABLE, ENABLE VALIDATE, etc.)
184
+ - Plain columns without FK (just extra column storage)
185
+
186
+ Examples:
187
+ PostgreSQL with UUID FK:
188
+ "account_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE"
189
+
190
+ MySQL with BIGINT FK:
191
+ "user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE RESTRICT"
192
+
193
+ Oracle with NUMBER FK:
194
+ "user_id NUMBER(10) REFERENCES users(id) ENABLE VALIDATE"
195
+
196
+ SQLite with INTEGER FK:
197
+ "tenant_id INTEGER NOT NULL REFERENCES tenants(id)"
198
+
199
+ Nullable FK (optional relationship):
200
+ "workspace_id UUID REFERENCES workspaces(id) ON DELETE SET NULL"
201
+
202
+ No FK (just extra column):
203
+ "organization_name VARCHAR(128) NOT NULL"
204
+
205
+ Deferred constraint (PostgreSQL):
206
+ "user_id UUID REFERENCES users(id) DEFERRABLE INITIALLY DEFERRED"
207
+
208
+ Notes:
209
+ - Column name (first word) is extracted for INSERT/SELECT queries
210
+ - Rest of definition is passed through to CREATE TABLE DDL
211
+ - Database validates the DDL syntax (fail-fast on errors)
212
+ - Works with all database dialects (PostgreSQL, MySQL, SQLite, Oracle, etc.)
213
+ """
214
+
215
+ in_memory: NotRequired[bool]
216
+ """Enable in-memory table storage (Oracle-specific). Default: False.
217
+
218
+ When enabled, tables are created with the INMEMORY clause for Oracle Database,
219
+ which stores table data in columnar format in memory for faster query performance.
220
+
221
+ This is an Oracle-specific feature that requires:
222
+ - Oracle Database 12.1.0.2 or higher
223
+ - Database In-Memory option license (Enterprise Edition)
224
+ - Sufficient INMEMORY_SIZE configured in the database instance
225
+
226
+ Other database adapters ignore this setting.
227
+
228
+ Examples:
229
+ Oracle with in-memory enabled:
230
+ config = OracleAsyncConfig(
231
+ pool_config={"dsn": "oracle://..."},
232
+ extension_config={
233
+ "adk": {
234
+ "in_memory": True
235
+ }
236
+ }
237
+ )
238
+
239
+ Notes:
240
+ - Improves query performance for analytics (10-100x faster)
241
+ - Tables created with INMEMORY clause
242
+ - Requires Oracle Database In-Memory option license
243
+ - Ignored by non-Oracle adapters
244
+ """
245
+
85
246
 
86
247
  class DatabaseConfigProtocol(ABC, Generic[ConnectionT, PoolT, DriverT]):
87
248
  """Protocol defining the interface for database configurations."""
@@ -89,6 +250,7 @@ class DatabaseConfigProtocol(ABC, Generic[ConnectionT, PoolT, DriverT]):
89
250
  __slots__ = (
90
251
  "_migration_commands",
91
252
  "_migration_loader",
253
+ "bind_key",
92
254
  "driver_features",
93
255
  "migration_config",
94
256
  "pool_instance",
@@ -96,18 +258,21 @@ class DatabaseConfigProtocol(ABC, Generic[ConnectionT, PoolT, DriverT]):
96
258
  )
97
259
 
98
260
  _migration_loader: "SQLFileLoader"
99
- _migration_commands: "MigrationCommands"
261
+ _migration_commands: "SyncMigrationCommands | AsyncMigrationCommands"
100
262
  driver_type: "ClassVar[type[Any]]"
101
263
  connection_type: "ClassVar[type[Any]]"
102
264
  is_async: "ClassVar[bool]" = False
103
265
  supports_connection_pooling: "ClassVar[bool]" = False
266
+ supports_transactional_ddl: "ClassVar[bool]" = False
104
267
  supports_native_arrow_import: "ClassVar[bool]" = False
105
268
  supports_native_arrow_export: "ClassVar[bool]" = False
106
269
  supports_native_parquet_import: "ClassVar[bool]" = False
107
270
  supports_native_parquet_export: "ClassVar[bool]" = False
271
+ bind_key: "str | None"
108
272
  statement_config: "StatementConfig"
109
- pool_instance: "Optional[PoolT]"
110
- migration_config: "Union[dict[str, Any], MigrationConfig]"
273
+ pool_instance: "PoolT | None"
274
+ migration_config: "dict[str, Any] | MigrationConfig"
275
+ driver_features: "dict[str, Any]"
111
276
 
112
277
  def __hash__(self) -> int:
113
278
  return id(self)
@@ -122,38 +287,38 @@ class DatabaseConfigProtocol(ABC, Generic[ConnectionT, PoolT, DriverT]):
122
287
  return f"{type(self).__name__}({parts})"
123
288
 
124
289
  @abstractmethod
125
- def create_connection(self) -> "Union[ConnectionT, Awaitable[ConnectionT]]":
290
+ def create_connection(self) -> "ConnectionT | Awaitable[ConnectionT]":
126
291
  """Create and return a new database connection."""
127
292
  raise NotImplementedError
128
293
 
129
294
  @abstractmethod
130
295
  def provide_connection(
131
296
  self, *args: Any, **kwargs: Any
132
- ) -> "Union[AbstractContextManager[ConnectionT], AbstractAsyncContextManager[ConnectionT]]":
297
+ ) -> "AbstractContextManager[ConnectionT] | AbstractAsyncContextManager[ConnectionT]":
133
298
  """Provide a database connection context manager."""
134
299
  raise NotImplementedError
135
300
 
136
301
  @abstractmethod
137
302
  def provide_session(
138
303
  self, *args: Any, **kwargs: Any
139
- ) -> "Union[AbstractContextManager[DriverT], AbstractAsyncContextManager[DriverT]]":
304
+ ) -> "AbstractContextManager[DriverT] | AbstractAsyncContextManager[DriverT]":
140
305
  """Provide a database session context manager."""
141
306
  raise NotImplementedError
142
307
 
143
308
  @abstractmethod
144
- def create_pool(self) -> "Union[PoolT, Awaitable[PoolT]]":
309
+ def create_pool(self) -> "PoolT | Awaitable[PoolT]":
145
310
  """Create and return connection pool."""
146
311
  raise NotImplementedError
147
312
 
148
313
  @abstractmethod
149
- def close_pool(self) -> "Optional[Awaitable[None]]":
314
+ def close_pool(self) -> "Awaitable[None] | None":
150
315
  """Terminate the connection pool."""
151
316
  raise NotImplementedError
152
317
 
153
318
  @abstractmethod
154
319
  def provide_pool(
155
320
  self, *args: Any, **kwargs: Any
156
- ) -> "Union[PoolT, Awaitable[PoolT], AbstractContextManager[PoolT], AbstractAsyncContextManager[PoolT]]":
321
+ ) -> "PoolT | Awaitable[PoolT] | AbstractContextManager[PoolT] | AbstractAsyncContextManager[PoolT]":
157
322
  """Provide pool instance."""
158
323
  raise NotImplementedError
159
324
 
@@ -176,10 +341,10 @@ class DatabaseConfigProtocol(ABC, Generic[ConnectionT, PoolT, DriverT]):
176
341
  at runtime when needed.
177
342
  """
178
343
  from sqlspec.loader import SQLFileLoader
179
- from sqlspec.migrations.commands import MigrationCommands
344
+ from sqlspec.migrations.commands import create_migration_commands
180
345
 
181
346
  self._migration_loader = SQLFileLoader()
182
- self._migration_commands = MigrationCommands(self) # type: ignore[arg-type]
347
+ self._migration_commands = create_migration_commands(self) # pyright: ignore
183
348
 
184
349
  def _ensure_migration_loader(self) -> "SQLFileLoader":
185
350
  """Get the migration SQL loader and auto-load files if needed.
@@ -200,7 +365,7 @@ class DatabaseConfigProtocol(ABC, Generic[ConnectionT, PoolT, DriverT]):
200
365
 
201
366
  return self._migration_loader
202
367
 
203
- def _ensure_migration_commands(self) -> "MigrationCommands":
368
+ def _ensure_migration_commands(self) -> "SyncMigrationCommands | AsyncMigrationCommands":
204
369
  """Get the migration commands instance.
205
370
 
206
371
  Returns:
@@ -219,13 +384,12 @@ class DatabaseConfigProtocol(ABC, Generic[ConnectionT, PoolT, DriverT]):
219
384
  """
220
385
  return self._ensure_migration_loader()
221
386
 
222
- def load_migration_sql_files(self, *paths: "Union[str, Path]") -> None:
387
+ def load_migration_sql_files(self, *paths: "str | Path") -> None:
223
388
  """Load additional migration SQL files from specified paths.
224
389
 
225
390
  Args:
226
391
  *paths: One or more file paths or directory paths to load migration SQL files from.
227
392
  """
228
- from pathlib import Path
229
393
 
230
394
  loader = self._ensure_migration_loader()
231
395
  for path in paths:
@@ -236,7 +400,7 @@ class DatabaseConfigProtocol(ABC, Generic[ConnectionT, PoolT, DriverT]):
236
400
  else:
237
401
  logger.warning("Migration path does not exist: %s", path_obj)
238
402
 
239
- def get_migration_commands(self) -> "MigrationCommands":
403
+ def get_migration_commands(self) -> "SyncMigrationCommands | AsyncMigrationCommands":
240
404
  """Get migration commands for this configuration.
241
405
 
242
406
  Returns:
@@ -244,25 +408,27 @@ class DatabaseConfigProtocol(ABC, Generic[ConnectionT, PoolT, DriverT]):
244
408
  """
245
409
  return self._ensure_migration_commands()
246
410
 
247
- def migrate_up(self, revision: str = "head") -> None:
411
+ async def migrate_up(self, revision: str = "head") -> None:
248
412
  """Apply migrations up to the specified revision.
249
413
 
250
414
  Args:
251
415
  revision: Target revision or "head" for latest. Defaults to "head".
252
416
  """
253
417
  commands = self._ensure_migration_commands()
254
- commands.upgrade(revision)
255
418
 
256
- def migrate_down(self, revision: str = "-1") -> None:
419
+ await cast("AsyncMigrationCommands", commands).upgrade(revision)
420
+
421
+ async def migrate_down(self, revision: str = "-1") -> None:
257
422
  """Apply migrations down to the specified revision.
258
423
 
259
424
  Args:
260
425
  revision: Target revision, "-1" for one step back, or "base" for all migrations. Defaults to "-1".
261
426
  """
262
427
  commands = self._ensure_migration_commands()
263
- commands.downgrade(revision)
264
428
 
265
- def get_current_migration(self, verbose: bool = False) -> "Optional[str]":
429
+ await cast("AsyncMigrationCommands", commands).downgrade(revision)
430
+
431
+ async def get_current_migration(self, verbose: bool = False) -> "str | None":
266
432
  """Get the current migration version.
267
433
 
268
434
  Args:
@@ -272,9 +438,10 @@ class DatabaseConfigProtocol(ABC, Generic[ConnectionT, PoolT, DriverT]):
272
438
  Current migration version or None if no migrations applied.
273
439
  """
274
440
  commands = self._ensure_migration_commands()
275
- return commands.current(verbose=verbose)
276
441
 
277
- def create_migration(self, message: str, file_type: str = "sql") -> None:
442
+ return await cast("AsyncMigrationCommands", commands).current(verbose=verbose)
443
+
444
+ async def create_migration(self, message: str, file_type: str = "sql") -> None:
278
445
  """Create a new migration file.
279
446
 
280
447
  Args:
@@ -282,9 +449,10 @@ class DatabaseConfigProtocol(ABC, Generic[ConnectionT, PoolT, DriverT]):
282
449
  file_type: Type of migration file to create ('sql' or 'py'). Defaults to 'sql'.
283
450
  """
284
451
  commands = self._ensure_migration_commands()
285
- commands.revision(message, file_type)
286
452
 
287
- def init_migrations(self, directory: "Optional[str]" = None, package: bool = True) -> None:
453
+ await cast("AsyncMigrationCommands", commands).revision(message, file_type)
454
+
455
+ async def init_migrations(self, directory: "str | None" = None, package: bool = True) -> None:
288
456
  """Initialize migration directory structure.
289
457
 
290
458
  Args:
@@ -293,17 +461,18 @@ class DatabaseConfigProtocol(ABC, Generic[ConnectionT, PoolT, DriverT]):
293
461
  """
294
462
  if directory is None:
295
463
  migration_config = self.migration_config or {}
296
- directory = migration_config.get("script_location") or "migrations"
464
+ directory = str(migration_config.get("script_location") or "migrations")
297
465
 
298
466
  commands = self._ensure_migration_commands()
299
467
  assert directory is not None
300
- commands.init(directory, package)
468
+
469
+ await cast("AsyncMigrationCommands", commands).init(directory, package)
301
470
 
302
471
 
303
472
  class NoPoolSyncConfig(DatabaseConfigProtocol[ConnectionT, None, DriverT]):
304
473
  """Base class for sync database configurations that do not implement a pool."""
305
474
 
306
- __slots__ = ("connection_config",)
475
+ __slots__ = ("connection_config", "extension_config")
307
476
  is_async: "ClassVar[bool]" = False
308
477
  supports_connection_pooling: "ClassVar[bool]" = False
309
478
  migration_tracker_type: "ClassVar[type[Any]]" = SyncMigrationTracker
@@ -311,14 +480,18 @@ class NoPoolSyncConfig(DatabaseConfigProtocol[ConnectionT, None, DriverT]):
311
480
  def __init__(
312
481
  self,
313
482
  *,
314
- connection_config: Optional[dict[str, Any]] = None,
315
- migration_config: "Optional[Union[dict[str, Any], MigrationConfig]]" = None,
316
- statement_config: "Optional[StatementConfig]" = None,
317
- driver_features: "Optional[dict[str, Any]]" = None,
483
+ connection_config: dict[str, Any] | None = None,
484
+ migration_config: "dict[str, Any] | MigrationConfig | None" = None,
485
+ statement_config: "StatementConfig | None" = None,
486
+ driver_features: "dict[str, Any] | None" = None,
487
+ bind_key: "str | None" = None,
488
+ extension_config: "dict[str, dict[str, Any]] | None" = None,
318
489
  ) -> None:
490
+ self.bind_key = bind_key
319
491
  self.pool_instance = None
320
492
  self.connection_config = connection_config or {}
321
- self.migration_config: Union[dict[str, Any], MigrationConfig] = migration_config or {}
493
+ self.extension_config: dict[str, dict[str, Any]] = extension_config or {}
494
+ self.migration_config: dict[str, Any] | MigrationConfig = migration_config or {}
322
495
  self._initialize_migration_components()
323
496
 
324
497
  if statement_config is None:
@@ -339,7 +512,7 @@ class NoPoolSyncConfig(DatabaseConfigProtocol[ConnectionT, None, DriverT]):
339
512
  raise NotImplementedError
340
513
 
341
514
  def provide_session(
342
- self, *args: Any, statement_config: "Optional[StatementConfig]" = None, **kwargs: Any
515
+ self, *args: Any, statement_config: "StatementConfig | None" = None, **kwargs: Any
343
516
  ) -> "AbstractContextManager[DriverT]":
344
517
  """Provide a database session context manager."""
345
518
  raise NotImplementedError
@@ -357,7 +530,7 @@ class NoPoolSyncConfig(DatabaseConfigProtocol[ConnectionT, None, DriverT]):
357
530
  class NoPoolAsyncConfig(DatabaseConfigProtocol[ConnectionT, None, DriverT]):
358
531
  """Base class for async database configurations that do not implement a pool."""
359
532
 
360
- __slots__ = ("connection_config",)
533
+ __slots__ = ("connection_config", "extension_config")
361
534
  is_async: "ClassVar[bool]" = True
362
535
  supports_connection_pooling: "ClassVar[bool]" = False
363
536
  migration_tracker_type: "ClassVar[type[Any]]" = AsyncMigrationTracker
@@ -365,14 +538,18 @@ class NoPoolAsyncConfig(DatabaseConfigProtocol[ConnectionT, None, DriverT]):
365
538
  def __init__(
366
539
  self,
367
540
  *,
368
- connection_config: "Optional[dict[str, Any]]" = None,
369
- migration_config: "Optional[Union[dict[str, Any], MigrationConfig]]" = None,
370
- statement_config: "Optional[StatementConfig]" = None,
371
- driver_features: "Optional[dict[str, Any]]" = None,
541
+ connection_config: "dict[str, Any] | None" = None,
542
+ migration_config: "dict[str, Any] | MigrationConfig | None" = None,
543
+ statement_config: "StatementConfig | None" = None,
544
+ driver_features: "dict[str, Any] | None" = None,
545
+ bind_key: "str | None" = None,
546
+ extension_config: "dict[str, dict[str, Any]] | None" = None,
372
547
  ) -> None:
548
+ self.bind_key = bind_key
373
549
  self.pool_instance = None
374
550
  self.connection_config = connection_config or {}
375
- self.migration_config: Union[dict[str, Any], MigrationConfig] = migration_config or {}
551
+ self.extension_config: dict[str, dict[str, Any]] = extension_config or {}
552
+ self.migration_config: dict[str, Any] | MigrationConfig = migration_config or {}
376
553
  self._initialize_migration_components()
377
554
 
378
555
  if statement_config is None:
@@ -393,7 +570,7 @@ class NoPoolAsyncConfig(DatabaseConfigProtocol[ConnectionT, None, DriverT]):
393
570
  raise NotImplementedError
394
571
 
395
572
  def provide_session(
396
- self, *args: Any, statement_config: "Optional[StatementConfig]" = None, **kwargs: Any
573
+ self, *args: Any, statement_config: "StatementConfig | None" = None, **kwargs: Any
397
574
  ) -> "AbstractAsyncContextManager[DriverT]":
398
575
  """Provide a database session context manager."""
399
576
  raise NotImplementedError
@@ -411,7 +588,7 @@ class NoPoolAsyncConfig(DatabaseConfigProtocol[ConnectionT, None, DriverT]):
411
588
  class SyncDatabaseConfig(DatabaseConfigProtocol[ConnectionT, PoolT, DriverT]):
412
589
  """Base class for sync database configurations with connection pooling."""
413
590
 
414
- __slots__ = ("pool_config",)
591
+ __slots__ = ("extension_config", "pool_config")
415
592
  is_async: "ClassVar[bool]" = False
416
593
  supports_connection_pooling: "ClassVar[bool]" = True
417
594
  migration_tracker_type: "ClassVar[type[Any]]" = SyncMigrationTracker
@@ -419,15 +596,19 @@ class SyncDatabaseConfig(DatabaseConfigProtocol[ConnectionT, PoolT, DriverT]):
419
596
  def __init__(
420
597
  self,
421
598
  *,
422
- pool_config: "Optional[dict[str, Any]]" = None,
423
- pool_instance: "Optional[PoolT]" = None,
424
- migration_config: "Optional[Union[dict[str, Any], MigrationConfig]]" = None,
425
- statement_config: "Optional[StatementConfig]" = None,
426
- driver_features: "Optional[dict[str, Any]]" = None,
599
+ pool_config: "dict[str, Any] | None" = None,
600
+ pool_instance: "PoolT | None" = None,
601
+ migration_config: "dict[str, Any] | MigrationConfig | None" = None,
602
+ statement_config: "StatementConfig | None" = None,
603
+ driver_features: "dict[str, Any] | None" = None,
604
+ bind_key: "str | None" = None,
605
+ extension_config: "dict[str, dict[str, Any]] | None" = None,
427
606
  ) -> None:
607
+ self.bind_key = bind_key
428
608
  self.pool_instance = pool_instance
429
609
  self.pool_config = pool_config or {}
430
- self.migration_config: Union[dict[str, Any], MigrationConfig] = migration_config or {}
610
+ self.extension_config: dict[str, dict[str, Any]] = extension_config or {}
611
+ self.migration_config: dict[str, Any] | MigrationConfig = migration_config or {}
431
612
  self._initialize_migration_components()
432
613
 
433
614
  if statement_config is None:
@@ -469,7 +650,7 @@ class SyncDatabaseConfig(DatabaseConfigProtocol[ConnectionT, PoolT, DriverT]):
469
650
  raise NotImplementedError
470
651
 
471
652
  def provide_session(
472
- self, *args: Any, statement_config: "Optional[StatementConfig]" = None, **kwargs: Any
653
+ self, *args: Any, statement_config: "StatementConfig | None" = None, **kwargs: Any
473
654
  ) -> "AbstractContextManager[DriverT]":
474
655
  """Provide a database session context manager."""
475
656
  raise NotImplementedError
@@ -488,7 +669,7 @@ class SyncDatabaseConfig(DatabaseConfigProtocol[ConnectionT, PoolT, DriverT]):
488
669
  class AsyncDatabaseConfig(DatabaseConfigProtocol[ConnectionT, PoolT, DriverT]):
489
670
  """Base class for async database configurations with connection pooling."""
490
671
 
491
- __slots__ = ("pool_config",)
672
+ __slots__ = ("extension_config", "pool_config")
492
673
  is_async: "ClassVar[bool]" = True
493
674
  supports_connection_pooling: "ClassVar[bool]" = True
494
675
  migration_tracker_type: "ClassVar[type[Any]]" = AsyncMigrationTracker
@@ -496,15 +677,19 @@ class AsyncDatabaseConfig(DatabaseConfigProtocol[ConnectionT, PoolT, DriverT]):
496
677
  def __init__(
497
678
  self,
498
679
  *,
499
- pool_config: "Optional[dict[str, Any]]" = None,
500
- pool_instance: "Optional[PoolT]" = None,
501
- migration_config: "Optional[Union[dict[str, Any], MigrationConfig]]" = None,
502
- statement_config: "Optional[StatementConfig]" = None,
503
- driver_features: "Optional[dict[str, Any]]" = None,
680
+ pool_config: "dict[str, Any] | None" = None,
681
+ pool_instance: "PoolT | None" = None,
682
+ migration_config: "dict[str, Any] | MigrationConfig | None" = None,
683
+ statement_config: "StatementConfig | None" = None,
684
+ driver_features: "dict[str, Any] | None" = None,
685
+ bind_key: "str | None" = None,
686
+ extension_config: "dict[str, dict[str, Any]] | None" = None,
504
687
  ) -> None:
688
+ self.bind_key = bind_key
505
689
  self.pool_instance = pool_instance
506
690
  self.pool_config = pool_config or {}
507
- self.migration_config: Union[dict[str, Any], MigrationConfig] = migration_config or {}
691
+ self.extension_config: dict[str, dict[str, Any]] = extension_config or {}
692
+ self.migration_config: dict[str, Any] | MigrationConfig = migration_config or {}
508
693
  self._initialize_migration_components()
509
694
 
510
695
  if statement_config is None:
@@ -548,7 +733,7 @@ class AsyncDatabaseConfig(DatabaseConfigProtocol[ConnectionT, PoolT, DriverT]):
548
733
  raise NotImplementedError
549
734
 
550
735
  def provide_session(
551
- self, *args: Any, statement_config: "Optional[StatementConfig]" = None, **kwargs: Any
736
+ self, *args: Any, statement_config: "StatementConfig | None" = None, **kwargs: Any
552
737
  ) -> "AbstractAsyncContextManager[DriverT]":
553
738
  """Provide a database session context manager."""
554
739
  raise NotImplementedError
sqlspec/core/__init__.py CHANGED
@@ -1,9 +1,9 @@
1
- """SQLSpec Core Module - High-Performance SQL Processing System.
1
+ """SQLSpec Core Module - SQL Processing System.
2
2
 
3
3
  This module provides the core SQL processing infrastructure for SQLSpec, implementing
4
4
  a complete pipeline for SQL statement compilation, parameter processing, caching,
5
- and result management. All components are optimized for MyPyC compilation and
6
- designed for maximum performance with minimal overhead.
5
+ and result management. All components are optimized for MyPyC compilation to
6
+ reduce overhead.
7
7
 
8
8
  Architecture Overview:
9
9
  The core module implements a single-pass processing pipeline where SQL statements
@@ -90,7 +90,7 @@ Example Usage:
90
90
  """
91
91
 
92
92
  from sqlspec.core import filters
93
- from sqlspec.core.cache import CacheConfig, CacheStats, MultiLevelCache, UnifiedCache, get_cache
93
+ from sqlspec.core.cache import CacheConfig, CacheStats, MultiLevelCache, UnifiedCache, get_cache, get_cache_config
94
94
  from sqlspec.core.compiler import OperationType, SQLProcessor
95
95
  from sqlspec.core.filters import StatementFilter
96
96
  from sqlspec.core.hashing import (
@@ -131,6 +131,7 @@ __all__ = (
131
131
  "UnifiedCache",
132
132
  "filters",
133
133
  "get_cache",
134
+ "get_cache_config",
134
135
  "hash_expression",
135
136
  "hash_expression_node",
136
137
  "hash_optimized_expression",