sqlspec 0.16.1__cp312-cp312-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-312-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-312-aarch64-linux-gnu.so +0 -0
  76. sqlspec/core/cache.py +871 -0
  77. sqlspec/core/compiler.cpython-312-aarch64-linux-gnu.so +0 -0
  78. sqlspec/core/compiler.py +417 -0
  79. sqlspec/core/filters.cpython-312-aarch64-linux-gnu.so +0 -0
  80. sqlspec/core/filters.py +830 -0
  81. sqlspec/core/hashing.cpython-312-aarch64-linux-gnu.so +0 -0
  82. sqlspec/core/hashing.py +310 -0
  83. sqlspec/core/parameters.cpython-312-aarch64-linux-gnu.so +0 -0
  84. sqlspec/core/parameters.py +1237 -0
  85. sqlspec/core/result.cpython-312-aarch64-linux-gnu.so +0 -0
  86. sqlspec/core/result.py +677 -0
  87. sqlspec/core/splitter.cpython-312-aarch64-linux-gnu.so +0 -0
  88. sqlspec/core/splitter.py +819 -0
  89. sqlspec/core/statement.cpython-312-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-312-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-312-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-312-aarch64-linux-gnu.so +0 -0
  138. sqlspec/utils/sync_tools.py +237 -0
  139. sqlspec/utils/text.cpython-312-aarch64-linux-gnu.so +0 -0
  140. sqlspec/utils/text.py +96 -0
  141. sqlspec/utils/type_guards.cpython-312-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,310 @@
