sqlspec 0.7.1__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 (54) hide show
  1. sqlspec/__init__.py +15 -0
  2. sqlspec/_serialization.py +16 -2
  3. sqlspec/_typing.py +40 -7
  4. sqlspec/adapters/adbc/__init__.py +7 -0
  5. sqlspec/adapters/adbc/config.py +183 -17
  6. sqlspec/adapters/adbc/driver.py +392 -0
  7. sqlspec/adapters/aiosqlite/__init__.py +5 -1
  8. sqlspec/adapters/aiosqlite/config.py +24 -6
  9. sqlspec/adapters/aiosqlite/driver.py +264 -0
  10. sqlspec/adapters/asyncmy/__init__.py +7 -2
  11. sqlspec/adapters/asyncmy/config.py +71 -11
  12. sqlspec/adapters/asyncmy/driver.py +246 -0
  13. sqlspec/adapters/asyncpg/__init__.py +9 -0
  14. sqlspec/adapters/asyncpg/config.py +102 -25
  15. sqlspec/adapters/asyncpg/driver.py +444 -0
  16. sqlspec/adapters/duckdb/__init__.py +5 -1
  17. sqlspec/adapters/duckdb/config.py +194 -12
  18. sqlspec/adapters/duckdb/driver.py +225 -0
  19. sqlspec/adapters/oracledb/__init__.py +7 -4
  20. sqlspec/adapters/oracledb/config/__init__.py +4 -4
  21. sqlspec/adapters/oracledb/config/_asyncio.py +96 -12
  22. sqlspec/adapters/oracledb/config/_common.py +1 -1
  23. sqlspec/adapters/oracledb/config/_sync.py +96 -12
  24. sqlspec/adapters/oracledb/driver.py +571 -0
  25. sqlspec/adapters/psqlpy/__init__.py +0 -0
  26. sqlspec/adapters/psqlpy/config.py +258 -0
  27. sqlspec/adapters/psqlpy/driver.py +335 -0
  28. sqlspec/adapters/psycopg/__init__.py +16 -0
  29. sqlspec/adapters/psycopg/config/__init__.py +6 -6
  30. sqlspec/adapters/psycopg/config/_async.py +107 -15
  31. sqlspec/adapters/psycopg/config/_common.py +2 -2
  32. sqlspec/adapters/psycopg/config/_sync.py +107 -15
  33. sqlspec/adapters/psycopg/driver.py +578 -0
  34. sqlspec/adapters/sqlite/__init__.py +7 -0
  35. sqlspec/adapters/sqlite/config.py +24 -6
  36. sqlspec/adapters/sqlite/driver.py +305 -0
  37. sqlspec/base.py +565 -63
  38. sqlspec/exceptions.py +30 -0
  39. sqlspec/extensions/litestar/__init__.py +19 -0
  40. sqlspec/extensions/litestar/_utils.py +56 -0
  41. sqlspec/extensions/litestar/config.py +87 -0
  42. sqlspec/extensions/litestar/handlers.py +213 -0
  43. sqlspec/extensions/litestar/plugin.py +105 -11
  44. sqlspec/statement.py +373 -0
  45. sqlspec/typing.py +81 -17
  46. sqlspec/utils/__init__.py +3 -0
  47. sqlspec/utils/fixtures.py +4 -5
  48. sqlspec/utils/sync_tools.py +335 -0
  49. {sqlspec-0.7.1.dist-info → sqlspec-0.9.0.dist-info}/METADATA +4 -1
  50. sqlspec-0.9.0.dist-info/RECORD +61 -0
  51. sqlspec-0.7.1.dist-info/RECORD +0 -46
  52. {sqlspec-0.7.1.dist-info → sqlspec-0.9.0.dist-info}/WHEEL +0 -0
  53. {sqlspec-0.7.1.dist-info → sqlspec-0.9.0.dist-info}/licenses/LICENSE +0 -0
  54. {sqlspec-0.7.1.dist-info → sqlspec-0.9.0.dist-info}/licenses/NOTICE +0 -0
