sqlspec 0.36.0__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.
Files changed (531) hide show
  1. ac8f31065839703b4e70__mypyc.cpython-310-aarch64-linux-gnu.so +0 -0
  2. sqlspec/__init__.py +140 -0
  3. sqlspec/__main__.py +12 -0
  4. sqlspec/__metadata__.py +14 -0
  5. sqlspec/_serialization.py +315 -0
  6. sqlspec/_typing.py +700 -0
  7. sqlspec/adapters/__init__.py +0 -0
  8. sqlspec/adapters/adbc/__init__.py +5 -0
  9. sqlspec/adapters/adbc/_typing.py +82 -0
  10. sqlspec/adapters/adbc/adk/__init__.py +5 -0
  11. sqlspec/adapters/adbc/adk/store.py +1273 -0
  12. sqlspec/adapters/adbc/config.py +295 -0
  13. sqlspec/adapters/adbc/core.cpython-310-aarch64-linux-gnu.so +0 -0
  14. sqlspec/adapters/adbc/core.py +735 -0
  15. sqlspec/adapters/adbc/data_dictionary.py +334 -0
  16. sqlspec/adapters/adbc/driver.py +529 -0
  17. sqlspec/adapters/adbc/events/__init__.py +5 -0
  18. sqlspec/adapters/adbc/events/store.py +285 -0
  19. sqlspec/adapters/adbc/litestar/__init__.py +5 -0
  20. sqlspec/adapters/adbc/litestar/store.py +502 -0
  21. sqlspec/adapters/adbc/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  22. sqlspec/adapters/adbc/type_converter.py +140 -0
  23. sqlspec/adapters/aiosqlite/__init__.py +25 -0
  24. sqlspec/adapters/aiosqlite/_typing.py +82 -0
  25. sqlspec/adapters/aiosqlite/adk/__init__.py +5 -0
  26. sqlspec/adapters/aiosqlite/adk/store.py +818 -0
  27. sqlspec/adapters/aiosqlite/config.py +334 -0
  28. sqlspec/adapters/aiosqlite/core.cpython-310-aarch64-linux-gnu.so +0 -0
  29. sqlspec/adapters/aiosqlite/core.py +315 -0
  30. sqlspec/adapters/aiosqlite/data_dictionary.py +208 -0
  31. sqlspec/adapters/aiosqlite/driver.py +313 -0
  32. sqlspec/adapters/aiosqlite/events/__init__.py +5 -0
  33. sqlspec/adapters/aiosqlite/events/store.py +20 -0
  34. sqlspec/adapters/aiosqlite/litestar/__init__.py +5 -0
  35. sqlspec/adapters/aiosqlite/litestar/store.py +279 -0
  36. sqlspec/adapters/aiosqlite/pool.py +533 -0
  37. sqlspec/adapters/asyncmy/__init__.py +21 -0
  38. sqlspec/adapters/asyncmy/_typing.py +87 -0
  39. sqlspec/adapters/asyncmy/adk/__init__.py +5 -0
  40. sqlspec/adapters/asyncmy/adk/store.py +703 -0
  41. sqlspec/adapters/asyncmy/config.py +302 -0
  42. sqlspec/adapters/asyncmy/core.cpython-310-aarch64-linux-gnu.so +0 -0
  43. sqlspec/adapters/asyncmy/core.py +360 -0
  44. sqlspec/adapters/asyncmy/data_dictionary.py +124 -0
  45. sqlspec/adapters/asyncmy/driver.py +383 -0
  46. sqlspec/adapters/asyncmy/events/__init__.py +5 -0
  47. sqlspec/adapters/asyncmy/events/store.py +104 -0
  48. sqlspec/adapters/asyncmy/litestar/__init__.py +5 -0
  49. sqlspec/adapters/asyncmy/litestar/store.py +296 -0
  50. sqlspec/adapters/asyncpg/__init__.py +19 -0
  51. sqlspec/adapters/asyncpg/_typing.py +88 -0
  52. sqlspec/adapters/asyncpg/adk/__init__.py +5 -0
  53. sqlspec/adapters/asyncpg/adk/store.py +748 -0
  54. sqlspec/adapters/asyncpg/config.py +569 -0
  55. sqlspec/adapters/asyncpg/core.cpython-310-aarch64-linux-gnu.so +0 -0
  56. sqlspec/adapters/asyncpg/core.py +367 -0
  57. sqlspec/adapters/asyncpg/data_dictionary.py +162 -0
  58. sqlspec/adapters/asyncpg/driver.py +487 -0
  59. sqlspec/adapters/asyncpg/events/__init__.py +6 -0
  60. sqlspec/adapters/asyncpg/events/backend.py +286 -0
  61. sqlspec/adapters/asyncpg/events/store.py +40 -0
  62. sqlspec/adapters/asyncpg/litestar/__init__.py +5 -0
  63. sqlspec/adapters/asyncpg/litestar/store.py +251 -0
  64. sqlspec/adapters/bigquery/__init__.py +14 -0
  65. sqlspec/adapters/bigquery/_typing.py +86 -0
  66. sqlspec/adapters/bigquery/adk/__init__.py +5 -0
  67. sqlspec/adapters/bigquery/adk/store.py +827 -0
  68. sqlspec/adapters/bigquery/config.py +353 -0
  69. sqlspec/adapters/bigquery/core.cpython-310-aarch64-linux-gnu.so +0 -0
  70. sqlspec/adapters/bigquery/core.py +715 -0
  71. sqlspec/adapters/bigquery/data_dictionary.py +128 -0
  72. sqlspec/adapters/bigquery/driver.py +548 -0
  73. sqlspec/adapters/bigquery/events/__init__.py +5 -0
  74. sqlspec/adapters/bigquery/events/store.py +139 -0
  75. sqlspec/adapters/bigquery/litestar/__init__.py +5 -0
  76. sqlspec/adapters/bigquery/litestar/store.py +325 -0
  77. sqlspec/adapters/bigquery/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  78. sqlspec/adapters/bigquery/type_converter.py +107 -0
  79. sqlspec/adapters/cockroach_asyncpg/__init__.py +24 -0
  80. sqlspec/adapters/cockroach_asyncpg/_typing.py +72 -0
  81. sqlspec/adapters/cockroach_asyncpg/adk/__init__.py +3 -0
  82. sqlspec/adapters/cockroach_asyncpg/adk/store.py +410 -0
  83. sqlspec/adapters/cockroach_asyncpg/config.py +238 -0
  84. sqlspec/adapters/cockroach_asyncpg/core.cpython-310-aarch64-linux-gnu.so +0 -0
  85. sqlspec/adapters/cockroach_asyncpg/core.py +55 -0
  86. sqlspec/adapters/cockroach_asyncpg/data_dictionary.py +107 -0
  87. sqlspec/adapters/cockroach_asyncpg/driver.py +144 -0
  88. sqlspec/adapters/cockroach_asyncpg/events/__init__.py +3 -0
  89. sqlspec/adapters/cockroach_asyncpg/events/store.py +20 -0
  90. sqlspec/adapters/cockroach_asyncpg/litestar/__init__.py +3 -0
  91. sqlspec/adapters/cockroach_asyncpg/litestar/store.py +142 -0
  92. sqlspec/adapters/cockroach_psycopg/__init__.py +38 -0
  93. sqlspec/adapters/cockroach_psycopg/_typing.py +129 -0
  94. sqlspec/adapters/cockroach_psycopg/adk/__init__.py +13 -0
  95. sqlspec/adapters/cockroach_psycopg/adk/store.py +868 -0
  96. sqlspec/adapters/cockroach_psycopg/config.py +484 -0
  97. sqlspec/adapters/cockroach_psycopg/core.cpython-310-aarch64-linux-gnu.so +0 -0
  98. sqlspec/adapters/cockroach_psycopg/core.py +63 -0
  99. sqlspec/adapters/cockroach_psycopg/data_dictionary.py +215 -0
  100. sqlspec/adapters/cockroach_psycopg/driver.py +284 -0
  101. sqlspec/adapters/cockroach_psycopg/events/__init__.py +6 -0
  102. sqlspec/adapters/cockroach_psycopg/events/store.py +34 -0
  103. sqlspec/adapters/cockroach_psycopg/litestar/__init__.py +3 -0
  104. sqlspec/adapters/cockroach_psycopg/litestar/store.py +325 -0
  105. sqlspec/adapters/duckdb/__init__.py +25 -0
  106. sqlspec/adapters/duckdb/_typing.py +81 -0
  107. sqlspec/adapters/duckdb/adk/__init__.py +14 -0
  108. sqlspec/adapters/duckdb/adk/store.py +850 -0
  109. sqlspec/adapters/duckdb/config.py +463 -0
  110. sqlspec/adapters/duckdb/core.cpython-310-aarch64-linux-gnu.so +0 -0
  111. sqlspec/adapters/duckdb/core.py +257 -0
  112. sqlspec/adapters/duckdb/data_dictionary.py +140 -0
  113. sqlspec/adapters/duckdb/driver.py +430 -0
  114. sqlspec/adapters/duckdb/events/__init__.py +5 -0
  115. sqlspec/adapters/duckdb/events/store.py +57 -0
  116. sqlspec/adapters/duckdb/litestar/__init__.py +5 -0
  117. sqlspec/adapters/duckdb/litestar/store.py +330 -0
  118. sqlspec/adapters/duckdb/pool.py +293 -0
  119. sqlspec/adapters/duckdb/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  120. sqlspec/adapters/duckdb/type_converter.py +118 -0
  121. sqlspec/adapters/mock/__init__.py +72 -0
  122. sqlspec/adapters/mock/_typing.py +147 -0
  123. sqlspec/adapters/mock/config.py +483 -0
  124. sqlspec/adapters/mock/core.py +319 -0
  125. sqlspec/adapters/mock/data_dictionary.py +366 -0
  126. sqlspec/adapters/mock/driver.py +721 -0
  127. sqlspec/adapters/mysqlconnector/__init__.py +36 -0
  128. sqlspec/adapters/mysqlconnector/_typing.py +141 -0
  129. sqlspec/adapters/mysqlconnector/adk/__init__.py +15 -0
  130. sqlspec/adapters/mysqlconnector/adk/store.py +1060 -0
  131. sqlspec/adapters/mysqlconnector/config.py +394 -0
  132. sqlspec/adapters/mysqlconnector/core.cpython-310-aarch64-linux-gnu.so +0 -0
  133. sqlspec/adapters/mysqlconnector/core.py +303 -0
  134. sqlspec/adapters/mysqlconnector/data_dictionary.py +235 -0
  135. sqlspec/adapters/mysqlconnector/driver.py +483 -0
  136. sqlspec/adapters/mysqlconnector/events/__init__.py +8 -0
  137. sqlspec/adapters/mysqlconnector/events/store.py +98 -0
  138. sqlspec/adapters/mysqlconnector/litestar/__init__.py +5 -0
  139. sqlspec/adapters/mysqlconnector/litestar/store.py +426 -0
  140. sqlspec/adapters/oracledb/__init__.py +60 -0
  141. sqlspec/adapters/oracledb/_numpy_handlers.py +141 -0
  142. sqlspec/adapters/oracledb/_typing.py +182 -0
  143. sqlspec/adapters/oracledb/_uuid_handlers.py +166 -0
  144. sqlspec/adapters/oracledb/adk/__init__.py +10 -0
  145. sqlspec/adapters/oracledb/adk/store.py +2369 -0
  146. sqlspec/adapters/oracledb/config.py +550 -0
  147. sqlspec/adapters/oracledb/core.cpython-310-aarch64-linux-gnu.so +0 -0
  148. sqlspec/adapters/oracledb/core.py +543 -0
  149. sqlspec/adapters/oracledb/data_dictionary.py +536 -0
  150. sqlspec/adapters/oracledb/driver.py +1229 -0
  151. sqlspec/adapters/oracledb/events/__init__.py +16 -0
  152. sqlspec/adapters/oracledb/events/backend.py +347 -0
  153. sqlspec/adapters/oracledb/events/store.py +420 -0
  154. sqlspec/adapters/oracledb/litestar/__init__.py +5 -0
  155. sqlspec/adapters/oracledb/litestar/store.py +781 -0
  156. sqlspec/adapters/oracledb/migrations.py +535 -0
  157. sqlspec/adapters/oracledb/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  158. sqlspec/adapters/oracledb/type_converter.py +211 -0
  159. sqlspec/adapters/psqlpy/__init__.py +17 -0
  160. sqlspec/adapters/psqlpy/_typing.py +79 -0
  161. sqlspec/adapters/psqlpy/adk/__init__.py +5 -0
  162. sqlspec/adapters/psqlpy/adk/store.py +766 -0
  163. sqlspec/adapters/psqlpy/config.py +304 -0
  164. sqlspec/adapters/psqlpy/core.cpython-310-aarch64-linux-gnu.so +0 -0
  165. sqlspec/adapters/psqlpy/core.py +480 -0
  166. sqlspec/adapters/psqlpy/data_dictionary.py +126 -0
  167. sqlspec/adapters/psqlpy/driver.py +438 -0
  168. sqlspec/adapters/psqlpy/events/__init__.py +6 -0
  169. sqlspec/adapters/psqlpy/events/backend.py +310 -0
  170. sqlspec/adapters/psqlpy/events/store.py +20 -0
  171. sqlspec/adapters/psqlpy/litestar/__init__.py +5 -0
  172. sqlspec/adapters/psqlpy/litestar/store.py +270 -0
  173. sqlspec/adapters/psqlpy/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  174. sqlspec/adapters/psqlpy/type_converter.py +113 -0
  175. sqlspec/adapters/psycopg/__init__.py +32 -0
  176. sqlspec/adapters/psycopg/_typing.py +164 -0
  177. sqlspec/adapters/psycopg/adk/__init__.py +10 -0
  178. sqlspec/adapters/psycopg/adk/store.py +1387 -0
  179. sqlspec/adapters/psycopg/config.py +576 -0
  180. sqlspec/adapters/psycopg/core.cpython-310-aarch64-linux-gnu.so +0 -0
  181. sqlspec/adapters/psycopg/core.py +450 -0
  182. sqlspec/adapters/psycopg/data_dictionary.py +289 -0
  183. sqlspec/adapters/psycopg/driver.py +975 -0
  184. sqlspec/adapters/psycopg/events/__init__.py +20 -0
  185. sqlspec/adapters/psycopg/events/backend.py +458 -0
  186. sqlspec/adapters/psycopg/events/store.py +42 -0
  187. sqlspec/adapters/psycopg/litestar/__init__.py +5 -0
  188. sqlspec/adapters/psycopg/litestar/store.py +552 -0
  189. sqlspec/adapters/psycopg/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  190. sqlspec/adapters/psycopg/type_converter.py +93 -0
  191. sqlspec/adapters/pymysql/__init__.py +21 -0
  192. sqlspec/adapters/pymysql/_typing.py +71 -0
  193. sqlspec/adapters/pymysql/adk/__init__.py +5 -0
  194. sqlspec/adapters/pymysql/adk/store.py +540 -0
  195. sqlspec/adapters/pymysql/config.py +195 -0
  196. sqlspec/adapters/pymysql/core.cpython-310-aarch64-linux-gnu.so +0 -0
  197. sqlspec/adapters/pymysql/core.py +299 -0
  198. sqlspec/adapters/pymysql/data_dictionary.py +122 -0
  199. sqlspec/adapters/pymysql/driver.py +259 -0
  200. sqlspec/adapters/pymysql/events/__init__.py +5 -0
  201. sqlspec/adapters/pymysql/events/store.py +50 -0
  202. sqlspec/adapters/pymysql/litestar/__init__.py +5 -0
  203. sqlspec/adapters/pymysql/litestar/store.py +232 -0
  204. sqlspec/adapters/pymysql/pool.py +137 -0
  205. sqlspec/adapters/spanner/__init__.py +40 -0
  206. sqlspec/adapters/spanner/_typing.py +86 -0
  207. sqlspec/adapters/spanner/adk/__init__.py +5 -0
  208. sqlspec/adapters/spanner/adk/store.py +732 -0
  209. sqlspec/adapters/spanner/config.py +352 -0
  210. sqlspec/adapters/spanner/core.cpython-310-aarch64-linux-gnu.so +0 -0
  211. sqlspec/adapters/spanner/core.py +188 -0
  212. sqlspec/adapters/spanner/data_dictionary.py +120 -0
  213. sqlspec/adapters/spanner/dialect/__init__.py +6 -0
  214. sqlspec/adapters/spanner/dialect/_spangres.py +57 -0
  215. sqlspec/adapters/spanner/dialect/_spanner.py +130 -0
  216. sqlspec/adapters/spanner/driver.py +373 -0
  217. sqlspec/adapters/spanner/events/__init__.py +5 -0
  218. sqlspec/adapters/spanner/events/store.py +187 -0
  219. sqlspec/adapters/spanner/litestar/__init__.py +5 -0
  220. sqlspec/adapters/spanner/litestar/store.py +291 -0
  221. sqlspec/adapters/spanner/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  222. sqlspec/adapters/spanner/type_converter.py +331 -0
  223. sqlspec/adapters/sqlite/__init__.py +19 -0
  224. sqlspec/adapters/sqlite/_typing.py +80 -0
  225. sqlspec/adapters/sqlite/adk/__init__.py +5 -0
  226. sqlspec/adapters/sqlite/adk/store.py +958 -0
  227. sqlspec/adapters/sqlite/config.py +280 -0
  228. sqlspec/adapters/sqlite/core.cpython-310-aarch64-linux-gnu.so +0 -0
  229. sqlspec/adapters/sqlite/core.py +312 -0
  230. sqlspec/adapters/sqlite/data_dictionary.py +202 -0
  231. sqlspec/adapters/sqlite/driver.py +359 -0
  232. sqlspec/adapters/sqlite/events/__init__.py +5 -0
  233. sqlspec/adapters/sqlite/events/store.py +20 -0
  234. sqlspec/adapters/sqlite/litestar/__init__.py +5 -0
  235. sqlspec/adapters/sqlite/litestar/store.py +316 -0
  236. sqlspec/adapters/sqlite/pool.py +198 -0
  237. sqlspec/adapters/sqlite/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  238. sqlspec/adapters/sqlite/type_converter.py +114 -0
  239. sqlspec/base.py +747 -0
  240. sqlspec/builder/__init__.py +179 -0
  241. sqlspec/builder/_base.cpython-310-aarch64-linux-gnu.so +0 -0
  242. sqlspec/builder/_base.py +1022 -0
  243. sqlspec/builder/_column.cpython-310-aarch64-linux-gnu.so +0 -0
  244. sqlspec/builder/_column.py +521 -0
  245. sqlspec/builder/_ddl.cpython-310-aarch64-linux-gnu.so +0 -0
  246. sqlspec/builder/_ddl.py +1642 -0
  247. sqlspec/builder/_delete.cpython-310-aarch64-linux-gnu.so +0 -0
  248. sqlspec/builder/_delete.py +95 -0
  249. sqlspec/builder/_dml.cpython-310-aarch64-linux-gnu.so +0 -0
  250. sqlspec/builder/_dml.py +365 -0
  251. sqlspec/builder/_explain.cpython-310-aarch64-linux-gnu.so +0 -0
  252. sqlspec/builder/_explain.py +579 -0
  253. sqlspec/builder/_expression_wrappers.cpython-310-aarch64-linux-gnu.so +0 -0
  254. sqlspec/builder/_expression_wrappers.py +46 -0
  255. sqlspec/builder/_factory.cpython-310-aarch64-linux-gnu.so +0 -0
  256. sqlspec/builder/_factory.py +1697 -0
  257. sqlspec/builder/_insert.cpython-310-aarch64-linux-gnu.so +0 -0
  258. sqlspec/builder/_insert.py +328 -0
  259. sqlspec/builder/_join.cpython-310-aarch64-linux-gnu.so +0 -0
  260. sqlspec/builder/_join.py +499 -0
  261. sqlspec/builder/_merge.cpython-310-aarch64-linux-gnu.so +0 -0
  262. sqlspec/builder/_merge.py +821 -0
  263. sqlspec/builder/_parsing_utils.cpython-310-aarch64-linux-gnu.so +0 -0
  264. sqlspec/builder/_parsing_utils.py +297 -0
  265. sqlspec/builder/_select.cpython-310-aarch64-linux-gnu.so +0 -0
  266. sqlspec/builder/_select.py +1660 -0
  267. sqlspec/builder/_temporal.cpython-310-aarch64-linux-gnu.so +0 -0
  268. sqlspec/builder/_temporal.py +139 -0
  269. sqlspec/builder/_update.cpython-310-aarch64-linux-gnu.so +0 -0
  270. sqlspec/builder/_update.py +173 -0
  271. sqlspec/builder/_vector_expressions.py +267 -0
  272. sqlspec/cli.py +911 -0
  273. sqlspec/config.py +1755 -0
  274. sqlspec/core/__init__.py +374 -0
  275. sqlspec/core/_correlation.cpython-310-aarch64-linux-gnu.so +0 -0
  276. sqlspec/core/_correlation.py +176 -0
  277. sqlspec/core/cache.cpython-310-aarch64-linux-gnu.so +0 -0
  278. sqlspec/core/cache.py +1069 -0
  279. sqlspec/core/compiler.cpython-310-aarch64-linux-gnu.so +0 -0
  280. sqlspec/core/compiler.py +954 -0
  281. sqlspec/core/explain.cpython-310-aarch64-linux-gnu.so +0 -0
  282. sqlspec/core/explain.py +275 -0
  283. sqlspec/core/filters.cpython-310-aarch64-linux-gnu.so +0 -0
  284. sqlspec/core/filters.py +952 -0
  285. sqlspec/core/hashing.cpython-310-aarch64-linux-gnu.so +0 -0
  286. sqlspec/core/hashing.py +262 -0
  287. sqlspec/core/metrics.cpython-310-aarch64-linux-gnu.so +0 -0
  288. sqlspec/core/metrics.py +83 -0
  289. sqlspec/core/parameters/__init__.py +71 -0
  290. sqlspec/core/parameters/_alignment.cpython-310-aarch64-linux-gnu.so +0 -0
  291. sqlspec/core/parameters/_alignment.py +270 -0
  292. sqlspec/core/parameters/_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  293. sqlspec/core/parameters/_converter.py +543 -0
  294. sqlspec/core/parameters/_processor.cpython-310-aarch64-linux-gnu.so +0 -0
  295. sqlspec/core/parameters/_processor.py +505 -0
  296. sqlspec/core/parameters/_registry.cpython-310-aarch64-linux-gnu.so +0 -0
  297. sqlspec/core/parameters/_registry.py +206 -0
  298. sqlspec/core/parameters/_transformers.cpython-310-aarch64-linux-gnu.so +0 -0
  299. sqlspec/core/parameters/_transformers.py +292 -0
  300. sqlspec/core/parameters/_types.cpython-310-aarch64-linux-gnu.so +0 -0
  301. sqlspec/core/parameters/_types.py +499 -0
  302. sqlspec/core/parameters/_validator.cpython-310-aarch64-linux-gnu.so +0 -0
  303. sqlspec/core/parameters/_validator.py +180 -0
  304. sqlspec/core/pipeline.cpython-310-aarch64-linux-gnu.so +0 -0
  305. sqlspec/core/pipeline.py +319 -0
  306. sqlspec/core/query_modifiers.cpython-310-aarch64-linux-gnu.so +0 -0
  307. sqlspec/core/query_modifiers.py +437 -0
  308. sqlspec/core/result/__init__.py +23 -0
  309. sqlspec/core/result/_base.cpython-310-aarch64-linux-gnu.so +0 -0
  310. sqlspec/core/result/_base.py +1121 -0
  311. sqlspec/core/result/_io.cpython-310-aarch64-linux-gnu.so +0 -0
  312. sqlspec/core/result/_io.py +28 -0
  313. sqlspec/core/splitter.cpython-310-aarch64-linux-gnu.so +0 -0
  314. sqlspec/core/splitter.py +966 -0
  315. sqlspec/core/stack.cpython-310-aarch64-linux-gnu.so +0 -0
  316. sqlspec/core/stack.py +163 -0
  317. sqlspec/core/statement.cpython-310-aarch64-linux-gnu.so +0 -0
  318. sqlspec/core/statement.py +1503 -0
  319. sqlspec/core/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  320. sqlspec/core/type_converter.py +339 -0
  321. sqlspec/data_dictionary/__init__.py +22 -0
  322. sqlspec/data_dictionary/_loader.py +123 -0
  323. sqlspec/data_dictionary/_registry.cpython-310-aarch64-linux-gnu.so +0 -0
  324. sqlspec/data_dictionary/_registry.py +74 -0
  325. sqlspec/data_dictionary/_types.cpython-310-aarch64-linux-gnu.so +0 -0
  326. sqlspec/data_dictionary/_types.py +121 -0
  327. sqlspec/data_dictionary/dialects/__init__.py +21 -0
  328. sqlspec/data_dictionary/dialects/bigquery.cpython-310-aarch64-linux-gnu.so +0 -0
  329. sqlspec/data_dictionary/dialects/bigquery.py +49 -0
  330. sqlspec/data_dictionary/dialects/cockroachdb.cpython-310-aarch64-linux-gnu.so +0 -0
  331. sqlspec/data_dictionary/dialects/cockroachdb.py +43 -0
  332. sqlspec/data_dictionary/dialects/duckdb.cpython-310-aarch64-linux-gnu.so +0 -0
  333. sqlspec/data_dictionary/dialects/duckdb.py +47 -0
  334. sqlspec/data_dictionary/dialects/mysql.cpython-310-aarch64-linux-gnu.so +0 -0
  335. sqlspec/data_dictionary/dialects/mysql.py +42 -0
  336. sqlspec/data_dictionary/dialects/oracle.cpython-310-aarch64-linux-gnu.so +0 -0
  337. sqlspec/data_dictionary/dialects/oracle.py +34 -0
  338. sqlspec/data_dictionary/dialects/postgres.cpython-310-aarch64-linux-gnu.so +0 -0
  339. sqlspec/data_dictionary/dialects/postgres.py +46 -0
  340. sqlspec/data_dictionary/dialects/spanner.cpython-310-aarch64-linux-gnu.so +0 -0
  341. sqlspec/data_dictionary/dialects/spanner.py +37 -0
  342. sqlspec/data_dictionary/dialects/sqlite.cpython-310-aarch64-linux-gnu.so +0 -0
  343. sqlspec/data_dictionary/dialects/sqlite.py +42 -0
  344. sqlspec/data_dictionary/sql/.gitkeep +0 -0
  345. sqlspec/data_dictionary/sql/bigquery/columns.sql +23 -0
  346. sqlspec/data_dictionary/sql/bigquery/foreign_keys.sql +34 -0
  347. sqlspec/data_dictionary/sql/bigquery/indexes.sql +19 -0
  348. sqlspec/data_dictionary/sql/bigquery/tables.sql +33 -0
  349. sqlspec/data_dictionary/sql/bigquery/version.sql +3 -0
  350. sqlspec/data_dictionary/sql/cockroachdb/columns.sql +34 -0
  351. sqlspec/data_dictionary/sql/cockroachdb/foreign_keys.sql +40 -0
  352. sqlspec/data_dictionary/sql/cockroachdb/indexes.sql +32 -0
  353. sqlspec/data_dictionary/sql/cockroachdb/tables.sql +44 -0
  354. sqlspec/data_dictionary/sql/cockroachdb/version.sql +3 -0
  355. sqlspec/data_dictionary/sql/duckdb/columns.sql +23 -0
  356. sqlspec/data_dictionary/sql/duckdb/foreign_keys.sql +36 -0
  357. sqlspec/data_dictionary/sql/duckdb/indexes.sql +19 -0
  358. sqlspec/data_dictionary/sql/duckdb/tables.sql +38 -0
  359. sqlspec/data_dictionary/sql/duckdb/version.sql +3 -0
  360. sqlspec/data_dictionary/sql/mysql/columns.sql +23 -0
  361. sqlspec/data_dictionary/sql/mysql/foreign_keys.sql +28 -0
  362. sqlspec/data_dictionary/sql/mysql/indexes.sql +26 -0
  363. sqlspec/data_dictionary/sql/mysql/tables.sql +33 -0
  364. sqlspec/data_dictionary/sql/mysql/version.sql +3 -0
  365. sqlspec/data_dictionary/sql/oracle/columns.sql +23 -0
  366. sqlspec/data_dictionary/sql/oracle/foreign_keys.sql +48 -0
  367. sqlspec/data_dictionary/sql/oracle/indexes.sql +44 -0
  368. sqlspec/data_dictionary/sql/oracle/tables.sql +25 -0
  369. sqlspec/data_dictionary/sql/oracle/version.sql +20 -0
  370. sqlspec/data_dictionary/sql/postgres/columns.sql +34 -0
  371. sqlspec/data_dictionary/sql/postgres/foreign_keys.sql +40 -0
  372. sqlspec/data_dictionary/sql/postgres/indexes.sql +56 -0
  373. sqlspec/data_dictionary/sql/postgres/tables.sql +44 -0
  374. sqlspec/data_dictionary/sql/postgres/version.sql +3 -0
  375. sqlspec/data_dictionary/sql/spanner/columns.sql +23 -0
  376. sqlspec/data_dictionary/sql/spanner/foreign_keys.sql +70 -0
  377. sqlspec/data_dictionary/sql/spanner/indexes.sql +30 -0
  378. sqlspec/data_dictionary/sql/spanner/tables.sql +9 -0
  379. sqlspec/data_dictionary/sql/spanner/version.sql +3 -0
  380. sqlspec/data_dictionary/sql/sqlite/columns.sql +23 -0
  381. sqlspec/data_dictionary/sql/sqlite/foreign_keys.sql +22 -0
  382. sqlspec/data_dictionary/sql/sqlite/indexes.sql +7 -0
  383. sqlspec/data_dictionary/sql/sqlite/tables.sql +28 -0
  384. sqlspec/data_dictionary/sql/sqlite/version.sql +3 -0
  385. sqlspec/driver/__init__.py +32 -0
  386. sqlspec/driver/_async.cpython-310-aarch64-linux-gnu.so +0 -0
  387. sqlspec/driver/_async.py +1737 -0
  388. sqlspec/driver/_common.cpython-310-aarch64-linux-gnu.so +0 -0
  389. sqlspec/driver/_common.py +1478 -0
  390. sqlspec/driver/_sql_helpers.cpython-310-aarch64-linux-gnu.so +0 -0
  391. sqlspec/driver/_sql_helpers.py +148 -0
  392. sqlspec/driver/_storage_helpers.cpython-310-aarch64-linux-gnu.so +0 -0
  393. sqlspec/driver/_storage_helpers.py +144 -0
  394. sqlspec/driver/_sync.cpython-310-aarch64-linux-gnu.so +0 -0
  395. sqlspec/driver/_sync.py +1710 -0
  396. sqlspec/exceptions.py +338 -0
  397. sqlspec/extensions/__init__.py +0 -0
  398. sqlspec/extensions/adk/__init__.py +70 -0
  399. sqlspec/extensions/adk/_types.py +51 -0
  400. sqlspec/extensions/adk/converters.py +172 -0
  401. sqlspec/extensions/adk/memory/__init__.py +69 -0
  402. sqlspec/extensions/adk/memory/_types.py +30 -0
  403. sqlspec/extensions/adk/memory/converters.py +149 -0
  404. sqlspec/extensions/adk/memory/service.py +217 -0
  405. sqlspec/extensions/adk/memory/store.py +569 -0
  406. sqlspec/extensions/adk/migrations/0001_create_adk_tables.py +246 -0
  407. sqlspec/extensions/adk/migrations/__init__.py +0 -0
  408. sqlspec/extensions/adk/service.py +225 -0
  409. sqlspec/extensions/adk/store.py +567 -0
  410. sqlspec/extensions/events/__init__.py +51 -0
  411. sqlspec/extensions/events/_channel.py +703 -0
  412. sqlspec/extensions/events/_hints.py +45 -0
  413. sqlspec/extensions/events/_models.py +23 -0
  414. sqlspec/extensions/events/_payload.py +69 -0
  415. sqlspec/extensions/events/_protocols.py +134 -0
  416. sqlspec/extensions/events/_queue.py +461 -0
  417. sqlspec/extensions/events/_store.py +209 -0
  418. sqlspec/extensions/events/migrations/0001_create_event_queue.py +59 -0
  419. sqlspec/extensions/events/migrations/__init__.py +3 -0
  420. sqlspec/extensions/fastapi/__init__.py +19 -0
  421. sqlspec/extensions/fastapi/extension.py +351 -0
  422. sqlspec/extensions/fastapi/providers.py +607 -0
  423. sqlspec/extensions/flask/__init__.py +37 -0
  424. sqlspec/extensions/flask/_state.py +76 -0
  425. sqlspec/extensions/flask/_utils.py +71 -0
  426. sqlspec/extensions/flask/extension.py +519 -0
  427. sqlspec/extensions/litestar/__init__.py +28 -0
  428. sqlspec/extensions/litestar/_utils.py +52 -0
  429. sqlspec/extensions/litestar/channels.py +165 -0
  430. sqlspec/extensions/litestar/cli.py +102 -0
  431. sqlspec/extensions/litestar/config.py +90 -0
  432. sqlspec/extensions/litestar/handlers.py +316 -0
  433. sqlspec/extensions/litestar/migrations/0001_create_session_table.py +137 -0
  434. sqlspec/extensions/litestar/migrations/__init__.py +3 -0
  435. sqlspec/extensions/litestar/plugin.py +671 -0
  436. sqlspec/extensions/litestar/providers.py +526 -0
  437. sqlspec/extensions/litestar/store.py +296 -0
  438. sqlspec/extensions/otel/__init__.py +58 -0
  439. sqlspec/extensions/prometheus/__init__.py +113 -0
  440. sqlspec/extensions/starlette/__init__.py +19 -0
  441. sqlspec/extensions/starlette/_state.py +30 -0
  442. sqlspec/extensions/starlette/_utils.py +96 -0
  443. sqlspec/extensions/starlette/extension.py +346 -0
  444. sqlspec/extensions/starlette/middleware.py +235 -0
  445. sqlspec/loader.cpython-310-aarch64-linux-gnu.so +0 -0
  446. sqlspec/loader.py +702 -0
  447. sqlspec/migrations/__init__.py +36 -0
  448. sqlspec/migrations/base.py +731 -0
  449. sqlspec/migrations/commands.py +1232 -0
  450. sqlspec/migrations/context.py +157 -0
  451. sqlspec/migrations/fix.py +204 -0
  452. sqlspec/migrations/loaders.py +443 -0
  453. sqlspec/migrations/runner.py +1172 -0
  454. sqlspec/migrations/templates.py +234 -0
  455. sqlspec/migrations/tracker.py +611 -0
  456. sqlspec/migrations/utils.py +256 -0
  457. sqlspec/migrations/validation.py +207 -0
  458. sqlspec/migrations/version.py +446 -0
  459. sqlspec/observability/__init__.py +55 -0
  460. sqlspec/observability/_common.cpython-310-aarch64-linux-gnu.so +0 -0
  461. sqlspec/observability/_common.py +77 -0
  462. sqlspec/observability/_config.cpython-310-aarch64-linux-gnu.so +0 -0
  463. sqlspec/observability/_config.py +348 -0
  464. sqlspec/observability/_diagnostics.cpython-310-aarch64-linux-gnu.so +0 -0
  465. sqlspec/observability/_diagnostics.py +74 -0
  466. sqlspec/observability/_dispatcher.cpython-310-aarch64-linux-gnu.so +0 -0
  467. sqlspec/observability/_dispatcher.py +152 -0
  468. sqlspec/observability/_formatters/__init__.py +13 -0
  469. sqlspec/observability/_formatters/_aws.cpython-310-aarch64-linux-gnu.so +0 -0
  470. sqlspec/observability/_formatters/_aws.py +102 -0
  471. sqlspec/observability/_formatters/_azure.cpython-310-aarch64-linux-gnu.so +0 -0
  472. sqlspec/observability/_formatters/_azure.py +96 -0
  473. sqlspec/observability/_formatters/_base.cpython-310-aarch64-linux-gnu.so +0 -0
  474. sqlspec/observability/_formatters/_base.py +57 -0
  475. sqlspec/observability/_formatters/_gcp.cpython-310-aarch64-linux-gnu.so +0 -0
  476. sqlspec/observability/_formatters/_gcp.py +131 -0
  477. sqlspec/observability/_formatting.py +58 -0
  478. sqlspec/observability/_observer.cpython-310-aarch64-linux-gnu.so +0 -0
  479. sqlspec/observability/_observer.py +357 -0
  480. sqlspec/observability/_runtime.cpython-310-aarch64-linux-gnu.so +0 -0
  481. sqlspec/observability/_runtime.py +420 -0
  482. sqlspec/observability/_sampling.cpython-310-aarch64-linux-gnu.so +0 -0
  483. sqlspec/observability/_sampling.py +188 -0
  484. sqlspec/observability/_spans.cpython-310-aarch64-linux-gnu.so +0 -0
  485. sqlspec/observability/_spans.py +161 -0
  486. sqlspec/protocols.py +916 -0
  487. sqlspec/py.typed +0 -0
  488. sqlspec/storage/__init__.py +48 -0
  489. sqlspec/storage/_utils.py +104 -0
  490. sqlspec/storage/backends/__init__.py +1 -0
  491. sqlspec/storage/backends/base.py +253 -0
  492. sqlspec/storage/backends/fsspec.py +529 -0
  493. sqlspec/storage/backends/local.py +441 -0
  494. sqlspec/storage/backends/obstore.py +916 -0
  495. sqlspec/storage/errors.py +104 -0
  496. sqlspec/storage/pipeline.py +582 -0
  497. sqlspec/storage/registry.py +301 -0
  498. sqlspec/typing.py +395 -0
  499. sqlspec/utils/__init__.py +7 -0
  500. sqlspec/utils/arrow_helpers.py +318 -0
  501. sqlspec/utils/config_tools.py +332 -0
  502. sqlspec/utils/correlation.cpython-310-aarch64-linux-gnu.so +0 -0
  503. sqlspec/utils/correlation.py +134 -0
  504. sqlspec/utils/deprecation.py +190 -0
  505. sqlspec/utils/fixtures.cpython-310-aarch64-linux-gnu.so +0 -0
  506. sqlspec/utils/fixtures.py +258 -0
  507. sqlspec/utils/logging.py +222 -0
  508. sqlspec/utils/module_loader.py +306 -0
  509. sqlspec/utils/portal.cpython-310-aarch64-linux-gnu.so +0 -0
  510. sqlspec/utils/portal.py +375 -0
  511. sqlspec/utils/schema.cpython-310-aarch64-linux-gnu.so +0 -0
  512. sqlspec/utils/schema.py +485 -0
  513. sqlspec/utils/serializers.cpython-310-aarch64-linux-gnu.so +0 -0
  514. sqlspec/utils/serializers.py +408 -0
  515. sqlspec/utils/singleton.cpython-310-aarch64-linux-gnu.so +0 -0
  516. sqlspec/utils/singleton.py +41 -0
  517. sqlspec/utils/sync_tools.cpython-310-aarch64-linux-gnu.so +0 -0
  518. sqlspec/utils/sync_tools.py +311 -0
  519. sqlspec/utils/text.cpython-310-aarch64-linux-gnu.so +0 -0
  520. sqlspec/utils/text.py +108 -0
  521. sqlspec/utils/type_converters.cpython-310-aarch64-linux-gnu.so +0 -0
  522. sqlspec/utils/type_converters.py +128 -0
  523. sqlspec/utils/type_guards.cpython-310-aarch64-linux-gnu.so +0 -0
  524. sqlspec/utils/type_guards.py +1360 -0
  525. sqlspec/utils/uuids.cpython-310-aarch64-linux-gnu.so +0 -0
  526. sqlspec/utils/uuids.py +225 -0
  527. sqlspec-0.36.0.dist-info/METADATA +205 -0
  528. sqlspec-0.36.0.dist-info/RECORD +531 -0
  529. sqlspec-0.36.0.dist-info/WHEEL +7 -0
  530. sqlspec-0.36.0.dist-info/entry_points.txt +2 -0
  531. sqlspec-0.36.0.dist-info/licenses/LICENSE +21 -0
