sqlspec 0.13.1__py3-none-any.whl → 0.16.2__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 (185) hide show
  1. sqlspec/__init__.py +71 -8
  2. sqlspec/__main__.py +12 -0
  3. sqlspec/__metadata__.py +1 -3
  4. sqlspec/_serialization.py +1 -2
  5. sqlspec/_sql.py +930 -136
  6. sqlspec/_typing.py +278 -142
  7. sqlspec/adapters/adbc/__init__.py +4 -3
  8. sqlspec/adapters/adbc/_types.py +12 -0
  9. sqlspec/adapters/adbc/config.py +116 -285
  10. sqlspec/adapters/adbc/driver.py +462 -340
  11. sqlspec/adapters/aiosqlite/__init__.py +18 -3
  12. sqlspec/adapters/aiosqlite/_types.py +13 -0
  13. sqlspec/adapters/aiosqlite/config.py +202 -150
  14. sqlspec/adapters/aiosqlite/driver.py +226 -247
  15. sqlspec/adapters/asyncmy/__init__.py +18 -3
  16. sqlspec/adapters/asyncmy/_types.py +12 -0
  17. sqlspec/adapters/asyncmy/config.py +80 -199
  18. sqlspec/adapters/asyncmy/driver.py +257 -215
  19. sqlspec/adapters/asyncpg/__init__.py +19 -4
  20. sqlspec/adapters/asyncpg/_types.py +17 -0
  21. sqlspec/adapters/asyncpg/config.py +81 -214
  22. sqlspec/adapters/asyncpg/driver.py +284 -359
  23. sqlspec/adapters/bigquery/__init__.py +17 -3
  24. sqlspec/adapters/bigquery/_types.py +12 -0
  25. sqlspec/adapters/bigquery/config.py +191 -299
  26. sqlspec/adapters/bigquery/driver.py +474 -634
  27. sqlspec/adapters/duckdb/__init__.py +14 -3
  28. sqlspec/adapters/duckdb/_types.py +12 -0
  29. sqlspec/adapters/duckdb/config.py +414 -397
  30. sqlspec/adapters/duckdb/driver.py +342 -393
  31. sqlspec/adapters/oracledb/__init__.py +19 -5
  32. sqlspec/adapters/oracledb/_types.py +14 -0
  33. sqlspec/adapters/oracledb/config.py +123 -458
  34. sqlspec/adapters/oracledb/driver.py +505 -531
  35. sqlspec/adapters/psqlpy/__init__.py +13 -3
  36. sqlspec/adapters/psqlpy/_types.py +11 -0
  37. sqlspec/adapters/psqlpy/config.py +93 -307
  38. sqlspec/adapters/psqlpy/driver.py +504 -213
  39. sqlspec/adapters/psycopg/__init__.py +19 -5
  40. sqlspec/adapters/psycopg/_types.py +17 -0
  41. sqlspec/adapters/psycopg/config.py +143 -472
  42. sqlspec/adapters/psycopg/driver.py +704 -825
  43. sqlspec/adapters/sqlite/__init__.py +14 -3
  44. sqlspec/adapters/sqlite/_types.py +11 -0
  45. sqlspec/adapters/sqlite/config.py +208 -142
  46. sqlspec/adapters/sqlite/driver.py +263 -278
  47. sqlspec/base.py +105 -9
  48. sqlspec/{statement/builder → builder}/__init__.py +12 -14
  49. sqlspec/{statement/builder/base.py → builder/_base.py} +184 -86
  50. sqlspec/{statement/builder/column.py → builder/_column.py} +97 -60
  51. sqlspec/{statement/builder/ddl.py → builder/_ddl.py} +61 -131
  52. sqlspec/{statement/builder → builder}/_ddl_utils.py +4 -10
  53. sqlspec/{statement/builder/delete.py → builder/_delete.py} +10 -30
  54. sqlspec/builder/_insert.py +421 -0
  55. sqlspec/builder/_merge.py +71 -0
  56. sqlspec/{statement/builder → builder}/_parsing_utils.py +49 -26
  57. sqlspec/builder/_select.py +170 -0
  58. sqlspec/{statement/builder/update.py → builder/_update.py} +16 -20
  59. sqlspec/builder/mixins/__init__.py +55 -0
  60. sqlspec/builder/mixins/_cte_and_set_ops.py +222 -0
  61. sqlspec/{statement/builder/mixins/_delete_from.py → builder/mixins/_delete_operations.py} +8 -1
  62. sqlspec/builder/mixins/_insert_operations.py +244 -0
  63. sqlspec/{statement/builder/mixins/_join.py → builder/mixins/_join_operations.py} +45 -13
  64. sqlspec/{statement/builder/mixins/_merge_clauses.py → builder/mixins/_merge_operations.py} +188 -30
  65. sqlspec/builder/mixins/_order_limit_operations.py +135 -0
  66. sqlspec/builder/mixins/_pivot_operations.py +153 -0
  67. sqlspec/builder/mixins/_select_operations.py +604 -0
  68. sqlspec/builder/mixins/_update_operations.py +202 -0
  69. sqlspec/builder/mixins/_where_clause.py +644 -0
  70. sqlspec/cli.py +247 -0
  71. sqlspec/config.py +183 -138
  72. sqlspec/core/__init__.py +63 -0
  73. sqlspec/core/cache.py +871 -0
  74. sqlspec/core/compiler.py +417 -0
  75. sqlspec/core/filters.py +830 -0
  76. sqlspec/core/hashing.py +310 -0
  77. sqlspec/core/parameters.py +1237 -0
  78. sqlspec/core/result.py +677 -0
  79. sqlspec/{statement → core}/splitter.py +321 -191
  80. sqlspec/core/statement.py +676 -0
  81. sqlspec/driver/__init__.py +7 -10
  82. sqlspec/driver/_async.py +422 -163
  83. sqlspec/driver/_common.py +545 -287
  84. sqlspec/driver/_sync.py +426 -160
  85. sqlspec/driver/mixins/__init__.py +2 -13
  86. sqlspec/driver/mixins/_result_tools.py +193 -0
  87. sqlspec/driver/mixins/_sql_translator.py +65 -14
  88. sqlspec/exceptions.py +5 -252
  89. sqlspec/extensions/aiosql/adapter.py +93 -96
  90. sqlspec/extensions/litestar/__init__.py +2 -1
  91. sqlspec/extensions/litestar/cli.py +48 -0
  92. sqlspec/extensions/litestar/config.py +0 -1
  93. sqlspec/extensions/litestar/handlers.py +15 -26
  94. sqlspec/extensions/litestar/plugin.py +21 -16
  95. sqlspec/extensions/litestar/providers.py +17 -52
  96. sqlspec/loader.py +423 -104
  97. sqlspec/migrations/__init__.py +35 -0
  98. sqlspec/migrations/base.py +414 -0
  99. sqlspec/migrations/commands.py +443 -0
  100. sqlspec/migrations/loaders.py +402 -0
  101. sqlspec/migrations/runner.py +213 -0
  102. sqlspec/migrations/tracker.py +140 -0
  103. sqlspec/migrations/utils.py +129 -0
  104. sqlspec/protocols.py +51 -186
  105. sqlspec/storage/__init__.py +1 -1
  106. sqlspec/storage/backends/base.py +37 -40
  107. sqlspec/storage/backends/fsspec.py +136 -112
  108. sqlspec/storage/backends/obstore.py +138 -160
  109. sqlspec/storage/capabilities.py +5 -4
  110. sqlspec/storage/registry.py +57 -106
  111. sqlspec/typing.py +136 -115
  112. sqlspec/utils/__init__.py +2 -2
  113. sqlspec/utils/correlation.py +0 -3
  114. sqlspec/utils/deprecation.py +6 -6
  115. sqlspec/utils/fixtures.py +6 -6
  116. sqlspec/utils/logging.py +0 -2
  117. sqlspec/utils/module_loader.py +7 -12
  118. sqlspec/utils/singleton.py +0 -1
  119. sqlspec/utils/sync_tools.py +17 -38
  120. sqlspec/utils/text.py +12 -51
  121. sqlspec/utils/type_guards.py +482 -235
  122. {sqlspec-0.13.1.dist-info → sqlspec-0.16.2.dist-info}/METADATA +7 -2
  123. sqlspec-0.16.2.dist-info/RECORD +134 -0
  124. sqlspec-0.16.2.dist-info/entry_points.txt +2 -0
  125. sqlspec/driver/connection.py +0 -207
  126. sqlspec/driver/mixins/_csv_writer.py +0 -91
  127. sqlspec/driver/mixins/_pipeline.py +0 -512
  128. sqlspec/driver/mixins/_result_utils.py +0 -140
  129. sqlspec/driver/mixins/_storage.py +0 -926
  130. sqlspec/driver/mixins/_type_coercion.py +0 -130
  131. sqlspec/driver/parameters.py +0 -138
  132. sqlspec/service/__init__.py +0 -4
  133. sqlspec/service/_util.py +0 -147
  134. sqlspec/service/base.py +0 -1131
  135. sqlspec/service/pagination.py +0 -26
  136. sqlspec/statement/__init__.py +0 -21
  137. sqlspec/statement/builder/insert.py +0 -288
  138. sqlspec/statement/builder/merge.py +0 -95
  139. sqlspec/statement/builder/mixins/__init__.py +0 -65
  140. sqlspec/statement/builder/mixins/_aggregate_functions.py +0 -250
  141. sqlspec/statement/builder/mixins/_case_builder.py +0 -91
  142. sqlspec/statement/builder/mixins/_common_table_expr.py +0 -90
  143. sqlspec/statement/builder/mixins/_from.py +0 -63
  144. sqlspec/statement/builder/mixins/_group_by.py +0 -118
  145. sqlspec/statement/builder/mixins/_having.py +0 -35
  146. sqlspec/statement/builder/mixins/_insert_from_select.py +0 -47
  147. sqlspec/statement/builder/mixins/_insert_into.py +0 -36
  148. sqlspec/statement/builder/mixins/_insert_values.py +0 -67
  149. sqlspec/statement/builder/mixins/_limit_offset.py +0 -53
  150. sqlspec/statement/builder/mixins/_order_by.py +0 -46
  151. sqlspec/statement/builder/mixins/_pivot.py +0 -79
  152. sqlspec/statement/builder/mixins/_returning.py +0 -37
  153. sqlspec/statement/builder/mixins/_select_columns.py +0 -61
  154. sqlspec/statement/builder/mixins/_set_ops.py +0 -122
  155. sqlspec/statement/builder/mixins/_unpivot.py +0 -77
  156. sqlspec/statement/builder/mixins/_update_from.py +0 -55
  157. sqlspec/statement/builder/mixins/_update_set.py +0 -94
  158. sqlspec/statement/builder/mixins/_update_table.py +0 -29
  159. sqlspec/statement/builder/mixins/_where.py +0 -401
  160. sqlspec/statement/builder/mixins/_window_functions.py +0 -86
  161. sqlspec/statement/builder/select.py +0 -221
  162. sqlspec/statement/filters.py +0 -596
  163. sqlspec/statement/parameter_manager.py +0 -220
  164. sqlspec/statement/parameters.py +0 -867
  165. sqlspec/statement/pipelines/__init__.py +0 -210
  166. sqlspec/statement/pipelines/analyzers/__init__.py +0 -9
  167. sqlspec/statement/pipelines/analyzers/_analyzer.py +0 -646
  168. sqlspec/statement/pipelines/context.py +0 -115
  169. sqlspec/statement/pipelines/transformers/__init__.py +0 -7
  170. sqlspec/statement/pipelines/transformers/_expression_simplifier.py +0 -88
  171. sqlspec/statement/pipelines/transformers/_literal_parameterizer.py +0 -1247
  172. sqlspec/statement/pipelines/transformers/_remove_comments_and_hints.py +0 -76
  173. sqlspec/statement/pipelines/validators/__init__.py +0 -23
  174. sqlspec/statement/pipelines/validators/_dml_safety.py +0 -290
  175. sqlspec/statement/pipelines/validators/_parameter_style.py +0 -370
  176. sqlspec/statement/pipelines/validators/_performance.py +0 -718
  177. sqlspec/statement/pipelines/validators/_security.py +0 -967
  178. sqlspec/statement/result.py +0 -435
  179. sqlspec/statement/sql.py +0 -1704
  180. sqlspec/statement/sql_compiler.py +0 -140
  181. sqlspec/utils/cached_property.py +0 -25
  182. sqlspec-0.13.1.dist-info/RECORD +0 -150
  183. {sqlspec-0.13.1.dist-info → sqlspec-0.16.2.dist-info}/WHEEL +0 -0
  184. {sqlspec-0.13.1.dist-info → sqlspec-0.16.2.dist-info}/licenses/LICENSE +0 -0
  185. {sqlspec-0.13.1.dist-info → sqlspec-0.16.2.dist-info}/licenses/NOTICE +0 -0
