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,1503 @@
1
+ """SQL statement and configuration management."""
2
+
3
+ import uuid
4
+ from collections.abc import Mapping, Sequence
5
+ from typing import TYPE_CHECKING, Any, Final, TypeAlias
6
+
7
+ import sqlglot
8
+ from mypy_extensions import mypyc_attr
9
+ from sqlglot import exp
10
+ from sqlglot.errors import ParseError
11
+
12
+ import sqlspec.exceptions
13
+ from sqlspec.core import pipeline
14
+ from sqlspec.core.cache import FiltersView
15
+ from sqlspec.core.compiler import OperationProfile, OperationType
16
+ from sqlspec.core.explain import ExplainFormat, ExplainOptions
17
+ from sqlspec.core.parameters import (
18
+ ParameterConverter,
19
+ ParameterProfile,
20
+ ParameterStyle,
21
+ ParameterStyleConfig,
22
+ ParameterValidator,
23
+ )
24
+ from sqlspec.core.query_modifiers import (
25
+ apply_limit,
26
+ apply_offset,
27
+ apply_select_only,
28
+ apply_where,
29
+ create_between_condition,
30
+ create_condition,
31
+ create_in_condition,
32
+ create_not_in_condition,
33
+ expr_eq,
34
+ expr_gt,
35
+ expr_gte,
36
+ expr_ilike,
37
+ expr_is_not_null,
38
+ expr_is_null,
39
+ expr_like,
40
+ expr_lt,
41
+ expr_lte,
42
+ expr_neq,
43
+ extract_column_name,
44
+ safe_modify_with_cte,
45
+ )
46
+ from sqlspec.typing import Empty, EmptyEnum
47
+ from sqlspec.utils.logging import get_logger
48
+ from sqlspec.utils.type_guards import is_statement_filter, supports_where
49
+
50
+ if TYPE_CHECKING:
51
+ from collections.abc import Callable
52
+
53
+ from sqlglot.dialects.dialect import DialectType
54
+
55
+ from sqlspec.builder import QueryBuilder
56
+ from sqlspec.core.filters import StatementFilter
57
+
58
+
59
+ __all__ = (
60
+ "SQL",
61
+ "ProcessedState",
62
+ "Statement",
63
+ "StatementConfig",
64
+ "get_default_config",
65
+ "get_default_parameter_config",
66
+ )
67
+ logger = get_logger("sqlspec.core.statement")
68
+
69
+ RETURNS_ROWS_OPERATIONS: Final = {"SELECT", "WITH", "VALUES", "TABLE", "SHOW", "DESCRIBE", "PRAGMA"}
70
+ MODIFYING_OPERATIONS: Final = {"INSERT", "UPDATE", "DELETE", "MERGE", "UPSERT"}
71
+ _ORDER_PARTS_COUNT: Final = 2
72
+ _MAX_PARAM_COLLISION_ATTEMPTS: Final = 1000
73
+
74
+
75
+ SQL_CONFIG_SLOTS: Final = (
76
+ "dialect",
77
+ "enable_analysis",
78
+ "enable_caching",
79
+ "enable_expression_simplification",
80
+ "enable_parameter_type_wrapping",
81
+ "enable_parsing",
82
+ "enable_transformations",
83
+ "enable_validation",
84
+ "execution_mode",
85
+ "execution_args",
86
+ "output_transformer",
87
+ "statement_transformers",
88
+ "parameter_config",
89
+ "parameter_converter",
90
+ "parameter_validator",
91
+ )
92
+
93
+ PROCESSED_STATE_SLOTS: Final = (
94
+ "compiled_sql",
95
+ "execution_parameters",
96
+ "parsed_expression",
97
+ "operation_type",
98
+ "parameter_casts",
99
+ "parameter_profile",
100
+ "operation_profile",
101
+ "validation_errors",
102
+ "is_many",
103
+ )
104
+
105
+
106
+ @mypyc_attr(allow_interpreted_subclasses=False)
107
+ class ProcessedState:
108
+ """Processing results for SQL statements.
109
+
110
+ Contains the compiled SQL, execution parameters, parsed expression,
111
+ operation type, and validation errors for a processed SQL statement.
112
+ """
113
+
114
+ __slots__ = PROCESSED_STATE_SLOTS
115
+ operation_type: "OperationType"
116
+
117
+ def __init__(
118
+ self,
119
+ compiled_sql: str,
120
+ execution_parameters: Any,
121
+ parsed_expression: "exp.Expression | None" = None,
122
+ operation_type: "OperationType" = "UNKNOWN",
123
+ parameter_casts: "dict[int, str] | None" = None,
124
+ validation_errors: "list[str] | None" = None,
125
+ parameter_profile: "ParameterProfile | None" = None,
126
+ operation_profile: "OperationProfile | None" = None,
127
+ is_many: bool = False,
128
+ ) -> None:
129
+ self.compiled_sql = compiled_sql
130
+ self.execution_parameters = execution_parameters
131
+ self.parsed_expression = parsed_expression
132
+ self.operation_type = operation_type
133
+ self.parameter_casts = parameter_casts or {}
134
+ self.validation_errors = validation_errors or []
135
+ self.parameter_profile = parameter_profile or ParameterProfile.empty()
136
+ self.operation_profile = operation_profile or OperationProfile.empty()
137
+ self.is_many = is_many
138
+
139
+ def __hash__(self) -> int:
140
+ return hash((self.compiled_sql, str(self.execution_parameters), self.operation_type))
141
+
142
+
143
+ @mypyc_attr(allow_interpreted_subclasses=False)
144
+ class SQL:
145
+ """SQL statement with parameter and filter support.
146
+
147
+ Represents a SQL statement that can be compiled with parameters and filters.
148
+ Supports both positional and named parameters, statement filtering,
149
+ and various execution modes including batch operations.
150
+ """
151
+
152
+ __slots__ = (
153
+ "_dialect",
154
+ "_filters",
155
+ "_hash",
156
+ "_is_many",
157
+ "_is_script",
158
+ "_named_parameters",
159
+ "_original_parameters",
160
+ "_positional_parameters",
161
+ "_processed_state",
162
+ "_raw_expression",
163
+ "_raw_sql",
164
+ "_sql_param_counters",
165
+ "_statement_config",
166
+ )
167
+
168
+ # Type annotation for mypyc compatibility
169
+ _sql_param_counters: "dict[str, int]"
170
+
171
+ def __init__(
172
+ self,
173
+ statement: "str | exp.Expression | 'SQL'",
174
+ *parameters: "Any | StatementFilter | list[Any | StatementFilter]",
175
+ statement_config: "StatementConfig | None" = None,
176
+ is_many: bool | None = None,
177
+ **kwargs: Any,
178
+ ) -> None:
179
+ """Initialize SQL statement.
180
+
181
+ Args:
182
+ statement: SQL string, expression, or existing SQL object
183
+ *parameters: Parameters and filters
184
+ statement_config: Configuration
185
+ is_many: Mark as execute_many operation
186
+ **kwargs: Additional parameters
187
+ """
188
+ config = statement_config or self._create_auto_config(statement, parameters, kwargs)
189
+ self._statement_config = config
190
+ self._dialect = self._normalize_dialect(config.dialect)
191
+ self._processed_state: EmptyEnum | ProcessedState = Empty
192
+ self._hash: int | None = None
193
+ self._filters: list[StatementFilter] = []
194
+ self._named_parameters: dict[str, Any] = {}
195
+ self._positional_parameters: list[Any] = []
196
+ self._sql_param_counters = {}
197
+ self._is_script = False
198
+ self._raw_expression: exp.Expression | None = None
199
+
200
+ if isinstance(statement, SQL):
201
+ self._init_from_sql_object(statement)
202
+ if is_many is not None:
203
+ self._is_many = is_many
204
+ else:
205
+ if isinstance(statement, str):
206
+ self._raw_sql = statement
207
+ else:
208
+ dialect = self._dialect
209
+ self._raw_sql = statement.sql(dialect=str(dialect) if dialect else None)
210
+ self._raw_expression = statement
211
+
212
+ self._is_many = is_many if is_many is not None else self._should_auto_detect_many(parameters)
213
+
214
+ self._original_parameters = parameters
215
+ self._process_parameters(*parameters, **kwargs)
216
+
217
+ def _create_auto_config(
218
+ self, _statement: "str | exp.Expression | 'SQL'", _parameters: tuple, _kwargs: "dict[str, Any]"
219
+ ) -> "StatementConfig":
220
+ """Create default StatementConfig when none provided.
221
+
222
+ Args:
223
+ _statement: The SQL statement (unused)
224
+ _parameters: Statement parameters (unused)
225
+ _kwargs: Additional keyword arguments (unused)
226
+
227
+ Returns:
228
+ Default StatementConfig instance
229
+ """
230
+ return get_default_config()
231
+
232
+ def _normalize_dialect(self, dialect: "DialectType") -> "str | None":
233
+ """Convert dialect to string representation.
234
+
235
+ Args:
236
+ dialect: Dialect type, string, or None
237
+
238
+ Returns:
239
+ String representation of the dialect or None
240
+ """
241
+ if dialect is None:
242
+ return None
243
+ if isinstance(dialect, str):
244
+ return dialect
245
+ return dialect.__class__.__name__.lower()
246
+
247
+ def _init_from_sql_object(self, sql_obj: "SQL") -> None:
248
+ """Initialize instance attributes from existing SQL object.
249
+
250
+ Args:
251
+ sql_obj: Existing SQL object to copy from
252
+ """
253
+ self._raw_sql = sql_obj.raw_sql
254
+ self._raw_expression = sql_obj.raw_expression
255
+ self._filters = sql_obj.filters.copy()
256
+ self._named_parameters = sql_obj.named_parameters.copy()
257
+ self._positional_parameters = sql_obj.positional_parameters.copy()
258
+ self._sql_param_counters = sql_obj._sql_param_counters.copy()
259
+ self._is_many = sql_obj.is_many
260
+ self._is_script = sql_obj.is_script
261
+ if sql_obj.is_processed:
262
+ self._processed_state = sql_obj.get_processed_state()
263
+
264
+ def _should_auto_detect_many(self, parameters: tuple) -> bool:
265
+ """Detect execute_many mode from parameter structure.
266
+
267
+ Args:
268
+ parameters: Parameter tuple to analyze
269
+
270
+ Returns:
271
+ True if parameters indicate batch execution
272
+ """
273
+ if len(parameters) == 1 and isinstance(parameters[0], list):
274
+ param_list = parameters[0]
275
+ if param_list and all(isinstance(item, (tuple, list)) for item in param_list):
276
+ return len(param_list) > 1
277
+ return False
278
+
279
+ def _process_parameters(self, *parameters: Any, dialect: str | None = None, **kwargs: Any) -> None:
280
+ """Process and organize parameters and filters.
281
+
282
+ Args:
283
+ *parameters: Variable parameters and filters
284
+ dialect: SQL dialect override
285
+ **kwargs: Additional named parameters
286
+ """
287
+ if dialect is not None:
288
+ self._dialect = self._normalize_dialect(dialect)
289
+
290
+ if "is_script" in kwargs:
291
+ self._is_script = bool(kwargs.pop("is_script"))
292
+
293
+ self._filters.extend(self._extract_filters(parameters))
294
+ self._normalize_parameters(parameters)
295
+ self._named_parameters.update(kwargs)
296
+
297
+ def _extract_filters(self, parameters: "tuple[Any, ...]") -> "list[StatementFilter]":
298
+ return [p for p in parameters if is_statement_filter(p)]
299
+
300
+ def _normalize_parameters(self, parameters: "tuple[Any, ...]") -> None:
301
+ actual_params = [p for p in parameters if not is_statement_filter(p)]
302
+ if not actual_params:
303
+ return
304
+
305
+ if len(actual_params) == 1:
306
+ param = actual_params[0]
307
+ if isinstance(param, dict):
308
+ self._named_parameters.update(param)
309
+ elif isinstance(param, (list, tuple)):
310
+ if self._is_many:
311
+ self._positional_parameters = list(param)
312
+ else:
313
+ self._positional_parameters.extend(param)
314
+ else:
315
+ self._positional_parameters.append(param)
316
+ else:
317
+ self._positional_parameters.extend(actual_params)
318
+
319
+ @property
320
+ def sql(self) -> str:
321
+ """Get the raw SQL string."""
322
+ return self._raw_sql
323
+
324
+ @property
325
+ def raw_sql(self) -> str:
326
+ """Get raw SQL string (public API).
327
+
328
+ Returns:
329
+ The raw SQL string
330
+ """
331
+ return self._raw_sql
332
+
333
+ @property
334
+ def parameters(self) -> Any:
335
+ """Get the original parameters."""
336
+ if self._named_parameters:
337
+ return self._named_parameters
338
+ return self._positional_parameters or []
339
+
340
+ @property
341
+ def positional_parameters(self) -> "list[Any]":
342
+ """Get positional parameters (public API)."""
343
+ return self._positional_parameters or []
344
+
345
+ @property
346
+ def named_parameters(self) -> "dict[str, Any]":
347
+ """Get named parameters (public API)."""
348
+ return self._named_parameters
349
+
350
+ @property
351
+ def original_parameters(self) -> Any:
352
+ """Get original parameters (public API)."""
353
+ return self._original_parameters
354
+
355
+ @property
356
+ def operation_type(self) -> "OperationType":
357
+ """SQL operation type."""
358
+ if self._processed_state is Empty:
359
+ return "UNKNOWN"
360
+ return self._processed_state.operation_type
361
+
362
+ @property
363
+ def statement_config(self) -> "StatementConfig":
364
+ """Statement configuration."""
365
+ return self._statement_config
366
+
367
+ @property
368
+ def expression(self) -> "exp.Expression | None":
369
+ """SQLGlot expression."""
370
+ if self._processed_state is not Empty:
371
+ return self._processed_state.parsed_expression
372
+ return self._raw_expression
373
+
374
+ @property
375
+ def raw_expression(self) -> "exp.Expression | None":
376
+ """Original expression supplied at construction, if available."""
377
+ return self._raw_expression
378
+
379
+ @property
380
+ def filters(self) -> "list[StatementFilter]":
381
+ """Applied filters."""
382
+ return self._filters.copy()
383
+
384
+ def get_filters_view(self) -> "FiltersView":
385
+ """Get zero-copy filters view (public API).
386
+
387
+ Returns:
388
+ Read-only view of filters without copying
389
+ """
390
+ return FiltersView(self._filters)
391
+
392
+ @property
393
+ def is_processed(self) -> bool:
394
+ """Check if SQL has been processed (public API)."""
395
+ return self._processed_state is not Empty
396
+
397
+ def get_processed_state(self) -> Any:
398
+ """Get processed state (public API)."""
399
+ return self._processed_state
400
+
401
+ @property
402
+ def dialect(self) -> "str | None":
403
+ """SQL dialect."""
404
+ return self._dialect
405
+
406
+ @property
407
+ def statement_expression(self) -> "exp.Expression | None":
408
+ """Get parsed statement expression (public API).
409
+
410
+ Returns:
411
+ Parsed SQLGlot expression or None if not parsed
412
+ """
413
+ if self._processed_state is not Empty:
414
+ return self._processed_state.parsed_expression
415
+ return self._raw_expression
416
+
417
+ @property
418
+ def is_many(self) -> bool:
419
+ """Check if this is execute_many."""
420
+ return self._is_many
421
+
422
+ @property
423
+ def is_script(self) -> bool:
424
+ """Check if this is script execution."""
425
+ return self._is_script
426
+
427
+ @property
428
+ def validation_errors(self) -> "list[str]":
429
+ """Validation errors."""
430
+ if self._processed_state is Empty:
431
+ return []
432
+ return self._processed_state.validation_errors.copy()
433
+
434
+ @property
435
+ def has_errors(self) -> bool:
436
+ """Check if there are validation errors."""
437
+ return len(self.validation_errors) > 0
438
+
439
+ def returns_rows(self) -> bool:
440
+ """Check if statement returns rows.
441
+
442
+ Returns:
443
+ True if the SQL statement returns result rows
444
+ """
445
+ if self._processed_state is Empty:
446
+ self.compile()
447
+ if self._processed_state is Empty:
448
+ return False
449
+
450
+ profile = self._processed_state.operation_profile
451
+ if profile.returns_rows:
452
+ return True
453
+
454
+ op_type = self._processed_state.operation_type
455
+ if op_type in RETURNS_ROWS_OPERATIONS:
456
+ return True
457
+
458
+ if self._processed_state.parsed_expression:
459
+ expr = self._processed_state.parsed_expression
460
+ if isinstance(expr, (exp.Insert, exp.Update, exp.Delete)) and expr.args.get("returning"):
461
+ return True
462
+
463
+ return False
464
+
465
+ def is_modifying_operation(self) -> bool:
466
+ """Check if the SQL statement is a modifying operation.
467
+
468
+ Returns:
469
+ True if the operation modifies data (INSERT/UPDATE/DELETE)
470
+ """
471
+ if self._processed_state is Empty:
472
+ return False
473
+
474
+ profile = self._processed_state.operation_profile
475
+ if profile.modifies_rows:
476
+ return True
477
+
478
+ op_type = self._processed_state.operation_type
479
+ if op_type in MODIFYING_OPERATIONS:
480
+ return True
481
+
482
+ if self._processed_state.parsed_expression:
483
+ return isinstance(self._processed_state.parsed_expression, (exp.Insert, exp.Update, exp.Delete, exp.Merge))
484
+
485
+ return False
486
+
487
+ def compile(self) -> "tuple[str, Any]":
488
+ """Compile SQL statement with parameters.
489
+
490
+ Returns:
491
+ Tuple of compiled SQL string and execution parameters
492
+ """
493
+ if self._processed_state is Empty:
494
+ try:
495
+ config = self._statement_config
496
+ raw_sql = self._raw_sql
497
+ params = self._named_parameters or self._positional_parameters
498
+ is_many = self._is_many
499
+ compiled_result = pipeline.compile_with_pipeline(
500
+ config, raw_sql, params, is_many=is_many, expression=self._raw_expression
501
+ )
502
+
503
+ self._processed_state = ProcessedState(
504
+ compiled_sql=compiled_result.compiled_sql,
505
+ execution_parameters=compiled_result.execution_parameters,
506
+ parsed_expression=compiled_result.expression,
507
+ operation_type=compiled_result.operation_type,
508
+ parameter_casts=compiled_result.parameter_casts,
509
+ parameter_profile=compiled_result.parameter_profile,
510
+ operation_profile=compiled_result.operation_profile,
511
+ validation_errors=[],
512
+ is_many=self._is_many,
513
+ )
514
+ except sqlspec.exceptions.SQLSpecError:
515
+ raise
516
+ except Exception as e:
517
+ self._processed_state = self._handle_compile_failure(e)
518
+
519
+ return self._processed_state.compiled_sql, self._processed_state.execution_parameters
520
+
521
+ def as_script(self) -> "SQL":
522
+ """Create copy marked for script execution.
523
+
524
+ Returns:
525
+ New SQL instance configured for script execution
526
+ """
527
+ original_params = self._original_parameters
528
+ config = self._statement_config
529
+ is_many = self._is_many
530
+ statement_seed = self._raw_expression or self._raw_sql
531
+ new_sql = SQL(statement_seed, *original_params, statement_config=config, is_many=is_many)
532
+ new_sql._named_parameters.update(self._named_parameters)
533
+ new_sql._positional_parameters = self._positional_parameters.copy()
534
+ new_sql._filters = self._filters.copy()
535
+ new_sql._is_script = True
536
+ return new_sql
537
+
538
+ def copy(
539
+ self, statement: "str | exp.Expression | None" = None, parameters: Any | None = None, **kwargs: Any
540
+ ) -> "SQL":
541
+ """Create copy with modifications.
542
+
543
+ Args:
544
+ statement: New SQL statement to use
545
+ parameters: New parameters to use
546
+ **kwargs: Additional modifications
547
+
548
+ Returns:
549
+ New SQL instance with modifications applied
550
+ """
551
+ statement_expression = self._raw_expression if statement is None else statement
552
+ new_sql = SQL(
553
+ statement_expression or self._raw_sql,
554
+ *(parameters if parameters is not None else self._original_parameters),
555
+ statement_config=self._statement_config,
556
+ is_many=self._is_many,
557
+ **kwargs,
558
+ )
559
+ if parameters is None:
560
+ new_sql._named_parameters.update(self._named_parameters)
561
+ new_sql._positional_parameters = self._positional_parameters.copy()
562
+ new_sql._filters = self._filters.copy()
563
+ return new_sql
564
+
565
+ def _handle_compile_failure(self, error: Exception) -> ProcessedState:
566
+ logger.debug("Processing failed, using fallback: %s", error)
567
+ return ProcessedState(
568
+ compiled_sql=self._raw_sql,
569
+ execution_parameters=self._named_parameters or self._positional_parameters,
570
+ operation_type="UNKNOWN",
571
+ parameter_casts={},
572
+ parameter_profile=ParameterProfile.empty(),
573
+ operation_profile=OperationProfile.empty(),
574
+ is_many=self._is_many,
575
+ )
576
+
577
+ # ==========================================================================
578
+ # Parameter Generation Helpers
579
+ # ==========================================================================
580
+
581
+ def _generate_sql_param_name(self, base_name: str) -> str:
582
+ """Generate unique parameter name with _sqlspec_ prefix.
583
+
584
+ Uses _sqlspec_ prefix to avoid collision with user-provided parameters.
585
+ Auto-generated parameters are namespaced to prevent conflicts.
586
+
587
+ Args:
588
+ base_name: The base name for the parameter (e.g., column name)
589
+
590
+ Returns:
591
+ A unique parameter name that doesn't exist in current parameters
592
+ """
593
+ prefixed_base = f"_sqlspec_{base_name}"
594
+ current_index = self._sql_param_counters.get(prefixed_base, 0)
595
+
596
+ if prefixed_base not in self._named_parameters:
597
+ self._sql_param_counters[prefixed_base] = current_index
598
+ return prefixed_base
599
+
600
+ next_index = current_index + 1
601
+ candidate = f"{prefixed_base}_{next_index}"
602
+
603
+ while candidate in self._named_parameters:
604
+ next_index += 1
605
+ if next_index > _MAX_PARAM_COLLISION_ATTEMPTS:
606
+ return f"{prefixed_base}_{uuid.uuid4().hex[:8]}"
607
+ candidate = f"{prefixed_base}_{next_index}"
608
+
609
+ self._sql_param_counters[prefixed_base] = next_index
610
+ return candidate
611
+
612
+ def _get_or_parse_expression(self) -> exp.Expression:
613
+ """Get the current expression or parse the raw SQL.
614
+
615
+ Returns:
616
+ The SQLGlot expression for this statement
617
+ """
618
+ if self.statement_expression is not None:
619
+ return self.statement_expression.copy()
620
+ if not self._statement_config.enable_parsing:
621
+ return exp.Select().from_(f"({self._raw_sql})")
622
+ try:
623
+ return sqlglot.parse_one(self._raw_sql, dialect=self._dialect)
624
+ except ParseError:
625
+ return exp.Select().from_(f"({self._raw_sql})")
626
+
627
+ def _create_modified_copy_with_expression(self, new_expr: exp.Expression) -> "SQL":
628
+ """Create a new SQL instance with a modified expression.
629
+
630
+ Args:
631
+ new_expr: The new SQLGlot expression
632
+
633
+ Returns:
634
+ New SQL instance with the expression and copied state
635
+ """
636
+ new_sql = SQL(
637
+ new_expr, *self._original_parameters, statement_config=self._statement_config, is_many=self._is_many
638
+ )
639
+ new_sql._named_parameters.update(self._named_parameters)
640
+ new_sql._positional_parameters = self._positional_parameters.copy()
641
+ new_sql._filters = self._filters.copy()
642
+ new_sql._sql_param_counters = self._sql_param_counters.copy()
643
+ return new_sql
644
+
645
+ def add_named_parameter(self, name: str, value: Any) -> "SQL":
646
+ """Add a named parameter and return a new SQL instance.
647
+
648
+ Args:
649
+ name: Parameter name
650
+ value: Parameter value
651
+
652
+ Returns:
653
+ New SQL instance with the added parameter
654
+ """
655
+ original_params = self._original_parameters
656
+ config = self._statement_config
657
+ is_many = self._is_many
658
+ statement_seed = self._raw_expression or self._raw_sql
659
+ new_sql = SQL(statement_seed, *original_params, statement_config=config, is_many=is_many)
660
+ new_sql._named_parameters.update(self._named_parameters)
661
+ new_sql._named_parameters[name] = value
662
+ new_sql._positional_parameters = self._positional_parameters.copy()
663
+ new_sql._filters = self._filters.copy()
664
+ return new_sql
665
+
666
+ def where(self, condition: "str | exp.Expression") -> "SQL":
667
+ """Add WHERE condition to the SQL statement.
668
+
669
+ Args:
670
+ condition: WHERE condition as string or SQLGlot expression
671
+
672
+ Returns:
673
+ New SQL instance with the WHERE condition applied
674
+ """
675
+ if self.statement_expression is not None:
676
+ current_expr = self.statement_expression.copy()
677
+ elif not self._statement_config.enable_parsing:
678
+ current_expr = exp.Select().from_(f"({self._raw_sql})")
679
+ else:
680
+ try:
681
+ current_expr = sqlglot.parse_one(self._raw_sql, dialect=self._dialect)
682
+ except ParseError:
683
+ subquery_sql = f"SELECT * FROM ({self._raw_sql}) AS subquery"
684
+ current_expr = sqlglot.parse_one(subquery_sql, dialect=self._dialect)
685
+
686
+ condition_expr: exp.Expression
687
+ if isinstance(condition, str):
688
+ if not self._statement_config.enable_parsing:
689
+ condition_expr = exp.Condition(this=condition)
690
+ else:
691
+ try:
692
+ condition_expr = sqlglot.parse_one(condition, dialect=self._dialect, into=exp.Condition)
693
+ except ParseError:
694
+ condition_expr = exp.Condition(this=condition)
695
+ else:
696
+ condition_expr = condition
697
+
698
+ if isinstance(current_expr, exp.Select) or supports_where(current_expr):
699
+ new_expr = current_expr.where(condition_expr, copy=False)
700
+ else:
701
+ new_expr = exp.Select().from_(current_expr).where(condition_expr, copy=False)
702
+
703
+ original_params = self._original_parameters
704
+ config = self._statement_config
705
+ is_many = self._is_many
706
+ new_sql = SQL(new_expr, *original_params, statement_config=config, is_many=is_many)
707
+
708
+ new_sql._named_parameters.update(self._named_parameters)
709
+ new_sql._positional_parameters = self._positional_parameters.copy()
710
+ new_sql._filters = self._filters.copy()
711
+ return new_sql
712
+
713
+ # ==========================================================================
714
+ # Parameterized WHERE Methods (using shared utilities)
715
+ # ==========================================================================
716
+
717
+ def where_eq(self, column: "str | exp.Column", value: Any) -> "SQL":
718
+ """Add WHERE column = value condition.
719
+
720
+ Args:
721
+ column: Column name or expression
722
+ value: Value to compare against
723
+
724
+ Returns:
725
+ New SQL instance with WHERE condition applied
726
+ """
727
+ expression = self._get_or_parse_expression()
728
+ col_name = extract_column_name(column)
729
+ param_name = self._generate_sql_param_name(col_name)
730
+ condition = create_condition(column, param_name, expr_eq)
731
+ new_expr = safe_modify_with_cte(expression, lambda e: apply_where(e, condition))
732
+ new_sql = self._create_modified_copy_with_expression(new_expr)
733
+ new_sql._named_parameters[param_name] = value
734
+ return new_sql
735
+
736
+ def where_neq(self, column: "str | exp.Column", value: Any) -> "SQL":
737
+ """Add WHERE column != value condition.
738
+
739
+ Args:
740
+ column: Column name or expression
741
+ value: Value to compare against
742
+
743
+ Returns:
744
+ New SQL instance with WHERE condition applied
745
+ """
746
+ expression = self._get_or_parse_expression()
747
+ col_name = extract_column_name(column)
748
+ param_name = self._generate_sql_param_name(col_name)
749
+ condition = create_condition(column, param_name, expr_neq)
750
+ new_expr = safe_modify_with_cte(expression, lambda e: apply_where(e, condition))
751
+ new_sql = self._create_modified_copy_with_expression(new_expr)
752
+ new_sql._named_parameters[param_name] = value
753
+ return new_sql
754
+
755
+ def where_lt(self, column: "str | exp.Column", value: Any) -> "SQL":
756
+ """Add WHERE column < value condition.
757
+
758
+ Args:
759
+ column: Column name or expression
760
+ value: Value to compare against
761
+
762
+ Returns:
763
+ New SQL instance with WHERE condition applied
764
+ """
765
+ expression = self._get_or_parse_expression()
766
+ col_name = extract_column_name(column)
767
+ param_name = self._generate_sql_param_name(col_name)
768
+ condition = create_condition(column, param_name, expr_lt)
769
+ new_expr = safe_modify_with_cte(expression, lambda e: apply_where(e, condition))
770
+ new_sql = self._create_modified_copy_with_expression(new_expr)
771
+ new_sql._named_parameters[param_name] = value
772
+ return new_sql
773
+
774
+ def where_lte(self, column: "str | exp.Column", value: Any) -> "SQL":
775
+ """Add WHERE column <= value condition.
776
+
777
+ Args:
778
+ column: Column name or expression
779
+ value: Value to compare against
780
+
781
+ Returns:
782
+ New SQL instance with WHERE condition applied
783
+ """
784
+ expression = self._get_or_parse_expression()
785
+ col_name = extract_column_name(column)
786
+ param_name = self._generate_sql_param_name(col_name)
787
+ condition = create_condition(column, param_name, expr_lte)
788
+ new_expr = safe_modify_with_cte(expression, lambda e: apply_where(e, condition))
789
+ new_sql = self._create_modified_copy_with_expression(new_expr)
790
+ new_sql._named_parameters[param_name] = value
791
+ return new_sql
792
+
793
+ def where_gt(self, column: "str | exp.Column", value: Any) -> "SQL":
794
+ """Add WHERE column > value condition.
795
+
796
+ Args:
797
+ column: Column name or expression
798
+ value: Value to compare against
799
+
800
+ Returns:
801
+ New SQL instance with WHERE condition applied
802
+ """
803
+ expression = self._get_or_parse_expression()
804
+ col_name = extract_column_name(column)
805
+ param_name = self._generate_sql_param_name(col_name)
806
+ condition = create_condition(column, param_name, expr_gt)
807
+ new_expr = safe_modify_with_cte(expression, lambda e: apply_where(e, condition))
808
+ new_sql = self._create_modified_copy_with_expression(new_expr)
809
+ new_sql._named_parameters[param_name] = value
810
+ return new_sql
811
+
812
+ def where_gte(self, column: "str | exp.Column", value: Any) -> "SQL":
813
+ """Add WHERE column >= value condition.
814
+
815
+ Args:
816
+ column: Column name or expression
817
+ value: Value to compare against
818
+
819
+ Returns:
820
+ New SQL instance with WHERE condition applied
821
+ """
822
+ expression = self._get_or_parse_expression()
823
+ col_name = extract_column_name(column)
824
+ param_name = self._generate_sql_param_name(col_name)
825
+ condition = create_condition(column, param_name, expr_gte)
826
+ new_expr = safe_modify_with_cte(expression, lambda e: apply_where(e, condition))
827
+ new_sql = self._create_modified_copy_with_expression(new_expr)
828
+ new_sql._named_parameters[param_name] = value
829
+ return new_sql
830
+
831
+ def where_like(self, column: "str | exp.Column", pattern: str) -> "SQL":
832
+ """Add WHERE column LIKE pattern condition.
833
+
834
+ Args:
835
+ column: Column name or expression
836
+ pattern: LIKE pattern (e.g., '%search%')
837
+
838
+ Returns:
839
+ New SQL instance with WHERE condition applied
840
+ """
841
+ expression = self._get_or_parse_expression()
842
+ col_name = extract_column_name(column)
843
+ param_name = self._generate_sql_param_name(col_name)
844
+ condition = create_condition(column, param_name, expr_like)
845
+ new_expr = safe_modify_with_cte(expression, lambda e: apply_where(e, condition))
846
+ new_sql = self._create_modified_copy_with_expression(new_expr)
847
+ new_sql._named_parameters[param_name] = pattern
848
+ return new_sql
849
+
850
+ def where_ilike(self, column: "str | exp.Column", pattern: str) -> "SQL":
851
+ """Add WHERE column ILIKE pattern condition (case-insensitive).
852
+
853
+ Args:
854
+ column: Column name or expression
855
+ pattern: ILIKE pattern (e.g., '%search%')
856
+
857
+ Returns:
858
+ New SQL instance with WHERE condition applied
859
+ """
860
+ expression = self._get_or_parse_expression()
861
+ col_name = extract_column_name(column)
862
+ param_name = self._generate_sql_param_name(col_name)
863
+ condition = create_condition(column, param_name, expr_ilike)
864
+ new_expr = safe_modify_with_cte(expression, lambda e: apply_where(e, condition))
865
+ new_sql = self._create_modified_copy_with_expression(new_expr)
866
+ new_sql._named_parameters[param_name] = pattern
867
+ return new_sql
868
+
869
+ def where_is_null(self, column: "str | exp.Column") -> "SQL":
870
+ """Add WHERE column IS NULL condition.
871
+
872
+ Args:
873
+ column: Column name or expression
874
+
875
+ Returns:
876
+ New SQL instance with WHERE condition applied
877
+ """
878
+ expression = self._get_or_parse_expression()
879
+ condition = create_condition(column, "_unused", expr_is_null)
880
+ new_expr = safe_modify_with_cte(expression, lambda e: apply_where(e, condition))
881
+ return self._create_modified_copy_with_expression(new_expr)
882
+
883
+ def where_is_not_null(self, column: "str | exp.Column") -> "SQL":
884
+ """Add WHERE column IS NOT NULL condition.
885
+
886
+ Args:
887
+ column: Column name or expression
888
+
889
+ Returns:
890
+ New SQL instance with WHERE condition applied
891
+ """
892
+ expression = self._get_or_parse_expression()
893
+ condition = create_condition(column, "_unused", expr_is_not_null)
894
+ new_expr = safe_modify_with_cte(expression, lambda e: apply_where(e, condition))
895
+ return self._create_modified_copy_with_expression(new_expr)
896
+
897
+ def where_in(self, column: "str | exp.Column", values: "Sequence[Any]") -> "SQL":
898
+ """Add WHERE column IN (values) condition.
899
+
900
+ Args:
901
+ column: Column name or expression
902
+ values: Sequence of values for IN clause
903
+
904
+ Returns:
905
+ New SQL instance with WHERE condition applied
906
+ """
907
+ if not values:
908
+ expression = self._get_or_parse_expression()
909
+ false_condition = exp.EQ(this=exp.Literal.number(1), expression=exp.Literal.number(0))
910
+ new_expr = safe_modify_with_cte(expression, lambda e: apply_where(e, false_condition))
911
+ return self._create_modified_copy_with_expression(new_expr)
912
+
913
+ expression = self._get_or_parse_expression()
914
+ col_name = extract_column_name(column)
915
+
916
+ param_names: list[str] = []
917
+ param_values: dict[str, Any] = {}
918
+ for i, val in enumerate(values):
919
+ param_name = self._generate_sql_param_name(f"{col_name}_in_{i}")
920
+ param_names.append(param_name)
921
+ param_values[param_name] = val
922
+
923
+ condition = create_in_condition(column, param_names)
924
+ new_expr = safe_modify_with_cte(expression, lambda e: apply_where(e, condition))
925
+ new_sql = self._create_modified_copy_with_expression(new_expr)
926
+ new_sql._named_parameters.update(param_values)
927
+ return new_sql
928
+
929
+ def where_not_in(self, column: "str | exp.Column", values: "Sequence[Any]") -> "SQL":
930
+ """Add WHERE column NOT IN (values) condition.
931
+
932
+ Args:
933
+ column: Column name or expression
934
+ values: Sequence of values for NOT IN clause
935
+
936
+ Returns:
937
+ New SQL instance with WHERE condition applied
938
+ """
939
+ if not values:
940
+ return self
941
+
942
+ expression = self._get_or_parse_expression()
943
+ col_name = extract_column_name(column)
944
+
945
+ param_names: list[str] = []
946
+ param_values: dict[str, Any] = {}
947
+ for i, val in enumerate(values):
948
+ param_name = self._generate_sql_param_name(f"{col_name}_not_in_{i}")
949
+ param_names.append(param_name)
950
+ param_values[param_name] = val
951
+
952
+ condition = create_not_in_condition(column, param_names)
953
+ new_expr = safe_modify_with_cte(expression, lambda e: apply_where(e, condition))
954
+ new_sql = self._create_modified_copy_with_expression(new_expr)
955
+ new_sql._named_parameters.update(param_values)
956
+ return new_sql
957
+
958
+ def where_between(self, column: "str | exp.Column", low: Any, high: Any) -> "SQL":
959
+ """Add WHERE column BETWEEN low AND high condition.
960
+
961
+ Args:
962
+ column: Column name or expression
963
+ low: Lower bound value
964
+ high: Upper bound value
965
+
966
+ Returns:
967
+ New SQL instance with WHERE condition applied
968
+ """
969
+ expression = self._get_or_parse_expression()
970
+ col_name = extract_column_name(column)
971
+ low_param = self._generate_sql_param_name(f"{col_name}_low")
972
+ high_param = self._generate_sql_param_name(f"{col_name}_high")
973
+ condition = create_between_condition(column, low_param, high_param)
974
+ new_expr = safe_modify_with_cte(expression, lambda e: apply_where(e, condition))
975
+ new_sql = self._create_modified_copy_with_expression(new_expr)
976
+ new_sql._named_parameters[low_param] = low
977
+ new_sql._named_parameters[high_param] = high
978
+ return new_sql
979
+
980
+ def order_by(self, *items: "str | exp.Expression", desc: bool = False) -> "SQL":
981
+ """Add ORDER BY clause to the SQL statement.
982
+
983
+ Args:
984
+ *items: ORDER BY expressions as strings or SQLGlot expressions
985
+ desc: Apply descending order to each item
986
+
987
+ Returns:
988
+ New SQL instance with ORDER BY applied
989
+ """
990
+ if not items:
991
+ return self
992
+
993
+ if self.statement_expression is not None:
994
+ current_expr = self.statement_expression.copy()
995
+ elif not self._statement_config.enable_parsing:
996
+ current_expr = exp.Select().from_(f"({self._raw_sql})")
997
+ else:
998
+ try:
999
+ current_expr = sqlglot.parse_one(self._raw_sql, dialect=self._dialect)
1000
+ except ParseError:
1001
+ current_expr = exp.Select().from_(f"({self._raw_sql})")
1002
+
1003
+ def parse_order_item(order_item: str) -> exp.Expression:
1004
+ normalized = order_item.strip()
1005
+ if not normalized:
1006
+ return exp.column(order_item)
1007
+
1008
+ if self._statement_config.enable_parsing:
1009
+ try:
1010
+ parsed = sqlglot.parse_one(normalized, dialect=self._dialect, into=exp.Ordered)
1011
+ except ParseError:
1012
+ parsed = None
1013
+ if parsed is not None:
1014
+ return parsed
1015
+
1016
+ parts = normalized.rsplit(None, 1)
1017
+ if len(parts) == _ORDER_PARTS_COUNT and parts[1].lower() in {"asc", "desc"}:
1018
+ base_expr = exp.column(parts[0]) if parts[0] else exp.column(normalized)
1019
+ return base_expr.desc() if parts[1].lower() == "desc" else base_expr.asc()
1020
+
1021
+ return exp.column(normalized)
1022
+
1023
+ new_expr = current_expr
1024
+ for item in items:
1025
+ if isinstance(item, str):
1026
+ order_expr = parse_order_item(item)
1027
+ if desc and not isinstance(order_expr, exp.Ordered):
1028
+ order_expr = order_expr.desc()
1029
+ else:
1030
+ order_expr = item.desc() if desc and not isinstance(item, exp.Ordered) else item
1031
+ if isinstance(new_expr, exp.Select):
1032
+ new_expr = new_expr.order_by(order_expr, copy=False)
1033
+ else:
1034
+ new_expr = exp.Select().from_(new_expr).order_by(order_expr)
1035
+
1036
+ original_params = self._original_parameters
1037
+ config = self._statement_config
1038
+ is_many = self._is_many
1039
+ new_sql = SQL(new_expr, *original_params, statement_config=config, is_many=is_many)
1040
+
1041
+ new_sql._named_parameters.update(self._named_parameters)
1042
+ new_sql._positional_parameters = self._positional_parameters.copy()
1043
+ new_sql._filters = self._filters.copy()
1044
+ return new_sql
1045
+
1046
+ # ==========================================================================
1047
+ # Pagination Methods
1048
+ # ==========================================================================
1049
+
1050
+ def limit(self, value: int) -> "SQL":
1051
+ """Add LIMIT clause to the SQL statement.
1052
+
1053
+ Args:
1054
+ value: Maximum number of rows to return
1055
+
1056
+ Returns:
1057
+ New SQL instance with LIMIT applied
1058
+
1059
+ Raises:
1060
+ SQLSpecError: If statement is not a SELECT
1061
+ """
1062
+ expression = self._get_or_parse_expression()
1063
+ new_expr = safe_modify_with_cte(expression, lambda e: apply_limit(e, value))
1064
+ return self._create_modified_copy_with_expression(new_expr)
1065
+
1066
+ def offset(self, value: int) -> "SQL":
1067
+ """Add OFFSET clause to the SQL statement.
1068
+
1069
+ Args:
1070
+ value: Number of rows to skip
1071
+
1072
+ Returns:
1073
+ New SQL instance with OFFSET applied
1074
+
1075
+ Raises:
1076
+ SQLSpecError: If statement is not a SELECT
1077
+ """
1078
+ expression = self._get_or_parse_expression()
1079
+ new_expr = safe_modify_with_cte(expression, lambda e: apply_offset(e, value))
1080
+ return self._create_modified_copy_with_expression(new_expr)
1081
+
1082
+ def paginate(self, page: int, page_size: int) -> "SQL":
1083
+ """Add LIMIT and OFFSET for pagination.
1084
+
1085
+ Args:
1086
+ page: Page number (1-indexed)
1087
+ page_size: Number of items per page
1088
+
1089
+ Returns:
1090
+ New SQL instance with LIMIT and OFFSET applied
1091
+
1092
+ Example:
1093
+ # Get page 3 with 20 items per page
1094
+ stmt = SQL("SELECT * FROM users").paginate(3, 20)
1095
+ # Results in: SELECT * FROM users LIMIT 20 OFFSET 40
1096
+ """
1097
+ if page < 1:
1098
+ msg = "paginate page must be >= 1"
1099
+ raise sqlspec.exceptions.SQLSpecError(msg)
1100
+ if page_size < 1:
1101
+ msg = "paginate page_size must be >= 1"
1102
+ raise sqlspec.exceptions.SQLSpecError(msg)
1103
+ offset_value = (page - 1) * page_size
1104
+ return self.limit(page_size).offset(offset_value)
1105
+
1106
+ # ==========================================================================
1107
+ # Column Projection Methods
1108
+ # ==========================================================================
1109
+
1110
+ def select_only(self, *columns: "str | exp.Expression") -> "SQL":
1111
+ """Replace SELECT columns with only the specified columns.
1112
+
1113
+ This is useful for narrowing down the columns returned by a query
1114
+ without modifying the FROM clause or WHERE conditions.
1115
+
1116
+ Args:
1117
+ *columns: Column names or expressions to select
1118
+
1119
+ Returns:
1120
+ New SQL instance with only the specified columns
1121
+
1122
+ Example:
1123
+ stmt = SQL("SELECT * FROM users WHERE active = 1")
1124
+ narrow = stmt.select_only("id", "name", "email")
1125
+ # Results in: SELECT id, name, email FROM users WHERE active = 1
1126
+ """
1127
+ if not columns:
1128
+ return self
1129
+
1130
+ expression = self._get_or_parse_expression()
1131
+ new_expr = safe_modify_with_cte(expression, lambda e: apply_select_only(e, columns))
1132
+ return self._create_modified_copy_with_expression(new_expr)
1133
+
1134
+ def explain(self, analyze: bool = False, verbose: bool = False, format: "str | None" = None) -> "SQL":
1135
+ """Create an EXPLAIN statement for this SQL.
1136
+
1137
+ Wraps the current SQL statement in an EXPLAIN clause with
1138
+ dialect-aware syntax generation.
1139
+
1140
+ Args:
1141
+ analyze: Execute the statement and show actual runtime statistics
1142
+ verbose: Show additional information
1143
+ format: Output format (TEXT, JSON, XML, YAML, TREE, TRADITIONAL)
1144
+
1145
+ Returns:
1146
+ New SQL instance containing the EXPLAIN statement
1147
+
1148
+ Examples:
1149
+ Basic EXPLAIN:
1150
+ stmt = SQL("SELECT * FROM users")
1151
+ explain_stmt = stmt.explain()
1152
+
1153
+ With options:
1154
+ explain_stmt = stmt.explain(analyze=True, format="json")
1155
+ """
1156
+ from sqlspec.builder import Explain
1157
+
1158
+ fmt = None
1159
+ if format is not None:
1160
+ fmt = ExplainFormat(format.lower())
1161
+
1162
+ options = ExplainOptions(analyze=analyze, verbose=verbose, format=fmt)
1163
+
1164
+ explain_builder = Explain(self, dialect=self._dialect, options=options)
1165
+ return explain_builder.build()
1166
+
1167
+ def builder(self, dialect: "DialectType | None" = None) -> "QueryBuilder":
1168
+ """Create a query builder seeded from this SQL statement.
1169
+
1170
+ Args:
1171
+ dialect: Optional SQL dialect override for parsing and rendering.
1172
+
1173
+ Returns:
1174
+ QueryBuilder instance initialized with the parsed statement.
1175
+
1176
+ Raises:
1177
+ SQLBuilderError: If the statement cannot be parsed.
1178
+
1179
+ Notes:
1180
+ Statements outside the DML set return an ExpressionBuilder without
1181
+ DML-specific helper methods.
1182
+ """
1183
+ if self._is_many:
1184
+ msg = "QueryBuilder does not support execute_many SQL statements."
1185
+ raise sqlspec.exceptions.SQLBuilderError(msg)
1186
+
1187
+ from sqlspec.builder import Delete, ExpressionBuilder, Insert, Merge, Select, Update
1188
+
1189
+ builder_dialect = dialect or self._dialect
1190
+ converter = self._statement_config.parameter_converter or ParameterConverter(
1191
+ self._statement_config.parameter_validator
1192
+ )
1193
+ raw_params = self.parameters
1194
+ converted_sql, converted_params = converter.convert_placeholder_style(
1195
+ self._raw_sql, raw_params, ParameterStyle.NAMED_COLON, is_many=False
1196
+ )
1197
+
1198
+ if self._raw_expression is not None and converted_sql == self._raw_sql and (builder_dialect == self._dialect):
1199
+ expression = self._raw_expression.copy()
1200
+ else:
1201
+ try:
1202
+ expression = sqlglot.parse_one(converted_sql, dialect=builder_dialect)
1203
+ except ParseError as exc:
1204
+ msg = f"Failed to parse SQL for builder: {exc}"
1205
+ raise sqlspec.exceptions.SQLBuilderError(msg) from exc
1206
+
1207
+ base_expression = expression
1208
+ ctes: list[exp.CTE] | None = None
1209
+ if isinstance(expression, exp.With):
1210
+ if expression.this is None:
1211
+ msg = "WITH expression does not include a base statement."
1212
+ raise sqlspec.exceptions.SQLBuilderError(msg)
1213
+ base_expression = expression.this
1214
+ ctes = list(expression.expressions)
1215
+
1216
+ builder: QueryBuilder
1217
+ if isinstance(base_expression, (exp.Select, exp.Union, exp.Except, exp.Intersect, exp.Values)):
1218
+ builder = Select(dialect=builder_dialect)
1219
+ builder.set_expression(base_expression.copy())
1220
+ elif isinstance(base_expression, exp.Insert):
1221
+ builder = Insert(dialect=builder_dialect)
1222
+ builder.set_expression(base_expression.copy())
1223
+ elif isinstance(base_expression, exp.Update):
1224
+ builder = Update(dialect=builder_dialect)
1225
+ builder.set_expression(base_expression.copy())
1226
+ elif isinstance(base_expression, exp.Delete):
1227
+ builder = Delete(dialect=builder_dialect)
1228
+ builder.set_expression(base_expression.copy())
1229
+ elif isinstance(base_expression, exp.Merge):
1230
+ builder = Merge(dialect=builder_dialect)
1231
+ builder.set_expression(base_expression.copy())
1232
+ else:
1233
+ builder = ExpressionBuilder(base_expression.copy(), dialect=builder_dialect)
1234
+
1235
+ if ctes:
1236
+ builder.load_ctes(ctes)
1237
+
1238
+ if isinstance(converted_params, Mapping):
1239
+ builder.load_parameters(converted_params)
1240
+ return builder
1241
+
1242
+ if (
1243
+ converted_params
1244
+ and isinstance(converted_params, Sequence)
1245
+ and not isinstance(converted_params, (str, bytes, bytearray))
1246
+ ):
1247
+ param_info = converter.validator.extract_parameters(converted_sql)
1248
+ param_map: dict[str, Any] = {}
1249
+ for index, param in enumerate(param_info):
1250
+ if index >= len(converted_params):
1251
+ break
1252
+ param_name = param.name or f"param_{param.ordinal}"
1253
+ param_map[param_name] = converted_params[index]
1254
+ builder.load_parameters(param_map)
1255
+
1256
+ return builder
1257
+
1258
+ def __hash__(self) -> int:
1259
+ """Hash value computation."""
1260
+ if self._hash is None:
1261
+ positional_tuple = tuple(self._positional_parameters)
1262
+ named_tuple = tuple(sorted(self._named_parameters.items())) if self._named_parameters else ()
1263
+ raw_sql = self._raw_sql
1264
+ is_many = self._is_many
1265
+ is_script = self._is_script
1266
+ self._hash = hash((raw_sql, positional_tuple, named_tuple, is_many, is_script))
1267
+ return self._hash
1268
+
1269
+ def __eq__(self, other: object) -> bool:
1270
+ """Equality comparison."""
1271
+ if not isinstance(other, SQL):
1272
+ return False
1273
+ return (
1274
+ self._raw_sql == other._raw_sql
1275
+ and self._positional_parameters == other._positional_parameters
1276
+ and self._named_parameters == other._named_parameters
1277
+ and self._is_many == other._is_many
1278
+ and self._is_script == other._is_script
1279
+ )
1280
+
1281
+ def __repr__(self) -> str:
1282
+ """String representation."""
1283
+ params_parts = []
1284
+ if self._positional_parameters:
1285
+ params_parts.append(f"params={self._positional_parameters}")
1286
+ if self._named_parameters:
1287
+ params_parts.append(f"named_params={self._named_parameters}")
1288
+ params_str = f", {', '.join(params_parts)}" if params_parts else ""
1289
+
1290
+ flags = []
1291
+ if self._is_many:
1292
+ flags.append("is_many")
1293
+ if self._is_script:
1294
+ flags.append("is_script")
1295
+ flags_str = f", {', '.join(flags)}" if flags else ""
1296
+
1297
+ return f"SQL({self._raw_sql!r}{params_str}{flags_str})"
1298
+
1299
+
1300
+ @mypyc_attr(allow_interpreted_subclasses=False)
1301
+ class StatementConfig:
1302
+ """Configuration for SQL statement processing.
1303
+
1304
+ Controls SQL parsing, validation, transformations, parameter handling,
1305
+ and other processing options for SQL statements.
1306
+ """
1307
+
1308
+ __slots__ = SQL_CONFIG_SLOTS
1309
+
1310
+ def __init__(
1311
+ self,
1312
+ parameter_config: "ParameterStyleConfig | None" = None,
1313
+ enable_parsing: bool = True,
1314
+ enable_validation: bool = True,
1315
+ enable_transformations: bool = True,
1316
+ enable_analysis: bool = False,
1317
+ enable_expression_simplification: bool = False,
1318
+ enable_parameter_type_wrapping: bool = True,
1319
+ enable_caching: bool = True,
1320
+ parameter_converter: "ParameterConverter | None" = None,
1321
+ parameter_validator: "ParameterValidator | None" = None,
1322
+ dialect: "DialectType | None" = None,
1323
+ execution_mode: "str | None" = None,
1324
+ execution_args: "dict[str, Any] | None" = None,
1325
+ output_transformer: "Callable[[str, Any], tuple[str, Any]] | None" = None,
1326
+ statement_transformers: "Sequence[Callable[[exp.Expression, Any], tuple[exp.Expression, Any]]] | None" = None,
1327
+ ) -> None:
1328
+ """Initialize StatementConfig.
1329
+
1330
+ Args:
1331
+ parameter_config: Parameter style configuration
1332
+ enable_parsing: Enable SQL parsing
1333
+ enable_validation: Run SQL validators
1334
+ enable_transformations: Apply SQL transformers
1335
+ enable_analysis: Run SQL analyzers
1336
+ enable_expression_simplification: Apply expression simplification
1337
+ enable_parameter_type_wrapping: Wrap parameters with type information
1338
+ enable_caching: Cache processed SQL statements
1339
+ parameter_converter: Handles parameter style conversions
1340
+ parameter_validator: Validates parameter usage and styles
1341
+ dialect: SQL dialect
1342
+ execution_mode: Special execution mode
1343
+ execution_args: Arguments for special execution modes
1344
+ output_transformer: Optional output transformation function
1345
+ statement_transformers: Optional AST transformers executed during compilation
1346
+ """
1347
+ self.enable_parsing = enable_parsing
1348
+ self.enable_validation = enable_validation
1349
+ self.enable_transformations = enable_transformations
1350
+ self.enable_analysis = enable_analysis
1351
+ self.enable_expression_simplification = enable_expression_simplification
1352
+ self.enable_parameter_type_wrapping = enable_parameter_type_wrapping
1353
+ self.enable_caching = enable_caching
1354
+ if parameter_converter is None:
1355
+ if parameter_validator is None:
1356
+ parameter_validator = ParameterValidator()
1357
+ self.parameter_converter = ParameterConverter(parameter_validator)
1358
+ else:
1359
+ self.parameter_converter = parameter_converter
1360
+
1361
+ if parameter_validator is None:
1362
+ self.parameter_validator = self.parameter_converter.validator
1363
+ else:
1364
+ self.parameter_validator = parameter_validator
1365
+ self.parameter_converter.validator = parameter_validator
1366
+ self.parameter_config = parameter_config or ParameterStyleConfig(
1367
+ default_parameter_style=ParameterStyle.QMARK, supported_parameter_styles={ParameterStyle.QMARK}
1368
+ )
1369
+
1370
+ self.dialect = dialect
1371
+ self.execution_mode = execution_mode
1372
+ self.execution_args = execution_args
1373
+ self.output_transformer = output_transformer
1374
+ if statement_transformers:
1375
+ self.statement_transformers = tuple(statement_transformers)
1376
+ else:
1377
+ self.statement_transformers = ()
1378
+
1379
+ def replace(self, **kwargs: Any) -> "StatementConfig":
1380
+ """Immutable update pattern.
1381
+
1382
+ Args:
1383
+ **kwargs: Attributes to update
1384
+
1385
+ Returns:
1386
+ New StatementConfig instance with updated attributes
1387
+ """
1388
+ for key in kwargs:
1389
+ if key not in SQL_CONFIG_SLOTS:
1390
+ msg = f"{key!r} is not a field in {type(self).__name__}"
1391
+ raise TypeError(msg)
1392
+
1393
+ current_kwargs: dict[str, Any] = {
1394
+ "parameter_config": self.parameter_config,
1395
+ "enable_parsing": self.enable_parsing,
1396
+ "enable_validation": self.enable_validation,
1397
+ "enable_transformations": self.enable_transformations,
1398
+ "enable_analysis": self.enable_analysis,
1399
+ "enable_expression_simplification": self.enable_expression_simplification,
1400
+ "enable_parameter_type_wrapping": self.enable_parameter_type_wrapping,
1401
+ "enable_caching": self.enable_caching,
1402
+ "parameter_converter": self.parameter_converter,
1403
+ "parameter_validator": self.parameter_validator,
1404
+ "dialect": self.dialect,
1405
+ "execution_mode": self.execution_mode,
1406
+ "execution_args": self.execution_args,
1407
+ "output_transformer": self.output_transformer,
1408
+ "statement_transformers": self.statement_transformers,
1409
+ }
1410
+ current_kwargs.update(kwargs)
1411
+ return type(self)(**current_kwargs)
1412
+
1413
+ def __hash__(self) -> int:
1414
+ """Hash based on configuration settings."""
1415
+ return hash((
1416
+ self.enable_parsing,
1417
+ self.enable_validation,
1418
+ self.enable_transformations,
1419
+ self.enable_analysis,
1420
+ self.enable_expression_simplification,
1421
+ self.enable_parameter_type_wrapping,
1422
+ self.enable_caching,
1423
+ str(self.dialect),
1424
+ self.parameter_config.hash(),
1425
+ self.execution_mode,
1426
+ self.output_transformer,
1427
+ self.statement_transformers,
1428
+ ))
1429
+
1430
+ def __repr__(self) -> str:
1431
+ """String representation of the StatementConfig instance."""
1432
+ field_strs = [
1433
+ f"parameter_config={self.parameter_config!r}",
1434
+ f"enable_parsing={self.enable_parsing!r}",
1435
+ f"enable_validation={self.enable_validation!r}",
1436
+ f"enable_transformations={self.enable_transformations!r}",
1437
+ f"enable_analysis={self.enable_analysis!r}",
1438
+ f"enable_expression_simplification={self.enable_expression_simplification!r}",
1439
+ f"enable_parameter_type_wrapping={self.enable_parameter_type_wrapping!r}",
1440
+ f"enable_caching={self.enable_caching!r}",
1441
+ f"parameter_converter={self.parameter_converter!r}",
1442
+ f"parameter_validator={self.parameter_validator!r}",
1443
+ f"dialect={self.dialect!r}",
1444
+ f"execution_mode={self.execution_mode!r}",
1445
+ f"execution_args={self.execution_args!r}",
1446
+ f"output_transformer={self.output_transformer!r}",
1447
+ f"statement_transformers={self.statement_transformers!r}",
1448
+ ]
1449
+ return f"{self.__class__.__name__}({', '.join(field_strs)})"
1450
+
1451
+ def __eq__(self, other: object) -> bool:
1452
+ """Equality comparison."""
1453
+ if not isinstance(other, type(self)):
1454
+ return False
1455
+
1456
+ if not self._compare_parameter_configs(self.parameter_config, other.parameter_config):
1457
+ return False
1458
+
1459
+ return (
1460
+ self.enable_parsing == other.enable_parsing
1461
+ and self.enable_validation == other.enable_validation
1462
+ and self.enable_transformations == other.enable_transformations
1463
+ and self.enable_analysis == other.enable_analysis
1464
+ and self.enable_expression_simplification == other.enable_expression_simplification
1465
+ and self.enable_parameter_type_wrapping == other.enable_parameter_type_wrapping
1466
+ and self.enable_caching == other.enable_caching
1467
+ and self.dialect == other.dialect
1468
+ and self.execution_mode == other.execution_mode
1469
+ and self.execution_args == other.execution_args
1470
+ and self.output_transformer == other.output_transformer
1471
+ and self.statement_transformers == other.statement_transformers
1472
+ )
1473
+
1474
+ def _compare_parameter_configs(self, config1: Any, config2: Any) -> bool:
1475
+ """Compare parameter configs."""
1476
+ return bool(
1477
+ config1.default_parameter_style == config2.default_parameter_style
1478
+ and config1.supported_parameter_styles == config2.supported_parameter_styles
1479
+ and config1.supported_execution_parameter_styles == config2.supported_execution_parameter_styles
1480
+ )
1481
+
1482
+
1483
+ def get_default_config() -> StatementConfig:
1484
+ """Get default statement configuration.
1485
+
1486
+ Returns:
1487
+ StatementConfig with default settings
1488
+ """
1489
+ return StatementConfig()
1490
+
1491
+
1492
+ def get_default_parameter_config() -> ParameterStyleConfig:
1493
+ """Get default parameter configuration.
1494
+
1495
+ Returns:
1496
+ ParameterStyleConfig with QMARK style as default
1497
+ """
1498
+ return ParameterStyleConfig(
1499
+ default_parameter_style=ParameterStyle.QMARK, supported_parameter_styles={ParameterStyle.QMARK}
1500
+ )
1501
+
1502
+
1503
+ Statement: TypeAlias = str | exp.Expression | SQL