sqlspec 0.8.0__py3-none-any.whl → 0.9.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 (45) hide show
  1. sqlspec/_typing.py +39 -6
  2. sqlspec/adapters/adbc/__init__.py +2 -2
  3. sqlspec/adapters/adbc/config.py +34 -11
  4. sqlspec/adapters/adbc/driver.py +167 -108
  5. sqlspec/adapters/aiosqlite/__init__.py +2 -2
  6. sqlspec/adapters/aiosqlite/config.py +2 -2
  7. sqlspec/adapters/aiosqlite/driver.py +28 -39
  8. sqlspec/adapters/asyncmy/__init__.py +3 -3
  9. sqlspec/adapters/asyncmy/config.py +11 -12
  10. sqlspec/adapters/asyncmy/driver.py +25 -34
  11. sqlspec/adapters/asyncpg/__init__.py +5 -5
  12. sqlspec/adapters/asyncpg/config.py +17 -19
  13. sqlspec/adapters/asyncpg/driver.py +249 -93
  14. sqlspec/adapters/duckdb/__init__.py +2 -2
  15. sqlspec/adapters/duckdb/config.py +2 -2
  16. sqlspec/adapters/duckdb/driver.py +49 -49
  17. sqlspec/adapters/oracledb/__init__.py +8 -8
  18. sqlspec/adapters/oracledb/config/__init__.py +6 -6
  19. sqlspec/adapters/oracledb/config/_asyncio.py +9 -10
  20. sqlspec/adapters/oracledb/config/_sync.py +8 -9
  21. sqlspec/adapters/oracledb/driver.py +114 -41
  22. sqlspec/adapters/psqlpy/__init__.py +0 -0
  23. sqlspec/adapters/psqlpy/config.py +258 -0
  24. sqlspec/adapters/psqlpy/driver.py +335 -0
  25. sqlspec/adapters/psycopg/__init__.py +10 -5
  26. sqlspec/adapters/psycopg/config/__init__.py +6 -6
  27. sqlspec/adapters/psycopg/config/_async.py +12 -12
  28. sqlspec/adapters/psycopg/config/_sync.py +13 -13
  29. sqlspec/adapters/psycopg/driver.py +180 -218
  30. sqlspec/adapters/sqlite/__init__.py +2 -2
  31. sqlspec/adapters/sqlite/config.py +2 -2
  32. sqlspec/adapters/sqlite/driver.py +43 -41
  33. sqlspec/base.py +275 -153
  34. sqlspec/exceptions.py +30 -0
  35. sqlspec/extensions/litestar/config.py +6 -0
  36. sqlspec/extensions/litestar/handlers.py +25 -0
  37. sqlspec/extensions/litestar/plugin.py +6 -1
  38. sqlspec/statement.py +373 -0
  39. sqlspec/typing.py +10 -1
  40. {sqlspec-0.8.0.dist-info → sqlspec-0.9.0.dist-info}/METADATA +4 -1
  41. sqlspec-0.9.0.dist-info/RECORD +61 -0
  42. sqlspec-0.8.0.dist-info/RECORD +0 -57
  43. {sqlspec-0.8.0.dist-info → sqlspec-0.9.0.dist-info}/WHEEL +0 -0
  44. {sqlspec-0.8.0.dist-info → sqlspec-0.9.0.dist-info}/licenses/LICENSE +0 -0
  45. {sqlspec-0.8.0.dist-info → sqlspec-0.9.0.dist-info}/licenses/NOTICE +0 -0
@@ -1,24 +1,24 @@
1
1
  from contextlib import contextmanager
2
2
  from typing import TYPE_CHECKING, Any, Optional, Union, cast
3
3
 
4
- from sqlspec.base import SyncDriverAdapterProtocol, T
4
+ from sqlspec.base import SyncArrowBulkOperationsMixin, SyncDriverAdapterProtocol, T
5
5
 
6
6
  if TYPE_CHECKING:
7
7
  from collections.abc import Generator
8
8
 
9
9
  from duckdb import DuckDBPyConnection
10
10
 
11
- from sqlspec.typing import ModelDTOT, StatementParameterType
11
+ from sqlspec.typing import ArrowTable, ModelDTOT, StatementParameterType
12
12
 
13
13
  __all__ = ("DuckDBDriver",)
14
14
 
15
15
 
16
- class DuckDBDriver(SyncDriverAdapterProtocol["DuckDBPyConnection"]):
16
+ class DuckDBDriver(SyncArrowBulkOperationsMixin["DuckDBPyConnection"], SyncDriverAdapterProtocol["DuckDBPyConnection"]):
17
17
  """DuckDB Sync Driver Adapter."""
