sqlspec 0.26.0__py3-none-any.whl → 0.28.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 (212) hide show
  1. sqlspec/__init__.py +7 -15
  2. sqlspec/_serialization.py +55 -25
  3. sqlspec/_typing.py +155 -52
  4. sqlspec/adapters/adbc/_types.py +1 -1
  5. sqlspec/adapters/adbc/adk/__init__.py +5 -0
  6. sqlspec/adapters/adbc/adk/store.py +880 -0
  7. sqlspec/adapters/adbc/config.py +62 -12
  8. sqlspec/adapters/adbc/data_dictionary.py +74 -2
  9. sqlspec/adapters/adbc/driver.py +226 -58
  10. sqlspec/adapters/adbc/litestar/__init__.py +5 -0
  11. sqlspec/adapters/adbc/litestar/store.py +504 -0
  12. sqlspec/adapters/adbc/type_converter.py +44 -50
  13. sqlspec/adapters/aiosqlite/_types.py +1 -1
  14. sqlspec/adapters/aiosqlite/adk/__init__.py +5 -0
  15. sqlspec/adapters/aiosqlite/adk/store.py +536 -0
  16. sqlspec/adapters/aiosqlite/config.py +86 -16
  17. sqlspec/adapters/aiosqlite/data_dictionary.py +34 -2
  18. sqlspec/adapters/aiosqlite/driver.py +127 -38
  19. sqlspec/adapters/aiosqlite/litestar/__init__.py +5 -0
  20. sqlspec/adapters/aiosqlite/litestar/store.py +281 -0
  21. sqlspec/adapters/aiosqlite/pool.py +7 -7
  22. sqlspec/adapters/asyncmy/__init__.py +7 -1
  23. sqlspec/adapters/asyncmy/_types.py +1 -1
  24. sqlspec/adapters/asyncmy/adk/__init__.py +5 -0
  25. sqlspec/adapters/asyncmy/adk/store.py +503 -0
  26. sqlspec/adapters/asyncmy/config.py +59 -17
  27. sqlspec/adapters/asyncmy/data_dictionary.py +41 -2
  28. sqlspec/adapters/asyncmy/driver.py +293 -62
  29. sqlspec/adapters/asyncmy/litestar/__init__.py +5 -0
  30. sqlspec/adapters/asyncmy/litestar/store.py +296 -0
  31. sqlspec/adapters/asyncpg/__init__.py +2 -1
  32. sqlspec/adapters/asyncpg/_type_handlers.py +71 -0
  33. sqlspec/adapters/asyncpg/_types.py +11 -7
  34. sqlspec/adapters/asyncpg/adk/__init__.py +5 -0
  35. sqlspec/adapters/asyncpg/adk/store.py +460 -0
  36. sqlspec/adapters/asyncpg/config.py +57 -36
  37. sqlspec/adapters/asyncpg/data_dictionary.py +48 -2
  38. sqlspec/adapters/asyncpg/driver.py +153 -23
  39. sqlspec/adapters/asyncpg/litestar/__init__.py +5 -0
  40. sqlspec/adapters/asyncpg/litestar/store.py +253 -0
  41. sqlspec/adapters/bigquery/_types.py +1 -1
  42. sqlspec/adapters/bigquery/adk/__init__.py +5 -0
  43. sqlspec/adapters/bigquery/adk/store.py +585 -0
  44. sqlspec/adapters/bigquery/config.py +36 -11
  45. sqlspec/adapters/bigquery/data_dictionary.py +42 -2
  46. sqlspec/adapters/bigquery/driver.py +489 -144
  47. sqlspec/adapters/bigquery/litestar/__init__.py +5 -0
  48. sqlspec/adapters/bigquery/litestar/store.py +327 -0
  49. sqlspec/adapters/bigquery/type_converter.py +55 -23
  50. sqlspec/adapters/duckdb/_types.py +2 -2
  51. sqlspec/adapters/duckdb/adk/__init__.py +14 -0
  52. sqlspec/adapters/duckdb/adk/store.py +563 -0
  53. sqlspec/adapters/duckdb/config.py +79 -21
  54. sqlspec/adapters/duckdb/data_dictionary.py +41 -2
  55. sqlspec/adapters/duckdb/driver.py +225 -44
  56. sqlspec/adapters/duckdb/litestar/__init__.py +5 -0
  57. sqlspec/adapters/duckdb/litestar/store.py +332 -0
  58. sqlspec/adapters/duckdb/pool.py +5 -5
  59. sqlspec/adapters/duckdb/type_converter.py +51 -21
  60. sqlspec/adapters/oracledb/_numpy_handlers.py +133 -0
  61. sqlspec/adapters/oracledb/_types.py +20 -2
  62. sqlspec/adapters/oracledb/adk/__init__.py +5 -0
  63. sqlspec/adapters/oracledb/adk/store.py +1628 -0
  64. sqlspec/adapters/oracledb/config.py +120 -36
  65. sqlspec/adapters/oracledb/data_dictionary.py +87 -20
  66. sqlspec/adapters/oracledb/driver.py +475 -86
  67. sqlspec/adapters/oracledb/litestar/__init__.py +5 -0
  68. sqlspec/adapters/oracledb/litestar/store.py +765 -0
  69. sqlspec/adapters/oracledb/migrations.py +316 -25
  70. sqlspec/adapters/oracledb/type_converter.py +91 -16
  71. sqlspec/adapters/psqlpy/_type_handlers.py +44 -0
  72. sqlspec/adapters/psqlpy/_types.py +2 -1
  73. sqlspec/adapters/psqlpy/adk/__init__.py +5 -0
  74. sqlspec/adapters/psqlpy/adk/store.py +483 -0
  75. sqlspec/adapters/psqlpy/config.py +45 -19
  76. sqlspec/adapters/psqlpy/data_dictionary.py +48 -2
  77. sqlspec/adapters/psqlpy/driver.py +108 -41
  78. sqlspec/adapters/psqlpy/litestar/__init__.py +5 -0
  79. sqlspec/adapters/psqlpy/litestar/store.py +272 -0
  80. sqlspec/adapters/psqlpy/type_converter.py +40 -11
  81. sqlspec/adapters/psycopg/_type_handlers.py +80 -0
  82. sqlspec/adapters/psycopg/_types.py +2 -1
  83. sqlspec/adapters/psycopg/adk/__init__.py +5 -0
  84. sqlspec/adapters/psycopg/adk/store.py +962 -0
  85. sqlspec/adapters/psycopg/config.py +65 -37
  86. sqlspec/adapters/psycopg/data_dictionary.py +91 -3
  87. sqlspec/adapters/psycopg/driver.py +200 -78
  88. sqlspec/adapters/psycopg/litestar/__init__.py +5 -0
  89. sqlspec/adapters/psycopg/litestar/store.py +554 -0
  90. sqlspec/adapters/sqlite/__init__.py +2 -1
  91. sqlspec/adapters/sqlite/_type_handlers.py +86 -0
  92. sqlspec/adapters/sqlite/_types.py +1 -1
  93. sqlspec/adapters/sqlite/adk/__init__.py +5 -0
  94. sqlspec/adapters/sqlite/adk/store.py +582 -0
  95. sqlspec/adapters/sqlite/config.py +85 -16
  96. sqlspec/adapters/sqlite/data_dictionary.py +34 -2
  97. sqlspec/adapters/sqlite/driver.py +120 -52
  98. sqlspec/adapters/sqlite/litestar/__init__.py +5 -0
  99. sqlspec/adapters/sqlite/litestar/store.py +318 -0
  100. sqlspec/adapters/sqlite/pool.py +5 -5
  101. sqlspec/base.py +45 -26
  102. sqlspec/builder/__init__.py +73 -4
  103. sqlspec/builder/_base.py +91 -58
  104. sqlspec/builder/_column.py +5 -5
  105. sqlspec/builder/_ddl.py +98 -89
  106. sqlspec/builder/_delete.py +5 -4
  107. sqlspec/builder/_dml.py +388 -0
  108. sqlspec/{_sql.py → builder/_factory.py} +41 -44
  109. sqlspec/builder/_insert.py +5 -82
  110. sqlspec/builder/{mixins/_join_operations.py → _join.py} +145 -143
  111. sqlspec/builder/_merge.py +446 -11
  112. sqlspec/builder/_parsing_utils.py +9 -11
  113. sqlspec/builder/_select.py +1313 -25
  114. sqlspec/builder/_update.py +11 -42
  115. sqlspec/cli.py +76 -69
  116. sqlspec/config.py +331 -62
  117. sqlspec/core/__init__.py +5 -4
  118. sqlspec/core/cache.py +18 -18
  119. sqlspec/core/compiler.py +6 -8
  120. sqlspec/core/filters.py +55 -47
  121. sqlspec/core/hashing.py +9 -9
  122. sqlspec/core/parameters.py +76 -45
  123. sqlspec/core/result.py +234 -47
  124. sqlspec/core/splitter.py +16 -17
  125. sqlspec/core/statement.py +32 -31
  126. sqlspec/core/type_conversion.py +3 -2
  127. sqlspec/driver/__init__.py +1 -3
  128. sqlspec/driver/_async.py +183 -160
  129. sqlspec/driver/_common.py +197 -109
  130. sqlspec/driver/_sync.py +189 -161
  131. sqlspec/driver/mixins/_result_tools.py +20 -236
  132. sqlspec/driver/mixins/_sql_translator.py +4 -4
  133. sqlspec/exceptions.py +70 -7
  134. sqlspec/extensions/adk/__init__.py +53 -0
  135. sqlspec/extensions/adk/_types.py +51 -0
  136. sqlspec/extensions/adk/converters.py +172 -0
  137. sqlspec/extensions/adk/migrations/0001_create_adk_tables.py +144 -0
  138. sqlspec/extensions/adk/migrations/__init__.py +0 -0
  139. sqlspec/extensions/adk/service.py +181 -0
  140. sqlspec/extensions/adk/store.py +536 -0
  141. sqlspec/extensions/aiosql/adapter.py +69 -61
  142. sqlspec/extensions/fastapi/__init__.py +21 -0
  143. sqlspec/extensions/fastapi/extension.py +331 -0
  144. sqlspec/extensions/fastapi/providers.py +543 -0
  145. sqlspec/extensions/flask/__init__.py +36 -0
  146. sqlspec/extensions/flask/_state.py +71 -0
  147. sqlspec/extensions/flask/_utils.py +40 -0
  148. sqlspec/extensions/flask/extension.py +389 -0
  149. sqlspec/extensions/litestar/__init__.py +21 -4
  150. sqlspec/extensions/litestar/cli.py +54 -10
  151. sqlspec/extensions/litestar/config.py +56 -266
  152. sqlspec/extensions/litestar/handlers.py +46 -17
  153. sqlspec/extensions/litestar/migrations/0001_create_session_table.py +137 -0
  154. sqlspec/extensions/litestar/migrations/__init__.py +3 -0
  155. sqlspec/extensions/litestar/plugin.py +349 -224
  156. sqlspec/extensions/litestar/providers.py +25 -25
  157. sqlspec/extensions/litestar/store.py +265 -0
  158. sqlspec/extensions/starlette/__init__.py +10 -0
  159. sqlspec/extensions/starlette/_state.py +25 -0
  160. sqlspec/extensions/starlette/_utils.py +52 -0
  161. sqlspec/extensions/starlette/extension.py +254 -0
  162. sqlspec/extensions/starlette/middleware.py +154 -0
  163. sqlspec/loader.py +30 -49
  164. sqlspec/migrations/base.py +200 -76
  165. sqlspec/migrations/commands.py +591 -62
  166. sqlspec/migrations/context.py +6 -9
  167. sqlspec/migrations/fix.py +199 -0
  168. sqlspec/migrations/loaders.py +47 -19
  169. sqlspec/migrations/runner.py +241 -75
  170. sqlspec/migrations/tracker.py +237 -21
  171. sqlspec/migrations/utils.py +51 -3
  172. sqlspec/migrations/validation.py +177 -0
  173. sqlspec/protocols.py +106 -36
  174. sqlspec/storage/_utils.py +85 -0
  175. sqlspec/storage/backends/fsspec.py +133 -107
  176. sqlspec/storage/backends/local.py +78 -51
  177. sqlspec/storage/backends/obstore.py +276 -168
  178. sqlspec/storage/registry.py +75 -39
  179. sqlspec/typing.py +30 -84
  180. sqlspec/utils/__init__.py +25 -4
  181. sqlspec/utils/arrow_helpers.py +81 -0
  182. sqlspec/utils/config_resolver.py +6 -6
  183. sqlspec/utils/correlation.py +4 -5
  184. sqlspec/utils/data_transformation.py +3 -2
  185. sqlspec/utils/deprecation.py +9 -8
  186. sqlspec/utils/fixtures.py +4 -4
  187. sqlspec/utils/logging.py +46 -6
  188. sqlspec/utils/module_loader.py +205 -5
  189. sqlspec/utils/portal.py +311 -0
  190. sqlspec/utils/schema.py +288 -0
  191. sqlspec/utils/serializers.py +113 -4
  192. sqlspec/utils/sync_tools.py +36 -22
  193. sqlspec/utils/text.py +1 -2
  194. sqlspec/utils/type_guards.py +136 -20
  195. sqlspec/utils/version.py +433 -0
  196. {sqlspec-0.26.0.dist-info → sqlspec-0.28.0.dist-info}/METADATA +41 -22
  197. sqlspec-0.28.0.dist-info/RECORD +221 -0
  198. sqlspec/builder/mixins/__init__.py +0 -55
  199. sqlspec/builder/mixins/_cte_and_set_ops.py +0 -253
  200. sqlspec/builder/mixins/_delete_operations.py +0 -50
  201. sqlspec/builder/mixins/_insert_operations.py +0 -282
  202. sqlspec/builder/mixins/_merge_operations.py +0 -698
  203. sqlspec/builder/mixins/_order_limit_operations.py +0 -145
  204. sqlspec/builder/mixins/_pivot_operations.py +0 -157
  205. sqlspec/builder/mixins/_select_operations.py +0 -930
  206. sqlspec/builder/mixins/_update_operations.py +0 -199
  207. sqlspec/builder/mixins/_where_clause.py +0 -1298
  208. sqlspec-0.26.0.dist-info/RECORD +0 -157
  209. sqlspec-0.26.0.dist-info/licenses/NOTICE +0 -29
  210. {sqlspec-0.26.0.dist-info → sqlspec-0.28.0.dist-info}/WHEEL +0 -0
  211. {sqlspec-0.26.0.dist-info → sqlspec-0.28.0.dist-info}/entry_points.txt +0 -0
  212. {sqlspec-0.26.0.dist-info → sqlspec-0.28.0.dist-info}/licenses/LICENSE +0 -0
