sqlspec 0.14.1__py3-none-any.whl → 0.15.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 (158) hide show
  1. sqlspec/__init__.py +50 -25
  2. sqlspec/__main__.py +1 -1
  3. sqlspec/__metadata__.py +1 -3
  4. sqlspec/_serialization.py +1 -2
  5. sqlspec/_sql.py +256 -120
  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 +115 -260
  10. sqlspec/adapters/adbc/driver.py +462 -367
  11. sqlspec/adapters/aiosqlite/__init__.py +18 -3
  12. sqlspec/adapters/aiosqlite/_types.py +13 -0
  13. sqlspec/adapters/aiosqlite/config.py +199 -129
  14. sqlspec/adapters/aiosqlite/driver.py +230 -269
  15. sqlspec/adapters/asyncmy/__init__.py +18 -3
  16. sqlspec/adapters/asyncmy/_types.py +12 -0
  17. sqlspec/adapters/asyncmy/config.py +80 -168
  18. sqlspec/adapters/asyncmy/driver.py +260 -225
  19. sqlspec/adapters/asyncpg/__init__.py +19 -4
  20. sqlspec/adapters/asyncpg/_types.py +17 -0
  21. sqlspec/adapters/asyncpg/config.py +82 -181
  22. sqlspec/adapters/asyncpg/driver.py +285 -383
  23. sqlspec/adapters/bigquery/__init__.py +17 -3
  24. sqlspec/adapters/bigquery/_types.py +12 -0
  25. sqlspec/adapters/bigquery/config.py +191 -258
  26. sqlspec/adapters/bigquery/driver.py +474 -646
  27. sqlspec/adapters/duckdb/__init__.py +14 -3
  28. sqlspec/adapters/duckdb/_types.py +12 -0
  29. sqlspec/adapters/duckdb/config.py +415 -351
  30. sqlspec/adapters/duckdb/driver.py +343 -413
  31. sqlspec/adapters/oracledb/__init__.py +19 -5
  32. sqlspec/adapters/oracledb/_types.py +14 -0
  33. sqlspec/adapters/oracledb/config.py +123 -379
  34. sqlspec/adapters/oracledb/driver.py +507 -560
  35. sqlspec/adapters/psqlpy/__init__.py +13 -3
  36. sqlspec/adapters/psqlpy/_types.py +11 -0
  37. sqlspec/adapters/psqlpy/config.py +93 -254
  38. sqlspec/adapters/psqlpy/driver.py +505 -234
  39. sqlspec/adapters/psycopg/__init__.py +19 -5
  40. sqlspec/adapters/psycopg/_types.py +17 -0
  41. sqlspec/adapters/psycopg/config.py +143 -403
  42. sqlspec/adapters/psycopg/driver.py +706 -872
  43. sqlspec/adapters/sqlite/__init__.py +14 -3
  44. sqlspec/adapters/sqlite/_types.py +11 -0
  45. sqlspec/adapters/sqlite/config.py +202 -118
  46. sqlspec/adapters/sqlite/driver.py +264 -303
  47. sqlspec/base.py +105 -9
  48. sqlspec/{statement/builder → builder}/__init__.py +12 -14
  49. sqlspec/{statement/builder → builder}/_base.py +120 -55
  50. sqlspec/{statement/builder → builder}/_column.py +17 -6
  51. sqlspec/{statement/builder → builder}/_ddl.py +46 -79
  52. sqlspec/{statement/builder → builder}/_ddl_utils.py +5 -10
  53. sqlspec/{statement/builder → builder}/_delete.py +6 -25
  54. sqlspec/{statement/builder → builder}/_insert.py +6 -64
  55. sqlspec/builder/_merge.py +56 -0
  56. sqlspec/{statement/builder → builder}/_parsing_utils.py +3 -10
  57. sqlspec/{statement/builder → builder}/_select.py +11 -56
  58. sqlspec/{statement/builder → builder}/_update.py +12 -18
  59. sqlspec/{statement/builder → builder}/mixins/__init__.py +10 -14
  60. sqlspec/{statement/builder → builder}/mixins/_cte_and_set_ops.py +48 -59
  61. sqlspec/{statement/builder → builder}/mixins/_insert_operations.py +22 -16
  62. sqlspec/{statement/builder → builder}/mixins/_join_operations.py +1 -3
  63. sqlspec/{statement/builder → builder}/mixins/_merge_operations.py +3 -5
  64. sqlspec/{statement/builder → builder}/mixins/_order_limit_operations.py +3 -3
  65. sqlspec/{statement/builder → builder}/mixins/_pivot_operations.py +4 -8
  66. sqlspec/{statement/builder → builder}/mixins/_select_operations.py +21 -36
  67. sqlspec/{statement/builder → builder}/mixins/_update_operations.py +3 -14
  68. sqlspec/{statement/builder → builder}/mixins/_where_clause.py +52 -79
  69. sqlspec/cli.py +4 -5
  70. sqlspec/config.py +180 -133
  71. sqlspec/core/__init__.py +63 -0
  72. sqlspec/core/cache.py +873 -0
  73. sqlspec/core/compiler.py +396 -0
  74. sqlspec/core/filters.py +828 -0
  75. sqlspec/core/hashing.py +310 -0
  76. sqlspec/core/parameters.py +1209 -0
  77. sqlspec/core/result.py +664 -0
  78. sqlspec/{statement → core}/splitter.py +321 -191
  79. sqlspec/core/statement.py +651 -0
  80. sqlspec/driver/__init__.py +7 -10
  81. sqlspec/driver/_async.py +387 -176
  82. sqlspec/driver/_common.py +527 -289
  83. sqlspec/driver/_sync.py +390 -172
  84. sqlspec/driver/mixins/__init__.py +2 -19
  85. sqlspec/driver/mixins/_result_tools.py +168 -0
  86. sqlspec/driver/mixins/_sql_translator.py +6 -3
  87. sqlspec/exceptions.py +5 -252
  88. sqlspec/extensions/aiosql/adapter.py +93 -96
  89. sqlspec/extensions/litestar/config.py +0 -1
  90. sqlspec/extensions/litestar/handlers.py +15 -26
  91. sqlspec/extensions/litestar/plugin.py +16 -14
  92. sqlspec/extensions/litestar/providers.py +17 -52
  93. sqlspec/loader.py +424 -105
  94. sqlspec/migrations/__init__.py +12 -0
  95. sqlspec/migrations/base.py +92 -68
  96. sqlspec/migrations/commands.py +24 -106
  97. sqlspec/migrations/loaders.py +402 -0
  98. sqlspec/migrations/runner.py +49 -51
  99. sqlspec/migrations/tracker.py +31 -44
  100. sqlspec/migrations/utils.py +64 -24
  101. sqlspec/protocols.py +7 -183
  102. sqlspec/storage/__init__.py +1 -1
  103. sqlspec/storage/backends/base.py +37 -40
  104. sqlspec/storage/backends/fsspec.py +136 -112
  105. sqlspec/storage/backends/obstore.py +138 -160
  106. sqlspec/storage/capabilities.py +5 -4
  107. sqlspec/storage/registry.py +57 -106
  108. sqlspec/typing.py +136 -115
  109. sqlspec/utils/__init__.py +2 -3
  110. sqlspec/utils/correlation.py +0 -3
  111. sqlspec/utils/deprecation.py +6 -6
  112. sqlspec/utils/fixtures.py +6 -6
  113. sqlspec/utils/logging.py +0 -2
  114. sqlspec/utils/module_loader.py +7 -12
  115. sqlspec/utils/singleton.py +0 -1
  116. sqlspec/utils/sync_tools.py +16 -37
  117. sqlspec/utils/text.py +12 -51
  118. sqlspec/utils/type_guards.py +443 -232
  119. {sqlspec-0.14.1.dist-info → sqlspec-0.15.0.dist-info}/METADATA +7 -2
  120. sqlspec-0.15.0.dist-info/RECORD +134 -0
  121. sqlspec/adapters/adbc/transformers.py +0 -108
  122. sqlspec/driver/connection.py +0 -207
  123. sqlspec/driver/mixins/_cache.py +0 -114
  124. sqlspec/driver/mixins/_csv_writer.py +0 -91
  125. sqlspec/driver/mixins/_pipeline.py +0 -508
  126. sqlspec/driver/mixins/_query_tools.py +0 -796
  127. sqlspec/driver/mixins/_result_utils.py +0 -138
  128. sqlspec/driver/mixins/_storage.py +0 -912
  129. sqlspec/driver/mixins/_type_coercion.py +0 -128
  130. sqlspec/driver/parameters.py +0 -138
  131. sqlspec/statement/__init__.py +0 -21
  132. sqlspec/statement/builder/_merge.py +0 -95
  133. sqlspec/statement/cache.py +0 -50
  134. sqlspec/statement/filters.py +0 -625
  135. sqlspec/statement/parameters.py +0 -956
  136. sqlspec/statement/pipelines/__init__.py +0 -210
  137. sqlspec/statement/pipelines/analyzers/__init__.py +0 -9
  138. sqlspec/statement/pipelines/analyzers/_analyzer.py +0 -646
  139. sqlspec/statement/pipelines/context.py +0 -109
  140. sqlspec/statement/pipelines/transformers/__init__.py +0 -7
  141. sqlspec/statement/pipelines/transformers/_expression_simplifier.py +0 -88
  142. sqlspec/statement/pipelines/transformers/_literal_parameterizer.py +0 -1247
  143. sqlspec/statement/pipelines/transformers/_remove_comments_and_hints.py +0 -76
  144. sqlspec/statement/pipelines/validators/__init__.py +0 -23
  145. sqlspec/statement/pipelines/validators/_dml_safety.py +0 -290
  146. sqlspec/statement/pipelines/validators/_parameter_style.py +0 -370
  147. sqlspec/statement/pipelines/validators/_performance.py +0 -714
  148. sqlspec/statement/pipelines/validators/_security.py +0 -967
  149. sqlspec/statement/result.py +0 -435
  150. sqlspec/statement/sql.py +0 -1774
  151. sqlspec/utils/cached_property.py +0 -25
  152. sqlspec/utils/statement_hashing.py +0 -203
  153. sqlspec-0.14.1.dist-info/RECORD +0 -145
  154. /sqlspec/{statement/builder → builder}/mixins/_delete_operations.py +0 -0
  155. {sqlspec-0.14.1.dist-info → sqlspec-0.15.0.dist-info}/WHEEL +0 -0
  156. {sqlspec-0.14.1.dist-info → sqlspec-0.15.0.dist-info}/entry_points.txt +0 -0
  157. {sqlspec-0.14.1.dist-info → sqlspec-0.15.0.dist-info}/licenses/LICENSE +0 -0
  158. {sqlspec-0.14.1.dist-info → sqlspec-0.15.0.dist-info}/licenses/NOTICE +0 -0