@@ -1,4 +1,15 @@
1
- from sqlspec.adapters.sqlite.config import CONNECTION_FIELDS, SqliteConfig
2
- from sqlspec.adapters.sqlite.driver import SqliteConnection, SqliteDriver
1
+ """SQLite adapter for SQLSpec."""
3
2
 
4
- __all__ = ("CONNECTION_FIELDS", "SqliteConfig", "SqliteConnection", "SqliteDriver")
3
+ from sqlspec.adapters.sqlite._types import SqliteConnection
4
+ from sqlspec.adapters.sqlite.config import SqliteConfig, SqliteConnectionParams
5
+ from sqlspec.adapters.sqlite.driver import SqliteCursor, SqliteDriver, SqliteExceptionHandler, sqlite_statement_config
6
+
7
+ __all__ = (
8
+ "SqliteConfig",
9
+ "SqliteConnection",
10
+ "SqliteConnectionParams",
11
+ "SqliteCursor",
12
+ "SqliteDriver",
13
+ "SqliteExceptionHandler",
14
+ "sqlite_statement_config",
15
+ )
@@ -0,0 +1,11 @@
1
+ import sqlite3
2
+ from typing import TYPE_CHECKING
3
+
4
+ if TYPE_CHECKING:
5
+ from typing_extensions import TypeAlias
6
+
7
+ SqliteConnection: TypeAlias = sqlite3.Connection
8
+ else:
9
+ SqliteConnection = sqlite3.Connection
10
+
11
+ __all__ = ("SqliteConnection",)
@@ -1,174 +1,240 @@
1
- """SQLite database configuration with direct field-based configuration."""
1
+ """SQLite database configuration with thread-local connections."""
2
2
 
