sqlspec 0.36.0__cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (531) hide show
  1. ac8f31065839703b4e70__mypyc.cpython-310-aarch64-linux-gnu.so +0 -0
  2. sqlspec/__init__.py +140 -0
  3. sqlspec/__main__.py +12 -0
  4. sqlspec/__metadata__.py +14 -0
  5. sqlspec/_serialization.py +315 -0
  6. sqlspec/_typing.py +700 -0
  7. sqlspec/adapters/__init__.py +0 -0
  8. sqlspec/adapters/adbc/__init__.py +5 -0
  9. sqlspec/adapters/adbc/_typing.py +82 -0
  10. sqlspec/adapters/adbc/adk/__init__.py +5 -0
  11. sqlspec/adapters/adbc/adk/store.py +1273 -0
  12. sqlspec/adapters/adbc/config.py +295 -0
  13. sqlspec/adapters/adbc/core.cpython-310-aarch64-linux-gnu.so +0 -0
  14. sqlspec/adapters/adbc/core.py +735 -0
  15. sqlspec/adapters/adbc/data_dictionary.py +334 -0
  16. sqlspec/adapters/adbc/driver.py +529 -0
  17. sqlspec/adapters/adbc/events/__init__.py +5 -0
  18. sqlspec/adapters/adbc/events/store.py +285 -0
  19. sqlspec/adapters/adbc/litestar/__init__.py +5 -0
  20. sqlspec/adapters/adbc/litestar/store.py +502 -0
  21. sqlspec/adapters/adbc/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  22. sqlspec/adapters/adbc/type_converter.py +140 -0
  23. sqlspec/adapters/aiosqlite/__init__.py +25 -0
  24. sqlspec/adapters/aiosqlite/_typing.py +82 -0
  25. sqlspec/adapters/aiosqlite/adk/__init__.py +5 -0
  26. sqlspec/adapters/aiosqlite/adk/store.py +818 -0
  27. sqlspec/adapters/aiosqlite/config.py +334 -0
  28. sqlspec/adapters/aiosqlite/core.cpython-310-aarch64-linux-gnu.so +0 -0
  29. sqlspec/adapters/aiosqlite/core.py +315 -0
  30. sqlspec/adapters/aiosqlite/data_dictionary.py +208 -0
  31. sqlspec/adapters/aiosqlite/driver.py +313 -0
  32. sqlspec/adapters/aiosqlite/events/__init__.py +5 -0
  33. sqlspec/adapters/aiosqlite/events/store.py +20 -0
  34. sqlspec/adapters/aiosqlite/litestar/__init__.py +5 -0
  35. sqlspec/adapters/aiosqlite/litestar/store.py +279 -0
  36. sqlspec/adapters/aiosqlite/pool.py +533 -0
  37. sqlspec/adapters/asyncmy/__init__.py +21 -0
  38. sqlspec/adapters/asyncmy/_typing.py +87 -0
  39. sqlspec/adapters/asyncmy/adk/__init__.py +5 -0
  40. sqlspec/adapters/asyncmy/adk/store.py +703 -0
  41. sqlspec/adapters/asyncmy/config.py +302 -0
  42. sqlspec/adapters/asyncmy/core.cpython-310-aarch64-linux-gnu.so +0 -0
  43. sqlspec/adapters/asyncmy/core.py +360 -0
  44. sqlspec/adapters/asyncmy/data_dictionary.py +124 -0
  45. sqlspec/adapters/asyncmy/driver.py +383 -0
  46. sqlspec/adapters/asyncmy/events/__init__.py +5 -0
  47. sqlspec/adapters/asyncmy/events/store.py +104 -0
  48. sqlspec/adapters/asyncmy/litestar/__init__.py +5 -0
  49. sqlspec/adapters/asyncmy/litestar/store.py +296 -0
  50. sqlspec/adapters/asyncpg/__init__.py +19 -0
  51. sqlspec/adapters/asyncpg/_typing.py +88 -0
  52. sqlspec/adapters/asyncpg/adk/__init__.py +5 -0
  53. sqlspec/adapters/asyncpg/adk/store.py +748 -0
  54. sqlspec/adapters/asyncpg/config.py +569 -0
  55. sqlspec/adapters/asyncpg/core.cpython-310-aarch64-linux-gnu.so +0 -0
  56. sqlspec/adapters/asyncpg/core.py +367 -0
  57. sqlspec/adapters/asyncpg/data_dictionary.py +162 -0
  58. sqlspec/adapters/asyncpg/driver.py +487 -0
  59. sqlspec/adapters/asyncpg/events/__init__.py +6 -0
  60. sqlspec/adapters/asyncpg/events/backend.py +286 -0
  61. sqlspec/adapters/asyncpg/events/store.py +40 -0
  62. sqlspec/adapters/asyncpg/litestar/__init__.py +5 -0
  63. sqlspec/adapters/asyncpg/litestar/store.py +251 -0
  64. sqlspec/adapters/bigquery/__init__.py +14 -0
  65. sqlspec/adapters/bigquery/_typing.py +86 -0
  66. sqlspec/adapters/bigquery/adk/__init__.py +5 -0
  67. sqlspec/adapters/bigquery/adk/store.py +827 -0
  68. sqlspec/adapters/bigquery/config.py +353 -0
  69. sqlspec/adapters/bigquery/core.cpython-310-aarch64-linux-gnu.so +0 -0
  70. sqlspec/adapters/bigquery/core.py +715 -0
  71. sqlspec/adapters/bigquery/data_dictionary.py +128 -0
  72. sqlspec/adapters/bigquery/driver.py +548 -0
  73. sqlspec/adapters/bigquery/events/__init__.py +5 -0
  74. sqlspec/adapters/bigquery/events/store.py +139 -0
  75. sqlspec/adapters/bigquery/litestar/__init__.py +5 -0
  76. sqlspec/adapters/bigquery/litestar/store.py +325 -0
  77. sqlspec/adapters/bigquery/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  78. sqlspec/adapters/bigquery/type_converter.py +107 -0
  79. sqlspec/adapters/cockroach_asyncpg/__init__.py +24 -0
  80. sqlspec/adapters/cockroach_asyncpg/_typing.py +72 -0
  81. sqlspec/adapters/cockroach_asyncpg/adk/__init__.py +3 -0
  82. sqlspec/adapters/cockroach_asyncpg/adk/store.py +410 -0
  83. sqlspec/adapters/cockroach_asyncpg/config.py +238 -0
  84. sqlspec/adapters/cockroach_asyncpg/core.cpython-310-aarch64-linux-gnu.so +0 -0
  85. sqlspec/adapters/cockroach_asyncpg/core.py +55 -0
  86. sqlspec/adapters/cockroach_asyncpg/data_dictionary.py +107 -0
  87. sqlspec/adapters/cockroach_asyncpg/driver.py +144 -0
  88. sqlspec/adapters/cockroach_asyncpg/events/__init__.py +3 -0
  89. sqlspec/adapters/cockroach_asyncpg/events/store.py +20 -0
  90. sqlspec/adapters/cockroach_asyncpg/litestar/__init__.py +3 -0
  91. sqlspec/adapters/cockroach_asyncpg/litestar/store.py +142 -0
  92. sqlspec/adapters/cockroach_psycopg/__init__.py +38 -0
  93. sqlspec/adapters/cockroach_psycopg/_typing.py +129 -0
  94. sqlspec/adapters/cockroach_psycopg/adk/__init__.py +13 -0
  95. sqlspec/adapters/cockroach_psycopg/adk/store.py +868 -0
  96. sqlspec/adapters/cockroach_psycopg/config.py +484 -0
  97. sqlspec/adapters/cockroach_psycopg/core.cpython-310-aarch64-linux-gnu.so +0 -0
  98. sqlspec/adapters/cockroach_psycopg/core.py +63 -0
  99. sqlspec/adapters/cockroach_psycopg/data_dictionary.py +215 -0
  100. sqlspec/adapters/cockroach_psycopg/driver.py +284 -0
  101. sqlspec/adapters/cockroach_psycopg/events/__init__.py +6 -0
  102. sqlspec/adapters/cockroach_psycopg/events/store.py +34 -0
  103. sqlspec/adapters/cockroach_psycopg/litestar/__init__.py +3 -0
  104. sqlspec/adapters/cockroach_psycopg/litestar/store.py +325 -0
  105. sqlspec/adapters/duckdb/__init__.py +25 -0
  106. sqlspec/adapters/duckdb/_typing.py +81 -0
  107. sqlspec/adapters/duckdb/adk/__init__.py +14 -0
  108. sqlspec/adapters/duckdb/adk/store.py +850 -0
  109. sqlspec/adapters/duckdb/config.py +463 -0
  110. sqlspec/adapters/duckdb/core.cpython-310-aarch64-linux-gnu.so +0 -0
  111. sqlspec/adapters/duckdb/core.py +257 -0
  112. sqlspec/adapters/duckdb/data_dictionary.py +140 -0
  113. sqlspec/adapters/duckdb/driver.py +430 -0
  114. sqlspec/adapters/duckdb/events/__init__.py +5 -0
  115. sqlspec/adapters/duckdb/events/store.py +57 -0
  116. sqlspec/adapters/duckdb/litestar/__init__.py +5 -0
  117. sqlspec/adapters/duckdb/litestar/store.py +330 -0
  118. sqlspec/adapters/duckdb/pool.py +293 -0
  119. sqlspec/adapters/duckdb/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  120. sqlspec/adapters/duckdb/type_converter.py +118 -0
  121. sqlspec/adapters/mock/__init__.py +72 -0
  122. sqlspec/adapters/mock/_typing.py +147 -0
  123. sqlspec/adapters/mock/config.py +483 -0
  124. sqlspec/adapters/mock/core.py +319 -0
  125. sqlspec/adapters/mock/data_dictionary.py +366 -0
  126. sqlspec/adapters/mock/driver.py +721 -0
  127. sqlspec/adapters/mysqlconnector/__init__.py +36 -0
  128. sqlspec/adapters/mysqlconnector/_typing.py +141 -0
  129. sqlspec/adapters/mysqlconnector/adk/__init__.py +15 -0
  130. sqlspec/adapters/mysqlconnector/adk/store.py +1060 -0
  131. sqlspec/adapters/mysqlconnector/config.py +394 -0
  132. sqlspec/adapters/mysqlconnector/core.cpython-310-aarch64-linux-gnu.so +0 -0
  133. sqlspec/adapters/mysqlconnector/core.py +303 -0
  134. sqlspec/adapters/mysqlconnector/data_dictionary.py +235 -0
  135. sqlspec/adapters/mysqlconnector/driver.py +483 -0
  136. sqlspec/adapters/mysqlconnector/events/__init__.py +8 -0
  137. sqlspec/adapters/mysqlconnector/events/store.py +98 -0
  138. sqlspec/adapters/mysqlconnector/litestar/__init__.py +5 -0
  139. sqlspec/adapters/mysqlconnector/litestar/store.py +426 -0
  140. sqlspec/adapters/oracledb/__init__.py +60 -0
  141. sqlspec/adapters/oracledb/_numpy_handlers.py +141 -0
  142. sqlspec/adapters/oracledb/_typing.py +182 -0
  143. sqlspec/adapters/oracledb/_uuid_handlers.py +166 -0
  144. sqlspec/adapters/oracledb/adk/__init__.py +10 -0
  145. sqlspec/adapters/oracledb/adk/store.py +2369 -0
  146. sqlspec/adapters/oracledb/config.py +550 -0
  147. sqlspec/adapters/oracledb/core.cpython-310-aarch64-linux-gnu.so +0 -0
  148. sqlspec/adapters/oracledb/core.py +543 -0
  149. sqlspec/adapters/oracledb/data_dictionary.py +536 -0
  150. sqlspec/adapters/oracledb/driver.py +1229 -0
  151. sqlspec/adapters/oracledb/events/__init__.py +16 -0
  152. sqlspec/adapters/oracledb/events/backend.py +347 -0
  153. sqlspec/adapters/oracledb/events/store.py +420 -0
  154. sqlspec/adapters/oracledb/litestar/__init__.py +5 -0
  155. sqlspec/adapters/oracledb/litestar/store.py +781 -0
  156. sqlspec/adapters/oracledb/migrations.py +535 -0
  157. sqlspec/adapters/oracledb/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  158. sqlspec/adapters/oracledb/type_converter.py +211 -0
  159. sqlspec/adapters/psqlpy/__init__.py +17 -0
  160. sqlspec/adapters/psqlpy/_typing.py +79 -0
  161. sqlspec/adapters/psqlpy/adk/__init__.py +5 -0
  162. sqlspec/adapters/psqlpy/adk/store.py +766 -0
  163. sqlspec/adapters/psqlpy/config.py +304 -0
  164. sqlspec/adapters/psqlpy/core.cpython-310-aarch64-linux-gnu.so +0 -0
  165. sqlspec/adapters/psqlpy/core.py +480 -0
  166. sqlspec/adapters/psqlpy/data_dictionary.py +126 -0
  167. sqlspec/adapters/psqlpy/driver.py +438 -0
  168. sqlspec/adapters/psqlpy/events/__init__.py +6 -0
  169. sqlspec/adapters/psqlpy/events/backend.py +310 -0
  170. sqlspec/adapters/psqlpy/events/store.py +20 -0
  171. sqlspec/adapters/psqlpy/litestar/__init__.py +5 -0
  172. sqlspec/adapters/psqlpy/litestar/store.py +270 -0
  173. sqlspec/adapters/psqlpy/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  174. sqlspec/adapters/psqlpy/type_converter.py +113 -0
  175. sqlspec/adapters/psycopg/__init__.py +32 -0
  176. sqlspec/adapters/psycopg/_typing.py +164 -0
  177. sqlspec/adapters/psycopg/adk/__init__.py +10 -0
  178. sqlspec/adapters/psycopg/adk/store.py +1387 -0
  179. sqlspec/adapters/psycopg/config.py +576 -0
  180. sqlspec/adapters/psycopg/core.cpython-310-aarch64-linux-gnu.so +0 -0
  181. sqlspec/adapters/psycopg/core.py +450 -0
  182. sqlspec/adapters/psycopg/data_dictionary.py +289 -0
  183. sqlspec/adapters/psycopg/driver.py +975 -0
  184. sqlspec/adapters/psycopg/events/__init__.py +20 -0
  185. sqlspec/adapters/psycopg/events/backend.py +458 -0
  186. sqlspec/adapters/psycopg/events/store.py +42 -0
  187. sqlspec/adapters/psycopg/litestar/__init__.py +5 -0
  188. sqlspec/adapters/psycopg/litestar/store.py +552 -0
  189. sqlspec/adapters/psycopg/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  190. sqlspec/adapters/psycopg/type_converter.py +93 -0
  191. sqlspec/adapters/pymysql/__init__.py +21 -0
  192. sqlspec/adapters/pymysql/_typing.py +71 -0
  193. sqlspec/adapters/pymysql/adk/__init__.py +5 -0
  194. sqlspec/adapters/pymysql/adk/store.py +540 -0
  195. sqlspec/adapters/pymysql/config.py +195 -0
  196. sqlspec/adapters/pymysql/core.cpython-310-aarch64-linux-gnu.so +0 -0
  197. sqlspec/adapters/pymysql/core.py +299 -0
  198. sqlspec/adapters/pymysql/data_dictionary.py +122 -0
  199. sqlspec/adapters/pymysql/driver.py +259 -0
  200. sqlspec/adapters/pymysql/events/__init__.py +5 -0
  201. sqlspec/adapters/pymysql/events/store.py +50 -0
  202. sqlspec/adapters/pymysql/litestar/__init__.py +5 -0
  203. sqlspec/adapters/pymysql/litestar/store.py +232 -0
  204. sqlspec/adapters/pymysql/pool.py +137 -0
  205. sqlspec/adapters/spanner/__init__.py +40 -0
  206. sqlspec/adapters/spanner/_typing.py +86 -0
  207. sqlspec/adapters/spanner/adk/__init__.py +5 -0
  208. sqlspec/adapters/spanner/adk/store.py +732 -0
  209. sqlspec/adapters/spanner/config.py +352 -0
  210. sqlspec/adapters/spanner/core.cpython-310-aarch64-linux-gnu.so +0 -0
  211. sqlspec/adapters/spanner/core.py +188 -0
  212. sqlspec/adapters/spanner/data_dictionary.py +120 -0
  213. sqlspec/adapters/spanner/dialect/__init__.py +6 -0
  214. sqlspec/adapters/spanner/dialect/_spangres.py +57 -0
  215. sqlspec/adapters/spanner/dialect/_spanner.py +130 -0
  216. sqlspec/adapters/spanner/driver.py +373 -0
  217. sqlspec/adapters/spanner/events/__init__.py +5 -0
  218. sqlspec/adapters/spanner/events/store.py +187 -0
  219. sqlspec/adapters/spanner/litestar/__init__.py +5 -0
  220. sqlspec/adapters/spanner/litestar/store.py +291 -0
  221. sqlspec/adapters/spanner/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  222. sqlspec/adapters/spanner/type_converter.py +331 -0
  223. sqlspec/adapters/sqlite/__init__.py +19 -0
  224. sqlspec/adapters/sqlite/_typing.py +80 -0
  225. sqlspec/adapters/sqlite/adk/__init__.py +5 -0
  226. sqlspec/adapters/sqlite/adk/store.py +958 -0
  227. sqlspec/adapters/sqlite/config.py +280 -0
  228. sqlspec/adapters/sqlite/core.cpython-310-aarch64-linux-gnu.so +0 -0
  229. sqlspec/adapters/sqlite/core.py +312 -0
  230. sqlspec/adapters/sqlite/data_dictionary.py +202 -0
  231. sqlspec/adapters/sqlite/driver.py +359 -0
  232. sqlspec/adapters/sqlite/events/__init__.py +5 -0
  233. sqlspec/adapters/sqlite/events/store.py +20 -0
  234. sqlspec/adapters/sqlite/litestar/__init__.py +5 -0
  235. sqlspec/adapters/sqlite/litestar/store.py +316 -0
  236. sqlspec/adapters/sqlite/pool.py +198 -0
  237. sqlspec/adapters/sqlite/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  238. sqlspec/adapters/sqlite/type_converter.py +114 -0
  239. sqlspec/base.py +747 -0
  240. sqlspec/builder/__init__.py +179 -0
  241. sqlspec/builder/_base.cpython-310-aarch64-linux-gnu.so +0 -0
  242. sqlspec/builder/_base.py +1022 -0
  243. sqlspec/builder/_column.cpython-310-aarch64-linux-gnu.so +0 -0
  244. sqlspec/builder/_column.py +521 -0
  245. sqlspec/builder/_ddl.cpython-310-aarch64-linux-gnu.so +0 -0
  246. sqlspec/builder/_ddl.py +1642 -0
  247. sqlspec/builder/_delete.cpython-310-aarch64-linux-gnu.so +0 -0
  248. sqlspec/builder/_delete.py +95 -0
  249. sqlspec/builder/_dml.cpython-310-aarch64-linux-gnu.so +0 -0
  250. sqlspec/builder/_dml.py +365 -0
  251. sqlspec/builder/_explain.cpython-310-aarch64-linux-gnu.so +0 -0
  252. sqlspec/builder/_explain.py +579 -0
  253. sqlspec/builder/_expression_wrappers.cpython-310-aarch64-linux-gnu.so +0 -0
  254. sqlspec/builder/_expression_wrappers.py +46 -0
  255. sqlspec/builder/_factory.cpython-310-aarch64-linux-gnu.so +0 -0
  256. sqlspec/builder/_factory.py +1697 -0
  257. sqlspec/builder/_insert.cpython-310-aarch64-linux-gnu.so +0 -0
  258. sqlspec/builder/_insert.py +328 -0
  259. sqlspec/builder/_join.cpython-310-aarch64-linux-gnu.so +0 -0
  260. sqlspec/builder/_join.py +499 -0
  261. sqlspec/builder/_merge.cpython-310-aarch64-linux-gnu.so +0 -0
  262. sqlspec/builder/_merge.py +821 -0
  263. sqlspec/builder/_parsing_utils.cpython-310-aarch64-linux-gnu.so +0 -0
  264. sqlspec/builder/_parsing_utils.py +297 -0
  265. sqlspec/builder/_select.cpython-310-aarch64-linux-gnu.so +0 -0
  266. sqlspec/builder/_select.py +1660 -0
  267. sqlspec/builder/_temporal.cpython-310-aarch64-linux-gnu.so +0 -0
  268. sqlspec/builder/_temporal.py +139 -0
  269. sqlspec/builder/_update.cpython-310-aarch64-linux-gnu.so +0 -0
  270. sqlspec/builder/_update.py +173 -0
  271. sqlspec/builder/_vector_expressions.py +267 -0
  272. sqlspec/cli.py +911 -0
  273. sqlspec/config.py +1755 -0
  274. sqlspec/core/__init__.py +374 -0
  275. sqlspec/core/_correlation.cpython-310-aarch64-linux-gnu.so +0 -0
  276. sqlspec/core/_correlation.py +176 -0
  277. sqlspec/core/cache.cpython-310-aarch64-linux-gnu.so +0 -0
  278. sqlspec/core/cache.py +1069 -0
  279. sqlspec/core/compiler.cpython-310-aarch64-linux-gnu.so +0 -0
  280. sqlspec/core/compiler.py +954 -0
  281. sqlspec/core/explain.cpython-310-aarch64-linux-gnu.so +0 -0
  282. sqlspec/core/explain.py +275 -0
  283. sqlspec/core/filters.cpython-310-aarch64-linux-gnu.so +0 -0
  284. sqlspec/core/filters.py +952 -0
  285. sqlspec/core/hashing.cpython-310-aarch64-linux-gnu.so +0 -0
  286. sqlspec/core/hashing.py +262 -0
  287. sqlspec/core/metrics.cpython-310-aarch64-linux-gnu.so +0 -0
  288. sqlspec/core/metrics.py +83 -0
  289. sqlspec/core/parameters/__init__.py +71 -0
  290. sqlspec/core/parameters/_alignment.cpython-310-aarch64-linux-gnu.so +0 -0
  291. sqlspec/core/parameters/_alignment.py +270 -0
  292. sqlspec/core/parameters/_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  293. sqlspec/core/parameters/_converter.py +543 -0
  294. sqlspec/core/parameters/_processor.cpython-310-aarch64-linux-gnu.so +0 -0
  295. sqlspec/core/parameters/_processor.py +505 -0
  296. sqlspec/core/parameters/_registry.cpython-310-aarch64-linux-gnu.so +0 -0
  297. sqlspec/core/parameters/_registry.py +206 -0
  298. sqlspec/core/parameters/_transformers.cpython-310-aarch64-linux-gnu.so +0 -0
  299. sqlspec/core/parameters/_transformers.py +292 -0
  300. sqlspec/core/parameters/_types.cpython-310-aarch64-linux-gnu.so +0 -0
  301. sqlspec/core/parameters/_types.py +499 -0
  302. sqlspec/core/parameters/_validator.cpython-310-aarch64-linux-gnu.so +0 -0
  303. sqlspec/core/parameters/_validator.py +180 -0
  304. sqlspec/core/pipeline.cpython-310-aarch64-linux-gnu.so +0 -0
  305. sqlspec/core/pipeline.py +319 -0
  306. sqlspec/core/query_modifiers.cpython-310-aarch64-linux-gnu.so +0 -0
  307. sqlspec/core/query_modifiers.py +437 -0
  308. sqlspec/core/result/__init__.py +23 -0
  309. sqlspec/core/result/_base.cpython-310-aarch64-linux-gnu.so +0 -0
  310. sqlspec/core/result/_base.py +1121 -0
  311. sqlspec/core/result/_io.cpython-310-aarch64-linux-gnu.so +0 -0
  312. sqlspec/core/result/_io.py +28 -0
  313. sqlspec/core/splitter.cpython-310-aarch64-linux-gnu.so +0 -0
  314. sqlspec/core/splitter.py +966 -0
  315. sqlspec/core/stack.cpython-310-aarch64-linux-gnu.so +0 -0
  316. sqlspec/core/stack.py +163 -0
  317. sqlspec/core/statement.cpython-310-aarch64-linux-gnu.so +0 -0
  318. sqlspec/core/statement.py +1503 -0
  319. sqlspec/core/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  320. sqlspec/core/type_converter.py +339 -0
  321. sqlspec/data_dictionary/__init__.py +22 -0
  322. sqlspec/data_dictionary/_loader.py +123 -0
  323. sqlspec/data_dictionary/_registry.cpython-310-aarch64-linux-gnu.so +0 -0
  324. sqlspec/data_dictionary/_registry.py +74 -0
  325. sqlspec/data_dictionary/_types.cpython-310-aarch64-linux-gnu.so +0 -0
  326. sqlspec/data_dictionary/_types.py +121 -0
  327. sqlspec/data_dictionary/dialects/__init__.py +21 -0
  328. sqlspec/data_dictionary/dialects/bigquery.cpython-310-aarch64-linux-gnu.so +0 -0
  329. sqlspec/data_dictionary/dialects/bigquery.py +49 -0
  330. sqlspec/data_dictionary/dialects/cockroachdb.cpython-310-aarch64-linux-gnu.so +0 -0
  331. sqlspec/data_dictionary/dialects/cockroachdb.py +43 -0
  332. sqlspec/data_dictionary/dialects/duckdb.cpython-310-aarch64-linux-gnu.so +0 -0
  333. sqlspec/data_dictionary/dialects/duckdb.py +47 -0
  334. sqlspec/data_dictionary/dialects/mysql.cpython-310-aarch64-linux-gnu.so +0 -0
  335. sqlspec/data_dictionary/dialects/mysql.py +42 -0
  336. sqlspec/data_dictionary/dialects/oracle.cpython-310-aarch64-linux-gnu.so +0 -0
  337. sqlspec/data_dictionary/dialects/oracle.py +34 -0
  338. sqlspec/data_dictionary/dialects/postgres.cpython-310-aarch64-linux-gnu.so +0 -0
  339. sqlspec/data_dictionary/dialects/postgres.py +46 -0
  340. sqlspec/data_dictionary/dialects/spanner.cpython-310-aarch64-linux-gnu.so +0 -0
  341. sqlspec/data_dictionary/dialects/spanner.py +37 -0
  342. sqlspec/data_dictionary/dialects/sqlite.cpython-310-aarch64-linux-gnu.so +0 -0
  343. sqlspec/data_dictionary/dialects/sqlite.py +42 -0
  344. sqlspec/data_dictionary/sql/.gitkeep +0 -0
  345. sqlspec/data_dictionary/sql/bigquery/columns.sql +23 -0
  346. sqlspec/data_dictionary/sql/bigquery/foreign_keys.sql +34 -0
  347. sqlspec/data_dictionary/sql/bigquery/indexes.sql +19 -0
  348. sqlspec/data_dictionary/sql/bigquery/tables.sql +33 -0
  349. sqlspec/data_dictionary/sql/bigquery/version.sql +3 -0
  350. sqlspec/data_dictionary/sql/cockroachdb/columns.sql +34 -0
  351. sqlspec/data_dictionary/sql/cockroachdb/foreign_keys.sql +40 -0
  352. sqlspec/data_dictionary/sql/cockroachdb/indexes.sql +32 -0
  353. sqlspec/data_dictionary/sql/cockroachdb/tables.sql +44 -0
  354. sqlspec/data_dictionary/sql/cockroachdb/version.sql +3 -0
  355. sqlspec/data_dictionary/sql/duckdb/columns.sql +23 -0
  356. sqlspec/data_dictionary/sql/duckdb/foreign_keys.sql +36 -0
  357. sqlspec/data_dictionary/sql/duckdb/indexes.sql +19 -0
  358. sqlspec/data_dictionary/sql/duckdb/tables.sql +38 -0
  359. sqlspec/data_dictionary/sql/duckdb/version.sql +3 -0
  360. sqlspec/data_dictionary/sql/mysql/columns.sql +23 -0
  361. sqlspec/data_dictionary/sql/mysql/foreign_keys.sql +28 -0
  362. sqlspec/data_dictionary/sql/mysql/indexes.sql +26 -0
  363. sqlspec/data_dictionary/sql/mysql/tables.sql +33 -0
  364. sqlspec/data_dictionary/sql/mysql/version.sql +3 -0
  365. sqlspec/data_dictionary/sql/oracle/columns.sql +23 -0
  366. sqlspec/data_dictionary/sql/oracle/foreign_keys.sql +48 -0
  367. sqlspec/data_dictionary/sql/oracle/indexes.sql +44 -0
  368. sqlspec/data_dictionary/sql/oracle/tables.sql +25 -0
  369. sqlspec/data_dictionary/sql/oracle/version.sql +20 -0
  370. sqlspec/data_dictionary/sql/postgres/columns.sql +34 -0
  371. sqlspec/data_dictionary/sql/postgres/foreign_keys.sql +40 -0
  372. sqlspec/data_dictionary/sql/postgres/indexes.sql +56 -0
  373. sqlspec/data_dictionary/sql/postgres/tables.sql +44 -0
  374. sqlspec/data_dictionary/sql/postgres/version.sql +3 -0
  375. sqlspec/data_dictionary/sql/spanner/columns.sql +23 -0
  376. sqlspec/data_dictionary/sql/spanner/foreign_keys.sql +70 -0
  377. sqlspec/data_dictionary/sql/spanner/indexes.sql +30 -0
  378. sqlspec/data_dictionary/sql/spanner/tables.sql +9 -0
  379. sqlspec/data_dictionary/sql/spanner/version.sql +3 -0
  380. sqlspec/data_dictionary/sql/sqlite/columns.sql +23 -0
  381. sqlspec/data_dictionary/sql/sqlite/foreign_keys.sql +22 -0
  382. sqlspec/data_dictionary/sql/sqlite/indexes.sql +7 -0
  383. sqlspec/data_dictionary/sql/sqlite/tables.sql +28 -0
  384. sqlspec/data_dictionary/sql/sqlite/version.sql +3 -0
  385. sqlspec/driver/__init__.py +32 -0
  386. sqlspec/driver/_async.cpython-310-aarch64-linux-gnu.so +0 -0
  387. sqlspec/driver/_async.py +1737 -0
  388. sqlspec/driver/_common.cpython-310-aarch64-linux-gnu.so +0 -0
  389. sqlspec/driver/_common.py +1478 -0
  390. sqlspec/driver/_sql_helpers.cpython-310-aarch64-linux-gnu.so +0 -0
  391. sqlspec/driver/_sql_helpers.py +148 -0
  392. sqlspec/driver/_storage_helpers.cpython-310-aarch64-linux-gnu.so +0 -0
  393. sqlspec/driver/_storage_helpers.py +144 -0
  394. sqlspec/driver/_sync.cpython-310-aarch64-linux-gnu.so +0 -0
  395. sqlspec/driver/_sync.py +1710 -0
  396. sqlspec/exceptions.py +338 -0
  397. sqlspec/extensions/__init__.py +0 -0
  398. sqlspec/extensions/adk/__init__.py +70 -0
  399. sqlspec/extensions/adk/_types.py +51 -0
  400. sqlspec/extensions/adk/converters.py +172 -0
  401. sqlspec/extensions/adk/memory/__init__.py +69 -0
  402. sqlspec/extensions/adk/memory/_types.py +30 -0
  403. sqlspec/extensions/adk/memory/converters.py +149 -0
  404. sqlspec/extensions/adk/memory/service.py +217 -0
  405. sqlspec/extensions/adk/memory/store.py +569 -0
  406. sqlspec/extensions/adk/migrations/0001_create_adk_tables.py +246 -0
  407. sqlspec/extensions/adk/migrations/__init__.py +0 -0
  408. sqlspec/extensions/adk/service.py +225 -0
  409. sqlspec/extensions/adk/store.py +567 -0
  410. sqlspec/extensions/events/__init__.py +51 -0
  411. sqlspec/extensions/events/_channel.py +703 -0
  412. sqlspec/extensions/events/_hints.py +45 -0
  413. sqlspec/extensions/events/_models.py +23 -0
  414. sqlspec/extensions/events/_payload.py +69 -0
  415. sqlspec/extensions/events/_protocols.py +134 -0
  416. sqlspec/extensions/events/_queue.py +461 -0
  417. sqlspec/extensions/events/_store.py +209 -0
  418. sqlspec/extensions/events/migrations/0001_create_event_queue.py +59 -0
  419. sqlspec/extensions/events/migrations/__init__.py +3 -0
  420. sqlspec/extensions/fastapi/__init__.py +19 -0
  421. sqlspec/extensions/fastapi/extension.py +351 -0
  422. sqlspec/extensions/fastapi/providers.py +607 -0
  423. sqlspec/extensions/flask/__init__.py +37 -0
  424. sqlspec/extensions/flask/_state.py +76 -0
  425. sqlspec/extensions/flask/_utils.py +71 -0
  426. sqlspec/extensions/flask/extension.py +519 -0
  427. sqlspec/extensions/litestar/__init__.py +28 -0
  428. sqlspec/extensions/litestar/_utils.py +52 -0
  429. sqlspec/extensions/litestar/channels.py +165 -0
  430. sqlspec/extensions/litestar/cli.py +102 -0
  431. sqlspec/extensions/litestar/config.py +90 -0
  432. sqlspec/extensions/litestar/handlers.py +316 -0
  433. sqlspec/extensions/litestar/migrations/0001_create_session_table.py +137 -0
  434. sqlspec/extensions/litestar/migrations/__init__.py +3 -0
  435. sqlspec/extensions/litestar/plugin.py +671 -0
  436. sqlspec/extensions/litestar/providers.py +526 -0
  437. sqlspec/extensions/litestar/store.py +296 -0
  438. sqlspec/extensions/otel/__init__.py +58 -0
  439. sqlspec/extensions/prometheus/__init__.py +113 -0
  440. sqlspec/extensions/starlette/__init__.py +19 -0
  441. sqlspec/extensions/starlette/_state.py +30 -0
  442. sqlspec/extensions/starlette/_utils.py +96 -0
  443. sqlspec/extensions/starlette/extension.py +346 -0
  444. sqlspec/extensions/starlette/middleware.py +235 -0
  445. sqlspec/loader.cpython-310-aarch64-linux-gnu.so +0 -0
  446. sqlspec/loader.py +702 -0
  447. sqlspec/migrations/__init__.py +36 -0
  448. sqlspec/migrations/base.py +731 -0
  449. sqlspec/migrations/commands.py +1232 -0
  450. sqlspec/migrations/context.py +157 -0
  451. sqlspec/migrations/fix.py +204 -0
  452. sqlspec/migrations/loaders.py +443 -0
  453. sqlspec/migrations/runner.py +1172 -0
  454. sqlspec/migrations/templates.py +234 -0
  455. sqlspec/migrations/tracker.py +611 -0
  456. sqlspec/migrations/utils.py +256 -0
  457. sqlspec/migrations/validation.py +207 -0
  458. sqlspec/migrations/version.py +446 -0
  459. sqlspec/observability/__init__.py +55 -0
  460. sqlspec/observability/_common.cpython-310-aarch64-linux-gnu.so +0 -0
  461. sqlspec/observability/_common.py +77 -0
  462. sqlspec/observability/_config.cpython-310-aarch64-linux-gnu.so +0 -0
  463. sqlspec/observability/_config.py +348 -0
  464. sqlspec/observability/_diagnostics.cpython-310-aarch64-linux-gnu.so +0 -0
  465. sqlspec/observability/_diagnostics.py +74 -0
  466. sqlspec/observability/_dispatcher.cpython-310-aarch64-linux-gnu.so +0 -0
  467. sqlspec/observability/_dispatcher.py +152 -0
  468. sqlspec/observability/_formatters/__init__.py +13 -0
  469. sqlspec/observability/_formatters/_aws.cpython-310-aarch64-linux-gnu.so +0 -0
  470. sqlspec/observability/_formatters/_aws.py +102 -0
  471. sqlspec/observability/_formatters/_azure.cpython-310-aarch64-linux-gnu.so +0 -0
  472. sqlspec/observability/_formatters/_azure.py +96 -0
  473. sqlspec/observability/_formatters/_base.cpython-310-aarch64-linux-gnu.so +0 -0
  474. sqlspec/observability/_formatters/_base.py +57 -0
  475. sqlspec/observability/_formatters/_gcp.cpython-310-aarch64-linux-gnu.so +0 -0
  476. sqlspec/observability/_formatters/_gcp.py +131 -0
  477. sqlspec/observability/_formatting.py +58 -0
  478. sqlspec/observability/_observer.cpython-310-aarch64-linux-gnu.so +0 -0
  479. sqlspec/observability/_observer.py +357 -0
  480. sqlspec/observability/_runtime.cpython-310-aarch64-linux-gnu.so +0 -0
  481. sqlspec/observability/_runtime.py +420 -0
  482. sqlspec/observability/_sampling.cpython-310-aarch64-linux-gnu.so +0 -0
  483. sqlspec/observability/_sampling.py +188 -0
  484. sqlspec/observability/_spans.cpython-310-aarch64-linux-gnu.so +0 -0
  485. sqlspec/observability/_spans.py +161 -0
  486. sqlspec/protocols.py +916 -0
  487. sqlspec/py.typed +0 -0
  488. sqlspec/storage/__init__.py +48 -0
  489. sqlspec/storage/_utils.py +104 -0
  490. sqlspec/storage/backends/__init__.py +1 -0
  491. sqlspec/storage/backends/base.py +253 -0
  492. sqlspec/storage/backends/fsspec.py +529 -0
  493. sqlspec/storage/backends/local.py +441 -0
  494. sqlspec/storage/backends/obstore.py +916 -0
  495. sqlspec/storage/errors.py +104 -0
  496. sqlspec/storage/pipeline.py +582 -0
  497. sqlspec/storage/registry.py +301 -0
  498. sqlspec/typing.py +395 -0
  499. sqlspec/utils/__init__.py +7 -0
  500. sqlspec/utils/arrow_helpers.py +318 -0
  501. sqlspec/utils/config_tools.py +332 -0
  502. sqlspec/utils/correlation.cpython-310-aarch64-linux-gnu.so +0 -0
  503. sqlspec/utils/correlation.py +134 -0
  504. sqlspec/utils/deprecation.py +190 -0
  505. sqlspec/utils/fixtures.cpython-310-aarch64-linux-gnu.so +0 -0
  506. sqlspec/utils/fixtures.py +258 -0
  507. sqlspec/utils/logging.py +222 -0
  508. sqlspec/utils/module_loader.py +306 -0
  509. sqlspec/utils/portal.cpython-310-aarch64-linux-gnu.so +0 -0
  510. sqlspec/utils/portal.py +375 -0
  511. sqlspec/utils/schema.cpython-310-aarch64-linux-gnu.so +0 -0
  512. sqlspec/utils/schema.py +485 -0
  513. sqlspec/utils/serializers.cpython-310-aarch64-linux-gnu.so +0 -0
  514. sqlspec/utils/serializers.py +408 -0
  515. sqlspec/utils/singleton.cpython-310-aarch64-linux-gnu.so +0 -0
  516. sqlspec/utils/singleton.py +41 -0
  517. sqlspec/utils/sync_tools.cpython-310-aarch64-linux-gnu.so +0 -0
  518. sqlspec/utils/sync_tools.py +311 -0
  519. sqlspec/utils/text.cpython-310-aarch64-linux-gnu.so +0 -0
  520. sqlspec/utils/text.py +108 -0
  521. sqlspec/utils/type_converters.cpython-310-aarch64-linux-gnu.so +0 -0
  522. sqlspec/utils/type_converters.py +128 -0
  523. sqlspec/utils/type_guards.cpython-310-aarch64-linux-gnu.so +0 -0
  524. sqlspec/utils/type_guards.py +1360 -0
  525. sqlspec/utils/uuids.cpython-310-aarch64-linux-gnu.so +0 -0
  526. sqlspec/utils/uuids.py +225 -0
  527. sqlspec-0.36.0.dist-info/METADATA +205 -0
  528. sqlspec-0.36.0.dist-info/RECORD +531 -0
  529. sqlspec-0.36.0.dist-info/WHEEL +7 -0
  530. sqlspec-0.36.0.dist-info/entry_points.txt +2 -0
  531. sqlspec-0.36.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,731 @@