@@ -3,191 +3,106 @@
3
3
  import logging
4
4
  from collections.abc import AsyncGenerator
5
5
  from contextlib import asynccontextmanager
6
- from typing import TYPE_CHECKING, Any, ClassVar, Optional, Union
6
+ from typing import TYPE_CHECKING, Any, ClassVar, Optional, TypedDict, Union
7
7
 
8
8
  import asyncmy
9
+ from asyncmy.cursors import Cursor, DictCursor
9
10
  from asyncmy.pool import Pool as AsyncmyPool
11
+ from typing_extensions import NotRequired
10
12
 
11
- from sqlspec.adapters.asyncmy.driver import AsyncmyConnection, AsyncmyDriver
13
+ from sqlspec.adapters.asyncmy._types import AsyncmyConnection
14
+ from sqlspec.adapters.asyncmy.driver import AsyncmyCursor, AsyncmyDriver, asyncmy_statement_config
12
15
  from sqlspec.config import AsyncDatabaseConfig
13
- from sqlspec.statement.sql import SQLConfig
14
- from sqlspec.typing import DictRow, Empty
15
16
 
16
17
  if TYPE_CHECKING:
17
18
  from asyncmy.cursors import Cursor, DictCursor
18
19
  from asyncmy.pool import Pool
19
20
 