3
- import logging
4
3
  import sqlite3
4
+ import threading
5
5
  from contextlib import contextmanager
6
- from typing import TYPE_CHECKING, Any, ClassVar, Optional, Union
6
+ from typing import TYPE_CHECKING, Any, ClassVar, Optional, TypedDict, Union, cast
7
7
 
8
- from sqlspec.adapters.sqlite.driver import SqliteConnection, SqliteDriver
9
- from sqlspec.config import NoPoolSyncConfig
10
- from sqlspec.statement.sql import SQLConfig
11
- from sqlspec.typing import DictRow
8
+ from typing_extensions import NotRequired
9
+
10
+ from sqlspec.adapters.sqlite._types import SqliteConnection
11
+ from sqlspec.adapters.sqlite.driver import SqliteCursor, SqliteDriver, sqlite_statement_config
12
+ from sqlspec.config import SyncDatabaseConfig
12
13
 
13
14
  if TYPE_CHECKING:
14
15
  from collections.abc import Generator
15
16
 
16
- from sqlglot.dialects.dialect import DialectType
17
-
18
- logger = logging.getLogger(__name__)
19
-
20
- CONNECTION_FIELDS = frozenset(
21
- {
22
- "database",
23
- "timeout",
24
- "detect_types",
25
- "isolation_level",
26
- "check_same_thread",
27
- "factory",
28
- "cached_statements",
29
- "uri",
30
- }
31
- )
32
-
33
- __all__ = ("CONNECTION_FIELDS", "SqliteConfig", "sqlite3")
34
-
35
-
36
- class SqliteConfig(NoPoolSyncConfig[SqliteConnection, SqliteDriver]):
37
- """Configuration for SQLite database connections with direct field-based configuration."""
38
-
39
- __slots__ = (
40
- "_dialect",
41
- "cached_statements",
42
- "check_same_thread",
43
- "database",
44
- "default_row_type",
45
- "detect_types",
46
- "extras",
47
- "factory",
48
- "isolation_level",
49
- "pool_instance",
50
- "statement_config",
51
- "timeout",
52
- "uri",
53
- )
54
-
55
- driver_type: type[SqliteDriver] = SqliteDriver
56
- connection_type: type[SqliteConnection] = SqliteConnection
57
- supported_parameter_styles: ClassVar[tuple[str, ...]] = ("qmark", "named_colon")
58
- preferred_parameter_style: ClassVar[str] = "qmark"
17
+ from sqlspec.core.statement import StatementConfig
18
+
19
+
20
+ class SqliteConnectionParams(TypedDict, total=False):
21
+ """SQLite connection parameters."""
22
+
23
+ database: NotRequired[str]
24
+ timeout: NotRequired[float]
25
+ detect_types: NotRequired[int]
26
+ isolation_level: "NotRequired[Optional[str]]"
27
+ check_same_thread: NotRequired[bool]
28
+ factory: "NotRequired[Optional[type[SqliteConnection]]]"
29
+ cached_statements: NotRequired[int]
30
+ uri: NotRequired[bool]
31
+
32
+
33
+ __all__ = ("SqliteConfig", "SqliteConnectionParams", "SqliteConnectionPool")
34
+
35
+
36
+ class SqliteConnectionPool:
37
+ """Thread-local connection manager for SQLite.
38
+
39
+ SQLite connections aren't thread-safe, so we use thread-local storage
40
+ to ensure each thread has its own connection. This is simpler and more
41
+ efficient than a traditional pool for SQLite's constraints.
42
+ """
43
+
44
+ __slots__ = ("_connection_parameters", "_enable_optimizations", "_thread_local")
59
45
 