@@ -20,12 +20,13 @@ Processing:
20
20
  """
21
21
 
22
22
  import re
23
- from collections.abc import Mapping, Sequence
23
+ from collections import OrderedDict
24
+ from collections.abc import Callable, Mapping, Sequence
24
25
  from datetime import date, datetime
25
26
  from decimal import Decimal
26
27
  from enum import Enum
27
28
  from functools import singledispatch
28
- from typing import Any, Callable, Optional
29
+ from typing import Any
29
30
 
30
31
  from mypy_extensions import mypyc_attr
31
32
 
@@ -107,7 +108,7 @@ class TypedParameter:
107
108
 
108
109
  __slots__ = ("_hash", "original_type", "semantic_name", "value")
109
110
 
110
- def __init__(self, value: Any, original_type: Optional[type] = None, semantic_name: Optional[str] = None) -> None:
111
+ def __init__(self, value: Any, original_type: type | None = None, semantic_name: str | None = None) -> None:
111
112
  """Initialize typed parameter wrapper.
112
113
 
113
114
  Args:
@@ -118,7 +119,7 @@ class TypedParameter:
118
119
  self.value = value
119
120
  self.original_type = original_type or type(value)
120
121
  self.semantic_name = semantic_name
121
- self._hash: Optional[int] = None
122
+ self._hash: int | None = None
122
123
 