@@ -0,0 +1,264 @@
1
+ from contextlib import asynccontextmanager
2
+ from typing import TYPE_CHECKING, Any, Optional, Union, cast
3
+
4
+ from sqlspec.base import AsyncDriverAdapterProtocol, T
5
+
6
+ if TYPE_CHECKING:
7
+ from collections.abc import AsyncGenerator
8
+
9
+ from aiosqlite import Connection, Cursor
10
+
11
+ from sqlspec.typing import ModelDTOT, StatementParameterType
12
+
13
+ __all__ = ("AiosqliteDriver",)
14
+
15
+
16
+ class AiosqliteDriver(AsyncDriverAdapterProtocol["Connection"]):
17
+ """SQLite Async Driver Adapter."""
18
+
19
+ connection: "Connection"
20
+ dialect: str = "sqlite"
21
+
22
+ def __init__(self, connection: "Connection") -> None:
23
+ self.connection = connection
24
+
25
+ @staticmethod
26
+ async def _cursor(connection: "Connection", *args: Any, **kwargs: Any) -> "Cursor":
27
+ return await connection.cursor(*args, **kwargs)
28
+
29
+ @asynccontextmanager
30
+ async def _with_cursor(self, connection: "Connection") -> "AsyncGenerator[Cursor, None]":
31
+ cursor = await self._cursor(connection)
32
+ try:
33
+ yield cursor
34
+ finally:
35
+ await cursor.close()
36
+
37
+ async def select(
38
+ self,
39
+ sql: str,
40
+ parameters: Optional["StatementParameterType"] = None,
41
+ /,
42
+ *,
43
+ connection: Optional["Connection"] = None,
44
+ schema_type: "Optional[type[ModelDTOT]]" = None,
45
+ **kwargs: Any,
46
+ ) -> "list[Union[ModelDTOT, dict[str, Any]]]":
47
+ """Fetch data from the database.
48
+
49
+ Returns:
50
+ List of row data as either model instances or dictionaries.
51
+ """
52
+ connection = self._connection(connection)
53
+ sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
54
+ async with self._with_cursor(connection) as cursor:
55
+ await cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
56
+ results = await cursor.fetchall() # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType]
57
+ if not results:
58
+ return []
59
+ column_names = [c[0] for c in cursor.description or []] # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType]
60
+ if schema_type is None:
61
+ return [dict(zip(column_names, row)) for row in results] # pyright: ignore[reportUnknownArgumentType]
62
+ return [cast("ModelDTOT", schema_type(**dict(zip(column_names, row)))) for row in results] # pyright: ignore[reportUnknownArgumentType]
63
+
64
+ async def select_one(
65
+ self,
66
+ sql: str,
67
+ parameters: Optional["StatementParameterType"] = None,
68
+ /,
69
+ *,
70
+ connection: Optional["Connection"] = None,
71
+ schema_type: "Optional[type[ModelDTOT]]" = None,
72
+ **kwargs: Any,
73
+ ) -> "Union[ModelDTOT, dict[str, Any]]":
74
+ """Fetch one row from the database.
75
+
76
+ Returns:
77
+ The first row of the query results.
78
+ """
79
+ connection = self._connection(connection)
80
+ sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
81
+ async with self._with_cursor(connection) as cursor:
82
+ await cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
83
+ result = await cursor.fetchone() # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType]
84
+ result = self.check_not_found(result)
85
+ column_names = [c[0] for c in cursor.description or []] # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType]
86
+ if schema_type is None:
87
+ return dict(zip(column_names, result)) # pyright: ignore[reportUnknownArgumentType, reportUnknownVariableType]
88
+ return cast("ModelDTOT", schema_type(**dict(zip(column_names, result)))) # pyright: ignore[reportUnknownArgumentType]
89
+
90
+ async def select_one_or_none(
91
+ self,
92
+ sql: str,
93
+ parameters: Optional["StatementParameterType"] = None,
94
+ /,
95
+ *,
96
+ connection: Optional["Connection"] = None,
97
+ schema_type: "Optional[type[ModelDTOT]]" = None,
98
+ **kwargs: Any,
99
+ ) -> "Optional[Union[ModelDTOT, dict[str, Any]]]":
100
+ """Fetch one row from the database.
101
+
102
+ Returns:
103
+ The first row of the query results.
104
+ """
105
+ connection = self._connection(connection)
106
+ sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
107
+ async with self._with_cursor(connection) as cursor:
108
+ await cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
109
+ result = await cursor.fetchone() # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType]
110
+ if result is None:
111
+ return None
112
+ column_names = [c[0] for c in cursor.description or []] # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType]
113
+ if schema_type is None:
114
+ return dict(zip(column_names, result)) # pyright: ignore[reportUnknownArgumentType, reportUnknownVariableType]
115
+ return cast("ModelDTOT", schema_type(**dict(zip(column_names, result)))) # pyright: ignore[reportUnknownArgumentType]
116
+
117
+ async def select_value(
118
+ self,
119
+ sql: str,
120
+ parameters: "Optional[StatementParameterType]" = None,
121
+ /,
122
+ *,
123
+ connection: "Optional[Connection]" = None,
124
+ schema_type: "Optional[type[T]]" = None,
125
+ **kwargs: Any,
126
+ ) -> "Union[T, Any]":
127
+ """Fetch a single value from the database.
128
+
129
+ Returns:
130
+ The first value from the first row of results, or None if no results.
131
+ """
132
+ connection = self._connection(connection)
133
+ sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
134
+ async with self._with_cursor(connection) as cursor:
135
+ await cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
136
+ result = await cursor.fetchone() # pyright: ignore[reportUnknownMemberType]
137
+ result = self.check_not_found(result)
138
+ if schema_type is None:
139
+ return result[0]
140
+ return schema_type(result[0]) # type: ignore[call-arg]
141
+
142
+ async def select_value_or_none(
143
+ self,
144
+ sql: str,
145
+ parameters: "Optional[StatementParameterType]" = None,
146
+ /,
147
+ *,
148
+ connection: "Optional[Connection]" = None,
149
+ schema_type: "Optional[type[T]]" = None,
150
+ **kwargs: Any,
151
+ ) -> "Optional[Union[T, Any]]":
152
+ """Fetch a single value from the database.
153
+
154
+ Returns:
155
+ The first value from the first row of results, or None if no results.
156
+ """
157
+ connection = self._connection(connection)
158
+ sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
159
+ async with self._with_cursor(connection) as cursor:
160
+ await cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
161
+ result = await cursor.fetchone() # pyright: ignore[reportUnknownMemberType]
162
+ if result is None:
163
+ return None
164
+ if schema_type is None:
165
+ return result[0]
166
+ return schema_type(result[0]) # type: ignore[call-arg]
167
+
168
+ async def insert_update_delete(
169
+ self,
170
+ sql: str,
171
+ parameters: Optional["StatementParameterType"] = None,
172
+ /,
173
+ *,
174
+ connection: Optional["Connection"] = None,
175
+ **kwargs: Any,
176
+ ) -> int:
177
+ """Insert, update, or delete data from the database.
178
+
179
+ Returns:
180
+ Row count affected by the operation.
181
+ """
182
+ connection = self._connection(connection)
183
+ sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
184
+
185
+ async with self._with_cursor(connection) as cursor:
186
+ await cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
187
+ return cursor.rowcount if hasattr(cursor, "rowcount") else -1 # pyright: ignore[reportUnknownVariableType, reportGeneralTypeIssues]
188
+
189
+ async def insert_update_delete_returning(
190
+ self,
191
+ sql: str,
192
+ parameters: Optional["StatementParameterType"] = None,
193
+ /,
194
+ *,
195
+ connection: Optional["Connection"] = None,
196
+ schema_type: "Optional[type[ModelDTOT]]" = None,
197
+ **kwargs: Any,
198
+ ) -> "Optional[Union[dict[str, Any], ModelDTOT]]":
199
+ """Insert, update, or delete data from the database and return result.
200
+
201
+ Returns:
202
+ The first row of results.
203
+ """
204
+ connection = self._connection(connection)
205
+ sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
206
+
207
+ async with self._with_cursor(connection) as cursor:
208
+ await cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
209
+ results = list(await cursor.fetchall()) # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType]
210
+ if not results: # Check if empty
211
+ return None
212
+ column_names = [c[0] for c in cursor.description or []] # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType]
213
+ if schema_type is not None:
214
+ return cast("ModelDTOT", schema_type(**dict(zip(column_names, results[0])))) # pyright: ignore[reportUnknownArgumentType, reportUnknownVariableType]
215
+ return dict(zip(column_names, results[0])) # pyright: ignore[reportUnknownArgumentType, reportUnknownVariableType]
216
+
217
+ async def execute_script(
218
+ self,
219
+ sql: str,
220
+ parameters: Optional["StatementParameterType"] = None,
221
+ /,
222
+ *,
223
+ connection: Optional["Connection"] = None,
224
+ **kwargs: Any,
225
+ ) -> str:
226
+ """Execute a script.
227
+
228
+ Returns:
229
+ Status message for the operation.
230
+ """
231
+ connection = self._connection(connection)
232
+ sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
233
+
234
+ async with self._with_cursor(connection) as cursor:
235
+ await cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
236
+ return "DONE"
237
+
238
+ async def execute_script_returning(
239
+ self,
240
+ sql: str,
241
+ parameters: Optional["StatementParameterType"] = None,
242
+ /,
243
+ *,
244
+ connection: Optional["Connection"] = None,
245
+ schema_type: "Optional[type[ModelDTOT]]" = None,
246
+ **kwargs: Any,
247
+ ) -> "Optional[Union[dict[str, Any], ModelDTOT]]":
248
+ """Execute a script and return result.
249
+
250
+ Returns:
251
+ The first row of results.
252
+ """
253
+ connection = self._connection(connection)
254
+ sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
255
+
256
+ async with self._with_cursor(connection) as cursor:
257
+ await cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
258
+ results = list(await cursor.fetchall()) # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType]
259
+ if not results: # Check if empty
260
+ return None
261
+ column_names = [c[0] for c in cursor.description or []] # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType]
262
+ if schema_type is not None:
263
+ return cast("ModelDTOT", schema_type(**dict(zip(column_names, results[0])))) # pyright: ignore[reportUnknownArgumentType, reportUnknownVariableType]
264
+ return dict(zip(column_names, results[0])) # pyright: ignore[reportUnknownArgumentType, reportUnknownVariableType]
@@ -1,3 +1,8 @@
1
- from sqlspec.adapters.asyncmy.config import AsyncMyConfig, AsyncmyPoolConfig
1
+ from sqlspec.adapters.asyncmy.config import AsyncmyConfig, AsyncmyPoolConfig
2
+ from sqlspec.adapters.asyncmy.driver import AsyncmyDriver # type: ignore[attr-defined]
2
3
 