60
46
  def __init__(
61
47
  self,
62
- database: str = ":memory:",
63
- statement_config: Optional[SQLConfig] = None,
64
- default_row_type: type[DictRow] = DictRow,
65
- # SQLite connection parameters
66
- timeout: Optional[float] = None,
67
- detect_types: Optional[int] = None,
68
- isolation_level: Optional[Union[str, None]] = None,
69
- check_same_thread: Optional[bool] = None,
70
- factory: Optional[type[SqliteConnection]] = None,
71
- cached_statements: Optional[int] = None,
72
- uri: Optional[bool] = None,
73
- **kwargs: Any,
48
+ connection_parameters: "dict[str, Any]",
49
+ enable_optimizations: bool = True,
50
+ **kwargs: Any, # Accept and ignore pool parameters for compatibility
51
+ ) -> None:
52
+ """Initialize the thread-local connection manager.
53
+
54
+ Args:
55
+ connection_parameters: SQLite connection parameters
56
+ enable_optimizations: Whether to apply performance PRAGMAs
57
+ **kwargs: Ignored pool parameters for compatibility
58
+ """
59
+ self._connection_parameters = connection_parameters
60
+ self._thread_local = threading.local()
61
+ self._enable_optimizations = enable_optimizations
62
+
63
+ def _create_connection(self) -> SqliteConnection:
64
+ """Create a new SQLite connection with optimizations."""
65
+ connection = sqlite3.connect(**self._connection_parameters)
66
+
67
+ # Only apply optimizations if requested and not in-memory
68
+ if self._enable_optimizations:
69
+ database = self._connection_parameters.get("database", ":memory:")
70
+ is_memory = database == ":memory:" or database.startswith("file::memory:")
71
+
72
+ if not is_memory:
73
+ # WAL mode doesn't work with in-memory databases
74
+ connection.execute("PRAGMA journal_mode = WAL")
75
+ # Set busy timeout for better concurrent access
76
+ connection.execute("PRAGMA busy_timeout = 5000")
77
+ connection.execute("PRAGMA optimize")
78
+ # These work for all database types
79
+ connection.execute("PRAGMA foreign_keys = ON")
80
+ connection.execute("PRAGMA synchronous = NORMAL")
81
+
82
+ return connection # type: ignore[no-any-return]
83
+
84
+ def _get_thread_connection(self) -> SqliteConnection:
85
+ """Get or create a connection for the current thread."""
86
+ try:
87
+ return cast("SqliteConnection", self._thread_local.connection)
88
+ except AttributeError:
89
+ # Connection doesn't exist for this thread yet
90
+ connection = self._create_connection()
91
+ self._thread_local.connection = connection
92
+ return connection
93
+
94
+ def _close_thread_connection(self) -> None:
95
+ """Close the connection for the current thread."""
96
+ try:
97
+ connection = self._thread_local.connection
98
+ connection.close()
99
+ del self._thread_local.connection
100
+ except AttributeError:
101
+ # No connection for this thread
102
+ pass
103
+
104
+ @contextmanager
105
+ def get_connection(self) -> "Generator[SqliteConnection, None, None]":
106
+ """Get a thread-local connection.
107
+
108
+ Yields:
109
+ SqliteConnection: A thread-local connection.
110
+ """
111
+ yield self._get_thread_connection()
112
+
113
+ def close(self) -> None:
114
+ """Close the thread-local connection if it exists."""
115
+ self._close_thread_connection()
116
+
117
+ def acquire(self) -> SqliteConnection:
118
+ """Acquire a thread-local connection.
119
+
120
+ Returns:
121
+ SqliteConnection: A thread-local connection
122
+ """
123
+ return self._get_thread_connection()
124
+
125
+ def release(self, connection: SqliteConnection) -> None:
126
+ """Release a connection (no-op for thread-local connections).
127
+
128
+ Args:
129
+ connection: The connection to release (ignored)
130
+ """
131
+ # No-op: thread-local connections are managed per-thread
132
+
133
+ # Compatibility methods that return dummy values
134
+ def size(self) -> int:
135
+ """Get pool size (always 1 for thread-local)."""
136
+ try:
137
+ _ = self._thread_local.connection
138
+ except AttributeError:
139
+ return 0
140
+ return 1
141
+
142
+ def checked_out(self) -> int:
143
+ """Get number of checked out connections (always 0)."""
144
+ return 0
145
+
146
+
147
+ class SqliteConfig(SyncDatabaseConfig[SqliteConnection, SqliteConnectionPool, SqliteDriver]):
148
+ """SQLite configuration with thread-local connections."""
149
+
150
+ driver_type: "ClassVar[type[SqliteDriver]]" = SqliteDriver
151
+ connection_type: "ClassVar[type[SqliteConnection]]" = SqliteConnection
152
+
153
+ def __init__(
154
+ self,
155
+ *,
156
+ pool_config: "Optional[Union[SqliteConnectionParams, dict[str, Any]]]" = None,
157
+ pool_instance: "Optional[SqliteConnectionPool]" = None,
158
+ statement_config: "Optional[StatementConfig]" = None,
159
+ migration_config: "Optional[dict[str, Any]]" = None,
74
160
  ) -> None:
75
161
  """Initialize SQLite configuration.
76
162
 
77
163
  Args:
78
- database: Path to the SQLite database file. Use ':memory:' for in-memory database.
164
+ pool_config: Configuration parameters including connection settings
165
+ pool_instance: Pre-created pool instance
79
166
  statement_config: Default SQL statement configuration
80
- default_row_type: Default row type for results
81
- timeout: Connection timeout in seconds
82
- detect_types: Type detection flags (sqlite3.PARSE_DECLTYPES | sqlite3.PARSE_COLNAMES)
83
- isolation_level: Transaction isolation level
84
- check_same_thread: Whether to check that connection is used on same thread
85
- factory: Custom Connection class factory
86
- cached_statements: Number of statements to cache
87
- uri: Whether to interpret database as URI
88
- **kwargs: Additional parameters (stored in extras)
167
+ migration_config: Migration configuration
89
168
  """
90
- if database is None:
91
- msg = "database parameter cannot be None"
92
- raise TypeError(msg)
93
-
94
- # Store connection parameters as instance attributes
95
- self.database = database
96
- self.timeout = timeout
97
- self.detect_types = detect_types
98
- self.isolation_level = isolation_level
99
- self.check_same_thread = check_same_thread
100
- self.factory = factory
101
- self.cached_statements = cached_statements
102
- self.uri = uri
103
-
104
- self.extras = kwargs or {}
105
-
106
- # Store other config
107
- self.statement_config = statement_config or SQLConfig()
108
- self.default_row_type = default_row_type
109
- self._dialect: DialectType = None
110
- super().__init__()
111
-
112
- @property
113
- def connection_config_dict(self) -> dict[str, Any]:
114
- """Return a dictionary of connection parameters for SQLite."""
115
- config = {
116
- "database": self.database,
117
- "timeout": self.timeout,
118
- "detect_types": self.detect_types,
119
- "isolation_level": self.isolation_level,
120
- "check_same_thread": self.check_same_thread,
121
- "factory": self.factory,
122
- "cached_statements": self.cached_statements,
123
- "uri": self.uri,
124
- }
125
- # Filter out None values since sqlite3.connect doesn't accept them
126
- return {k: v for k, v in config.items() if v is not None}
169
+ if pool_config is None:
170
+ pool_config = {}
171
+ if "database" not in pool_config or pool_config["database"] == ":memory:":
172
+ pool_config["database"] = "file::memory:?cache=shared"
173
+ pool_config["uri"] = True
174
+
175
+ super().__init__(
176
+ pool_instance=pool_instance,
177
+ pool_config=cast("dict[str, Any]", pool_config),
178
+ migration_config=migration_config,
179
+ statement_config=statement_config or sqlite_statement_config,
180
+ driver_features={},
181
+ )
182
+
183
+ def _get_connection_config_dict(self) -> "dict[str, Any]":
184
+ """Get connection configuration as plain dict for pool creation."""
185
+ # Filter out pool-specific parameters that SQLite doesn't use
186
+ excluded_keys = {"pool_min_size", "pool_max_size", "pool_timeout", "pool_recycle_seconds", "extra"}
187
+ return {k: v for k, v in self.pool_config.items() if v is not None and k not in excluded_keys}
188
+
189
+ def _create_pool(self) -> SqliteConnectionPool:
190
+ """Create connection pool from configuration."""
191
+ config_dict = self._get_connection_config_dict()
192
+ # Pass all pool_config as kwargs to be ignored by the pool
193
+ return SqliteConnectionPool(connection_parameters=config_dict, **self.pool_config)
194
+
195
+ def _close_pool(self) -> None:
196
+ """Close the connection pool."""
197
+ if self.pool_instance:
198
+ self.pool_instance.close()
127
199
 