123
124
  def __hash__(self) -> int:
124
125
  """Cached hash value."""
@@ -144,7 +145,7 @@ class TypedParameter:
144
145
 
145
146
 
146
147
  @singledispatch
147
- def _wrap_parameter_by_type(value: Any, semantic_name: Optional[str] = None) -> Any:
148
+ def _wrap_parameter_by_type(value: Any, semantic_name: str | None = None) -> Any:
148
149
  """Type-specific parameter wrapping using singledispatch.
149
150
 
150
151
  Args:
@@ -158,31 +159,31 @@ def _wrap_parameter_by_type(value: Any, semantic_name: Optional[str] = None) ->
158
159
 
159
160
 
160
161
  @_wrap_parameter_by_type.register
161
- def _(value: bool, semantic_name: Optional[str] = None) -> TypedParameter:
162
+ def _(value: bool, semantic_name: str | None = None) -> TypedParameter:
162
163
  """Wrap boolean values to prevent SQLGlot parsing issues."""
163
164
  return TypedParameter(value, bool, semantic_name)
164
165
 
165
166
 
166
167
  @_wrap_parameter_by_type.register
167
- def _(value: Decimal, semantic_name: Optional[str] = None) -> TypedParameter:
168
+ def _(value: Decimal, semantic_name: str | None = None) -> TypedParameter:
168
169
  """Wrap Decimal values to preserve precision."""
169
170
  return TypedParameter(value, Decimal, semantic_name)
170
171
 
171
172
 
172
173
  @_wrap_parameter_by_type.register
173
- def _(value: datetime, semantic_name: Optional[str] = None) -> TypedParameter:
174
+ def _(value: datetime, semantic_name: str | None = None) -> TypedParameter:
174
175
  """Wrap datetime values for database-specific formatting."""
175
176
  return TypedParameter(value, datetime, semantic_name)
176
177
 
177
178
 
178
179
  @_wrap_parameter_by_type.register
179
- def _(value: date, semantic_name: Optional[str] = None) -> TypedParameter:
180
+ def _(value: date, semantic_name: str | None = None) -> TypedParameter:
180
181
  """Wrap date values for database-specific formatting."""
181
182
  return TypedParameter(value, date, semantic_name)
182
183
 
183
184
 
184
185
  @_wrap_parameter_by_type.register
185
- def _(value: bytes, semantic_name: Optional[str] = None) -> TypedParameter:
186
+ def _(value: bytes, semantic_name: str | None = None) -> TypedParameter:
186
187
  """Wrap bytes values to prevent string conversion issues in ADBC/Arrow."""
187
188
  return TypedParameter(value, bytes, semantic_name)
188
189
 
@@ -204,7 +205,7 @@ class ParameterInfo:
204
205
  __slots__ = ("name", "ordinal", "placeholder_text", "position", "style")
205
206
 
206
207
  def __init__(
207
- self, name: Optional[str], style: ParameterStyle, position: int, ordinal: int, placeholder_text: str
208
+ self, name: str | None, style: ParameterStyle, position: int, ordinal: int, placeholder_text: str
208
209
  ) -> None:
209
210
  """Initialize parameter information.
