sqlspec 0.11.0__py3-none-any.whl → 0.12.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 (155) hide show
  1. sqlspec/__init__.py +16 -3
  2. sqlspec/_serialization.py +3 -10
  3. sqlspec/_sql.py +1147 -0
  4. sqlspec/_typing.py +343 -41
  5. sqlspec/adapters/adbc/__init__.py +2 -6
  6. sqlspec/adapters/adbc/config.py +474 -149
  7. sqlspec/adapters/adbc/driver.py +330 -644
  8. sqlspec/adapters/aiosqlite/__init__.py +2 -6
  9. sqlspec/adapters/aiosqlite/config.py +143 -57
  10. sqlspec/adapters/aiosqlite/driver.py +269 -462
  11. sqlspec/adapters/asyncmy/__init__.py +3 -8
  12. sqlspec/adapters/asyncmy/config.py +247 -202
  13. sqlspec/adapters/asyncmy/driver.py +217 -451
  14. sqlspec/adapters/asyncpg/__init__.py +4 -7
  15. sqlspec/adapters/asyncpg/config.py +329 -176
  16. sqlspec/adapters/asyncpg/driver.py +418 -498
  17. sqlspec/adapters/bigquery/__init__.py +2 -2
  18. sqlspec/adapters/bigquery/config.py +407 -0
  19. sqlspec/adapters/bigquery/driver.py +592 -634
  20. sqlspec/adapters/duckdb/__init__.py +4 -1
  21. sqlspec/adapters/duckdb/config.py +432 -321
  22. sqlspec/adapters/duckdb/driver.py +393 -436
  23. sqlspec/adapters/oracledb/__init__.py +3 -8
  24. sqlspec/adapters/oracledb/config.py +625 -0
  25. sqlspec/adapters/oracledb/driver.py +549 -942
  26. sqlspec/adapters/psqlpy/__init__.py +4 -7
  27. sqlspec/adapters/psqlpy/config.py +372 -203
  28. sqlspec/adapters/psqlpy/driver.py +197 -550
  29. sqlspec/adapters/psycopg/__init__.py +3 -8
  30. sqlspec/adapters/psycopg/config.py +741 -0
  31. sqlspec/adapters/psycopg/driver.py +732 -733
  32. sqlspec/adapters/sqlite/__init__.py +2 -6
  33. sqlspec/adapters/sqlite/config.py +146 -81
  34. sqlspec/adapters/sqlite/driver.py +243 -426
  35. sqlspec/base.py +220 -825
  36. sqlspec/config.py +354 -0
  37. sqlspec/driver/__init__.py +22 -0
  38. sqlspec/driver/_async.py +252 -0
  39. sqlspec/driver/_common.py +338 -0
  40. sqlspec/driver/_sync.py +261 -0
  41. sqlspec/driver/mixins/__init__.py +17 -0
  42. sqlspec/driver/mixins/_pipeline.py +523 -0
  43. sqlspec/driver/mixins/_result_utils.py +122 -0
  44. sqlspec/driver/mixins/_sql_translator.py +35 -0
  45. sqlspec/driver/mixins/_storage.py +993 -0
  46. sqlspec/driver/mixins/_type_coercion.py +131 -0
  47. sqlspec/exceptions.py +299 -7
  48. sqlspec/extensions/aiosql/__init__.py +10 -0
  49. sqlspec/extensions/aiosql/adapter.py +474 -0
  50. sqlspec/extensions/litestar/__init__.py +1 -6
  51. sqlspec/extensions/litestar/_utils.py +1 -5
  52. sqlspec/extensions/litestar/config.py +5 -6
  53. sqlspec/extensions/litestar/handlers.py +13 -12
  54. sqlspec/extensions/litestar/plugin.py +22 -24
  55. sqlspec/extensions/litestar/providers.py +37 -55
  56. sqlspec/loader.py +528 -0
  57. sqlspec/service/__init__.py +3 -0
  58. sqlspec/service/base.py +24 -0
  59. sqlspec/service/pagination.py +26 -0
  60. sqlspec/statement/__init__.py +21 -0
  61. sqlspec/statement/builder/__init__.py +54 -0
  62. sqlspec/statement/builder/_ddl_utils.py +119 -0
  63. sqlspec/statement/builder/_parsing_utils.py +135 -0
  64. sqlspec/statement/builder/base.py +328 -0
  65. sqlspec/statement/builder/ddl.py +1379 -0
  66. sqlspec/statement/builder/delete.py +80 -0
  67. sqlspec/statement/builder/insert.py +274 -0
  68. sqlspec/statement/builder/merge.py +95 -0
  69. sqlspec/statement/builder/mixins/__init__.py +65 -0
  70. sqlspec/statement/builder/mixins/_aggregate_functions.py +151 -0
  71. sqlspec/statement/builder/mixins/_case_builder.py +91 -0
  72. sqlspec/statement/builder/mixins/_common_table_expr.py +91 -0
  73. sqlspec/statement/builder/mixins/_delete_from.py +34 -0
  74. sqlspec/statement/builder/mixins/_from.py +61 -0
  75. sqlspec/statement/builder/mixins/_group_by.py +119 -0
  76. sqlspec/statement/builder/mixins/_having.py +35 -0
  77. sqlspec/statement/builder/mixins/_insert_from_select.py +48 -0
  78. sqlspec/statement/builder/mixins/_insert_into.py +36 -0
  79. sqlspec/statement/builder/mixins/_insert_values.py +69 -0
  80. sqlspec/statement/builder/mixins/_join.py +110 -0
  81. sqlspec/statement/builder/mixins/_limit_offset.py +53 -0
  82. sqlspec/statement/builder/mixins/_merge_clauses.py +405 -0
  83. sqlspec/statement/builder/mixins/_order_by.py +46 -0
  84. sqlspec/statement/builder/mixins/_pivot.py +82 -0
  85. sqlspec/statement/builder/mixins/_returning.py +37 -0
  86. sqlspec/statement/builder/mixins/_select_columns.py +60 -0
  87. sqlspec/statement/builder/mixins/_set_ops.py +122 -0
  88. sqlspec/statement/builder/mixins/_unpivot.py +80 -0
  89. sqlspec/statement/builder/mixins/_update_from.py +54 -0
  90. sqlspec/statement/builder/mixins/_update_set.py +91 -0
  91. sqlspec/statement/builder/mixins/_update_table.py +29 -0
  92. sqlspec/statement/builder/mixins/_where.py +374 -0
  93. sqlspec/statement/builder/mixins/_window_functions.py +86 -0
  94. sqlspec/statement/builder/protocols.py +20 -0
  95. sqlspec/statement/builder/select.py +206 -0
  96. sqlspec/statement/builder/update.py +178 -0
  97. sqlspec/statement/filters.py +571 -0
  98. sqlspec/statement/parameters.py +736 -0
  99. sqlspec/statement/pipelines/__init__.py +67 -0
  100. sqlspec/statement/pipelines/analyzers/__init__.py +9 -0
  101. sqlspec/statement/pipelines/analyzers/_analyzer.py +649 -0
  102. sqlspec/statement/pipelines/base.py +315 -0
  103. sqlspec/statement/pipelines/context.py +119 -0
  104. sqlspec/statement/pipelines/result_types.py +41 -0
  105. sqlspec/statement/pipelines/transformers/__init__.py +8 -0
  106. sqlspec/statement/pipelines/transformers/_expression_simplifier.py +256 -0
  107. sqlspec/statement/pipelines/transformers/_literal_parameterizer.py +623 -0
  108. sqlspec/statement/pipelines/transformers/_remove_comments.py +66 -0
  109. sqlspec/statement/pipelines/transformers/_remove_hints.py +81 -0
  110. sqlspec/statement/pipelines/validators/__init__.py +23 -0
  111. sqlspec/statement/pipelines/validators/_dml_safety.py +275 -0
  112. sqlspec/statement/pipelines/validators/_parameter_style.py +297 -0
  113. sqlspec/statement/pipelines/validators/_performance.py +703 -0
  114. sqlspec/statement/pipelines/validators/_security.py +990 -0
  115. sqlspec/statement/pipelines/validators/base.py +67 -0
  116. sqlspec/statement/result.py +527 -0
  117. sqlspec/statement/splitter.py +701 -0
  118. sqlspec/statement/sql.py +1198 -0
  119. sqlspec/storage/__init__.py +15 -0
  120. sqlspec/storage/backends/__init__.py +0 -0
  121. sqlspec/storage/backends/base.py +166 -0
  122. sqlspec/storage/backends/fsspec.py +315 -0
  123. sqlspec/storage/backends/obstore.py +464 -0
  124. sqlspec/storage/protocol.py +170 -0
  125. sqlspec/storage/registry.py +315 -0
  126. sqlspec/typing.py +157 -36
  127. sqlspec/utils/correlation.py +155 -0
  128. sqlspec/utils/deprecation.py +3 -6
  129. sqlspec/utils/fixtures.py +6 -11
  130. sqlspec/utils/logging.py +135 -0
  131. sqlspec/utils/module_loader.py +45 -43
  132. sqlspec/utils/serializers.py +4 -0
  133. sqlspec/utils/singleton.py +6 -8
  134. sqlspec/utils/sync_tools.py +15 -27
  135. sqlspec/utils/text.py +58 -26
  136. {sqlspec-0.11.0.dist-info → sqlspec-0.12.0.dist-info}/METADATA +100 -26
  137. sqlspec-0.12.0.dist-info/RECORD +145 -0
  138. sqlspec/adapters/bigquery/config/__init__.py +0 -3
  139. sqlspec/adapters/bigquery/config/_common.py +0 -40
  140. sqlspec/adapters/bigquery/config/_sync.py +0 -87
  141. sqlspec/adapters/oracledb/config/__init__.py +0 -9
  142. sqlspec/adapters/oracledb/config/_asyncio.py +0 -186
  143. sqlspec/adapters/oracledb/config/_common.py +0 -131
  144. sqlspec/adapters/oracledb/config/_sync.py +0 -186
  145. sqlspec/adapters/psycopg/config/__init__.py +0 -19
  146. sqlspec/adapters/psycopg/config/_async.py +0 -169
  147. sqlspec/adapters/psycopg/config/_common.py +0 -56
  148. sqlspec/adapters/psycopg/config/_sync.py +0 -168
  149. sqlspec/filters.py +0 -330
  150. sqlspec/mixins.py +0 -306
  151. sqlspec/statement.py +0 -378
  152. sqlspec-0.11.0.dist-info/RECORD +0 -69
  153. {sqlspec-0.11.0.dist-info → sqlspec-0.12.0.dist-info}/WHEEL +0 -0
  154. {sqlspec-0.11.0.dist-info → sqlspec-0.12.0.dist-info}/licenses/LICENSE +0 -0
  155. {sqlspec-0.11.0.dist-info → sqlspec-0.12.0.dist-info}/licenses/NOTICE +0 -0