3
- __all__ = ("AsyncMyConfig", "AsyncmyPoolConfig")
4
+ __all__ = (
5
+ "AsyncmyConfig",
6
+ "AsyncmyDriver",
7
+ "AsyncmyPoolConfig",
8
+ )
@@ -1,22 +1,22 @@
1
1
  from contextlib import asynccontextmanager
2
- from dataclasses import dataclass
3
- from typing import TYPE_CHECKING, Optional, TypeVar, Union
2
+ from dataclasses import dataclass, field
3
+ from typing import TYPE_CHECKING, Any, Optional, TypeVar, Union
4
4
 
5
5
  from asyncmy.connection import Connection # pyright: ignore[reportUnknownVariableType]
6
- from asyncmy.pool import Pool # pyright: ignore[reportUnknownVariableType]
7
6
 
7
+ from sqlspec.adapters.asyncmy.driver import AsyncmyDriver # type: ignore[attr-defined]
8
8
  from sqlspec.base import AsyncDatabaseConfig, GenericPoolConfig
9
9
  from sqlspec.exceptions import ImproperConfigurationError
10
10
  from sqlspec.typing import Empty, EmptyType, dataclass_to_dict
11
11
 
12
12
  if TYPE_CHECKING:
13
13
  from collections.abc import AsyncGenerator