21
+ from sqlspec.core.statement import StatementConfig
20
22
 
21
- __all__ = ("CONNECTION_FIELDS", "POOL_FIELDS", "AsyncmyConfig")
23
+
24
+ __all__ = ("AsyncmyConfig", "AsyncmyConnectionParams", "AsyncmyPoolParams")
22
25
 
23
26
  logger = logging.getLogger(__name__)
24
27
 
25
- CONNECTION_FIELDS = frozenset(
26
- {
27
- "host",
28
- "user",
29
- "password",
30
- "database",
31
- "port",
32
- "unix_socket",
33
- "charset",
34
- "connect_timeout",
35
- "read_default_file",
36
- "read_default_group",
37
- "autocommit",
38
- "local_infile",
39
- "ssl",
40
- "sql_mode",
41
- "init_command",
42
- "cursor_class",
43
- }
44
- )
45
-
46
- POOL_FIELDS = CONNECTION_FIELDS.union({"minsize", "maxsize", "echo", "pool_recycle"})
47
28
 
29
+ class AsyncmyConnectionParams(TypedDict, total=False):
30
+ """Asyncmy connection parameters."""
48
31
 
49
- class AsyncmyConfig(AsyncDatabaseConfig[AsyncmyConnection, "Pool", AsyncmyDriver]): # pyright: ignore
50
- """Configuration for Asyncmy database connections with direct field-based configuration."""
32
+ host: NotRequired[str]
33
+ user: NotRequired[str]
34
+ password: NotRequired[str]
35
+ database: NotRequired[str]
36
+ port: NotRequired[int]
37
+ unix_socket: NotRequired[str]
38
+ charset: NotRequired[str]
39
+ connect_timeout: NotRequired[int]
40
+ read_default_file: NotRequired[str]
41
+ read_default_group: NotRequired[str]
42
+ autocommit: NotRequired[bool]
43
+ local_infile: NotRequired[bool]
44
+ ssl: NotRequired[Any]
45
+ sql_mode: NotRequired[str]
46
+ init_command: NotRequired[str]
47
+ cursor_class: NotRequired[Union[type["Cursor"], type["DictCursor"]]]
48
+ extra: NotRequired[dict[str, Any]]
51
49
 