210
211
 
@@ -234,17 +235,8 @@ class ParameterInfo:
234
235
  class ParameterStyleConfig:
235
236
  """Configuration for parameter style processing.
236
237
 
237
- Provides configuration for parameter processing operations.
238
-
239
- Attributes:
240
- default_parameter_style: Primary parsing style
241
- supported_parameter_styles: All input styles supported
242
- supported_execution_parameter_styles: Styles driver can execute
243
- default_execution_parameter_style: Target execution format
244
- type_coercion_map: Type conversions
245
- output_transformer: Final SQL/parameter transformation hook
246
- preserve_parameter_format: Maintain original parameter structure
247
- needs_static_script_compilation: Embed parameters in SQL
238
+ Provides configuration for parameter processing operations including
239
+ style conversion, type coercion, and parameter format preservation.
248
240
  """
249
241
 
250
242
  __slots__ = (
@@ -265,17 +257,17 @@ class ParameterStyleConfig:
265
257
  def __init__(
266
258
  self,
267
259
  default_parameter_style: ParameterStyle,
268
- supported_parameter_styles: Optional[set[ParameterStyle]] = None,
269
- supported_execution_parameter_styles: Optional[set[ParameterStyle]] = None,
270
- default_execution_parameter_style: Optional[ParameterStyle] = None,
271
- type_coercion_map: Optional[dict[type, Callable[[Any], Any]]] = None,
260
+ supported_parameter_styles: set[ParameterStyle] | None = None,
261
+ supported_execution_parameter_styles: set[ParameterStyle] | None = None,
262
+ default_execution_parameter_style: ParameterStyle | None = None,
263
+ type_coercion_map: dict[type, Callable[[Any], Any]] | None = None,
272
264
  has_native_list_expansion: bool = False,
273
265
  needs_static_script_compilation: bool = False,
274
266
  allow_mixed_parameter_styles: bool = False,
275
267
  preserve_parameter_format: bool = True,
276
268
  preserve_original_params_for_many: bool = False,
277
- output_transformer: Optional[Callable[[str, Any], tuple[str, Any]]] = None,
278
- ast_transformer: Optional[Callable[[Any, Any], tuple[Any, Any]]] = None,
269
+ output_transformer: Callable[[str, Any], tuple[str, Any]] | None = None,
270
+ ast_transformer: Callable[[Any, Any], tuple[Any, Any]] | None = None,
279
271
  ) -> None:
280
272
  """Initialize parameter style configuration.
281
273
 
@@ -343,13 +335,18 @@ class ParameterValidator:
343
335
  compatibility with target dialects.
344
336
  """
345
337
 
346
- __slots__ = ("_parameter_cache",)
338
+ __slots__ = ("_cache_max_size", "_parameter_cache")
347
339
 
348
- def __init__(self) -> None:
349
- """Initialize validator with parameter cache."""
350
- self._parameter_cache: dict[str, list[ParameterInfo]] = {}
340
+ def __init__(self, cache_max_size: int = 5000) -> None:
341
+ """Initialize validator with bounded LRU cache.
342
+
343
+ Args:
344
+ cache_max_size: Maximum number of SQL strings to cache (default: 5000)
345
+ """
346
+ self._parameter_cache: OrderedDict[str, list[ParameterInfo]] = OrderedDict()
347
+ self._cache_max_size = cache_max_size
351
348
 
352
- def _extract_parameter_style(self, match: "re.Match[str]") -> "tuple[Optional[ParameterStyle], Optional[str]]":
349
+ def _extract_parameter_style(self, match: "re.Match[str]") -> "tuple[ParameterStyle | None, str | None]":
353
350
  """Extract parameter style and name from regex match.
354
351
 
355
352
  Args:
@@ -396,8 +393,15 @@ class ParameterValidator:
396
393
  """
397
394
  cached_result = self._parameter_cache.get(sql)
398
395
  if cached_result is not None:
396
+ self._parameter_cache.move_to_end(sql)
399
397
  return cached_result
400
398
 
399
+ if not any(c in sql for c in ("?", "%", ":", "@", "$")):
400
+ if len(self._parameter_cache) >= self._cache_max_size:
401
+ self._parameter_cache.popitem(last=False)
402
+ self._parameter_cache[sql] = []
403
+ return []
404
+
401
405
  parameters: list[ParameterInfo] = []
402
406
  ordinal = 0
403
407
 
@@ -425,10 +429,13 @@ class ParameterValidator:
425
429
  )