@@ -1,8 +1,4 @@
1
- from sqlspec.adapters.aiosqlite.config import AiosqliteConfig
1
+ from sqlspec.adapters.aiosqlite.config import CONNECTION_FIELDS, AiosqliteConfig
2
2
  from sqlspec.adapters.aiosqlite.driver import AiosqliteConnection, AiosqliteDriver
3
3
 
4
- __all__ = (
5
- "AiosqliteConfig",
6
- "AiosqliteConnection",
7
- "AiosqliteDriver",
8
- )
4
+ __all__ = ("CONNECTION_FIELDS", "AiosqliteConfig", "AiosqliteConnection", "AiosqliteDriver")
@@ -1,87 +1,158 @@
1
+ """Aiosqlite database configuration with direct field-based configuration."""
2
+
3
+ import logging
4
+ from collections.abc import AsyncGenerator
1
5
  from contextlib import asynccontextmanager
2
- from dataclasses import dataclass, field
3
- from typing import TYPE_CHECKING, Any, Optional, Union
6
+ from dataclasses import replace
7
+ from typing import TYPE_CHECKING, Any, ClassVar, Optional
4
8
 
5
9
  import aiosqlite
6
10
 
7
11
  from sqlspec.adapters.aiosqlite.driver import AiosqliteConnection, AiosqliteDriver