14
- from typing import Any
15
14
 
16
15
  from asyncmy.cursors import Cursor, DictCursor # pyright: ignore[reportUnknownVariableType]
16
+ from asyncmy.pool import Pool # pyright: ignore[reportUnknownVariableType]
17
17
 
18
18
  __all__ = (
19
- "AsyncMyConfig",
19
+ "AsyncmyConfig",
20
20
  "AsyncmyPoolConfig",
21
21
  )
22
22
 
@@ -104,7 +104,7 @@ class AsyncmyPoolConfig(GenericPoolConfig):
104
104
 
105
105
 
106
106
  @dataclass
107
- class AsyncMyConfig(AsyncDatabaseConfig[Connection, Pool]):
107
+ class AsyncmyConfig(AsyncDatabaseConfig["Connection", "Pool", "AsyncmyDriver"]):
108
108
  """Asyncmy Configuration."""
109
109
 
110
110
  __is_async__ = True
@@ -112,12 +112,34 @@ class AsyncMyConfig(AsyncDatabaseConfig[Connection, Pool]):
112
112
 
113
113
  pool_config: "Optional[AsyncmyPoolConfig]" = None
114
114
  """Asyncmy Pool configuration"""
115
+ connection_type: "type[Connection]" = field(hash=False, init=False, default_factory=lambda: Connection) # pyright: ignore
116
+ """Type of the connection object"""
117
+ driver_type: "type[AsyncmyDriver]" = field(hash=False, init=False, default_factory=lambda: AsyncmyDriver)
118
+ """Type of the driver object"""
119
+ pool_instance: "Optional[Pool]" = field(hash=False, default=None) # pyright: ignore[reportUnknownVariableType]
120
+ """Instance of the pool"""
115
121
 