1
+ """Base classes for SQLSpec migrations."""
2
+
3
+ import ast
4
+ import hashlib
5
+ from abc import ABC, abstractmethod
6
+ from pathlib import Path
7
+ from typing import TYPE_CHECKING, Any, Generic, TypeVar, cast
8
+
9
+ from rich.console import Console
10
+
11
+ from sqlspec.builder import CreateTable, Delete, Insert, Select, Update, sql
12
+ from sqlspec.loader import SQLFileLoader
13
+ from sqlspec.migrations.context import MigrationContext
14
+ from sqlspec.migrations.loaders import get_migration_loader
15
+ from sqlspec.migrations.templates import MigrationTemplateSettings, TemplateDescriptionHints, build_template_settings
16
+ from sqlspec.migrations.version import parse_version
17
+ from sqlspec.utils.logging import get_logger
18
+ from sqlspec.utils.module_loader import module_to_os_path
19
+ from sqlspec.utils.sync_tools import await_
20
+
21
+ if TYPE_CHECKING:
22
+ from sqlspec.config import DatabaseConfigProtocol
23
+ from sqlspec.observability import ObservabilityRuntime
24
+
25
+ __all__ = ("BaseMigrationCommands", "BaseMigrationRunner", "BaseMigrationTracker")
26
+
27
+ DriverT = TypeVar("DriverT")
28
+ ConfigT = TypeVar("ConfigT", bound="DatabaseConfigProtocol[Any, Any, Any]")
29
+
30
+ logger = get_logger("sqlspec.migrations.base")
31
+
32
+
33
+ class BaseMigrationTracker(ABC, Generic[DriverT]):
34
+ """Base class for migration version tracking."""
35
+
36
+ __slots__ = ("version_table",)
37
+
38
+ def __init__(self, version_table_name: str = "ddl_migrations") -> None:
39
+ """Initialize the migration tracker.
40
+
41
+ Args:
42
+ version_table_name: Name of the table to track migrations.
43
+ """
44
+ self.version_table = version_table_name
45
+
46
+ def _get_create_table_sql(self) -> CreateTable:
47
+ """Get SQL builder for creating the tracking table.
48
+
49
+ Schema includes both legacy and new versioning columns:
50
+ - version_num: Migration version (sequential or timestamp format)
51
+ - version_type: Format indicator ('sequential' or 'timestamp')
52
+ - execution_sequence: Auto-incrementing application order
53
+ - description: Human-readable migration description
54
+ - applied_at: Timestamp when migration was applied
55
+ - execution_time_ms: Migration execution duration
56
+ - checksum: MD5 hash for content verification
57
+ - applied_by: User who applied the migration
58
+
59
+ Returns:
60
+ SQL builder object for table creation.
61
+ """
62
+ return (
63
+ sql
64
+ .create_table(self.version_table)
65
+ .if_not_exists()
66
+ .column("version_num", "VARCHAR(32)", primary_key=True)
67
+ .column("version_type", "VARCHAR(16)")
68
+ .column("execution_sequence", "INTEGER")
69
+ .column("description", "TEXT")
70
+ .column("applied_at", "TIMESTAMP", default="CURRENT_TIMESTAMP", not_null=True)
71
+ .column("execution_time_ms", "INTEGER")
72
+ .column("checksum", "VARCHAR(64)")
73
+ .column("applied_by", "VARCHAR(255)")
74
+ )
75
+
76
+ def _get_current_version_sql(self) -> Select:
77
+ """Get SQL builder for retrieving current version.
78
+
79
+ Uses execution_sequence to get the last applied migration,
80
+ which may differ from version_num order due to out-of-order migrations.
81
+
82
+ Returns:
83
+ SQL builder object for version query.
84
+ """
85
+ return sql.select("version_num").from_(self.version_table).order_by("execution_sequence DESC").limit(1)
86
+
87
+ def _get_applied_migrations_sql(self) -> Select:
88
+ """Get SQL builder for retrieving all applied migrations.
89
+
90
+ Orders by execution_sequence to show migrations in application order,
91
+ which preserves the actual execution history for out-of-order migrations.
92
+
93
+ Returns:
94
+ SQL builder object for migrations query.
95
+ """
96
+ return sql.select("*").from_(self.version_table).order_by("execution_sequence")
97
+
98
+ def _get_next_execution_sequence_sql(self) -> Select:
99
+ """Get SQL builder for retrieving next execution sequence.
100
+
101
+ Returns:
102
+ SQL builder object for sequence query.
103
+ """
104
+ return sql.select("COALESCE(MAX(execution_sequence), 0) + 1 AS next_seq").from_(self.version_table)
105
+
106
+ def _get_record_migration_sql(
107
+ self,
108
+ version: str,
109
+ version_type: str,
110
+ execution_sequence: int,
111
+ description: str,
112
+ execution_time_ms: int,
113
+ checksum: str,
114
+ applied_by: str,
115
+ ) -> Insert:
116
+ """Get SQL builder for recording a migration.
117
+
118
+ Args:
119
+ version: Version number of the migration.
120
+ version_type: Version format type ('sequential' or 'timestamp').
121
+ execution_sequence: Auto-incrementing application order.
122
+ description: Description of the migration.
123
+ execution_time_ms: Execution time in milliseconds.
124
+ checksum: MD5 checksum of the migration content.
125
+ applied_by: User who applied the migration.
126
+
127
+ Returns:
128
+ SQL builder object for insert.
129
+ """
130
+ return (
131
+ sql
132
+ .insert(self.version_table)
133
+ .columns(
134
+ "version_num",
135
+ "version_type",
136
+ "execution_sequence",
137
+ "description",
138
+ "execution_time_ms",
139
+ "checksum",
140
+ "applied_by",
141
+ )
142
+ .values(version, version_type, execution_sequence, description, execution_time_ms, checksum, applied_by)
143
+ )
144
+
145
+ def _get_remove_migration_sql(self, version: str) -> Delete:
146
+ """Get SQL builder for removing a migration record.
147
+
148
+ Args:
149
+ version: Version number to remove.
150
+
151
+ Returns:
152
+ SQL builder object for delete.
153
+ """
154
+ return sql.delete().from_(self.version_table).where(sql.version_num == version)
155
+
156
+ def _get_update_version_sql(self, old_version: str, new_version: str, new_version_type: str) -> Update:
157
+ """Get SQL builder for updating version record.
158
+
159
+ Updates version_num and version_type while preserving execution_sequence,
160
+ applied_at, and other metadata. Used during fix command to convert
161
+ timestamp versions to sequential format.
162
+
163
+ Args:
164
+ old_version: Current version string.
165
+ new_version: New version string.
166
+ new_version_type: New version type ('sequential' or 'timestamp').
167
+
168
+ Returns:
169
+ SQL builder object for update.
170
+ """
171
+ return (
172
+ sql
173
+ .update(self.version_table)
174
+ .set("version_num", new_version)
175
+ .set("version_type", new_version_type)
176
+ .where(sql.version_num == old_version)
177
+ )
178
+
179
+ def _get_check_column_exists_sql(self) -> Select:
180
+ """Get SQL to check what columns exist in the tracking table.
181
+
182
+ Returns a query that will fail gracefully if the table doesn't exist,
183
+ and returns column names if it does.
184
+
185
+ Returns:
186
+ SQL builder object for column check query.
187
+ """
188
+ return sql.select("*").from_(self.version_table).limit(0)
189
+
190
+ def _get_add_missing_columns_sql(self, missing_columns: "set[str]") -> "list[str]":
191
+ """Generate ALTER TABLE statements to add missing columns.
192
+
193
+ Args:
194
+ missing_columns: Set of column names that need to be added.
195
+
196
+ Returns:
197
+ List of SQL statements to execute.
198
+ """
199
+
200
+ statements = []
201
+ target_create = self._get_create_table_sql()
202
+
203
+ column_definitions = {col.name.lower(): col for col in target_create.columns}
204
+
205
+ for col_name in sorted(missing_columns):
206
+ if col_name in column_definitions:
207
+ col_def = column_definitions[col_name]
208
+ alter = sql.alter_table(self.version_table).add_column(
209
+ name=col_def.name,
210
+ dtype=col_def.dtype,
211
+ default=col_def.default,
212
+ not_null=col_def.not_null,
213
+ unique=col_def.unique,
214
+ comment=col_def.comment,
215
+ )
216
+ statements.append(str(alter))
217
+
218
+ return statements
219
+
220
+ def _detect_missing_columns(self, existing_columns: "set[str]") -> "set[str]":
221
+ """Detect which columns are missing from the current schema.
222
+
223
+ Args:
224
+ existing_columns: Set of existing column names (may be uppercase/lowercase).
225
+
226
+ Returns:
227
+ Set of missing column names (lowercase).
228
+ """
229
+ target_create = self._get_create_table_sql()
230
+ target_columns = {col.name.lower() for col in target_create.columns}
231
+ existing_lower = {col.lower() for col in existing_columns}
232
+ return target_columns - existing_lower
233
+
234
+ @abstractmethod
235
+ def ensure_tracking_table(self, driver: DriverT) -> Any:
236
+ """Create the migration tracking table if it doesn't exist.
237
+
238
+ Implementations should also check for and add any missing columns
239
+ to support schema migrations from older versions.
240
+ """
241
+ ...
242
+
243
+ @abstractmethod
244
+ def get_current_version(self, driver: DriverT) -> Any:
245
+ """Get the latest applied migration version."""
246
+ ...
247
+
248
+ @abstractmethod
249
+ def get_applied_migrations(self, driver: DriverT) -> Any:
250
+ """Get all applied migrations in order."""
251
+ ...
252
+
253
+ @abstractmethod
254
+ def record_migration(
255
+ self, driver: DriverT, version: str, description: str, execution_time_ms: int, checksum: str
256
+ ) -> Any:
257
+ """Record a successfully applied migration."""
258
+ ...
259
+
260
+ @abstractmethod
261
+ def remove_migration(self, driver: DriverT, version: str) -> Any:
262
+ """Remove a migration record."""
263
+ ...
264
+
265
+
266
+ class BaseMigrationRunner(ABC, Generic[DriverT]):
267
+ """Base class for migration execution."""
268
+
269
+ extension_configs: "dict[str, dict[str, Any]]"
270
+
271
+ def __init__(
272
+ self,
273
+ migrations_path: Path,
274
+ extension_migrations: "dict[str, Path] | None" = None,
275
+ context: "Any | None" = None,
276
+ extension_configs: "dict[str, dict[str, Any]] | None" = None,
277
+ description_hints: "TemplateDescriptionHints | None" = None,
278
+ ) -> None:
279
+ """Initialize the migration runner.
280
+
281
+ Args:
282
+ migrations_path: Path to the directory containing migration files.
283
+ extension_migrations: Optional mapping of extension names to their migration paths.
284
+ context: Optional migration context for Python migrations.
285
+ extension_configs: Optional mapping of extension names to their configurations.
286
+ description_hints: Preferred metadata keys for extracting human descriptions
287
+ from SQL comments and Python docstrings.
288
+ """
289
+ self.migrations_path = migrations_path
290
+ self.extension_migrations = extension_migrations or {}
291
+ self.loader = SQLFileLoader()
292
+ self.project_root: Path | None = None
293
+ self.context = context
294
+ self.extension_configs = extension_configs or {}
295
+ self.description_hints = description_hints or TemplateDescriptionHints()
296
+
297
+ def _extract_version(self, filename: str) -> str | None:
298
+ """Extract version from filename.
299
+
300
+ Args:
301
+ filename: The migration filename.
302
+
303
+ Returns:
304
+ The extracted version string or None.
305
+ """
306
+ stem = Path(filename).stem
307
+
308
+ if stem.startswith("ext_"):
309
+ return stem
310
+
311
+ parts = stem.split("_", 1)
312
+ return parts[0].zfill(4) if parts and parts[0].isdigit() else None
313
+
314
+ def _calculate_checksum(self, content: str) -> str:
315
+ """Calculate MD5 checksum of migration content.
316
+
317
+ Args:
318
+ content: The migration file content.
319
+
320
+ Returns:
321
+ MD5 checksum hex string.
322
+ """
323
+
324
+ return hashlib.md5(content.encode()).hexdigest() # noqa: S324
325
+
326
+ def _get_migration_files_sync(self) -> "list[tuple[str, Path]]":
327
+ """Get all migration files sorted by version.
328
+
329
+ Uses version-aware sorting that handles both sequential and timestamp
330
+ formats correctly, with extension migrations sorted by extension name.
331
+
332
+ Returns:
333
+ List of tuples containing (version, file_path).
334
+ """
335
+ migrations = []
336
+
337
+ # Scan primary migration path
338
+ if self.migrations_path.exists():
339
+ for pattern in ("*.sql", "*.py"):
340
+ for file_path in self.migrations_path.glob(pattern):
341
+ if file_path.name.startswith("."):
342
+ continue
343
+ version = self._extract_version(file_path.name)
344
+ if version:
345
+ migrations.append((version, file_path))
346
+
347
+ # Scan extension migration paths
348
+ for ext_name, ext_path in self.extension_migrations.items():
349
+ if ext_path.exists():
350
+ for pattern in ("*.sql", "*.py"):
351
+ for file_path in ext_path.glob(pattern):
352
+ if file_path.name.startswith("."):
353
+ continue
354
+ # Prefix extension migrations to avoid version conflicts
355
+ version = self._extract_version(file_path.name)
356
+ if version:
357
+ # Use ext_ prefix to distinguish extension migrations
358
+ prefixed_version = f"ext_{ext_name}_{version}"
359
+ migrations.append((prefixed_version, file_path))
360
+
361
+ return sorted(migrations, key=_migration_sort_key)
362
+
363
+ def _load_migration_metadata(self, file_path: Path, version: "str | None" = None) -> "dict[str, Any]":
364
+ """Load migration metadata from file.
365
+
366
+ Args:
367
+ file_path: Path to the migration file.
368
+ version: Optional pre-extracted version (preserves prefixes like ext_adk_0001).
369
+
370
+ Returns:
371
+ Migration metadata dictionary.
372
+ """
373
+ if version is None:
374
+ version = self._extract_version(file_path.name)
375
+
376
+ context_to_use = self.context
377
+
378
+ for ext_name, ext_path in self.extension_migrations.items():
379
+ if file_path.parent == ext_path:
380
+ if ext_name in self.extension_configs and self.context:
381
+ context_to_use = MigrationContext(
382
+ dialect=self.context.dialect,
383
+ config=self.context.config,
384
+ driver=self.context.driver,
385
+ metadata=self.context.metadata.copy() if self.context.metadata else {},
386
+ extension_config=self.extension_configs[ext_name],
387
+ )
388
+ break
389
+
390
+ loader = get_migration_loader(file_path, self.migrations_path, self.project_root, context_to_use)
391
+ loader.validate_migration_file(file_path)
392
+ content = file_path.read_text(encoding="utf-8")
393
+ checksum = self._calculate_checksum(content)
394
+ description = self._extract_description(content, file_path)
395
+ if not description:
396
+ description = file_path.stem.split("_", 1)[1] if "_" in file_path.stem else ""
397
+
398
+ has_upgrade, has_downgrade = True, False
399
+
400
+ if file_path.suffix == ".sql":
401
+ up_query, down_query = f"migrate-{version}-up", f"migrate-{version}-down"
402
+ self.loader.clear_cache()
403
+ self.loader.load_sql(file_path)
404
+ has_upgrade, has_downgrade = self.loader.has_query(up_query), self.loader.has_query(down_query)
405
+ else:
406
+ try:
407
+ has_downgrade = bool(await_(loader.get_down_sql, raise_sync_error=False)(file_path))
408
+ except Exception:
409
+ has_downgrade = False
410
+
411
+ return {
412
+ "version": version,
413
+ "description": description,
414
+ "file_path": file_path,
415
+ "checksum": checksum,
416
+ "has_upgrade": has_upgrade,
417
+ "has_downgrade": has_downgrade,
418
+ "loader": loader,
419
+ }
420
+
421
+ def _extract_description(self, content: str, file_path: Path) -> str:
422
+ if file_path.suffix == ".sql":
423
+ return self._extract_sql_description(content)
424
+ if file_path.suffix == ".py":
425
+ return self._extract_python_description(content)
426
+ return ""
427
+
428
+ def _extract_sql_description(self, content: str) -> str:
429
+ keys = self.description_hints.sql_keys
430
+ for line in content.splitlines():
431
+ stripped = line.strip()
432
+ if not stripped:
433
+ continue
434
+ if stripped.startswith("--"):
435
+ body = stripped.lstrip("-").strip()
436
+ if not body:
437
+ continue
438
+ if ":" in body:
439
+ key, value = body.split(":", 1)
440
+ if key.strip() in keys:
441
+ return value.strip()
442
+ continue
443
+ break
444
+ return ""
445
+
446
+ def _extract_python_description(self, content: str) -> str:
447
+ try:
448
+ module = ast.parse(content)
449
+ except SyntaxError:
450
+ return ""
451
+ docstring = ast.get_docstring(module) or ""
452
+ keys = self.description_hints.python_keys
453
+ for line in docstring.splitlines():
454
+ stripped = line.strip()
455
+ if not stripped:
456
+ continue
457
+ if ":" in stripped:
458
+ key, value = stripped.split(":", 1)
459
+ if key.strip() in keys:
460
+ return value.strip()
461
+ return stripped
462
+ return ""
463
+
464
+ def _get_migration_sql(self, migration: "dict[str, Any]", direction: str) -> "list[str] | None":
465
+ """Get migration SQL for given direction.
466
+
467
+ Args:
468
+ migration: Migration metadata.
469
+ direction: Either 'up' or 'down'.
470
+
471
+ Returns:
472
+ SQL object for the migration.
473
+ """
474
+ if not migration.get(f"has_{direction}grade"):
475
+ if direction == "down":
476
+ logger.warning("Migration %s has no downgrade query", migration["version"])
477
+ return None
478
+ msg = f"Migration {migration['version']} has no upgrade query"
479
+ raise ValueError(msg)
480
+
481
+ file_path, loader = migration["file_path"], migration["loader"]
482
+
483
+ try:
484
+ method = loader.get_up_sql if direction == "up" else loader.get_down_sql
485
+ sql_statements = await_(method, raise_sync_error=False)(file_path)
486
+
487
+ except Exception as e:
488
+ if direction == "down":
489
+ logger.warning("Failed to load downgrade for migration %s: %s", migration["version"], e)
490
+ return None
491
+ msg = f"Failed to load upgrade for migration {migration['version']}: {e}"
492
+ raise ValueError(msg) from e
493
+ else:
494
+ if sql_statements:
495
+ return cast("list[str]", sql_statements)
496
+ return None
497
+
498
+ @abstractmethod
499
+ def get_migration_files(self) -> Any:
500
+ """Get all migration files sorted by version."""
501
+ ...
502
+
503
+ @abstractmethod
504
+ def load_migration(self, file_path: Path) -> Any:
505
+ """Load a migration file and extract its components."""
506
+ ...
507
+
508
+ @abstractmethod
509
+ def execute_upgrade(self, driver: DriverT, migration: "dict[str, Any]") -> Any:
510
+ """Execute an upgrade migration."""
511
+ ...
512
+
513
+ @abstractmethod
514
+ def execute_downgrade(self, driver: DriverT, migration: "dict[str, Any]") -> Any:
515
+ """Execute a downgrade migration."""
516
+ ...
517
+
518
+ @abstractmethod
519
+ def load_all_migrations(self) -> Any:
520
+ """Load all migrations into a single namespace for bulk operations."""
521
+ ...
522
+
523
+
524
+ def _migration_sort_key(item: "tuple[str, Path]") -> Any:
525
+ return parse_version(item[0])
526
+
527
+
528
+ class BaseMigrationCommands(ABC, Generic[ConfigT, DriverT]):
529
+ """Base class for migration commands."""
530
+
531
+ extension_configs: "dict[str, dict[str, Any]]"
532
+
533
+ def __init__(self, config: ConfigT) -> None:
534
+ """Initialize migration commands.
535
+
536
+ Args:
537
+ config: The SQLSpec configuration.
538
+ """
539
+ self.config = config
540
+ migration_config = cast("dict[str, Any]", self.config.migration_config) or {}
541
+
542
+ self.version_table = migration_config.get("version_table_name", "ddl_migrations")
543
+ self.migrations_path = Path(migration_config.get("script_location", "migrations"))
544
+ self.project_root = Path(migration_config["project_root"]) if "project_root" in migration_config else None
545
+ self.include_extensions = migration_config.get("include_extensions", [])
546
+ self.extension_configs = self._parse_extension_configs()
547
+ self._template_settings: MigrationTemplateSettings = build_template_settings(migration_config)
548
+ self._runtime: ObservabilityRuntime | None = self.config.get_observability_runtime()
549
+ self._last_command_error: Exception | None = None
550
+ self._last_command_metrics: dict[str, float] | None = None
551
+
552
+ def _parse_extension_configs(self) -> "dict[str, dict[str, Any]]":
553
+ """Parse extension configurations from include_extensions.
554
+
555
+ Reads extension configuration from config.extension_config for each
556
+ extension listed in include_extensions.
557
+
558
+ Returns:
559
+ Dictionary mapping extension names to their configurations.
560
+ """
561
+ configs = {}
562
+
563
+ for ext_config in self.include_extensions:
564
+ if not isinstance(ext_config, str):
565
+ logger.warning("Extension must be a string name, got: %s", ext_config)
566
+ continue
567
+
568
+ ext_name = ext_config
569
+ ext_options = cast("dict[str, Any]", self.config.extension_config).get(ext_name, {})
570
+ configs[ext_name] = ext_options
571
+
572
+ return configs
573
+
574
+ def _discover_extension_migrations(self) -> "dict[str, Path]":
575
+ """Discover migration paths for configured extensions.
576
+
577
+ Returns:
578
+ Dictionary mapping extension names to their migration paths.
579
+ """
580
+
581
+ extension_migrations = {}
582
+
583
+ for ext_name in self.extension_configs:
584
+ module_name = "sqlspec.extensions.litestar" if ext_name == "litestar" else f"sqlspec.extensions.{ext_name}"
585
+
586
+ try:
587
+ module_path = module_to_os_path(module_name)
588
+ migrations_dir = module_path / "migrations"
589
+
590
+ if migrations_dir.exists():
591
+ extension_migrations[ext_name] = migrations_dir
592
+ logger.debug("Found migrations for extension %s at %s", ext_name, migrations_dir)
593
+ else:
594
+ logger.warning("No migrations directory found for extension %s", ext_name)
595
+ except TypeError:
596
+ logger.warning("Extension %s not found", ext_name)
597
+
598
+ return extension_migrations
599
+
600
+ def _get_init_readme_content(self) -> str:
601
+ """Get README content for migration directory initialization.
602
+
603
+ Returns:
604
+ README markdown content.
605
+ """
606
+ return """# SQLSpec Migrations
607
+
608
+ This directory contains database migration files.
609
+
610
+ ## File Format
611
+
612
+ Migration files use SQLFileLoader's named query syntax with versioned names:
613
+
614
+ ```sql
615
+ -- name: migrate-20251011120000-up
616
+ CREATE TABLE example (
617
+ id INTEGER PRIMARY KEY,
618
+ name TEXT NOT NULL
619
+ );
620
+
621
+ -- name: migrate-20251011120000-down
622
+ DROP TABLE example;
623
+ ```
624
+
625
+ ## Naming Conventions
626
+
627
+ ### File Names
628
+
629
+ Format: `{version}_{description}.sql`
630
+
631
+ - Version: Timestamp in YYYYMMDDHHmmss format (UTC)
632
+ - Description: Brief description using underscores
633
+ - Example: `20251011120000_create_users_table.sql`
634
+
635
+ ### Query Names
636
+
637
+ - Upgrade: `migrate-{version}-up`
638
+ - Downgrade: `migrate-{version}-down`
639
+
640
+ ## Version Format
641
+
642
+ Migrations use **timestamp-based versioning** (YYYYMMDDHHmmss):
643
+
644
+ - **Format**: 14-digit UTC timestamp
645
+ - **Example**: `20251011120000` (October 11, 2025 at 12:00:00 UTC)
646
+ - **Benefits**: Eliminates merge conflicts when multiple developers create migrations concurrently
647
+
648
+ ### Creating Migrations
649
+
650
+ Use the CLI to generate timestamped migrations:
651
+
652
+ ```bash
653
+ sqlspec create-migration "add user table"
654
+ # Creates: 20251011120000_add_user_table.sql
655
+ ```
656
+
657
+ The timestamp is automatically generated in UTC timezone.
658
+
659
+ ## Migration Execution
660
+
661
+ Migrations are applied in chronological order based on their timestamps.
662
+ The database tracks both version and execution order separately to handle
663
+ out-of-order migrations gracefully (e.g., from late-merging branches).
664
+ """
665
+
666
+ def _get_init_init_content(self) -> str:
667
+ """Get __init__.py content for migration directory initialization.
668
+
669
+ Returns:
670
+ Python module docstring content for the __init__.py file.
671
+ """
672
+ return """Migrations.
673
+ """
674
+
675
+ def init_directory(self, directory: str, package: bool = True) -> None:
676
+ """Initialize migration directory structure.
677
+
678
+ Args:
679
+ directory: Directory to initialize migrations in.
680
+ package: Whether to create __init__.py file.
681
+ """
682
+ console = Console()
683
+
684
+ migrations_dir = Path(directory)
685
+ migrations_dir.mkdir(parents=True, exist_ok=True)
686
+
687
+ if package:
688
+ init = migrations_dir / "__init__.py"
689
+ init.write_text(self._get_init_init_content())
690
+
691
+ readme = migrations_dir / "README.md"
692
+ readme.write_text(self._get_init_readme_content())
693
+
694
+ console.print(f"[green]Initialized migrations in {directory}[/]")
695
+
696
+ def _record_command_metric(self, name: str, value: float) -> None:
697
+ """Accumulate per-command metrics for decorator flushing."""
698
+
699
+ if self._last_command_metrics is None:
700
+ self._last_command_metrics = {}
701
+ self._last_command_metrics[name] = self._last_command_metrics.get(name, 0.0) + value
702
+
703
+ @abstractmethod
704
+ def init(self, directory: str, package: bool = True) -> Any:
705
+ """Initialize migration directory structure."""
706
+ ...
707
+
708
+ @abstractmethod
709
+ def current(self, verbose: bool = False) -> Any:
710
+ """Show current migration version."""
711
+ ...
712
+
713
+ @abstractmethod
714
+ def upgrade(self, revision: str = "head") -> Any:
715
+ """Upgrade to a target revision."""
716
+ ...
717
+
718
+ @abstractmethod
719
+ def downgrade(self, revision: str = "-1") -> Any:
720
+ """Downgrade to a target revision."""
721
+ ...
722
+
723
+ @abstractmethod
724
+ def stamp(self, revision: str) -> Any:
725
+ """Mark database as being at a specific revision without running migrations."""
726
+ ...
727
+
728
+ @abstractmethod
729
+ def revision(self, message: str, file_type: str = "sql") -> Any:
730
+ """Create a new migration file."""
731
+ ...