8
- from sqlspec.base import NoPoolAsyncConfig
12
+ from sqlspec.config import AsyncDatabaseConfig
9
13
  from sqlspec.exceptions import ImproperConfigurationError
10
- from sqlspec.typing import Empty, EmptyType, dataclass_to_dict
14
+ from sqlspec.statement.sql import SQLConfig
15
+ from sqlspec.typing import DictRow, Empty
11
16
 
12
17
  if TYPE_CHECKING:
13
- from collections.abc import AsyncGenerator
14
18
  from typing import Literal
15
19
 
20
+ from sqlglot.dialects.dialect import DialectType
21
+
16
22
 
17
- __all__ = ("AiosqliteConfig",)
23
+ __all__ = ("CONNECTION_FIELDS", "AiosqliteConfig")
18
24
 
25
+ logger = logging.getLogger(__name__)
19
26
 
20
- @dataclass
21
- class AiosqliteConfig(NoPoolAsyncConfig["AiosqliteConnection", "AiosqliteDriver"]):
22
- """Configuration for Aiosqlite database connections.
27
+ CONNECTION_FIELDS = frozenset(
28
+ {"database", "timeout", "detect_types", "isolation_level", "check_same_thread", "cached_statements", "uri"}
29
+ )
23
30
 
24
- This class provides configuration options for Aiosqlite database connections, wrapping all parameters
25
- available to aiosqlite.connect().
26
31
 
27
- For details see: https://github.com/omnilib/aiosqlite/blob/main/aiosqlite/__init__.pyi
32
+ class AiosqliteConfig(AsyncDatabaseConfig[AiosqliteConnection, None, AiosqliteDriver]):
33
+ """Configuration for Aiosqlite database connections with direct field-based configuration.
34
+
35
+ Note: Aiosqlite doesn't support connection pooling, so pool_instance is always None.
28
36
  """
29
37
 
30
- database: "Union[str, EmptyType]" = field(default=":memory:")
31
- """The path to the database file to be opened. Pass ":memory:" to open a connection to a database that resides in RAM instead of on disk."""
32
- timeout: "Union[float, EmptyType]" = field(default=Empty)
33
- """How many seconds the connection should wait before raising an OperationalError when a table is locked. If another thread or process has acquired a shared lock, a wait for the specified timeout occurs."""
34
- detect_types: "Union[int, EmptyType]" = field(default=Empty)
35
- """Control whether and how data types are detected. It can be 0 (default) or a combination of PARSE_DECLTYPES and PARSE_COLNAMES."""
36
- isolation_level: "Optional[Union[Literal['DEFERRED', 'IMMEDIATE', 'EXCLUSIVE'], EmptyType]]" = field(default=Empty)
37
- """The isolation_level of the connection. This can be None for autocommit mode or one of "DEFERRED", "IMMEDIATE" or "EXCLUSIVE"."""
38
- check_same_thread: "Union[bool, EmptyType]" = field(default=Empty)
39
- """If True (default), ProgrammingError is raised if the database connection is used by a thread other than the one that created it. If False, the connection may be shared across multiple threads."""
40
- cached_statements: "Union[int, EmptyType]" = field(default=Empty)
41
- """The number of statements that SQLite will cache for this connection. The default is 128."""
42
- uri: "Union[bool, EmptyType]" = field(default=Empty)
43
- """If set to True, database is interpreted as a URI with supported options."""
44
- connection_type: "type[AiosqliteConnection]" = field(init=False, default_factory=lambda: AiosqliteConnection)
45
- """Type of the connection object"""
46
- driver_type: "type[AiosqliteDriver]" = field(init=False, default_factory=lambda: AiosqliteDriver) # type: ignore[type-abstract,unused-ignore]
47
- """Type of the driver object"""
38
+ __slots__ = (
39
+ "_dialect",
40
+ "cached_statements",
41
+ "check_same_thread",
42
+ "database",
43
+ "default_row_type",
44
+ "detect_types",
45
+ "extras",
46
+ "isolation_level",
47
+ "pool_instance",
48
+ "statement_config",
49
+ "timeout",
50
+ "uri",
51
+ )
52
+
53
+ is_async: ClassVar[bool] = True
54
+ supports_connection_pooling: ClassVar[bool] = False
55
+
56
+ driver_type: type[AiosqliteDriver] = AiosqliteDriver
57
+ connection_type: type[AiosqliteConnection] = AiosqliteConnection
58
+
59
+ # Parameter style support information
60
+ supported_parameter_styles: ClassVar[tuple[str, ...]] = ("qmark", "named_colon")
61
+ """AIOSQLite supports ? (qmark) and :name (named_colon) parameter styles."""
62
+
63
+ preferred_parameter_style: ClassVar[str] = "qmark"
64
+ """AIOSQLite's native parameter style is ? (qmark)."""
65
+
66
+ def __init__(
67
+ self,
68
+ database: str = ":memory:",
69
+ statement_config: Optional[SQLConfig] = None,
70
+ default_row_type: type[DictRow] = DictRow,
71
+ # Connection parameters
72
+ timeout: Optional[float] = None,
73
+ detect_types: Optional[int] = None,
74
+ isolation_level: Optional["Optional[Literal['DEFERRED', 'IMMEDIATE', 'EXCLUSIVE']]"] = None,
75
+ check_same_thread: Optional[bool] = None,
76
+ cached_statements: Optional[int] = None,
77
+ uri: Optional[bool] = None,
78
+ **kwargs: Any,
79
+ ) -> None:
80
+ """Initialize Aiosqlite configuration.
81
+
82
+ Args:
83
+ database: The path to the database file to be opened. Pass ":memory:" for in-memory database
84
+ statement_config: Default SQL statement configuration
85
+ default_row_type: Default row type for results
86
+ timeout: How many seconds the connection should wait before raising an OperationalError when a table is locked
87
+ detect_types: Control whether and how data types are detected. It can be 0 (default) or a combination of PARSE_DECLTYPES and PARSE_COLNAMES
88
+ isolation_level: The isolation_level of the connection. This can be None for autocommit mode or one of "DEFERRED", "IMMEDIATE" or "EXCLUSIVE"
89
+ check_same_thread: If True (default), ProgrammingError is raised if the database connection is used by a thread other than the one that created it
90
+ cached_statements: The number of statements that SQLite will cache for this connection. The default is 128
91
+ uri: If set to True, database is interpreted as a URI with supported options
92
+ **kwargs: Additional parameters (stored in extras)
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.cached_statements = cached_statements
101
+ self.uri = uri
102
+ self.extras = kwargs or {}
103
+ # Store other config
104
+ self.statement_config = statement_config or SQLConfig()
105
+ self.default_row_type = default_row_type
106
+ self._dialect: DialectType = None
107
+
108
+ super().__init__()
48
109
 
49
110
  @property
50
- def connection_config_dict(self) -> "dict[str, Any]":
51
- """Return the connection configuration as a dict.
111
+ def connection_config_dict(self) -> dict[str, Any]:
112
+ """Return the connection configuration as a dict for aiosqlite.connect()."""
113
+ # Gather non-None connection parameters
114
+ config = {
115
+ field: getattr(self, field)
116
+ for field in CONNECTION_FIELDS
117
+ if getattr(self, field, None) is not None and getattr(self, field) is not Empty
118
+ }
52
119
 
