sqlspec 0.16.1__cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.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 (148) hide show
  1. 51ff5a9eadfdefd49f98__mypyc.cpython-310-aarch64-linux-gnu.so +0 -0
  2. sqlspec/__init__.py +92 -0
  3. sqlspec/__main__.py +12 -0
  4. sqlspec/__metadata__.py +14 -0
  5. sqlspec/_serialization.py +77 -0
  6. sqlspec/_sql.py +1780 -0
  7. sqlspec/_typing.py +680 -0
  8. sqlspec/adapters/__init__.py +0 -0
  9. sqlspec/adapters/adbc/__init__.py +5 -0
  10. sqlspec/adapters/adbc/_types.py +12 -0
  11. sqlspec/adapters/adbc/config.py +361 -0
  12. sqlspec/adapters/adbc/driver.py +512 -0
  13. sqlspec/adapters/aiosqlite/__init__.py +19 -0
  14. sqlspec/adapters/aiosqlite/_types.py +13 -0
  15. sqlspec/adapters/aiosqlite/config.py +253 -0
  16. sqlspec/adapters/aiosqlite/driver.py +248 -0
  17. sqlspec/adapters/asyncmy/__init__.py +19 -0
  18. sqlspec/adapters/asyncmy/_types.py +12 -0
  19. sqlspec/adapters/asyncmy/config.py +180 -0
  20. sqlspec/adapters/asyncmy/driver.py +274 -0
  21. sqlspec/adapters/asyncpg/__init__.py +21 -0
  22. sqlspec/adapters/asyncpg/_types.py +17 -0
  23. sqlspec/adapters/asyncpg/config.py +229 -0
  24. sqlspec/adapters/asyncpg/driver.py +344 -0
  25. sqlspec/adapters/bigquery/__init__.py +18 -0
  26. sqlspec/adapters/bigquery/_types.py +12 -0
  27. sqlspec/adapters/bigquery/config.py +298 -0
  28. sqlspec/adapters/bigquery/driver.py +558 -0
  29. sqlspec/adapters/duckdb/__init__.py +22 -0
  30. sqlspec/adapters/duckdb/_types.py +12 -0
  31. sqlspec/adapters/duckdb/config.py +504 -0
  32. sqlspec/adapters/duckdb/driver.py +368 -0
  33. sqlspec/adapters/oracledb/__init__.py +32 -0
  34. sqlspec/adapters/oracledb/_types.py +14 -0
  35. sqlspec/adapters/oracledb/config.py +317 -0
  36. sqlspec/adapters/oracledb/driver.py +538 -0
  37. sqlspec/adapters/psqlpy/__init__.py +16 -0
  38. sqlspec/adapters/psqlpy/_types.py +11 -0
  39. sqlspec/adapters/psqlpy/config.py +214 -0
  40. sqlspec/adapters/psqlpy/driver.py +530 -0
  41. sqlspec/adapters/psycopg/__init__.py +32 -0
  42. sqlspec/adapters/psycopg/_types.py +17 -0
  43. sqlspec/adapters/psycopg/config.py +426 -0
  44. sqlspec/adapters/psycopg/driver.py +796 -0
  45. sqlspec/adapters/sqlite/__init__.py +15 -0
  46. sqlspec/adapters/sqlite/_types.py +11 -0
  47. sqlspec/adapters/sqlite/config.py +240 -0
  48. sqlspec/adapters/sqlite/driver.py +294 -0
  49. sqlspec/base.py +571 -0
  50. sqlspec/builder/__init__.py +62 -0
  51. sqlspec/builder/_base.py +473 -0
  52. sqlspec/builder/_column.py +320 -0
  53. sqlspec/builder/_ddl.py +1346 -0
  54. sqlspec/builder/_ddl_utils.py +103 -0
  55. sqlspec/builder/_delete.py +76 -0
  56. sqlspec/builder/_insert.py +256 -0
  57. sqlspec/builder/_merge.py +71 -0
  58. sqlspec/builder/_parsing_utils.py +140 -0
  59. sqlspec/builder/_select.py +170 -0
  60. sqlspec/builder/_update.py +188 -0
  61. sqlspec/builder/mixins/__init__.py +55 -0
  62. sqlspec/builder/mixins/_cte_and_set_ops.py +222 -0
  63. sqlspec/builder/mixins/_delete_operations.py +41 -0
  64. sqlspec/builder/mixins/_insert_operations.py +244 -0
  65. sqlspec/builder/mixins/_join_operations.py +122 -0
  66. sqlspec/builder/mixins/_merge_operations.py +476 -0
  67. sqlspec/builder/mixins/_order_limit_operations.py +135 -0
  68. sqlspec/builder/mixins/_pivot_operations.py +153 -0
  69. sqlspec/builder/mixins/_select_operations.py +603 -0
  70. sqlspec/builder/mixins/_update_operations.py +187 -0
  71. sqlspec/builder/mixins/_where_clause.py +621 -0
  72. sqlspec/cli.py +247 -0
  73. sqlspec/config.py +395 -0
  74. sqlspec/core/__init__.py +63 -0
  75. sqlspec/core/cache.cpython-310-aarch64-linux-gnu.so +0 -0
  76. sqlspec/core/cache.py +871 -0
  77. sqlspec/core/compiler.cpython-310-aarch64-linux-gnu.so +0 -0
  78. sqlspec/core/compiler.py +417 -0
  79. sqlspec/core/filters.cpython-310-aarch64-linux-gnu.so +0 -0
  80. sqlspec/core/filters.py +830 -0
  81. sqlspec/core/hashing.cpython-310-aarch64-linux-gnu.so +0 -0
  82. sqlspec/core/hashing.py +310 -0
  83. sqlspec/core/parameters.cpython-310-aarch64-linux-gnu.so +0 -0
  84. sqlspec/core/parameters.py +1237 -0
  85. sqlspec/core/result.cpython-310-aarch64-linux-gnu.so +0 -0
  86. sqlspec/core/result.py +677 -0
  87. sqlspec/core/splitter.cpython-310-aarch64-linux-gnu.so +0 -0
  88. sqlspec/core/splitter.py +819 -0
  89. sqlspec/core/statement.cpython-310-aarch64-linux-gnu.so +0 -0
  90. sqlspec/core/statement.py +676 -0
  91. sqlspec/driver/__init__.py +19 -0
  92. sqlspec/driver/_async.py +502 -0
  93. sqlspec/driver/_common.py +631 -0
  94. sqlspec/driver/_sync.py +503 -0
  95. sqlspec/driver/mixins/__init__.py +6 -0
  96. sqlspec/driver/mixins/_result_tools.py +193 -0
  97. sqlspec/driver/mixins/_sql_translator.py +86 -0
  98. sqlspec/exceptions.py +193 -0
  99. sqlspec/extensions/__init__.py +0 -0
  100. sqlspec/extensions/aiosql/__init__.py +10 -0
  101. sqlspec/extensions/aiosql/adapter.py +461 -0
  102. sqlspec/extensions/litestar/__init__.py +6 -0
  103. sqlspec/extensions/litestar/_utils.py +52 -0
  104. sqlspec/extensions/litestar/cli.py +48 -0
  105. sqlspec/extensions/litestar/config.py +92 -0
  106. sqlspec/extensions/litestar/handlers.py +260 -0
  107. sqlspec/extensions/litestar/plugin.py +145 -0
  108. sqlspec/extensions/litestar/providers.py +454 -0
  109. sqlspec/loader.cpython-310-aarch64-linux-gnu.so +0 -0
  110. sqlspec/loader.py +760 -0
  111. sqlspec/migrations/__init__.py +35 -0
  112. sqlspec/migrations/base.py +414 -0
  113. sqlspec/migrations/commands.py +443 -0
  114. sqlspec/migrations/loaders.py +402 -0
  115. sqlspec/migrations/runner.py +213 -0
  116. sqlspec/migrations/tracker.py +140 -0
  117. sqlspec/migrations/utils.py +129 -0
  118. sqlspec/protocols.py +407 -0
  119. sqlspec/py.typed +0 -0
  120. sqlspec/storage/__init__.py +23 -0
  121. sqlspec/storage/backends/__init__.py +0 -0
  122. sqlspec/storage/backends/base.py +163 -0
  123. sqlspec/storage/backends/fsspec.py +386 -0
  124. sqlspec/storage/backends/obstore.py +459 -0
  125. sqlspec/storage/capabilities.py +102 -0
  126. sqlspec/storage/registry.py +239 -0
  127. sqlspec/typing.py +299 -0
  128. sqlspec/utils/__init__.py +3 -0
  129. sqlspec/utils/correlation.py +150 -0
  130. sqlspec/utils/deprecation.py +106 -0
  131. sqlspec/utils/fixtures.cpython-310-aarch64-linux-gnu.so +0 -0
  132. sqlspec/utils/fixtures.py +58 -0
  133. sqlspec/utils/logging.py +127 -0
  134. sqlspec/utils/module_loader.py +89 -0
  135. sqlspec/utils/serializers.py +4 -0
  136. sqlspec/utils/singleton.py +32 -0
  137. sqlspec/utils/sync_tools.cpython-310-aarch64-linux-gnu.so +0 -0
  138. sqlspec/utils/sync_tools.py +237 -0
  139. sqlspec/utils/text.cpython-310-aarch64-linux-gnu.so +0 -0
  140. sqlspec/utils/text.py +96 -0
  141. sqlspec/utils/type_guards.cpython-310-aarch64-linux-gnu.so +0 -0
  142. sqlspec/utils/type_guards.py +1139 -0
  143. sqlspec-0.16.1.dist-info/METADATA +365 -0
  144. sqlspec-0.16.1.dist-info/RECORD +148 -0
  145. sqlspec-0.16.1.dist-info/WHEEL +7 -0
  146. sqlspec-0.16.1.dist-info/entry_points.txt +2 -0
  147. sqlspec-0.16.1.dist-info/licenses/LICENSE +21 -0
  148. sqlspec-0.16.1.dist-info/licenses/NOTICE +29 -0
@@ -0,0 +1,417 @@
1
+ """SQL processor with integrated caching and compilation.
2
+
3
+ This module implements the core compilation system for SQL statements with
4
+ integrated parameter processing and caching.
5
+
6
+ Components:
7
+ - CompiledSQL: Immutable compilation result with complete information
8
+ - SQLProcessor: Single-pass compiler with integrated caching
9
+ - Integrated parameter processing via ParameterProcessor
10
+
11
+ Features:
12
+ - Single SQLGlot parse for efficient processing
13
+ - AST-based operation type detection
14
+ - Unified caching system with LRU eviction
15
+ - Complete StatementConfig support
16
+ """
17
+
18
+ import hashlib
19
+ from collections import OrderedDict
20
+ from typing import TYPE_CHECKING, Any, Optional
21
+
22
+ import sqlglot
23
+ from mypy_extensions import mypyc_attr
24
+ from sqlglot import expressions as exp
25
+ from sqlglot.errors import ParseError
26
+ from typing_extensions import Literal
27
+
28
+ from sqlspec.core.parameters import ParameterProcessor
29
+ from sqlspec.utils.logging import get_logger
30
+
31
+ if TYPE_CHECKING:
32
+ from sqlspec.core.statement import StatementConfig
33
+
34
+ # Define OperationType here to avoid circular import
35
+ OperationType = Literal[
36
+ "SELECT",
37
+ "INSERT",
38
+ "UPDATE",
39
+ "DELETE",
40
+ "COPY",
41
+ "COPY_FROM",
42
+ "COPY_TO",
43
+ "EXECUTE",
44
+ "SCRIPT",
45
+ "DDL",
46
+ "PRAGMA",
47
+ "UNKNOWN",
48
+ ]
49
+
50
+
51
+ __all__ = ("CompiledSQL", "OperationType", "SQLProcessor")
52
+
53
+ logger = get_logger("sqlspec.core.compiler")
54
+
55
+ _OPERATION_TYPES = {
56
+ "SELECT": "SELECT",
57
+ "INSERT": "INSERT",
58
+ "UPDATE": "UPDATE",
59
+ "DELETE": "DELETE",
60
+ "COPY": "COPY",
61
+ "COPY_FROM": "COPY_FROM",
62
+ "COPY_TO": "COPY_TO",
63
+ "EXECUTE": "EXECUTE",
64
+ "SCRIPT": "SCRIPT",
65
+ "DDL": "DDL",
66
+ "PRAGMA": "PRAGMA",
67
+ "UNKNOWN": "UNKNOWN",
68
+ }
69
+
70
+
71
+ @mypyc_attr(allow_interpreted_subclasses=True)
72
+ class CompiledSQL:
73
+ """Immutable compiled SQL result with complete information.
74
+
75
+ This class represents the result of SQL compilation, containing all
76
+ information needed for execution.
77
+
78
+ Features:
79
+ - Immutable design for safe sharing
80
+ - Cached hash for efficient dictionary operations
81
+ - Complete operation type detection
82
+ - Parameter style and execution information
83
+ - Support for execute_many operations
84
+ """
85
+
86
+ __slots__ = (
87
+ "_hash",
88
+ "compiled_sql",
89
+ "execution_parameters",
90
+ "expression",
91
+ "operation_type",
92
+ "parameter_style",
93
+ "supports_many",
94
+ )
95
+
96
+ def __init__(
97
+ self,
98
+ compiled_sql: str,
99
+ execution_parameters: Any,
100
+ operation_type: str,
101
+ expression: Optional["exp.Expression"] = None,
102
+ parameter_style: Optional[str] = None,
103
+ supports_many: bool = False,
104
+ ) -> None:
105
+ """Initialize immutable compiled result.
106
+
107
+ Args:
108
+ compiled_sql: Final SQL string ready for execution
109
+ execution_parameters: Parameters in driver-specific format
110
+ operation_type: Detected SQL operation type (SELECT, INSERT, etc.)
111
+ expression: SQLGlot AST expression
112
+ parameter_style: Parameter style used in compilation
113
+ supports_many: Whether this supports execute_many operations
114
+ """
115
+ self.compiled_sql = compiled_sql
116
+ self.execution_parameters = execution_parameters
117
+ self.operation_type = operation_type
118
+ self.expression = expression
119
+ self.parameter_style = parameter_style
120
+ self.supports_many = supports_many
121
+ self._hash: Optional[int] = None
122
+
123
+ def __hash__(self) -> int:
124
+ """Cached hash value with optimization."""
125
+ if self._hash is None:
126
+ # Optimize by avoiding str() conversion if possible
127
+ param_str = str(self.execution_parameters)
128
+ self._hash = hash((self.compiled_sql, param_str, self.operation_type, self.parameter_style))
129
+ return self._hash
130
+
131
+ def __eq__(self, other: object) -> bool:
132
+ """Equality comparison for compiled results."""
133
+ if not isinstance(other, CompiledSQL):
134
+ return False
135
+ return (
136
+ self.compiled_sql == other.compiled_sql
137
+ and self.execution_parameters == other.execution_parameters
138
+ and self.operation_type == other.operation_type
139
+ and self.parameter_style == other.parameter_style
140
+ )
141
+
142
+ def __repr__(self) -> str:
143
+ """String representation for debugging."""
144
+ return (
145
+ f"CompiledSQL(sql={self.compiled_sql!r}, "
146
+ f"params={self.execution_parameters!r}, "
147
+ f"type={self.operation_type!r})"
148
+ )
149
+
150
+
151
+ @mypyc_attr(allow_interpreted_subclasses=True)
152
+ class SQLProcessor:
153
+ """SQL processor with integrated caching and compilation.
154
+
155
+ This is the core compilation engine that processes SQL statements with
156
+ integrated parameter processing and caching.
157
+
158
+ Processing Flow:
159
+ 1. Parameter detection and normalization (if needed)
160
+ 2. Single SQLGlot parse
161
+ 3. AST-based operation type detection
162
+ 4. Parameter conversion (if needed)
163
+ 5. Final SQL generation with execution parameters
164
+
165
+ Features:
166
+ - LRU cache with O(1) operations
167
+ - Integrated parameter processing
168
+ - Cached compilation results
169
+ - Complete StatementConfig support
170
+ """
171
+
172
+ __slots__ = ("_cache", "_cache_hits", "_cache_misses", "_config", "_max_cache_size", "_parameter_processor")
173
+
174
+ def __init__(self, config: "StatementConfig", max_cache_size: int = 1000) -> None:
175
+ """Initialize processor with configuration and caching.
176
+
177
+ Args:
178
+ config: Statement configuration with parameter processing settings
179
+ max_cache_size: Maximum number of cached compilation results
180
+ """
181
+ self._config = config
182
+ self._cache: OrderedDict[str, CompiledSQL] = OrderedDict()
183
+ self._parameter_processor = ParameterProcessor()
184
+ self._max_cache_size = max_cache_size
185
+ self._cache_hits = 0
186
+ self._cache_misses = 0
187
+
188
+ def compile(self, sql: str, parameters: Any = None, is_many: bool = False) -> CompiledSQL:
189
+ """Compile SQL statement with integrated caching.
190
+
191
+ Args:
192
+ sql: Raw SQL string for compilation
193
+ parameters: Parameter values in any format
194
+ is_many: Whether this is for execute_many operation
195
+
196
+ Returns:
197
+ CompiledSQL with all information for execution
198
+ """
199
+ if not self._config.enable_caching:
200
+ return self._compile_uncached(sql, parameters, is_many)
201
+
202
+ cache_key = self._make_cache_key(sql, parameters)
203
+
204
+ if cache_key in self._cache:
205
+ # Move to end for LRU behavior
206
+ result = self._cache[cache_key]
207
+ del self._cache[cache_key]
208
+ self._cache[cache_key] = result
209
+ self._cache_hits += 1
210
+ return result
211
+
212
+ self._cache_misses += 1
213
+ result = self._compile_uncached(sql, parameters, is_many)
214
+
215
+ if len(self._cache) >= self._max_cache_size:
216
+ self._cache.popitem(last=False)
217
+
218
+ self._cache[cache_key] = result
219
+ return result
220
+
221
+ def _compile_uncached(self, sql: str, parameters: Any, is_many: bool = False) -> CompiledSQL:
222
+ """Compile SQL without caching.
223
+
224
+ Args:
225
+ sql: Raw SQL string
226
+ parameters: Parameter values
227
+ is_many: Whether this is for execute_many operation
228
+
229
+ Returns:
230
+ CompiledSQL result
231
+ """
232
+ try:
233
+ # Cache dialect string to avoid repeated conversions
234
+ dialect_str = str(self._config.dialect) if self._config.dialect else None
235
+
236
+ # Process parameters in single call
237
+ processed_sql: str
238
+ processed_params: Any
239
+ processed_sql, processed_params = self._parameter_processor.process(
240
+ sql=sql,
241
+ parameters=parameters,
242
+ config=self._config.parameter_config,
243
+ dialect=dialect_str,
244
+ is_many=is_many,
245
+ )
246
+
247
+ # Optimize static compilation path
248
+ if self._config.parameter_config.needs_static_script_compilation and processed_params is None:
249
+ sqlglot_sql = processed_sql
250
+ else:
251
+ sqlglot_sql, _ = self._parameter_processor._get_sqlglot_compatible_sql(
252
+ sql, parameters, self._config.parameter_config, dialect_str
253
+ )
254
+
255
+ final_parameters = processed_params
256
+ ast_was_transformed = False
257
+ expression = None
258
+ operation_type = "EXECUTE"
259
+
260
+ if self._config.enable_parsing:
261
+ try:
262
+ # Use copy=False for performance optimization
263
+ expression = sqlglot.parse_one(sqlglot_sql, dialect=dialect_str)
264
+ operation_type = self._detect_operation_type(expression)
265
+
266
+ # Handle AST transformation if configured
267
+ ast_transformer = self._config.parameter_config.ast_transformer
268
+ if ast_transformer:
269
+ expression, final_parameters = ast_transformer(expression, processed_params)
270
+ ast_was_transformed = True
271
+
272
+ except ParseError:
273
+ expression = None
274
+ operation_type = "EXECUTE"
275
+
276
+ # Optimize final SQL generation path
277
+ if self._config.parameter_config.needs_static_script_compilation and processed_params is None:
278
+ final_sql, final_params = processed_sql, processed_params
279
+ elif ast_was_transformed and expression is not None:
280
+ final_sql = expression.sql(dialect=dialect_str)
281
+ final_params = final_parameters
282
+ logger.debug("AST was transformed - final SQL: %s, final params: %s", final_sql, final_params)
283
+
284
+ # Apply output transformer if configured
285
+ output_transformer = self._config.output_transformer
286
+ if output_transformer:
287
+ final_sql, final_params = output_transformer(final_sql, final_params)
288
+ else:
289
+ final_sql, final_params = self._apply_final_transformations(
290
+ expression, processed_sql, final_parameters, dialect_str
291
+ )
292
+
293
+ return CompiledSQL(
294
+ compiled_sql=final_sql,
295
+ execution_parameters=final_params,
296
+ operation_type=operation_type,
297
+ expression=expression,
298
+ parameter_style=self._config.parameter_config.default_parameter_style.value,
299
+ supports_many=isinstance(final_params, list) and len(final_params) > 0,
300
+ )
301
+
302
+ except Exception as e:
303
+ logger.warning("Compilation failed, using fallback: %s", e)
304
+ return CompiledSQL(
305
+ compiled_sql=sql, execution_parameters=parameters, operation_type=_OPERATION_TYPES["UNKNOWN"]
306
+ )
307
+
308
+ def _make_cache_key(self, sql: str, parameters: Any) -> str:
309
+ """Generate cache key for compilation result.
310
+
311
+ Args:
312
+ sql: SQL string
313
+ parameters: Parameter values
314
+
315
+ Returns:
316
+ Cache key string
317
+ """
318
+ # Optimize key generation by avoiding string conversion overhead
319
+ param_repr = repr(parameters)
320
+ dialect_str = str(self._config.dialect) if self._config.dialect else None
321
+ param_style = self._config.parameter_config.default_parameter_style.value
322
+
323
+ # Use direct tuple construction for better performance
324
+ hash_data = (
325
+ sql,
326
+ param_repr,
327
+ param_style,
328
+ dialect_str,
329
+ self._config.enable_parsing,
330
+ self._config.enable_transformations,
331
+ )
332
+
333
+ # Optimize hash computation
334
+ hash_str = hashlib.sha256(str(hash_data).encode("utf-8")).hexdigest()[:16]
335
+ return f"sql_{hash_str}"
336
+
337
+ def _detect_operation_type(self, expression: "exp.Expression") -> str:
338
+ """Detect operation type from AST.
339
+
340
+ Uses SQLGlot AST structure to determine operation type.
341
+
342
+ Args:
343
+ expression: SQLGlot AST expression
344
+
345
+ Returns:
346
+ Operation type string
347
+ """
348
+ # Use isinstance for compatibility with mocks and inheritance
349
+ if isinstance(expression, exp.Select):
350
+ return "SELECT"
351
+ if isinstance(expression, exp.Insert):
352
+ return "INSERT"
353
+ if isinstance(expression, exp.Update):
354
+ return "UPDATE"
355
+ if isinstance(expression, exp.Delete):
356
+ return "DELETE"
357
+ if isinstance(expression, exp.Pragma):
358
+ return "PRAGMA"
359
+ if isinstance(expression, exp.Command):
360
+ return "EXECUTE"
361
+ if isinstance(expression, exp.Copy):
362
+ copy_kind = expression.args.get("kind")
363
+ if copy_kind is True:
364
+ return "COPY_FROM"
365
+ if copy_kind is False:
366
+ return "COPY_TO"
367
+ return "COPY"
368
+ if isinstance(expression, (exp.Create, exp.Drop, exp.Alter)):
369
+ return "DDL"
370
+ return "UNKNOWN"
371
+
372
+ def _apply_final_transformations(
373
+ self, expression: "Optional[exp.Expression]", sql: str, parameters: Any, dialect_str: "Optional[str]"
374
+ ) -> "tuple[str, Any]":
375
+ """Apply final transformations.
376
+
377
+ Args:
378
+ expression: SQLGlot AST expression (if available)
379
+ sql: Compiled SQL string (fallback)
380
+ parameters: Execution parameters
381
+ dialect_str: SQL dialect for AST-to-SQL conversion
382
+
383
+ Returns:
384
+ Tuple of (final_sql, final_parameters)
385
+ """
386
+ output_transformer = self._config.output_transformer
387
+ if output_transformer:
388
+ if expression is not None:
389
+ ast_sql = expression.sql(dialect=dialect_str)
390
+ return output_transformer(ast_sql, parameters)
391
+ return output_transformer(sql, parameters)
392
+
393
+ return sql, parameters
394
+
395
+ def clear_cache(self) -> None:
396
+ """Clear compilation cache."""
397
+ self._cache.clear()
398
+ self._cache_hits = 0
399
+ self._cache_misses = 0
400
+
401
+ @property
402
+ def cache_stats(self) -> "dict[str, int]":
403
+ """Get cache statistics.
404
+
405
+ Returns:
406
+ Dictionary with cache hit/miss statistics
407
+ """
408
+ total_requests = self._cache_hits + self._cache_misses
409
+ hit_rate_pct = int((self._cache_hits / total_requests) * 100) if total_requests > 0 else 0
410
+
411
+ return {
412
+ "hits": self._cache_hits,
413
+ "misses": self._cache_misses,
414
+ "size": len(self._cache),
415
+ "max_size": self._max_cache_size,
416
+ "hit_rate_percent": hit_rate_pct,
417
+ }