52
- is_async: ClassVar[bool] = True
53
- supports_connection_pooling: ClassVar[bool] = True
54
- driver_type: type[AsyncmyDriver] = AsyncmyDriver
55
- connection_type: type[AsyncmyConnection] = AsyncmyConnection # pyright: ignore
56
50
 
57
- # Parameter style support information
58
- supported_parameter_styles: ClassVar[tuple[str, ...]] = ("pyformat_positional",)
59
- """AsyncMy only supports %s (pyformat_positional) parameter style."""
51
+ class AsyncmyPoolParams(AsyncmyConnectionParams, total=False):
52
+ """Asyncmy pool parameters."""
60
53
 
61
- default_parameter_style: ClassVar[str] = "pyformat_positional"
62
- """AsyncMy's native parameter style is %s (pyformat_positional)."""
54
+ minsize: NotRequired[int]
55
+ maxsize: NotRequired[int]
56
+ echo: NotRequired[bool]
57
+ pool_recycle: NotRequired[int]
58
+
59
+
60
+ class AsyncmyConfig(AsyncDatabaseConfig[AsyncmyConnection, "Pool", AsyncmyDriver]): # pyright: ignore
61
+ """Configuration for Asyncmy database connections with direct field-based configuration."""
62
+
63
+ driver_type: ClassVar[type[AsyncmyDriver]] = AsyncmyDriver
64
+ connection_type: "ClassVar[type[AsyncmyConnection]]" = AsyncmyConnection # pyright: ignore
63
65
 
