sqlspec 0.47.0__cp314-cp314-win_amd64.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 (621) hide show
  1. f68e0789eb443ecb1c2c__mypyc.cp314-win_amd64.pyd +0 -0
  2. sqlspec/__init__.py +167 -0
  3. sqlspec/__main__.py +12 -0
  4. sqlspec/__metadata__.py +14 -0
  5. sqlspec/_typing.py +714 -0
  6. sqlspec/adapters/__init__.py +0 -0
  7. sqlspec/adapters/adbc/__init__.py +13 -0
  8. sqlspec/adapters/adbc/_typing.py +106 -0
  9. sqlspec/adapters/adbc/adk/__init__.py +5 -0
  10. sqlspec/adapters/adbc/adk/store.py +1280 -0
  11. sqlspec/adapters/adbc/config.py +378 -0
  12. sqlspec/adapters/adbc/core.cp314-win_amd64.pyd +0 -0
  13. sqlspec/adapters/adbc/core.py +922 -0
  14. sqlspec/adapters/adbc/data_dictionary.py +339 -0
  15. sqlspec/adapters/adbc/driver.py +534 -0
  16. sqlspec/adapters/adbc/events/__init__.py +5 -0
  17. sqlspec/adapters/adbc/events/store.py +285 -0
  18. sqlspec/adapters/adbc/litestar/__init__.py +5 -0
  19. sqlspec/adapters/adbc/litestar/store.py +534 -0
  20. sqlspec/adapters/adbc/type_converter.cp314-win_amd64.pyd +0 -0
  21. sqlspec/adapters/adbc/type_converter.py +142 -0
  22. sqlspec/adapters/aiomysql/__init__.py +21 -0
  23. sqlspec/adapters/aiomysql/_typing.py +137 -0
  24. sqlspec/adapters/aiomysql/adk/__init__.py +5 -0
  25. sqlspec/adapters/aiomysql/adk/store.py +678 -0
  26. sqlspec/adapters/aiomysql/config.py +305 -0
  27. sqlspec/adapters/aiomysql/core.cp314-win_amd64.pyd +0 -0
  28. sqlspec/adapters/aiomysql/core.py +536 -0
  29. sqlspec/adapters/aiomysql/data_dictionary.py +121 -0
  30. sqlspec/adapters/aiomysql/driver.py +386 -0
  31. sqlspec/adapters/aiomysql/events/__init__.py +5 -0
  32. sqlspec/adapters/aiomysql/events/store.py +104 -0
  33. sqlspec/adapters/aiomysql/litestar/__init__.py +5 -0
  34. sqlspec/adapters/aiomysql/litestar/store.py +314 -0
  35. sqlspec/adapters/aiosqlite/__init__.py +26 -0
  36. sqlspec/adapters/aiosqlite/_typing.py +109 -0
  37. sqlspec/adapters/aiosqlite/adk/__init__.py +5 -0
  38. sqlspec/adapters/aiosqlite/adk/store.py +829 -0
  39. sqlspec/adapters/aiosqlite/config.py +315 -0
  40. sqlspec/adapters/aiosqlite/core.cp314-win_amd64.pyd +0 -0
  41. sqlspec/adapters/aiosqlite/core.py +315 -0
  42. sqlspec/adapters/aiosqlite/data_dictionary.py +202 -0
  43. sqlspec/adapters/aiosqlite/driver.py +311 -0
  44. sqlspec/adapters/aiosqlite/events/__init__.py +5 -0
  45. sqlspec/adapters/aiosqlite/events/store.py +20 -0
  46. sqlspec/adapters/aiosqlite/litestar/__init__.py +5 -0
  47. sqlspec/adapters/aiosqlite/litestar/store.py +279 -0
  48. sqlspec/adapters/aiosqlite/pool.cp314-win_amd64.pyd +0 -0
  49. sqlspec/adapters/aiosqlite/pool.py +734 -0
  50. sqlspec/adapters/asyncmy/__init__.py +21 -0
  51. sqlspec/adapters/asyncmy/_typing.py +113 -0
  52. sqlspec/adapters/asyncmy/adk/__init__.py +5 -0
  53. sqlspec/adapters/asyncmy/adk/store.py +644 -0
  54. sqlspec/adapters/asyncmy/config.py +307 -0
  55. sqlspec/adapters/asyncmy/core.cp314-win_amd64.pyd +0 -0
  56. sqlspec/adapters/asyncmy/core.py +538 -0
  57. sqlspec/adapters/asyncmy/data_dictionary.py +122 -0
  58. sqlspec/adapters/asyncmy/driver.py +391 -0
  59. sqlspec/adapters/asyncmy/events/__init__.py +5 -0
  60. sqlspec/adapters/asyncmy/events/store.py +104 -0
  61. sqlspec/adapters/asyncmy/litestar/__init__.py +5 -0
  62. sqlspec/adapters/asyncmy/litestar/store.py +296 -0
  63. sqlspec/adapters/asyncpg/__init__.py +26 -0
  64. sqlspec/adapters/asyncpg/_typing.py +103 -0
  65. sqlspec/adapters/asyncpg/adk/__init__.py +5 -0
  66. sqlspec/adapters/asyncpg/adk/store.py +483 -0
  67. sqlspec/adapters/asyncpg/config.py +575 -0
  68. sqlspec/adapters/asyncpg/core.cp314-win_amd64.pyd +0 -0
  69. sqlspec/adapters/asyncpg/core.py +480 -0
  70. sqlspec/adapters/asyncpg/data_dictionary.py +157 -0
  71. sqlspec/adapters/asyncpg/driver.py +487 -0
  72. sqlspec/adapters/asyncpg/events/__init__.py +6 -0
  73. sqlspec/adapters/asyncpg/events/_hub.py +181 -0
  74. sqlspec/adapters/asyncpg/events/backend.py +210 -0
  75. sqlspec/adapters/asyncpg/events/store.py +40 -0
  76. sqlspec/adapters/asyncpg/litestar/__init__.py +5 -0
  77. sqlspec/adapters/asyncpg/litestar/store.py +251 -0
  78. sqlspec/adapters/bigquery/__init__.py +15 -0
  79. sqlspec/adapters/bigquery/_typing.py +108 -0
  80. sqlspec/adapters/bigquery/config.py +362 -0
  81. sqlspec/adapters/bigquery/core.cp314-win_amd64.pyd +0 -0
  82. sqlspec/adapters/bigquery/core.py +768 -0
  83. sqlspec/adapters/bigquery/data_dictionary.py +120 -0
  84. sqlspec/adapters/bigquery/driver.py +542 -0
  85. sqlspec/adapters/bigquery/events/__init__.py +5 -0
  86. sqlspec/adapters/bigquery/events/store.py +139 -0
  87. sqlspec/adapters/bigquery/litestar/__init__.py +5 -0
  88. sqlspec/adapters/bigquery/litestar/store.py +325 -0
  89. sqlspec/adapters/bigquery/type_converter.cp314-win_amd64.pyd +0 -0
  90. sqlspec/adapters/bigquery/type_converter.py +107 -0
  91. sqlspec/adapters/cockroach_asyncpg/__init__.py +26 -0
  92. sqlspec/adapters/cockroach_asyncpg/_typing.py +73 -0
  93. sqlspec/adapters/cockroach_asyncpg/adk/__init__.py +3 -0
  94. sqlspec/adapters/cockroach_asyncpg/adk/store.py +465 -0
  95. sqlspec/adapters/cockroach_asyncpg/config.py +248 -0
  96. sqlspec/adapters/cockroach_asyncpg/core.cp314-win_amd64.pyd +0 -0
  97. sqlspec/adapters/cockroach_asyncpg/core.py +55 -0
  98. sqlspec/adapters/cockroach_asyncpg/data_dictionary.py +110 -0
  99. sqlspec/adapters/cockroach_asyncpg/driver.py +142 -0
  100. sqlspec/adapters/cockroach_asyncpg/events/__init__.py +3 -0
  101. sqlspec/adapters/cockroach_asyncpg/events/store.py +20 -0
  102. sqlspec/adapters/cockroach_asyncpg/litestar/__init__.py +3 -0
  103. sqlspec/adapters/cockroach_asyncpg/litestar/store.py +142 -0
  104. sqlspec/adapters/cockroach_psycopg/__init__.py +39 -0
  105. sqlspec/adapters/cockroach_psycopg/_typing.py +137 -0
  106. sqlspec/adapters/cockroach_psycopg/adk/__init__.py +13 -0
  107. sqlspec/adapters/cockroach_psycopg/adk/store.py +1039 -0
  108. sqlspec/adapters/cockroach_psycopg/config.py +511 -0
  109. sqlspec/adapters/cockroach_psycopg/core.cp314-win_amd64.pyd +0 -0
  110. sqlspec/adapters/cockroach_psycopg/core.py +63 -0
  111. sqlspec/adapters/cockroach_psycopg/data_dictionary.py +220 -0
  112. sqlspec/adapters/cockroach_psycopg/driver.py +273 -0
  113. sqlspec/adapters/cockroach_psycopg/events/__init__.py +6 -0
  114. sqlspec/adapters/cockroach_psycopg/events/store.py +34 -0
  115. sqlspec/adapters/cockroach_psycopg/litestar/__init__.py +3 -0
  116. sqlspec/adapters/cockroach_psycopg/litestar/store.py +327 -0
  117. sqlspec/adapters/duckdb/__init__.py +29 -0
  118. sqlspec/adapters/duckdb/_typing.py +104 -0
  119. sqlspec/adapters/duckdb/adk/__init__.py +14 -0
  120. sqlspec/adapters/duckdb/adk/store.py +935 -0
  121. sqlspec/adapters/duckdb/config.py +386 -0
  122. sqlspec/adapters/duckdb/core.cp314-win_amd64.pyd +0 -0
  123. sqlspec/adapters/duckdb/core.py +332 -0
  124. sqlspec/adapters/duckdb/data_dictionary.py +140 -0
  125. sqlspec/adapters/duckdb/driver.py +426 -0
  126. sqlspec/adapters/duckdb/events/__init__.py +5 -0
  127. sqlspec/adapters/duckdb/events/store.py +57 -0
  128. sqlspec/adapters/duckdb/litestar/__init__.py +5 -0
  129. sqlspec/adapters/duckdb/litestar/store.py +330 -0
  130. sqlspec/adapters/duckdb/pool.cp314-win_amd64.pyd +0 -0
  131. sqlspec/adapters/duckdb/pool.py +350 -0
  132. sqlspec/adapters/duckdb/type_converter.cp314-win_amd64.pyd +0 -0
  133. sqlspec/adapters/duckdb/type_converter.py +118 -0
  134. sqlspec/adapters/mysqlconnector/__init__.py +39 -0
  135. sqlspec/adapters/mysqlconnector/_typing.py +186 -0
  136. sqlspec/adapters/mysqlconnector/adk/__init__.py +15 -0
  137. sqlspec/adapters/mysqlconnector/adk/store.py +1183 -0
  138. sqlspec/adapters/mysqlconnector/config.py +421 -0
  139. sqlspec/adapters/mysqlconnector/core.cp314-win_amd64.pyd +0 -0
  140. sqlspec/adapters/mysqlconnector/core.py +472 -0
  141. sqlspec/adapters/mysqlconnector/data_dictionary.py +230 -0
  142. sqlspec/adapters/mysqlconnector/driver.py +516 -0
  143. sqlspec/adapters/mysqlconnector/events/__init__.py +8 -0
  144. sqlspec/adapters/mysqlconnector/events/store.py +98 -0
  145. sqlspec/adapters/mysqlconnector/litestar/__init__.py +5 -0
  146. sqlspec/adapters/mysqlconnector/litestar/store.py +426 -0
  147. sqlspec/adapters/oracledb/__init__.py +39 -0
  148. sqlspec/adapters/oracledb/_json_handlers.cp314-win_amd64.pyd +0 -0
  149. sqlspec/adapters/oracledb/_json_handlers.py +196 -0
  150. sqlspec/adapters/oracledb/_param_types.cp314-win_amd64.pyd +0 -0
  151. sqlspec/adapters/oracledb/_param_types.py +46 -0
  152. sqlspec/adapters/oracledb/_typing.py +258 -0
  153. sqlspec/adapters/oracledb/_uuid_handlers.cp314-win_amd64.pyd +0 -0
  154. sqlspec/adapters/oracledb/_uuid_handlers.py +163 -0
  155. sqlspec/adapters/oracledb/_vector_handlers.cp314-win_amd64.pyd +0 -0
  156. sqlspec/adapters/oracledb/_vector_handlers.py +228 -0
  157. sqlspec/adapters/oracledb/adk/__init__.py +21 -0
  158. sqlspec/adapters/oracledb/adk/store.py +2453 -0
  159. sqlspec/adapters/oracledb/config.py +575 -0
  160. sqlspec/adapters/oracledb/core.cp314-win_amd64.pyd +0 -0
  161. sqlspec/adapters/oracledb/core.py +820 -0
  162. sqlspec/adapters/oracledb/data_dictionary.py +404 -0
  163. sqlspec/adapters/oracledb/driver.py +1277 -0
  164. sqlspec/adapters/oracledb/events/__init__.py +16 -0
  165. sqlspec/adapters/oracledb/events/_hub.py +345 -0
  166. sqlspec/adapters/oracledb/events/backend.py +300 -0
  167. sqlspec/adapters/oracledb/events/store.py +420 -0
  168. sqlspec/adapters/oracledb/litestar/__init__.py +5 -0
  169. sqlspec/adapters/oracledb/litestar/store.py +781 -0
  170. sqlspec/adapters/oracledb/migrations.py +539 -0
  171. sqlspec/adapters/oracledb/type_converter.cp314-win_amd64.pyd +0 -0
  172. sqlspec/adapters/oracledb/type_converter.py +211 -0
  173. sqlspec/adapters/psqlpy/__init__.py +18 -0
  174. sqlspec/adapters/psqlpy/_typing.py +121 -0
  175. sqlspec/adapters/psqlpy/adk/__init__.py +5 -0
  176. sqlspec/adapters/psqlpy/adk/store.py +591 -0
  177. sqlspec/adapters/psqlpy/config.py +376 -0
  178. sqlspec/adapters/psqlpy/core.cp314-win_amd64.pyd +0 -0
  179. sqlspec/adapters/psqlpy/core.py +694 -0
  180. sqlspec/adapters/psqlpy/data_dictionary.py +121 -0
  181. sqlspec/adapters/psqlpy/driver.py +411 -0
  182. sqlspec/adapters/psqlpy/events/__init__.py +6 -0
  183. sqlspec/adapters/psqlpy/events/_hub.py +204 -0
  184. sqlspec/adapters/psqlpy/events/backend.py +210 -0
  185. sqlspec/adapters/psqlpy/events/store.py +20 -0
  186. sqlspec/adapters/psqlpy/litestar/__init__.py +5 -0
  187. sqlspec/adapters/psqlpy/litestar/store.py +270 -0
  188. sqlspec/adapters/psqlpy/type_converter.cp314-win_amd64.pyd +0 -0
  189. sqlspec/adapters/psqlpy/type_converter.py +113 -0
  190. sqlspec/adapters/psycopg/__init__.py +38 -0
  191. sqlspec/adapters/psycopg/_typing.py +218 -0
  192. sqlspec/adapters/psycopg/adk/__init__.py +10 -0
  193. sqlspec/adapters/psycopg/adk/store.py +1106 -0
  194. sqlspec/adapters/psycopg/config.py +695 -0
  195. sqlspec/adapters/psycopg/core.cp314-win_amd64.pyd +0 -0
  196. sqlspec/adapters/psycopg/core.py +520 -0
  197. sqlspec/adapters/psycopg/data_dictionary.py +278 -0
  198. sqlspec/adapters/psycopg/driver.py +1033 -0
  199. sqlspec/adapters/psycopg/events/__init__.py +20 -0
  200. sqlspec/adapters/psycopg/events/_hub.py +388 -0
  201. sqlspec/adapters/psycopg/events/backend.py +398 -0
  202. sqlspec/adapters/psycopg/events/store.py +42 -0
  203. sqlspec/adapters/psycopg/litestar/__init__.py +5 -0
  204. sqlspec/adapters/psycopg/litestar/store.py +554 -0
  205. sqlspec/adapters/psycopg/type_converter.cp314-win_amd64.pyd +0 -0
  206. sqlspec/adapters/psycopg/type_converter.py +93 -0
  207. sqlspec/adapters/pymysql/__init__.py +21 -0
  208. sqlspec/adapters/pymysql/_typing.py +92 -0
  209. sqlspec/adapters/pymysql/adk/__init__.py +5 -0
  210. sqlspec/adapters/pymysql/adk/store.py +657 -0
  211. sqlspec/adapters/pymysql/config.py +176 -0
  212. sqlspec/adapters/pymysql/core.cp314-win_amd64.pyd +0 -0
  213. sqlspec/adapters/pymysql/core.py +469 -0
  214. sqlspec/adapters/pymysql/data_dictionary.py +120 -0
  215. sqlspec/adapters/pymysql/driver.py +271 -0
  216. sqlspec/adapters/pymysql/events/__init__.py +5 -0
  217. sqlspec/adapters/pymysql/events/store.py +50 -0
  218. sqlspec/adapters/pymysql/litestar/__init__.py +5 -0
  219. sqlspec/adapters/pymysql/litestar/store.py +232 -0
  220. sqlspec/adapters/pymysql/pool.cp314-win_amd64.pyd +0 -0
  221. sqlspec/adapters/pymysql/pool.py +184 -0
  222. sqlspec/adapters/spanner/__init__.py +33 -0
  223. sqlspec/adapters/spanner/_typing.py +102 -0
  224. sqlspec/adapters/spanner/adk/__init__.py +5 -0
  225. sqlspec/adapters/spanner/adk/store.py +758 -0
  226. sqlspec/adapters/spanner/config.py +355 -0
  227. sqlspec/adapters/spanner/core.cp314-win_amd64.pyd +0 -0
  228. sqlspec/adapters/spanner/core.py +263 -0
  229. sqlspec/adapters/spanner/data_dictionary.py +120 -0
  230. sqlspec/adapters/spanner/driver.py +407 -0
  231. sqlspec/adapters/spanner/events/__init__.py +5 -0
  232. sqlspec/adapters/spanner/events/store.py +187 -0
  233. sqlspec/adapters/spanner/litestar/__init__.py +5 -0
  234. sqlspec/adapters/spanner/litestar/store.py +291 -0
  235. sqlspec/adapters/spanner/type_converter.cp314-win_amd64.pyd +0 -0
  236. sqlspec/adapters/spanner/type_converter.py +342 -0
  237. sqlspec/adapters/sqlite/__init__.py +19 -0
  238. sqlspec/adapters/sqlite/_typing.py +123 -0
  239. sqlspec/adapters/sqlite/adk/__init__.py +5 -0
  240. sqlspec/adapters/sqlite/adk/store.py +992 -0
  241. sqlspec/adapters/sqlite/config.py +240 -0
  242. sqlspec/adapters/sqlite/core.cp314-win_amd64.pyd +0 -0
  243. sqlspec/adapters/sqlite/core.py +357 -0
  244. sqlspec/adapters/sqlite/data_dictionary.py +198 -0
  245. sqlspec/adapters/sqlite/driver.py +527 -0
  246. sqlspec/adapters/sqlite/events/__init__.py +5 -0
  247. sqlspec/adapters/sqlite/events/store.py +20 -0
  248. sqlspec/adapters/sqlite/litestar/__init__.py +5 -0
  249. sqlspec/adapters/sqlite/litestar/store.py +316 -0
  250. sqlspec/adapters/sqlite/pool.cp314-win_amd64.pyd +0 -0
  251. sqlspec/adapters/sqlite/pool.py +237 -0
  252. sqlspec/adapters/sqlite/type_converter.cp314-win_amd64.pyd +0 -0
  253. sqlspec/adapters/sqlite/type_converter.py +114 -0
  254. sqlspec/base.py +832 -0
  255. sqlspec/builder/__init__.py +181 -0
  256. sqlspec/builder/_base.cp314-win_amd64.pyd +0 -0
  257. sqlspec/builder/_base.py +1071 -0
  258. sqlspec/builder/_column.cp314-win_amd64.pyd +0 -0
  259. sqlspec/builder/_column.py +521 -0
  260. sqlspec/builder/_ddl.cp314-win_amd64.pyd +0 -0
  261. sqlspec/builder/_ddl.py +1691 -0
  262. sqlspec/builder/_delete.cp314-win_amd64.pyd +0 -0
  263. sqlspec/builder/_delete.py +95 -0
  264. sqlspec/builder/_dml.cp314-win_amd64.pyd +0 -0
  265. sqlspec/builder/_dml.py +386 -0
  266. sqlspec/builder/_explain.cp314-win_amd64.pyd +0 -0
  267. sqlspec/builder/_explain.py +579 -0
  268. sqlspec/builder/_expression_wrappers.cp314-win_amd64.pyd +0 -0
  269. sqlspec/builder/_expression_wrappers.py +46 -0
  270. sqlspec/builder/_factory.cp314-win_amd64.pyd +0 -0
  271. sqlspec/builder/_factory.py +1884 -0
  272. sqlspec/builder/_insert.cp314-win_amd64.pyd +0 -0
  273. sqlspec/builder/_insert.py +405 -0
  274. sqlspec/builder/_join.cp314-win_amd64.pyd +0 -0
  275. sqlspec/builder/_join.py +489 -0
  276. sqlspec/builder/_merge.cp314-win_amd64.pyd +0 -0
  277. sqlspec/builder/_merge.py +823 -0
  278. sqlspec/builder/_parsing_utils.cp314-win_amd64.pyd +0 -0
  279. sqlspec/builder/_parsing_utils.py +295 -0
  280. sqlspec/builder/_select.cp314-win_amd64.pyd +0 -0
  281. sqlspec/builder/_select.py +1666 -0
  282. sqlspec/builder/_temporal.cp314-win_amd64.pyd +0 -0
  283. sqlspec/builder/_temporal.py +167 -0
  284. sqlspec/builder/_update.cp314-win_amd64.pyd +0 -0
  285. sqlspec/builder/_update.py +173 -0
  286. sqlspec/builder/_vector_distance.cp314-win_amd64.pyd +0 -0
  287. sqlspec/builder/_vector_distance.py +330 -0
  288. sqlspec/cli.py +1095 -0
  289. sqlspec/config.py +2383 -0
  290. sqlspec/core/__init__.py +372 -0
  291. sqlspec/core/_correlation.cp314-win_amd64.pyd +0 -0
  292. sqlspec/core/_correlation.py +176 -0
  293. sqlspec/core/_pagination.py +42 -0
  294. sqlspec/core/_pool.cp314-win_amd64.pyd +0 -0
  295. sqlspec/core/_pool.py +76 -0
  296. sqlspec/core/cache.cp314-win_amd64.pyd +0 -0
  297. sqlspec/core/cache.py +1085 -0
  298. sqlspec/core/compiler.cp314-win_amd64.pyd +0 -0
  299. sqlspec/core/compiler.py +1090 -0
  300. sqlspec/core/config_runtime.cp314-win_amd64.pyd +0 -0
  301. sqlspec/core/config_runtime.py +174 -0
  302. sqlspec/core/explain.cp314-win_amd64.pyd +0 -0
  303. sqlspec/core/explain.py +275 -0
  304. sqlspec/core/filters.cp314-win_amd64.pyd +0 -0
  305. sqlspec/core/filters.py +969 -0
  306. sqlspec/core/hashing.cp314-win_amd64.pyd +0 -0
  307. sqlspec/core/hashing.py +266 -0
  308. sqlspec/core/metrics.cp314-win_amd64.pyd +0 -0
  309. sqlspec/core/metrics.py +83 -0
  310. sqlspec/core/parameters/__init__.py +72 -0
  311. sqlspec/core/parameters/_alignment.cp314-win_amd64.pyd +0 -0
  312. sqlspec/core/parameters/_alignment.py +283 -0
  313. sqlspec/core/parameters/_converter.cp314-win_amd64.pyd +0 -0
  314. sqlspec/core/parameters/_converter.py +554 -0
  315. sqlspec/core/parameters/_processor.cp314-win_amd64.pyd +0 -0
  316. sqlspec/core/parameters/_processor.py +1182 -0
  317. sqlspec/core/parameters/_registry.cp314-win_amd64.pyd +0 -0
  318. sqlspec/core/parameters/_registry.py +206 -0
  319. sqlspec/core/parameters/_transformers.cp314-win_amd64.pyd +0 -0
  320. sqlspec/core/parameters/_transformers.py +324 -0
  321. sqlspec/core/parameters/_types.cp314-win_amd64.pyd +0 -0
  322. sqlspec/core/parameters/_types.py +536 -0
  323. sqlspec/core/parameters/_validator.cp314-win_amd64.pyd +0 -0
  324. sqlspec/core/parameters/_validator.py +171 -0
  325. sqlspec/core/pipeline.cp314-win_amd64.pyd +0 -0
  326. sqlspec/core/pipeline.py +333 -0
  327. sqlspec/core/query_modifiers.cp314-win_amd64.pyd +0 -0
  328. sqlspec/core/query_modifiers.py +508 -0
  329. sqlspec/core/result/__init__.py +25 -0
  330. sqlspec/core/result/_base.cp314-win_amd64.pyd +0 -0
  331. sqlspec/core/result/_base.py +1232 -0
  332. sqlspec/core/result/_io.cp314-win_amd64.pyd +0 -0
  333. sqlspec/core/result/_io.py +28 -0
  334. sqlspec/core/splitter.cp314-win_amd64.pyd +0 -0
  335. sqlspec/core/splitter.py +1021 -0
  336. sqlspec/core/sqlcommenter.cp314-win_amd64.pyd +0 -0
  337. sqlspec/core/sqlcommenter.py +249 -0
  338. sqlspec/core/stack.cp314-win_amd64.pyd +0 -0
  339. sqlspec/core/stack.py +163 -0
  340. sqlspec/core/statement.cp314-win_amd64.pyd +0 -0
  341. sqlspec/core/statement.py +1865 -0
  342. sqlspec/core/type_converter.cp314-win_amd64.pyd +0 -0
  343. sqlspec/core/type_converter.py +340 -0
  344. sqlspec/data_dictionary/__init__.py +22 -0
  345. sqlspec/data_dictionary/_loader.cp314-win_amd64.pyd +0 -0
  346. sqlspec/data_dictionary/_loader.py +138 -0
  347. sqlspec/data_dictionary/_registry.cp314-win_amd64.pyd +0 -0
  348. sqlspec/data_dictionary/_registry.py +74 -0
  349. sqlspec/data_dictionary/_types.cp314-win_amd64.pyd +0 -0
  350. sqlspec/data_dictionary/_types.py +121 -0
  351. sqlspec/data_dictionary/dialects/__init__.py +21 -0
  352. sqlspec/data_dictionary/dialects/bigquery.cp314-win_amd64.pyd +0 -0
  353. sqlspec/data_dictionary/dialects/bigquery.py +81 -0
  354. sqlspec/data_dictionary/dialects/cockroachdb.cp314-win_amd64.pyd +0 -0
  355. sqlspec/data_dictionary/dialects/cockroachdb.py +54 -0
  356. sqlspec/data_dictionary/dialects/duckdb.cp314-win_amd64.pyd +0 -0
  357. sqlspec/data_dictionary/dialects/duckdb.py +47 -0
  358. sqlspec/data_dictionary/dialects/mysql.cp314-win_amd64.pyd +0 -0
  359. sqlspec/data_dictionary/dialects/mysql.py +53 -0
  360. sqlspec/data_dictionary/dialects/oracle.cp314-win_amd64.pyd +0 -0
  361. sqlspec/data_dictionary/dialects/oracle.py +197 -0
  362. sqlspec/data_dictionary/dialects/postgres.cp314-win_amd64.pyd +0 -0
  363. sqlspec/data_dictionary/dialects/postgres.py +69 -0
  364. sqlspec/data_dictionary/dialects/spanner.cp314-win_amd64.pyd +0 -0
  365. sqlspec/data_dictionary/dialects/spanner.py +37 -0
  366. sqlspec/data_dictionary/dialects/sqlite.cp314-win_amd64.pyd +0 -0
  367. sqlspec/data_dictionary/dialects/sqlite.py +59 -0
  368. sqlspec/data_dictionary/sql/.gitkeep +0 -0
  369. sqlspec/data_dictionary/sql/bigquery/columns.sql +23 -0
  370. sqlspec/data_dictionary/sql/bigquery/foreign_keys.sql +34 -0
  371. sqlspec/data_dictionary/sql/bigquery/indexes.sql +19 -0
  372. sqlspec/data_dictionary/sql/bigquery/tables.sql +33 -0
  373. sqlspec/data_dictionary/sql/bigquery/version.sql +3 -0
  374. sqlspec/data_dictionary/sql/cockroachdb/columns.sql +34 -0
  375. sqlspec/data_dictionary/sql/cockroachdb/foreign_keys.sql +40 -0
  376. sqlspec/data_dictionary/sql/cockroachdb/indexes.sql +32 -0
  377. sqlspec/data_dictionary/sql/cockroachdb/tables.sql +44 -0
  378. sqlspec/data_dictionary/sql/cockroachdb/version.sql +3 -0
  379. sqlspec/data_dictionary/sql/duckdb/columns.sql +23 -0
  380. sqlspec/data_dictionary/sql/duckdb/foreign_keys.sql +36 -0
  381. sqlspec/data_dictionary/sql/duckdb/indexes.sql +19 -0
  382. sqlspec/data_dictionary/sql/duckdb/tables.sql +38 -0
  383. sqlspec/data_dictionary/sql/duckdb/version.sql +3 -0
  384. sqlspec/data_dictionary/sql/mysql/columns.sql +23 -0
  385. sqlspec/data_dictionary/sql/mysql/foreign_keys.sql +28 -0
  386. sqlspec/data_dictionary/sql/mysql/indexes.sql +26 -0
  387. sqlspec/data_dictionary/sql/mysql/tables.sql +33 -0
  388. sqlspec/data_dictionary/sql/mysql/version.sql +3 -0
  389. sqlspec/data_dictionary/sql/oracle/columns.sql +23 -0
  390. sqlspec/data_dictionary/sql/oracle/foreign_keys.sql +48 -0
  391. sqlspec/data_dictionary/sql/oracle/indexes.sql +44 -0
  392. sqlspec/data_dictionary/sql/oracle/tables.sql +25 -0
  393. sqlspec/data_dictionary/sql/oracle/version.sql +20 -0
  394. sqlspec/data_dictionary/sql/postgres/columns.sql +34 -0
  395. sqlspec/data_dictionary/sql/postgres/foreign_keys.sql +40 -0
  396. sqlspec/data_dictionary/sql/postgres/indexes.sql +56 -0
  397. sqlspec/data_dictionary/sql/postgres/tables.sql +44 -0
  398. sqlspec/data_dictionary/sql/postgres/version.sql +3 -0
  399. sqlspec/data_dictionary/sql/spanner/columns.sql +23 -0
  400. sqlspec/data_dictionary/sql/spanner/foreign_keys.sql +70 -0
  401. sqlspec/data_dictionary/sql/spanner/indexes.sql +30 -0
  402. sqlspec/data_dictionary/sql/spanner/tables.sql +9 -0
  403. sqlspec/data_dictionary/sql/spanner/version.sql +3 -0
  404. sqlspec/data_dictionary/sql/sqlite/columns.sql +23 -0
  405. sqlspec/data_dictionary/sql/sqlite/foreign_keys.sql +22 -0
  406. sqlspec/data_dictionary/sql/sqlite/indexes.sql +7 -0
  407. sqlspec/data_dictionary/sql/sqlite/tables.sql +28 -0
  408. sqlspec/data_dictionary/sql/sqlite/version.sql +3 -0
  409. sqlspec/dialects/__init__.py +22 -0
  410. sqlspec/dialects/_compat.cp314-win_amd64.pyd +0 -0
  411. sqlspec/dialects/_compat.py +14 -0
  412. sqlspec/dialects/postgres/__init__.py +9 -0
  413. sqlspec/dialects/postgres/_generators.cp314-win_amd64.pyd +0 -0
  414. sqlspec/dialects/postgres/_generators.py +57 -0
  415. sqlspec/dialects/postgres/_operators.cp314-win_amd64.pyd +0 -0
  416. sqlspec/dialects/postgres/_operators.py +81 -0
  417. sqlspec/dialects/postgres/_paradedb.py +50 -0
  418. sqlspec/dialects/postgres/_pgvector.py +36 -0
  419. sqlspec/dialects/spanner/__init__.py +6 -0
  420. sqlspec/dialects/spanner/_generators.cp314-win_amd64.pyd +0 -0
  421. sqlspec/dialects/spanner/_generators.py +206 -0
  422. sqlspec/dialects/spanner/_spangres.py +77 -0
  423. sqlspec/dialects/spanner/_spanner.py +179 -0
  424. sqlspec/driver/__init__.py +49 -0
  425. sqlspec/driver/_async.cp314-win_amd64.pyd +0 -0
  426. sqlspec/driver/_async.py +1830 -0
  427. sqlspec/driver/_common.cp314-win_amd64.pyd +0 -0
  428. sqlspec/driver/_common.py +2292 -0
  429. sqlspec/driver/_exception_handler.cp314-win_amd64.pyd +0 -0
  430. sqlspec/driver/_exception_handler.py +108 -0
  431. sqlspec/driver/_query_cache.cp314-win_amd64.pyd +0 -0
  432. sqlspec/driver/_query_cache.py +96 -0
  433. sqlspec/driver/_sql_helpers.cp314-win_amd64.pyd +0 -0
  434. sqlspec/driver/_sql_helpers.py +139 -0
  435. sqlspec/driver/_storage_helpers.cp314-win_amd64.pyd +0 -0
  436. sqlspec/driver/_storage_helpers.py +153 -0
  437. sqlspec/driver/_sync.cp314-win_amd64.pyd +0 -0
  438. sqlspec/driver/_sync.py +1817 -0
  439. sqlspec/exceptions.cp314-win_amd64.pyd +0 -0
  440. sqlspec/exceptions.py +480 -0
  441. sqlspec/extensions/__init__.py +0 -0
  442. sqlspec/extensions/adk/__init__.py +84 -0
  443. sqlspec/extensions/adk/_config_utils.py +199 -0
  444. sqlspec/extensions/adk/_types.cp314-win_amd64.pyd +0 -0
  445. sqlspec/extensions/adk/_types.py +41 -0
  446. sqlspec/extensions/adk/artifact/__init__.py +57 -0
  447. sqlspec/extensions/adk/artifact/_types.cp314-win_amd64.pyd +0 -0
  448. sqlspec/extensions/adk/artifact/_types.py +32 -0
  449. sqlspec/extensions/adk/artifact/service.py +508 -0
  450. sqlspec/extensions/adk/artifact/store.py +361 -0
  451. sqlspec/extensions/adk/converters.py +212 -0
  452. sqlspec/extensions/adk/memory/__init__.py +69 -0
  453. sqlspec/extensions/adk/memory/_types.cp314-win_amd64.pyd +0 -0
  454. sqlspec/extensions/adk/memory/_types.py +30 -0
  455. sqlspec/extensions/adk/memory/converters.py +225 -0
  456. sqlspec/extensions/adk/memory/service.py +316 -0
  457. sqlspec/extensions/adk/memory/store.py +525 -0
  458. sqlspec/extensions/adk/migrations/0001_create_adk_tables.py +184 -0
  459. sqlspec/extensions/adk/migrations/__init__.py +0 -0
  460. sqlspec/extensions/adk/service.py +279 -0
  461. sqlspec/extensions/adk/store.py +590 -0
  462. sqlspec/extensions/events/__init__.py +51 -0
  463. sqlspec/extensions/events/_channel.py +703 -0
  464. sqlspec/extensions/events/_hints.cp314-win_amd64.pyd +0 -0
  465. sqlspec/extensions/events/_hints.py +45 -0
  466. sqlspec/extensions/events/_models.py +23 -0
  467. sqlspec/extensions/events/_payload.cp314-win_amd64.pyd +0 -0
  468. sqlspec/extensions/events/_payload.py +69 -0
  469. sqlspec/extensions/events/_protocols.py +134 -0
  470. sqlspec/extensions/events/_queue.py +462 -0
  471. sqlspec/extensions/events/_store.py +209 -0
  472. sqlspec/extensions/events/migrations/0001_create_event_queue.py +59 -0
  473. sqlspec/extensions/events/migrations/__init__.py +3 -0
  474. sqlspec/extensions/fastapi/__init__.py +22 -0
  475. sqlspec/extensions/fastapi/extension.py +391 -0
  476. sqlspec/extensions/fastapi/providers.cp314-win_amd64.pyd +0 -0
  477. sqlspec/extensions/fastapi/providers.py +712 -0
  478. sqlspec/extensions/flask/__init__.py +38 -0
  479. sqlspec/extensions/flask/_state.py +87 -0
  480. sqlspec/extensions/flask/_utils.py +71 -0
  481. sqlspec/extensions/flask/extension.py +539 -0
  482. sqlspec/extensions/litestar/__init__.py +31 -0
  483. sqlspec/extensions/litestar/_utils.py +52 -0
  484. sqlspec/extensions/litestar/channels.py +165 -0
  485. sqlspec/extensions/litestar/cli.py +102 -0
  486. sqlspec/extensions/litestar/config.py +90 -0
  487. sqlspec/extensions/litestar/handlers.py +316 -0
  488. sqlspec/extensions/litestar/migrations/0001_create_session_table.py +137 -0
  489. sqlspec/extensions/litestar/migrations/__init__.py +3 -0
  490. sqlspec/extensions/litestar/plugin.py +1066 -0
  491. sqlspec/extensions/litestar/providers.cp314-win_amd64.pyd +0 -0
  492. sqlspec/extensions/litestar/providers.py +784 -0
  493. sqlspec/extensions/litestar/store.py +298 -0
  494. sqlspec/extensions/otel/__init__.py +58 -0
  495. sqlspec/extensions/prometheus/__init__.py +113 -0
  496. sqlspec/extensions/sanic/__init__.py +19 -0
  497. sqlspec/extensions/sanic/_state.py +43 -0
  498. sqlspec/extensions/sanic/_utils.py +127 -0
  499. sqlspec/extensions/sanic/extension.py +647 -0
  500. sqlspec/extensions/starlette/__init__.py +22 -0
  501. sqlspec/extensions/starlette/_state.py +42 -0
  502. sqlspec/extensions/starlette/_utils.py +96 -0
  503. sqlspec/extensions/starlette/extension.py +374 -0
  504. sqlspec/extensions/starlette/middleware.py +281 -0
  505. sqlspec/loader.cp314-win_amd64.pyd +0 -0
  506. sqlspec/loader.py +727 -0
  507. sqlspec/migrations/__init__.py +39 -0
  508. sqlspec/migrations/base.cp314-win_amd64.pyd +0 -0
  509. sqlspec/migrations/base.py +862 -0
  510. sqlspec/migrations/commands.py +2151 -0
  511. sqlspec/migrations/context.cp314-win_amd64.pyd +0 -0
  512. sqlspec/migrations/context.py +157 -0
  513. sqlspec/migrations/fix.cp314-win_amd64.pyd +0 -0
  514. sqlspec/migrations/fix.py +204 -0
  515. sqlspec/migrations/loaders.cp314-win_amd64.pyd +0 -0
  516. sqlspec/migrations/loaders.py +443 -0
  517. sqlspec/migrations/runner.cp314-win_amd64.pyd +0 -0
  518. sqlspec/migrations/runner.py +1195 -0
  519. sqlspec/migrations/squash.cp314-win_amd64.pyd +0 -0
  520. sqlspec/migrations/squash.py +490 -0
  521. sqlspec/migrations/templates.cp314-win_amd64.pyd +0 -0
  522. sqlspec/migrations/templates.py +234 -0
  523. sqlspec/migrations/tracker.cp314-win_amd64.pyd +0 -0
  524. sqlspec/migrations/tracker.py +792 -0
  525. sqlspec/migrations/utils.cp314-win_amd64.pyd +0 -0
  526. sqlspec/migrations/utils.py +256 -0
  527. sqlspec/migrations/validation.cp314-win_amd64.pyd +0 -0
  528. sqlspec/migrations/validation.py +359 -0
  529. sqlspec/migrations/version.cp314-win_amd64.pyd +0 -0
  530. sqlspec/migrations/version.py +446 -0
  531. sqlspec/observability/__init__.py +57 -0
  532. sqlspec/observability/_common.cp314-win_amd64.pyd +0 -0
  533. sqlspec/observability/_common.py +77 -0
  534. sqlspec/observability/_config.cp314-win_amd64.pyd +0 -0
  535. sqlspec/observability/_config.py +364 -0
  536. sqlspec/observability/_diagnostics.cp314-win_amd64.pyd +0 -0
  537. sqlspec/observability/_diagnostics.py +74 -0
  538. sqlspec/observability/_dispatcher.cp314-win_amd64.pyd +0 -0
  539. sqlspec/observability/_dispatcher.py +200 -0
  540. sqlspec/observability/_formatters/__init__.py +13 -0
  541. sqlspec/observability/_formatters/_aws.cp314-win_amd64.pyd +0 -0
  542. sqlspec/observability/_formatters/_aws.py +102 -0
  543. sqlspec/observability/_formatters/_azure.cp314-win_amd64.pyd +0 -0
  544. sqlspec/observability/_formatters/_azure.py +96 -0
  545. sqlspec/observability/_formatters/_base.cp314-win_amd64.pyd +0 -0
  546. sqlspec/observability/_formatters/_base.py +57 -0
  547. sqlspec/observability/_formatters/_gcp.cp314-win_amd64.pyd +0 -0
  548. sqlspec/observability/_formatters/_gcp.py +131 -0
  549. sqlspec/observability/_formatting.py +58 -0
  550. sqlspec/observability/_observer.cp314-win_amd64.pyd +0 -0
  551. sqlspec/observability/_observer.py +361 -0
  552. sqlspec/observability/_runtime.cp314-win_amd64.pyd +0 -0
  553. sqlspec/observability/_runtime.py +461 -0
  554. sqlspec/observability/_sampling.cp314-win_amd64.pyd +0 -0
  555. sqlspec/observability/_sampling.py +188 -0
  556. sqlspec/observability/_spans.cp314-win_amd64.pyd +0 -0
  557. sqlspec/observability/_spans.py +161 -0
  558. sqlspec/protocols.py +955 -0
  559. sqlspec/py.typed +0 -0
  560. sqlspec/service.py +433 -0
  561. sqlspec/storage/__init__.py +48 -0
  562. sqlspec/storage/_arrow_payload.py +68 -0
  563. sqlspec/storage/_paths.cp314-win_amd64.pyd +0 -0
  564. sqlspec/storage/_paths.py +58 -0
  565. sqlspec/storage/_utils.py +46 -0
  566. sqlspec/storage/backends/__init__.py +1 -0
  567. sqlspec/storage/backends/base.cp314-win_amd64.pyd +0 -0
  568. sqlspec/storage/backends/base.py +374 -0
  569. sqlspec/storage/backends/fsspec.py +574 -0
  570. sqlspec/storage/backends/local.py +468 -0
  571. sqlspec/storage/backends/obstore.py +956 -0
  572. sqlspec/storage/errors.cp314-win_amd64.pyd +0 -0
  573. sqlspec/storage/errors.py +102 -0
  574. sqlspec/storage/pipeline.cp314-win_amd64.pyd +0 -0
  575. sqlspec/storage/pipeline.py +628 -0
  576. sqlspec/storage/registry.cp314-win_amd64.pyd +0 -0
  577. sqlspec/storage/registry.py +329 -0
  578. sqlspec/typing.py +405 -0
  579. sqlspec/utils/__init__.py +7 -0
  580. sqlspec/utils/arrow_helpers.py +384 -0
  581. sqlspec/utils/config_tools.cp314-win_amd64.pyd +0 -0
  582. sqlspec/utils/config_tools.py +314 -0
  583. sqlspec/utils/correlation.cp314-win_amd64.pyd +0 -0
  584. sqlspec/utils/correlation.py +134 -0
  585. sqlspec/utils/deprecation.cp314-win_amd64.pyd +0 -0
  586. sqlspec/utils/deprecation.py +157 -0
  587. sqlspec/utils/dispatch.cp314-win_amd64.pyd +0 -0
  588. sqlspec/utils/dispatch.py +101 -0
  589. sqlspec/utils/fixtures.cp314-win_amd64.pyd +0 -0
  590. sqlspec/utils/fixtures.py +260 -0
  591. sqlspec/utils/logging.cp314-win_amd64.pyd +0 -0
  592. sqlspec/utils/logging.py +251 -0
  593. sqlspec/utils/module_loader.py +306 -0
  594. sqlspec/utils/portal.cp314-win_amd64.pyd +0 -0
  595. sqlspec/utils/portal.py +377 -0
  596. sqlspec/utils/schema.cp314-win_amd64.pyd +0 -0
  597. sqlspec/utils/schema.py +1040 -0
  598. sqlspec/utils/serializers/__init__.py +30 -0
  599. sqlspec/utils/serializers/_json.cp314-win_amd64.pyd +0 -0
  600. sqlspec/utils/serializers/_json.py +415 -0
  601. sqlspec/utils/serializers/_numpy.cp314-win_amd64.pyd +0 -0
  602. sqlspec/utils/serializers/_numpy.py +65 -0
  603. sqlspec/utils/serializers/_schema.cp314-win_amd64.pyd +0 -0
  604. sqlspec/utils/serializers/_schema.py +285 -0
  605. sqlspec/utils/singleton.cp314-win_amd64.pyd +0 -0
  606. sqlspec/utils/singleton.py +41 -0
  607. sqlspec/utils/sync_tools.cp314-win_amd64.pyd +0 -0
  608. sqlspec/utils/sync_tools.py +316 -0
  609. sqlspec/utils/text.cp314-win_amd64.pyd +0 -0
  610. sqlspec/utils/text.py +109 -0
  611. sqlspec/utils/type_converters.cp314-win_amd64.pyd +0 -0
  612. sqlspec/utils/type_converters.py +216 -0
  613. sqlspec/utils/type_guards.cp314-win_amd64.pyd +0 -0
  614. sqlspec/utils/type_guards.py +1508 -0
  615. sqlspec/utils/uuids.cp314-win_amd64.pyd +0 -0
  616. sqlspec/utils/uuids.py +241 -0
  617. sqlspec-0.47.0.dist-info/METADATA +202 -0
  618. sqlspec-0.47.0.dist-info/RECORD +621 -0
  619. sqlspec-0.47.0.dist-info/WHEEL +4 -0
  620. sqlspec-0.47.0.dist-info/entry_points.txt +6 -0
  621. sqlspec-0.47.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,1691 @@