426
430
  ordinal += 1
427
431
 
432
+ if len(self._parameter_cache) >= self._cache_max_size:
433
+ self._parameter_cache.popitem(last=False)
434
+
428
435
  self._parameter_cache[sql] = parameters
429
436
  return parameters
430
437
 
431
- def get_sqlglot_incompatible_styles(self, dialect: Optional[str] = None) -> "set[ParameterStyle]":
438
+ def get_sqlglot_incompatible_styles(self, dialect: str | None = None) -> "set[ParameterStyle]":
432
439
  """Get parameter styles incompatible with SQLGlot for dialect.
433
440
 
434
441
  Args:
@@ -491,7 +498,7 @@ class ParameterConverter:
491
498
  ParameterStyle.POSITIONAL_PYFORMAT: lambda _: "%s",
492
499
  }
493
500
 
494
- def normalize_sql_for_parsing(self, sql: str, dialect: Optional[str] = None) -> "tuple[str, list[ParameterInfo]]":
501
+ def normalize_sql_for_parsing(self, sql: str, dialect: str | None = None) -> "tuple[str, list[ParameterInfo]]":
495
502
  """Convert SQL to parsable format.
496
503
 
497
504
  Takes raw SQL with potentially incompatible parameter styles and converts
@@ -1002,13 +1009,37 @@ class ParameterProcessor:
1002
1009
  target_style = self._determine_target_execution_style(original_styles, config)