116
- pool_instance: "Optional[Pool]" = None # pyright: ignore[reportUnknownVariableType]
117
- """Optional pool to use.
122
+ @property
123
+ def connection_config_dict(self) -> "dict[str, Any]":
124
+ """Return the connection configuration as a dict.
118
125
 
119
- If set, the plugin will use the provided pool rather than instantiate one.
120
- """
126
+ Returns:
127
+ A string keyed dict of config kwargs for the Asyncmy connect function.
128
+
129
+ Raises:
130
+ ImproperConfigurationError: If the connection configuration is not provided.
131
+ """
132
+ if self.pool_config:
133
+ # Filter out pool-specific parameters
134
+ pool_only_params = {"minsize", "maxsize", "echo", "pool_recycle"}
135
+ return dataclass_to_dict(
136
+ self.pool_config,
137
+ exclude_empty=True,
138
+ convert_nested=False,
139
+ exclude=pool_only_params.union({"pool_instance", "driver_type", "connection_type"}),
140
+ )
141
+ msg = "You must provide a 'pool_config' for this adapter."
142
+ raise ImproperConfigurationError(msg)
121
143
 
122
144
  @property
123
145
  def pool_config_dict(self) -> "dict[str, Any]":
@@ -130,10 +152,31 @@ class AsyncMyConfig(AsyncDatabaseConfig[Connection, Pool]):
130
152
  ImproperConfigurationError: If the pool configuration is not provided.