1
+ """DDL statement builders.
2
+
3
+ Provides builders for DDL operations including CREATE, DROP, ALTER,
4
+ TRUNCATE, and other schema manipulation statements.
5
+ """
6
+
7
+ from typing import TYPE_CHECKING, Any, Union
8
+
9
+ from sqlglot import exp
10
+ from typing_extensions import Self
11
+
12
+ from sqlspec.builder._base import BuiltQuery, QueryBuilder
13
+ from sqlspec.builder._select import Select
14
+ from sqlspec.core import SQL, SQLResult
15
+ from sqlspec.utils.type_guards import has_sqlglot_expression, has_with_method
16
+
17
+ if TYPE_CHECKING:
18
+ from sqlglot.dialects.dialect import DialectType
19
+
20
+ from sqlspec.builder._column import ColumnExpression
21
+ from sqlspec.core import StatementConfig
22
+
23
+ __all__ = (
24
+ "AlterOperation",
25
+ "AlterTable",
26
+ "ColumnDefinition",
27
+ "CommentOn",
28
+ "ConstraintDefinition",
29
+ "CreateIndex",
30
+ "CreateMaterializedView",
31
+ "CreateSchema",
32
+ "CreateTable",
33
+ "CreateTableAsSelect",
34
+ "CreateView",
35
+ "DDLBuilder",
36
+ "DropIndex",
37
+ "DropMaterializedView",
38
+ "DropSchema",
39
+ "DropTable",
40
+ "DropView",
41
+ "RenameTable",
42
+ "Truncate",
43
+ )
44
+
45
+ CONSTRAINT_TYPE_PRIMARY_KEY = "PRIMARY KEY"
46
+ CONSTRAINT_TYPE_FOREIGN_KEY = "FOREIGN KEY"
47
+ CONSTRAINT_TYPE_UNIQUE = "UNIQUE"
48
+ CONSTRAINT_TYPE_CHECK = "CHECK"
49
+
50
+ FOREIGN_KEY_ACTION_CASCADE = "CASCADE"
51
+ FOREIGN_KEY_ACTION_SET_NULL = "SET NULL"
52
+ FOREIGN_KEY_ACTION_SET_DEFAULT = "SET DEFAULT"
53
+ FOREIGN_KEY_ACTION_RESTRICT = "RESTRICT"
54
+ FOREIGN_KEY_ACTION_NO_ACTION = "NO ACTION"
55
+
56
+ VALID_FOREIGN_KEY_ACTIONS = {
57
+ FOREIGN_KEY_ACTION_CASCADE,
58
+ FOREIGN_KEY_ACTION_SET_NULL,
59
+ FOREIGN_KEY_ACTION_SET_DEFAULT,
60
+ FOREIGN_KEY_ACTION_RESTRICT,
61
+ FOREIGN_KEY_ACTION_NO_ACTION,
62
+ None,
63
+ }
64
+
65
+ VALID_CONSTRAINT_TYPES = {
66
+ CONSTRAINT_TYPE_PRIMARY_KEY,
67
+ CONSTRAINT_TYPE_FOREIGN_KEY,
68
+ CONSTRAINT_TYPE_UNIQUE,
69
+ CONSTRAINT_TYPE_CHECK,
70
+ }
71
+
72
+ CURRENT_TIMESTAMP_KEYWORD = "CURRENT_TIMESTAMP"
73
+ CURRENT_DATE_KEYWORD = "CURRENT_DATE"
74
+ CURRENT_TIME_KEYWORD = "CURRENT_TIME"
75
+
76
+
77
+ def build_column_expression(col: "ColumnDefinition") -> "exp.Expr":
78
+ """Build SQLGlot expression for a column definition."""
79
+ col_def = exp.ColumnDef(this=exp.to_identifier(col.name), kind=exp.DataType.build(col.dtype))
80
+
81
+ constraints: list[exp.ColumnConstraint] = []
82
+
83
+ if col.not_null:
84
+ constraints.append(exp.ColumnConstraint(kind=exp.NotNullColumnConstraint()))
85
+
86
+ if col.primary_key:
87
+ constraints.append(exp.ColumnConstraint(kind=exp.PrimaryKeyColumnConstraint()))
88
+
89
+ if col.unique:
90
+ constraints.append(exp.ColumnConstraint(kind=exp.UniqueColumnConstraint()))
91
+
92
+ if col.default is not None:
93
+ default_expr: exp.Expr | None = None
94
+ if isinstance(col.default, str):
95
+ default_upper = col.default.upper()
96
+ if default_upper == CURRENT_TIMESTAMP_KEYWORD:
97
+ default_expr = exp.CurrentTimestamp()
98
+ elif default_upper == CURRENT_DATE_KEYWORD:
99
+ default_expr = exp.CurrentDate()
100
+ elif default_upper == CURRENT_TIME_KEYWORD:
101
+ default_expr = exp.CurrentTime()
102
+ elif "(" in col.default:
103
+ default_expr = exp.maybe_parse(col.default)
104
+ else:
105
+ default_expr = exp.convert(col.default)
106
+ else:
107
+ default_expr = exp.convert(col.default)
108
+
109
+ constraints.append(exp.ColumnConstraint(kind=exp.DefaultColumnConstraint(this=default_expr)))
110
+
111
+ if col.check:
112
+ constraints.append(exp.ColumnConstraint(kind=exp.Check(this=exp.maybe_parse(col.check))))
113
+
114
+ if col.comment:
115
+ constraints.append(exp.ColumnConstraint(kind=exp.CommentColumnConstraint(this=exp.convert(col.comment))))
116
+
117
+ if col.generated:
118
+ constraints.append(
119
+ exp.ColumnConstraint(kind=exp.GeneratedAsIdentityColumnConstraint(this=exp.maybe_parse(col.generated)))
120
+ )
121
+
122
+ if col.collate:
123
+ constraints.append(exp.ColumnConstraint(kind=exp.CollateColumnConstraint(this=exp.to_identifier(col.collate))))
124
+
125
+ if constraints:
126
+ col_def.set("constraints", constraints)
127
+
128
+ return col_def
129
+
130
+
131
+ def build_constraint_expression(constraint: "ConstraintDefinition") -> "exp.Expr | None":
132
+ """Build SQLGlot expression for a table constraint."""
133
+ if constraint.constraint_type == CONSTRAINT_TYPE_PRIMARY_KEY:
134
+ pk_constraint = exp.PrimaryKey(expressions=[exp.to_identifier(col) for col in constraint.columns])
135
+
136
+ if constraint.name:
137
+ return exp.Constraint(this=exp.to_identifier(constraint.name), expression=pk_constraint)
138
+ return pk_constraint
139
+
140
+ if constraint.constraint_type == CONSTRAINT_TYPE_FOREIGN_KEY:
141
+ fk_constraint = exp.ForeignKey(
142
+ expressions=[exp.to_identifier(col) for col in constraint.columns],
143
+ reference=exp.Reference(
144
+ this=exp.to_table(constraint.references_table) if constraint.references_table else None,
145
+ expressions=[exp.to_identifier(col) for col in constraint.references_columns],
146
+ on_delete=constraint.on_delete,
147
+ on_update=constraint.on_update,
148
+ ),
149
+ )
150
+
151
+ if constraint.name:
152
+ return exp.Constraint(this=exp.to_identifier(constraint.name), expression=fk_constraint)
153
+ return fk_constraint
154
+
155
+ if constraint.constraint_type == CONSTRAINT_TYPE_UNIQUE:
156
+ unique_constraint = exp.UniqueKeyProperty(expressions=[exp.to_identifier(col) for col in constraint.columns])
157
+
158
+ if constraint.name:
159
+ return exp.Constraint(this=exp.to_identifier(constraint.name), expression=unique_constraint)
160
+ return unique_constraint
161
+
162
+ if constraint.constraint_type == CONSTRAINT_TYPE_CHECK:
163
+ check_expr = exp.Check(this=exp.maybe_parse(constraint.condition) if constraint.condition else None)
164
+
165
+ if constraint.name:
166
+ return exp.Constraint(this=exp.to_identifier(constraint.name), expression=check_expr)
167
+ return check_expr
168
+
169
+ return None
170
+
171
+
172
+ class DDLBuilder(QueryBuilder):
173
+ """Base class for DDL builders (CREATE, DROP, ALTER, etc)."""
174
+
175
+ __slots__ = ()
176
+
177
+ def __init__(self, dialect: "DialectType" = None) -> None:
178
+ super().__init__(dialect=dialect)
179
+ self._expression: exp.Expr | None = None
180
+
181
+ def _create_base_expression(self) -> exp.Expr:
182
+ msg = "Subclasses must implement _create_base_expression."
183
+ raise NotImplementedError(msg)
184
+
185
+ @property
186
+ def _expected_result_type(self) -> "type[SQLResult]":
187
+ return SQLResult
188
+
189
+ def build(self, dialect: "DialectType" = None) -> "BuiltQuery":
190
+ if self._expression is None:
191
+ self._expression = self._create_base_expression()
192
+ return super().build(dialect=dialect)
193
+
194
+ def to_statement(self, config: "StatementConfig | None" = None) -> "SQL":
195
+ return super().to_statement(config=config)
196
+
197
+
198
+ class ColumnDefinition:
199
+ """Column definition for CREATE TABLE."""
200
+
201
+ __slots__ = (
202
+ "auto_increment",
203
+ "check",
204
+ "collate",
205
+ "comment",
206
+ "default",
207
+ "dtype",
208
+ "generated",
209
+ "name",
210
+ "not_null",
211
+ "primary_key",
212
+ "unique",
213
+ )
214
+
215
+ def __init__(
216
+ self,
217
+ name: str,
218
+ dtype: str,
219
+ default: "Any | None" = None,
220
+ not_null: bool = False,
221
+ primary_key: bool = False,
222
+ unique: bool = False,
223
+ auto_increment: bool = False,
224
+ comment: "str | None" = None,
225
+ check: "str | None" = None,
226
+ generated: "str | None" = None,
227
+ collate: "str | None" = None,
228
+ ) -> None:
229
+ self.name = name
230
+ self.dtype = dtype
231
+ self.default = default
232
+ self.not_null = not_null
233
+ self.primary_key = primary_key
234
+ self.unique = unique
235
+ self.auto_increment = auto_increment
236
+ self.comment = comment
237
+ self.check = check
238
+ self.generated = generated
239
+ self.collate = collate
240
+
241
+
242
+ class ConstraintDefinition:
243
+ """Constraint definition for CREATE TABLE."""
244
+
245
+ __slots__ = (
246
+ "columns",
247
+ "condition",
248
+ "constraint_type",
249
+ "deferrable",
250
+ "initially_deferred",
251
+ "name",
252
+ "on_delete",
253
+ "on_update",
254
+ "references_columns",
255
+ "references_table",
256
+ )
257
+
258
+ def __init__(
259
+ self,
260
+ constraint_type: str,
261
+ name: "str | None" = None,
262
+ columns: "list[str] | None" = None,
263
+ references_table: "str | None" = None,
264
+ references_columns: "list[str] | None" = None,
265
+ condition: "str | None" = None,
266
+ on_delete: "str | None" = None,
267
+ on_update: "str | None" = None,
268
+ deferrable: bool = False,
269
+ initially_deferred: bool = False,
270
+ ) -> None:
271
+ self.constraint_type = constraint_type
272
+ self.name = name
273
+ self.columns = columns or []
274
+ self.references_table = references_table
275
+ self.references_columns = references_columns or []
276
+ self.condition = condition
277
+ self.on_delete = on_delete
278
+ self.on_update = on_update
279
+ self.deferrable = deferrable
280
+ self.initially_deferred = initially_deferred
281
+
282
+
283
+ class CreateTable(DDLBuilder):
284
+ """Builder for CREATE TABLE statements with columns and constraints.
285
+
286
+ Example:
287
+ builder = (
288
+ CreateTable("users")
289
+ .column("id", "SERIAL", primary_key=True)
290
+ .column("email", "VARCHAR(255)", not_null=True, unique=True)
291
+ .column("created_at", "TIMESTAMP", default="CURRENT_TIMESTAMP")
292
+ .foreign_key_constraint("org_id", "organizations", "id")
293
+ )
294
+ sql = builder.build().sql
295
+ """
296
+
297
+ __slots__ = (
298
+ "_columns",
299
+ "_constraints",
300
+ "_if_not_exists",
301
+ "_like_table",
302
+ "_partition_by",
303
+ "_schema",
304
+ "_table_name",
305
+ "_table_options",
306
+ "_tablespace",
307
+ "_temporary",
308
+ )
309
+
310
+ def __init__(self, table_name: str, dialect: "DialectType" = None) -> None:
311
+ super().__init__(dialect=dialect)
312
+ self._table_name = table_name
313
+ self._if_not_exists = False
314
+ self._temporary = False
315
+ self._columns: list[ColumnDefinition] = []
316
+ self._constraints: list[ConstraintDefinition] = []
317
+ self._table_options: dict[str, Any] = {}
318
+ self._schema: str | None = None
319
+ self._tablespace: str | None = None
320
+ self._like_table: str | None = None
321
+ self._partition_by: str | None = None
322
+
323
+ def in_schema(self, schema_name: str) -> "Self":
324
+ """Set the schema for the table."""
325
+ self._schema = schema_name
326
+ return self
327
+
328
+ def if_not_exists(self) -> "Self":
329
+ """Add IF NOT EXISTS clause."""
330
+ self._if_not_exists = True
331
+ return self
332
+
333
+ def temporary(self) -> "Self":
334
+ """Create a temporary table."""
335
+ self._temporary = True
336
+ return self
337
+
338
+ def like(self, source_table: str) -> "Self":
339
+ """Create table LIKE another table."""
340
+ self._like_table = source_table
341
+ return self
342
+
343
+ def tablespace(self, name: str) -> "Self":
344
+ """Set tablespace for the table."""
345
+ self._tablespace = name
346
+ return self
347
+
348
+ def partition_by(self, partition_spec: str) -> "Self":
349
+ """Set partitioning specification."""
350
+ self._partition_by = partition_spec
351
+ return self
352
+
353
+ @property
354
+ def columns(self) -> "list[ColumnDefinition]":
355
+ """Get the list of column definitions for this table.
356
+
357
+ Returns:
358
+ List of ColumnDefinition objects.
359
+ """
360
+ return self._columns
361
+
362
+ def column(
363
+ self,
364
+ name: str,
365
+ dtype: str,
366
+ default: "Any | None" = None,
367
+ not_null: bool = False,
368
+ primary_key: bool = False,
369
+ unique: bool = False,
370
+ auto_increment: bool = False,
371
+ comment: "str | None" = None,
372
+ check: "str | None" = None,
373
+ generated: "str | None" = None,
374
+ collate: "str | None" = None,
375
+ ) -> "Self":
376
+ """Add a column definition to the table."""
377
+ if not name:
378
+ self._raise_sql_builder_error("Column name must be a non-empty string")
379
+
380
+ if not dtype:
381
+ self._raise_sql_builder_error("Column type must be a non-empty string")
382
+
383
+ if any(col.name == name for col in self._columns):
384
+ self._raise_sql_builder_error(f"Column '{name}' already defined")
385
+
386
+ column_def = ColumnDefinition(
387
+ name=name,
388
+ dtype=dtype,
389
+ default=default,
390
+ not_null=not_null,
391
+ primary_key=primary_key,
392
+ unique=unique,
393
+ auto_increment=auto_increment,
394
+ comment=comment,
395
+ check=check,
396
+ generated=generated,
397
+ collate=collate,
398
+ )
399
+
400
+ self._columns.append(column_def)
401
+
402
+ if primary_key and not self._has_primary_key_constraint():
403
+ self.primary_key_constraint([name])
404
+
405
+ return self
406
+
407
+ def primary_key_constraint(self, columns: "str | list[str]", name: "str | None" = None) -> "Self":
408
+ """Add a primary key constraint."""
409
+ col_list = [columns] if isinstance(columns, str) else list(columns)
410
+
411
+ if not col_list:
412
+ self._raise_sql_builder_error("Primary key must include at least one column")
413
+
414
+ existing_pk = self._find_primary_key_constraint()
415
+ if existing_pk:
416
+ for col in col_list:
417
+ if col not in existing_pk.columns:
418
+ existing_pk.columns.append(col)
419
+ else:
420
+ constraint = ConstraintDefinition(constraint_type=CONSTRAINT_TYPE_PRIMARY_KEY, name=name, columns=col_list)
421
+ self._constraints.append(constraint)
422
+
423
+ return self
424
+
425
+ def foreign_key_constraint(
426
+ self,
427
+ columns: "str | list[str]",
428
+ references_table: str,
429
+ references_columns: "str | list[str]",
430
+ name: "str | None" = None,
431
+ on_delete: "str | None" = None,
432
+ on_update: "str | None" = None,
433
+ deferrable: bool = False,
434
+ initially_deferred: bool = False,
435
+ ) -> "Self":
436
+ """Add a foreign key constraint."""
437
+ col_list = [columns] if isinstance(columns, str) else list(columns)
438
+
439
+ ref_col_list = [references_columns] if isinstance(references_columns, str) else list(references_columns)
440
+
441
+ if len(col_list) != len(ref_col_list):
442
+ self._raise_sql_builder_error("Foreign key columns and referenced columns must have same length")
443
+
444
+ self._validate_foreign_key_action(on_delete, "ON DELETE")
445
+ self._validate_foreign_key_action(on_update, "ON UPDATE")
446
+
447
+ constraint = ConstraintDefinition(
448
+ constraint_type=CONSTRAINT_TYPE_FOREIGN_KEY,
449
+ name=name,
450
+ columns=col_list,
451
+ references_table=references_table,
452
+ references_columns=ref_col_list,
453
+ on_delete=on_delete.upper() if on_delete else None,
454
+ on_update=on_update.upper() if on_update else None,
455
+ deferrable=deferrable,
456
+ initially_deferred=initially_deferred,
457
+ )
458
+
459
+ self._constraints.append(constraint)
460
+ return self
461
+
462
+ def unique_constraint(self, columns: "str | list[str]", name: "str | None" = None) -> "Self":
463
+ """Add a unique constraint."""
464
+ col_list = [columns] if isinstance(columns, str) else list(columns)
465
+
466
+ if not col_list:
467
+ self._raise_sql_builder_error("Unique constraint must include at least one column")
468
+
469
+ constraint = ConstraintDefinition(constraint_type=CONSTRAINT_TYPE_UNIQUE, name=name, columns=col_list)
470
+
471
+ self._constraints.append(constraint)
472
+ return self
473
+
474
+ def check_constraint(self, condition: Union[str, "ColumnExpression"], name: "str | None" = None) -> "Self":
475
+ """Add a check constraint."""
476
+ if not condition:
477
+ self._raise_sql_builder_error("Check constraint must have a condition")
478
+
479
+ condition_str: str
480
+ if has_sqlglot_expression(condition):
481
+ sqlglot_expr = condition.sqlglot_expression
482
+ condition_str = sqlglot_expr.sql(dialect=self.dialect) if sqlglot_expr else str(condition)
483
+ else:
484
+ condition_str = str(condition)
485
+
486
+ constraint = ConstraintDefinition(constraint_type=CONSTRAINT_TYPE_CHECK, name=name, condition=condition_str)
487
+
488
+ self._constraints.append(constraint)
489
+ return self
490
+
491
+ def engine(self, engine_name: str) -> "Self":
492
+ """Set storage engine (MySQL/MariaDB)."""
493
+ self._table_options["engine"] = engine_name
494
+ return self
495
+
496
+ def charset(self, charset_name: str) -> "Self":
497
+ """Set character set."""
498
+ self._table_options["charset"] = charset_name
499
+ return self
500
+
501
+ def collate(self, collation: str) -> "Self":
502
+ """Set table collation."""
503
+ self._table_options["collate"] = collation
504
+ return self
505
+
506
+ def comment(self, comment_text: str) -> "Self":
507
+ """Set table comment."""
508
+ self._table_options["comment"] = comment_text
509
+ return self
510
+
511
+ def with_option(self, key: str, value: "Any") -> "Self":
512
+ """Add custom table option."""
513
+ self._table_options[key] = value
514
+ return self
515
+
516
+ def _create_base_expression(self) -> "exp.Expr":
517
+ """Create the SQLGlot expression for CREATE TABLE."""
518
+ if not self._columns and not self._like_table:
519
+ self._raise_sql_builder_error("Table must have at least one column or use LIKE clause")
520
+
521
+ column_defs: list[exp.Expr] = []
522
+ for col in self._columns:
523
+ col_expr = build_column_expression(col)
524
+ column_defs.append(col_expr)
525
+
526
+ for constraint in self._constraints:
527
+ if self._is_redundant_single_column_primary_key(constraint):
528
+ continue
529
+
530
+ constraint_expr = build_constraint_expression(constraint)
531
+ if constraint_expr:
532
+ column_defs.append(constraint_expr)
533
+
534
+ props: list[exp.Property] = []
535
+ if self._table_options.get("engine"):
536
+ props.append(
537
+ exp.Property(
538
+ this=exp.to_identifier("ENGINE"), value=exp.to_identifier(self._table_options.get("engine"))
539
+ )
540
+ )
541
+ if self._tablespace:
542
+ props.append(exp.Property(this=exp.to_identifier("TABLESPACE"), value=exp.to_identifier(self._tablespace)))
543
+ if self._partition_by:
544
+ props.append(exp.Property(this=exp.to_identifier("PARTITION BY"), value=exp.convert(self._partition_by)))
545
+
546
+ for key, value in self._table_options.items():
547
+ if key != "engine":
548
+ props.append(exp.Property(this=exp.to_identifier(key.upper()), value=exp.convert(value)))
549
+
550
+ properties_node = exp.Properties(expressions=props) if props else None
551
+
552
+ if self._schema:
553
+ table_identifier = exp.Table(this=exp.to_identifier(self._table_name), db=exp.to_identifier(self._schema))
554
+ else:
555
+ table_identifier = exp.Table(this=exp.to_identifier(self._table_name))
556
+
557
+ schema_expr = exp.Schema(this=table_identifier, expressions=column_defs)
558
+
559
+ like_expr = None
560
+ if self._like_table:
561
+ like_expr = exp.to_table(self._like_table)
562
+
563
+ return exp.Create(
564
+ kind="TABLE",
565
+ this=schema_expr,
566
+ exists=self._if_not_exists,
567
+ temporary=self._temporary,
568
+ properties=properties_node,
569
+ like=like_expr,
570
+ )
571
+
572
+ def _has_primary_key_constraint(self) -> bool:
573
+ """Check if table already has a primary key constraint."""
574
+ return any(c.constraint_type == CONSTRAINT_TYPE_PRIMARY_KEY for c in self._constraints)
575
+
576
+ def _find_primary_key_constraint(self) -> "ConstraintDefinition | None":
577
+ """Find existing primary key constraint."""
578
+ return next((c for c in self._constraints if c.constraint_type == CONSTRAINT_TYPE_PRIMARY_KEY), None)
579
+
580
+ def _validate_foreign_key_action(self, action: "str | None", action_type: str) -> None:
581
+ """Validate foreign key action (ON DELETE or ON UPDATE)."""
582
+ if action and action.upper() not in VALID_FOREIGN_KEY_ACTIONS:
583
+ self._raise_sql_builder_error(f"Invalid {action_type} action: {action}")
584
+
585
+ def _is_redundant_single_column_primary_key(self, constraint: "ConstraintDefinition") -> bool:
586
+ """Check if constraint is a redundant single-column primary key."""
587
+ if constraint.constraint_type != CONSTRAINT_TYPE_PRIMARY_KEY or len(constraint.columns) != 1:
588
+ return False
589
+
590
+ col_name = constraint.columns[0]
591
+ return any(c.name == col_name and c.primary_key for c in self._columns)
592
+
593
+
594
+ class DropTable(DDLBuilder):
595
+ """Builder for DROP TABLE [IF EXISTS] ... [CASCADE|RESTRICT]."""
596
+
597
+ __slots__ = ("_cascade", "_if_exists", "_table_name")
598
+
599
+ def __init__(self, table_name: str, dialect: "DialectType" = None) -> None:
600
+ """Initialize DROP TABLE with table name.
601
+
602
+ Args:
603
+ table_name: Name of the table to drop
604
+ dialect: SQL dialect to use
605
+ """
606
+ super().__init__(dialect=dialect)
607
+ self._table_name = table_name
608
+ self._if_exists = False
609
+ self._cascade: bool | None = None
610
+
611
+ def table(self, name: str) -> Self:
612
+ self._table_name = name
613
+ return self
614
+
615
+ def if_exists(self) -> Self:
616
+ self._if_exists = True
617
+ return self
618
+
619
+ def cascade(self) -> Self:
620
+ self._cascade = True
621
+ return self
622
+
623
+ def restrict(self) -> Self:
624
+ self._cascade = False
625
+ return self
626
+
627
+ def _create_base_expression(self) -> exp.Expr:
628
+ if not self._table_name:
629
+ self._raise_sql_builder_error("Table name must be set for DROP TABLE.")
630
+ return exp.Drop(
631
+ kind="TABLE", this=exp.to_table(self._table_name), exists=self._if_exists, cascade=self._cascade
632
+ )
633
+
634
+
635
+ class DropIndex(DDLBuilder):
636
+ """Builder for DROP INDEX [IF EXISTS] ... [ON table] [CASCADE|RESTRICT]."""
637
+
638
+ __slots__ = ("_cascade", "_if_exists", "_index_name", "_table_name")
639
+
640
+ def __init__(self, index_name: str, dialect: "DialectType" = None) -> None:
641
+ """Initialize DROP INDEX with index name.
642
+
643
+ Args:
644
+ index_name: Name of the index to drop
645
+ dialect: SQL dialect to use
646
+ """
647
+ super().__init__(dialect=dialect)
648
+ self._index_name = index_name
649
+ self._table_name: str | None = None
650
+ self._if_exists = False
651
+ self._cascade: bool | None = None
652
+
653
+ def name(self, index_name: str) -> Self:
654
+ self._index_name = index_name
655
+ return self
656
+
657
+ def on_table(self, table_name: str) -> Self:
658
+ self._table_name = table_name
659
+ return self
660
+
661
+ def if_exists(self) -> Self:
662
+ self._if_exists = True
663
+ return self
664
+
665
+ def cascade(self) -> Self:
666
+ self._cascade = True
667
+ return self
668
+
669
+ def restrict(self) -> Self:
670
+ self._cascade = False
671
+ return self
672
+
673
+ def _create_base_expression(self) -> exp.Expr:
674
+ if not self._index_name:
675
+ self._raise_sql_builder_error("Index name must be set for DROP INDEX.")
676
+ return exp.Drop(
677
+ kind="INDEX",
678
+ this=exp.to_identifier(self._index_name),
679
+ table=exp.to_table(self._table_name) if self._table_name else None,
680
+ exists=self._if_exists,
681
+ cascade=self._cascade,
682
+ )
683
+
684
+
685
+ class DropView(DDLBuilder):
686
+ """Builder for DROP VIEW [IF EXISTS] ... [CASCADE|RESTRICT]."""
687
+
688
+ __slots__ = ("_cascade", "_if_exists", "_view_name")
689
+
690
+ def __init__(self, view_name: str, dialect: "DialectType" = None) -> None:
691
+ """Initialize DROP VIEW with view name.
692
+
693
+ Args:
694
+ view_name: Name of the view to drop
695
+ dialect: SQL dialect to use
696
+ """
697
+ super().__init__(dialect=dialect)
698
+ self._view_name = view_name
699
+ self._if_exists = False
700
+ self._cascade: bool | None = None
701
+
702
+ def name(self, view_name: str) -> Self:
703
+ self._view_name = view_name
704
+ return self
705
+
706
+ def if_exists(self) -> Self:
707
+ self._if_exists = True
708
+ return self
709
+
710
+ def cascade(self) -> Self:
711
+ self._cascade = True
712
+ return self
713
+
714
+ def restrict(self) -> Self:
715
+ self._cascade = False
716
+ return self
717
+
718
+ def _create_base_expression(self) -> exp.Expr:
719
+ if not self._view_name:
720
+ self._raise_sql_builder_error("View name must be set for DROP VIEW.")
721
+ return exp.Drop(
722
+ kind="VIEW", this=exp.to_identifier(self._view_name), exists=self._if_exists, cascade=self._cascade
723
+ )
724
+
725
+
726
+ class DropSchema(DDLBuilder):
727
+ """Builder for DROP SCHEMA [IF EXISTS] ... [CASCADE|RESTRICT]."""
728
+
729
+ __slots__ = ("_cascade", "_if_exists", "_schema_name")
730
+
731
+ def __init__(self, schema_name: str, dialect: "DialectType" = None) -> None:
732
+ """Initialize DROP SCHEMA with schema name.
733
+
734
+ Args:
735
+ schema_name: Name of the schema to drop
736
+ dialect: SQL dialect to use
737
+ """
738
+ super().__init__(dialect=dialect)
739
+ self._schema_name = schema_name
740
+ self._if_exists = False
741
+ self._cascade: bool | None = None
742
+
743
+ def name(self, schema_name: str) -> Self:
744
+ self._schema_name = schema_name
745
+ return self
746
+
747
+ def if_exists(self) -> Self:
748
+ self._if_exists = True
749
+ return self
750
+
751
+ def cascade(self) -> Self:
752
+ self._cascade = True
753
+ return self
754
+
755
+ def restrict(self) -> Self:
756
+ self._cascade = False
757
+ return self
758
+
759
+ def _create_base_expression(self) -> exp.Expr:
760
+ if not self._schema_name:
761
+ self._raise_sql_builder_error("Schema name must be set for DROP SCHEMA.")
762
+ return exp.Drop(
763
+ kind="SCHEMA", this=exp.to_identifier(self._schema_name), exists=self._if_exists, cascade=self._cascade
764
+ )
765
+
766
+
767
+ class DropMaterializedView(DDLBuilder):
768
+ """Builder for DROP MATERIALIZED VIEW [IF EXISTS] ... [CASCADE|RESTRICT]."""
769
+
770
+ __slots__ = ("_cascade", "_if_exists", "_view_name")
771
+
772
+ def __init__(self, view_name: str, dialect: "DialectType" = None) -> None:
773
+ """Initialize DROP MATERIALIZED VIEW with view name.
774
+
775
+ Args:
776
+ view_name: Name of the materialized view to drop
777
+ dialect: SQL dialect to use
778
+ """
779
+ super().__init__(dialect=dialect)
780
+ self._view_name = view_name
781
+ self._if_exists = False
782
+ self._cascade: bool | None = None
783
+
784
+ def name(self, view_name: str) -> Self:
785
+ """Set the materialized view name."""
786
+ self._view_name = view_name
787
+ return self
788
+
789
+ def if_exists(self) -> Self:
790
+ """Add IF EXISTS clause."""
791
+ self._if_exists = True
792
+ return self
793
+
794
+ def cascade(self) -> Self:
795
+ """Add CASCADE to drop dependent objects."""
796
+ self._cascade = True
797
+ return self
798
+
799
+ def restrict(self) -> Self:
800
+ """Add RESTRICT to prevent dropping if dependencies exist."""
801
+ self._cascade = False
802
+ return self
803
+
804
+ def _create_base_expression(self) -> exp.Expr:
805
+ if not self._view_name:
806
+ self._raise_sql_builder_error("View name must be set for DROP MATERIALIZED VIEW.")
807
+ return exp.Drop(
808
+ kind="MATERIALIZED VIEW",
809
+ this=exp.to_identifier(self._view_name),
810
+ exists=self._if_exists,
811
+ cascade=self._cascade,
812
+ )
813
+
814
+
815
+ class CreateIndex(DDLBuilder):
816
+ """Builder for CREATE [UNIQUE] INDEX [IF NOT EXISTS] ... ON ... (...)."""
817
+
818
+ __slots__ = ("_columns", "_if_not_exists", "_index_name", "_table_name", "_unique", "_using", "_where")
819
+
820
+ def __init__(self, index_name: str, dialect: "DialectType" = None) -> None:
821
+ """Initialize CREATE INDEX with index name.
822
+
823
+ Args:
824
+ index_name: Name of the index to create
825
+ dialect: SQL dialect to use
826
+ """
827
+ super().__init__(dialect=dialect)
828
+ self._index_name = index_name
829
+ self._table_name: str | None = None
830
+ self._columns: list[str | exp.Ordered | exp.Expr] = []
831
+ self._unique = False
832
+ self._if_not_exists = False
833
+ self._using: str | None = None
834
+ self._where: str | exp.Expr | None = None
835
+
836
+ def name(self, index_name: str) -> Self:
837
+ self._index_name = index_name
838
+ return self
839
+
840
+ def on_table(self, table_name: str) -> Self:
841
+ self._table_name = table_name
842
+ return self
843
+
844
+ def columns(self, *cols: str | exp.Ordered | exp.Expr) -> Self:
845
+ self._columns.extend(cols)
846
+ return self
847
+
848
+ def expressions(self, *exprs: str | exp.Expr) -> Self:
849
+ self._columns.extend(exprs)
850
+ return self
851
+
852
+ def unique(self) -> Self:
853
+ self._unique = True
854
+ return self
855
+
856
+ def if_not_exists(self) -> Self:
857
+ self._if_not_exists = True
858
+ return self
859
+
860
+ def using(self, method: str) -> Self:
861
+ self._using = method
862
+ return self
863
+
864
+ def where(self, condition: str | exp.Expr) -> Self:
865
+ self._where = condition
866
+ return self
867
+
868
+ def _create_base_expression(self) -> exp.Expr:
869
+ """Build the CREATE INDEX expression used by this builder.
870
+
871
+ Columns are turned into raw expressions (not ``Ordered``) to preserve natural NULL ordering,
872
+ string ``where`` clauses become expressions, and the final ``exp.Index`` is wrapped in an ``exp.Create`` with the configured flags.
873
+ """
874
+ if not self._index_name or not self._table_name:
875
+ self._raise_sql_builder_error("Index name and table name must be set for CREATE INDEX.")
876
+
877
+ cols: list[exp.Expr] = []
878
+ for col in self._columns:
879
+ if isinstance(col, str):
880
+ cols.append(exp.column(col))
881
+ else:
882
+ cols.append(col)
883
+
884
+ where_expr = None
885
+ if self._where:
886
+ where_expr = exp.condition(self._where) if isinstance(self._where, str) else self._where
887
+
888
+ index_params = exp.IndexParameters(columns=cols) if cols else None
889
+
890
+ index_expr = exp.Index(
891
+ this=exp.to_identifier(self._index_name), table=exp.to_table(self._table_name), params=index_params
892
+ )
893
+
894
+ if where_expr:
895
+ index_expr.set("where", where_expr)
896
+
897
+ return exp.Create(kind="INDEX", this=index_expr, unique=self._unique, exists=self._if_not_exists)
898
+
899
+
900
+ class Truncate(DDLBuilder):
901
+ """Builder for TRUNCATE TABLE ... [CASCADE|RESTRICT] [RESTART IDENTITY|CONTINUE IDENTITY]."""
902
+
903
+ __slots__ = ("_cascade", "_identity", "_table_name")
904
+
905
+ def __init__(self, table_name: str, dialect: "DialectType" = None) -> None:
906
+ """Initialize TRUNCATE with table name.
907
+
908
+ Args:
909
+ table_name: Name of the table to truncate
910
+ dialect: SQL dialect to use
911
+ """
912
+ super().__init__(dialect=dialect)
913
+ self._table_name = table_name
914
+ self._cascade: bool | None = None
915
+ self._identity: str | None = None
916
+
917
+ def table(self, name: str) -> Self:
918
+ self._table_name = name
919
+ return self
920
+
921
+ def cascade(self) -> Self:
922
+ self._cascade = True
923
+ return self
924
+
925
+ def restrict(self) -> Self:
926
+ self._cascade = False
927
+ return self
928
+
929
+ def restart_identity(self) -> Self:
930
+ self._identity = "RESTART"
931
+ return self
932
+
933
+ def continue_identity(self) -> Self:
934
+ self._identity = "CONTINUE"
935
+ return self
936
+
937
+ def _create_base_expression(self) -> exp.Expr:
938
+ if not self._table_name:
939
+ self._raise_sql_builder_error("Table name must be set for TRUNCATE TABLE.")
940
+ identity_expr = exp.Var(this=self._identity) if self._identity else None
941
+ return exp.TruncateTable(this=exp.to_table(self._table_name), cascade=self._cascade, identity=identity_expr)
942
+
943
+
944
+ class AlterOperation:
945
+ """Represents a single ALTER TABLE operation."""
946
+
947
+ __slots__ = (
948
+ "after_column",
949
+ "column_definition",
950
+ "column_name",
951
+ "constraint_definition",
952
+ "constraint_name",
953
+ "first",
954
+ "new_name",
955
+ "new_type",
956
+ "operation_type",
957
+ "using_expression",
958
+ )
959
+
960
+ def __init__(
961
+ self,
962
+ operation_type: str,
963
+ column_name: "str | None" = None,
964
+ column_definition: "ColumnDefinition | None" = None,
965
+ constraint_name: "str | None" = None,
966
+ constraint_definition: "ConstraintDefinition | None" = None,
967
+ new_type: "str | None" = None,
968
+ new_name: "str | None" = None,
969
+ after_column: "str | None" = None,
970
+ first: bool = False,
971
+ using_expression: "str | None" = None,
972
+ ) -> None:
973
+ self.operation_type = operation_type
974
+ self.column_name = column_name
975
+ self.column_definition = column_definition
976
+ self.constraint_name = constraint_name
977
+ self.constraint_definition = constraint_definition
978
+ self.new_type = new_type
979
+ self.new_name = new_name
980
+ self.after_column = after_column
981
+ self.first = first
982
+ self.using_expression = using_expression
983
+
984
+
985
+ class CreateSchema(DDLBuilder):
986
+ """Builder for CREATE SCHEMA [IF NOT EXISTS] schema_name [AUTHORIZATION user_name]."""
987
+
988
+ __slots__ = ("_authorization", "_if_not_exists", "_schema_name")
989
+
990
+ def __init__(self, schema_name: str, dialect: "DialectType" = None) -> None:
991
+ """Initialize CREATE SCHEMA with schema name.
992
+
993
+ Args:
994
+ schema_name: Name of the schema to create
995
+ dialect: SQL dialect to use
996
+ """
997
+ super().__init__(dialect=dialect)
998
+ self._schema_name = schema_name
999
+ self._if_not_exists = False
1000
+ self._authorization: str | None = None
1001
+
1002
+ def name(self, schema_name: str) -> Self:
1003
+ self._schema_name = schema_name
1004
+ return self
1005
+
1006
+ def if_not_exists(self) -> Self:
1007
+ self._if_not_exists = True
1008
+ return self
1009
+
1010
+ def authorization(self, user_name: str) -> Self:
1011
+ self._authorization = user_name
1012
+ return self
1013
+
1014
+ def _create_base_expression(self) -> exp.Expr:
1015
+ if not self._schema_name:
1016
+ self._raise_sql_builder_error("Schema name must be set for CREATE SCHEMA.")
1017
+ props: list[exp.Property] = []
1018
+ if self._authorization:
1019
+ props.append(
1020
+ exp.Property(this=exp.to_identifier("AUTHORIZATION"), value=exp.to_identifier(self._authorization))
1021
+ )
1022
+ properties_node = exp.Properties(expressions=props) if props else None
1023
+ return exp.Create(
1024
+ kind="SCHEMA",
1025
+ this=exp.to_identifier(self._schema_name),
1026
+ exists=self._if_not_exists,
1027
+ properties=properties_node,
1028
+ )
1029
+
1030
+
1031
+ class CreateTableAsSelect(DDLBuilder):
1032
+ """Builder for CREATE TABLE [IF NOT EXISTS] ... AS SELECT ... (CTAS).
1033
+
1034
+ Example:
1035
+ builder = (
1036
+ CreateTableAsSelectBuilder()
1037
+ .name("my_table")
1038
+ .if_not_exists()
1039
+ .columns("id", "name")
1040
+ .as_select(select_builder)
1041
+ )
1042
+ sql = builder.build().sql
1043
+
1044
+ Methods:
1045
+ - name(table_name: str): Set the table name.
1046
+ - if_not_exists(): Add IF NOT EXISTS.
1047
+ - columns(*cols: str): Set explicit column list (optional).
1048
+ - as_select(select_query): Set the SELECT source (SQL, SelectBuilder, or str).
1049
+ """
1050
+
1051
+ __slots__ = ("_columns", "_if_not_exists", "_select_query", "_table_name")
1052
+
1053
+ def __init__(self, dialect: "DialectType" = None) -> None:
1054
+ super().__init__(dialect=dialect)
1055
+ self._table_name: str | None = None
1056
+ self._if_not_exists = False
1057
+ self._columns: list[str] = []
1058
+ self._select_query: object | None = None
1059
+
1060
+ def name(self, table_name: str) -> Self:
1061
+ self._table_name = table_name
1062
+ return self
1063
+
1064
+ def if_not_exists(self) -> Self:
1065
+ self._if_not_exists = True
1066
+ return self
1067
+
1068
+ def columns(self, *cols: str) -> Self:
1069
+ self._columns = list(cols)
1070
+ return self
1071
+
1072
+ def as_select(self, select_query: "str | exp.Expr") -> Self:
1073
+ self._select_query = select_query
1074
+ return self
1075
+
1076
+ def _create_base_expression(self) -> exp.Expr:
1077
+ if not self._table_name:
1078
+ self._raise_sql_builder_error("Table name must be set for CREATE TABLE AS SELECT.")
1079
+ if self._select_query is None:
1080
+ self._raise_sql_builder_error("SELECT query must be set for CREATE TABLE AS SELECT.")
1081
+
1082
+ select_expr = None
1083
+ select_parameters = None
1084
+
1085
+ if isinstance(self._select_query, SQL):
1086
+ select_expr = self._select_query.expression
1087
+ select_parameters = self._select_query.parameters
1088
+ elif isinstance(self._select_query, Select):
1089
+ select_expr = self._select_query.get_expression()
1090
+ select_parameters = self._select_query.parameters
1091
+
1092
+ with_ctes = self._select_query.with_ctes
1093
+ if with_ctes and select_expr and isinstance(select_expr, exp.Select):
1094
+ for alias, cte in with_ctes.items():
1095
+ if has_with_method(select_expr):
1096
+ select_expr = select_expr.with_(cte.this, as_=alias, copy=False)
1097
+ elif isinstance(self._select_query, str):
1098
+ select_expr = exp.maybe_parse(self._select_query)
1099
+ select_parameters = None
1100
+ else:
1101
+ self._raise_sql_builder_error("Unsupported type for SELECT query in CTAS.")
1102
+ if select_expr is None:
1103
+ self._raise_sql_builder_error("SELECT query must be a valid SELECT expression.")
1104
+
1105
+ if select_parameters:
1106
+ for p_name, p_value in select_parameters.items():
1107
+ self._parameters[p_name] = p_value
1108
+
1109
+ schema_expr = None
1110
+ if self._columns:
1111
+ schema_expr = exp.Schema(expressions=[exp.column(c) for c in self._columns])
1112
+
1113
+ return exp.Create(
1114
+ kind="TABLE",
1115
+ this=exp.to_table(self._table_name),
1116
+ exists=self._if_not_exists,
1117
+ expression=select_expr,
1118
+ schema=schema_expr,
1119
+ )
1120
+
1121
+
1122
+ class CreateMaterializedView(DDLBuilder):
1123
+ """Builder for CREATE MATERIALIZED VIEW [IF NOT EXISTS] ... AS SELECT ..."""
1124
+
1125
+ __slots__ = (
1126
+ "_columns",
1127
+ "_hints",
1128
+ "_if_not_exists",
1129
+ "_refresh_mode",
1130
+ "_select_query",
1131
+ "_storage_parameters",
1132
+ "_tablespace",
1133
+ "_using_index",
1134
+ "_view_name",
1135
+ "_with_data",
1136
+ )
1137
+
1138
+ def __init__(self, view_name: str, dialect: "DialectType" = None) -> None:
1139
+ """Initialize CREATE MATERIALIZED VIEW with view name.
1140
+
1141
+ Args:
1142
+ view_name: Name of the materialized view to create
1143
+ dialect: SQL dialect to use
1144
+ """
1145
+ super().__init__(dialect=dialect)
1146
+ self._view_name = view_name
1147
+ self._if_not_exists = False
1148
+ self._columns: list[str] = []
1149
+ self._select_query: str | exp.Expr | None = None
1150
+ self._with_data: bool | None = None
1151
+ self._refresh_mode: str | None = None
1152
+ self._storage_parameters: dict[str, Any] = {}
1153
+ self._tablespace: str | None = None
1154
+ self._using_index: str | None = None
1155
+ self._hints: list[str] = []
1156
+
1157
+ def name(self, view_name: str) -> Self:
1158
+ self._view_name = view_name
1159
+ return self
1160
+
1161
+ def if_not_exists(self) -> Self:
1162
+ self._if_not_exists = True
1163
+ return self
1164
+
1165
+ def columns(self, *cols: str) -> Self:
1166
+ self._columns = list(cols)
1167
+ return self
1168
+
1169
+ def as_select(self, select_query: "str | exp.Expr") -> Self:
1170
+ self._select_query = select_query
1171
+ return self
1172
+
1173
+ def with_data(self) -> Self:
1174
+ self._with_data = True
1175
+ return self
1176
+
1177
+ def no_data(self) -> Self:
1178
+ self._with_data = False
1179
+ return self
1180
+
1181
+ def refresh_mode(self, mode: str) -> Self:
1182
+ self._refresh_mode = mode
1183
+ return self
1184
+
1185
+ def storage_parameter(self, key: str, value: Any) -> Self:
1186
+ self._storage_parameters[key] = value
1187
+ return self
1188
+
1189
+ def tablespace(self, name: str) -> Self:
1190
+ self._tablespace = name
1191
+ return self
1192
+
1193
+ def using_index(self, index_name: str) -> Self:
1194
+ self._using_index = index_name
1195
+ return self
1196
+
1197
+ def with_hint(self, hint: str) -> Self:
1198
+ self._hints.append(hint)
1199
+ return self
1200
+
1201
+ def _create_base_expression(self) -> exp.Expr:
1202
+ if not self._view_name:
1203
+ self._raise_sql_builder_error("View name must be set for CREATE MATERIALIZED VIEW.")
1204
+ if self._select_query is None:
1205
+ self._raise_sql_builder_error("SELECT query must be set for CREATE MATERIALIZED VIEW.")
1206
+
1207
+ select_expr: exp.Expr | None = None
1208
+ select_parameters: dict[str, Any] | None = None
1209
+
1210
+ if isinstance(self._select_query, SQL):
1211
+ select_expr = self._select_query.expression
1212
+ select_parameters = self._select_query.parameters
1213
+ elif isinstance(self._select_query, Select):
1214
+ select_expr = self._select_query.get_expression()
1215
+ select_parameters = self._select_query.parameters
1216
+ elif isinstance(self._select_query, str):
1217
+ select_expr = exp.maybe_parse(self._select_query)
1218
+ select_parameters = None
1219
+ else:
1220
+ self._raise_sql_builder_error("Unsupported type for SELECT query in materialized view.")
1221
+ if select_expr is None or not isinstance(select_expr, exp.Select):
1222
+ self._raise_sql_builder_error("SELECT query must be a valid SELECT expression.")
1223
+
1224
+ if select_parameters:
1225
+ for p_name, p_value in select_parameters.items():
1226
+ self._parameters[p_name] = p_value
1227
+
1228
+ schema_expr = None
1229
+ if self._columns:
1230
+ schema_expr = exp.Schema(expressions=[exp.column(c) for c in self._columns])
1231
+
1232
+ props: list[exp.Property] = []
1233
+ if self._refresh_mode:
1234
+ props.append(exp.Property(this=exp.to_identifier("REFRESH_MODE"), value=exp.convert(self._refresh_mode)))
1235
+ if self._tablespace:
1236
+ props.append(exp.Property(this=exp.to_identifier("TABLESPACE"), value=exp.to_identifier(self._tablespace)))
1237
+ if self._using_index:
1238
+ props.append(
1239
+ exp.Property(this=exp.to_identifier("USING_INDEX"), value=exp.to_identifier(self._using_index))
1240
+ )
1241
+ for k, v in self._storage_parameters.items():
1242
+ props.append(exp.Property(this=exp.to_identifier(k), value=exp.convert(str(v))))
1243
+ if self._with_data is not None:
1244
+ props.append(exp.Property(this=exp.to_identifier("WITH_DATA" if self._with_data else "NO_DATA")))
1245
+ props.extend(exp.Property(this=exp.to_identifier("HINT"), value=exp.convert(hint)) for hint in self._hints)
1246
+ properties_node = exp.Properties(expressions=props) if props else None
1247
+
1248
+ return exp.Create(
1249
+ kind="MATERIALIZED_VIEW",
1250
+ this=exp.to_identifier(self._view_name),
1251
+ exists=self._if_not_exists,
1252
+ expression=select_expr,
1253
+ schema=schema_expr,
1254
+ properties=properties_node,
1255
+ )
1256
+
1257
+
1258
+ class CreateView(DDLBuilder):
1259
+ """Builder for CREATE VIEW [IF NOT EXISTS] ... AS SELECT ..."""
1260
+
1261
+ __slots__ = ("_columns", "_hints", "_if_not_exists", "_select_query", "_view_name")
1262
+
1263
+ def __init__(self, view_name: str, dialect: "DialectType" = None) -> None:
1264
+ """Initialize CREATE VIEW with view name.
1265
+
1266
+ Args:
1267
+ view_name: Name of the view to create
1268
+ dialect: SQL dialect to use
1269
+ """
1270
+ super().__init__(dialect=dialect)
1271
+ self._view_name = view_name
1272
+ self._if_not_exists = False
1273
+ self._columns: list[str] = []
1274
+ self._select_query: str | exp.Expr | None = None
1275
+ self._hints: list[str] = []
1276
+
1277
+ def name(self, view_name: str) -> Self:
1278
+ self._view_name = view_name
1279
+ return self
1280
+
1281
+ def if_not_exists(self) -> Self:
1282
+ self._if_not_exists = True
1283
+ return self
1284
+
1285
+ def columns(self, *cols: str) -> Self:
1286
+ self._columns = list(cols)
1287
+ return self
1288
+
1289
+ def as_select(self, select_query: "str | exp.Expr") -> Self:
1290
+ self._select_query = select_query
1291
+ return self
1292
+
1293
+ def with_hint(self, hint: str) -> Self:
1294
+ self._hints.append(hint)
1295
+ return self
1296
+
1297
+ def _create_base_expression(self) -> exp.Expr:
1298
+ if not self._view_name:
1299
+ self._raise_sql_builder_error("View name must be set for CREATE VIEW.")
1300
+ if self._select_query is None:
1301
+ self._raise_sql_builder_error("SELECT query must be set for CREATE VIEW.")
1302
+
1303
+ select_expr: exp.Expr | None = None
1304
+ select_parameters: dict[str, Any] | None = None
1305
+
1306
+ if isinstance(self._select_query, SQL):
1307
+ select_expr = self._select_query.expression
1308
+ select_parameters = self._select_query.parameters
1309
+ elif isinstance(self._select_query, Select):
1310
+ select_expr = self._select_query.get_expression()
1311
+ select_parameters = self._select_query.parameters
1312
+ elif isinstance(self._select_query, str):
1313
+ select_expr = exp.maybe_parse(self._select_query)
1314
+ select_parameters = None
1315
+ else:
1316
+ self._raise_sql_builder_error("Unsupported type for SELECT query in view.")
1317
+ if select_expr is None or not isinstance(select_expr, exp.Select):
1318
+ self._raise_sql_builder_error("SELECT query must be a valid SELECT expression.")
1319
+
1320
+ if select_parameters:
1321
+ for p_name, p_value in select_parameters.items():
1322
+ self._parameters[p_name] = p_value
1323
+
1324
+ schema_expr = None
1325
+ if self._columns:
1326
+ schema_expr = exp.Schema(expressions=[exp.column(c) for c in self._columns])
1327
+
1328
+ props: list[exp.Property] = [
1329
+ exp.Property(this=exp.to_identifier("HINT"), value=exp.convert(h)) for h in self._hints
1330
+ ]
1331
+ properties_node = exp.Properties(expressions=props) if props else None
1332
+
1333
+ return exp.Create(
1334
+ kind="VIEW",
1335
+ this=exp.to_identifier(self._view_name),
1336
+ exists=self._if_not_exists,
1337
+ expression=select_expr,
1338
+ schema=schema_expr,
1339
+ properties=properties_node,
1340
+ )
1341
+
1342
+
1343
+ class AlterTable(DDLBuilder):
1344
+ """Builder for ALTER TABLE operations.
1345
+
1346
+ Example:
1347
+ builder = (
1348
+ AlterTable("users")
1349
+ .add_column("email", "VARCHAR(255)", not_null=True)
1350
+ .drop_column("old_field")
1351
+ .add_constraint("check_age", "CHECK (age >= 18)")
1352
+ )
1353
+ """
1354
+
1355
+ __slots__ = ("_if_exists", "_operations", "_schema", "_table_name")
1356
+
1357
+ def __init__(self, table_name: str, dialect: "DialectType" = None) -> None:
1358
+ super().__init__(dialect=dialect)
1359
+ self._table_name = table_name
1360
+ self._operations: list[AlterOperation] = []
1361
+ self._schema: str | None = None
1362
+ self._if_exists = False
1363
+
1364
+ def if_exists(self) -> "Self":
1365
+ """Add IF EXISTS clause."""
1366
+ self._if_exists = True
1367
+ return self
1368
+
1369
+ def add_column(
1370
+ self,
1371
+ name: str,
1372
+ dtype: str,
1373
+ default: "Any | None" = None,
1374
+ not_null: bool = False,
1375
+ unique: bool = False,
1376
+ comment: "str | None" = None,
1377
+ after: "str | None" = None,
1378
+ first: bool = False,
1379
+ ) -> "Self":
1380
+ """Add a new column to the table."""
1381
+ if not name:
1382
+ self._raise_sql_builder_error("Column name must be a non-empty string")
1383
+
1384
+ if not dtype:
1385
+ self._raise_sql_builder_error("Column type must be a non-empty string")
1386
+
1387
+ column_def = ColumnDefinition(
1388
+ name=name, dtype=dtype, default=default, not_null=not_null, unique=unique, comment=comment
1389
+ )
1390
+
1391
+ operation = AlterOperation(
1392
+ operation_type="ADD COLUMN", column_definition=column_def, after_column=after, first=first
1393
+ )
1394
+
1395
+ self._operations.append(operation)
1396
+ return self
1397
+
1398
+ def drop_column(self, name: str, cascade: bool = False) -> "Self":
1399
+ """Drop a column from the table."""
1400
+ if not name:
1401
+ self._raise_sql_builder_error("Column name must be a non-empty string")
1402
+
1403
+ operation = AlterOperation(operation_type="DROP COLUMN CASCADE" if cascade else "DROP COLUMN", column_name=name)
1404
+
1405
+ self._operations.append(operation)
1406
+ return self
1407
+
1408
+ def alter_column_type(self, name: str, new_type: str, using: "str | None" = None) -> "Self":
1409
+ """Change the type of an existing column."""
1410
+ if not name:
1411
+ self._raise_sql_builder_error("Column name must be a non-empty string")
1412
+
1413
+ if not new_type:
1414
+ self._raise_sql_builder_error("New type must be a non-empty string")
1415
+
1416
+ operation = AlterOperation(
1417
+ operation_type="ALTER COLUMN TYPE", column_name=name, new_type=new_type, using_expression=using
1418
+ )
1419
+
1420
+ self._operations.append(operation)
1421
+ return self
1422
+
1423
+ def rename_column(self, old_name: str, new_name: str) -> "Self":
1424
+ """Rename a column."""
1425
+ if not old_name:
1426
+ self._raise_sql_builder_error("Old column name must be a non-empty string")
1427
+
1428
+ if not new_name:
1429
+ self._raise_sql_builder_error("New column name must be a non-empty string")
1430
+
1431
+ operation = AlterOperation(operation_type="RENAME COLUMN", column_name=old_name, new_name=new_name)
1432
+
1433
+ self._operations.append(operation)
1434
+ return self
1435
+
1436
+ def add_constraint(
1437
+ self,
1438
+ constraint_type: str,
1439
+ columns: "str | list[str] | None" = None,
1440
+ name: "str | None" = None,
1441
+ references_table: "str | None" = None,
1442
+ references_columns: "str | list[str] | None" = None,
1443
+ condition: "str | ColumnExpression | None" = None,
1444
+ on_delete: "str | None" = None,
1445
+ on_update: "str | None" = None,
1446
+ ) -> "Self":
1447
+ """Add a constraint to the table.
1448
+
1449
+ Args:
1450
+ constraint_type: Type of constraint ('PRIMARY KEY', 'FOREIGN KEY', 'UNIQUE', 'CHECK')
1451
+ columns: Column(s) for the constraint (not needed for CHECK)
1452
+ name: Optional constraint name
1453
+ references_table: Table referenced by foreign key
1454
+ references_columns: Columns referenced by foreign key
1455
+ condition: CHECK constraint condition
1456
+ on_delete: Foreign key ON DELETE action
1457
+ on_update: Foreign key ON UPDATE action
1458
+ """
1459
+ if constraint_type.upper() not in VALID_CONSTRAINT_TYPES:
1460
+ self._raise_sql_builder_error(f"Invalid constraint type: {constraint_type}")
1461
+
1462
+ col_list = None
1463
+ if columns is not None:
1464
+ col_list = [columns] if isinstance(columns, str) else list(columns)
1465
+
1466
+ ref_col_list = None
1467
+ if references_columns is not None:
1468
+ ref_col_list = [references_columns] if isinstance(references_columns, str) else list(references_columns)
1469
+
1470
+ condition_str: str | None = None
1471
+ if condition is not None:
1472
+ if has_sqlglot_expression(condition):
1473
+ sqlglot_expr = condition.sqlglot_expression
1474
+ condition_str = sqlglot_expr.sql(dialect=self.dialect) if sqlglot_expr else str(condition)
1475
+ else:
1476
+ condition_str = str(condition)
1477
+
1478
+ constraint_def = ConstraintDefinition(
1479
+ constraint_type=constraint_type.upper(),
1480
+ name=name,
1481
+ columns=col_list or [],
1482
+ references_table=references_table,
1483
+ references_columns=ref_col_list or [],
1484
+ condition=condition_str,
1485
+ on_delete=on_delete,
1486
+ on_update=on_update,
1487
+ )
1488
+
1489
+ operation = AlterOperation(operation_type="ADD CONSTRAINT", constraint_definition=constraint_def)
1490
+
1491
+ self._operations.append(operation)
1492
+ return self
1493
+
1494
+ def drop_constraint(self, name: str, cascade: bool = False) -> "Self":
1495
+ """Drop a constraint from the table."""
1496
+ if not name:
1497
+ self._raise_sql_builder_error("Constraint name must be a non-empty string")
1498
+
1499
+ operation = AlterOperation(
1500
+ operation_type="DROP CONSTRAINT CASCADE" if cascade else "DROP CONSTRAINT", constraint_name=name
1501
+ )
1502
+
1503
+ self._operations.append(operation)
1504
+ return self
1505
+
1506
+ def set_not_null(self, column: str) -> "Self":
1507
+ """Set a column to NOT NULL."""
1508
+ operation = AlterOperation(operation_type="ALTER COLUMN SET NOT NULL", column_name=column)
1509
+
1510
+ self._operations.append(operation)
1511
+ return self
1512
+
1513
+ def drop_not_null(self, column: str) -> "Self":
1514
+ """Remove NOT NULL constraint from a column."""
1515
+ operation = AlterOperation(operation_type="ALTER COLUMN DROP NOT NULL", column_name=column)
1516
+
1517
+ self._operations.append(operation)
1518
+ return self
1519
+
1520
+ def _create_base_expression(self) -> "exp.Expr":
1521
+ """Create the SQLGlot expression for ALTER TABLE."""
1522
+ if not self._operations:
1523
+ self._raise_sql_builder_error("At least one operation must be specified for ALTER TABLE")
1524
+
1525
+ if self._schema:
1526
+ table = exp.Table(this=exp.to_identifier(self._table_name), db=exp.to_identifier(self._schema))
1527
+ else:
1528
+ table = exp.to_table(self._table_name)
1529
+
1530
+ actions: list[exp.Expr] = [self._build_operation_expression(op) for op in self._operations]
1531
+
1532
+ return exp.Alter(this=table, kind="TABLE", actions=actions, exists=self._if_exists)
1533
+
1534
+ def _build_operation_expression(self, op: "AlterOperation") -> exp.Expr:
1535
+ """Build a structured SQLGlot expression for a single alter operation."""
1536
+ op_type = op.operation_type.upper()
1537
+
1538
+ if op_type == "ADD COLUMN":
1539
+ if not op.column_definition:
1540
+ self._raise_sql_builder_error("Column definition required for ADD COLUMN")
1541
+ return build_column_expression(op.column_definition)
1542
+
1543
+ if op_type == "DROP COLUMN":
1544
+ return exp.Drop(this=exp.to_identifier(op.column_name), kind="COLUMN", exists=True)
1545
+
1546
+ if op_type == "DROP COLUMN CASCADE":
1547
+ return exp.Drop(this=exp.to_identifier(op.column_name), kind="COLUMN", cascade=True, exists=True)
1548
+
1549
+ if op_type == "ALTER COLUMN TYPE":
1550
+ if not op.new_type:
1551
+ self._raise_sql_builder_error("New type required for ALTER COLUMN TYPE")
1552
+ return exp.AlterColumn(
1553
+ this=exp.to_identifier(op.column_name),
1554
+ dtype=exp.DataType.build(op.new_type),
1555
+ using=exp.maybe_parse(op.using_expression) if op.using_expression else None,
1556
+ )
1557
+
1558
+ if op_type == "RENAME COLUMN":
1559
+ return exp.RenameColumn(this=exp.to_identifier(op.column_name), to=exp.to_identifier(op.new_name))
1560
+
1561
+ if op_type == "ADD CONSTRAINT":
1562
+ if not op.constraint_definition:
1563
+ self._raise_sql_builder_error("Constraint definition required for ADD CONSTRAINT")
1564
+ constraint_expr = build_constraint_expression(op.constraint_definition)
1565
+ return exp.AddConstraint(this=constraint_expr)
1566
+
1567
+ if op_type == "DROP CONSTRAINT":
1568
+ return exp.Drop(this=exp.to_identifier(op.constraint_name), kind="CONSTRAINT", exists=True)
1569
+
1570
+ if op_type == "DROP CONSTRAINT CASCADE":
1571
+ return exp.Drop(this=exp.to_identifier(op.constraint_name), kind="CONSTRAINT", cascade=True, exists=True)
1572
+
1573
+ if op_type == "ALTER COLUMN SET NOT NULL":
1574
+ return exp.AlterColumn(this=exp.to_identifier(op.column_name), allow_null=False)
1575
+
1576
+ if op_type == "ALTER COLUMN DROP NOT NULL":
1577
+ return exp.AlterColumn(this=exp.to_identifier(op.column_name), drop=True, allow_null=True)
1578
+
1579
+ if op_type == "ALTER COLUMN SET DEFAULT":
1580
+ if not op.column_definition or op.column_definition.default is None:
1581
+ self._raise_sql_builder_error("Default value required for SET DEFAULT")
1582
+ default_val = op.column_definition.default
1583
+ default_expr: exp.Expr | None
1584
+ if isinstance(default_val, str):
1585
+ if self._is_sql_function_default(default_val):
1586
+ default_expr = exp.maybe_parse(default_val)
1587
+ else:
1588
+ default_expr = exp.convert(default_val)
1589
+ elif isinstance(default_val, (int, float)):
1590
+ default_expr = exp.convert(default_val)
1591
+ elif default_val is True:
1592
+ default_expr = exp.true()
1593
+ elif default_val is False:
1594
+ default_expr = exp.false()
1595
+ else:
1596
+ default_expr = exp.convert(str(default_val))
1597
+ return exp.AlterColumn(this=exp.to_identifier(op.column_name), default=default_expr)
1598
+
1599
+ if op_type == "ALTER COLUMN DROP DEFAULT":
1600
+ return exp.AlterColumn(this=exp.to_identifier(op.column_name), kind="DROP DEFAULT")
1601
+
1602
+ self._raise_sql_builder_error(f"Unknown operation type: {op.operation_type}")
1603
+ raise AssertionError
1604
+
1605
+ def _is_sql_function_default(self, default_val: str) -> bool:
1606
+ """Check if default value is a SQL function or expression."""
1607
+ default_upper = default_val.upper()
1608
+ return (
1609
+ default_upper in {CURRENT_TIMESTAMP_KEYWORD, CURRENT_DATE_KEYWORD, CURRENT_TIME_KEYWORD}
1610
+ or "(" in default_val
1611
+ )
1612
+
1613
+
1614
+ class CommentOn(DDLBuilder):
1615
+ """Builder for COMMENT ON ... IS ... statements."""
1616
+
1617
+ __slots__ = ("_column", "_comment", "_table", "_target_type")
1618
+
1619
+ def __init__(self, dialect: "DialectType" = None) -> None:
1620
+ """Initialize COMMENT ON builder.
1621
+
1622
+ Args:
1623
+ dialect: SQL dialect to use
1624
+ """
1625
+ super().__init__(dialect=dialect)
1626
+ self._target_type: str | None = None
1627
+ self._table: str | None = None
1628
+ self._column: str | None = None
1629
+ self._comment: str | None = None
1630
+
1631
+ def on_table(self, table: str) -> Self:
1632
+ self._target_type = "TABLE"
1633
+ self._table = table
1634
+ self._column = None
1635
+ return self
1636
+
1637
+ def on_column(self, table: str, column: str) -> Self:
1638
+ self._target_type = "COLUMN"
1639
+ self._table = table
1640
+ self._column = column
1641
+ return self
1642
+
1643
+ def is_(self, comment: str) -> Self:
1644
+ self._comment = comment
1645
+ return self
1646
+
1647
+ def _create_base_expression(self) -> exp.Expr:
1648
+ if self._target_type == "TABLE" and self._table and self._comment is not None:
1649
+ return exp.Comment(this=exp.to_table(self._table), kind="TABLE", expression=exp.convert(self._comment))
1650
+ if self._target_type == "COLUMN" and self._table and self._column and self._comment is not None:
1651
+ return exp.Comment(
1652
+ this=exp.Column(table=self._table, this=self._column),
1653
+ kind="COLUMN",
1654
+ expression=exp.convert(self._comment),
1655
+ )
1656
+ self._raise_sql_builder_error("Must specify target and comment for COMMENT ON statement.")
1657
+ raise AssertionError
1658
+
1659
+
1660
+ class RenameTable(DDLBuilder):
1661
+ """Builder for ALTER TABLE ... RENAME TO ... statements."""
1662
+
1663
+ __slots__ = ("_new_name", "_old_name")
1664
+
1665
+ def __init__(self, old_name: str, dialect: "DialectType" = None) -> None:
1666
+ """Initialize RENAME TABLE with old name.
1667
+
1668
+ Args:
1669
+ old_name: Current name of the table
1670
+ dialect: SQL dialect to use
1671
+ """
1672
+ super().__init__(dialect=dialect)
1673
+ self._old_name = old_name
1674
+ self._new_name: str | None = None
1675
+
1676
+ def table(self, old_name: str) -> Self:
1677
+ self._old_name = old_name
1678
+ return self
1679
+
1680
+ def to(self, new_name: str) -> Self:
1681
+ self._new_name = new_name
1682
+ return self
1683
+
1684
+ def _create_base_expression(self) -> exp.Expr:
1685
+ if not self._old_name or not self._new_name:
1686
+ self._raise_sql_builder_error("Both old and new table names must be set for RENAME TABLE.")
1687
+ return exp.Alter(
1688
+ this=exp.to_table(self._old_name),
1689
+ kind="TABLE",
1690
+ actions=[exp.AlterRename(this=exp.to_identifier(self._new_name))],
1691
+ )