128
200
  def create_connection(self) -> SqliteConnection:
129
- """Create and return a SQLite connection."""
130
- connection = sqlite3.connect(**self.connection_config_dict)
131
- connection.row_factory = sqlite3.Row
132
- return connection # type: ignore[no-any-return]
201
+ """Get a SQLite connection from the pool.
202
+
203
+ Returns:
204
+ SqliteConnection: A connection from the pool
205
+ """
206
+ pool = self.provide_pool()
207
+ return pool.acquire()
133
208
 
134
209
  @contextmanager
135
- def provide_connection(self, *args: Any, **kwargs: Any) -> "Generator[SqliteConnection, None, None]":
210
+ def provide_connection(self, *args: "Any", **kwargs: "Any") -> "Generator[SqliteConnection, None, None]":
136
211
  """Provide a SQLite connection context manager.
137
212
 
138
- Args:
139
- *args: Variable length argument list
140
- **kwargs: Arbitrary keyword arguments
141
-
142
213
  Yields:
143
- SqliteConnection: A SQLite connection
144
-
214
+ SqliteConnection: A thread-local connection
145
215
  """
146
- connection = self.create_connection()
147
- try:
216
+ pool = self.provide_pool()
217
+ with pool.get_connection() as connection:
148
218
  yield connection