64
66
  def __init__(
65
67
  self,
66
- statement_config: Optional[SQLConfig] = None,
67
- default_row_type: type[DictRow] = DictRow,
68
- # Connection parameters
69
- host: Optional[str] = None,
70
- user: Optional[str] = None,
71
- password: Optional[str] = None,
72
- database: Optional[str] = None,
73
- port: Optional[int] = None,
74
- unix_socket: Optional[str] = None,
75
- charset: Optional[str] = None,
76
- connect_timeout: Optional[float] = None,
77
- read_default_file: Optional[str] = None,
78
- read_default_group: Optional[str] = None,
79
- autocommit: Optional[bool] = None,
80
- local_infile: Optional[bool] = None,
81
- ssl: Optional[Any] = None,
82
- sql_mode: Optional[str] = None,
83
- init_command: Optional[str] = None,
84
- cursor_class: Optional[Union["type[Cursor]", "type[DictCursor]"]] = None,
85
- # Pool parameters
86
- minsize: Optional[int] = None,
87
- maxsize: Optional[int] = None,
88
- echo: Optional[bool] = None,
89
- pool_recycle: Optional[int] = None,
90
- pool_instance: Optional["Pool"] = None,
91
- **kwargs: Any,
68
+ *,
69
+ pool_config: "Optional[Union[AsyncmyPoolParams, dict[str, Any]]]" = None,
70
+ pool_instance: "Optional[Pool]" = None,
71
+ migration_config: Optional[dict[str, Any]] = None,
72
+ statement_config: "Optional[StatementConfig]" = None,
92
73
  ) -> None:
93
74
  """Initialize Asyncmy configuration.
94
75
 
95
76
  Args:
96
- statement_config: Default SQL statement configuration
97
- default_row_type: Default row type for results
98
- host: Host where the database server is located
99
- user: The username used to authenticate with the database
100
- password: The password used to authenticate with the database
101
- database: The database name to use
102
- port: The TCP/IP port of the MySQL server
103
- unix_socket: The location of the Unix socket file
104
- charset: The character set to use for the connection
105
- connect_timeout: Timeout before throwing an error when connecting
106
- read_default_file: MySQL configuration file to read
107
- read_default_group: Group to read from the configuration file
108
- autocommit: If True, autocommit mode will be enabled
109
- local_infile: If True, enables LOAD LOCAL INFILE
110
- ssl: SSL connection parameters or boolean
111
- sql_mode: Default SQL_MODE to use
112
- init_command: Initial SQL statement to execute once connected
113
- cursor_class: Custom cursor class to use
114
- minsize: Minimum number of connections to keep in the pool
115
- maxsize: Maximum number of connections allowed in the pool
116
- echo: If True, logging will be enabled for all SQL statements
117
- pool_recycle: Number of seconds after which a connection is recycled
118
- pool_instance: Existing connection pool instance to use
119
- **kwargs: Additional parameters (stored in extras)
120
- """
121
- # Store connection parameters as instance attributes
122
- self.host = host
123
- self.user = user
124
- self.password = password
125
- self.database = database
126
- self.port = port
127
- self.unix_socket = unix_socket
128
- self.charset = charset
129
- self.connect_timeout = connect_timeout
130
- self.read_default_file = read_default_file
131
- self.read_default_group = read_default_group
132
- self.autocommit = autocommit
133
- self.local_infile = local_infile
134
- self.ssl = ssl
135
- self.sql_mode = sql_mode
136
- self.init_command = init_command
137
- self.cursor_class = cursor_class
138
-
139
- # Store pool parameters as instance attributes
140
- self.minsize = minsize
141
- self.maxsize = maxsize
142
- self.echo = echo
143
- self.pool_recycle = pool_recycle
144
- self.extras = kwargs or {}
145
-
146
- # Store other config
147
- self.statement_config = statement_config or SQLConfig()
148
- self.default_row_type = default_row_type
149
-
150
- super().__init__() # pyright: ignore
151
-
152
- @property
153
- def connection_config_dict(self) -> dict[str, Any]:
154
- """Return the connection configuration as a dict for asyncmy.connect().
155
-
156
- This method filters out pool-specific parameters that are not valid for asyncmy.connect().
77
+ pool_config: Pool configuration parameters
78
+ pool_instance: Existing pool instance to use
79
+ migration_config: Migration configuration
80
+ statement_config: Statement configuration override
157
81
  """