1003
1010
  return self._converter.convert_placeholder_style(sql, parameters, target_style, is_many)
1004
1011
 
1012
+ def _generate_processor_cache_key(
1013
+ self, sql: str, parameters: Any, config: ParameterStyleConfig, is_many: bool, dialect: "str | None"
1014
+ ) -> str:
1015
+ """Generate optimized cache key for parameter processing.
1016
+
1017
+ Uses parameter fingerprint (type + structure) instead of repr()
1018
+ for better performance on large parameter sets.
1019
+
1020
+ Args:
1021
+ sql: SQL string
1022
+ parameters: Parameter values
1023
+ config: Parameter style configuration
1024
+ is_many: Whether this is execute_many
1025
+ dialect: SQL dialect
1026
+
1027
+ Returns:
1028
+ Cache key string
1029
+ """
1030
+ param_fingerprint = (
1031
+ "none"
1032
+ if parameters is None
1033
+ else f"seq_{len(parameters)}_{type(parameters).__name__}"
1034
+ if isinstance(parameters, (list, tuple))
1035
+ else f"map_{len(parameters)}"
1036
+ if isinstance(parameters, dict)
1037
+ else f"scalar_{type(parameters).__name__}"
1038
+ )
1039
+ return f"{sql}:{param_fingerprint}:{config.default_parameter_style}:{is_many}:{dialect}"
1040
+
1005
1041
  def process(
1006
- self,
1007
- sql: str,
1008
- parameters: Any,
1009
- config: ParameterStyleConfig,
1010
- dialect: Optional[str] = None,
1011
- is_many: bool = False,
1042
+ self, sql: str, parameters: Any, config: ParameterStyleConfig, dialect: str | None = None, is_many: bool = False
1012
1043
  ) -> "tuple[str, Any]":