18
18
 
19
19
  connection: "DuckDBPyConnection"
20
20
  use_cursor: bool = True
21
- # param_style is inherited from CommonDriverAttributes
21
+ dialect: str = "duckdb"
22
22
 
23
23
  def __init__(self, connection: "DuckDBPyConnection", use_cursor: bool = True) -> None:
24
24
  self.connection = connection
@@ -27,7 +27,6 @@ class DuckDBDriver(SyncDriverAdapterProtocol["DuckDBPyConnection"]):
27
27
  # --- Helper Methods --- #
28
28
  def _cursor(self, connection: "DuckDBPyConnection") -> "DuckDBPyConnection":
29
29
  if self.use_cursor:
30
- # Ignore lack of type hint on cursor()
31
30
  return connection.cursor()
32
31
  return connection
33
32
 
@@ -40,20 +39,22 @@ class DuckDBDriver(SyncDriverAdapterProtocol["DuckDBPyConnection"]):
40
39
  finally:
41
40
  cursor.close()
42
41
  else:
43
- yield connection # Yield the connection directly
42
+ yield connection
44
43
 
45
- # --- Public API Methods (Original Implementation + _process_sql_params) --- #
44
+ # --- Public API Methods --- #
46
45
 
47
46
  def select(
48
47
  self,
49
48
  sql: str,
50
49
  parameters: Optional["StatementParameterType"] = None,
51
50
  /,
51
+ *,
52
52
  connection: Optional["DuckDBPyConnection"] = None,
53
53
  schema_type: "Optional[type[ModelDTOT]]" = None,
54
+ **kwargs: Any,
54
55
  ) -> "list[Union[ModelDTOT, dict[str, Any]]]":
55
56
  connection = self._connection(connection)
56
- sql, parameters = self._process_sql_params(sql, parameters)
57
+ sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
57
58
  with self._with_cursor(connection) as cursor:
58
59
  cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
59
60
  results = cursor.fetchall() # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType]
@@ -71,16 +72,17 @@ class DuckDBDriver(SyncDriverAdapterProtocol["DuckDBPyConnection"]):
71
72
  sql: str,
72
73
  parameters: Optional["StatementParameterType"] = None,
73
74
  /,
75
+ *,
74
76
  connection: Optional["DuckDBPyConnection"] = None,
75
77
  schema_type: "Optional[type[ModelDTOT]]" = None,
78
+ **kwargs: Any,
76
79
  ) -> "Union[ModelDTOT, dict[str, Any]]":
77
80
  connection = self._connection(connection)
78
- sql, parameters = self._process_sql_params(sql, parameters)
79
-
81
+ sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
80
82
  with self._with_cursor(connection) as cursor:
81
83
  cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
82
84
  result = cursor.fetchone() # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType]
83
- result = self.check_not_found(result) # pyright: ignore
85
+ result = self.check_not_found(result) # pyright: ignore
84
86
 
85
87
  column_names = [col[0] for col in cursor.description or []] # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
86
88
  if schema_type is not None:
@@ -93,12 +95,13 @@ class DuckDBDriver(SyncDriverAdapterProtocol["DuckDBPyConnection"]):
93
95
  sql: str,
94
96
  parameters: Optional["StatementParameterType"] = None,
95
97
  /,
98
+ *,
96
99
  connection: Optional["DuckDBPyConnection"] = None,
97
100
  schema_type: "Optional[type[ModelDTOT]]" = None,
101
+ **kwargs: Any,
98
102
  ) -> "Optional[Union[ModelDTOT, dict[str, Any]]]":
99
103
  connection = self._connection(connection)
100
- sql, parameters = self._process_sql_params(sql, parameters)
101
-
104
+ sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
102
105
  with self._with_cursor(connection) as cursor:
103
106
  cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
104
107
  result = cursor.fetchone() # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType]
@@ -115,16 +118,17 @@ class DuckDBDriver(SyncDriverAdapterProtocol["DuckDBPyConnection"]):
115
118
  sql: str,
116
119
  parameters: "Optional[StatementParameterType]" = None,
117
120
  /,
121
+ *,
118
122
  connection: "Optional[DuckDBPyConnection]" = None,
119
123
  schema_type: "Optional[type[T]]" = None,
124
+ **kwargs: Any,
120
125
  ) -> "Union[T, Any]":
121
126
  connection = self._connection(connection)