149
- finally:
150
- connection.close()
151
219
 
152
220
  @contextmanager
153
- def provide_session(self, *args: Any, **kwargs: Any) -> "Generator[SqliteDriver, None, None]":
154
- """Provide a SQLite driver session context manager.
155
-
156
- Args:
157
- *args: Variable length argument list
158
- **kwargs: Arbitrary keyword arguments
221
+ def provide_session(
222
+ self, *args: "Any", statement_config: "Optional[StatementConfig]" = None, **kwargs: "Any"
223
+ ) -> "Generator[SqliteDriver, None, None]":
224
+ """Provide a SQLite driver session.
159
225
 
160
226
  Yields:
161
- SqliteDriver: A SQLite driver
227
+ SqliteDriver: A driver instance with thread-local connection
162
228
  """
163
229
  with self.provide_connection(*args, **kwargs) as connection:
164
- statement_config = self.statement_config
165
- # Inject parameter style info if not already set
166
- if statement_config.allowed_parameter_styles is None:
167
- from dataclasses import replace
168
-
169
- statement_config = replace(
170
- statement_config,
171
- allowed_parameter_styles=self.supported_parameter_styles,
172
- target_parameter_style=self.preferred_parameter_style,
173
- )
174
- yield self.driver_type(connection=connection, config=statement_config)
230
+ yield self.driver_type(connection=connection, statement_config=statement_config or self.statement_config)
231
+
232
+ def get_signature_namespace(self) -> "dict[str, type[Any]]":
233
+ """Get the signature namespace for SQLite types.
234
+
235
+ Returns:
236
+ Dictionary mapping type names to types.
237
+ """
238
+ namespace = super().get_signature_namespace()
239
+ namespace.update({"SqliteConnection": SqliteConnection, "SqliteCursor": SqliteCursor})
240
+ return namespace