53
- Returns:
54
- A string keyed dict of config kwargs for the aiosqlite.connect() function.
55
- """
56
- return dataclass_to_dict(
57
- self,
58
- exclude_empty=True,
59
- convert_nested=False,
60
- exclude={"pool_instance", "connection_type", "driver_type"},
61
- )
120
+ # Merge extras parameters
121
+ config.update(self.extras)
62
122
 
63
- async def create_connection(self) -> "AiosqliteConnection":
64
- """Create and return a new database connection.
123
+ return config
65
124
 
66
- Returns:
67
- A new Aiosqlite connection instance.
125
+ async def _create_pool(self) -> None:
126
+ """Aiosqlite doesn't support pooling."""
127
+ return
128
+
129
+ async def _close_pool(self) -> None:
130
+ """Aiosqlite doesn't support pooling."""
131
+ return
68
132
 
69
- Raises:
70
- ImproperConfigurationError: If the connection could not be established.
133
+ async def create_connection(self) -> AiosqliteConnection:
134
+ """Create a single async connection.
135
+
136
+ Returns:
137
+ An Aiosqlite connection instance.
71
138
  """
72
139
  try:
73
- return await aiosqlite.connect(**self.connection_config_dict)
140
+ config = self.connection_config_dict
141
+ return await aiosqlite.connect(**config)
74
142
  except Exception as e:
75
143
  msg = f"Could not configure the Aiosqlite connection. Error: {e!s}"
76
144
  raise ImproperConfigurationError(msg) from e
77
145
 
78
146
  @asynccontextmanager
79
- async def provide_connection(self, *args: "Any", **kwargs: "Any") -> "AsyncGenerator[AiosqliteConnection, None]":
80
- """Create and provide a database connection.
147
+ async def provide_connection(self, *args: Any, **kwargs: Any) -> AsyncGenerator[AiosqliteConnection, None]:
148
+ """Provide an async connection context manager.
149
+
150
+ Args:
151
+ *args: Additional arguments.
152
+ **kwargs: Additional keyword arguments.
81
153
 
82
154
  Yields:
83
155
  An Aiosqlite connection instance.
84
-
85
156
  """
86
157
  connection = await self.create_connection()
87
158
  try:
@@ -90,13 +161,28 @@ class AiosqliteConfig(NoPoolAsyncConfig["AiosqliteConnection", "AiosqliteDriver"
90
161
  await connection.close()
91
162
 
92
163
  @asynccontextmanager
93
- async def provide_session(self, *args: Any, **kwargs: Any) -> "AsyncGenerator[AiosqliteDriver, None]":
94
- """Create and provide a database connection.
95
-
96
- Yields:
97
- A Aiosqlite driver instance.
164
+ async def provide_session(self, *args: Any, **kwargs: Any) -> AsyncGenerator[AiosqliteDriver, None]:
165
+ """Provide an async driver session context manager.
98
166
 
167
+ Args:
168
+ *args: Additional arguments.
169
+ **kwargs: Additional keyword arguments.
99
170
 
171
+ Yields:
172
+ An AiosqliteDriver instance.
100
173
  """
101
174
  async with self.provide_connection(*args, **kwargs) as connection:
102
- yield self.driver_type(connection)
175
+ # Create statement config with parameter style info if not already set
176
+ statement_config = self.statement_config
177
+ if statement_config.allowed_parameter_styles is None:
178
+ statement_config = replace(
179
+ statement_config,
180
+ allowed_parameter_styles=self.supported_parameter_styles,
181
+ target_parameter_style=self.preferred_parameter_style,
182
+ )
183
+
184
+ yield self.driver_type(connection=connection, config=statement_config)
185
+
186
+ async def provide_pool(self, *args: Any, **kwargs: Any) -> None:
187
+ """Aiosqlite doesn't support pooling."""
188
+ return