158
- # Gather non-None connection parameters
159
- config = {
160
- field: getattr(self, field)
161
- for field in CONNECTION_FIELDS
162
- if getattr(self, field, None) is not None and getattr(self, field) is not Empty
163
- }
164
-
165
- config.update(self.extras)
166
-
167
- return config
168
-
169
- @property
170
- def pool_config_dict(self) -> dict[str, Any]:
171
- """Return the full pool configuration as a dict for asyncmy.create_pool().
172
-
173
- Returns:
174
- A dictionary containing all pool configuration parameters.
175
- """
176
- # Gather non-None parameters from all fields (connection + pool)
177
- config = {
178
- field: getattr(self, field)
179
- for field in POOL_FIELDS
180
- if getattr(self, field, None) is not None and getattr(self, field) is not Empty
181
- }
182
-
183
- # Merge extras parameters
184
- config.update(self.extras)
185
-
186
- return config
82
+ processed_pool_config: dict[str, Any] = dict(pool_config) if pool_config else {}
83
+ if "extra" in processed_pool_config:
84
+ extras = processed_pool_config.pop("extra")
85
+ processed_pool_config.update(extras)
86
+
87
+ if "host" not in processed_pool_config:
88
+ processed_pool_config["host"] = "localhost"
89
+ if "port" not in processed_pool_config:
90
+ processed_pool_config["port"] = 3306
91
+
92
+ if statement_config is None:
93
+ statement_config = asyncmy_statement_config
94
+
95
+ super().__init__(
96
+ pool_config=processed_pool_config,
97
+ pool_instance=pool_instance,
98
+ migration_config=migration_config,
99
+ statement_config=statement_config,
100
+ driver_features={},
101
+ )
187
102
 
188
103
  async def _create_pool(self) -> "Pool": # pyright: ignore
189
104
  """Create the actual async connection pool."""
190
- return await asyncmy.create_pool(**self.pool_config_dict)
105
+ return await asyncmy.create_pool(**dict(self.pool_config))
191
106
 
192
107
  async def _close_pool(self) -> None:
193
108
  """Close the actual async connection pool."""
@@ -221,28 +136,22 @@ class AsyncmyConfig(AsyncDatabaseConfig[AsyncmyConnection, "Pool", AsyncmyDriver
221
136
  yield connection
222
137
 
223
138
  @asynccontextmanager
224
- async def provide_session(self, *args: Any, **kwargs: Any) -> AsyncGenerator[AsyncmyDriver, None]:
139
+ async def provide_session(
140
+ self, *args: Any, statement_config: "Optional[StatementConfig]" = None, **kwargs: Any
141
+ ) -> AsyncGenerator[AsyncmyDriver, None]:
225
142
  """Provide an async driver session context manager.
226
143
 
227
144
  Args:
228
145
  *args: Additional arguments.
146
+ statement_config: Optional statement configuration override.
229
147
  **kwargs: Additional keyword arguments.
230
148
 
231
149
  Yields:
232
150
  An AsyncmyDriver instance.
233
151
  """
234
152
  async with self.provide_connection(*args, **kwargs) as connection:
235
- statement_config = self.statement_config
236
- # Inject parameter style info if not already set
237
- if statement_config.allowed_parameter_styles is None:
238
- from dataclasses import replace
239
-
240
- statement_config = replace(
241
- statement_config,
242
- allowed_parameter_styles=self.supported_parameter_styles,
243
- default_parameter_style=self.default_parameter_style,
244
- )
245
- yield self.driver_type(connection=connection, config=statement_config)
153
+ final_statement_config = statement_config or asyncmy_statement_config
154
+ yield self.driver_type(connection=connection, statement_config=final_statement_config)
246
155
 
247
156
  async def provide_pool(self, *args: Any, **kwargs: Any) -> "Pool": # pyright: ignore
248
157
  """Provide async pool instance.
@@ -263,6 +172,9 @@ class AsyncmyConfig(AsyncDatabaseConfig[AsyncmyConnection, "Pool", AsyncmyDriver
263
172
  Returns:
264
173
  Dictionary mapping type names to types.
265
174
  """
175
+
266
176
  namespace = super().get_signature_namespace()
267
- namespace.update({"AsyncmyConnection": AsyncmyConnection, "AsyncmyPool": AsyncmyPool})
177
+ namespace.update(
178
+ {"AsyncmyConnection": AsyncmyConnection, "AsyncmyPool": AsyncmyPool, "AsyncmyCursor": AsyncmyCursor}
179
+ )
268
180
  return namespace