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
@@ -0,0 +1,952 @@
1
+ """Filter system for SQL statement manipulation.
2
+
3
+ This module provides filters that can be applied to SQL statements to add
4
+ WHERE clauses, ORDER BY clauses, LIMIT/OFFSET, and other modifications.
5
+
6
+ Components:
7
+ - StatementFilter: Abstract base class for all filters
8
+ - BeforeAfterFilter: Date range filtering
9
+ - InCollectionFilter: IN clause filtering
10
+ - LimitOffsetFilter: Pagination support
11
+ - OrderByFilter: Sorting support
12
+ - SearchFilter: Text search filtering
13
+ - Various collection and negation filters
14
+
15
+ Features:
16
+ - Parameter conflict resolution
17
+ - Type-safe filter application
18
+ - Cacheable filter configurations
19
+ """
20
+
21
+ import uuid
22
+ from abc import ABC, abstractmethod
23
+ from collections import abc
24
+ from collections.abc import Sequence
25
+ from datetime import datetime
26
+ from typing import TYPE_CHECKING, Any, Generic, Literal, TypeAlias
27
+
28
+ import sqlglot
29
+ from mypy_extensions import mypyc_attr
30
+ from sqlglot import exp
31
+ from typing_extensions import TypeVar
32
+
33
+ from sqlspec.utils.type_guards import has_field_name
34
+
35
+ if TYPE_CHECKING:
36
+ from sqlglot.expressions import Condition
37
+
38
+ from sqlspec.core.statement import SQL
39
+
40
+ __all__ = (
41
+ "AnyCollectionFilter",
42
+ "BeforeAfterFilter",
43
+ "FilterTypeT",
44
+ "FilterTypes",
45
+ "InAnyFilter",
46
+ "InCollectionFilter",
47
+ "LimitOffsetFilter",
48
+ "NotAnyCollectionFilter",
49
+ "NotInCollectionFilter",
50
+ "NotInSearchFilter",
51
+ "NotNullFilter",
52
+ "NullFilter",
53
+ "OffsetPagination",
54
+ "OnBeforeAfterFilter",
55
+ "OrderByFilter",
56
+ "PaginationFilter",
57
+ "SearchFilter",
58
+ "StatementFilter",
59
+ "apply_filter",
60
+ "canonicalize_filters",
61
+ "create_filters",
62
+ )
63
+
64
+ T = TypeVar("T")
65
+ FilterTypeT = TypeVar("FilterTypeT", bound="StatementFilter")
66
+
67
+
68
+ @mypyc_attr(allow_interpreted_subclasses=True)
69
+ class StatementFilter(ABC):
70
+ """Abstract base class for filters that can be appended to a statement."""
71
+
72
+ __slots__ = ()
73
+
74
+ @abstractmethod
75
+ def append_to_statement(self, statement: "SQL") -> "SQL":
76
+ """Append the filter to the statement.
77
+
78
+ This method should modify the SQL expression only, not the parameters.
79
+ Parameters should be provided via extract_parameters().
80
+ """
81
+
82
+ def extract_parameters(self) -> "tuple[list[Any], dict[str, Any]]":
83
+ """Extract parameters that this filter contributes.
84
+
85
+ Returns:
86
+ Tuple of (positional_parameters, named_parameters) where:
87
+ - positional_parameters: List of positional parameter values
88
+ - named_parameters: Dict of parameter name to value
89
+ """
90
+ return [], {}
91
+
92
+ def _resolve_parameter_conflicts(self, statement: "SQL", proposed_names: "list[str]") -> "list[str]":
93
+ """Resolve parameter name conflicts.
94
+
95
+ Args:
96
+ statement: The SQL statement to check for existing parameters
97
+ proposed_names: List of proposed parameter names
98
+
99
+ Returns:
100
+ List of resolved parameter names (same length as proposed_names)
101
+ """
102
+ existing_params = set(statement.named_parameters.keys())
103
+ existing_params.update(statement.parameters.keys() if isinstance(statement.parameters, dict) else [])
104
+
105
+ resolved_names = []
106
+ for name in proposed_names:
107
+ if name in existing_params:
108
+ unique_suffix = str(uuid.uuid4()).replace("-", "")[:8]
109
+ resolved_name = f"{name}_{unique_suffix}"
110
+ else:
111
+ resolved_name = name
112
+ resolved_names.append(resolved_name)
113
+ existing_params.add(resolved_name)
114
+
115
+ return resolved_names
116
+
117
+ @abstractmethod
118
+ def get_cache_key(self) -> "tuple[Any, ...]":
119
+ """Return a cache key for this filter's configuration.
120
+
121
+ Returns:
122
+ Tuple of hashable values representing the filter's configuration
123
+ """
124
+
125
+
126
+ class BeforeAfterFilter(StatementFilter):
127
+ """Filter for datetime range queries.
128
+
129
+ Applies WHERE clauses for before/after datetime filtering.
130
+ """
131
+
132
+ __slots__ = ("_after", "_before", "_field_name")
133
+
134
+ def __init__(self, field_name: str, before: datetime | None = None, after: datetime | None = None) -> None:
135
+ self._field_name = field_name
136
+ self._before = before
137
+ self._after = after
138
+
139
+ @property
140
+ def field_name(self) -> str:
141
+ return self._field_name
142
+
143
+ @property
144
+ def before(self) -> datetime | None:
145
+ return self._before
146
+
147
+ @property
148
+ def after(self) -> datetime | None:
149
+ return self._after
150
+
151
+ def get_param_names(self) -> "list[str]":
152
+ """Get parameter names without storing them."""
153
+ names = []
154
+ if self.before:
155
+ names.append(f"{self.field_name}_before")
156
+ if self.after:
157
+ names.append(f"{self.field_name}_after")
158
+ return names
159
+
160
+ def extract_parameters(self) -> "tuple[list[Any], dict[str, Any]]":
161
+ """Extract filter parameters."""
162
+ named_parameters = {}
163
+ param_names = self.get_param_names()
164
+ param_idx = 0
165
+ if self.before:
166
+ named_parameters[param_names[param_idx]] = self.before
167
+ param_idx += 1
168
+ if self.after:
169
+ named_parameters[param_names[param_idx]] = self.after
170
+ return [], named_parameters
171
+
172
+ def append_to_statement(self, statement: "SQL") -> "SQL":
173
+ """Apply filter to SQL expression only."""
174
+ conditions: list[Condition] = []
175
+ col_expr = exp.column(self.field_name)
176
+
177
+ proposed_names = self.get_param_names()
178
+ if not proposed_names:
179
+ return statement
180
+
181
+ resolved_names = self._resolve_parameter_conflicts(statement, proposed_names)
182
+
183
+ param_idx = 0
184
+ result = statement
185
+ if self.before:
186
+ before_param_name = resolved_names[param_idx]
187
+ param_idx += 1
188
+ conditions.append(exp.LT(this=col_expr, expression=exp.Placeholder(this=before_param_name)))
189
+ result = result.add_named_parameter(before_param_name, self.before)
190
+
191
+ if self.after:
192
+ after_param_name = resolved_names[param_idx]
193
+ conditions.append(exp.GT(this=col_expr, expression=exp.Placeholder(this=after_param_name)))
194
+ result = result.add_named_parameter(after_param_name, self.after)
195
+
196
+ final_condition = conditions[0]
197
+ for cond in conditions[1:]:
198
+ final_condition = exp.And(this=final_condition, expression=cond)
199
+ return result.where(final_condition)
200
+
201
+ def get_cache_key(self) -> "tuple[Any, ...]":
202
+ """Return cache key for this filter configuration."""
203
+ return ("BeforeAfterFilter", self.field_name, self.before, self.after)
204
+
205
+
206
+ class OnBeforeAfterFilter(StatementFilter):
207
+ """Filter for inclusive datetime range queries.
208
+
209
+ Applies WHERE clauses for on-or-before/on-or-after datetime filtering.
210
+ """
211
+
212
+ __slots__ = ("_field_name", "_on_or_after", "_on_or_before")
213
+
214
+ def __init__(
215
+ self, field_name: str, on_or_before: datetime | None = None, on_or_after: datetime | None = None
216
+ ) -> None:
217
+ self._field_name = field_name
218
+ self._on_or_before = on_or_before
219
+ self._on_or_after = on_or_after
220
+
221
+ @property
222
+ def field_name(self) -> str:
223
+ return self._field_name
224
+
225
+ @property
226
+ def on_or_before(self) -> datetime | None:
227
+ return self._on_or_before
228
+
229
+ @property
230
+ def on_or_after(self) -> datetime | None:
231
+ return self._on_or_after
232
+
233
+ def get_param_names(self) -> "list[str]":
234
+ """Get parameter names without storing them."""
235
+ names = []
236
+ if self.on_or_before:
237
+ names.append(f"{self.field_name}_on_or_before")
238
+ if self.on_or_after:
239
+ names.append(f"{self.field_name}_on_or_after")
240
+ return names
241
+
242
+ def extract_parameters(self) -> "tuple[list[Any], dict[str, Any]]":
243
+ """Extract filter parameters."""
244
+ named_parameters = {}
245
+ param_names = self.get_param_names()
246
+ param_idx = 0
247
+ if self.on_or_before:
248
+ named_parameters[param_names[param_idx]] = self.on_or_before
249
+ param_idx += 1
250
+ if self.on_or_after:
251
+ named_parameters[param_names[param_idx]] = self.on_or_after
252
+ return [], named_parameters
253
+
254
+ def append_to_statement(self, statement: "SQL") -> "SQL":
255
+ conditions: list[Condition] = []
256
+
257
+ proposed_names = self.get_param_names()
258
+ if not proposed_names:
259
+ return statement
260
+
261
+ resolved_names = self._resolve_parameter_conflicts(statement, proposed_names)
262
+
263
+ param_idx = 0
264
+ result = statement
265
+ if self.on_or_before:
266
+ before_param_name = resolved_names[param_idx]
267
+ param_idx += 1
268
+ conditions.append(
269
+ exp.LTE(this=exp.column(self.field_name), expression=exp.Placeholder(this=before_param_name))
270
+ )
271
+ result = result.add_named_parameter(before_param_name, self.on_or_before)
272
+
273
+ if self.on_or_after:
274
+ after_param_name = resolved_names[param_idx]
275
+ conditions.append(
276
+ exp.GTE(this=exp.column(self.field_name), expression=exp.Placeholder(this=after_param_name))
277
+ )
278
+ result = result.add_named_parameter(after_param_name, self.on_or_after)
279
+
280
+ final_condition = conditions[0]
281
+ for cond in conditions[1:]:
282
+ final_condition = exp.And(this=final_condition, expression=cond)
283
+ return result.where(final_condition)
284
+
285
+ def get_cache_key(self) -> "tuple[Any, ...]":
286
+ """Return cache key for this filter configuration."""
287
+ return ("OnBeforeAfterFilter", self.field_name, self.on_or_before, self.on_or_after)
288
+
289
+
290
+ class InAnyFilter(StatementFilter, ABC, Generic[T]):
291
+ """Base class for collection-based filters that support ANY operations."""
292
+
293
+ __slots__ = ()
294
+
295
+ def append_to_statement(self, statement: "SQL") -> "SQL":
296
+ raise NotImplementedError
297
+
298
+
299
+ class InCollectionFilter(InAnyFilter[T]):
300
+ """Filter for IN clause queries.
301
+
302
+ Constructs WHERE ... IN (...) clauses.
303
+ """
304
+
305
+ __slots__ = ("_field_name", "_values")
306
+
307
+ def __init__(self, field_name: str, values: abc.Collection[T] | None = None) -> None:
308
+ self._field_name = field_name
309
+ self._values = values
310
+
311
+ @property
312
+ def field_name(self) -> str:
313
+ return self._field_name
314
+
315
+ @property
316
+ def values(self) -> abc.Collection[T] | None:
317
+ return self._values
318
+
319
+ def get_param_names(self) -> "list[str]":
320
+ """Get parameter names without storing them."""
321
+ if not self.values:
322
+ return []
323
+ return [f"{self.field_name}_in_{i}" for i, _ in enumerate(self.values)]
324
+
325
+ def extract_parameters(self) -> "tuple[list[Any], dict[str, Any]]":
326
+ """Extract filter parameters."""
327
+ named_parameters = {}
328
+ if self.values:
329
+ param_names = self.get_param_names()
330
+ for i, value in enumerate(self.values):
331
+ named_parameters[param_names[i]] = value
332
+ return [], named_parameters
333
+
334
+ def append_to_statement(self, statement: "SQL") -> "SQL":
335
+ if self.values is None:
336
+ return statement
337
+
338
+ if not self.values:
339
+ return statement.where(exp.false())
340
+
341
+ resolved_names = self._resolve_parameter_conflicts(statement, self.get_param_names())
342
+
343
+ placeholder_expressions: list[exp.Placeholder] = [
344
+ exp.Placeholder(this=param_name) for param_name in resolved_names
345
+ ]
346
+
347
+ result = statement.where(exp.In(this=exp.column(self.field_name), expressions=placeholder_expressions))
348
+
349
+ for resolved_name, value in zip(resolved_names, self.values, strict=False):
350
+ result = result.add_named_parameter(resolved_name, value)
351
+ return result
352
+
353
+ def get_cache_key(self) -> "tuple[Any, ...]":
354
+ """Return cache key for this filter configuration."""
355
+ values_tuple = tuple(self.values) if self.values is not None else None
356
+ return ("InCollectionFilter", self.field_name, values_tuple)
357
+
358
+
359
+ class NotInCollectionFilter(InAnyFilter[T]):
360
+ """Filter for NOT IN clause queries.
361
+
362
+ Constructs WHERE ... NOT IN (...) clauses.
363
+ """
364
+
365
+ __slots__ = ("_field_name", "_values")
366
+
367
+ def __init__(self, field_name: str, values: abc.Collection[T] | None = None) -> None:
368
+ self._field_name = field_name
369
+ self._values = values
370
+
371
+ @property
372
+ def field_name(self) -> str:
373
+ return self._field_name
374
+
375
+ @property
376
+ def values(self) -> abc.Collection[T] | None:
377
+ return self._values
378
+
379
+ def get_param_names(self) -> "list[str]":
380
+ """Get parameter names without storing them."""
381
+ if not self.values:
382
+ return []
383
+ # Use object id to ensure uniqueness between instances
384
+ return [f"{self.field_name}_notin_{i}_{id(self)}" for i, _ in enumerate(self.values)]
385
+
386
+ def extract_parameters(self) -> "tuple[list[Any], dict[str, Any]]":
387
+ """Extract filter parameters."""
388
+ named_parameters = {}
389
+ if self.values:
390
+ param_names = self.get_param_names()
391
+ for i, value in enumerate(self.values):
392
+ named_parameters[param_names[i]] = value
393
+ return [], named_parameters
394
+
395
+ def append_to_statement(self, statement: "SQL") -> "SQL":
396
+ if self.values is None or not self.values:
397
+ return statement
398
+
399
+ resolved_names = self._resolve_parameter_conflicts(statement, self.get_param_names())
400
+
401
+ placeholder_expressions: list[exp.Placeholder] = [
402
+ exp.Placeholder(this=param_name) for param_name in resolved_names
403
+ ]
404
+
405
+ result = statement.where(
406
+ exp.Not(this=exp.In(this=exp.column(self.field_name), expressions=placeholder_expressions))
407
+ )
408
+
409
+ for resolved_name, value in zip(resolved_names, self.values, strict=False):
410
+ result = result.add_named_parameter(resolved_name, value)
411
+ return result
412
+
413
+ def get_cache_key(self) -> "tuple[Any, ...]":
414
+ """Return cache key for this filter configuration."""
415
+ values_tuple = tuple(self.values) if self.values is not None else None
416
+ return ("NotInCollectionFilter", self.field_name, values_tuple)
417
+
418
+
419
+ class AnyCollectionFilter(InAnyFilter[T]):
420
+ """Filter for PostgreSQL-style ANY clause queries.
421
+
422
+ Constructs WHERE column_name = ANY (array_expression) clauses.
423
+ """
424
+
425
+ __slots__ = ("_field_name", "_values")
426
+
427
+ def __init__(self, field_name: str, values: abc.Collection[T] | None = None) -> None:
428
+ self._field_name = field_name
429
+ self._values = values
430
+
431
+ @property
432
+ def field_name(self) -> str:
433
+ return self._field_name
434
+
435
+ @property
436
+ def values(self) -> abc.Collection[T] | None:
437
+ return self._values
438
+
439
+ def get_param_names(self) -> "list[str]":
440
+ """Get parameter names without storing them."""
441
+ if not self.values:
442
+ return []
443
+ return [f"{self.field_name}_any_{i}" for i, _ in enumerate(self.values)]
444
+
445
+ def extract_parameters(self) -> "tuple[list[Any], dict[str, Any]]":
446
+ """Extract filter parameters."""
447
+ named_parameters = {}
448
+ if self.values:
449
+ param_names = self.get_param_names()
450
+ for i, value in enumerate(self.values):
451
+ named_parameters[param_names[i]] = value
452
+ return [], named_parameters
453
+
454
+ def append_to_statement(self, statement: "SQL") -> "SQL":
455
+ if self.values is None:
456
+ return statement
457
+
458
+ if not self.values:
459
+ return statement.where(exp.false())
460
+
461
+ resolved_names = self._resolve_parameter_conflicts(statement, self.get_param_names())
462
+
463
+ placeholder_expressions: list[exp.Expression] = [
464
+ exp.Placeholder(this=param_name) for param_name in resolved_names
465
+ ]
466
+
467
+ array_expr = exp.Array(expressions=placeholder_expressions)
468
+ result = statement.where(exp.EQ(this=exp.column(self.field_name), expression=exp.Any(this=array_expr)))
469
+
470
+ for resolved_name, value in zip(resolved_names, self.values, strict=False):
471
+ result = result.add_named_parameter(resolved_name, value)
472
+ return result
473
+
474
+ def get_cache_key(self) -> "tuple[Any, ...]":
475
+ """Return cache key for this filter configuration."""
476
+ values_tuple = tuple(self.values) if self.values is not None else None
477
+ return ("AnyCollectionFilter", self.field_name, values_tuple)
478
+
479
+
480
+ class NotAnyCollectionFilter(InAnyFilter[T]):
481
+ """Filter for PostgreSQL-style NOT ANY clause queries.
482
+
483
+ Constructs WHERE NOT (column_name = ANY (array_expression)) clauses.
484
+ """
485
+
486
+ __slots__ = ("_field_name", "_values")
487
+
488
+ def __init__(self, field_name: str, values: abc.Collection[T] | None = None) -> None:
489
+ self._field_name = field_name
490
+ self._values = values
491
+
492
+ @property
493
+ def field_name(self) -> str:
494
+ return self._field_name
495
+
496
+ @property
497
+ def values(self) -> abc.Collection[T] | None:
498
+ return self._values
499
+
500
+ def get_param_names(self) -> "list[str]":
501
+ """Get parameter names without storing them."""
502
+ if not self.values:
503
+ return []
504
+ return [f"{self.field_name}_not_any_{i}" for i, _ in enumerate(self.values)]
505
+
506
+ def extract_parameters(self) -> "tuple[list[Any], dict[str, Any]]":
507
+ """Extract filter parameters."""
508
+ named_parameters = {}
509
+ if self.values:
510
+ param_names = self.get_param_names()
511
+ for i, value in enumerate(self.values):
512
+ named_parameters[param_names[i]] = value
513
+ return [], named_parameters
514
+
515
+ def append_to_statement(self, statement: "SQL") -> "SQL":
516
+ if self.values is None or not self.values:
517
+ return statement
518
+
519
+ resolved_names = self._resolve_parameter_conflicts(statement, self.get_param_names())
520
+
521
+ placeholder_expressions: list[exp.Expression] = [
522
+ exp.Placeholder(this=param_name) for param_name in resolved_names
523
+ ]
524
+
525
+ array_expr = exp.Array(expressions=placeholder_expressions)
526
+ condition = exp.EQ(this=exp.column(self.field_name), expression=exp.Any(this=array_expr))
527
+ result = statement.where(exp.Not(this=condition))
528
+
529
+ for resolved_name, value in zip(resolved_names, self.values, strict=False):
530
+ result = result.add_named_parameter(resolved_name, value)
531
+ return result
532
+
533
+ def get_cache_key(self) -> "tuple[Any, ...]":
534
+ """Return cache key for this filter configuration."""
535
+ values_tuple = tuple(self.values) if self.values is not None else None
536
+ return ("NotAnyCollectionFilter", self.field_name, values_tuple)
537
+
538
+
539
+ class PaginationFilter(StatementFilter, ABC):
540
+ """Base class for pagination-related filters."""
541
+
542
+ __slots__ = ()
543
+
544
+ @abstractmethod
545
+ def append_to_statement(self, statement: "SQL") -> "SQL":
546
+ raise NotImplementedError
547
+
548
+
549
+ class LimitOffsetFilter(PaginationFilter):
550
+ """Filter for LIMIT and OFFSET clauses.
551
+
552
+ Adds pagination support through LIMIT/OFFSET SQL clauses.
553
+ """
554
+
555
+ __slots__ = ("_limit", "_offset")
556
+
557
+ def __init__(self, limit: int, offset: int) -> None:
558
+ self._limit = limit
559
+ self._offset = offset
560
+
561
+ @property
562
+ def limit(self) -> int:
563
+ return self._limit
564
+
565
+ @property
566
+ def offset(self) -> int:
567
+ return self._offset
568
+
569
+ def get_param_names(self) -> "list[str]":
570
+ """Get parameter names without storing them."""
571
+ return ["limit", "offset"]
572
+
573
+ def extract_parameters(self) -> "tuple[list[Any], dict[str, Any]]":
574
+ """Extract filter parameters."""
575
+ param_names = self.get_param_names()
576
+ return [], {param_names[0]: self.limit, param_names[1]: self.offset}
577
+
578
+ def append_to_statement(self, statement: "SQL") -> "SQL":
579
+ resolved_names = self._resolve_parameter_conflicts(statement, self.get_param_names())
580
+ limit_param_name, offset_param_name = resolved_names
581
+
582
+ limit_placeholder = exp.Placeholder(this=limit_param_name)
583
+ offset_placeholder = exp.Placeholder(this=offset_param_name)
584
+
585
+ if statement.statement_expression is not None:
586
+ current_statement = statement.statement_expression.copy()
587
+ elif not statement.statement_config.enable_parsing:
588
+ current_statement = exp.Select().from_(f"({statement.raw_sql})")
589
+ else:
590
+ try:
591
+ current_statement = sqlglot.parse_one(statement.raw_sql, dialect=statement.dialect)
592
+ except Exception:
593
+ current_statement = exp.Select().from_(f"({statement.raw_sql})")
594
+
595
+ if isinstance(current_statement, exp.Select):
596
+ new_statement = current_statement.limit(limit_placeholder).offset(offset_placeholder)
597
+ else:
598
+ new_statement = exp.Select().from_(current_statement).limit(limit_placeholder).offset(offset_placeholder)
599
+
600
+ result = statement.copy(statement=new_statement)
601
+ result = result.add_named_parameter(limit_param_name, self.limit)
602
+ return result.add_named_parameter(offset_param_name, self.offset)
603
+
604
+ def get_cache_key(self) -> "tuple[Any, ...]":
605
+ """Return cache key for this filter configuration."""
606
+ return ("LimitOffsetFilter", self.limit, self.offset)
607
+
608
+
609
+ class OrderByFilter(StatementFilter):
610
+ """Filter for ORDER BY clauses.
611
+
612
+ Adds sorting capability to SQL queries.
613
+ """
614
+
615
+ __slots__ = ("_field_name", "_sort_order")
616
+
617
+ def __init__(self, field_name: str, sort_order: Literal["asc", "desc"] = "asc") -> None:
618
+ self._field_name = field_name
619
+ self._sort_order = sort_order
620
+
621
+ @property
622
+ def field_name(self) -> str:
623
+ return self._field_name
624
+
625
+ @property
626
+ def sort_order(self) -> Literal["asc", "desc"]:
627
+ return self._sort_order # pyright: ignore
628
+
629
+ def extract_parameters(self) -> "tuple[list[Any], dict[str, Any]]":
630
+ """Extract filter parameters."""
631
+ return [], {}
632
+
633
+ def append_to_statement(self, statement: "SQL") -> "SQL":
634
+ converted_sort_order = self.sort_order.lower()
635
+ if converted_sort_order not in {"asc", "desc"}:
636
+ converted_sort_order = "asc"
637
+
638
+ col_expr = exp.column(self.field_name)
639
+ order_expr = col_expr.desc() if converted_sort_order == "desc" else col_expr.asc()
640
+
641
+ if statement.statement_expression is not None:
642
+ current_statement = statement.statement_expression.copy()
643
+ elif not statement.statement_config.enable_parsing:
644
+ current_statement = exp.Select().from_(f"({statement.raw_sql})")
645
+ else:
646
+ try:
647
+ current_statement = sqlglot.parse_one(statement.raw_sql, dialect=statement.dialect)
648
+ except Exception:
649
+ current_statement = exp.Select().from_(f"({statement.raw_sql})")
650
+
651
+ if isinstance(current_statement, exp.Select):
652
+ new_statement = current_statement.order_by(order_expr)
653
+ else:
654
+ new_statement = exp.Select().from_(current_statement).order_by(order_expr)
655
+
656
+ return statement.copy(statement=new_statement)
657
+
658
+ def get_cache_key(self) -> "tuple[Any, ...]":
659
+ """Return cache key for this filter configuration."""
660
+ return ("OrderByFilter", self.field_name, self.sort_order)
661
+
662
+
663
+ class SearchFilter(StatementFilter):
664
+ """Filter for text search queries.
665
+
666
+ Constructs WHERE field_name LIKE '%value%' clauses.
667
+ """
668
+
669
+ __slots__ = ("_field_name", "_ignore_case", "_value")
670
+
671
+ def __init__(self, field_name: str | set[str], value: str | None, ignore_case: bool | None = False) -> None:
672
+ self._field_name = field_name
673
+ self._value = value
674
+ self._ignore_case = ignore_case
675
+
676
+ @property
677
+ def field_name(self) -> "str | set[str]":
678
+ return self._field_name
679
+
680
+ @property
681
+ def value(self) -> str | None:
682
+ return self._value
683
+
684
+ @property
685
+ def ignore_case(self) -> bool | None:
686
+ return self._ignore_case
687
+
688
+ def get_param_name(self) -> str | None:
689
+ """Get parameter name without storing it."""
690
+ if not self.value:
691
+ return None
692
+ if isinstance(self.field_name, str):
693
+ return f"{self.field_name}_search"
694
+ return "search_value"
695
+
696
+ def extract_parameters(self) -> "tuple[list[Any], dict[str, Any]]":
697
+ """Extract filter parameters."""
698
+ named_parameters = {}
699
+ param_name = self.get_param_name()
700
+ if self.value and param_name:
701
+ search_value_with_wildcards = f"%{self.value}%"
702
+ named_parameters[param_name] = search_value_with_wildcards
703
+ return [], named_parameters
704
+
705
+ def append_to_statement(self, statement: "SQL") -> "SQL":
706
+ param_name = self.get_param_name()
707
+ if not self.value or not param_name:
708
+ return statement
709
+
710
+ resolved_names = self._resolve_parameter_conflicts(statement, [param_name])
711
+ param_name = resolved_names[0]
712
+
713
+ pattern_expr = exp.Placeholder(this=param_name)
714
+ like_op = exp.ILike if self.ignore_case else exp.Like
715
+
716
+ if isinstance(self.field_name, str):
717
+ result = statement.where(like_op(this=exp.column(self.field_name), expression=pattern_expr))
718
+ elif isinstance(self.field_name, set) and self.field_name:
719
+ field_conditions: list[Condition] = [
720
+ like_op(this=exp.column(field), expression=pattern_expr) for field in self.field_name
721
+ ]
722
+ if not field_conditions:
723
+ return statement
724
+
725
+ final_condition: Condition = field_conditions[0]
726
+ for cond in field_conditions[1:]:
727
+ final_condition = exp.Or(this=final_condition, expression=cond)
728
+ result = statement.where(final_condition)
729
+ else:
730
+ result = statement
731
+
732
+ search_value_with_wildcards = f"%{self.value}%"
733
+ return result.add_named_parameter(param_name, search_value_with_wildcards)
734
+
735
+ def get_cache_key(self) -> "tuple[Any, ...]":
736
+ """Return cache key for this filter configuration."""
737
+ field_names = tuple(sorted(self.field_name)) if isinstance(self.field_name, set) else self.field_name
738
+ return ("SearchFilter", field_names, self.value, self.ignore_case)
739
+
740
+
741
+ class NullFilter(StatementFilter):
742
+ """Filter for IS NULL queries.
743
+
744
+ Constructs WHERE field_name IS NULL clauses.
745
+ """
746
+
747
+ __slots__ = ("_field_name",)
748
+
749
+ def __init__(self, field_name: str) -> None:
750
+ self._field_name = field_name
751
+
752
+ @property
753
+ def field_name(self) -> str:
754
+ return self._field_name
755
+
756
+ def extract_parameters(self) -> "tuple[list[Any], dict[str, Any]]":
757
+ """Extract filter parameters.
758
+
759
+ Returns empty parameters since IS NULL requires no values.
760
+ """
761
+ return [], {}
762
+
763
+ def append_to_statement(self, statement: "SQL") -> "SQL":
764
+ """Apply IS NULL filter to SQL expression."""
765
+ col_expr = exp.column(self.field_name)
766
+ is_null_condition = exp.Is(this=col_expr, expression=exp.Null())
767
+ return statement.where(is_null_condition)
768
+
769
+ def get_cache_key(self) -> "tuple[Any, ...]":
770
+ """Return cache key for this filter configuration."""
771
+ return ("NullFilter", self.field_name)
772
+
773
+
774
+ class NotNullFilter(StatementFilter):
775
+ """Filter for IS NOT NULL queries.
776
+
777
+ Constructs WHERE field_name IS NOT NULL clauses.
778
+ """
779
+
780
+ __slots__ = ("_field_name",)
781
+
782
+ def __init__(self, field_name: str) -> None:
783
+ self._field_name = field_name
784
+
785
+ @property
786
+ def field_name(self) -> str:
787
+ return self._field_name
788
+
789
+ def extract_parameters(self) -> "tuple[list[Any], dict[str, Any]]":
790
+ """Extract filter parameters.
791
+
792
+ Returns empty parameters since IS NOT NULL requires no values.
793
+ """
794
+ return [], {}
795
+
796
+ def append_to_statement(self, statement: "SQL") -> "SQL":
797
+ """Apply IS NOT NULL filter to SQL expression."""
798
+ col_expr = exp.column(self.field_name)
799
+ is_null_condition = exp.Is(this=col_expr, expression=exp.Null())
800
+ is_not_null_condition = exp.Not(this=is_null_condition)
801
+ return statement.where(is_not_null_condition)
802
+
803
+ def get_cache_key(self) -> "tuple[Any, ...]":
804
+ """Return cache key for this filter configuration."""
805
+ return ("NotNullFilter", self.field_name)
806
+
807
+
808
+ class NotInSearchFilter(SearchFilter):
809
+ """Filter for negated text search queries.
810
+
811
+ Constructs WHERE field_name NOT LIKE '%value%' clauses.
812
+ """
813
+
814
+ def get_param_name(self) -> str | None:
815
+ """Get parameter name without storing it."""
816
+ if not self.value:
817
+ return None
818
+ if isinstance(self.field_name, str):
819
+ return f"{self.field_name}_not_search"
820
+ return "not_search_value"
821
+
822
+ def extract_parameters(self) -> "tuple[list[Any], dict[str, Any]]":
823
+ """Extract filter parameters."""
824
+ named_parameters = {}
825
+ param_name = self.get_param_name()
826
+ if self.value and param_name:
827
+ search_value_with_wildcards = f"%{self.value}%"
828
+ named_parameters[param_name] = search_value_with_wildcards
829
+ return [], named_parameters
830
+
831
+ def append_to_statement(self, statement: "SQL") -> "SQL":
832
+ param_name = self.get_param_name()
833
+ if not self.value or not param_name:
834
+ return statement
835
+
836
+ resolved_names = self._resolve_parameter_conflicts(statement, [param_name])
837
+ param_name = resolved_names[0]
838
+
839
+ pattern_expr = exp.Placeholder(this=param_name)
840
+ like_op = exp.ILike if self.ignore_case else exp.Like
841
+
842
+ result = statement
843
+ if isinstance(self.field_name, str):
844
+ result = statement.where(exp.Not(this=like_op(this=exp.column(self.field_name), expression=pattern_expr)))
845
+ elif isinstance(self.field_name, set) and self.field_name:
846
+ field_conditions: list[Condition] = [
847
+ exp.Not(this=like_op(this=exp.column(field), expression=pattern_expr)) for field in self.field_name
848
+ ]
849
+ if not field_conditions:
850
+ return statement
851
+
852
+ final_condition: Condition = field_conditions[0]
853
+ if len(field_conditions) > 1:
854
+ for cond in field_conditions[1:]:
855
+ final_condition = exp.And(this=final_condition, expression=cond)
856
+ result = statement.where(final_condition)
857
+
858
+ search_value_with_wildcards = f"%{self.value}%"
859
+ return result.add_named_parameter(param_name, search_value_with_wildcards)
860
+
861
+ def get_cache_key(self) -> "tuple[Any, ...]":
862
+ """Return cache key for this filter configuration."""
863
+ field_names = tuple(sorted(self.field_name)) if isinstance(self.field_name, set) else self.field_name
864
+ return ("NotInSearchFilter", field_names, self.value, self.ignore_case)
865
+
866
+
867
+ class OffsetPagination(Generic[T]):
868
+ """Container for data returned using limit/offset pagination."""
869
+
870
+ __slots__ = ("items", "limit", "offset", "total")
871
+
872
+ items: Sequence[T]
873
+ limit: int
874
+ offset: int
875
+ total: int
876
+
877
+ def __init__(self, items: Sequence[T], limit: int, offset: int, total: int) -> None:
878
+ """Initialize OffsetPagination.
879
+
880
+ Args:
881
+ items: List of data being sent as part of the response.
882
+ limit: Maximal number of items to send.
883
+ offset: Offset from the beginning of the query. Identical to an index.
884
+ total: Total number of items.
885
+ """
886
+ self.items = items
887
+ self.limit = limit
888
+ self.offset = offset
889
+ self.total = total
890
+
891
+
892
+ def apply_filter(statement: "SQL", filter_obj: StatementFilter) -> "SQL":
893
+ """Apply a statement filter to a SQL query object.
894
+
895
+ Args:
896
+ statement: The SQL query object to modify.
897
+ filter_obj: The filter to apply.
898
+
899
+ Returns:
900
+ The modified query object.
901
+ """
902
+ return filter_obj.append_to_statement(statement)
903
+
904
+
905
+ FilterTypes: TypeAlias = (
906
+ BeforeAfterFilter
907
+ | OnBeforeAfterFilter
908
+ | InCollectionFilter[Any]
909
+ | LimitOffsetFilter
910
+ | OrderByFilter
911
+ | SearchFilter
912
+ | NotInCollectionFilter[Any]
913
+ | NotInSearchFilter
914
+ | AnyCollectionFilter[Any]
915
+ | NotAnyCollectionFilter[Any]
916
+ | NullFilter
917
+ | NotNullFilter
918
+ )
919
+
920
+
921
+ def create_filters(filters: "list[StatementFilter]") -> "tuple[StatementFilter, ...]":
922
+ """Convert mutable filters to immutable tuple.
923
+
924
+ Since StatementFilter classes are now immutable (with read-only properties),
925
+ we just need to convert to a tuple for consistent sharing.
926
+
927
+ Args:
928
+ filters: List of StatementFilter objects (already immutable)
929
+
930
+ Returns:
931
+ Tuple of StatementFilter objects
932
+ """
933
+ return tuple(filters)
934
+
935
+
936
+ def _filter_sort_key(f: "StatementFilter") -> "tuple[str, str]":
937
+ """Sort key for canonicalizing filters by type and field_name."""
938
+ class_name = type(f).__name__
939
+ field_name = str(f.field_name) if has_field_name(f) else ""
940
+ return (class_name, field_name)
941
+
942
+
943
+ def canonicalize_filters(filters: "list[StatementFilter]") -> "tuple[StatementFilter, ...]":
944
+ """Sort filters by type and field_name for consistent hashing.
945
+
946
+ Args:
947
+ filters: List of StatementFilter objects
948
+
949
+ Returns:
950
+ Canonically sorted tuple of filters
951
+ """
952
+ return tuple(sorted(filters, key=_filter_sort_key))