sqlspec 0.47.0__cp314-cp314-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (621) hide show
  1. f68e0789eb443ecb1c2c__mypyc.cp314-win_amd64.pyd +0 -0
  2. sqlspec/__init__.py +167 -0
  3. sqlspec/__main__.py +12 -0
  4. sqlspec/__metadata__.py +14 -0
  5. sqlspec/_typing.py +714 -0
  6. sqlspec/adapters/__init__.py +0 -0
  7. sqlspec/adapters/adbc/__init__.py +13 -0
  8. sqlspec/adapters/adbc/_typing.py +106 -0
  9. sqlspec/adapters/adbc/adk/__init__.py +5 -0
  10. sqlspec/adapters/adbc/adk/store.py +1280 -0
  11. sqlspec/adapters/adbc/config.py +378 -0
  12. sqlspec/adapters/adbc/core.cp314-win_amd64.pyd +0 -0
  13. sqlspec/adapters/adbc/core.py +922 -0
  14. sqlspec/adapters/adbc/data_dictionary.py +339 -0
  15. sqlspec/adapters/adbc/driver.py +534 -0
  16. sqlspec/adapters/adbc/events/__init__.py +5 -0
  17. sqlspec/adapters/adbc/events/store.py +285 -0
  18. sqlspec/adapters/adbc/litestar/__init__.py +5 -0
  19. sqlspec/adapters/adbc/litestar/store.py +534 -0
  20. sqlspec/adapters/adbc/type_converter.cp314-win_amd64.pyd +0 -0
  21. sqlspec/adapters/adbc/type_converter.py +142 -0
  22. sqlspec/adapters/aiomysql/__init__.py +21 -0
  23. sqlspec/adapters/aiomysql/_typing.py +137 -0
  24. sqlspec/adapters/aiomysql/adk/__init__.py +5 -0
  25. sqlspec/adapters/aiomysql/adk/store.py +678 -0
  26. sqlspec/adapters/aiomysql/config.py +305 -0
  27. sqlspec/adapters/aiomysql/core.cp314-win_amd64.pyd +0 -0
  28. sqlspec/adapters/aiomysql/core.py +536 -0
  29. sqlspec/adapters/aiomysql/data_dictionary.py +121 -0
  30. sqlspec/adapters/aiomysql/driver.py +386 -0
  31. sqlspec/adapters/aiomysql/events/__init__.py +5 -0
  32. sqlspec/adapters/aiomysql/events/store.py +104 -0
  33. sqlspec/adapters/aiomysql/litestar/__init__.py +5 -0
  34. sqlspec/adapters/aiomysql/litestar/store.py +314 -0
  35. sqlspec/adapters/aiosqlite/__init__.py +26 -0
  36. sqlspec/adapters/aiosqlite/_typing.py +109 -0
  37. sqlspec/adapters/aiosqlite/adk/__init__.py +5 -0
  38. sqlspec/adapters/aiosqlite/adk/store.py +829 -0
  39. sqlspec/adapters/aiosqlite/config.py +315 -0
  40. sqlspec/adapters/aiosqlite/core.cp314-win_amd64.pyd +0 -0
  41. sqlspec/adapters/aiosqlite/core.py +315 -0
  42. sqlspec/adapters/aiosqlite/data_dictionary.py +202 -0
  43. sqlspec/adapters/aiosqlite/driver.py +311 -0
  44. sqlspec/adapters/aiosqlite/events/__init__.py +5 -0
  45. sqlspec/adapters/aiosqlite/events/store.py +20 -0
  46. sqlspec/adapters/aiosqlite/litestar/__init__.py +5 -0
  47. sqlspec/adapters/aiosqlite/litestar/store.py +279 -0
  48. sqlspec/adapters/aiosqlite/pool.cp314-win_amd64.pyd +0 -0
  49. sqlspec/adapters/aiosqlite/pool.py +734 -0
  50. sqlspec/adapters/asyncmy/__init__.py +21 -0
  51. sqlspec/adapters/asyncmy/_typing.py +113 -0
  52. sqlspec/adapters/asyncmy/adk/__init__.py +5 -0
  53. sqlspec/adapters/asyncmy/adk/store.py +644 -0
  54. sqlspec/adapters/asyncmy/config.py +307 -0
  55. sqlspec/adapters/asyncmy/core.cp314-win_amd64.pyd +0 -0
  56. sqlspec/adapters/asyncmy/core.py +538 -0
  57. sqlspec/adapters/asyncmy/data_dictionary.py +122 -0
  58. sqlspec/adapters/asyncmy/driver.py +391 -0
  59. sqlspec/adapters/asyncmy/events/__init__.py +5 -0
  60. sqlspec/adapters/asyncmy/events/store.py +104 -0
  61. sqlspec/adapters/asyncmy/litestar/__init__.py +5 -0
  62. sqlspec/adapters/asyncmy/litestar/store.py +296 -0
  63. sqlspec/adapters/asyncpg/__init__.py +26 -0
  64. sqlspec/adapters/asyncpg/_typing.py +103 -0
  65. sqlspec/adapters/asyncpg/adk/__init__.py +5 -0
  66. sqlspec/adapters/asyncpg/adk/store.py +483 -0
  67. sqlspec/adapters/asyncpg/config.py +575 -0
  68. sqlspec/adapters/asyncpg/core.cp314-win_amd64.pyd +0 -0
  69. sqlspec/adapters/asyncpg/core.py +480 -0
  70. sqlspec/adapters/asyncpg/data_dictionary.py +157 -0
  71. sqlspec/adapters/asyncpg/driver.py +487 -0
  72. sqlspec/adapters/asyncpg/events/__init__.py +6 -0
  73. sqlspec/adapters/asyncpg/events/_hub.py +181 -0
  74. sqlspec/adapters/asyncpg/events/backend.py +210 -0
  75. sqlspec/adapters/asyncpg/events/store.py +40 -0
  76. sqlspec/adapters/asyncpg/litestar/__init__.py +5 -0
  77. sqlspec/adapters/asyncpg/litestar/store.py +251 -0
  78. sqlspec/adapters/bigquery/__init__.py +15 -0
  79. sqlspec/adapters/bigquery/_typing.py +108 -0
  80. sqlspec/adapters/bigquery/config.py +362 -0
  81. sqlspec/adapters/bigquery/core.cp314-win_amd64.pyd +0 -0
  82. sqlspec/adapters/bigquery/core.py +768 -0
  83. sqlspec/adapters/bigquery/data_dictionary.py +120 -0
  84. sqlspec/adapters/bigquery/driver.py +542 -0
  85. sqlspec/adapters/bigquery/events/__init__.py +5 -0
  86. sqlspec/adapters/bigquery/events/store.py +139 -0
  87. sqlspec/adapters/bigquery/litestar/__init__.py +5 -0
  88. sqlspec/adapters/bigquery/litestar/store.py +325 -0
  89. sqlspec/adapters/bigquery/type_converter.cp314-win_amd64.pyd +0 -0
  90. sqlspec/adapters/bigquery/type_converter.py +107 -0
  91. sqlspec/adapters/cockroach_asyncpg/__init__.py +26 -0
  92. sqlspec/adapters/cockroach_asyncpg/_typing.py +73 -0
  93. sqlspec/adapters/cockroach_asyncpg/adk/__init__.py +3 -0
  94. sqlspec/adapters/cockroach_asyncpg/adk/store.py +465 -0
  95. sqlspec/adapters/cockroach_asyncpg/config.py +248 -0
  96. sqlspec/adapters/cockroach_asyncpg/core.cp314-win_amd64.pyd +0 -0
  97. sqlspec/adapters/cockroach_asyncpg/core.py +55 -0
  98. sqlspec/adapters/cockroach_asyncpg/data_dictionary.py +110 -0
  99. sqlspec/adapters/cockroach_asyncpg/driver.py +142 -0
  100. sqlspec/adapters/cockroach_asyncpg/events/__init__.py +3 -0
  101. sqlspec/adapters/cockroach_asyncpg/events/store.py +20 -0
  102. sqlspec/adapters/cockroach_asyncpg/litestar/__init__.py +3 -0
  103. sqlspec/adapters/cockroach_asyncpg/litestar/store.py +142 -0
  104. sqlspec/adapters/cockroach_psycopg/__init__.py +39 -0
  105. sqlspec/adapters/cockroach_psycopg/_typing.py +137 -0
  106. sqlspec/adapters/cockroach_psycopg/adk/__init__.py +13 -0
  107. sqlspec/adapters/cockroach_psycopg/adk/store.py +1039 -0
  108. sqlspec/adapters/cockroach_psycopg/config.py +511 -0
  109. sqlspec/adapters/cockroach_psycopg/core.cp314-win_amd64.pyd +0 -0
  110. sqlspec/adapters/cockroach_psycopg/core.py +63 -0
  111. sqlspec/adapters/cockroach_psycopg/data_dictionary.py +220 -0
  112. sqlspec/adapters/cockroach_psycopg/driver.py +273 -0
  113. sqlspec/adapters/cockroach_psycopg/events/__init__.py +6 -0
  114. sqlspec/adapters/cockroach_psycopg/events/store.py +34 -0
  115. sqlspec/adapters/cockroach_psycopg/litestar/__init__.py +3 -0
  116. sqlspec/adapters/cockroach_psycopg/litestar/store.py +327 -0
  117. sqlspec/adapters/duckdb/__init__.py +29 -0
  118. sqlspec/adapters/duckdb/_typing.py +104 -0
  119. sqlspec/adapters/duckdb/adk/__init__.py +14 -0
  120. sqlspec/adapters/duckdb/adk/store.py +935 -0
  121. sqlspec/adapters/duckdb/config.py +386 -0
  122. sqlspec/adapters/duckdb/core.cp314-win_amd64.pyd +0 -0
  123. sqlspec/adapters/duckdb/core.py +332 -0
  124. sqlspec/adapters/duckdb/data_dictionary.py +140 -0
  125. sqlspec/adapters/duckdb/driver.py +426 -0
  126. sqlspec/adapters/duckdb/events/__init__.py +5 -0
  127. sqlspec/adapters/duckdb/events/store.py +57 -0
  128. sqlspec/adapters/duckdb/litestar/__init__.py +5 -0
  129. sqlspec/adapters/duckdb/litestar/store.py +330 -0
  130. sqlspec/adapters/duckdb/pool.cp314-win_amd64.pyd +0 -0
  131. sqlspec/adapters/duckdb/pool.py +350 -0
  132. sqlspec/adapters/duckdb/type_converter.cp314-win_amd64.pyd +0 -0
  133. sqlspec/adapters/duckdb/type_converter.py +118 -0
  134. sqlspec/adapters/mysqlconnector/__init__.py +39 -0
  135. sqlspec/adapters/mysqlconnector/_typing.py +186 -0
  136. sqlspec/adapters/mysqlconnector/adk/__init__.py +15 -0
  137. sqlspec/adapters/mysqlconnector/adk/store.py +1183 -0
  138. sqlspec/adapters/mysqlconnector/config.py +421 -0
  139. sqlspec/adapters/mysqlconnector/core.cp314-win_amd64.pyd +0 -0
  140. sqlspec/adapters/mysqlconnector/core.py +472 -0
  141. sqlspec/adapters/mysqlconnector/data_dictionary.py +230 -0
  142. sqlspec/adapters/mysqlconnector/driver.py +516 -0
  143. sqlspec/adapters/mysqlconnector/events/__init__.py +8 -0
  144. sqlspec/adapters/mysqlconnector/events/store.py +98 -0
  145. sqlspec/adapters/mysqlconnector/litestar/__init__.py +5 -0
  146. sqlspec/adapters/mysqlconnector/litestar/store.py +426 -0
  147. sqlspec/adapters/oracledb/__init__.py +39 -0
  148. sqlspec/adapters/oracledb/_json_handlers.cp314-win_amd64.pyd +0 -0
  149. sqlspec/adapters/oracledb/_json_handlers.py +196 -0
  150. sqlspec/adapters/oracledb/_param_types.cp314-win_amd64.pyd +0 -0
  151. sqlspec/adapters/oracledb/_param_types.py +46 -0
  152. sqlspec/adapters/oracledb/_typing.py +258 -0
  153. sqlspec/adapters/oracledb/_uuid_handlers.cp314-win_amd64.pyd +0 -0
  154. sqlspec/adapters/oracledb/_uuid_handlers.py +163 -0
  155. sqlspec/adapters/oracledb/_vector_handlers.cp314-win_amd64.pyd +0 -0
  156. sqlspec/adapters/oracledb/_vector_handlers.py +228 -0
  157. sqlspec/adapters/oracledb/adk/__init__.py +21 -0
  158. sqlspec/adapters/oracledb/adk/store.py +2453 -0
  159. sqlspec/adapters/oracledb/config.py +575 -0
  160. sqlspec/adapters/oracledb/core.cp314-win_amd64.pyd +0 -0
  161. sqlspec/adapters/oracledb/core.py +820 -0
  162. sqlspec/adapters/oracledb/data_dictionary.py +404 -0
  163. sqlspec/adapters/oracledb/driver.py +1277 -0
  164. sqlspec/adapters/oracledb/events/__init__.py +16 -0
  165. sqlspec/adapters/oracledb/events/_hub.py +345 -0
  166. sqlspec/adapters/oracledb/events/backend.py +300 -0
  167. sqlspec/adapters/oracledb/events/store.py +420 -0
  168. sqlspec/adapters/oracledb/litestar/__init__.py +5 -0
  169. sqlspec/adapters/oracledb/litestar/store.py +781 -0
  170. sqlspec/adapters/oracledb/migrations.py +539 -0
  171. sqlspec/adapters/oracledb/type_converter.cp314-win_amd64.pyd +0 -0
  172. sqlspec/adapters/oracledb/type_converter.py +211 -0
  173. sqlspec/adapters/psqlpy/__init__.py +18 -0
  174. sqlspec/adapters/psqlpy/_typing.py +121 -0
  175. sqlspec/adapters/psqlpy/adk/__init__.py +5 -0
  176. sqlspec/adapters/psqlpy/adk/store.py +591 -0
  177. sqlspec/adapters/psqlpy/config.py +376 -0
  178. sqlspec/adapters/psqlpy/core.cp314-win_amd64.pyd +0 -0
  179. sqlspec/adapters/psqlpy/core.py +694 -0
  180. sqlspec/adapters/psqlpy/data_dictionary.py +121 -0
  181. sqlspec/adapters/psqlpy/driver.py +411 -0
  182. sqlspec/adapters/psqlpy/events/__init__.py +6 -0
  183. sqlspec/adapters/psqlpy/events/_hub.py +204 -0
  184. sqlspec/adapters/psqlpy/events/backend.py +210 -0
  185. sqlspec/adapters/psqlpy/events/store.py +20 -0
  186. sqlspec/adapters/psqlpy/litestar/__init__.py +5 -0
  187. sqlspec/adapters/psqlpy/litestar/store.py +270 -0
  188. sqlspec/adapters/psqlpy/type_converter.cp314-win_amd64.pyd +0 -0
  189. sqlspec/adapters/psqlpy/type_converter.py +113 -0
  190. sqlspec/adapters/psycopg/__init__.py +38 -0
  191. sqlspec/adapters/psycopg/_typing.py +218 -0
  192. sqlspec/adapters/psycopg/adk/__init__.py +10 -0
  193. sqlspec/adapters/psycopg/adk/store.py +1106 -0
  194. sqlspec/adapters/psycopg/config.py +695 -0
  195. sqlspec/adapters/psycopg/core.cp314-win_amd64.pyd +0 -0
  196. sqlspec/adapters/psycopg/core.py +520 -0
  197. sqlspec/adapters/psycopg/data_dictionary.py +278 -0
  198. sqlspec/adapters/psycopg/driver.py +1033 -0
  199. sqlspec/adapters/psycopg/events/__init__.py +20 -0
  200. sqlspec/adapters/psycopg/events/_hub.py +388 -0
  201. sqlspec/adapters/psycopg/events/backend.py +398 -0
  202. sqlspec/adapters/psycopg/events/store.py +42 -0
  203. sqlspec/adapters/psycopg/litestar/__init__.py +5 -0
  204. sqlspec/adapters/psycopg/litestar/store.py +554 -0
  205. sqlspec/adapters/psycopg/type_converter.cp314-win_amd64.pyd +0 -0
  206. sqlspec/adapters/psycopg/type_converter.py +93 -0
  207. sqlspec/adapters/pymysql/__init__.py +21 -0
  208. sqlspec/adapters/pymysql/_typing.py +92 -0
  209. sqlspec/adapters/pymysql/adk/__init__.py +5 -0
  210. sqlspec/adapters/pymysql/adk/store.py +657 -0
  211. sqlspec/adapters/pymysql/config.py +176 -0
  212. sqlspec/adapters/pymysql/core.cp314-win_amd64.pyd +0 -0
  213. sqlspec/adapters/pymysql/core.py +469 -0
  214. sqlspec/adapters/pymysql/data_dictionary.py +120 -0
  215. sqlspec/adapters/pymysql/driver.py +271 -0
  216. sqlspec/adapters/pymysql/events/__init__.py +5 -0
  217. sqlspec/adapters/pymysql/events/store.py +50 -0
  218. sqlspec/adapters/pymysql/litestar/__init__.py +5 -0
  219. sqlspec/adapters/pymysql/litestar/store.py +232 -0
  220. sqlspec/adapters/pymysql/pool.cp314-win_amd64.pyd +0 -0
  221. sqlspec/adapters/pymysql/pool.py +184 -0
  222. sqlspec/adapters/spanner/__init__.py +33 -0
  223. sqlspec/adapters/spanner/_typing.py +102 -0
  224. sqlspec/adapters/spanner/adk/__init__.py +5 -0
  225. sqlspec/adapters/spanner/adk/store.py +758 -0
  226. sqlspec/adapters/spanner/config.py +355 -0
  227. sqlspec/adapters/spanner/core.cp314-win_amd64.pyd +0 -0
  228. sqlspec/adapters/spanner/core.py +263 -0
  229. sqlspec/adapters/spanner/data_dictionary.py +120 -0
  230. sqlspec/adapters/spanner/driver.py +407 -0
  231. sqlspec/adapters/spanner/events/__init__.py +5 -0
  232. sqlspec/adapters/spanner/events/store.py +187 -0
  233. sqlspec/adapters/spanner/litestar/__init__.py +5 -0
  234. sqlspec/adapters/spanner/litestar/store.py +291 -0
  235. sqlspec/adapters/spanner/type_converter.cp314-win_amd64.pyd +0 -0
  236. sqlspec/adapters/spanner/type_converter.py +342 -0
  237. sqlspec/adapters/sqlite/__init__.py +19 -0
  238. sqlspec/adapters/sqlite/_typing.py +123 -0
  239. sqlspec/adapters/sqlite/adk/__init__.py +5 -0
  240. sqlspec/adapters/sqlite/adk/store.py +992 -0
  241. sqlspec/adapters/sqlite/config.py +240 -0
  242. sqlspec/adapters/sqlite/core.cp314-win_amd64.pyd +0 -0
  243. sqlspec/adapters/sqlite/core.py +357 -0
  244. sqlspec/adapters/sqlite/data_dictionary.py +198 -0
  245. sqlspec/adapters/sqlite/driver.py +527 -0
  246. sqlspec/adapters/sqlite/events/__init__.py +5 -0
  247. sqlspec/adapters/sqlite/events/store.py +20 -0
  248. sqlspec/adapters/sqlite/litestar/__init__.py +5 -0
  249. sqlspec/adapters/sqlite/litestar/store.py +316 -0
  250. sqlspec/adapters/sqlite/pool.cp314-win_amd64.pyd +0 -0
  251. sqlspec/adapters/sqlite/pool.py +237 -0
  252. sqlspec/adapters/sqlite/type_converter.cp314-win_amd64.pyd +0 -0
  253. sqlspec/adapters/sqlite/type_converter.py +114 -0
  254. sqlspec/base.py +832 -0
  255. sqlspec/builder/__init__.py +181 -0
  256. sqlspec/builder/_base.cp314-win_amd64.pyd +0 -0
  257. sqlspec/builder/_base.py +1071 -0
  258. sqlspec/builder/_column.cp314-win_amd64.pyd +0 -0
  259. sqlspec/builder/_column.py +521 -0
  260. sqlspec/builder/_ddl.cp314-win_amd64.pyd +0 -0
  261. sqlspec/builder/_ddl.py +1691 -0
  262. sqlspec/builder/_delete.cp314-win_amd64.pyd +0 -0
  263. sqlspec/builder/_delete.py +95 -0
  264. sqlspec/builder/_dml.cp314-win_amd64.pyd +0 -0
  265. sqlspec/builder/_dml.py +386 -0
  266. sqlspec/builder/_explain.cp314-win_amd64.pyd +0 -0
  267. sqlspec/builder/_explain.py +579 -0
  268. sqlspec/builder/_expression_wrappers.cp314-win_amd64.pyd +0 -0
  269. sqlspec/builder/_expression_wrappers.py +46 -0
  270. sqlspec/builder/_factory.cp314-win_amd64.pyd +0 -0
  271. sqlspec/builder/_factory.py +1884 -0
  272. sqlspec/builder/_insert.cp314-win_amd64.pyd +0 -0
  273. sqlspec/builder/_insert.py +405 -0
  274. sqlspec/builder/_join.cp314-win_amd64.pyd +0 -0
  275. sqlspec/builder/_join.py +489 -0
  276. sqlspec/builder/_merge.cp314-win_amd64.pyd +0 -0
  277. sqlspec/builder/_merge.py +823 -0
  278. sqlspec/builder/_parsing_utils.cp314-win_amd64.pyd +0 -0
  279. sqlspec/builder/_parsing_utils.py +295 -0
  280. sqlspec/builder/_select.cp314-win_amd64.pyd +0 -0
  281. sqlspec/builder/_select.py +1666 -0
  282. sqlspec/builder/_temporal.cp314-win_amd64.pyd +0 -0
  283. sqlspec/builder/_temporal.py +167 -0
  284. sqlspec/builder/_update.cp314-win_amd64.pyd +0 -0
  285. sqlspec/builder/_update.py +173 -0
  286. sqlspec/builder/_vector_distance.cp314-win_amd64.pyd +0 -0
  287. sqlspec/builder/_vector_distance.py +330 -0
  288. sqlspec/cli.py +1095 -0
  289. sqlspec/config.py +2383 -0
  290. sqlspec/core/__init__.py +372 -0
  291. sqlspec/core/_correlation.cp314-win_amd64.pyd +0 -0
  292. sqlspec/core/_correlation.py +176 -0
  293. sqlspec/core/_pagination.py +42 -0
  294. sqlspec/core/_pool.cp314-win_amd64.pyd +0 -0
  295. sqlspec/core/_pool.py +76 -0
  296. sqlspec/core/cache.cp314-win_amd64.pyd +0 -0
  297. sqlspec/core/cache.py +1085 -0
  298. sqlspec/core/compiler.cp314-win_amd64.pyd +0 -0
  299. sqlspec/core/compiler.py +1090 -0
  300. sqlspec/core/config_runtime.cp314-win_amd64.pyd +0 -0
  301. sqlspec/core/config_runtime.py +174 -0
  302. sqlspec/core/explain.cp314-win_amd64.pyd +0 -0
  303. sqlspec/core/explain.py +275 -0
  304. sqlspec/core/filters.cp314-win_amd64.pyd +0 -0
  305. sqlspec/core/filters.py +969 -0
  306. sqlspec/core/hashing.cp314-win_amd64.pyd +0 -0
  307. sqlspec/core/hashing.py +266 -0
  308. sqlspec/core/metrics.cp314-win_amd64.pyd +0 -0
  309. sqlspec/core/metrics.py +83 -0
  310. sqlspec/core/parameters/__init__.py +72 -0
  311. sqlspec/core/parameters/_alignment.cp314-win_amd64.pyd +0 -0
  312. sqlspec/core/parameters/_alignment.py +283 -0
  313. sqlspec/core/parameters/_converter.cp314-win_amd64.pyd +0 -0
  314. sqlspec/core/parameters/_converter.py +554 -0
  315. sqlspec/core/parameters/_processor.cp314-win_amd64.pyd +0 -0
  316. sqlspec/core/parameters/_processor.py +1182 -0
  317. sqlspec/core/parameters/_registry.cp314-win_amd64.pyd +0 -0
  318. sqlspec/core/parameters/_registry.py +206 -0
  319. sqlspec/core/parameters/_transformers.cp314-win_amd64.pyd +0 -0
  320. sqlspec/core/parameters/_transformers.py +324 -0
  321. sqlspec/core/parameters/_types.cp314-win_amd64.pyd +0 -0
  322. sqlspec/core/parameters/_types.py +536 -0
  323. sqlspec/core/parameters/_validator.cp314-win_amd64.pyd +0 -0
  324. sqlspec/core/parameters/_validator.py +171 -0
  325. sqlspec/core/pipeline.cp314-win_amd64.pyd +0 -0
  326. sqlspec/core/pipeline.py +333 -0
  327. sqlspec/core/query_modifiers.cp314-win_amd64.pyd +0 -0
  328. sqlspec/core/query_modifiers.py +508 -0
  329. sqlspec/core/result/__init__.py +25 -0
  330. sqlspec/core/result/_base.cp314-win_amd64.pyd +0 -0
  331. sqlspec/core/result/_base.py +1232 -0
  332. sqlspec/core/result/_io.cp314-win_amd64.pyd +0 -0
  333. sqlspec/core/result/_io.py +28 -0
  334. sqlspec/core/splitter.cp314-win_amd64.pyd +0 -0
  335. sqlspec/core/splitter.py +1021 -0
  336. sqlspec/core/sqlcommenter.cp314-win_amd64.pyd +0 -0
  337. sqlspec/core/sqlcommenter.py +249 -0
  338. sqlspec/core/stack.cp314-win_amd64.pyd +0 -0
  339. sqlspec/core/stack.py +163 -0
  340. sqlspec/core/statement.cp314-win_amd64.pyd +0 -0
  341. sqlspec/core/statement.py +1865 -0
  342. sqlspec/core/type_converter.cp314-win_amd64.pyd +0 -0
  343. sqlspec/core/type_converter.py +340 -0
  344. sqlspec/data_dictionary/__init__.py +22 -0
  345. sqlspec/data_dictionary/_loader.cp314-win_amd64.pyd +0 -0
  346. sqlspec/data_dictionary/_loader.py +138 -0
  347. sqlspec/data_dictionary/_registry.cp314-win_amd64.pyd +0 -0
  348. sqlspec/data_dictionary/_registry.py +74 -0
  349. sqlspec/data_dictionary/_types.cp314-win_amd64.pyd +0 -0
  350. sqlspec/data_dictionary/_types.py +121 -0
  351. sqlspec/data_dictionary/dialects/__init__.py +21 -0
  352. sqlspec/data_dictionary/dialects/bigquery.cp314-win_amd64.pyd +0 -0
  353. sqlspec/data_dictionary/dialects/bigquery.py +81 -0
  354. sqlspec/data_dictionary/dialects/cockroachdb.cp314-win_amd64.pyd +0 -0
  355. sqlspec/data_dictionary/dialects/cockroachdb.py +54 -0
  356. sqlspec/data_dictionary/dialects/duckdb.cp314-win_amd64.pyd +0 -0
  357. sqlspec/data_dictionary/dialects/duckdb.py +47 -0
  358. sqlspec/data_dictionary/dialects/mysql.cp314-win_amd64.pyd +0 -0
  359. sqlspec/data_dictionary/dialects/mysql.py +53 -0
  360. sqlspec/data_dictionary/dialects/oracle.cp314-win_amd64.pyd +0 -0
  361. sqlspec/data_dictionary/dialects/oracle.py +197 -0
  362. sqlspec/data_dictionary/dialects/postgres.cp314-win_amd64.pyd +0 -0
  363. sqlspec/data_dictionary/dialects/postgres.py +69 -0
  364. sqlspec/data_dictionary/dialects/spanner.cp314-win_amd64.pyd +0 -0
  365. sqlspec/data_dictionary/dialects/spanner.py +37 -0
  366. sqlspec/data_dictionary/dialects/sqlite.cp314-win_amd64.pyd +0 -0
  367. sqlspec/data_dictionary/dialects/sqlite.py +59 -0
  368. sqlspec/data_dictionary/sql/.gitkeep +0 -0
  369. sqlspec/data_dictionary/sql/bigquery/columns.sql +23 -0
  370. sqlspec/data_dictionary/sql/bigquery/foreign_keys.sql +34 -0
  371. sqlspec/data_dictionary/sql/bigquery/indexes.sql +19 -0
  372. sqlspec/data_dictionary/sql/bigquery/tables.sql +33 -0
  373. sqlspec/data_dictionary/sql/bigquery/version.sql +3 -0
  374. sqlspec/data_dictionary/sql/cockroachdb/columns.sql +34 -0
  375. sqlspec/data_dictionary/sql/cockroachdb/foreign_keys.sql +40 -0
  376. sqlspec/data_dictionary/sql/cockroachdb/indexes.sql +32 -0
  377. sqlspec/data_dictionary/sql/cockroachdb/tables.sql +44 -0
  378. sqlspec/data_dictionary/sql/cockroachdb/version.sql +3 -0
  379. sqlspec/data_dictionary/sql/duckdb/columns.sql +23 -0
  380. sqlspec/data_dictionary/sql/duckdb/foreign_keys.sql +36 -0
  381. sqlspec/data_dictionary/sql/duckdb/indexes.sql +19 -0
  382. sqlspec/data_dictionary/sql/duckdb/tables.sql +38 -0
  383. sqlspec/data_dictionary/sql/duckdb/version.sql +3 -0
  384. sqlspec/data_dictionary/sql/mysql/columns.sql +23 -0
  385. sqlspec/data_dictionary/sql/mysql/foreign_keys.sql +28 -0
  386. sqlspec/data_dictionary/sql/mysql/indexes.sql +26 -0
  387. sqlspec/data_dictionary/sql/mysql/tables.sql +33 -0
  388. sqlspec/data_dictionary/sql/mysql/version.sql +3 -0
  389. sqlspec/data_dictionary/sql/oracle/columns.sql +23 -0
  390. sqlspec/data_dictionary/sql/oracle/foreign_keys.sql +48 -0
  391. sqlspec/data_dictionary/sql/oracle/indexes.sql +44 -0
  392. sqlspec/data_dictionary/sql/oracle/tables.sql +25 -0
  393. sqlspec/data_dictionary/sql/oracle/version.sql +20 -0
  394. sqlspec/data_dictionary/sql/postgres/columns.sql +34 -0
  395. sqlspec/data_dictionary/sql/postgres/foreign_keys.sql +40 -0
  396. sqlspec/data_dictionary/sql/postgres/indexes.sql +56 -0
  397. sqlspec/data_dictionary/sql/postgres/tables.sql +44 -0
  398. sqlspec/data_dictionary/sql/postgres/version.sql +3 -0
  399. sqlspec/data_dictionary/sql/spanner/columns.sql +23 -0
  400. sqlspec/data_dictionary/sql/spanner/foreign_keys.sql +70 -0
  401. sqlspec/data_dictionary/sql/spanner/indexes.sql +30 -0
  402. sqlspec/data_dictionary/sql/spanner/tables.sql +9 -0
  403. sqlspec/data_dictionary/sql/spanner/version.sql +3 -0
  404. sqlspec/data_dictionary/sql/sqlite/columns.sql +23 -0
  405. sqlspec/data_dictionary/sql/sqlite/foreign_keys.sql +22 -0
  406. sqlspec/data_dictionary/sql/sqlite/indexes.sql +7 -0
  407. sqlspec/data_dictionary/sql/sqlite/tables.sql +28 -0
  408. sqlspec/data_dictionary/sql/sqlite/version.sql +3 -0
  409. sqlspec/dialects/__init__.py +22 -0
  410. sqlspec/dialects/_compat.cp314-win_amd64.pyd +0 -0
  411. sqlspec/dialects/_compat.py +14 -0
  412. sqlspec/dialects/postgres/__init__.py +9 -0
  413. sqlspec/dialects/postgres/_generators.cp314-win_amd64.pyd +0 -0
  414. sqlspec/dialects/postgres/_generators.py +57 -0
  415. sqlspec/dialects/postgres/_operators.cp314-win_amd64.pyd +0 -0
  416. sqlspec/dialects/postgres/_operators.py +81 -0
  417. sqlspec/dialects/postgres/_paradedb.py +50 -0
  418. sqlspec/dialects/postgres/_pgvector.py +36 -0
  419. sqlspec/dialects/spanner/__init__.py +6 -0
  420. sqlspec/dialects/spanner/_generators.cp314-win_amd64.pyd +0 -0
  421. sqlspec/dialects/spanner/_generators.py +206 -0
  422. sqlspec/dialects/spanner/_spangres.py +77 -0
  423. sqlspec/dialects/spanner/_spanner.py +179 -0
  424. sqlspec/driver/__init__.py +49 -0
  425. sqlspec/driver/_async.cp314-win_amd64.pyd +0 -0
  426. sqlspec/driver/_async.py +1830 -0
  427. sqlspec/driver/_common.cp314-win_amd64.pyd +0 -0
  428. sqlspec/driver/_common.py +2292 -0
  429. sqlspec/driver/_exception_handler.cp314-win_amd64.pyd +0 -0
  430. sqlspec/driver/_exception_handler.py +108 -0
  431. sqlspec/driver/_query_cache.cp314-win_amd64.pyd +0 -0
  432. sqlspec/driver/_query_cache.py +96 -0
  433. sqlspec/driver/_sql_helpers.cp314-win_amd64.pyd +0 -0
  434. sqlspec/driver/_sql_helpers.py +139 -0
  435. sqlspec/driver/_storage_helpers.cp314-win_amd64.pyd +0 -0
  436. sqlspec/driver/_storage_helpers.py +153 -0
  437. sqlspec/driver/_sync.cp314-win_amd64.pyd +0 -0
  438. sqlspec/driver/_sync.py +1817 -0
  439. sqlspec/exceptions.cp314-win_amd64.pyd +0 -0
  440. sqlspec/exceptions.py +480 -0
  441. sqlspec/extensions/__init__.py +0 -0
  442. sqlspec/extensions/adk/__init__.py +84 -0
  443. sqlspec/extensions/adk/_config_utils.py +199 -0
  444. sqlspec/extensions/adk/_types.cp314-win_amd64.pyd +0 -0
  445. sqlspec/extensions/adk/_types.py +41 -0
  446. sqlspec/extensions/adk/artifact/__init__.py +57 -0
  447. sqlspec/extensions/adk/artifact/_types.cp314-win_amd64.pyd +0 -0
  448. sqlspec/extensions/adk/artifact/_types.py +32 -0
  449. sqlspec/extensions/adk/artifact/service.py +508 -0
  450. sqlspec/extensions/adk/artifact/store.py +361 -0
  451. sqlspec/extensions/adk/converters.py +212 -0
  452. sqlspec/extensions/adk/memory/__init__.py +69 -0
  453. sqlspec/extensions/adk/memory/_types.cp314-win_amd64.pyd +0 -0
  454. sqlspec/extensions/adk/memory/_types.py +30 -0
  455. sqlspec/extensions/adk/memory/converters.py +225 -0
  456. sqlspec/extensions/adk/memory/service.py +316 -0
  457. sqlspec/extensions/adk/memory/store.py +525 -0
  458. sqlspec/extensions/adk/migrations/0001_create_adk_tables.py +184 -0
  459. sqlspec/extensions/adk/migrations/__init__.py +0 -0
  460. sqlspec/extensions/adk/service.py +279 -0
  461. sqlspec/extensions/adk/store.py +590 -0
  462. sqlspec/extensions/events/__init__.py +51 -0
  463. sqlspec/extensions/events/_channel.py +703 -0
  464. sqlspec/extensions/events/_hints.cp314-win_amd64.pyd +0 -0
  465. sqlspec/extensions/events/_hints.py +45 -0
  466. sqlspec/extensions/events/_models.py +23 -0
  467. sqlspec/extensions/events/_payload.cp314-win_amd64.pyd +0 -0
  468. sqlspec/extensions/events/_payload.py +69 -0
  469. sqlspec/extensions/events/_protocols.py +134 -0
  470. sqlspec/extensions/events/_queue.py +462 -0
  471. sqlspec/extensions/events/_store.py +209 -0
  472. sqlspec/extensions/events/migrations/0001_create_event_queue.py +59 -0
  473. sqlspec/extensions/events/migrations/__init__.py +3 -0
  474. sqlspec/extensions/fastapi/__init__.py +22 -0
  475. sqlspec/extensions/fastapi/extension.py +391 -0
  476. sqlspec/extensions/fastapi/providers.cp314-win_amd64.pyd +0 -0
  477. sqlspec/extensions/fastapi/providers.py +712 -0
  478. sqlspec/extensions/flask/__init__.py +38 -0
  479. sqlspec/extensions/flask/_state.py +87 -0
  480. sqlspec/extensions/flask/_utils.py +71 -0
  481. sqlspec/extensions/flask/extension.py +539 -0
  482. sqlspec/extensions/litestar/__init__.py +31 -0
  483. sqlspec/extensions/litestar/_utils.py +52 -0
  484. sqlspec/extensions/litestar/channels.py +165 -0
  485. sqlspec/extensions/litestar/cli.py +102 -0
  486. sqlspec/extensions/litestar/config.py +90 -0
  487. sqlspec/extensions/litestar/handlers.py +316 -0
  488. sqlspec/extensions/litestar/migrations/0001_create_session_table.py +137 -0
  489. sqlspec/extensions/litestar/migrations/__init__.py +3 -0
  490. sqlspec/extensions/litestar/plugin.py +1066 -0
  491. sqlspec/extensions/litestar/providers.cp314-win_amd64.pyd +0 -0
  492. sqlspec/extensions/litestar/providers.py +784 -0
  493. sqlspec/extensions/litestar/store.py +298 -0
  494. sqlspec/extensions/otel/__init__.py +58 -0
  495. sqlspec/extensions/prometheus/__init__.py +113 -0
  496. sqlspec/extensions/sanic/__init__.py +19 -0
  497. sqlspec/extensions/sanic/_state.py +43 -0
  498. sqlspec/extensions/sanic/_utils.py +127 -0
  499. sqlspec/extensions/sanic/extension.py +647 -0
  500. sqlspec/extensions/starlette/__init__.py +22 -0
  501. sqlspec/extensions/starlette/_state.py +42 -0
  502. sqlspec/extensions/starlette/_utils.py +96 -0
  503. sqlspec/extensions/starlette/extension.py +374 -0
  504. sqlspec/extensions/starlette/middleware.py +281 -0
  505. sqlspec/loader.cp314-win_amd64.pyd +0 -0
  506. sqlspec/loader.py +727 -0
  507. sqlspec/migrations/__init__.py +39 -0
  508. sqlspec/migrations/base.cp314-win_amd64.pyd +0 -0
  509. sqlspec/migrations/base.py +862 -0
  510. sqlspec/migrations/commands.py +2151 -0
  511. sqlspec/migrations/context.cp314-win_amd64.pyd +0 -0
  512. sqlspec/migrations/context.py +157 -0
  513. sqlspec/migrations/fix.cp314-win_amd64.pyd +0 -0
  514. sqlspec/migrations/fix.py +204 -0
  515. sqlspec/migrations/loaders.cp314-win_amd64.pyd +0 -0
  516. sqlspec/migrations/loaders.py +443 -0
  517. sqlspec/migrations/runner.cp314-win_amd64.pyd +0 -0
  518. sqlspec/migrations/runner.py +1195 -0
  519. sqlspec/migrations/squash.cp314-win_amd64.pyd +0 -0
  520. sqlspec/migrations/squash.py +490 -0
  521. sqlspec/migrations/templates.cp314-win_amd64.pyd +0 -0
  522. sqlspec/migrations/templates.py +234 -0
  523. sqlspec/migrations/tracker.cp314-win_amd64.pyd +0 -0
  524. sqlspec/migrations/tracker.py +792 -0
  525. sqlspec/migrations/utils.cp314-win_amd64.pyd +0 -0
  526. sqlspec/migrations/utils.py +256 -0
  527. sqlspec/migrations/validation.cp314-win_amd64.pyd +0 -0
  528. sqlspec/migrations/validation.py +359 -0
  529. sqlspec/migrations/version.cp314-win_amd64.pyd +0 -0
  530. sqlspec/migrations/version.py +446 -0
  531. sqlspec/observability/__init__.py +57 -0
  532. sqlspec/observability/_common.cp314-win_amd64.pyd +0 -0
  533. sqlspec/observability/_common.py +77 -0
  534. sqlspec/observability/_config.cp314-win_amd64.pyd +0 -0
  535. sqlspec/observability/_config.py +364 -0
  536. sqlspec/observability/_diagnostics.cp314-win_amd64.pyd +0 -0
  537. sqlspec/observability/_diagnostics.py +74 -0
  538. sqlspec/observability/_dispatcher.cp314-win_amd64.pyd +0 -0
  539. sqlspec/observability/_dispatcher.py +200 -0
  540. sqlspec/observability/_formatters/__init__.py +13 -0
  541. sqlspec/observability/_formatters/_aws.cp314-win_amd64.pyd +0 -0
  542. sqlspec/observability/_formatters/_aws.py +102 -0
  543. sqlspec/observability/_formatters/_azure.cp314-win_amd64.pyd +0 -0
  544. sqlspec/observability/_formatters/_azure.py +96 -0
  545. sqlspec/observability/_formatters/_base.cp314-win_amd64.pyd +0 -0
  546. sqlspec/observability/_formatters/_base.py +57 -0
  547. sqlspec/observability/_formatters/_gcp.cp314-win_amd64.pyd +0 -0
  548. sqlspec/observability/_formatters/_gcp.py +131 -0
  549. sqlspec/observability/_formatting.py +58 -0
  550. sqlspec/observability/_observer.cp314-win_amd64.pyd +0 -0
  551. sqlspec/observability/_observer.py +361 -0
  552. sqlspec/observability/_runtime.cp314-win_amd64.pyd +0 -0
  553. sqlspec/observability/_runtime.py +461 -0
  554. sqlspec/observability/_sampling.cp314-win_amd64.pyd +0 -0
  555. sqlspec/observability/_sampling.py +188 -0
  556. sqlspec/observability/_spans.cp314-win_amd64.pyd +0 -0
  557. sqlspec/observability/_spans.py +161 -0
  558. sqlspec/protocols.py +955 -0
  559. sqlspec/py.typed +0 -0
  560. sqlspec/service.py +433 -0
  561. sqlspec/storage/__init__.py +48 -0
  562. sqlspec/storage/_arrow_payload.py +68 -0
  563. sqlspec/storage/_paths.cp314-win_amd64.pyd +0 -0
  564. sqlspec/storage/_paths.py +58 -0
  565. sqlspec/storage/_utils.py +46 -0
  566. sqlspec/storage/backends/__init__.py +1 -0
  567. sqlspec/storage/backends/base.cp314-win_amd64.pyd +0 -0
  568. sqlspec/storage/backends/base.py +374 -0
  569. sqlspec/storage/backends/fsspec.py +574 -0
  570. sqlspec/storage/backends/local.py +468 -0
  571. sqlspec/storage/backends/obstore.py +956 -0
  572. sqlspec/storage/errors.cp314-win_amd64.pyd +0 -0
  573. sqlspec/storage/errors.py +102 -0
  574. sqlspec/storage/pipeline.cp314-win_amd64.pyd +0 -0
  575. sqlspec/storage/pipeline.py +628 -0
  576. sqlspec/storage/registry.cp314-win_amd64.pyd +0 -0
  577. sqlspec/storage/registry.py +329 -0
  578. sqlspec/typing.py +405 -0
  579. sqlspec/utils/__init__.py +7 -0
  580. sqlspec/utils/arrow_helpers.py +384 -0
  581. sqlspec/utils/config_tools.cp314-win_amd64.pyd +0 -0
  582. sqlspec/utils/config_tools.py +314 -0
  583. sqlspec/utils/correlation.cp314-win_amd64.pyd +0 -0
  584. sqlspec/utils/correlation.py +134 -0
  585. sqlspec/utils/deprecation.cp314-win_amd64.pyd +0 -0
  586. sqlspec/utils/deprecation.py +157 -0
  587. sqlspec/utils/dispatch.cp314-win_amd64.pyd +0 -0
  588. sqlspec/utils/dispatch.py +101 -0
  589. sqlspec/utils/fixtures.cp314-win_amd64.pyd +0 -0
  590. sqlspec/utils/fixtures.py +260 -0
  591. sqlspec/utils/logging.cp314-win_amd64.pyd +0 -0
  592. sqlspec/utils/logging.py +251 -0
  593. sqlspec/utils/module_loader.py +306 -0
  594. sqlspec/utils/portal.cp314-win_amd64.pyd +0 -0
  595. sqlspec/utils/portal.py +377 -0
  596. sqlspec/utils/schema.cp314-win_amd64.pyd +0 -0
  597. sqlspec/utils/schema.py +1040 -0
  598. sqlspec/utils/serializers/__init__.py +30 -0
  599. sqlspec/utils/serializers/_json.cp314-win_amd64.pyd +0 -0
  600. sqlspec/utils/serializers/_json.py +415 -0
  601. sqlspec/utils/serializers/_numpy.cp314-win_amd64.pyd +0 -0
  602. sqlspec/utils/serializers/_numpy.py +65 -0
  603. sqlspec/utils/serializers/_schema.cp314-win_amd64.pyd +0 -0
  604. sqlspec/utils/serializers/_schema.py +285 -0
  605. sqlspec/utils/singleton.cp314-win_amd64.pyd +0 -0
  606. sqlspec/utils/singleton.py +41 -0
  607. sqlspec/utils/sync_tools.cp314-win_amd64.pyd +0 -0
  608. sqlspec/utils/sync_tools.py +316 -0
  609. sqlspec/utils/text.cp314-win_amd64.pyd +0 -0
  610. sqlspec/utils/text.py +109 -0
  611. sqlspec/utils/type_converters.cp314-win_amd64.pyd +0 -0
  612. sqlspec/utils/type_converters.py +216 -0
  613. sqlspec/utils/type_guards.cp314-win_amd64.pyd +0 -0
  614. sqlspec/utils/type_guards.py +1508 -0
  615. sqlspec/utils/uuids.cp314-win_amd64.pyd +0 -0
  616. sqlspec/utils/uuids.py +241 -0
  617. sqlspec-0.47.0.dist-info/METADATA +202 -0
  618. sqlspec-0.47.0.dist-info/RECORD +621 -0
  619. sqlspec-0.47.0.dist-info/WHEEL +4 -0
  620. sqlspec-0.47.0.dist-info/entry_points.txt +6 -0
  621. sqlspec-0.47.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,330 @@
1
+ """DuckDB sync session store for Litestar integration."""
2
+
3
+ from datetime import datetime, timedelta, timezone
4
+ from typing import TYPE_CHECKING
5
+
6
+ from sqlspec.extensions.litestar.store import BaseSQLSpecStore
7
+ from sqlspec.utils.sync_tools import async_
8
+
9
+ if TYPE_CHECKING:
10
+ from sqlspec.adapters.duckdb.config import DuckDBConfig
11
+
12
+
13
+ __all__ = ("DuckdbStore",)
14
+
15
+
16
+ class DuckdbStore(BaseSQLSpecStore["DuckDBConfig"]):
17
+ """DuckDB session store using synchronous DuckDB driver.
18
+
19
+ Implements server-side session storage for Litestar using DuckDB
20
+ via the synchronous duckdb driver. Uses Litestar's sync_to_thread
21
+ utility to provide an async interface compatible with the Store protocol.
22
+
23
+ Provides efficient session management with:
24
+ - Sync operations wrapped for async compatibility
25
+ - INSERT OR REPLACE for UPSERT functionality
26
+ - Native TIMESTAMP type support
27
+ - Automatic expiration handling
28
+ - Efficient cleanup of expired sessions
29
+ - Columnar storage optimized for analytical queries
30
+
31
+ Note:
32
+ DuckDB is primarily designed for analytical (OLAP) workloads.
33
+ For high-concurrency OLTP session stores, consider PostgreSQL adapters.
34
+
35
+ Args:
36
+ config: DuckDBConfig instance.
37
+
38
+ Example:
39
+ from sqlspec.adapters.duckdb import DuckDBConfig
40
+ from sqlspec.adapters.duckdb.litestar.store import DuckdbStore
41
+
42
+ config = DuckDBConfig()
43
+ store = DuckdbStore(config)
44
+ await store.create_table()
45
+ """
46
+
47
+ __slots__ = ()
48
+
49
+ def __init__(self, config: "DuckDBConfig") -> None:
50
+ """Initialize DuckDB session store.
51
+
52
+ Args:
53
+ config: DuckDBConfig instance.
54
+
55
+ Notes:
56
+ Table name is read from config.extension_config["litestar"]["session_table"].
57
+ """
58
+ super().__init__(config)
59
+
60
+ def _get_create_table_sql(self) -> str:
61
+ """Get DuckDB CREATE TABLE SQL.
62
+
63
+ Returns:
64
+ SQL statement to create the sessions table with proper indexes.
65
+
66
+ Notes:
67
+ - Uses TIMESTAMP type for expires_at (DuckDB native datetime type)
68
+ - TIMESTAMP supports ISO 8601 format and direct comparisons
69
+ - Columnar storage makes this efficient for analytical queries
70
+ - DuckDB does not support partial indexes, so full index is created
71
+ """
72
+ return f"""
73
+ CREATE TABLE IF NOT EXISTS {self._table_name} (
74
+ session_id VARCHAR PRIMARY KEY,
75
+ data BLOB NOT NULL,
76
+ expires_at TIMESTAMP,
77
+ created_at TIMESTAMP DEFAULT NOW(),
78
+ updated_at TIMESTAMP DEFAULT NOW()
79
+ );
80
+ CREATE INDEX IF NOT EXISTS idx_{self._table_name}_expires_at
81
+ ON {self._table_name}(expires_at);
82
+ """
83
+
84
+ def _get_drop_table_sql(self) -> "list[str]":
85
+ """Get DuckDB DROP TABLE SQL statements.
86
+
87
+ Returns:
88
+ List of SQL statements to drop indexes and table.
89
+ """
90
+ return [f"DROP INDEX IF EXISTS idx_{self._table_name}_expires_at", f"DROP TABLE IF EXISTS {self._table_name}"]
91
+
92
+ def _datetime_to_timestamp(self, dt: "datetime | None") -> "str | None":
93
+ """Convert datetime to ISO 8601 string for DuckDB TIMESTAMP storage.
94
+
95
+ Args:
96
+ dt: Datetime to convert (must be UTC-aware).
97
+
98
+ Returns:
99
+ ISO 8601 formatted string, or None if dt is None.
100
+
101
+ Notes:
102
+ DuckDB's TIMESTAMP type accepts ISO 8601 format strings.
103
+ This enables efficient storage and comparison operations.
104
+ """
105
+ if dt is None:
106
+ return None
107
+ return dt.isoformat()
108
+
109
+ def _timestamp_to_datetime(self, ts: "str | datetime | None") -> "datetime | None":
110
+ """Convert TIMESTAMP string back to datetime.
111
+
112
+ Args:
113
+ ts: ISO 8601 timestamp string or datetime object.
114
+
115
+ Returns:
116
+ UTC-aware datetime, or None if ts is None.
117
+ """
118
+ if ts is None:
119
+ return None
120
+ if isinstance(ts, datetime):
121
+ if ts.tzinfo is None:
122
+ return ts.replace(tzinfo=timezone.utc)
123
+ return ts
124
+ dt = datetime.fromisoformat(ts)
125
+ if dt.tzinfo is None:
126
+ dt = dt.replace(tzinfo=timezone.utc)
127
+ return dt
128
+
129
+ def _create_table(self) -> None:
130
+ """Synchronous implementation of create_table."""
131
+ sql = self._get_create_table_sql()
132
+ with self._config.provide_session() as driver:
133
+ driver.execute_script(sql)
134
+ self._log_table_created()
135
+
136
+ async def create_table(self) -> None:
137
+ """Create the session table if it doesn't exist."""
138
+ await async_(self._create_table)()
139
+
140
+ def _get(self, key: str, renew_for: "int | timedelta | None" = None) -> "bytes | None":
141
+ """Synchronous implementation of get."""
142
+ sql = f"""
143
+ SELECT data, expires_at FROM {self._table_name}
144
+ WHERE session_id = ?
145
+ AND (expires_at IS NULL OR expires_at > CURRENT_TIMESTAMP)
146
+ """
147
+
148
+ with self._config.provide_connection() as conn:
149
+ cursor = conn.execute(sql, (key,))
150
+ row = cursor.fetchone()
151
+
152
+ if row is None:
153
+ return None
154
+
155
+ data, expires_at_str = row
156
+
157
+ if renew_for is not None and expires_at_str is not None:
158
+ new_expires_at = self._calculate_expires_at(renew_for)
159
+ new_expires_at_str = self._datetime_to_timestamp(new_expires_at)
160
+ if new_expires_at_str is not None:
161
+ update_sql = f"""
162
+ UPDATE {self._table_name}
163
+ SET expires_at = ?, updated_at = NOW()
164
+ WHERE session_id = ?
165
+ """
166
+ conn.execute(update_sql, (new_expires_at_str, key))
167
+ conn.commit()
168
+
169
+ return bytes(data)
170
+
171
+ async def get(self, key: str, renew_for: "int | timedelta | None" = None) -> "bytes | None":
172
+ """Get a session value by key.
173
+
174
+ Args:
175
+ key: Session ID to retrieve.
176
+ renew_for: If given, renew the expiry time for this duration.
177
+
178
+ Returns:
179
+ Session data as bytes if found and not expired, None otherwise.
180
+ """
181
+ return await async_(self._get)(key, renew_for)
182
+
183
+ def _set(self, key: str, value: "str | bytes", expires_in: "int | timedelta | None" = None) -> None:
184
+ """Synchronous implementation of set.
185
+
186
+ Notes:
187
+ Stores expires_at as TIMESTAMP (ISO 8601 string) for DuckDB native support.
188
+ Uses INSERT ON CONFLICT instead of INSERT OR REPLACE to ensure all columns
189
+ are properly updated. created_at uses DEFAULT on insert, updated_at gets
190
+ current timestamp on both insert and update.
191
+ """
192
+ data = self._value_to_bytes(value)
193
+ expires_at = self._calculate_expires_at(expires_in)
194
+ expires_at_str = self._datetime_to_timestamp(expires_at)
195
+
196
+ sql = f"""
197
+ INSERT INTO {self._table_name} (session_id, data, expires_at)
198
+ VALUES (?, ?, ?)
199
+ ON CONFLICT (session_id)
200
+ DO UPDATE SET
201
+ data = EXCLUDED.data,
202
+ expires_at = EXCLUDED.expires_at,
203
+ updated_at = NOW()
204
+ """
205
+
206
+ with self._config.provide_connection() as conn:
207
+ conn.execute(sql, (key, data, expires_at_str))
208
+ conn.commit()
209
+
210
+ async def set(self, key: str, value: "str | bytes", expires_in: "int | timedelta | None" = None) -> None:
211
+ """Store a session value.
212
+
213
+ Args:
214
+ key: Session ID.
215
+ value: Session data.
216
+ expires_in: Time until expiration.
217
+ """
218
+ await async_(self._set)(key, value, expires_in)
219
+
220
+ def _delete(self, key: str) -> None:
221
+ """Synchronous implementation of delete."""
222
+ sql = f"DELETE FROM {self._table_name} WHERE session_id = ?"
223
+
224
+ with self._config.provide_connection() as conn:
225
+ conn.execute(sql, (key,))
226
+ conn.commit()
227
+
228
+ async def delete(self, key: str) -> None:
229
+ """Delete a session by key.
230
+
231
+ Args:
232
+ key: Session ID to delete.
233
+ """
234
+ await async_(self._delete)(key)
235
+
236
+ def _delete_all(self) -> None:
237
+ """Synchronous implementation of delete_all."""
238
+ sql = f"DELETE FROM {self._table_name}"
239
+
240
+ with self._config.provide_connection() as conn:
241
+ conn.execute(sql)
242
+ conn.commit()
243
+ self._log_delete_all()
244
+
245
+ async def delete_all(self) -> None:
246
+ """Delete all sessions from the store."""
247
+ await async_(self._delete_all)()
248
+
249
+ def _exists(self, key: str) -> bool:
250
+ """Synchronous implementation of exists."""
251
+ sql = f"""
252
+ SELECT 1 FROM {self._table_name}
253
+ WHERE session_id = ?
254
+ AND (expires_at IS NULL OR expires_at > CURRENT_TIMESTAMP)
255
+ """
256
+
257
+ with self._config.provide_connection() as conn:
258
+ cursor = conn.execute(sql, (key,))
259
+ result = cursor.fetchone()
260
+ return result is not None
261
+
262
+ async def exists(self, key: str) -> bool:
263
+ """Check if a session key exists and is not expired.
264
+
265
+ Args:
266
+ key: Session ID to check.
267
+
268
+ Returns:
269
+ True if the session exists and is not expired.
270
+ """
271
+ return await async_(self._exists)(key)
272
+
273
+ def _expires_in(self, key: str) -> "int | None":
274
+ """Synchronous implementation of expires_in."""
275
+ sql = f"""
276
+ SELECT expires_at FROM {self._table_name}
277
+ WHERE session_id = ?
278
+ """
279
+
280
+ with self._config.provide_connection() as conn:
281
+ cursor = conn.execute(sql, (key,))
282
+ row = cursor.fetchone()
283
+
284
+ if row is None or row[0] is None:
285
+ return None
286
+
287
+ expires_at_str = row[0]
288
+ expires_at = self._timestamp_to_datetime(expires_at_str)
289
+
290
+ if expires_at is None:
291
+ return None
292
+
293
+ now = datetime.now(timezone.utc)
294
+
295
+ if expires_at <= now:
296
+ return 0
297
+
298
+ delta = expires_at - now
299
+ return int(delta.total_seconds())
300
+
301
+ async def expires_in(self, key: str) -> "int | None":
302
+ """Get the time in seconds until the session expires.
303
+
304
+ Args:
305
+ key: Session ID to check.
306
+
307
+ Returns:
308
+ Seconds until expiration, or None if no expiry or key doesn't exist.
309
+ """
310
+ return await async_(self._expires_in)(key)
311
+
312
+ def _delete_expired(self) -> int:
313
+ """Synchronous implementation of delete_expired."""
314
+ sql = f"DELETE FROM {self._table_name} WHERE expires_at <= CURRENT_TIMESTAMP"
315
+
316
+ with self._config.provide_connection() as conn:
317
+ cursor = conn.execute(sql)
318
+ count = cursor.fetchone()
319
+ row_count = count[0] if count else 0
320
+ if row_count > 0:
321
+ self._log_delete_expired(row_count)
322
+ return row_count
323
+
324
+ async def delete_expired(self) -> int:
325
+ """Delete all expired sessions.
326
+
327
+ Returns:
328
+ Number of sessions deleted.
329
+ """
330
+ return await async_(self._delete_expired)()
@@ -0,0 +1,350 @@
1
+ """DuckDB connection pool with thread-local connections."""
2
+
3
+ import logging
4
+ import threading
5
+ import time
6
+ import uuid
7
+ from contextlib import contextmanager, suppress
8
+ from typing import TYPE_CHECKING, Any, Final, cast
9
+
10
+ import duckdb
11
+
12
+ from sqlspec.adapters.duckdb._typing import DuckDBConnection
13
+ from sqlspec.utils.logging import POOL_LOGGER_NAME, get_logger, log_with_context
14
+
15
+ if TYPE_CHECKING:
16
+ from collections.abc import Callable, Generator
17
+
18
+
19
+ logger = get_logger(POOL_LOGGER_NAME)
20
+ _ADAPTER_NAME = "duckdb"
21
+
22
+ DEFAULT_MIN_POOL: Final[int] = 1
23
+ DEFAULT_MAX_POOL: Final[int] = 4
24
+ POOL_TIMEOUT: Final[float] = 30.0
25
+ POOL_RECYCLE: Final[int] = 86400
26
+ HEALTH_CHECK_INTERVAL: Final[float] = 30.0
27
+
28
+ __all__ = ("DuckDBConnectionPool",)
29
+
30
+
31
+ class DuckDBConnectionPool:
32
+ """Thread-local connection manager for DuckDB.
33
+
34
+ Uses thread-local storage to ensure each thread gets its own DuckDB connection,
35
+ preventing the thread-safety issues that cause segmentation faults when
36
+ multiple cursors share the same connection concurrently.
37
+
38
+ This design trades traditional pooling for thread safety, which is essential
39
+ for DuckDB since connections and cursors are not thread-safe.
40
+ """
41
+
42
+ __slots__ = (
43
+ "_connection_config",
44
+ "_connection_times",
45
+ "_created_connections",
46
+ "_extension_flags",
47
+ "_extensions",
48
+ "_health_check_interval",
49
+ "_is_memory_db",
50
+ "_lock",
51
+ "_on_connection_create",
52
+ "_pool_id",
53
+ "_recycle",
54
+ "_secrets",
55
+ "_thread_local",
56
+ )
57
+
58
+ def __init__(
59
+ self,
60
+ connection_config: "dict[str, Any]",
61
+ pool_recycle_seconds: int = POOL_RECYCLE,
62
+ health_check_interval: float = HEALTH_CHECK_INTERVAL,
63
+ extensions: "list[dict[str, Any]] | None" = None,
64
+ extension_flags: "dict[str, Any] | None" = None,
65
+ secrets: "list[dict[str, Any]] | None" = None,
66
+ on_connection_create: "Callable[[DuckDBConnection], DuckDBConnection | None] | None" = None,
67
+ ) -> None:
68
+ """Initialize the thread-local connection manager.
69
+
70
+ Args:
71
+ connection_config: DuckDB connection configuration
72
+ pool_recycle_seconds: Connection recycle time in seconds
73
+ health_check_interval: Seconds of idle time before running health check
74
+ extensions: List of extensions to install/load
75
+ extension_flags: Connection-level SET statements applied after creation
76
+ secrets: List of secrets to create
77
+ on_connection_create: Callback executed when connection is created
78
+ """
79
+ self._connection_config = connection_config
80
+ self._recycle = pool_recycle_seconds
81
+ self._health_check_interval = health_check_interval
82
+ self._extensions = extensions or []
83
+ self._extension_flags = extension_flags or {}
84
+ self._secrets = secrets or []
85
+ self._on_connection_create = on_connection_create
86
+ self._thread_local = threading.local()
87
+ self._lock = threading.RLock()
88
+ self._created_connections = 0
89
+ self._connection_times: dict[int, float] = {}
90
+ self._pool_id = str(uuid.uuid4())[:8]
91
+ # Track if this pool uses an in-memory database
92
+ # In-memory databases require connections to stay alive to preserve data
93
+ database = connection_config.get("database", "")
94
+ self._is_memory_db = database.startswith(":memory:") or database == ""
95
+
96
+ @property
97
+ def _database_name(self) -> str:
98
+ """Get sanitized database name for logging."""
99
+ db = self._connection_config.get("database", "")
100
+ if db.startswith(":memory:") or db == "":
101
+ return ":memory:"
102
+ return str(db)
103
+
104
+ def _create_connection(self) -> DuckDBConnection:
105
+ """Create a new DuckDB connection with extensions and secrets."""
106
+ connect_parameters = {}
107
+ config_dict = {}
108
+
109
+ for key, value in self._connection_config.items():
110
+ if key in {"database", "read_only"}:
111
+ connect_parameters[key] = value
112
+ else:
113
+ config_dict[key] = value
114
+
115
+ if config_dict:
116
+ connect_parameters["config"] = config_dict
117
+
118
+ connection = duckdb.connect(**connect_parameters)
119
+
120
+ self._apply_extension_flags(connection)
121
+
122
+ for ext_config in self._extensions:
123
+ ext_name = ext_config.get("name")
124
+ if not ext_name:
125
+ continue
126
+
127
+ install_kwargs = {}
128
+ if "version" in ext_config:
129
+ install_kwargs["version"] = ext_config["version"]
130
+ if "repository" in ext_config:
131
+ install_kwargs["repository"] = ext_config["repository"]
132
+ if ext_config.get("force_install", False):
133
+ install_kwargs["force_install"] = True
134
+
135
+ try:
136
+ if install_kwargs:
137
+ connection.install_extension(ext_name, **install_kwargs)
138
+ connection.load_extension(ext_name)
139
+ except Exception as e:
140
+ log_with_context(
141
+ logger,
142
+ logging.DEBUG,
143
+ "pool.extension.load.failed",
144
+ adapter=_ADAPTER_NAME,
145
+ pool_id=self._pool_id,
146
+ database=self._database_name,
147
+ extension=ext_name,
148
+ error=str(e),
149
+ )
150
+
151
+ for secret_config in self._secrets:
152
+ secret_type = secret_config.get("secret_type")
153
+ secret_name = secret_config.get("name")
154
+ secret_value = secret_config.get("value")
155
+
156
+ if not (secret_type and secret_name and secret_value):
157
+ continue
158
+
159
+ value_pairs = []
160
+ for key, value in secret_value.items():
161
+ escaped_value = str(value).replace("'", "''")
162
+ value_pairs.append(f"'{key}' = '{escaped_value}'")
163
+ value_string = ", ".join(value_pairs)
164
+ scope_clause = ""
165
+ if "scope" in secret_config:
166
+ scope_clause = f" SCOPE '{secret_config['scope']}'"
167
+
168
+ sql = f"""
169
+ CREATE SECRET {secret_name} (
170
+ TYPE {secret_type},
171
+ {value_string}
172
+ ){scope_clause}
173
+ """
174
+ with suppress(Exception):
175
+ connection.execute(sql)
176
+
177
+ if self._on_connection_create:
178
+ with suppress(Exception):
179
+ self._on_connection_create(connection)
180
+
181
+ conn_id = id(connection)
182
+ with self._lock:
183
+ self._created_connections += 1
184
+ self._connection_times[conn_id] = time.time()
185
+
186
+ return connection
187
+
188
+ def _apply_extension_flags(self, connection: DuckDBConnection) -> None:
189
+ """Apply connection-level extension flags via SET statements."""
190
+
191
+ if not self._extension_flags:
192
+ return
193
+
194
+ for key, value in self._extension_flags.items():
195
+ if not key or not key.replace("_", "").isalnum():
196
+ continue
197
+
198
+ normalized = self._normalize_flag_value(value)
199
+ try:
200
+ connection.execute(f"SET {key} = {normalized}")
201
+ except Exception as exc: # pragma: no cover - best-effort guard
202
+ log_with_context(
203
+ logger,
204
+ logging.DEBUG,
205
+ "pool.flag.set.failed",
206
+ adapter=_ADAPTER_NAME,
207
+ pool_id=self._pool_id,
208
+ database=self._database_name,
209
+ flag=key,
210
+ error=str(exc),
211
+ )
212
+
213
+ @staticmethod
214
+ def _normalize_flag_value(value: Any) -> str:
215
+ """Convert Python value to DuckDB SET literal."""
216
+
217
+ if isinstance(value, bool):
218
+ return "TRUE" if value else "FALSE"
219
+ if isinstance(value, (int, float)):
220
+ return str(value)
221
+ escaped = str(value).replace("'", "''")
222
+ return f"'{escaped}'"
223
+
224
+ def _get_thread_connection(self) -> DuckDBConnection:
225
+ """Get or create a connection for the current thread.
226
+
227
+ Each thread gets its own dedicated DuckDB connection to prevent
228
+ thread-safety issues with concurrent cursor operations.
229
+ """
230
+ thread_state = self._thread_local.__dict__
231
+ if "connection" not in thread_state:
232
+ self._thread_local.connection = self._create_connection()
233
+ self._thread_local.created_at = time.time()
234
+ self._thread_local.last_used = time.time()
235
+ return cast("DuckDBConnection", self._thread_local.connection)
236
+
237
+ if self._recycle > 0 and time.time() - self._thread_local.created_at > self._recycle:
238
+ with suppress(Exception):
239
+ self._thread_local.connection.close()
240
+ self._thread_local.connection = self._create_connection()
241
+ self._thread_local.created_at = time.time()
242
+ self._thread_local.last_used = time.time()
243
+ return cast("DuckDBConnection", self._thread_local.connection)
244
+
245
+ idle_time = time.time() - thread_state.get("last_used", 0)
246
+ if idle_time > self._health_check_interval and not self._is_connection_alive(self._thread_local.connection):
247
+ log_with_context(
248
+ logger,
249
+ logging.DEBUG,
250
+ "pool.connection.recycle",
251
+ adapter=_ADAPTER_NAME,
252
+ pool_id=self._pool_id,
253
+ database=self._database_name,
254
+ idle_seconds=round(idle_time, 1),
255
+ reason="failed_health_check",
256
+ )
257
+ with suppress(Exception):
258
+ self._thread_local.connection.close()
259
+ self._thread_local.connection = self._create_connection()
260
+ self._thread_local.created_at = time.time()
261
+
262
+ self._thread_local.last_used = time.time()
263
+ return cast("DuckDBConnection", self._thread_local.connection)
264
+
265
+ def _close_thread_connection(self) -> None:
266
+ """Close the connection for the current thread."""
267
+ thread_state = self._thread_local.__dict__
268
+ if "connection" in thread_state:
269
+ with suppress(Exception):
270
+ self._thread_local.connection.close()
271
+ del self._thread_local.connection
272
+ if "created_at" in thread_state:
273
+ del self._thread_local.created_at
274
+ if "last_used" in thread_state:
275
+ del self._thread_local.last_used
276
+
277
+ def _is_connection_alive(self, connection: DuckDBConnection) -> bool:
278
+ """Check if a connection is still alive and usable.
279
+
280
+ Args:
281
+ connection: Connection to check
282
+
283
+ Returns:
284
+ True if connection is alive, False otherwise
285
+ """
286
+ try:
287
+ cursor = connection.cursor()
288
+ cursor.close()
289
+ except Exception:
290
+ return False
291
+ return True
292
+
293
+ @contextmanager
294
+ def get_connection(self) -> "Generator[DuckDBConnection, None, None]":
295
+ """Get a thread-local connection.
296
+
297
+ Each thread gets its own dedicated DuckDB connection to prevent
298
+ thread-safety issues with concurrent cursor operations.
299
+
300
+ For file-based databases, the connection is closed when the context
301
+ manager exits to release DuckDB's file lock, allowing subsequent
302
+ connections with different configurations.
303
+
304
+ For in-memory databases, connections are kept alive to preserve data,
305
+ as in-memory data is lost when the last connection closes.
306
+
307
+ Yields:
308
+ DuckDBConnection: A thread-local connection.
309
+ """
310
+ connection = self._get_thread_connection()
311
+ try:
312
+ yield connection
313
+ except Exception:
314
+ self._close_thread_connection()
315
+ raise
316
+ else:
317
+ # Only close connection for file-based databases to release file locks
318
+ # In-memory databases need connections to stay alive to preserve data
319
+ if not self._is_memory_db:
320
+ self._close_thread_connection()
321
+
322
+ def close(self) -> None:
323
+ """Close the thread-local connection if it exists."""
324
+ self._close_thread_connection()
325
+
326
+ def size(self) -> int:
327
+ """Get current pool size (always 1 for thread-local)."""
328
+ return 1 if "connection" in self._thread_local.__dict__ else 0
329
+
330
+ def checked_out(self) -> int:
331
+ """Get number of checked out connections (always 0 for thread-local)."""
332
+ return 0
333
+
334
+ def acquire(self) -> DuckDBConnection:
335
+ """Acquire a thread-local connection.
336
+
337
+ Each thread gets its own dedicated DuckDB connection to prevent
338
+ thread-safety issues with concurrent cursor operations.
339
+
340
+ Returns:
341
+ DuckDBConnection: A thread-local connection
342
+ """
343
+ return self._get_thread_connection()
344
+
345
+ def release(self, connection: DuckDBConnection) -> None:
346
+ """Release a connection (no-op for thread-local connections).
347
+
348
+ Args:
349
+ connection: The connection to release (ignored)
350
+ """