131
153
  """
132
154
  if self.pool_config:
133
- return dataclass_to_dict(self.pool_config, exclude_empty=True, convert_nested=False)
155
+ return dataclass_to_dict(
156
+ self.pool_config,
157
+ exclude_empty=True,
158
+ convert_nested=False,
159
+ exclude={"pool_instance", "driver_type", "connection_type"},
160
+ )
134
161
  msg = "'pool_config' methods can not be used when a 'pool_instance' is provided."
135
162
  raise ImproperConfigurationError(msg)
136
163
 
164
+ async def create_connection(self) -> "Connection": # pyright: ignore[reportUnknownParameterType]
165
+ """Create and return a new asyncmy connection from the pool.
166
+
167
+ Returns:
168
+ A Connection instance.
169
+
170
+ Raises:
171
+ ImproperConfigurationError: If the connection could not be created.
172
+ """
173
+ try:
174
+ async with self.provide_connection() as conn:
175
+ return conn
176
+ except Exception as e:
177
+ msg = f"Could not configure the Asyncmy connection. Error: {e!s}"
178
+ raise ImproperConfigurationError(msg) from e
179
+
137
180
  async def create_pool(self) -> "Pool": # pyright: ignore[reportUnknownParameterType]
138
181
  """Return a pool. If none exists yet, create one.
139
182
 
@@ -179,3 +222,20 @@ class AsyncMyConfig(AsyncDatabaseConfig[Connection, Pool]):
179
222
  pool = await self.provide_pool(*args, **kwargs) # pyright: ignore[reportUnknownVariableType,reportUnknownMemberType]
180
223
  async with pool.acquire() as connection: # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
181
224
  yield connection # pyright: ignore[reportUnknownMemberType]