1013
1044
  """Process parameters through the complete pipeline.
1014
1045
 
@@ -1029,7 +1060,7 @@ class ParameterProcessor:
1029
1060
  Returns:
1030
1061
  Tuple of (final_sql, execution_parameters)
1031
1062
  """
1032
- cache_key = f"{sql}:{hash(repr(parameters))}:{config.default_parameter_style}:{is_many}:{dialect}"
1063
+ cache_key = self._generate_processor_cache_key(sql, parameters, config, is_many, dialect)
1033
1064
  if cache_key in self._cache:
1034
1065
  return self._cache[cache_key]
1035
1066
 
@@ -1082,7 +1113,7 @@ class ParameterProcessor:
1082
1113
  return processed_sql, processed_parameters
1083
1114
 
1084
1115
  def get_sqlglot_compatible_sql(
1085
- self, sql: str, parameters: Any, config: ParameterStyleConfig, dialect: Optional[str] = None
1116
+ self, sql: str, parameters: Any, config: ParameterStyleConfig, dialect: str | None = None
1086
1117
  ) -> "tuple[str, Any]":
1087
1118
  """Get SQL normalized for parsing only (Phase 1 only).
1088
1119
 
@@ -1139,7 +1170,7 @@ class ParameterProcessor:
1139
1170
 
1140
1171
  return True
1141
1172
 
1142
- def _needs_sqlglot_normalization(self, param_info: "list[ParameterInfo]", dialect: Optional[str] = None) -> bool:
1173
+ def _needs_sqlglot_normalization(self, param_info: "list[ParameterInfo]", dialect: str | None = None) -> bool:
1143
1174
  """Check if SQLGlot normalization is needed for this SQL."""
1144
1175
  incompatible_styles = self._validator.get_sqlglot_incompatible_styles(dialect)
1145
1176
  return any(p.style in incompatible_styles for p in param_info)
@@ -1252,7 +1283,7 @@ def is_iterable_parameters(obj: Any) -> bool:
1252
1283
  )
1253
1284
 
1254
1285
 
1255
- def wrap_with_type(value: Any, semantic_name: Optional[str] = None) -> Any:
1286
+ def wrap_with_type(value: Any, semantic_name: str | None = None) -> Any:
1256
1287
  """Public API for type wrapping.
1257
1288
 
1258
1289
  Args: