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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (531) hide show
  1. ac8f31065839703b4e70__mypyc.cpython-310-aarch64-linux-gnu.so +0 -0
  2. sqlspec/__init__.py +140 -0
  3. sqlspec/__main__.py +12 -0
  4. sqlspec/__metadata__.py +14 -0
  5. sqlspec/_serialization.py +315 -0
  6. sqlspec/_typing.py +700 -0
  7. sqlspec/adapters/__init__.py +0 -0
  8. sqlspec/adapters/adbc/__init__.py +5 -0
  9. sqlspec/adapters/adbc/_typing.py +82 -0
  10. sqlspec/adapters/adbc/adk/__init__.py +5 -0
  11. sqlspec/adapters/adbc/adk/store.py +1273 -0
  12. sqlspec/adapters/adbc/config.py +295 -0
  13. sqlspec/adapters/adbc/core.cpython-310-aarch64-linux-gnu.so +0 -0
  14. sqlspec/adapters/adbc/core.py +735 -0
  15. sqlspec/adapters/adbc/data_dictionary.py +334 -0
  16. sqlspec/adapters/adbc/driver.py +529 -0
  17. sqlspec/adapters/adbc/events/__init__.py +5 -0
  18. sqlspec/adapters/adbc/events/store.py +285 -0
  19. sqlspec/adapters/adbc/litestar/__init__.py +5 -0
  20. sqlspec/adapters/adbc/litestar/store.py +502 -0
  21. sqlspec/adapters/adbc/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  22. sqlspec/adapters/adbc/type_converter.py +140 -0
  23. sqlspec/adapters/aiosqlite/__init__.py +25 -0
  24. sqlspec/adapters/aiosqlite/_typing.py +82 -0
  25. sqlspec/adapters/aiosqlite/adk/__init__.py +5 -0
  26. sqlspec/adapters/aiosqlite/adk/store.py +818 -0
  27. sqlspec/adapters/aiosqlite/config.py +334 -0
  28. sqlspec/adapters/aiosqlite/core.cpython-310-aarch64-linux-gnu.so +0 -0
  29. sqlspec/adapters/aiosqlite/core.py +315 -0
  30. sqlspec/adapters/aiosqlite/data_dictionary.py +208 -0
  31. sqlspec/adapters/aiosqlite/driver.py +313 -0
  32. sqlspec/adapters/aiosqlite/events/__init__.py +5 -0
  33. sqlspec/adapters/aiosqlite/events/store.py +20 -0
  34. sqlspec/adapters/aiosqlite/litestar/__init__.py +5 -0
  35. sqlspec/adapters/aiosqlite/litestar/store.py +279 -0
  36. sqlspec/adapters/aiosqlite/pool.py +533 -0
  37. sqlspec/adapters/asyncmy/__init__.py +21 -0
  38. sqlspec/adapters/asyncmy/_typing.py +87 -0
  39. sqlspec/adapters/asyncmy/adk/__init__.py +5 -0
  40. sqlspec/adapters/asyncmy/adk/store.py +703 -0
  41. sqlspec/adapters/asyncmy/config.py +302 -0
  42. sqlspec/adapters/asyncmy/core.cpython-310-aarch64-linux-gnu.so +0 -0
  43. sqlspec/adapters/asyncmy/core.py +360 -0
  44. sqlspec/adapters/asyncmy/data_dictionary.py +124 -0
  45. sqlspec/adapters/asyncmy/driver.py +383 -0
  46. sqlspec/adapters/asyncmy/events/__init__.py +5 -0
  47. sqlspec/adapters/asyncmy/events/store.py +104 -0
  48. sqlspec/adapters/asyncmy/litestar/__init__.py +5 -0
  49. sqlspec/adapters/asyncmy/litestar/store.py +296 -0
  50. sqlspec/adapters/asyncpg/__init__.py +19 -0
  51. sqlspec/adapters/asyncpg/_typing.py +88 -0
  52. sqlspec/adapters/asyncpg/adk/__init__.py +5 -0
  53. sqlspec/adapters/asyncpg/adk/store.py +748 -0
  54. sqlspec/adapters/asyncpg/config.py +569 -0
  55. sqlspec/adapters/asyncpg/core.cpython-310-aarch64-linux-gnu.so +0 -0
  56. sqlspec/adapters/asyncpg/core.py +367 -0
  57. sqlspec/adapters/asyncpg/data_dictionary.py +162 -0
  58. sqlspec/adapters/asyncpg/driver.py +487 -0
  59. sqlspec/adapters/asyncpg/events/__init__.py +6 -0
  60. sqlspec/adapters/asyncpg/events/backend.py +286 -0
  61. sqlspec/adapters/asyncpg/events/store.py +40 -0
  62. sqlspec/adapters/asyncpg/litestar/__init__.py +5 -0
  63. sqlspec/adapters/asyncpg/litestar/store.py +251 -0
  64. sqlspec/adapters/bigquery/__init__.py +14 -0
  65. sqlspec/adapters/bigquery/_typing.py +86 -0
  66. sqlspec/adapters/bigquery/adk/__init__.py +5 -0
  67. sqlspec/adapters/bigquery/adk/store.py +827 -0
  68. sqlspec/adapters/bigquery/config.py +353 -0
  69. sqlspec/adapters/bigquery/core.cpython-310-aarch64-linux-gnu.so +0 -0
  70. sqlspec/adapters/bigquery/core.py +715 -0
  71. sqlspec/adapters/bigquery/data_dictionary.py +128 -0
  72. sqlspec/adapters/bigquery/driver.py +548 -0
  73. sqlspec/adapters/bigquery/events/__init__.py +5 -0
  74. sqlspec/adapters/bigquery/events/store.py +139 -0
  75. sqlspec/adapters/bigquery/litestar/__init__.py +5 -0
  76. sqlspec/adapters/bigquery/litestar/store.py +325 -0
  77. sqlspec/adapters/bigquery/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  78. sqlspec/adapters/bigquery/type_converter.py +107 -0
  79. sqlspec/adapters/cockroach_asyncpg/__init__.py +24 -0
  80. sqlspec/adapters/cockroach_asyncpg/_typing.py +72 -0
  81. sqlspec/adapters/cockroach_asyncpg/adk/__init__.py +3 -0
  82. sqlspec/adapters/cockroach_asyncpg/adk/store.py +410 -0
  83. sqlspec/adapters/cockroach_asyncpg/config.py +238 -0
  84. sqlspec/adapters/cockroach_asyncpg/core.cpython-310-aarch64-linux-gnu.so +0 -0
  85. sqlspec/adapters/cockroach_asyncpg/core.py +55 -0
  86. sqlspec/adapters/cockroach_asyncpg/data_dictionary.py +107 -0
  87. sqlspec/adapters/cockroach_asyncpg/driver.py +144 -0
  88. sqlspec/adapters/cockroach_asyncpg/events/__init__.py +3 -0
  89. sqlspec/adapters/cockroach_asyncpg/events/store.py +20 -0
  90. sqlspec/adapters/cockroach_asyncpg/litestar/__init__.py +3 -0
  91. sqlspec/adapters/cockroach_asyncpg/litestar/store.py +142 -0
  92. sqlspec/adapters/cockroach_psycopg/__init__.py +38 -0
  93. sqlspec/adapters/cockroach_psycopg/_typing.py +129 -0
  94. sqlspec/adapters/cockroach_psycopg/adk/__init__.py +13 -0
  95. sqlspec/adapters/cockroach_psycopg/adk/store.py +868 -0
  96. sqlspec/adapters/cockroach_psycopg/config.py +484 -0
  97. sqlspec/adapters/cockroach_psycopg/core.cpython-310-aarch64-linux-gnu.so +0 -0
  98. sqlspec/adapters/cockroach_psycopg/core.py +63 -0
  99. sqlspec/adapters/cockroach_psycopg/data_dictionary.py +215 -0
  100. sqlspec/adapters/cockroach_psycopg/driver.py +284 -0
  101. sqlspec/adapters/cockroach_psycopg/events/__init__.py +6 -0
  102. sqlspec/adapters/cockroach_psycopg/events/store.py +34 -0
  103. sqlspec/adapters/cockroach_psycopg/litestar/__init__.py +3 -0
  104. sqlspec/adapters/cockroach_psycopg/litestar/store.py +325 -0
  105. sqlspec/adapters/duckdb/__init__.py +25 -0
  106. sqlspec/adapters/duckdb/_typing.py +81 -0
  107. sqlspec/adapters/duckdb/adk/__init__.py +14 -0
  108. sqlspec/adapters/duckdb/adk/store.py +850 -0
  109. sqlspec/adapters/duckdb/config.py +463 -0
  110. sqlspec/adapters/duckdb/core.cpython-310-aarch64-linux-gnu.so +0 -0
  111. sqlspec/adapters/duckdb/core.py +257 -0
  112. sqlspec/adapters/duckdb/data_dictionary.py +140 -0
  113. sqlspec/adapters/duckdb/driver.py +430 -0
  114. sqlspec/adapters/duckdb/events/__init__.py +5 -0
  115. sqlspec/adapters/duckdb/events/store.py +57 -0
  116. sqlspec/adapters/duckdb/litestar/__init__.py +5 -0
  117. sqlspec/adapters/duckdb/litestar/store.py +330 -0
  118. sqlspec/adapters/duckdb/pool.py +293 -0
  119. sqlspec/adapters/duckdb/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  120. sqlspec/adapters/duckdb/type_converter.py +118 -0
  121. sqlspec/adapters/mock/__init__.py +72 -0
  122. sqlspec/adapters/mock/_typing.py +147 -0
  123. sqlspec/adapters/mock/config.py +483 -0
  124. sqlspec/adapters/mock/core.py +319 -0
  125. sqlspec/adapters/mock/data_dictionary.py +366 -0
  126. sqlspec/adapters/mock/driver.py +721 -0
  127. sqlspec/adapters/mysqlconnector/__init__.py +36 -0
  128. sqlspec/adapters/mysqlconnector/_typing.py +141 -0
  129. sqlspec/adapters/mysqlconnector/adk/__init__.py +15 -0
  130. sqlspec/adapters/mysqlconnector/adk/store.py +1060 -0
  131. sqlspec/adapters/mysqlconnector/config.py +394 -0
  132. sqlspec/adapters/mysqlconnector/core.cpython-310-aarch64-linux-gnu.so +0 -0
  133. sqlspec/adapters/mysqlconnector/core.py +303 -0
  134. sqlspec/adapters/mysqlconnector/data_dictionary.py +235 -0
  135. sqlspec/adapters/mysqlconnector/driver.py +483 -0
  136. sqlspec/adapters/mysqlconnector/events/__init__.py +8 -0
  137. sqlspec/adapters/mysqlconnector/events/store.py +98 -0
  138. sqlspec/adapters/mysqlconnector/litestar/__init__.py +5 -0
  139. sqlspec/adapters/mysqlconnector/litestar/store.py +426 -0
  140. sqlspec/adapters/oracledb/__init__.py +60 -0
  141. sqlspec/adapters/oracledb/_numpy_handlers.py +141 -0
  142. sqlspec/adapters/oracledb/_typing.py +182 -0
  143. sqlspec/adapters/oracledb/_uuid_handlers.py +166 -0
  144. sqlspec/adapters/oracledb/adk/__init__.py +10 -0
  145. sqlspec/adapters/oracledb/adk/store.py +2369 -0
  146. sqlspec/adapters/oracledb/config.py +550 -0
  147. sqlspec/adapters/oracledb/core.cpython-310-aarch64-linux-gnu.so +0 -0
  148. sqlspec/adapters/oracledb/core.py +543 -0
  149. sqlspec/adapters/oracledb/data_dictionary.py +536 -0
  150. sqlspec/adapters/oracledb/driver.py +1229 -0
  151. sqlspec/adapters/oracledb/events/__init__.py +16 -0
  152. sqlspec/adapters/oracledb/events/backend.py +347 -0
  153. sqlspec/adapters/oracledb/events/store.py +420 -0
  154. sqlspec/adapters/oracledb/litestar/__init__.py +5 -0
  155. sqlspec/adapters/oracledb/litestar/store.py +781 -0
  156. sqlspec/adapters/oracledb/migrations.py +535 -0
  157. sqlspec/adapters/oracledb/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  158. sqlspec/adapters/oracledb/type_converter.py +211 -0
  159. sqlspec/adapters/psqlpy/__init__.py +17 -0
  160. sqlspec/adapters/psqlpy/_typing.py +79 -0
  161. sqlspec/adapters/psqlpy/adk/__init__.py +5 -0
  162. sqlspec/adapters/psqlpy/adk/store.py +766 -0
  163. sqlspec/adapters/psqlpy/config.py +304 -0
  164. sqlspec/adapters/psqlpy/core.cpython-310-aarch64-linux-gnu.so +0 -0
  165. sqlspec/adapters/psqlpy/core.py +480 -0
  166. sqlspec/adapters/psqlpy/data_dictionary.py +126 -0
  167. sqlspec/adapters/psqlpy/driver.py +438 -0
  168. sqlspec/adapters/psqlpy/events/__init__.py +6 -0
  169. sqlspec/adapters/psqlpy/events/backend.py +310 -0
  170. sqlspec/adapters/psqlpy/events/store.py +20 -0
  171. sqlspec/adapters/psqlpy/litestar/__init__.py +5 -0
  172. sqlspec/adapters/psqlpy/litestar/store.py +270 -0
  173. sqlspec/adapters/psqlpy/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  174. sqlspec/adapters/psqlpy/type_converter.py +113 -0
  175. sqlspec/adapters/psycopg/__init__.py +32 -0
  176. sqlspec/adapters/psycopg/_typing.py +164 -0
  177. sqlspec/adapters/psycopg/adk/__init__.py +10 -0
  178. sqlspec/adapters/psycopg/adk/store.py +1387 -0
  179. sqlspec/adapters/psycopg/config.py +576 -0
  180. sqlspec/adapters/psycopg/core.cpython-310-aarch64-linux-gnu.so +0 -0
  181. sqlspec/adapters/psycopg/core.py +450 -0
  182. sqlspec/adapters/psycopg/data_dictionary.py +289 -0
  183. sqlspec/adapters/psycopg/driver.py +975 -0
  184. sqlspec/adapters/psycopg/events/__init__.py +20 -0
  185. sqlspec/adapters/psycopg/events/backend.py +458 -0
  186. sqlspec/adapters/psycopg/events/store.py +42 -0
  187. sqlspec/adapters/psycopg/litestar/__init__.py +5 -0
  188. sqlspec/adapters/psycopg/litestar/store.py +552 -0
  189. sqlspec/adapters/psycopg/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  190. sqlspec/adapters/psycopg/type_converter.py +93 -0
  191. sqlspec/adapters/pymysql/__init__.py +21 -0
  192. sqlspec/adapters/pymysql/_typing.py +71 -0
  193. sqlspec/adapters/pymysql/adk/__init__.py +5 -0
  194. sqlspec/adapters/pymysql/adk/store.py +540 -0
  195. sqlspec/adapters/pymysql/config.py +195 -0
  196. sqlspec/adapters/pymysql/core.cpython-310-aarch64-linux-gnu.so +0 -0
  197. sqlspec/adapters/pymysql/core.py +299 -0
  198. sqlspec/adapters/pymysql/data_dictionary.py +122 -0
  199. sqlspec/adapters/pymysql/driver.py +259 -0
  200. sqlspec/adapters/pymysql/events/__init__.py +5 -0
  201. sqlspec/adapters/pymysql/events/store.py +50 -0
  202. sqlspec/adapters/pymysql/litestar/__init__.py +5 -0
  203. sqlspec/adapters/pymysql/litestar/store.py +232 -0
  204. sqlspec/adapters/pymysql/pool.py +137 -0
  205. sqlspec/adapters/spanner/__init__.py +40 -0
  206. sqlspec/adapters/spanner/_typing.py +86 -0
  207. sqlspec/adapters/spanner/adk/__init__.py +5 -0
  208. sqlspec/adapters/spanner/adk/store.py +732 -0
  209. sqlspec/adapters/spanner/config.py +352 -0
  210. sqlspec/adapters/spanner/core.cpython-310-aarch64-linux-gnu.so +0 -0
  211. sqlspec/adapters/spanner/core.py +188 -0
  212. sqlspec/adapters/spanner/data_dictionary.py +120 -0
  213. sqlspec/adapters/spanner/dialect/__init__.py +6 -0
  214. sqlspec/adapters/spanner/dialect/_spangres.py +57 -0
  215. sqlspec/adapters/spanner/dialect/_spanner.py +130 -0
  216. sqlspec/adapters/spanner/driver.py +373 -0
  217. sqlspec/adapters/spanner/events/__init__.py +5 -0
  218. sqlspec/adapters/spanner/events/store.py +187 -0
  219. sqlspec/adapters/spanner/litestar/__init__.py +5 -0
  220. sqlspec/adapters/spanner/litestar/store.py +291 -0
  221. sqlspec/adapters/spanner/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  222. sqlspec/adapters/spanner/type_converter.py +331 -0
  223. sqlspec/adapters/sqlite/__init__.py +19 -0
  224. sqlspec/adapters/sqlite/_typing.py +80 -0
  225. sqlspec/adapters/sqlite/adk/__init__.py +5 -0
  226. sqlspec/adapters/sqlite/adk/store.py +958 -0
  227. sqlspec/adapters/sqlite/config.py +280 -0
  228. sqlspec/adapters/sqlite/core.cpython-310-aarch64-linux-gnu.so +0 -0
  229. sqlspec/adapters/sqlite/core.py +312 -0
  230. sqlspec/adapters/sqlite/data_dictionary.py +202 -0
  231. sqlspec/adapters/sqlite/driver.py +359 -0
  232. sqlspec/adapters/sqlite/events/__init__.py +5 -0
  233. sqlspec/adapters/sqlite/events/store.py +20 -0
  234. sqlspec/adapters/sqlite/litestar/__init__.py +5 -0
  235. sqlspec/adapters/sqlite/litestar/store.py +316 -0
  236. sqlspec/adapters/sqlite/pool.py +198 -0
  237. sqlspec/adapters/sqlite/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  238. sqlspec/adapters/sqlite/type_converter.py +114 -0
  239. sqlspec/base.py +747 -0
  240. sqlspec/builder/__init__.py +179 -0
  241. sqlspec/builder/_base.cpython-310-aarch64-linux-gnu.so +0 -0
  242. sqlspec/builder/_base.py +1022 -0
  243. sqlspec/builder/_column.cpython-310-aarch64-linux-gnu.so +0 -0
  244. sqlspec/builder/_column.py +521 -0
  245. sqlspec/builder/_ddl.cpython-310-aarch64-linux-gnu.so +0 -0
  246. sqlspec/builder/_ddl.py +1642 -0
  247. sqlspec/builder/_delete.cpython-310-aarch64-linux-gnu.so +0 -0
  248. sqlspec/builder/_delete.py +95 -0
  249. sqlspec/builder/_dml.cpython-310-aarch64-linux-gnu.so +0 -0
  250. sqlspec/builder/_dml.py +365 -0
  251. sqlspec/builder/_explain.cpython-310-aarch64-linux-gnu.so +0 -0
  252. sqlspec/builder/_explain.py +579 -0
  253. sqlspec/builder/_expression_wrappers.cpython-310-aarch64-linux-gnu.so +0 -0
  254. sqlspec/builder/_expression_wrappers.py +46 -0
  255. sqlspec/builder/_factory.cpython-310-aarch64-linux-gnu.so +0 -0
  256. sqlspec/builder/_factory.py +1697 -0
  257. sqlspec/builder/_insert.cpython-310-aarch64-linux-gnu.so +0 -0
  258. sqlspec/builder/_insert.py +328 -0
  259. sqlspec/builder/_join.cpython-310-aarch64-linux-gnu.so +0 -0
  260. sqlspec/builder/_join.py +499 -0
  261. sqlspec/builder/_merge.cpython-310-aarch64-linux-gnu.so +0 -0
  262. sqlspec/builder/_merge.py +821 -0
  263. sqlspec/builder/_parsing_utils.cpython-310-aarch64-linux-gnu.so +0 -0
  264. sqlspec/builder/_parsing_utils.py +297 -0
  265. sqlspec/builder/_select.cpython-310-aarch64-linux-gnu.so +0 -0
  266. sqlspec/builder/_select.py +1660 -0
  267. sqlspec/builder/_temporal.cpython-310-aarch64-linux-gnu.so +0 -0
  268. sqlspec/builder/_temporal.py +139 -0
  269. sqlspec/builder/_update.cpython-310-aarch64-linux-gnu.so +0 -0
  270. sqlspec/builder/_update.py +173 -0
  271. sqlspec/builder/_vector_expressions.py +267 -0
  272. sqlspec/cli.py +911 -0
  273. sqlspec/config.py +1755 -0
  274. sqlspec/core/__init__.py +374 -0
  275. sqlspec/core/_correlation.cpython-310-aarch64-linux-gnu.so +0 -0
  276. sqlspec/core/_correlation.py +176 -0
  277. sqlspec/core/cache.cpython-310-aarch64-linux-gnu.so +0 -0
  278. sqlspec/core/cache.py +1069 -0
  279. sqlspec/core/compiler.cpython-310-aarch64-linux-gnu.so +0 -0
  280. sqlspec/core/compiler.py +954 -0
  281. sqlspec/core/explain.cpython-310-aarch64-linux-gnu.so +0 -0
  282. sqlspec/core/explain.py +275 -0
  283. sqlspec/core/filters.cpython-310-aarch64-linux-gnu.so +0 -0
  284. sqlspec/core/filters.py +952 -0
  285. sqlspec/core/hashing.cpython-310-aarch64-linux-gnu.so +0 -0
  286. sqlspec/core/hashing.py +262 -0
  287. sqlspec/core/metrics.cpython-310-aarch64-linux-gnu.so +0 -0
  288. sqlspec/core/metrics.py +83 -0
  289. sqlspec/core/parameters/__init__.py +71 -0
  290. sqlspec/core/parameters/_alignment.cpython-310-aarch64-linux-gnu.so +0 -0
  291. sqlspec/core/parameters/_alignment.py +270 -0
  292. sqlspec/core/parameters/_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  293. sqlspec/core/parameters/_converter.py +543 -0
  294. sqlspec/core/parameters/_processor.cpython-310-aarch64-linux-gnu.so +0 -0
  295. sqlspec/core/parameters/_processor.py +505 -0
  296. sqlspec/core/parameters/_registry.cpython-310-aarch64-linux-gnu.so +0 -0
  297. sqlspec/core/parameters/_registry.py +206 -0
  298. sqlspec/core/parameters/_transformers.cpython-310-aarch64-linux-gnu.so +0 -0
  299. sqlspec/core/parameters/_transformers.py +292 -0
  300. sqlspec/core/parameters/_types.cpython-310-aarch64-linux-gnu.so +0 -0
  301. sqlspec/core/parameters/_types.py +499 -0
  302. sqlspec/core/parameters/_validator.cpython-310-aarch64-linux-gnu.so +0 -0
  303. sqlspec/core/parameters/_validator.py +180 -0
  304. sqlspec/core/pipeline.cpython-310-aarch64-linux-gnu.so +0 -0
  305. sqlspec/core/pipeline.py +319 -0
  306. sqlspec/core/query_modifiers.cpython-310-aarch64-linux-gnu.so +0 -0
  307. sqlspec/core/query_modifiers.py +437 -0
  308. sqlspec/core/result/__init__.py +23 -0
  309. sqlspec/core/result/_base.cpython-310-aarch64-linux-gnu.so +0 -0
  310. sqlspec/core/result/_base.py +1121 -0
  311. sqlspec/core/result/_io.cpython-310-aarch64-linux-gnu.so +0 -0
  312. sqlspec/core/result/_io.py +28 -0
  313. sqlspec/core/splitter.cpython-310-aarch64-linux-gnu.so +0 -0
  314. sqlspec/core/splitter.py +966 -0
  315. sqlspec/core/stack.cpython-310-aarch64-linux-gnu.so +0 -0
  316. sqlspec/core/stack.py +163 -0
  317. sqlspec/core/statement.cpython-310-aarch64-linux-gnu.so +0 -0
  318. sqlspec/core/statement.py +1503 -0
  319. sqlspec/core/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  320. sqlspec/core/type_converter.py +339 -0
  321. sqlspec/data_dictionary/__init__.py +22 -0
  322. sqlspec/data_dictionary/_loader.py +123 -0
  323. sqlspec/data_dictionary/_registry.cpython-310-aarch64-linux-gnu.so +0 -0
  324. sqlspec/data_dictionary/_registry.py +74 -0
  325. sqlspec/data_dictionary/_types.cpython-310-aarch64-linux-gnu.so +0 -0
  326. sqlspec/data_dictionary/_types.py +121 -0
  327. sqlspec/data_dictionary/dialects/__init__.py +21 -0
  328. sqlspec/data_dictionary/dialects/bigquery.cpython-310-aarch64-linux-gnu.so +0 -0
  329. sqlspec/data_dictionary/dialects/bigquery.py +49 -0
  330. sqlspec/data_dictionary/dialects/cockroachdb.cpython-310-aarch64-linux-gnu.so +0 -0
  331. sqlspec/data_dictionary/dialects/cockroachdb.py +43 -0
  332. sqlspec/data_dictionary/dialects/duckdb.cpython-310-aarch64-linux-gnu.so +0 -0
  333. sqlspec/data_dictionary/dialects/duckdb.py +47 -0
  334. sqlspec/data_dictionary/dialects/mysql.cpython-310-aarch64-linux-gnu.so +0 -0
  335. sqlspec/data_dictionary/dialects/mysql.py +42 -0
  336. sqlspec/data_dictionary/dialects/oracle.cpython-310-aarch64-linux-gnu.so +0 -0
  337. sqlspec/data_dictionary/dialects/oracle.py +34 -0
  338. sqlspec/data_dictionary/dialects/postgres.cpython-310-aarch64-linux-gnu.so +0 -0
  339. sqlspec/data_dictionary/dialects/postgres.py +46 -0
  340. sqlspec/data_dictionary/dialects/spanner.cpython-310-aarch64-linux-gnu.so +0 -0
  341. sqlspec/data_dictionary/dialects/spanner.py +37 -0
  342. sqlspec/data_dictionary/dialects/sqlite.cpython-310-aarch64-linux-gnu.so +0 -0
  343. sqlspec/data_dictionary/dialects/sqlite.py +42 -0
  344. sqlspec/data_dictionary/sql/.gitkeep +0 -0
  345. sqlspec/data_dictionary/sql/bigquery/columns.sql +23 -0
  346. sqlspec/data_dictionary/sql/bigquery/foreign_keys.sql +34 -0
  347. sqlspec/data_dictionary/sql/bigquery/indexes.sql +19 -0
  348. sqlspec/data_dictionary/sql/bigquery/tables.sql +33 -0
  349. sqlspec/data_dictionary/sql/bigquery/version.sql +3 -0
  350. sqlspec/data_dictionary/sql/cockroachdb/columns.sql +34 -0
  351. sqlspec/data_dictionary/sql/cockroachdb/foreign_keys.sql +40 -0
  352. sqlspec/data_dictionary/sql/cockroachdb/indexes.sql +32 -0
  353. sqlspec/data_dictionary/sql/cockroachdb/tables.sql +44 -0
  354. sqlspec/data_dictionary/sql/cockroachdb/version.sql +3 -0
  355. sqlspec/data_dictionary/sql/duckdb/columns.sql +23 -0
  356. sqlspec/data_dictionary/sql/duckdb/foreign_keys.sql +36 -0
  357. sqlspec/data_dictionary/sql/duckdb/indexes.sql +19 -0
  358. sqlspec/data_dictionary/sql/duckdb/tables.sql +38 -0
  359. sqlspec/data_dictionary/sql/duckdb/version.sql +3 -0
  360. sqlspec/data_dictionary/sql/mysql/columns.sql +23 -0
  361. sqlspec/data_dictionary/sql/mysql/foreign_keys.sql +28 -0
  362. sqlspec/data_dictionary/sql/mysql/indexes.sql +26 -0
  363. sqlspec/data_dictionary/sql/mysql/tables.sql +33 -0
  364. sqlspec/data_dictionary/sql/mysql/version.sql +3 -0
  365. sqlspec/data_dictionary/sql/oracle/columns.sql +23 -0
  366. sqlspec/data_dictionary/sql/oracle/foreign_keys.sql +48 -0
  367. sqlspec/data_dictionary/sql/oracle/indexes.sql +44 -0
  368. sqlspec/data_dictionary/sql/oracle/tables.sql +25 -0
  369. sqlspec/data_dictionary/sql/oracle/version.sql +20 -0
  370. sqlspec/data_dictionary/sql/postgres/columns.sql +34 -0
  371. sqlspec/data_dictionary/sql/postgres/foreign_keys.sql +40 -0
  372. sqlspec/data_dictionary/sql/postgres/indexes.sql +56 -0
  373. sqlspec/data_dictionary/sql/postgres/tables.sql +44 -0
  374. sqlspec/data_dictionary/sql/postgres/version.sql +3 -0
  375. sqlspec/data_dictionary/sql/spanner/columns.sql +23 -0
  376. sqlspec/data_dictionary/sql/spanner/foreign_keys.sql +70 -0
  377. sqlspec/data_dictionary/sql/spanner/indexes.sql +30 -0
  378. sqlspec/data_dictionary/sql/spanner/tables.sql +9 -0
  379. sqlspec/data_dictionary/sql/spanner/version.sql +3 -0
  380. sqlspec/data_dictionary/sql/sqlite/columns.sql +23 -0
  381. sqlspec/data_dictionary/sql/sqlite/foreign_keys.sql +22 -0
  382. sqlspec/data_dictionary/sql/sqlite/indexes.sql +7 -0
  383. sqlspec/data_dictionary/sql/sqlite/tables.sql +28 -0
  384. sqlspec/data_dictionary/sql/sqlite/version.sql +3 -0
  385. sqlspec/driver/__init__.py +32 -0
  386. sqlspec/driver/_async.cpython-310-aarch64-linux-gnu.so +0 -0
  387. sqlspec/driver/_async.py +1737 -0
  388. sqlspec/driver/_common.cpython-310-aarch64-linux-gnu.so +0 -0
  389. sqlspec/driver/_common.py +1478 -0
  390. sqlspec/driver/_sql_helpers.cpython-310-aarch64-linux-gnu.so +0 -0
  391. sqlspec/driver/_sql_helpers.py +148 -0
  392. sqlspec/driver/_storage_helpers.cpython-310-aarch64-linux-gnu.so +0 -0
  393. sqlspec/driver/_storage_helpers.py +144 -0
  394. sqlspec/driver/_sync.cpython-310-aarch64-linux-gnu.so +0 -0
  395. sqlspec/driver/_sync.py +1710 -0
  396. sqlspec/exceptions.py +338 -0
  397. sqlspec/extensions/__init__.py +0 -0
  398. sqlspec/extensions/adk/__init__.py +70 -0
  399. sqlspec/extensions/adk/_types.py +51 -0
  400. sqlspec/extensions/adk/converters.py +172 -0
  401. sqlspec/extensions/adk/memory/__init__.py +69 -0
  402. sqlspec/extensions/adk/memory/_types.py +30 -0
  403. sqlspec/extensions/adk/memory/converters.py +149 -0
  404. sqlspec/extensions/adk/memory/service.py +217 -0
  405. sqlspec/extensions/adk/memory/store.py +569 -0
  406. sqlspec/extensions/adk/migrations/0001_create_adk_tables.py +246 -0
  407. sqlspec/extensions/adk/migrations/__init__.py +0 -0
  408. sqlspec/extensions/adk/service.py +225 -0
  409. sqlspec/extensions/adk/store.py +567 -0
  410. sqlspec/extensions/events/__init__.py +51 -0
  411. sqlspec/extensions/events/_channel.py +703 -0
  412. sqlspec/extensions/events/_hints.py +45 -0
  413. sqlspec/extensions/events/_models.py +23 -0
  414. sqlspec/extensions/events/_payload.py +69 -0
  415. sqlspec/extensions/events/_protocols.py +134 -0
  416. sqlspec/extensions/events/_queue.py +461 -0
  417. sqlspec/extensions/events/_store.py +209 -0
  418. sqlspec/extensions/events/migrations/0001_create_event_queue.py +59 -0
  419. sqlspec/extensions/events/migrations/__init__.py +3 -0
  420. sqlspec/extensions/fastapi/__init__.py +19 -0
  421. sqlspec/extensions/fastapi/extension.py +351 -0
  422. sqlspec/extensions/fastapi/providers.py +607 -0
  423. sqlspec/extensions/flask/__init__.py +37 -0
  424. sqlspec/extensions/flask/_state.py +76 -0
  425. sqlspec/extensions/flask/_utils.py +71 -0
  426. sqlspec/extensions/flask/extension.py +519 -0
  427. sqlspec/extensions/litestar/__init__.py +28 -0
  428. sqlspec/extensions/litestar/_utils.py +52 -0
  429. sqlspec/extensions/litestar/channels.py +165 -0
  430. sqlspec/extensions/litestar/cli.py +102 -0
  431. sqlspec/extensions/litestar/config.py +90 -0
  432. sqlspec/extensions/litestar/handlers.py +316 -0
  433. sqlspec/extensions/litestar/migrations/0001_create_session_table.py +137 -0
  434. sqlspec/extensions/litestar/migrations/__init__.py +3 -0
  435. sqlspec/extensions/litestar/plugin.py +671 -0
  436. sqlspec/extensions/litestar/providers.py +526 -0
  437. sqlspec/extensions/litestar/store.py +296 -0
  438. sqlspec/extensions/otel/__init__.py +58 -0
  439. sqlspec/extensions/prometheus/__init__.py +113 -0
  440. sqlspec/extensions/starlette/__init__.py +19 -0
  441. sqlspec/extensions/starlette/_state.py +30 -0
  442. sqlspec/extensions/starlette/_utils.py +96 -0
  443. sqlspec/extensions/starlette/extension.py +346 -0
  444. sqlspec/extensions/starlette/middleware.py +235 -0
  445. sqlspec/loader.cpython-310-aarch64-linux-gnu.so +0 -0
  446. sqlspec/loader.py +702 -0
  447. sqlspec/migrations/__init__.py +36 -0
  448. sqlspec/migrations/base.py +731 -0
  449. sqlspec/migrations/commands.py +1232 -0
  450. sqlspec/migrations/context.py +157 -0
  451. sqlspec/migrations/fix.py +204 -0
  452. sqlspec/migrations/loaders.py +443 -0
  453. sqlspec/migrations/runner.py +1172 -0
  454. sqlspec/migrations/templates.py +234 -0
  455. sqlspec/migrations/tracker.py +611 -0
  456. sqlspec/migrations/utils.py +256 -0
  457. sqlspec/migrations/validation.py +207 -0
  458. sqlspec/migrations/version.py +446 -0
  459. sqlspec/observability/__init__.py +55 -0
  460. sqlspec/observability/_common.cpython-310-aarch64-linux-gnu.so +0 -0
  461. sqlspec/observability/_common.py +77 -0
  462. sqlspec/observability/_config.cpython-310-aarch64-linux-gnu.so +0 -0
  463. sqlspec/observability/_config.py +348 -0
  464. sqlspec/observability/_diagnostics.cpython-310-aarch64-linux-gnu.so +0 -0
  465. sqlspec/observability/_diagnostics.py +74 -0
  466. sqlspec/observability/_dispatcher.cpython-310-aarch64-linux-gnu.so +0 -0
  467. sqlspec/observability/_dispatcher.py +152 -0
  468. sqlspec/observability/_formatters/__init__.py +13 -0
  469. sqlspec/observability/_formatters/_aws.cpython-310-aarch64-linux-gnu.so +0 -0
  470. sqlspec/observability/_formatters/_aws.py +102 -0
  471. sqlspec/observability/_formatters/_azure.cpython-310-aarch64-linux-gnu.so +0 -0
  472. sqlspec/observability/_formatters/_azure.py +96 -0
  473. sqlspec/observability/_formatters/_base.cpython-310-aarch64-linux-gnu.so +0 -0
  474. sqlspec/observability/_formatters/_base.py +57 -0
  475. sqlspec/observability/_formatters/_gcp.cpython-310-aarch64-linux-gnu.so +0 -0
  476. sqlspec/observability/_formatters/_gcp.py +131 -0
  477. sqlspec/observability/_formatting.py +58 -0
  478. sqlspec/observability/_observer.cpython-310-aarch64-linux-gnu.so +0 -0
  479. sqlspec/observability/_observer.py +357 -0
  480. sqlspec/observability/_runtime.cpython-310-aarch64-linux-gnu.so +0 -0
  481. sqlspec/observability/_runtime.py +420 -0
  482. sqlspec/observability/_sampling.cpython-310-aarch64-linux-gnu.so +0 -0
  483. sqlspec/observability/_sampling.py +188 -0
  484. sqlspec/observability/_spans.cpython-310-aarch64-linux-gnu.so +0 -0
  485. sqlspec/observability/_spans.py +161 -0
  486. sqlspec/protocols.py +916 -0
  487. sqlspec/py.typed +0 -0
  488. sqlspec/storage/__init__.py +48 -0
  489. sqlspec/storage/_utils.py +104 -0
  490. sqlspec/storage/backends/__init__.py +1 -0
  491. sqlspec/storage/backends/base.py +253 -0
  492. sqlspec/storage/backends/fsspec.py +529 -0
  493. sqlspec/storage/backends/local.py +441 -0
  494. sqlspec/storage/backends/obstore.py +916 -0
  495. sqlspec/storage/errors.py +104 -0
  496. sqlspec/storage/pipeline.py +582 -0
  497. sqlspec/storage/registry.py +301 -0
  498. sqlspec/typing.py +395 -0
  499. sqlspec/utils/__init__.py +7 -0
  500. sqlspec/utils/arrow_helpers.py +318 -0
  501. sqlspec/utils/config_tools.py +332 -0
  502. sqlspec/utils/correlation.cpython-310-aarch64-linux-gnu.so +0 -0
  503. sqlspec/utils/correlation.py +134 -0
  504. sqlspec/utils/deprecation.py +190 -0
  505. sqlspec/utils/fixtures.cpython-310-aarch64-linux-gnu.so +0 -0
  506. sqlspec/utils/fixtures.py +258 -0
  507. sqlspec/utils/logging.py +222 -0
  508. sqlspec/utils/module_loader.py +306 -0
  509. sqlspec/utils/portal.cpython-310-aarch64-linux-gnu.so +0 -0
  510. sqlspec/utils/portal.py +375 -0
  511. sqlspec/utils/schema.cpython-310-aarch64-linux-gnu.so +0 -0
  512. sqlspec/utils/schema.py +485 -0
  513. sqlspec/utils/serializers.cpython-310-aarch64-linux-gnu.so +0 -0
  514. sqlspec/utils/serializers.py +408 -0
  515. sqlspec/utils/singleton.cpython-310-aarch64-linux-gnu.so +0 -0
  516. sqlspec/utils/singleton.py +41 -0
  517. sqlspec/utils/sync_tools.cpython-310-aarch64-linux-gnu.so +0 -0
  518. sqlspec/utils/sync_tools.py +311 -0
  519. sqlspec/utils/text.cpython-310-aarch64-linux-gnu.so +0 -0
  520. sqlspec/utils/text.py +108 -0
  521. sqlspec/utils/type_converters.cpython-310-aarch64-linux-gnu.so +0 -0
  522. sqlspec/utils/type_converters.py +128 -0
  523. sqlspec/utils/type_guards.cpython-310-aarch64-linux-gnu.so +0 -0
  524. sqlspec/utils/type_guards.py +1360 -0
  525. sqlspec/utils/uuids.cpython-310-aarch64-linux-gnu.so +0 -0
  526. sqlspec/utils/uuids.py +225 -0
  527. sqlspec-0.36.0.dist-info/METADATA +205 -0
  528. sqlspec-0.36.0.dist-info/RECORD +531 -0
  529. sqlspec-0.36.0.dist-info/WHEEL +7 -0
  530. sqlspec-0.36.0.dist-info/entry_points.txt +2 -0
  531. sqlspec-0.36.0.dist-info/licenses/LICENSE +21 -0
sqlspec/loader.py ADDED
@@ -0,0 +1,702 @@
1
+ """SQL file loader for managing SQL statements from files.
2
+
3
+ Provides functionality to load, cache, and manage SQL statements
4
+ from files using named SQL queries.
5
+
6
+ SQL files declare query metadata with comment directives like ``-- name: query_name`` (hyphens and suffixes allowed)
7
+ and ``-- dialect: dialect_name``.
8
+ """
9
+
10
+ import hashlib
11
+ import logging
12
+ import re
13
+ import time
14
+ from datetime import datetime, timezone
15
+ from pathlib import Path
16
+ from typing import TYPE_CHECKING, Any, Final
17
+ from urllib.parse import unquote, urlparse
18
+
19
+ from sqlspec.core import SQL, get_cache, get_cache_config
20
+ from sqlspec.exceptions import (
21
+ FileNotFoundInStorageError,
22
+ SQLFileNotFoundError,
23
+ SQLFileParseError,
24
+ StorageOperationFailedError,
25
+ )
26
+ from sqlspec.storage.registry import storage_registry as default_storage_registry
27
+ from sqlspec.utils.correlation import CorrelationContext
28
+ from sqlspec.utils.logging import get_logger, log_with_context
29
+ from sqlspec.utils.text import slugify
30
+
31
+ if TYPE_CHECKING:
32
+ from sqlspec.observability import ObservabilityRuntime
33
+ from sqlspec.storage.registry import StorageRegistry
34
+
35
+ __all__ = ("NamedStatement", "SQLFile", "SQLFileCacheEntry", "SQLFileLoader")
36
+
37
+ logger = get_logger("sqlspec.loader")
38
+
39
+ QUERY_NAME_PATTERN = re.compile(r"^\s*--\s*name\s*:\s*([\w-]+[^\w\s]*)\s*$", re.MULTILINE | re.IGNORECASE)
40
+ TRIM_SPECIAL_CHARS = re.compile(r"[^\w.-]")
41
+
42
+ DIALECT_PATTERN = re.compile(r"^\s*--\s*dialect\s*:\s*(?P<dialect>[a-zA-Z0-9_]+)\s*$", re.IGNORECASE | re.MULTILINE)
43
+
44
+
45
+ DIALECT_ALIASES: Final = {
46
+ "postgresql": "postgres",
47
+ "pg": "postgres",
48
+ "pgplsql": "postgres",
49
+ "plsql": "oracle",
50
+ "oracledb": "oracle",
51
+ "tsql": "mssql",
52
+ }
53
+
54
+ MIN_QUERY_PARTS: Final = 3
55
+
56
+
57
+ def _normalize_query_name(name: str) -> str:
58
+ """Normalize query name to be a valid Python identifier.
59
+
60
+ Convert hyphens to underscores, preserve dots for namespacing,
61
+ and remove invalid characters.
62
+
63
+ Args:
64
+ name: Raw query name from SQL file.
65
+
66
+ Returns:
67
+ Normalized query name suitable as Python identifier.
68
+ """
69
+ parts = name.split(".")
70
+ normalized_parts = []
71
+
72
+ for part in parts:
73
+ normalized_part = slugify(part, separator="_")
74
+ normalized_parts.append(normalized_part)
75
+
76
+ return ".".join(normalized_parts)
77
+
78
+
79
+ def _normalize_dialect(dialect: str) -> str:
80
+ """Normalize dialect name with aliases.
81
+
82
+ Args:
83
+ dialect: Raw dialect name from SQL file.
84
+
85
+ Returns:
86
+ Normalized dialect name.
87
+ """
88
+ normalized = dialect.lower().strip()
89
+ return DIALECT_ALIASES.get(normalized, normalized)
90
+
91
+
92
+ class NamedStatement:
93
+ """Represents a parsed SQL statement with metadata.
94
+
95
+ Contains individual SQL statements extracted from files with their
96
+ normalized names, SQL content, optional dialect specifications,
97
+ and line position for error reporting.
98
+ """
99
+
100
+ __slots__ = ("dialect", "name", "sql", "start_line")
101
+
102
+ def __init__(self, name: str, sql: str, dialect: "str | None" = None, start_line: int = 0) -> None:
103
+ self.name = name
104
+ self.sql = sql
105
+ self.dialect = dialect
106
+ self.start_line = start_line
107
+
108
+
109
+ class SQLFile:
110
+ """Represents a loaded SQL file with metadata.
111
+
112
+ Contains SQL content and associated metadata including file location,
113
+ timestamps, and content hash.
114
+ """
115
+
116
+ __slots__ = ("checksum", "content", "loaded_at", "metadata", "path")
117
+
118
+ def __init__(
119
+ self, content: str, path: str, metadata: "dict[str, Any] | None" = None, loaded_at: "datetime | None" = None
120
+ ) -> None:
121
+ """Initialize SQLFile.
122
+
123
+ Args:
124
+ content: Raw SQL content from the file.
125
+ path: Path where the SQL file was loaded from.
126
+ metadata: Optional metadata associated with the SQL file.
127
+ loaded_at: Timestamp when the file was loaded.
128
+ """
129
+ self.content = content
130
+ self.path = path
131
+ self.metadata = metadata or {}
132
+ self.loaded_at = loaded_at or datetime.now(timezone.utc)
133
+ self.checksum = hashlib.md5(self.content.encode(), usedforsecurity=False).hexdigest()
134
+
135
+
136
+ class SQLFileCacheEntry:
137
+ """Cached SQL file with parsed statements.
138
+
139
+ Stored in the file cache to avoid re-parsing SQL files when their
140
+ content hasn't changed.
141
+ """
142
+
143
+ __slots__ = ("parsed_statements", "sql_file", "statement_names")
144
+
145
+ def __init__(self, sql_file: SQLFile, parsed_statements: "dict[str, NamedStatement]") -> None:
146
+ """Initialize cached SQL file.
147
+
148
+ Args:
149
+ sql_file: Original SQLFile with content and metadata.
150
+ parsed_statements: Named statements from the file.
151
+ """
152
+ self.sql_file = sql_file
153
+ self.parsed_statements = parsed_statements
154
+ self.statement_names = tuple(parsed_statements.keys())
155
+
156
+
157
+ class SQLFileLoader:
158
+ """Loads and parses SQL files with named SQL queries.
159
+
160
+ Loads SQL files containing named queries (using -- name: syntax)
161
+ and retrieves them by name.
162
+ """
163
+
164
+ __slots__ = ("_files", "_queries", "_query_to_file", "_runtime", "encoding", "storage_registry")
165
+
166
+ def __init__(
167
+ self,
168
+ *,
169
+ encoding: str = "utf-8",
170
+ storage_registry: "StorageRegistry | None" = None,
171
+ runtime: "ObservabilityRuntime | None" = None,
172
+ ) -> None:
173
+ """Initialize the SQL file loader.
174
+
175
+ Args:
176
+ encoding: Text encoding for reading SQL files.
177
+ storage_registry: Storage registry for handling file URIs.
178
+ runtime: Observability runtime for instrumentation.
179
+ """
180
+ self.encoding = encoding
181
+
182
+ self.storage_registry = storage_registry or default_storage_registry
183
+ self._queries: dict[str, NamedStatement] = {}
184
+ self._files: dict[str, SQLFile] = {}
185
+ self._query_to_file: dict[str, str] = {}
186
+ self._runtime = runtime
187
+
188
+ def set_observability_runtime(self, runtime: "ObservabilityRuntime | None") -> None:
189
+ """Attach an observability runtime used for instrumentation."""
190
+
191
+ self._runtime = runtime
192
+
193
+ def _metric(self, name: str, amount: float = 1.0) -> None:
194
+ if self._runtime is not None:
195
+ self._runtime.increment_metric(name, amount)
196
+
197
+ def _raise_file_not_found(self, path: str) -> None:
198
+ """Raise SQLFileNotFoundError for nonexistent file.
199
+
200
+ Args:
201
+ path: File path that was not found.
202
+
203
+ Raises:
204
+ SQLFileNotFoundError: Always raised.
205
+ """
206
+ raise SQLFileNotFoundError(path)
207
+
208
+ def _generate_file_cache_key(self, path: str | Path) -> str:
209
+ """Generate cache key for a file path.
210
+
211
+ Args:
212
+ path: File path to generate key for.
213
+
214
+ Returns:
215
+ Cache key string for the file.
216
+ """
217
+ path_str = str(path)
218
+ path_hash = hashlib.md5(path_str.encode(), usedforsecurity=False).hexdigest()
219
+ return f"file:{path_hash[:16]}"
220
+
221
+ def _calculate_file_checksum(self, path: str | Path) -> str:
222
+ """Calculate checksum for file content validation.
223
+
224
+ Args:
225
+ path: File path to calculate checksum for.
226
+
227
+ Returns:
228
+ MD5 checksum of file content.
229
+
230
+ Raises:
231
+ SQLFileParseError: If file cannot be read.
232
+ """
233
+ try:
234
+ return hashlib.md5(self._read_file_content(path).encode(), usedforsecurity=False).hexdigest()
235
+ except Exception as e:
236
+ raise SQLFileParseError(str(path), str(path), e) from e
237
+
238
+ def _is_file_unchanged(self, path: str | Path, cached_file: SQLFileCacheEntry) -> bool:
239
+ """Check if file has changed since caching.
240
+
241
+ Args:
242
+ path: File path to check.
243
+ cached_file: Cached file data.
244
+
245
+ Returns:
246
+ True if file is unchanged, False otherwise.
247
+ """
248
+ try:
249
+ current_checksum = self._calculate_file_checksum(path)
250
+ except Exception:
251
+ return False
252
+ else:
253
+ return current_checksum == cached_file.sql_file.checksum
254
+
255
+ def _read_file_content(self, path: str | Path) -> str:
256
+ """Read file content using storage backend.
257
+
258
+ Args:
259
+ path: File path (can be local path or URI).
260
+
261
+ Returns:
262
+ File content as string.
263
+
264
+ Raises:
265
+ SQLFileNotFoundError: If file does not exist.
266
+ SQLFileParseError: If file cannot be read or parsed.
267
+
268
+ Notes:
269
+ File:// URIs are normalized before delegation to the backend, including trimming Windows-style leading slashes so filenames resolve correctly.
270
+ """
271
+ path_str = str(path)
272
+
273
+ try:
274
+ backend = self.storage_registry.get(path)
275
+ if path_str.startswith("file://"):
276
+ parsed = urlparse(path_str)
277
+ file_path = unquote(parsed.path)
278
+ if file_path and len(file_path) > 2 and file_path[2] == ":": # noqa: PLR2004
279
+ file_path = file_path[1:]
280
+ filename = Path(file_path).name
281
+ return backend.read_text(filename, encoding=self.encoding)
282
+ return backend.read_text(path_str, encoding=self.encoding)
283
+ except KeyError as e:
284
+ raise SQLFileNotFoundError(path_str) from e
285
+ except FileNotFoundInStorageError as e:
286
+ raise SQLFileNotFoundError(path_str) from e
287
+ except FileNotFoundError as e:
288
+ raise SQLFileNotFoundError(path_str) from e
289
+ except StorageOperationFailedError as e:
290
+ raise SQLFileParseError(path_str, path_str, e) from e
291
+ except Exception as e:
292
+ raise SQLFileParseError(path_str, path_str, e) from e
293
+
294
+ @staticmethod
295
+ def _strip_leading_comments(sql_text: str) -> str:
296
+ """Remove leading comment lines from a SQL string."""
297
+ lines = sql_text.strip().split("\n")
298
+ first_sql_line_index = -1
299
+ for i, line in enumerate(lines):
300
+ if line.strip() and not line.strip().startswith("--"):
301
+ first_sql_line_index = i
302
+ break
303
+ if first_sql_line_index == -1:
304
+ return ""
305
+ return "\n".join(lines[first_sql_line_index:]).strip()
306
+
307
+ @staticmethod
308
+ def _parse_sql_content(content: str, file_path: str) -> "dict[str, NamedStatement]":
309
+ """Parse SQL content and extract named statements with dialect specifications.
310
+
311
+ Files without any named statement markers are gracefully skipped by returning
312
+ an empty dictionary. The caller is responsible for handling empty results
313
+ appropriately.
314
+
315
+ Args:
316
+ content: Raw SQL file content to parse.
317
+ file_path: File path for error reporting.
318
+
319
+ Returns:
320
+ Dictionary mapping normalized statement names to NamedStatement objects.
321
+ Empty dict if no named statement markers found in the content.
322
+
323
+ Raises:
324
+ SQLFileParseError: If named statements are malformed (duplicate names or
325
+ invalid content after parsing).
326
+ """
327
+ statements: dict[str, NamedStatement] = {}
328
+
329
+ name_matches = list(QUERY_NAME_PATTERN.finditer(content))
330
+ if not name_matches:
331
+ return {}
332
+
333
+ for i, match in enumerate(name_matches):
334
+ raw_statement_name = match.group(1).strip()
335
+ statement_start_line = content[: match.start()].count("\n")
336
+
337
+ start_pos = match.end()
338
+ end_pos = name_matches[i + 1].start() if i + 1 < len(name_matches) else len(content)
339
+
340
+ statement_section = content[start_pos:end_pos].strip()
341
+ if not raw_statement_name or not statement_section:
342
+ continue
343
+
344
+ dialect = None
345
+ statement_sql = statement_section
346
+
347
+ section_lines = [line.strip() for line in statement_section.split("\n") if line.strip()]
348
+ if section_lines:
349
+ first_line = section_lines[0]
350
+ dialect_match = DIALECT_PATTERN.match(first_line)
351
+ if dialect_match:
352
+ declared_dialect = dialect_match.group("dialect").lower()
353
+
354
+ dialect = _normalize_dialect(declared_dialect)
355
+ remaining_lines = section_lines[1:]
356
+ statement_sql = "\n".join(remaining_lines)
357
+
358
+ clean_sql = SQLFileLoader._strip_leading_comments(statement_sql)
359
+ if clean_sql:
360
+ normalized_name = _normalize_query_name(raw_statement_name)
361
+ if normalized_name in statements:
362
+ raise SQLFileParseError(
363
+ file_path, file_path, ValueError(f"Duplicate statement name: {raw_statement_name}")
364
+ )
365
+
366
+ statements[normalized_name] = NamedStatement(
367
+ name=normalized_name, sql=clean_sql, dialect=dialect, start_line=statement_start_line
368
+ )
369
+ log_with_context(
370
+ logger, logging.DEBUG, "sql.parse", file_path=file_path, query_name=normalized_name, dialect=dialect
371
+ )
372
+
373
+ if not statements:
374
+ raise SQLFileParseError(file_path, file_path, ValueError("No valid SQL statements found after parsing"))
375
+
376
+ return statements
377
+
378
+ def load_sql(self, *paths: str | Path) -> None:
379
+ """Load SQL files and parse named queries.
380
+
381
+ Args:
382
+ *paths: One or more file paths or directory paths to load.
383
+ """
384
+ runtime = self._runtime
385
+ span = None
386
+ error: Exception | None = None
387
+ start_time = time.perf_counter()
388
+ path_count = len(paths)
389
+ previous_correlation_id = CorrelationContext.get()
390
+ if runtime is not None:
391
+ runtime.increment_metric("loader.load.invocations")
392
+ runtime.increment_metric("loader.paths.requested", path_count)
393
+ span = runtime.start_span(
394
+ "sqlspec.loader.load",
395
+ attributes={"sqlspec.loader.path_count": path_count, "sqlspec.loader.encoding": self.encoding},
396
+ )
397
+
398
+ try:
399
+ for path in paths:
400
+ path_str = str(path)
401
+ if "://" in path_str:
402
+ self._load_single_file(path, None)
403
+ else:
404
+ path_obj = Path(path)
405
+ if path_obj.is_dir():
406
+ self._load_directory(path_obj)
407
+ elif path_obj.exists():
408
+ self._load_single_file(path_obj, None)
409
+ elif path_obj.suffix:
410
+ self._raise_file_not_found(str(path))
411
+
412
+ except Exception as exc:
413
+ error = exc
414
+ if runtime is not None:
415
+ runtime.increment_metric("loader.load.errors")
416
+ raise
417
+ finally:
418
+ duration_ms = (time.perf_counter() - start_time) * 1000
419
+ if runtime is not None:
420
+ runtime.record_metric("loader.last_load_ms", duration_ms)
421
+ runtime.increment_metric("loader.load.duration_ms", duration_ms)
422
+ runtime.end_span(span, error=error)
423
+ CorrelationContext.set(previous_correlation_id)
424
+
425
+ def _load_directory(self, dir_path: Path) -> None:
426
+ """Load all SQL files from a directory.
427
+
428
+ Args:
429
+ dir_path: Directory path to load SQL files from.
430
+ """
431
+ runtime = self._runtime
432
+ if runtime is not None:
433
+ runtime.increment_metric("loader.directories.scanned")
434
+
435
+ sql_files = list(dir_path.rglob("*.sql"))
436
+ if not sql_files:
437
+ return
438
+
439
+ for file_path in sql_files:
440
+ relative_path = file_path.relative_to(dir_path)
441
+ namespace_parts = relative_path.parent.parts
442
+ self._load_single_file(file_path, ".".join(namespace_parts) if namespace_parts else None)
443
+
444
+ def _load_single_file(self, file_path: str | Path, namespace: str | None) -> bool:
445
+ """Load a single SQL file with optional namespace.
446
+
447
+ Args:
448
+ file_path: Path to the SQL file.
449
+ namespace: Optional namespace prefix for queries.
450
+
451
+ Returns:
452
+ True if file was newly loaded, False if already cached.
453
+ """
454
+ path_str = str(file_path)
455
+ runtime = self._runtime
456
+ if runtime is not None:
457
+ runtime.increment_metric("loader.files.considered")
458
+
459
+ if path_str in self._files:
460
+ if runtime is not None:
461
+ runtime.increment_metric("loader.cache.hit")
462
+ return False
463
+
464
+ cache_config = get_cache_config()
465
+ if not cache_config.compiled_cache_enabled:
466
+ self._load_file_without_cache(file_path, namespace)
467
+ if runtime is not None:
468
+ runtime.increment_metric("loader.cache.miss")
469
+ return True
470
+
471
+ cache_key_str = self._generate_file_cache_key(file_path)
472
+ cache = get_cache()
473
+ cached_file = cache.get_file(cache_key_str)
474
+
475
+ if (
476
+ cached_file is not None
477
+ and isinstance(cached_file, SQLFileCacheEntry)
478
+ and self._is_file_unchanged(file_path, cached_file)
479
+ ):
480
+ self._files[path_str] = cached_file.sql_file
481
+ for name, statement in cached_file.parsed_statements.items():
482
+ namespaced_name = f"{namespace}.{name}" if namespace else name
483
+ if namespaced_name in self._queries:
484
+ existing_file = self._query_to_file.get(namespaced_name, "unknown")
485
+ if existing_file != path_str:
486
+ raise SQLFileParseError(
487
+ path_str,
488
+ path_str,
489
+ ValueError(f"Query name '{namespaced_name}' already exists in file: {existing_file}"),
490
+ )
491
+ self._queries[namespaced_name] = statement
492
+ self._query_to_file[namespaced_name] = path_str
493
+ if runtime is not None:
494
+ runtime.increment_metric("loader.cache.hit")
495
+ return True
496
+
497
+ self._load_file_without_cache(file_path, namespace)
498
+
499
+ if path_str in self._files:
500
+ sql_file = self._files[path_str]
501
+ file_statements: dict[str, NamedStatement] = {}
502
+ for query_name, query_path in self._query_to_file.items():
503
+ if query_path == path_str:
504
+ stored_name = query_name
505
+ if namespace and query_name.startswith(f"{namespace}."):
506
+ stored_name = query_name[len(namespace) + 1 :]
507
+ file_statements[stored_name] = self._queries[query_name]
508
+
509
+ cached_file_data = SQLFileCacheEntry(sql_file=sql_file, parsed_statements=file_statements)
510
+ cache.put_file(cache_key_str, cached_file_data)
511
+ if runtime is not None:
512
+ runtime.increment_metric("loader.cache.miss")
513
+ runtime.increment_metric("loader.files.loaded")
514
+ runtime.increment_metric("loader.statements.loaded", len(file_statements))
515
+
516
+ return True
517
+
518
+ def _load_file_without_cache(self, file_path: str | Path, namespace: str | None) -> None:
519
+ """Load a single SQL file without using cache.
520
+
521
+ Args:
522
+ file_path: Path to the SQL file.
523
+ namespace: Optional namespace prefix for queries.
524
+ """
525
+ path_str = str(file_path)
526
+ runtime = self._runtime
527
+ content = self._read_file_content(file_path)
528
+ statements = self._parse_sql_content(content, path_str)
529
+
530
+ if not statements:
531
+ log_with_context(
532
+ logger, logging.DEBUG, "sql.load", file_path=path_str, status="skipped", reason="no_named_statements"
533
+ )
534
+ return
535
+
536
+ sql_file = SQLFile(content=content, path=path_str)
537
+ self._files[path_str] = sql_file
538
+
539
+ for name, statement in statements.items():
540
+ namespaced_name = f"{namespace}.{name}" if namespace else name
541
+ if namespaced_name in self._queries:
542
+ existing_file = self._query_to_file.get(namespaced_name, "unknown")
543
+ if existing_file != path_str:
544
+ raise SQLFileParseError(
545
+ path_str,
546
+ path_str,
547
+ ValueError(f"Query name '{namespaced_name}' already exists in file: {existing_file}"),
548
+ )
549
+ self._queries[namespaced_name] = statement
550
+ self._query_to_file[namespaced_name] = path_str
551
+ log_with_context(
552
+ logger, logging.DEBUG, "sql.load", file_path=path_str, statement_count=len(statements), status="loaded"
553
+ )
554
+ if runtime is not None:
555
+ runtime.increment_metric("loader.files.loaded")
556
+ runtime.increment_metric("loader.statements.loaded", len(statements))
557
+
558
+ def add_named_sql(self, name: str, sql: str, dialect: "str | None" = None) -> None:
559
+ """Add a named SQL query directly without loading from a file.
560
+
561
+ Args:
562
+ name: Name for the SQL query.
563
+ sql: Raw SQL content.
564
+ dialect: Optional dialect for the SQL statement.
565
+
566
+ Raises:
567
+ ValueError: If query name already exists.
568
+ """
569
+
570
+ normalized_name = _normalize_query_name(name)
571
+
572
+ if normalized_name in self._queries:
573
+ existing_source = self._query_to_file.get(normalized_name, "<directly added>")
574
+ msg = f"Query name '{name}' already exists (source: {existing_source})"
575
+ raise ValueError(msg)
576
+
577
+ if dialect is not None:
578
+ dialect = _normalize_dialect(dialect)
579
+
580
+ statement = NamedStatement(name=normalized_name, sql=sql.strip(), dialect=dialect, start_line=0)
581
+ self._queries[normalized_name] = statement
582
+ self._query_to_file[normalized_name] = "<directly added>"
583
+
584
+ def get_file(self, path: str | Path) -> "SQLFile | None":
585
+ """Get a loaded SQLFile object by path.
586
+
587
+ Args:
588
+ path: Path of the file.
589
+
590
+ Returns:
591
+ SQLFile object if loaded, None otherwise.
592
+ """
593
+ return self._files.get(str(path))
594
+
595
+ def get_file_for_query(self, name: str) -> "SQLFile | None":
596
+ """Get the SQLFile object containing a query.
597
+
598
+ Args:
599
+ name: Query name (hyphens are converted to underscores).
600
+
601
+ Returns:
602
+ SQLFile object if query exists, None otherwise.
603
+ """
604
+ safe_name = _normalize_query_name(name)
605
+ if safe_name in self._query_to_file:
606
+ file_path = self._query_to_file[safe_name]
607
+ return self._files.get(file_path)
608
+ return None
609
+
610
+ def list_queries(self) -> "list[str]":
611
+ """List all available query names.
612
+
613
+ Returns:
614
+ Sorted list of query names.
615
+ """
616
+ return sorted(self._queries.keys())
617
+
618
+ def list_files(self) -> "list[str]":
619
+ """List all loaded file paths.
620
+
621
+ Returns:
622
+ Sorted list of file paths.
623
+ """
624
+ return sorted(self._files.keys())
625
+
626
+ def has_query(self, name: str) -> bool:
627
+ """Check if a query exists.
628
+
629
+ Args:
630
+ name: Query name to check.
631
+
632
+ Returns:
633
+ True if query exists.
634
+ """
635
+ safe_name = _normalize_query_name(name)
636
+ return safe_name in self._queries
637
+
638
+ def clear_cache(self) -> None:
639
+ """Clear all cached files and queries."""
640
+ self._files.clear()
641
+ self._queries.clear()
642
+ self._query_to_file.clear()
643
+
644
+ cache_config = get_cache_config()
645
+ if cache_config.compiled_cache_enabled:
646
+ cache = get_cache()
647
+ cache.clear()
648
+
649
+ def clear_file_cache(self) -> None:
650
+ """Clear the file cache only, keeping loaded queries."""
651
+ cache_config = get_cache_config()
652
+ if cache_config.compiled_cache_enabled:
653
+ cache = get_cache()
654
+ cache.clear()
655
+
656
+ def get_query_text(self, name: str) -> str:
657
+ """Get raw SQL text for a query.
658
+
659
+ Args:
660
+ name: Query name.
661
+
662
+ Returns:
663
+ Raw SQL text.
664
+
665
+ Raises:
666
+ SQLFileNotFoundError: If query not found.
667
+ """
668
+ safe_name = _normalize_query_name(name)
669
+ if safe_name not in self._queries:
670
+ raise SQLFileNotFoundError(name)
671
+ return self._queries[safe_name].sql
672
+
673
+ def get_sql(self, name: str) -> "SQL":
674
+ """Get a SQL object by statement name.
675
+
676
+ Args:
677
+ name: Name of the statement (from -- name: in SQL file).
678
+ Hyphens in names are converted to underscores.
679
+
680
+ Returns:
681
+ SQL object ready for execution.
682
+
683
+ Raises:
684
+ SQLFileNotFoundError: If statement name not found.
685
+ """
686
+ safe_name = _normalize_query_name(name)
687
+
688
+ if safe_name not in self._queries:
689
+ available = ", ".join(sorted(self._queries.keys())) if self._queries else "none"
690
+ raise SQLFileNotFoundError(name, path=f"Statement '{name}' not found. Available statements: {available}")
691
+
692
+ parsed_statement = self._queries[safe_name]
693
+ sqlglot_dialect = None
694
+ if parsed_statement.dialect:
695
+ sqlglot_dialect = _normalize_dialect(parsed_statement.dialect)
696
+
697
+ sql = SQL(parsed_statement.sql, dialect=sqlglot_dialect)
698
+ try:
699
+ sql.compile()
700
+ except Exception as exc:
701
+ raise SQLFileParseError(name=name, path="<statement>", original_error=exc) from exc
702
+ return sql