225
+
226
+ @asynccontextmanager
227
+ async def provide_session(self, *args: "Any", **kwargs: "Any") -> "AsyncGenerator[AsyncmyDriver, None]":
228
+ """Create and provide a database session.
229
+
230
+ Yields:
231
+ An Asyncmy driver instance.
232
+
233
+ """
234
+ async with self.provide_connection(*args, **kwargs) as connection: # pyright: ignore[reportUnknownVariableType]
235
+ yield self.driver_type(connection) # pyright: ignore[reportUnknownArgumentType]
236
+
237
+ async def close_pool(self) -> None:
238
+ """Close the connection pool."""
239
+ if self.pool_instance is not None: # pyright: ignore[reportUnknownMemberType]
240
+ await self.pool_instance.close() # pyright: ignore[reportUnknownMemberType]
241
+ self.pool_instance = None
@@ -0,0 +1,246 @@
1
+ # type: ignore
2
+ from collections.abc import AsyncGenerator
3
+ from contextlib import asynccontextmanager
4
+ from typing import TYPE_CHECKING, Any, Optional, Union, cast
5
+
6
+ from sqlspec.base import AsyncDriverAdapterProtocol, T
7
+
8
+ if TYPE_CHECKING:
9
+ from asyncmy import Connection
10
+ from asyncmy.cursors import Cursor
11
+
12
+ from sqlspec.typing import ModelDTOT, StatementParameterType
13
+
14
+ __all__ = ("AsyncmyDriver",)
15
+
16
+
17
+ class AsyncmyDriver(AsyncDriverAdapterProtocol["Connection"]):
18
+ """Asyncmy MySQL/MariaDB Driver Adapter."""
19
+
20
+ connection: "Connection"
21
+ dialect: str = "mysql"
22
+
23
+ def __init__(self, connection: "Connection") -> None:
24
+ self.connection = connection
25
+
26
+ @staticmethod
27
+ async def _cursor(connection: "Connection") -> "Cursor":
28
+ return await connection.cursor()
29
+
30
+ @staticmethod
31
+ @asynccontextmanager
32
+ async def _with_cursor(connection: "Connection") -> AsyncGenerator["Cursor", None]:
33
+ cursor = connection.cursor()
34
+ try:
35
+ yield cursor
36
+ finally:
37
+ await cursor.close()
38
+
39
+ async def select(
40
+ self,
41
+ sql: str,
42
+ parameters: Optional["StatementParameterType"] = None,
43
+ /,
44
+ *,
45
+ connection: Optional["Connection"] = None,
46
+ schema_type: "Optional[type[ModelDTOT]]" = None,
47
+ **kwargs: Any,
48
+ ) -> "list[Union[ModelDTOT, dict[str, Any]]]":
49
+ """Fetch data from the database.
50
+
51
+ Returns:
52
+ List of row data as either model instances or dictionaries.
53
+ """
54
+ connection = self._connection(connection)
55
+ sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
56
+ async with self._with_cursor(connection) as cursor:
57
+ await cursor.execute(sql, parameters)
58
+ results = await cursor.fetchall()
59
+ if not results:
60
+ return []
61
+ column_names = [c[0] for c in cursor.description or []]
62
+ if schema_type is None:
63
+ return [dict(zip(column_names, row)) for row in results]
64
+ return [schema_type(**dict(zip(column_names, row))) for row in results]
65
+
66
+ async def select_one(
67
+ self,
68
+ sql: str,
69
+ parameters: Optional["StatementParameterType"] = None,
70
+ /,
71
+ *,
72
+ connection: Optional["Connection"] = None,
73
+ schema_type: "Optional[type[ModelDTOT]]" = None,
74
+ **kwargs: Any,
75
+ ) -> "Union[ModelDTOT, dict[str, Any]]":
76
+ """Fetch one row from the database.
77
+
78
+ Returns:
79
+ The first row of the query results.
80
+ """
81
+ connection = self._connection(connection)
82
+ sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
83
+ async with self._with_cursor(connection) as cursor:
84
+ await cursor.execute(sql, parameters)
85
+ result = await cursor.fetchone()
86
+ result = self.check_not_found(result)
87
+ column_names = [c[0] for c in cursor.description or []]
88
+ if schema_type is None:
89
+ return dict(zip(column_names, result))
90
+ return cast("ModelDTOT", schema_type(**dict(zip(column_names, result))))
91
+
92
+ async def select_one_or_none(
93
+ self,
94
+ sql: str,
95
+ parameters: Optional["StatementParameterType"] = None,
96
+ /,
97
+ *,
98
+ connection: Optional["Connection"] = None,
99
+ schema_type: "Optional[type[ModelDTOT]]" = None,
100
+ **kwargs: Any,
101
+ ) -> "Optional[Union[ModelDTOT, dict[str, Any]]]":
102
+ """Fetch one row from the database.
103
+
104
+ Returns:
105
+ The first row of the query results.
106
+ """
107
+ connection = self._connection(connection)
108
+ sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
109
+ async with self._with_cursor(connection) as cursor:
110
+ await cursor.execute(sql, parameters)
111
+ result = await cursor.fetchone()
112
+ if result is None:
113
+ return None
114
+ column_names = [c[0] for c in cursor.description or []]
115
+ if schema_type is None:
116
+ return dict(zip(column_names, result))
117
+ return cast("ModelDTOT", schema_type(**dict(zip(column_names, result))))
118
+
119
+ async def select_value(
120
+ self,
121
+ sql: str,
122
+ parameters: "Optional[StatementParameterType]" = None,
123
+ /,
124
+ *,
125
+ connection: "Optional[Connection]" = None,
126
+ schema_type: "Optional[type[T]]" = None,
127
+ **kwargs: Any,
128
+ ) -> "Union[T, Any]":
129
+ """Fetch a single value from the database.
130
+
131
+ Returns:
132
+ The first value from the first row of results, or None if no results.
133
+ """
134
+ connection = self._connection(connection)
135
+ sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
136
+
137
+ async with self._with_cursor(connection) as cursor:
138
+ await cursor.execute(sql, parameters)
139
+ result = await cursor.fetchone()
140
+ result = self.check_not_found(result)
141
+
142
+ value = result[0]
143
+ if schema_type is not None:
144
+ return schema_type(value) # type: ignore[call-arg]
145
+ return value
146
+
147
+ async def select_value_or_none(
148
+ self,
149
+ sql: str,
150
+ parameters: "Optional[StatementParameterType]" = None,
151
+ /,
152
+ *,
153
+ connection: "Optional[Connection]" = None,
154
+ schema_type: "Optional[type[T]]" = None,
155
+ **kwargs: Any,
156
+ ) -> "Optional[Union[T, Any]]":
157
+ """Fetch a single value from the database.
158
+
159
+ Returns:
160
+ The first value from the first row of results, or None if no results.
161
+ """
162
+ connection = self._connection(connection)
163
+ sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
164
+
165
+ async with self._with_cursor(connection) as cursor:
166
+ await cursor.execute(sql, parameters)
167
+ result = await cursor.fetchone()
168
+
169
+ if result is None:
170
+ return None
171
+
172
+ value = result[0]
173
+ if schema_type is not None:
174
+ return schema_type(value) # type: ignore[call-arg]
175
+ return value
176
+
177
+ async def insert_update_delete(
178
+ self,
179
+ sql: str,
180
+ parameters: Optional["StatementParameterType"] = None,
181
+ /,
182
+ *,
183
+ connection: Optional["Connection"] = None,
184
+ **kwargs: Any,
185
+ ) -> int:
186
+ """Insert, update, or delete data from the database.
187
+
188
+ Returns:
189
+ Row count affected by the operation.
190
+ """
191
+ connection = self._connection(connection)
192
+ sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
193
+
194
+ async with self._with_cursor(connection) as cursor:
195
+ await cursor.execute(sql, parameters)
196
+ return cursor.rowcount
197
+
198
+ async def insert_update_delete_returning(
199
+ self,
200
+ sql: str,
201
+ parameters: Optional["StatementParameterType"] = None,
202
+ /,
203
+ *,
204
+ connection: Optional["Connection"] = None,
205
+ schema_type: "Optional[type[ModelDTOT]]" = None,
206
+ **kwargs: Any,
207
+ ) -> "Optional[Union[dict[str, Any], ModelDTOT]]":
208
+ """Insert, update, or delete data from the database and return result.
209
+
210
+ Returns:
211
+ The first row of results.
212
+ """
213
+ connection = self._connection(connection)
214
+ sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
215
+ column_names: list[str] = []
216
+
217
+ async with self._with_cursor(connection) as cursor:
218
+ await cursor.execute(sql, parameters)
219
+ result = await cursor.fetchone()
220
+ if result is None:
221
+ return None
222
+ column_names = [c[0] for c in cursor.description or []]
223
+ if schema_type is not None:
224
+ return cast("ModelDTOT", schema_type(**dict(zip(column_names, result))))
225
+ return dict(zip(column_names, result))
226
+
227
+ async def execute_script(
228
+ self,
229
+ sql: str,
230
+ parameters: Optional["StatementParameterType"] = None,
231
+ /,
232
+ *,
233
+ connection: Optional["Connection"] = None,
234
+ **kwargs: Any,
235
+ ) -> str:
236
+ """Execute a script.
237
+
238
+ Returns:
239
+ Status message for the operation.
240
+ """
241
+ connection = self._connection(connection)
242
+ sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
243
+
244
+ async with self._with_cursor(connection) as cursor:
245
+ await cursor.execute(sql, parameters)
246
+ return "DONE"
@@ -0,0 +1,9 @@
1
+ from sqlspec.adapters.asyncpg.config import AsyncpgConfig, AsyncpgPoolConfig
2
+ from sqlspec.adapters.asyncpg.driver import AsyncpgConnection, AsyncpgDriver
3
+
4
+ __all__ = (
5
+ "AsyncpgConfig",
6
+ "AsyncpgConnection",
7
+ "AsyncpgDriver",
8
+ "AsyncpgPoolConfig",
9
+ )