122
- sql, parameters = self._process_sql_params(sql, parameters)
123
-
127
+ sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
124
128
  with self._with_cursor(connection) as cursor:
125
129
  cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
126
130
  result = cursor.fetchone() # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
127
- result = self.check_not_found(result) # pyright: ignore
131
+ result = self.check_not_found(result) # pyright: ignore
128
132
  if schema_type is None:
129
133
  return result[0] # pyright: ignore
130
134
  return schema_type(result[0]) # type: ignore[call-arg]
@@ -134,11 +138,13 @@ class DuckDBDriver(SyncDriverAdapterProtocol["DuckDBPyConnection"]):
134
138
  sql: str,
135
139
  parameters: "Optional[StatementParameterType]" = None,
136
140
  /,
141
+ *,
137
142
  connection: "Optional[DuckDBPyConnection]" = None,
138
143
  schema_type: "Optional[type[T]]" = None,
144
+ **kwargs: Any,
139
145
  ) -> "Optional[Union[T, Any]]":
140
146
  connection = self._connection(connection)
141
- sql, parameters = self._process_sql_params(sql, parameters)
147
+ sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
142
148
  with self._with_cursor(connection) as cursor:
143
149
  cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
144
150
  result = cursor.fetchone() # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
@@ -153,10 +159,12 @@ class DuckDBDriver(SyncDriverAdapterProtocol["DuckDBPyConnection"]):
153
159
  sql: str,
154
160
  parameters: Optional["StatementParameterType"] = None,
155
161
  /,
162
+ *,
156
163
  connection: Optional["DuckDBPyConnection"] = None,
164
+ **kwargs: Any,
157
165
  ) -> int:
158
166
  connection = self._connection(connection)
159
- sql, parameters = self._process_sql_params(sql, parameters)
167
+ sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
160
168
  with self._with_cursor(connection) as cursor:
161
169
  cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
162
170
  return getattr(cursor, "rowcount", -1) # pyright: ignore[reportUnknownMemberType]
@@ -166,11 +174,13 @@ class DuckDBDriver(SyncDriverAdapterProtocol["DuckDBPyConnection"]):
166
174
  sql: str,
167
175
  parameters: Optional["StatementParameterType"] = None,
168
176
  /,
177
+ *,
169
178
  connection: Optional["DuckDBPyConnection"] = None,
170
179
  schema_type: "Optional[type[ModelDTOT]]" = None,
180
+ **kwargs: Any,
171
181
  ) -> "Optional[Union[dict[str, Any], ModelDTOT]]":
172
182
  connection = self._connection(connection)
173
- sql, parameters = self._process_sql_params(sql, parameters)
183
+ sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
174
184
  with self._with_cursor(connection) as cursor:
175
185
  cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
176
186
  result = cursor.fetchall() # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType]
@@ -182,44 +192,34 @@ class DuckDBDriver(SyncDriverAdapterProtocol["DuckDBPyConnection"]):
182
192
  # Always return dictionaries
183
193
  return dict(zip(column_names, result[0])) # pyright: ignore[reportUnknownArgumentType,reportUnknownVariableType]
184
194
 
185
- def _process_sql_params(
186
- self, sql: str, parameters: "Optional[StatementParameterType]" = None
187
- ) -> "tuple[str, Optional[Union[tuple[Any, ...], list[Any], dict[str, Any]]]]":
188
- """Process SQL query and parameters for DB-API execution.
189
-
190
- Converts named parameters (:name) to positional parameters (?) for DuckDB.
191
-
192
- Args:
193
- sql: The SQL query string.
194
- parameters: The parameters for the query (dict, tuple, list, or None).
195
-
196
- Returns:
197
- A tuple containing the processed SQL string and the processed parameters.
198
- """
199
- if not isinstance(parameters, dict) or not parameters:
200
- # If parameters are not a dict, or empty dict, assume positional/no params
201
- # Let the underlying driver handle tuples/lists directly
202
- return sql, parameters
203
-
204
- # Convert named parameters to positional parameters
205
- processed_sql = sql
206
- processed_params: list[Any] = []
207
- for key, value in parameters.items():
208
- # Replace :key with ? in the SQL
209
- processed_sql = processed_sql.replace(f":{key}", "?")
210
- processed_params.append(value)
211
-
212
- return processed_sql, tuple(processed_params)
213
-
214
195
  def execute_script(
215
196
  self,
216
197
  sql: str,
217
198
  parameters: Optional["StatementParameterType"] = None,
218
199
  /,
200
+ *,
219
201
  connection: Optional["DuckDBPyConnection"] = None,
202
+ **kwargs: Any,
220
203
  ) -> str:
221
204
  connection = self._connection(connection)
222
- sql, parameters = self._process_sql_params(sql, parameters)
205
+ sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
223
206
  with self._with_cursor(connection) as cursor:
224
207
  cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
225
208
  return cast("str", getattr(cursor, "statusmessage", "DONE")) # pyright: ignore[reportUnknownMemberType]
209
+
210
+ # --- Arrow Bulk Operations ---
211
+
212
+ def select_arrow( # pyright: ignore[reportUnknownParameterType]
213
+ self,
214
+ sql: str,
215
+ parameters: "Optional[StatementParameterType]" = None,
216
+ /,
217
+ *,
218
+ connection: "Optional[DuckDBPyConnection]" = None,
219
+ **kwargs: Any,
220
+ ) -> "ArrowTable":
221
+ connection = self._connection(connection)
222
+ sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
223
+ with self._with_cursor(connection) as cursor:
224
+ cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
225
+ return cast("ArrowTable", cursor.fetch_arrow_table()) # pyright: ignore[reportUnknownMemberType]
@@ -1,16 +1,16 @@
1
1
  from sqlspec.adapters.oracledb.config import (
2
- OracleAsync,
3
- OracleAsyncPool,
4
- OracleSync,
5
- OracleSyncPool,
2
+ OracleAsyncConfig,
3
+ OracleAsyncPoolConfig,
4
+ OracleSyncConfig,
5
+ OracleSyncPoolConfig,
6
6
  )
7
7
  from sqlspec.adapters.oracledb.driver import OracleAsyncDriver, OracleSyncDriver
8
8
 
9
9
  __all__ = (
10
- "OracleAsync",
10
+ "OracleAsyncConfig",
11
11
  "OracleAsyncDriver",
12
- "OracleAsyncPool",
13
- "OracleSync",
12
+ "OracleAsyncPoolConfig",
13
+ "OracleSyncConfig",
14
14
  "OracleSyncDriver",
15
- "OracleSyncPool",
15
+ "OracleSyncPoolConfig",
16
16
  )
@@ -1,9 +1,9 @@
1
- from sqlspec.adapters.oracledb.config._asyncio import OracleAsync, OracleAsyncPool
2
- from sqlspec.adapters.oracledb.config._sync import OracleSync, OracleSyncPool
1
+ from sqlspec.adapters.oracledb.config._asyncio import OracleAsyncConfig, OracleAsyncPoolConfig
2
+ from sqlspec.adapters.oracledb.config._sync import OracleSyncConfig, OracleSyncPoolConfig
3
3
 
4
4
  __all__ = (
5
- "OracleAsync",
6
- "OracleAsyncPool",
7
- "OracleSync",
8
- "OracleSyncPool",
5
+ "OracleAsyncConfig",
6
+ "OracleAsyncPoolConfig",
7
+ "OracleSyncConfig",
8
+ "OracleSyncPoolConfig",
9
9
  )
@@ -1,6 +1,6 @@
1
1
  from contextlib import asynccontextmanager
2
2
  from dataclasses import dataclass, field
3
- from typing import TYPE_CHECKING, Any, Optional
3
+ from typing import TYPE_CHECKING, Any, Optional, cast
4
4
 
5
5
  from oracledb import create_pool_async as oracledb_create_pool # pyright: ignore[reportUnknownVariableType]
6
6
  from oracledb.connection import AsyncConnection
@@ -18,18 +18,18 @@ if TYPE_CHECKING:
18
18
 
19
19
 
20
20
  __all__ = (
21
- "OracleAsync",
22
- "OracleAsyncPool",
21
+ "OracleAsyncConfig",
22
+ "OracleAsyncPoolConfig",
23
23
  )
24
24
 
25
25
 
26
26
  @dataclass
27
- class OracleAsyncPool(OracleGenericPoolConfig["AsyncConnection", "AsyncConnectionPool"]):
27
+ class OracleAsyncPoolConfig(OracleGenericPoolConfig["AsyncConnection", "AsyncConnectionPool"]):
28
28
  """Async Oracle Pool Config"""
29
29
 
30
30
 
31
31
  @dataclass
32
- class OracleAsync(AsyncDatabaseConfig["AsyncConnection", "AsyncConnectionPool", "OracleAsyncDriver"]):
32
+ class OracleAsyncConfig(AsyncDatabaseConfig["AsyncConnection", "AsyncConnectionPool", "OracleAsyncDriver"]):
33
33
  """Oracle Async database Configuration.
34
34
 
35
35
  This class provides the base configuration for Oracle database connections, extending
@@ -42,7 +42,7 @@ class OracleAsync(AsyncDatabaseConfig["AsyncConnection", "AsyncConnectionPool",
42
42
  options.([2](https://python-oracledb.readthedocs.io/en/latest/user_guide/tuning.html))
43
43
  """