1
+ """Statement hashing utilities for cache key generation.
2
+
3
+ This module provides centralized hashing logic for SQL statements,
4
+ including expressions, parameters, filters, and complete SQL objects.
5
+
6
+ Also supports fine-grained AST sub-expression caching.
7
+ """
8
+
9
+ from typing import TYPE_CHECKING, Any, Optional
10
+
11
+ from sqlglot import exp
12
+
13
+ from sqlspec.utils.type_guards import is_typed_parameter
14
+
15
+ if TYPE_CHECKING:
16
+ from sqlspec.core.filters import StatementFilter
17
+ from sqlspec.core.statement import SQL
18
+
19
+ __all__ = (
20
+ "hash_expression",
21
+ "hash_expression_node",
22
+ "hash_optimized_expression",
23
+ "hash_parameters",
24
+ "hash_sql_statement",
25
+ )
26
+
27
+
28
+ def hash_expression(expr: Optional[exp.Expression], _seen: Optional[set[int]] = None) -> int:
29
+ """Generate deterministic hash from AST structure.
30
+
31
+ Args:
32
+ expr: SQLGlot Expression to hash
33
+ _seen: Set of seen object IDs to handle circular references
34
+
35
+ Returns:
36
+ Deterministic hash of the AST structure
37
+ """
38
+ if expr is None:
39
+ return hash(None)
40
+
41
+ if _seen is None:
42
+ _seen = set()
43
+
44
+ expr_id = id(expr)
45
+ if expr_id in _seen:
46
+ return hash(expr_id)
47
+
48
+ _seen.add(expr_id)
49
+
50
+ # Build hash from type and args
51
+ components: list[Any] = [type(expr).__name__]
52
+
53
+ for key, value in sorted(expr.args.items()):
54
+ components.extend((key, _hash_value(value, _seen)))
55
+
56
+ return hash(tuple(components))
57
+
58
+
59
+ def _hash_value(value: Any, _seen: set[int]) -> int:
60
+ """Hash different value types consistently.
61
+
62
+ Args:
63
+ value: Value to hash (can be Expression, list, dict, or primitive)
64
+ _seen: Set of seen object IDs to handle circular references
65
+
66
+ Returns:
67
+ Deterministic hash of the value
68
+ """
69
+ if isinstance(value, exp.Expression):
70
+ return hash_expression(value, _seen)
71
+ if isinstance(value, list):
72
+ return hash(tuple(_hash_value(v, _seen) for v in value))
73
+ if isinstance(value, dict):
74
+ items = sorted((k, _hash_value(v, _seen)) for k, v in value.items())
75
+ return hash(tuple(items))
76
+ if isinstance(value, tuple):
77
+ return hash(tuple(_hash_value(v, _seen) for v in value))
78
+ # Primitives: str, int, bool, None, etc.
79
+ return hash(value)
80
+
81
+
82
+ def hash_parameters(
83
+ positional_parameters: Optional[list[Any]] = None,
84
+ named_parameters: Optional[dict[str, Any]] = None,
85
+ original_parameters: Optional[Any] = None,
86
+ ) -> int:
87
+ """Generate hash for SQL parameters.
88
+
89
+ Args:
90
+ positional_parameters: List of positional parameters
91
+ named_parameters: Dictionary of named parameters
92
+ original_parameters: Original parameters (for execute_many)
93
+
94
+ Returns:
95
+ Combined hash of all parameters
96
+ """
97
+ param_hash = 0
98
+
99
+ # Hash positional parameters
100
+ if positional_parameters:
101
+ from sqlspec.core.parameters import TypedParameter
102
+
103
+ hashable_parameters: list[tuple[Any, Any]] = []
104
+ for param in positional_parameters:
105
+ if isinstance(param, TypedParameter):
106
+ if isinstance(param.value, (list, dict)):
107
+ hashable_parameters.append((repr(param.value), param.original_type))
108
+ else:
109
+ hashable_parameters.append((param.value, param.original_type))
110
+ elif isinstance(param, (list, dict)):
111
+ # Convert unhashable types to hashable representations
112
+ hashable_parameters.append((repr(param), "unhashable"))
113
+ else:
114
+ # Check if param itself contains unhashable types
115
+ try:
116
+ hash(param)
117
+ hashable_parameters.append((param, "primitive"))
118
+ except TypeError:
119
+ # If unhashable, convert to string representation
120
+ hashable_parameters.append((repr(param), "unhashable_repr"))
121
+
122
+ param_hash ^= hash(tuple(hashable_parameters))
123
+
124
+ if named_parameters:
125
+ # Handle unhashable types in named parameters
126
+ hashable_items = []
127
+ for key, value in sorted(named_parameters.items()):
128
+ if is_typed_parameter(value):
129
+ # For TypedParameter, hash its value with type info
130
+ if isinstance(value.value, (list, dict)):
131
+ hashable_items.append((key, (repr(value.value), value.original_type)))
132
+ else:
133
+ hashable_items.append((key, (value.value, value.original_type)))
134
+ elif isinstance(value, (list, dict)):
135
+ hashable_items.append((key, (repr(value), "unhashable")))
136
+ else:
137
+ hashable_items.append((key, (value, "primitive")))
138
+ param_hash ^= hash(tuple(hashable_items))
139
+
140
+ # Hash original parameters (important for execute_many)
141
+ if original_parameters is not None:
142
+ if isinstance(original_parameters, list):
143
+ # For execute_many, hash the count and first few items to avoid
144
+ param_hash ^= hash(("original_count", len(original_parameters)))
145
+ if original_parameters:
146
+ # Hash first 3 items as representatives
147
+ sample_size = min(3, len(original_parameters))
148
+ sample_hash = hash(repr(original_parameters[:sample_size]))
149
+ param_hash ^= hash(("original_sample", sample_hash))
150
+ else:
151
+ param_hash ^= hash(("original", repr(original_parameters)))
152
+
153
+ return param_hash
154
+
155
+
156
+ def _hash_filter_value(value: Any) -> int:
157
+ try:
158
+ return hash(value)
159
+ except TypeError:
160
+ return hash(repr(value))
161
+
162
+
163
+ def hash_filters(filters: Optional[list["StatementFilter"]] = None) -> int:
164
+ """Generate hash for statement filters.
165
+
166
+ Args:
167
+ filters: List of statement filters
168
+
169
+ Returns:
170
+ Hash of the filters
171
+ """
172
+ if not filters:
173
+ return 0
174
+
175
+ # Use class names and any hashable attributes
176
+ filter_components = []
177
+ for f in filters:
178
+ # Use class name as primary identifier
179
+ components: list[Any] = [f.__class__.__name__]
180
+
181
+ # Add any hashable attributes if available
182
+ # Use getattr with default instead of hasattr for mypyc compatibility
183
+ filter_dict = getattr(f, "__dict__", None)
184
+ if filter_dict is not None:
185
+ for key, value in sorted(filter_dict.items()):
186
+ components.append((key, _hash_filter_value(value)))
187
+
188
+ filter_components.append(tuple(components))
189
+
190
+ return hash(tuple(filter_components))
191
+
192
+
193
+ def hash_sql_statement(statement: "SQL") -> str:
194
+ """Generate a complete cache key for a SQL statement.
195
+
196
+ This centralizes all the complex hashing logic that was previously
197
+ scattered across different parts of the codebase.
198
+
199
+ Args:
200
+ statement: SQL statement object
201
+
202
+ Returns:
203
+ Cache key string
204
+ """
205
+ from sqlspec.utils.type_guards import is_expression
206
+
207
+ # Hash the expression or raw SQL
208
+ if is_expression(statement._statement):
209
+ expr_hash = hash_expression(statement._statement)
210
+ else:
211
+ expr_hash = hash(statement._raw_sql)
212
+
213
+ # Hash all parameters
214
+ param_hash = hash_parameters(
215
+ positional_parameters=statement._positional_parameters,
216
+ named_parameters=statement._named_parameters,
217
+ original_parameters=statement._original_parameters,
218
+ )
219
+
220
+ # Hash filters
221
+ filter_hash = hash_filters(statement._filters)
222
+
223
+ # Combine with other state
224
+ state_components = [
225
+ expr_hash,
226
+ param_hash,
227
+ filter_hash,
228
+ hash(statement._dialect),
229
+ hash(statement._is_many),
230
+ hash(statement._is_script),
231
+ ]
232
+
233
+ return f"sql:{hash(tuple(state_components))}"
234
+
235
+
236
+ def hash_expression_node(node: exp.Expression, include_children: bool = True, dialect: Optional[str] = None) -> str:
237
+ """Generate a cache key for an individual expression node.
238
+
239
+ This is used for sub-expression caching where we want to cache
240
+ frequently used SQL fragments like complex JOIN clauses or WHERE conditions.
241
+
242
+ Args:
243
+ node: The expression node to hash
244
+ include_children: Whether to include child nodes in the hash
245
+ dialect: SQL dialect for context-aware hashing
246
+
247
+ Returns:
248
+ Cache key string for the expression node
249
+ """
250
+ if include_children:
251
+ # Full structural hash including all children
252
+ node_hash = hash_expression(node)
253
+ else:
254
+ # Shallow hash - just the node type and immediate args
255
+ components: list[Any] = [type(node).__name__]
256
+ for key, value in sorted(node.args.items()):
257
+ if not isinstance(value, (list, exp.Expression)):
258
+ # Only include primitive values, not child expressions
259
+ components.extend((key, hash(value)))
260
+ node_hash = hash(tuple(components))
261
+
262
+ dialect_part = f":{dialect}" if dialect else ""
263
+ return f"expr{dialect_part}:{node_hash}"
264
+
265
+
266
+ def hash_optimized_expression(
267
+ expr: exp.Expression,
268
+ dialect: str,
269
+ schema: Optional[dict[str, Any]] = None,
270
+ optimizer_settings: Optional[dict[str, Any]] = None,
271
+ ) -> str:
272
+ """Generate a cache key for optimized expressions.
273
+
274
+ This creates a unique key that captures the expression structure,
275
+ dialect, schema context, and optimizer settings to ensure we only
276
+ reuse optimized expressions when all context matches.
277
+
278
+ Args:
279
+ expr: The unoptimized expression
280
+ dialect: Target SQL dialect
281
+ schema: Schema information
282
+ optimizer_settings: Additional optimizer configuration
283
+
284
+ Returns:
285
+ Cache key string for the optimized expression
286
+ """
287
+ # Base expression hash
288
+ expr_hash = hash_expression(expr)
289
+
290
+ # Schema hash - simplified representation
291
+ schema_hash = 0
292
+ if schema:
293
+ # Hash table names and column counts to avoid deep schema hashing
294
+ schema_items = []
295
+ for table_name, table_schema in sorted(schema.items()):
296
+ if isinstance(table_schema, dict):
297
+ schema_items.append((table_name, len(table_schema)))
298
+ else:
299
+ schema_items.append((table_name, hash("unknown")))
300
+ schema_hash = hash(tuple(schema_items))
301
+
302
+ # Optimizer settings hash
303
+ settings_hash = 0
304
+ if optimizer_settings:
305
+ settings_items = sorted(optimizer_settings.items())
306
+ settings_hash = hash(tuple(settings_items))
307
+
308
+ # Combine all components
309
+ components = (expr_hash, dialect, schema_hash, settings_hash)
310
+ return f"opt:{hash(components)}"