sqlspec/core/cache.py ADDED
@@ -0,0 +1,1069 @@
1
+ """Caching system for SQL statement processing.
2
+
3
+ This module provides a caching system with LRU eviction and TTL support for
4
+ SQL statement processing and SQLGlot expression caching.
5
+
6
+ Components:
7
+ - CacheKey: Immutable cache key
8
+ - LRUCache: LRU + TTL cache implementation
9
+ - NamespacedCache: Namespace-aware cache wrapper for statement processing
10
+ """
11
+
12
+ import logging
13
+ import threading
14
+ import time
15
+ from typing import TYPE_CHECKING, Any, Final
16
+
17
+ from mypy_extensions import mypyc_attr
18
+ from typing_extensions import TypeVar
19
+
20
+ from sqlspec.core.pipeline import (
21
+ configure_statement_pipeline_cache,
22
+ get_statement_pipeline_metrics,
23
+ reset_statement_pipeline_cache,
24
+ )
25
+ from sqlspec.utils.logging import get_logger, log_with_context
26
+ from sqlspec.utils.type_guards import has_field_name, has_filter_attributes
27
+
28
+ if TYPE_CHECKING:
29
+ from collections.abc import Callable, Iterator
30
+
31
+ import sqlglot.expressions as exp
32
+
33
+
34
+ __all__ = (
35
+ "CacheKey",
36
+ "CacheStats",
37
+ "CachedStatement",
38
+ "FiltersView",
39
+ "LRUCache",
40
+ "NamespacedCache",
41
+ "canonicalize_filters",
42
+ "create_cache_key",
43
+ "get_cache",
44
+ "get_cache_config",
45
+ "get_cache_instances",
46
+ "get_default_cache",
47
+ "get_pipeline_metrics",
48
+ "reset_pipeline_registry",
49
+ "set_cache_instances",
50
+ )
51
+
52
+ logger = get_logger("sqlspec.cache")
53
+
54
+ T = TypeVar("T")
55
+ CacheValueT = TypeVar("CacheValueT")
56
+
57
+
58
+ DEFAULT_MAX_SIZE: Final = 10000
59
+ DEFAULT_TTL_SECONDS: Final = 3600
60
+ CACHE_STATS_UPDATE_INTERVAL: Final = 100
61
+
62
+
63
+ CACHE_KEY_SLOTS: Final = ("_hash", "_key_data")
64
+ CACHE_NODE_SLOTS: Final = ("key", "value", "prev", "next", "timestamp", "access_count")
65
+ LRU_CACHE_SLOTS: Final = ("_cache", "_lock", "_max_size", "_ttl", "_head", "_tail", "_stats")
66
+ CACHE_STATS_SLOTS: Final = ("hits", "misses", "evictions", "total_operations", "memory_usage")
67
+
68
+
69
+ @mypyc_attr(allow_interpreted_subclasses=False)
70
+ class CacheKey:
71
+ """Immutable cache key.
72
+
73
+ Args:
74
+ key_data: Tuple of hashable values that uniquely identify the cached item
75
+ """
76
+
77
+ __slots__ = ("_hash", "_key_data")
78
+
79
+ def __init__(self, key_data: "tuple[Any, ...]") -> None:
80
+ """Initialize cache key.
81
+
82
+ Args:
83
+ key_data: Tuple of hashable values for the cache key
84
+ """
85
+ self._key_data = key_data
86
+ self._hash = hash(key_data)
87
+
88
+ @property
89
+ def key_data(self) -> "tuple[Any, ...]":
90
+ """Get the key data tuple."""
91
+ return self._key_data
92
+
93
+ def __hash__(self) -> int:
94
+ """Return cached hash value."""
95
+ return self._hash
96
+
97
+ def __eq__(self, other: object) -> bool:
98
+ """Equality comparison."""
99
+ if type(other) is not CacheKey:
100
+ return False
101
+ other_key = other
102
+ if self._hash != other_key._hash:
103
+ return False
104
+ return self._key_data == other_key._key_data
105
+
106
+ def __repr__(self) -> str:
107
+ """String representation of the cache key."""
108
+ return f"CacheKey({self._key_data!r})"
109
+
110
+
111
+ @mypyc_attr(allow_interpreted_subclasses=False)
112
+ class CacheStats:
113
+ """Cache statistics tracking.
114
+
115
+ Tracks cache metrics including hit rates, evictions, and memory usage.
116
+ """
117
+
118
+ __slots__ = CACHE_STATS_SLOTS
119
+
120
+ def __init__(self) -> None:
121
+ """Initialize cache statistics."""
122
+ self.hits = 0
123
+ self.misses = 0
124
+ self.evictions = 0
125
+ self.total_operations = 0
126
+ self.memory_usage = 0
127
+
128
+ @property
129
+ def hit_rate(self) -> float:
130
+ """Calculate cache hit rate as percentage."""
131
+ total = self.hits + self.misses
132
+ return (self.hits / total * 100) if total > 0 else 0.0
133
+
134
+ @property
135
+ def miss_rate(self) -> float:
136
+ """Calculate cache miss rate as percentage."""
137
+ return 100.0 - self.hit_rate
138
+
139
+ def record_hit(self) -> None:
140
+ """Record a cache hit."""
141
+ self.hits += 1
142
+ self.total_operations += 1
143
+
144
+ def record_miss(self) -> None:
145
+ """Record a cache miss."""
146
+ self.misses += 1
147
+ self.total_operations += 1
148
+
149
+ def record_eviction(self) -> None:
150
+ """Record a cache eviction."""
151
+ self.evictions += 1
152
+
153
+ def reset(self) -> None:
154
+ """Reset all statistics."""
155
+ self.hits = 0
156
+ self.misses = 0
157
+ self.evictions = 0
158
+ self.total_operations = 0
159
+ self.memory_usage = 0
160
+
161
+ def __repr__(self) -> str:
162
+ """String representation of cache statistics."""
163
+ return (
164
+ f"CacheStats(hit_rate={self.hit_rate:.1f}%, "
165
+ f"hits={self.hits}, misses={self.misses}, "
166
+ f"evictions={self.evictions}, ops={self.total_operations})"
167
+ )
168
+
169
+
170
+ @mypyc_attr(allow_interpreted_subclasses=False)
171
+ class CacheNode:
172
+ """Internal cache node for LRU linked list implementation."""
173
+
174
+ __slots__ = CACHE_NODE_SLOTS
175
+
176
+ def __init__(self, key: CacheKey, value: Any) -> None:
177
+ """Initialize cache node.
178
+
179
+ Args:
180
+ key: Cache key for this node
181
+ value: Cached value
182
+ """
183
+ self.key = key
184
+ self.value = value
185
+ self.prev: CacheNode | None = None
186
+ self.next: CacheNode | None = None
187
+ self.timestamp = time.time()
188
+ self.access_count = 1
189
+
190
+
191
+ @mypyc_attr(allow_interpreted_subclasses=False)
192
+ class LRUCache:
193
+ """Cache with LRU eviction and TTL support.
194
+
195
+ Args:
196
+ max_size: Maximum number of items to cache (LRU eviction when exceeded)
197
+ ttl_seconds: Time-to-live in seconds (None for no expiration)
198
+ """
199
+
200
+ __slots__ = LRU_CACHE_SLOTS
201
+
202
+ def __init__(self, max_size: int = DEFAULT_MAX_SIZE, ttl_seconds: int | None = DEFAULT_TTL_SECONDS) -> None:
203
+ """Initialize LRU cache.
204
+
205
+ Args:
206
+ max_size: Maximum number of cache entries
207
+ ttl_seconds: Time-to-live in seconds (None for no expiration)
208
+ """
209
+ self._cache: dict[CacheKey, CacheNode] = {}
210
+ self._lock = threading.RLock()
211
+ self._max_size = max_size
212
+ self._ttl = ttl_seconds
213
+ self._stats = CacheStats()
214
+
215
+ self._head = CacheNode(CacheKey(()), None)
216
+ self._tail = CacheNode(CacheKey(()), None)
217
+ self._head.next = self._tail
218
+ self._tail.prev = self._head
219
+
220
+ def get(self, key: CacheKey) -> Any | None:
221
+ """Get value from cache.
222
+
223
+ Args:
224
+ key: Cache key to lookup
225
+
226
+ Returns:
227
+ Cached value or None if not found or expired
228
+ """
229
+ with self._lock:
230
+ node = self._cache.get(key)
231
+ if node is None:
232
+ self._stats.record_miss()
233
+ if logger.isEnabledFor(logging.DEBUG):
234
+ log_with_context(logger, logging.DEBUG, "cache.miss", cache_size=len(self._cache))
235
+ return None
236
+
237
+ ttl = self._ttl
238
+ if ttl is not None:
239
+ current_time = time.time()
240
+ if (current_time - node.timestamp) > ttl:
241
+ self._remove_node(node)
242
+ del self._cache[key]
243
+ self._stats.record_miss()
244
+ self._stats.record_eviction()
245
+ if logger.isEnabledFor(logging.DEBUG):
246
+ log_with_context(
247
+ logger, logging.DEBUG, "cache.evict", cache_size=len(self._cache), reason="expired"
248
+ )
249
+ return None
250
+
251
+ self._move_to_head(node)
252
+ node.access_count += 1
253
+ self._stats.record_hit()
254
+ if logger.isEnabledFor(logging.DEBUG):
255
+ log_with_context(logger, logging.DEBUG, "cache.hit", cache_size=len(self._cache))
256
+ return node.value
257
+
258
+ def put(self, key: CacheKey, value: Any) -> None:
259
+ """Put value in cache.
260
+
261
+ Args:
262
+ key: Cache key
263
+ value: Value to cache
264
+ """
265
+ with self._lock:
266
+ existing_node = self._cache.get(key)
267
+ if existing_node is not None:
268
+ existing_node.value = value
269
+ existing_node.timestamp = time.time()
270
+ existing_node.access_count += 1
271
+ self._move_to_head(existing_node)
272
+ return
273
+
274
+ new_node = CacheNode(key, value)
275
+ self._cache[key] = new_node
276
+ self._add_to_head(new_node)
277
+
278
+ if len(self._cache) > self._max_size:
279
+ tail_node = self._tail.prev
280
+ if tail_node is not None and tail_node is not self._head:
281
+ self._remove_node(tail_node)
282
+ del self._cache[tail_node.key]
283
+ self._stats.record_eviction()
284
+ if logger.isEnabledFor(logging.DEBUG):
285
+ log_with_context(
286
+ logger, logging.DEBUG, "cache.evict", cache_size=len(self._cache), reason="max_size"
287
+ )
288
+
289
+ def delete(self, key: CacheKey) -> bool:
290
+ """Delete entry from cache.
291
+
292
+ Args:
293
+ key: Cache key to delete
294
+
295
+ Returns:
296
+ True if key was found and deleted, False otherwise
297
+ """
298
+ with self._lock:
299
+ node: CacheNode | None = self._cache.get(key)
300
+ if node is None:
301
+ return False
302
+
303
+ self._remove_node(node)
304
+ del self._cache[key]
305
+ return True
306
+
307
+ def clear(self) -> None:
308
+ """Clear all cache entries."""
309
+ with self._lock:
310
+ self._cache.clear()
311
+ self._head.next = self._tail
312
+ self._tail.prev = self._head
313
+ self._stats.reset()
314
+
315
+ def size(self) -> int:
316
+ """Get current cache size."""
317
+ return len(self._cache)
318
+
319
+ def is_empty(self) -> bool:
320
+ """Check if cache is empty."""
321
+ return not self._cache
322
+
323
+ def get_stats(self) -> CacheStats:
324
+ """Get cache statistics."""
325
+ return self._stats
326
+
327
+ def _add_to_head(self, node: CacheNode) -> None:
328
+ """Add node to head of list."""
329
+ node.prev = self._head
330
+ head_next: CacheNode | None = self._head.next
331
+ node.next = head_next
332
+ if head_next is not None:
333
+ head_next.prev = node
334
+ self._head.next = node
335
+
336
+ def _remove_node(self, node: CacheNode) -> None:
337
+ """Remove node from linked list."""
338
+ node_prev: CacheNode | None = node.prev
339
+ node_next: CacheNode | None = node.next
340
+ if node_prev is not None:
341
+ node_prev.next = node_next
342
+ if node_next is not None:
343
+ node_next.prev = node_prev
344
+
345
+ def _move_to_head(self, node: CacheNode) -> None:
346
+ """Move node to head of list."""
347
+ self._remove_node(node)
348
+ self._add_to_head(node)
349
+
350
+ def __len__(self) -> int:
351
+ """Get current cache size."""
352
+ return len(self._cache)
353
+
354
+ def __contains__(self, key: CacheKey) -> bool:
355
+ """Check if key exists in cache."""
356
+ with self._lock:
357
+ node = self._cache.get(key)
358
+ if node is None:
359
+ return False
360
+
361
+ ttl = self._ttl
362
+ return not (ttl is not None and time.time() - node.timestamp > ttl)
363
+
364
+
365
+ _default_cache: LRUCache | None = None
366
+ _cache_lock = threading.Lock()
367
+
368
+
369
+ def get_default_cache() -> LRUCache:
370
+ """Get the default LRU cache instance.
371
+
372
+ Returns:
373
+ Singleton default cache instance
374
+ """
375
+ global _default_cache
376
+ if _default_cache is None:
377
+ with _cache_lock:
378
+ if _default_cache is None:
379
+ config = get_cache_config()
380
+ _default_cache = LRUCache(config.sql_cache_size)
381
+ return _default_cache
382
+
383
+
384
+ def get_cache_instances() -> "tuple[LRUCache | None, NamespacedCache | None]":
385
+ """Return the current cache instances.
386
+
387
+ Returns:
388
+ Tuple of (default_cache, namespaced_cache).
389
+ """
390
+ return _default_cache, _namespaced_cache
391
+
392
+
393
+ def set_cache_instances(default_cache: "LRUCache | None", namespaced_cache: "NamespacedCache | None") -> None:
394
+ """Replace cache instances (used by tests and diagnostics).
395
+
396
+ Args:
397
+ default_cache: Default cache instance or None.
398
+ namespaced_cache: Namespaced cache instance or None.
399
+ """
400
+ global _default_cache, _namespaced_cache
401
+ _default_cache = default_cache
402
+ _namespaced_cache = namespaced_cache
403
+
404
+
405
+ def clear_all_caches() -> None:
406
+ """Clear all cache instances."""
407
+ if _default_cache is not None:
408
+ _default_cache.clear()
409
+ cache = get_cache()
410
+ cache.clear()
411
+ reset_statement_pipeline_cache()
412
+
413
+
414
+ def get_cache_statistics() -> "dict[str, CacheStats]":
415
+ """Get statistics from all cache instances.
416
+
417
+ Returns:
418
+ Dictionary mapping cache type to statistics
419
+ """
420
+ stats: dict[str, CacheStats] = {}
421
+ default_cache = get_default_cache()
422
+ stats["default"] = default_cache.get_stats()
423
+ cache = get_cache()
424
+ stats["namespaced"] = cache.get_stats()
425
+ return stats
426
+
427
+
428
+ _global_cache_config: "CacheConfig | None" = None
429
+
430
+
431
+ @mypyc_attr(allow_interpreted_subclasses=False)
432
+ class CacheConfig:
433
+ """Global cache configuration for SQLSpec."""
434
+
435
+ def __init__(
436
+ self,
437
+ *,
438
+ compiled_cache_enabled: bool = True,
439
+ sql_cache_enabled: bool = True,
440
+ fragment_cache_enabled: bool = True,
441
+ optimized_cache_enabled: bool = True,
442
+ sql_cache_size: int = 1000,
443
+ fragment_cache_size: int = 5000,
444
+ optimized_cache_size: int = 2000,
445
+ ) -> None:
446
+ """Initialize cache configuration.
447
+
448
+ Args:
449
+ compiled_cache_enabled: Master switch for namespaced caches and compiled SQL caching.
450
+ sql_cache_enabled: Enable statement and builder caching.
451
+ fragment_cache_enabled: Enable expression, parameter, and file caching.
452
+ optimized_cache_enabled: Enable optimized expression caching.
453
+ sql_cache_size: Maximum statement/builder cache entries.
454
+ fragment_cache_size: Maximum expression/parameter/file cache entries.
455
+ optimized_cache_size: Maximum optimized cache entries.
456
+ """
457
+ self.compiled_cache_enabled = compiled_cache_enabled
458
+ self.sql_cache_enabled = sql_cache_enabled
459
+ self.fragment_cache_enabled = fragment_cache_enabled
460
+ self.optimized_cache_enabled = optimized_cache_enabled
461
+ self.sql_cache_size = sql_cache_size
462
+ self.fragment_cache_size = fragment_cache_size
463
+ self.optimized_cache_size = optimized_cache_size
464
+
465
+
466
+ def get_cache_config() -> CacheConfig:
467
+ """Get the global cache configuration.
468
+
469
+ Returns:
470
+ Current global cache configuration instance
471
+ """
472
+ global _global_cache_config
473
+ if _global_cache_config is None:
474
+ _global_cache_config = CacheConfig()
475
+ _configure_pipeline_cache(_global_cache_config)
476
+ return _global_cache_config
477
+
478
+
479
+ def _configure_pipeline_cache(config: "CacheConfig") -> None:
480
+ compiled_cache_enabled = config.compiled_cache_enabled and config.sql_cache_enabled
481
+ fragment_cache_enabled = config.compiled_cache_enabled and config.fragment_cache_enabled
482
+ cache_size = config.sql_cache_size if compiled_cache_enabled else 0
483
+ parse_cache_size = config.fragment_cache_size if fragment_cache_enabled else 0
484
+ configure_statement_pipeline_cache(
485
+ cache_size=cache_size, parse_cache_size=parse_cache_size, cache_enabled=compiled_cache_enabled
486
+ )
487
+
488
+
489
+ def update_cache_config(config: CacheConfig) -> None:
490
+ """Update the global cache configuration.
491
+
492
+ Clears all existing caches when configuration changes.
493
+
494
+ Args:
495
+ config: New cache configuration to apply globally
496
+ """
497
+ logger = get_logger("sqlspec.cache")
498
+ log_with_context(
499
+ logger,
500
+ logging.DEBUG,
501
+ "cache.config.updated",
502
+ compiled_cache_enabled=config.compiled_cache_enabled,
503
+ sql_cache_enabled=config.sql_cache_enabled,
504
+ fragment_cache_enabled=config.fragment_cache_enabled,
505
+ optimized_cache_enabled=config.optimized_cache_enabled,
506
+ sql_cache_size=config.sql_cache_size,
507
+ fragment_cache_size=config.fragment_cache_size,
508
+ optimized_cache_size=config.optimized_cache_size,
509
+ )
510
+
511
+ global _default_cache, _global_cache_config, _namespaced_cache
512
+ _global_cache_config = config
513
+
514
+ _configure_pipeline_cache(config)
515
+
516
+ if _default_cache is not None:
517
+ _default_cache.clear()
518
+ if _namespaced_cache is not None:
519
+ _namespaced_cache.clear()
520
+ _default_cache = None
521
+ _namespaced_cache = None
522
+
523
+ log_with_context(
524
+ logger,
525
+ logging.DEBUG,
526
+ "cache.config.cleared",
527
+ compiled_cache_enabled=config.compiled_cache_enabled,
528
+ sql_cache_enabled=config.sql_cache_enabled,
529
+ fragment_cache_enabled=config.fragment_cache_enabled,
530
+ optimized_cache_enabled=config.optimized_cache_enabled,
531
+ )
532
+
533
+
534
+ def get_cache_stats() -> "dict[str, CacheStats]":
535
+ """Get cache statistics from all caches.
536
+
537
+ Returns:
538
+ Dictionary of cache statistics
539
+ """
540
+ return get_cache_statistics()
541
+
542
+
543
+ def reset_cache_stats() -> None:
544
+ """Reset all cache statistics."""
545
+ clear_all_caches()
546
+
547
+
548
+ def log_cache_stats() -> None:
549
+ """Log cache statistics."""
550
+ logger = get_logger("sqlspec.cache")
551
+ stats = get_cache_stats()
552
+ stats_summary = {
553
+ name: {
554
+ "hits": stat.hits,
555
+ "misses": stat.misses,
556
+ "evictions": stat.evictions,
557
+ "total_operations": stat.total_operations,
558
+ "memory_usage": stat.memory_usage,
559
+ }
560
+ for name, stat in stats.items()
561
+ }
562
+ log_with_context(logger, logging.DEBUG, "cache.stats", stats=stats_summary)
563
+
564
+
565
+ @mypyc_attr(allow_interpreted_subclasses=False)
566
+ class CachedStatement:
567
+ """Immutable cached statement result.
568
+
569
+ This class stores compiled SQL and parameters in an immutable format
570
+ that can be safely shared between different parts of the system without
571
+ risk of mutation. Tuple parameters ensure no copying is needed.
572
+ """
573
+
574
+ __slots__ = ("compiled_sql", "expression", "parameters")
575
+
576
+ def __init__(
577
+ self,
578
+ compiled_sql: str,
579
+ parameters: "tuple[Any, ...] | dict[str, Any] | None",
580
+ expression: "exp.Expression | None",
581
+ ) -> None:
582
+ self.compiled_sql = compiled_sql
583
+ self.parameters = parameters
584
+ self.expression = expression
585
+
586
+ def __repr__(self) -> str:
587
+ return (
588
+ "CachedStatement("
589
+ f"compiled_sql={self.compiled_sql!r}, "
590
+ f"parameters={self.parameters!r}, "
591
+ f"expression={self.expression!r})"
592
+ )
593
+
594
+ def __eq__(self, other: object) -> bool:
595
+ if not isinstance(other, CachedStatement):
596
+ return False
597
+ return (
598
+ self.compiled_sql == other.compiled_sql
599
+ and self.parameters == other.parameters
600
+ and self.expression == other.expression
601
+ )
602
+
603
+ def __hash__(self) -> int:
604
+ return hash((self.compiled_sql, self.parameters, self.expression))
605
+
606
+
607
+ def create_cache_key(namespace: str, key: str, dialect: str | None = None) -> str:
608
+ """Create optimized cache key using string concatenation.
609
+
610
+ Args:
611
+ namespace: Cache namespace name.
612
+ key: Base cache key.
613
+ dialect: SQL dialect (optional).
614
+
615
+ Returns:
616
+ Optimized cache key string.
617
+ """
618
+ return f"{namespace}:{dialect or 'default'}:{key}"
619
+
620
+
621
+ def _sql_cache_enabled(config: "CacheConfig") -> bool:
622
+ return config.sql_cache_enabled
623
+
624
+
625
+ def _sql_cache_size(config: "CacheConfig") -> int:
626
+ return config.sql_cache_size
627
+
628
+
629
+ def _fragment_cache_enabled(config: "CacheConfig") -> bool:
630
+ return config.fragment_cache_enabled
631
+
632
+
633
+ def _fragment_cache_size(config: "CacheConfig") -> int:
634
+ return config.fragment_cache_size
635
+
636
+
637
+ def _optimized_cache_enabled(config: "CacheConfig") -> bool:
638
+ return config.optimized_cache_enabled
639
+
640
+
641
+ def _optimized_cache_size(config: "CacheConfig") -> int:
642
+ return config.optimized_cache_size
643
+
644
+
645
+ NAMESPACED_CACHE_CONFIG: "dict[str, tuple[Callable[[CacheConfig], bool], Callable[[CacheConfig], int]]]" = {
646
+ "statement": (_sql_cache_enabled, _sql_cache_size),
647
+ "builder": (_sql_cache_enabled, _sql_cache_size),
648
+ "expression": (_fragment_cache_enabled, _fragment_cache_size),
649
+ "file": (_fragment_cache_enabled, _fragment_cache_size),
650
+ "optimized": (_optimized_cache_enabled, _optimized_cache_size),
651
+ }
652
+
653
+
654
+ @mypyc_attr(allow_interpreted_subclasses=False)
655
+ class NamespacedCache:
656
+ """Single cache with namespace isolation.
657
+
658
+ Uses per-namespace LRU caches sized by CacheConfig to keep memory usage
659
+ predictable while avoiding stringly-typed cache access.
660
+ """
661
+
662
+ __slots__ = ("_caches", "_config")
663
+
664
+ def __init__(self, config: "CacheConfig | None" = None, ttl_seconds: int | None = DEFAULT_TTL_SECONDS) -> None:
665
+ """Initialize namespaced cache.
666
+
667
+ Args:
668
+ config: Cache configuration to apply.
669
+ ttl_seconds: Time-to-live in seconds (None for no expiration).
670
+ """
671
+ self._config = config or get_cache_config()
672
+ self._caches = self._build_caches(self._config, ttl_seconds)
673
+
674
+ @staticmethod
675
+ def _build_caches(config: "CacheConfig", ttl_seconds: int | None) -> "dict[str, LRUCache]":
676
+ caches: dict[str, LRUCache] = {}
677
+ for namespace, (_, size_getter) in NAMESPACED_CACHE_CONFIG.items():
678
+ size = size_getter(config)
679
+ caches[namespace] = LRUCache(size, ttl_seconds)
680
+ return caches
681
+
682
+ def _is_enabled(self, namespace: str) -> bool:
683
+ if not self._config.compiled_cache_enabled:
684
+ return False
685
+ enabled_getter = NAMESPACED_CACHE_CONFIG[namespace][0]
686
+ return bool(enabled_getter(self._config))
687
+
688
+ def _get(self, namespace: str, key: str, dialect: str | None = None) -> Any | None:
689
+ """Get cached value by namespace.
690
+
691
+ Args:
692
+ namespace: Cache namespace.
693
+ key: Cache key.
694
+ dialect: Optional SQL dialect.
695
+
696
+ Returns:
697
+ Cached value or None if not found.
698
+ """
699
+ if not self._is_enabled(namespace):
700
+ return None
701
+ cache = self._caches[namespace]
702
+ full_key = create_cache_key(namespace, key, dialect)
703
+ cache_key = CacheKey((full_key,))
704
+ return cache.get(cache_key)
705
+
706
+ def _put(self, namespace: str, key: str, value: Any, dialect: str | None = None) -> None:
707
+ """Put cached value by namespace.
708
+
709
+ Args:
710
+ namespace: Cache namespace.
711
+ key: Cache key.
712
+ value: Value to cache.
713
+ dialect: Optional SQL dialect.
714
+ """
715
+ if not self._is_enabled(namespace):
716
+ return
717
+ cache = self._caches[namespace]
718
+ full_key = create_cache_key(namespace, key, dialect)
719
+ cache_key = CacheKey((full_key,))
720
+ cache.put(cache_key, value)
721
+
722
+ def _delete(self, namespace: str, key: str, dialect: str | None = None) -> bool:
723
+ """Delete cached value by namespace.
724
+
725
+ Args:
726
+ namespace: Cache namespace.
727
+ key: Cache key.
728
+ dialect: Optional SQL dialect.
729
+
730
+ Returns:
731
+ True when the key was found and deleted.
732
+ """
733
+ if not self._is_enabled(namespace):
734
+ return False
735
+ cache = self._caches[namespace]
736
+ full_key = create_cache_key(namespace, key, dialect)
737
+ cache_key = CacheKey((full_key,))
738
+ return cache.delete(cache_key)
739
+
740
+ def get_statement(self, key: str, dialect: str | None = None) -> Any | None:
741
+ """Get cached statement data.
742
+
743
+ Args:
744
+ key: Cache key.
745
+ dialect: Optional SQL dialect.
746
+
747
+ Returns:
748
+ Cached value or None if not found.
749
+ """
750
+ return self._get("statement", key, dialect)
751
+
752
+ def put_statement(self, key: str, value: Any, dialect: str | None = None) -> None:
753
+ """Cache compiled statement data.
754
+
755
+ Args:
756
+ key: Cache key.
757
+ value: Value to cache.
758
+ dialect: Optional SQL dialect.
759
+ """
760
+ self._put("statement", key, value, dialect)
761
+
762
+ def delete_statement(self, key: str, dialect: str | None = None) -> bool:
763
+ """Delete cached statement data.
764
+
765
+ Args:
766
+ key: Cache key.
767
+ dialect: Optional SQL dialect.
768
+
769
+ Returns:
770
+ True when the key was found and deleted.
771
+ """
772
+ return self._delete("statement", key, dialect)
773
+
774
+ def get_expression(self, key: str, dialect: str | None = None) -> Any | None:
775
+ """Get cached expression data.
776
+
777
+ Args:
778
+ key: Cache key.
779
+ dialect: Optional SQL dialect.
780
+
781
+ Returns:
782
+ Cached value or None if not found.
783
+ """
784
+ return self._get("expression", key, dialect)
785
+
786
+ def put_expression(self, key: str, value: Any, dialect: str | None = None) -> None:
787
+ """Cache parsed expression data.
788
+
789
+ Args:
790
+ key: Cache key.
791
+ value: Value to cache.
792
+ dialect: Optional SQL dialect.
793
+ """
794
+ self._put("expression", key, value, dialect)
795
+
796
+ def delete_expression(self, key: str, dialect: str | None = None) -> bool:
797
+ """Delete cached expression data.
798
+
799
+ Args:
800
+ key: Cache key.
801
+ dialect: Optional SQL dialect.
802
+
803
+ Returns:
804
+ True when the key was found and deleted.
805
+ """
806
+ return self._delete("expression", key, dialect)
807
+
808
+ def get_optimized(self, key: str, dialect: str | None = None) -> Any | None:
809
+ """Get cached optimized expression data.
810
+
811
+ Args:
812
+ key: Cache key.
813
+ dialect: Optional SQL dialect.
814
+
815
+ Returns:
816
+ Cached value or None if not found.
817
+ """
818
+ return self._get("optimized", key, dialect)
819
+
820
+ def put_optimized(self, key: str, value: Any, dialect: str | None = None) -> None:
821
+ """Cache optimized expression data.
822
+
823
+ Args:
824
+ key: Cache key.
825
+ value: Value to cache.
826
+ dialect: Optional SQL dialect.
827
+ """
828
+ self._put("optimized", key, value, dialect)
829
+
830
+ def delete_optimized(self, key: str, dialect: str | None = None) -> bool:
831
+ """Delete cached optimized expression data.
832
+
833
+ Args:
834
+ key: Cache key.
835
+ dialect: Optional SQL dialect.
836
+
837
+ Returns:
838
+ True when the key was found and deleted.
839
+ """
840
+ return self._delete("optimized", key, dialect)
841
+
842
+ def get_builder(self, key: str, dialect: str | None = None) -> Any | None:
843
+ """Get cached builder statement data.
844
+
845
+ Args:
846
+ key: Cache key.
847
+ dialect: Optional SQL dialect.
848
+
849
+ Returns:
850
+ Cached value or None if not found.
851
+ """
852
+ return self._get("builder", key, dialect)
853
+
854
+ def put_builder(self, key: str, value: Any, dialect: str | None = None) -> None:
855
+ """Cache builder statement data.
856
+
857
+ Args:
858
+ key: Cache key.
859
+ value: Value to cache.
860
+ dialect: Optional SQL dialect.
861
+ """
862
+ self._put("builder", key, value, dialect)
863
+
864
+ def delete_builder(self, key: str, dialect: str | None = None) -> bool:
865
+ """Delete cached builder statement data.
866
+
867
+ Args:
868
+ key: Cache key.
869
+ dialect: Optional SQL dialect.
870
+
871
+ Returns:
872
+ True when the key was found and deleted.
873
+ """
874
+ return self._delete("builder", key, dialect)
875
+
876
+ def get_file(self, key: str, dialect: str | None = None) -> Any | None:
877
+ """Get cached SQL file data.
878
+
879
+ Args:
880
+ key: Cache key.
881
+ dialect: Optional SQL dialect.
882
+
883
+ Returns:
884
+ Cached value or None if not found.
885
+ """
886
+ return self._get("file", key, dialect)
887
+
888
+ def put_file(self, key: str, value: Any, dialect: str | None = None) -> None:
889
+ """Cache SQL file data.
890
+
891
+ Args:
892
+ key: Cache key.
893
+ value: Value to cache.
894
+ dialect: Optional SQL dialect.
895
+ """
896
+ self._put("file", key, value, dialect)
897
+
898
+ def delete_file(self, key: str, dialect: str | None = None) -> bool:
899
+ """Delete cached SQL file data.
900
+
901
+ Args:
902
+ key: Cache key.
903
+ dialect: Optional SQL dialect.
904
+
905
+ Returns:
906
+ True when the key was found and deleted.
907
+ """
908
+ return self._delete("file", key, dialect)
909
+
910
+ def clear(self) -> None:
911
+ """Clear all cache entries."""
912
+ for cache in self._caches.values():
913
+ cache.clear()
914
+
915
+ def get_stats(self) -> CacheStats:
916
+ """Get cache statistics."""
917
+ aggregated = CacheStats()
918
+ for cache in self._caches.values():
919
+ stats = cache.get_stats()
920
+ aggregated.hits += stats.hits
921
+ aggregated.misses += stats.misses
922
+ aggregated.evictions += stats.evictions
923
+ aggregated.total_operations += stats.total_operations
924
+ aggregated.memory_usage += stats.memory_usage
925
+ return aggregated
926
+
927
+
928
+ _namespaced_cache: NamespacedCache | None = None
929
+
930
+
931
+ def get_cache() -> NamespacedCache:
932
+ """Get the namespaced cache instance.
933
+
934
+ Returns:
935
+ Singleton namespaced cache instance
936
+ """
937
+ global _namespaced_cache
938
+ if _namespaced_cache is None:
939
+ with _cache_lock:
940
+ if _namespaced_cache is None:
941
+ _namespaced_cache = NamespacedCache(get_cache_config())
942
+ return _namespaced_cache
943
+
944
+
945
+ @mypyc_attr(allow_interpreted_subclasses=False)
946
+ class Filter:
947
+ """Immutable filter that can be safely shared."""
948
+
949
+ __slots__ = ("field_name", "operation", "value")
950
+
951
+ def __init__(self, field_name: str, operation: str, value: Any) -> None:
952
+ if not field_name:
953
+ msg = "Field name cannot be empty"
954
+ raise ValueError(msg)
955
+ if not operation:
956
+ msg = "Operation cannot be empty"
957
+ raise ValueError(msg)
958
+ self.field_name = field_name
959
+ self.operation = operation
960
+ self.value = value
961
+
962
+ def __repr__(self) -> str:
963
+ return f"Filter(field_name={self.field_name!r}, operation={self.operation!r}, value={self.value!r})"
964
+
965
+ def __eq__(self, other: object) -> bool:
966
+ if not isinstance(other, Filter):
967
+ return False
968
+ return self.field_name == other.field_name and self.operation == other.operation and self.value == other.value
969
+
970
+ def __hash__(self) -> int:
971
+ return hash((self.field_name, self.operation, self.value))
972
+
973
+
974
+ def canonicalize_filters(filters: "list[Filter]") -> "tuple[Filter, ...]":
975
+ """Create canonical representation of filters for cache keys.
976
+
977
+ Args:
978
+ filters: List of filters to canonicalize
979
+
980
+ Returns:
981
+ Tuple of unique filters sorted by field_name, operation, then value
982
+ """
983
+ if not filters:
984
+ return ()
985
+
986
+ # Deduplicate and sort for canonical representation
987
+ unique_filters = set(filters)
988
+ return tuple(sorted(unique_filters, key=_filter_sort_key))
989
+
990
+
991
+ def _filter_sort_key(filter_obj: "Filter") -> "tuple[str, str, str]":
992
+ return filter_obj.field_name, filter_obj.operation, str(filter_obj.value)
993
+
994
+
995
+ @mypyc_attr(allow_interpreted_subclasses=False)
996
+ class FiltersView:
997
+ """Read-only view of filters without copying.
998
+
999
+ Provides zero-copy access to filters with methods for querying,
1000
+ iteration, and canonical representation generation.
1001
+ """
1002
+
1003
+ __slots__ = ("_filters_ref",)
1004
+
1005
+ def __init__(self, filters: "list[Any]") -> None:
1006
+ """Initialize filters view.
1007
+
1008
+ Args:
1009
+ filters: List of filters (will be referenced, not copied)
1010
+ """
1011
+ self._filters_ref = filters
1012
+
1013
+ def __len__(self) -> int:
1014
+ """Get number of filters."""
1015
+ return len(self._filters_ref)
1016
+
1017
+ def __iter__(self) -> "Iterator[Any]":
1018
+ """Iterate over filters."""
1019
+ return iter(self._filters_ref)
1020
+
1021
+ def get_by_field(self, field_name: str) -> "list[Any]":
1022
+ """Get all filters for a specific field.
1023
+
1024
+ Args:
1025
+ field_name: Field name to filter by
1026
+
1027
+ Returns:
1028
+ List of filters matching the field name
1029
+ """
1030
+ return [f for f in self._filters_ref if has_field_name(f) and f.field_name == field_name]
1031
+
1032
+ def has_field(self, field_name: str) -> bool:
1033
+ """Check if any filter exists for a field.
1034
+
1035
+ Args:
1036
+ field_name: Field name to check
1037
+
1038
+ Returns:
1039
+ True if field has filters
1040
+ """
1041
+ return any(has_field_name(f) and f.field_name == field_name for f in self._filters_ref)
1042
+
1043
+ def to_canonical(self) -> "tuple[Any, ...]":
1044
+ """Create canonical representation for cache keys.
1045
+
1046
+ Returns:
1047
+ Canonical tuple representation of filters
1048
+ """
1049
+ # Convert to Filter objects if needed, then canonicalize
1050
+ filter_objects = []
1051
+ for f in self._filters_ref:
1052
+ if isinstance(f, Filter):
1053
+ filter_objects.append(f)
1054
+ elif has_filter_attributes(f):
1055
+ filter_objects.append(Filter(f.field_name, f.operation, f.value))
1056
+
1057
+ return canonicalize_filters(filter_objects)
1058
+
1059
+
1060
+ def get_pipeline_metrics() -> "list[dict[str, Any]]":
1061
+ """Return metrics for the shared statement pipeline cache when enabled."""
1062
+
1063
+ return get_statement_pipeline_metrics()
1064
+
1065
+
1066
+ def reset_pipeline_registry() -> None:
1067
+ """Clear shared statement pipeline caches and metrics."""
1068
+
1069
+ reset_statement_pipeline_cache()