44
44
 
45
- pool_config: "Optional[OracleAsyncPool]" = None
45
+ pool_config: "Optional[OracleAsyncPoolConfig]" = None
46
46
  """Oracle Pool configuration"""
47
47
  pool_instance: "Optional[AsyncConnectionPool]" = None
48
48
  """Optional pool to use.
@@ -112,7 +112,7 @@ class OracleAsync(AsyncDatabaseConfig["AsyncConnection", "AsyncConnectionPool",
112
112
  raise ImproperConfigurationError(msg)
113
113
 
114
114
  async def create_connection(self) -> "AsyncConnection":
115
- """Create and return a new oracledb async connection.
115
+ """Create and return a new oracledb async connection from the pool.
116
116
 
117
117
  Returns:
118
118
  An AsyncConnection instance.
@@ -121,9 +121,8 @@ class OracleAsync(AsyncDatabaseConfig["AsyncConnection", "AsyncConnectionPool",
121
121
  ImproperConfigurationError: If the connection could not be created.
122
122
  """
123
123
  try:
124
- import oracledb
125
-
126
- return await oracledb.connect_async(**self.connection_config_dict) # type: ignore[no-any-return]
124
+ pool = await self.provide_pool()
125
+ return cast("AsyncConnection", await pool.acquire()) # type: ignore[no-any-return,unused-ignore]
127
126
  except Exception as e:
128
127
  msg = f"Could not configure the Oracle async connection. Error: {e!s}"
129
128
  raise ImproperConfigurationError(msg) from e
@@ -18,18 +18,18 @@ if TYPE_CHECKING:
18
18
 
19
19
 
20
20
  __all__ = (
21
- "OracleSync",
22
- "OracleSyncPool",
21
+ "OracleSyncConfig",
22
+ "OracleSyncPoolConfig",
23
23
  )
24
24
 
25
25
 
26
26
  @dataclass
27
- class OracleSyncPool(OracleGenericPoolConfig["Connection", "ConnectionPool"]):
27
+ class OracleSyncPoolConfig(OracleGenericPoolConfig["Connection", "ConnectionPool"]):
28
28
  """Sync Oracle Pool Config"""
29
29
 
30
30
 
31
31
  @dataclass
32
- class OracleSync(SyncDatabaseConfig["Connection", "ConnectionPool", "OracleSyncDriver"]):
32
+ class OracleSyncConfig(SyncDatabaseConfig["Connection", "ConnectionPool", "OracleSyncDriver"]):
33
33
  """Oracle Sync database Configuration.
34
34
 
35
35
  This class provides the base configuration for Oracle database connections, extending
@@ -42,7 +42,7 @@ class OracleSync(SyncDatabaseConfig["Connection", "ConnectionPool", "OracleSyncD
42
42
  options.([2](https://python-oracledb.readthedocs.io/en/latest/user_guide/tuning.html))
43
43
  """
44
44
 
45
- pool_config: "Optional[OracleSyncPool]" = None
45
+ pool_config: "Optional[OracleSyncPoolConfig]" = None
46
46
  """Oracle Pool configuration"""
47
47
  pool_instance: "Optional[ConnectionPool]" = None
48
48
  """Optional pool to use.
@@ -112,7 +112,7 @@ class OracleSync(SyncDatabaseConfig["Connection", "ConnectionPool", "OracleSyncD
112
112
  raise ImproperConfigurationError(msg)
113
113
 
114
114
  def create_connection(self) -> "Connection":
115
- """Create and return a new oracledb connection.
115
+ """Create and return a new oracledb connection from the pool.
116
116
 
117
117
  Returns:
118
118
  A Connection instance.
@@ -121,9 +121,8 @@ class OracleSync(SyncDatabaseConfig["Connection", "ConnectionPool", "OracleSyncD
121
121
  ImproperConfigurationError: If the connection could not be created.
122
122
  """
123
123
  try:
124
- import oracledb
125
-
126
- return oracledb.connect(**self.connection_config_dict)
124
+ pool = self.provide_pool()
125
+ return pool.acquire()
127
126
  except Exception as e:
128
127
  msg = f"Could not configure the Oracle connection. Error: {e!s}"
129
128
  raise ImproperConfigurationError(msg) from e