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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (531) hide show
  1. ac8f31065839703b4e70__mypyc.cpython-310-aarch64-linux-gnu.so +0 -0
  2. sqlspec/__init__.py +140 -0
  3. sqlspec/__main__.py +12 -0
  4. sqlspec/__metadata__.py +14 -0
  5. sqlspec/_serialization.py +315 -0
  6. sqlspec/_typing.py +700 -0
  7. sqlspec/adapters/__init__.py +0 -0
  8. sqlspec/adapters/adbc/__init__.py +5 -0
  9. sqlspec/adapters/adbc/_typing.py +82 -0
  10. sqlspec/adapters/adbc/adk/__init__.py +5 -0
  11. sqlspec/adapters/adbc/adk/store.py +1273 -0
  12. sqlspec/adapters/adbc/config.py +295 -0
  13. sqlspec/adapters/adbc/core.cpython-310-aarch64-linux-gnu.so +0 -0
  14. sqlspec/adapters/adbc/core.py +735 -0
  15. sqlspec/adapters/adbc/data_dictionary.py +334 -0
  16. sqlspec/adapters/adbc/driver.py +529 -0
  17. sqlspec/adapters/adbc/events/__init__.py +5 -0
  18. sqlspec/adapters/adbc/events/store.py +285 -0
  19. sqlspec/adapters/adbc/litestar/__init__.py +5 -0
  20. sqlspec/adapters/adbc/litestar/store.py +502 -0
  21. sqlspec/adapters/adbc/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  22. sqlspec/adapters/adbc/type_converter.py +140 -0
  23. sqlspec/adapters/aiosqlite/__init__.py +25 -0
  24. sqlspec/adapters/aiosqlite/_typing.py +82 -0
  25. sqlspec/adapters/aiosqlite/adk/__init__.py +5 -0
  26. sqlspec/adapters/aiosqlite/adk/store.py +818 -0
  27. sqlspec/adapters/aiosqlite/config.py +334 -0
  28. sqlspec/adapters/aiosqlite/core.cpython-310-aarch64-linux-gnu.so +0 -0
  29. sqlspec/adapters/aiosqlite/core.py +315 -0
  30. sqlspec/adapters/aiosqlite/data_dictionary.py +208 -0
  31. sqlspec/adapters/aiosqlite/driver.py +313 -0
  32. sqlspec/adapters/aiosqlite/events/__init__.py +5 -0
  33. sqlspec/adapters/aiosqlite/events/store.py +20 -0
  34. sqlspec/adapters/aiosqlite/litestar/__init__.py +5 -0
  35. sqlspec/adapters/aiosqlite/litestar/store.py +279 -0
  36. sqlspec/adapters/aiosqlite/pool.py +533 -0
  37. sqlspec/adapters/asyncmy/__init__.py +21 -0
  38. sqlspec/adapters/asyncmy/_typing.py +87 -0
  39. sqlspec/adapters/asyncmy/adk/__init__.py +5 -0
  40. sqlspec/adapters/asyncmy/adk/store.py +703 -0
  41. sqlspec/adapters/asyncmy/config.py +302 -0
  42. sqlspec/adapters/asyncmy/core.cpython-310-aarch64-linux-gnu.so +0 -0
  43. sqlspec/adapters/asyncmy/core.py +360 -0
  44. sqlspec/adapters/asyncmy/data_dictionary.py +124 -0
  45. sqlspec/adapters/asyncmy/driver.py +383 -0
  46. sqlspec/adapters/asyncmy/events/__init__.py +5 -0
  47. sqlspec/adapters/asyncmy/events/store.py +104 -0
  48. sqlspec/adapters/asyncmy/litestar/__init__.py +5 -0
  49. sqlspec/adapters/asyncmy/litestar/store.py +296 -0
  50. sqlspec/adapters/asyncpg/__init__.py +19 -0
  51. sqlspec/adapters/asyncpg/_typing.py +88 -0
  52. sqlspec/adapters/asyncpg/adk/__init__.py +5 -0
  53. sqlspec/adapters/asyncpg/adk/store.py +748 -0
  54. sqlspec/adapters/asyncpg/config.py +569 -0
  55. sqlspec/adapters/asyncpg/core.cpython-310-aarch64-linux-gnu.so +0 -0
  56. sqlspec/adapters/asyncpg/core.py +367 -0
  57. sqlspec/adapters/asyncpg/data_dictionary.py +162 -0
  58. sqlspec/adapters/asyncpg/driver.py +487 -0
  59. sqlspec/adapters/asyncpg/events/__init__.py +6 -0
  60. sqlspec/adapters/asyncpg/events/backend.py +286 -0
  61. sqlspec/adapters/asyncpg/events/store.py +40 -0
  62. sqlspec/adapters/asyncpg/litestar/__init__.py +5 -0
  63. sqlspec/adapters/asyncpg/litestar/store.py +251 -0
  64. sqlspec/adapters/bigquery/__init__.py +14 -0
  65. sqlspec/adapters/bigquery/_typing.py +86 -0
  66. sqlspec/adapters/bigquery/adk/__init__.py +5 -0
  67. sqlspec/adapters/bigquery/adk/store.py +827 -0
  68. sqlspec/adapters/bigquery/config.py +353 -0
  69. sqlspec/adapters/bigquery/core.cpython-310-aarch64-linux-gnu.so +0 -0
  70. sqlspec/adapters/bigquery/core.py +715 -0
  71. sqlspec/adapters/bigquery/data_dictionary.py +128 -0
  72. sqlspec/adapters/bigquery/driver.py +548 -0
  73. sqlspec/adapters/bigquery/events/__init__.py +5 -0
  74. sqlspec/adapters/bigquery/events/store.py +139 -0
  75. sqlspec/adapters/bigquery/litestar/__init__.py +5 -0
  76. sqlspec/adapters/bigquery/litestar/store.py +325 -0
  77. sqlspec/adapters/bigquery/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  78. sqlspec/adapters/bigquery/type_converter.py +107 -0
  79. sqlspec/adapters/cockroach_asyncpg/__init__.py +24 -0
  80. sqlspec/adapters/cockroach_asyncpg/_typing.py +72 -0
  81. sqlspec/adapters/cockroach_asyncpg/adk/__init__.py +3 -0
  82. sqlspec/adapters/cockroach_asyncpg/adk/store.py +410 -0
  83. sqlspec/adapters/cockroach_asyncpg/config.py +238 -0
  84. sqlspec/adapters/cockroach_asyncpg/core.cpython-310-aarch64-linux-gnu.so +0 -0
  85. sqlspec/adapters/cockroach_asyncpg/core.py +55 -0
  86. sqlspec/adapters/cockroach_asyncpg/data_dictionary.py +107 -0
  87. sqlspec/adapters/cockroach_asyncpg/driver.py +144 -0
  88. sqlspec/adapters/cockroach_asyncpg/events/__init__.py +3 -0
  89. sqlspec/adapters/cockroach_asyncpg/events/store.py +20 -0
  90. sqlspec/adapters/cockroach_asyncpg/litestar/__init__.py +3 -0
  91. sqlspec/adapters/cockroach_asyncpg/litestar/store.py +142 -0
  92. sqlspec/adapters/cockroach_psycopg/__init__.py +38 -0
  93. sqlspec/adapters/cockroach_psycopg/_typing.py +129 -0
  94. sqlspec/adapters/cockroach_psycopg/adk/__init__.py +13 -0
  95. sqlspec/adapters/cockroach_psycopg/adk/store.py +868 -0
  96. sqlspec/adapters/cockroach_psycopg/config.py +484 -0
  97. sqlspec/adapters/cockroach_psycopg/core.cpython-310-aarch64-linux-gnu.so +0 -0
  98. sqlspec/adapters/cockroach_psycopg/core.py +63 -0
  99. sqlspec/adapters/cockroach_psycopg/data_dictionary.py +215 -0
  100. sqlspec/adapters/cockroach_psycopg/driver.py +284 -0
  101. sqlspec/adapters/cockroach_psycopg/events/__init__.py +6 -0
  102. sqlspec/adapters/cockroach_psycopg/events/store.py +34 -0
  103. sqlspec/adapters/cockroach_psycopg/litestar/__init__.py +3 -0
  104. sqlspec/adapters/cockroach_psycopg/litestar/store.py +325 -0
  105. sqlspec/adapters/duckdb/__init__.py +25 -0
  106. sqlspec/adapters/duckdb/_typing.py +81 -0
  107. sqlspec/adapters/duckdb/adk/__init__.py +14 -0
  108. sqlspec/adapters/duckdb/adk/store.py +850 -0
  109. sqlspec/adapters/duckdb/config.py +463 -0
  110. sqlspec/adapters/duckdb/core.cpython-310-aarch64-linux-gnu.so +0 -0
  111. sqlspec/adapters/duckdb/core.py +257 -0
  112. sqlspec/adapters/duckdb/data_dictionary.py +140 -0
  113. sqlspec/adapters/duckdb/driver.py +430 -0
  114. sqlspec/adapters/duckdb/events/__init__.py +5 -0
  115. sqlspec/adapters/duckdb/events/store.py +57 -0
  116. sqlspec/adapters/duckdb/litestar/__init__.py +5 -0
  117. sqlspec/adapters/duckdb/litestar/store.py +330 -0
  118. sqlspec/adapters/duckdb/pool.py +293 -0
  119. sqlspec/adapters/duckdb/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  120. sqlspec/adapters/duckdb/type_converter.py +118 -0
  121. sqlspec/adapters/mock/__init__.py +72 -0
  122. sqlspec/adapters/mock/_typing.py +147 -0
  123. sqlspec/adapters/mock/config.py +483 -0
  124. sqlspec/adapters/mock/core.py +319 -0
  125. sqlspec/adapters/mock/data_dictionary.py +366 -0
  126. sqlspec/adapters/mock/driver.py +721 -0
  127. sqlspec/adapters/mysqlconnector/__init__.py +36 -0
  128. sqlspec/adapters/mysqlconnector/_typing.py +141 -0
  129. sqlspec/adapters/mysqlconnector/adk/__init__.py +15 -0
  130. sqlspec/adapters/mysqlconnector/adk/store.py +1060 -0
  131. sqlspec/adapters/mysqlconnector/config.py +394 -0
  132. sqlspec/adapters/mysqlconnector/core.cpython-310-aarch64-linux-gnu.so +0 -0
  133. sqlspec/adapters/mysqlconnector/core.py +303 -0
  134. sqlspec/adapters/mysqlconnector/data_dictionary.py +235 -0
  135. sqlspec/adapters/mysqlconnector/driver.py +483 -0
  136. sqlspec/adapters/mysqlconnector/events/__init__.py +8 -0
  137. sqlspec/adapters/mysqlconnector/events/store.py +98 -0
  138. sqlspec/adapters/mysqlconnector/litestar/__init__.py +5 -0
  139. sqlspec/adapters/mysqlconnector/litestar/store.py +426 -0
  140. sqlspec/adapters/oracledb/__init__.py +60 -0
  141. sqlspec/adapters/oracledb/_numpy_handlers.py +141 -0
  142. sqlspec/adapters/oracledb/_typing.py +182 -0
  143. sqlspec/adapters/oracledb/_uuid_handlers.py +166 -0
  144. sqlspec/adapters/oracledb/adk/__init__.py +10 -0
  145. sqlspec/adapters/oracledb/adk/store.py +2369 -0
  146. sqlspec/adapters/oracledb/config.py +550 -0
  147. sqlspec/adapters/oracledb/core.cpython-310-aarch64-linux-gnu.so +0 -0
  148. sqlspec/adapters/oracledb/core.py +543 -0
  149. sqlspec/adapters/oracledb/data_dictionary.py +536 -0
  150. sqlspec/adapters/oracledb/driver.py +1229 -0
  151. sqlspec/adapters/oracledb/events/__init__.py +16 -0
  152. sqlspec/adapters/oracledb/events/backend.py +347 -0
  153. sqlspec/adapters/oracledb/events/store.py +420 -0
  154. sqlspec/adapters/oracledb/litestar/__init__.py +5 -0
  155. sqlspec/adapters/oracledb/litestar/store.py +781 -0
  156. sqlspec/adapters/oracledb/migrations.py +535 -0
  157. sqlspec/adapters/oracledb/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  158. sqlspec/adapters/oracledb/type_converter.py +211 -0
  159. sqlspec/adapters/psqlpy/__init__.py +17 -0
  160. sqlspec/adapters/psqlpy/_typing.py +79 -0
  161. sqlspec/adapters/psqlpy/adk/__init__.py +5 -0
  162. sqlspec/adapters/psqlpy/adk/store.py +766 -0
  163. sqlspec/adapters/psqlpy/config.py +304 -0
  164. sqlspec/adapters/psqlpy/core.cpython-310-aarch64-linux-gnu.so +0 -0
  165. sqlspec/adapters/psqlpy/core.py +480 -0
  166. sqlspec/adapters/psqlpy/data_dictionary.py +126 -0
  167. sqlspec/adapters/psqlpy/driver.py +438 -0
  168. sqlspec/adapters/psqlpy/events/__init__.py +6 -0
  169. sqlspec/adapters/psqlpy/events/backend.py +310 -0
  170. sqlspec/adapters/psqlpy/events/store.py +20 -0
  171. sqlspec/adapters/psqlpy/litestar/__init__.py +5 -0
  172. sqlspec/adapters/psqlpy/litestar/store.py +270 -0
  173. sqlspec/adapters/psqlpy/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  174. sqlspec/adapters/psqlpy/type_converter.py +113 -0
  175. sqlspec/adapters/psycopg/__init__.py +32 -0
  176. sqlspec/adapters/psycopg/_typing.py +164 -0
  177. sqlspec/adapters/psycopg/adk/__init__.py +10 -0
  178. sqlspec/adapters/psycopg/adk/store.py +1387 -0
  179. sqlspec/adapters/psycopg/config.py +576 -0
  180. sqlspec/adapters/psycopg/core.cpython-310-aarch64-linux-gnu.so +0 -0
  181. sqlspec/adapters/psycopg/core.py +450 -0
  182. sqlspec/adapters/psycopg/data_dictionary.py +289 -0
  183. sqlspec/adapters/psycopg/driver.py +975 -0
  184. sqlspec/adapters/psycopg/events/__init__.py +20 -0
  185. sqlspec/adapters/psycopg/events/backend.py +458 -0
  186. sqlspec/adapters/psycopg/events/store.py +42 -0
  187. sqlspec/adapters/psycopg/litestar/__init__.py +5 -0
  188. sqlspec/adapters/psycopg/litestar/store.py +552 -0
  189. sqlspec/adapters/psycopg/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  190. sqlspec/adapters/psycopg/type_converter.py +93 -0
  191. sqlspec/adapters/pymysql/__init__.py +21 -0
  192. sqlspec/adapters/pymysql/_typing.py +71 -0
  193. sqlspec/adapters/pymysql/adk/__init__.py +5 -0
  194. sqlspec/adapters/pymysql/adk/store.py +540 -0
  195. sqlspec/adapters/pymysql/config.py +195 -0
  196. sqlspec/adapters/pymysql/core.cpython-310-aarch64-linux-gnu.so +0 -0
  197. sqlspec/adapters/pymysql/core.py +299 -0
  198. sqlspec/adapters/pymysql/data_dictionary.py +122 -0
  199. sqlspec/adapters/pymysql/driver.py +259 -0
  200. sqlspec/adapters/pymysql/events/__init__.py +5 -0
  201. sqlspec/adapters/pymysql/events/store.py +50 -0
  202. sqlspec/adapters/pymysql/litestar/__init__.py +5 -0
  203. sqlspec/adapters/pymysql/litestar/store.py +232 -0
  204. sqlspec/adapters/pymysql/pool.py +137 -0
  205. sqlspec/adapters/spanner/__init__.py +40 -0
  206. sqlspec/adapters/spanner/_typing.py +86 -0
  207. sqlspec/adapters/spanner/adk/__init__.py +5 -0
  208. sqlspec/adapters/spanner/adk/store.py +732 -0
  209. sqlspec/adapters/spanner/config.py +352 -0
  210. sqlspec/adapters/spanner/core.cpython-310-aarch64-linux-gnu.so +0 -0
  211. sqlspec/adapters/spanner/core.py +188 -0
  212. sqlspec/adapters/spanner/data_dictionary.py +120 -0
  213. sqlspec/adapters/spanner/dialect/__init__.py +6 -0
  214. sqlspec/adapters/spanner/dialect/_spangres.py +57 -0
  215. sqlspec/adapters/spanner/dialect/_spanner.py +130 -0
  216. sqlspec/adapters/spanner/driver.py +373 -0
  217. sqlspec/adapters/spanner/events/__init__.py +5 -0
  218. sqlspec/adapters/spanner/events/store.py +187 -0
  219. sqlspec/adapters/spanner/litestar/__init__.py +5 -0
  220. sqlspec/adapters/spanner/litestar/store.py +291 -0
  221. sqlspec/adapters/spanner/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  222. sqlspec/adapters/spanner/type_converter.py +331 -0
  223. sqlspec/adapters/sqlite/__init__.py +19 -0
  224. sqlspec/adapters/sqlite/_typing.py +80 -0
  225. sqlspec/adapters/sqlite/adk/__init__.py +5 -0
  226. sqlspec/adapters/sqlite/adk/store.py +958 -0
  227. sqlspec/adapters/sqlite/config.py +280 -0
  228. sqlspec/adapters/sqlite/core.cpython-310-aarch64-linux-gnu.so +0 -0
  229. sqlspec/adapters/sqlite/core.py +312 -0
  230. sqlspec/adapters/sqlite/data_dictionary.py +202 -0
  231. sqlspec/adapters/sqlite/driver.py +359 -0
  232. sqlspec/adapters/sqlite/events/__init__.py +5 -0
  233. sqlspec/adapters/sqlite/events/store.py +20 -0
  234. sqlspec/adapters/sqlite/litestar/__init__.py +5 -0
  235. sqlspec/adapters/sqlite/litestar/store.py +316 -0
  236. sqlspec/adapters/sqlite/pool.py +198 -0
  237. sqlspec/adapters/sqlite/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  238. sqlspec/adapters/sqlite/type_converter.py +114 -0
  239. sqlspec/base.py +747 -0
  240. sqlspec/builder/__init__.py +179 -0
  241. sqlspec/builder/_base.cpython-310-aarch64-linux-gnu.so +0 -0
  242. sqlspec/builder/_base.py +1022 -0
  243. sqlspec/builder/_column.cpython-310-aarch64-linux-gnu.so +0 -0
  244. sqlspec/builder/_column.py +521 -0
  245. sqlspec/builder/_ddl.cpython-310-aarch64-linux-gnu.so +0 -0
  246. sqlspec/builder/_ddl.py +1642 -0
  247. sqlspec/builder/_delete.cpython-310-aarch64-linux-gnu.so +0 -0
  248. sqlspec/builder/_delete.py +95 -0
  249. sqlspec/builder/_dml.cpython-310-aarch64-linux-gnu.so +0 -0
  250. sqlspec/builder/_dml.py +365 -0
  251. sqlspec/builder/_explain.cpython-310-aarch64-linux-gnu.so +0 -0
  252. sqlspec/builder/_explain.py +579 -0
  253. sqlspec/builder/_expression_wrappers.cpython-310-aarch64-linux-gnu.so +0 -0
  254. sqlspec/builder/_expression_wrappers.py +46 -0
  255. sqlspec/builder/_factory.cpython-310-aarch64-linux-gnu.so +0 -0
  256. sqlspec/builder/_factory.py +1697 -0
  257. sqlspec/builder/_insert.cpython-310-aarch64-linux-gnu.so +0 -0
  258. sqlspec/builder/_insert.py +328 -0
  259. sqlspec/builder/_join.cpython-310-aarch64-linux-gnu.so +0 -0
  260. sqlspec/builder/_join.py +499 -0
  261. sqlspec/builder/_merge.cpython-310-aarch64-linux-gnu.so +0 -0
  262. sqlspec/builder/_merge.py +821 -0
  263. sqlspec/builder/_parsing_utils.cpython-310-aarch64-linux-gnu.so +0 -0
  264. sqlspec/builder/_parsing_utils.py +297 -0
  265. sqlspec/builder/_select.cpython-310-aarch64-linux-gnu.so +0 -0
  266. sqlspec/builder/_select.py +1660 -0
  267. sqlspec/builder/_temporal.cpython-310-aarch64-linux-gnu.so +0 -0
  268. sqlspec/builder/_temporal.py +139 -0
  269. sqlspec/builder/_update.cpython-310-aarch64-linux-gnu.so +0 -0
  270. sqlspec/builder/_update.py +173 -0
  271. sqlspec/builder/_vector_expressions.py +267 -0
  272. sqlspec/cli.py +911 -0
  273. sqlspec/config.py +1755 -0
  274. sqlspec/core/__init__.py +374 -0
  275. sqlspec/core/_correlation.cpython-310-aarch64-linux-gnu.so +0 -0
  276. sqlspec/core/_correlation.py +176 -0
  277. sqlspec/core/cache.cpython-310-aarch64-linux-gnu.so +0 -0
  278. sqlspec/core/cache.py +1069 -0
  279. sqlspec/core/compiler.cpython-310-aarch64-linux-gnu.so +0 -0
  280. sqlspec/core/compiler.py +954 -0
  281. sqlspec/core/explain.cpython-310-aarch64-linux-gnu.so +0 -0
  282. sqlspec/core/explain.py +275 -0
  283. sqlspec/core/filters.cpython-310-aarch64-linux-gnu.so +0 -0
  284. sqlspec/core/filters.py +952 -0
  285. sqlspec/core/hashing.cpython-310-aarch64-linux-gnu.so +0 -0
  286. sqlspec/core/hashing.py +262 -0
  287. sqlspec/core/metrics.cpython-310-aarch64-linux-gnu.so +0 -0
  288. sqlspec/core/metrics.py +83 -0
  289. sqlspec/core/parameters/__init__.py +71 -0
  290. sqlspec/core/parameters/_alignment.cpython-310-aarch64-linux-gnu.so +0 -0
  291. sqlspec/core/parameters/_alignment.py +270 -0
  292. sqlspec/core/parameters/_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  293. sqlspec/core/parameters/_converter.py +543 -0
  294. sqlspec/core/parameters/_processor.cpython-310-aarch64-linux-gnu.so +0 -0
  295. sqlspec/core/parameters/_processor.py +505 -0
  296. sqlspec/core/parameters/_registry.cpython-310-aarch64-linux-gnu.so +0 -0
  297. sqlspec/core/parameters/_registry.py +206 -0
  298. sqlspec/core/parameters/_transformers.cpython-310-aarch64-linux-gnu.so +0 -0
  299. sqlspec/core/parameters/_transformers.py +292 -0
  300. sqlspec/core/parameters/_types.cpython-310-aarch64-linux-gnu.so +0 -0
  301. sqlspec/core/parameters/_types.py +499 -0
  302. sqlspec/core/parameters/_validator.cpython-310-aarch64-linux-gnu.so +0 -0
  303. sqlspec/core/parameters/_validator.py +180 -0
  304. sqlspec/core/pipeline.cpython-310-aarch64-linux-gnu.so +0 -0
  305. sqlspec/core/pipeline.py +319 -0
  306. sqlspec/core/query_modifiers.cpython-310-aarch64-linux-gnu.so +0 -0
  307. sqlspec/core/query_modifiers.py +437 -0
  308. sqlspec/core/result/__init__.py +23 -0
  309. sqlspec/core/result/_base.cpython-310-aarch64-linux-gnu.so +0 -0
  310. sqlspec/core/result/_base.py +1121 -0
  311. sqlspec/core/result/_io.cpython-310-aarch64-linux-gnu.so +0 -0
  312. sqlspec/core/result/_io.py +28 -0
  313. sqlspec/core/splitter.cpython-310-aarch64-linux-gnu.so +0 -0
  314. sqlspec/core/splitter.py +966 -0
  315. sqlspec/core/stack.cpython-310-aarch64-linux-gnu.so +0 -0
  316. sqlspec/core/stack.py +163 -0
  317. sqlspec/core/statement.cpython-310-aarch64-linux-gnu.so +0 -0
  318. sqlspec/core/statement.py +1503 -0
  319. sqlspec/core/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  320. sqlspec/core/type_converter.py +339 -0
  321. sqlspec/data_dictionary/__init__.py +22 -0
  322. sqlspec/data_dictionary/_loader.py +123 -0
  323. sqlspec/data_dictionary/_registry.cpython-310-aarch64-linux-gnu.so +0 -0
  324. sqlspec/data_dictionary/_registry.py +74 -0
  325. sqlspec/data_dictionary/_types.cpython-310-aarch64-linux-gnu.so +0 -0
  326. sqlspec/data_dictionary/_types.py +121 -0
  327. sqlspec/data_dictionary/dialects/__init__.py +21 -0
  328. sqlspec/data_dictionary/dialects/bigquery.cpython-310-aarch64-linux-gnu.so +0 -0
  329. sqlspec/data_dictionary/dialects/bigquery.py +49 -0
  330. sqlspec/data_dictionary/dialects/cockroachdb.cpython-310-aarch64-linux-gnu.so +0 -0
  331. sqlspec/data_dictionary/dialects/cockroachdb.py +43 -0
  332. sqlspec/data_dictionary/dialects/duckdb.cpython-310-aarch64-linux-gnu.so +0 -0
  333. sqlspec/data_dictionary/dialects/duckdb.py +47 -0
  334. sqlspec/data_dictionary/dialects/mysql.cpython-310-aarch64-linux-gnu.so +0 -0
  335. sqlspec/data_dictionary/dialects/mysql.py +42 -0
  336. sqlspec/data_dictionary/dialects/oracle.cpython-310-aarch64-linux-gnu.so +0 -0
  337. sqlspec/data_dictionary/dialects/oracle.py +34 -0
  338. sqlspec/data_dictionary/dialects/postgres.cpython-310-aarch64-linux-gnu.so +0 -0
  339. sqlspec/data_dictionary/dialects/postgres.py +46 -0
  340. sqlspec/data_dictionary/dialects/spanner.cpython-310-aarch64-linux-gnu.so +0 -0
  341. sqlspec/data_dictionary/dialects/spanner.py +37 -0
  342. sqlspec/data_dictionary/dialects/sqlite.cpython-310-aarch64-linux-gnu.so +0 -0
  343. sqlspec/data_dictionary/dialects/sqlite.py +42 -0
  344. sqlspec/data_dictionary/sql/.gitkeep +0 -0
  345. sqlspec/data_dictionary/sql/bigquery/columns.sql +23 -0
  346. sqlspec/data_dictionary/sql/bigquery/foreign_keys.sql +34 -0
  347. sqlspec/data_dictionary/sql/bigquery/indexes.sql +19 -0
  348. sqlspec/data_dictionary/sql/bigquery/tables.sql +33 -0
  349. sqlspec/data_dictionary/sql/bigquery/version.sql +3 -0
  350. sqlspec/data_dictionary/sql/cockroachdb/columns.sql +34 -0
  351. sqlspec/data_dictionary/sql/cockroachdb/foreign_keys.sql +40 -0
  352. sqlspec/data_dictionary/sql/cockroachdb/indexes.sql +32 -0
  353. sqlspec/data_dictionary/sql/cockroachdb/tables.sql +44 -0
  354. sqlspec/data_dictionary/sql/cockroachdb/version.sql +3 -0
  355. sqlspec/data_dictionary/sql/duckdb/columns.sql +23 -0
  356. sqlspec/data_dictionary/sql/duckdb/foreign_keys.sql +36 -0
  357. sqlspec/data_dictionary/sql/duckdb/indexes.sql +19 -0
  358. sqlspec/data_dictionary/sql/duckdb/tables.sql +38 -0
  359. sqlspec/data_dictionary/sql/duckdb/version.sql +3 -0
  360. sqlspec/data_dictionary/sql/mysql/columns.sql +23 -0
  361. sqlspec/data_dictionary/sql/mysql/foreign_keys.sql +28 -0
  362. sqlspec/data_dictionary/sql/mysql/indexes.sql +26 -0
  363. sqlspec/data_dictionary/sql/mysql/tables.sql +33 -0
  364. sqlspec/data_dictionary/sql/mysql/version.sql +3 -0
  365. sqlspec/data_dictionary/sql/oracle/columns.sql +23 -0
  366. sqlspec/data_dictionary/sql/oracle/foreign_keys.sql +48 -0
  367. sqlspec/data_dictionary/sql/oracle/indexes.sql +44 -0
  368. sqlspec/data_dictionary/sql/oracle/tables.sql +25 -0
  369. sqlspec/data_dictionary/sql/oracle/version.sql +20 -0
  370. sqlspec/data_dictionary/sql/postgres/columns.sql +34 -0
  371. sqlspec/data_dictionary/sql/postgres/foreign_keys.sql +40 -0
  372. sqlspec/data_dictionary/sql/postgres/indexes.sql +56 -0
  373. sqlspec/data_dictionary/sql/postgres/tables.sql +44 -0
  374. sqlspec/data_dictionary/sql/postgres/version.sql +3 -0
  375. sqlspec/data_dictionary/sql/spanner/columns.sql +23 -0
  376. sqlspec/data_dictionary/sql/spanner/foreign_keys.sql +70 -0
  377. sqlspec/data_dictionary/sql/spanner/indexes.sql +30 -0
  378. sqlspec/data_dictionary/sql/spanner/tables.sql +9 -0
  379. sqlspec/data_dictionary/sql/spanner/version.sql +3 -0
  380. sqlspec/data_dictionary/sql/sqlite/columns.sql +23 -0
  381. sqlspec/data_dictionary/sql/sqlite/foreign_keys.sql +22 -0
  382. sqlspec/data_dictionary/sql/sqlite/indexes.sql +7 -0
  383. sqlspec/data_dictionary/sql/sqlite/tables.sql +28 -0
  384. sqlspec/data_dictionary/sql/sqlite/version.sql +3 -0
  385. sqlspec/driver/__init__.py +32 -0
  386. sqlspec/driver/_async.cpython-310-aarch64-linux-gnu.so +0 -0
  387. sqlspec/driver/_async.py +1737 -0
  388. sqlspec/driver/_common.cpython-310-aarch64-linux-gnu.so +0 -0
  389. sqlspec/driver/_common.py +1478 -0
  390. sqlspec/driver/_sql_helpers.cpython-310-aarch64-linux-gnu.so +0 -0
  391. sqlspec/driver/_sql_helpers.py +148 -0
  392. sqlspec/driver/_storage_helpers.cpython-310-aarch64-linux-gnu.so +0 -0
  393. sqlspec/driver/_storage_helpers.py +144 -0
  394. sqlspec/driver/_sync.cpython-310-aarch64-linux-gnu.so +0 -0
  395. sqlspec/driver/_sync.py +1710 -0
  396. sqlspec/exceptions.py +338 -0
  397. sqlspec/extensions/__init__.py +0 -0
  398. sqlspec/extensions/adk/__init__.py +70 -0
  399. sqlspec/extensions/adk/_types.py +51 -0
  400. sqlspec/extensions/adk/converters.py +172 -0
  401. sqlspec/extensions/adk/memory/__init__.py +69 -0
  402. sqlspec/extensions/adk/memory/_types.py +30 -0
  403. sqlspec/extensions/adk/memory/converters.py +149 -0
  404. sqlspec/extensions/adk/memory/service.py +217 -0
  405. sqlspec/extensions/adk/memory/store.py +569 -0
  406. sqlspec/extensions/adk/migrations/0001_create_adk_tables.py +246 -0
  407. sqlspec/extensions/adk/migrations/__init__.py +0 -0
  408. sqlspec/extensions/adk/service.py +225 -0
  409. sqlspec/extensions/adk/store.py +567 -0
  410. sqlspec/extensions/events/__init__.py +51 -0
  411. sqlspec/extensions/events/_channel.py +703 -0
  412. sqlspec/extensions/events/_hints.py +45 -0
  413. sqlspec/extensions/events/_models.py +23 -0
  414. sqlspec/extensions/events/_payload.py +69 -0
  415. sqlspec/extensions/events/_protocols.py +134 -0
  416. sqlspec/extensions/events/_queue.py +461 -0
  417. sqlspec/extensions/events/_store.py +209 -0
  418. sqlspec/extensions/events/migrations/0001_create_event_queue.py +59 -0
  419. sqlspec/extensions/events/migrations/__init__.py +3 -0
  420. sqlspec/extensions/fastapi/__init__.py +19 -0
  421. sqlspec/extensions/fastapi/extension.py +351 -0
  422. sqlspec/extensions/fastapi/providers.py +607 -0
  423. sqlspec/extensions/flask/__init__.py +37 -0
  424. sqlspec/extensions/flask/_state.py +76 -0
  425. sqlspec/extensions/flask/_utils.py +71 -0
  426. sqlspec/extensions/flask/extension.py +519 -0
  427. sqlspec/extensions/litestar/__init__.py +28 -0
  428. sqlspec/extensions/litestar/_utils.py +52 -0
  429. sqlspec/extensions/litestar/channels.py +165 -0
  430. sqlspec/extensions/litestar/cli.py +102 -0
  431. sqlspec/extensions/litestar/config.py +90 -0
  432. sqlspec/extensions/litestar/handlers.py +316 -0
  433. sqlspec/extensions/litestar/migrations/0001_create_session_table.py +137 -0
  434. sqlspec/extensions/litestar/migrations/__init__.py +3 -0
  435. sqlspec/extensions/litestar/plugin.py +671 -0
  436. sqlspec/extensions/litestar/providers.py +526 -0
  437. sqlspec/extensions/litestar/store.py +296 -0
  438. sqlspec/extensions/otel/__init__.py +58 -0
  439. sqlspec/extensions/prometheus/__init__.py +113 -0
  440. sqlspec/extensions/starlette/__init__.py +19 -0
  441. sqlspec/extensions/starlette/_state.py +30 -0
  442. sqlspec/extensions/starlette/_utils.py +96 -0
  443. sqlspec/extensions/starlette/extension.py +346 -0
  444. sqlspec/extensions/starlette/middleware.py +235 -0
  445. sqlspec/loader.cpython-310-aarch64-linux-gnu.so +0 -0
  446. sqlspec/loader.py +702 -0
  447. sqlspec/migrations/__init__.py +36 -0
  448. sqlspec/migrations/base.py +731 -0
  449. sqlspec/migrations/commands.py +1232 -0
  450. sqlspec/migrations/context.py +157 -0
  451. sqlspec/migrations/fix.py +204 -0
  452. sqlspec/migrations/loaders.py +443 -0
  453. sqlspec/migrations/runner.py +1172 -0
  454. sqlspec/migrations/templates.py +234 -0
  455. sqlspec/migrations/tracker.py +611 -0
  456. sqlspec/migrations/utils.py +256 -0
  457. sqlspec/migrations/validation.py +207 -0
  458. sqlspec/migrations/version.py +446 -0
  459. sqlspec/observability/__init__.py +55 -0
  460. sqlspec/observability/_common.cpython-310-aarch64-linux-gnu.so +0 -0
  461. sqlspec/observability/_common.py +77 -0
  462. sqlspec/observability/_config.cpython-310-aarch64-linux-gnu.so +0 -0
  463. sqlspec/observability/_config.py +348 -0
  464. sqlspec/observability/_diagnostics.cpython-310-aarch64-linux-gnu.so +0 -0
  465. sqlspec/observability/_diagnostics.py +74 -0
  466. sqlspec/observability/_dispatcher.cpython-310-aarch64-linux-gnu.so +0 -0
  467. sqlspec/observability/_dispatcher.py +152 -0
  468. sqlspec/observability/_formatters/__init__.py +13 -0
  469. sqlspec/observability/_formatters/_aws.cpython-310-aarch64-linux-gnu.so +0 -0
  470. sqlspec/observability/_formatters/_aws.py +102 -0
  471. sqlspec/observability/_formatters/_azure.cpython-310-aarch64-linux-gnu.so +0 -0
  472. sqlspec/observability/_formatters/_azure.py +96 -0
  473. sqlspec/observability/_formatters/_base.cpython-310-aarch64-linux-gnu.so +0 -0
  474. sqlspec/observability/_formatters/_base.py +57 -0
  475. sqlspec/observability/_formatters/_gcp.cpython-310-aarch64-linux-gnu.so +0 -0
  476. sqlspec/observability/_formatters/_gcp.py +131 -0
  477. sqlspec/observability/_formatting.py +58 -0
  478. sqlspec/observability/_observer.cpython-310-aarch64-linux-gnu.so +0 -0
  479. sqlspec/observability/_observer.py +357 -0
  480. sqlspec/observability/_runtime.cpython-310-aarch64-linux-gnu.so +0 -0
  481. sqlspec/observability/_runtime.py +420 -0
  482. sqlspec/observability/_sampling.cpython-310-aarch64-linux-gnu.so +0 -0
  483. sqlspec/observability/_sampling.py +188 -0
  484. sqlspec/observability/_spans.cpython-310-aarch64-linux-gnu.so +0 -0
  485. sqlspec/observability/_spans.py +161 -0
  486. sqlspec/protocols.py +916 -0
  487. sqlspec/py.typed +0 -0
  488. sqlspec/storage/__init__.py +48 -0
  489. sqlspec/storage/_utils.py +104 -0
  490. sqlspec/storage/backends/__init__.py +1 -0
  491. sqlspec/storage/backends/base.py +253 -0
  492. sqlspec/storage/backends/fsspec.py +529 -0
  493. sqlspec/storage/backends/local.py +441 -0
  494. sqlspec/storage/backends/obstore.py +916 -0
  495. sqlspec/storage/errors.py +104 -0
  496. sqlspec/storage/pipeline.py +582 -0
  497. sqlspec/storage/registry.py +301 -0
  498. sqlspec/typing.py +395 -0
  499. sqlspec/utils/__init__.py +7 -0
  500. sqlspec/utils/arrow_helpers.py +318 -0
  501. sqlspec/utils/config_tools.py +332 -0
  502. sqlspec/utils/correlation.cpython-310-aarch64-linux-gnu.so +0 -0
  503. sqlspec/utils/correlation.py +134 -0
  504. sqlspec/utils/deprecation.py +190 -0
  505. sqlspec/utils/fixtures.cpython-310-aarch64-linux-gnu.so +0 -0
  506. sqlspec/utils/fixtures.py +258 -0
  507. sqlspec/utils/logging.py +222 -0
  508. sqlspec/utils/module_loader.py +306 -0
  509. sqlspec/utils/portal.cpython-310-aarch64-linux-gnu.so +0 -0
  510. sqlspec/utils/portal.py +375 -0
  511. sqlspec/utils/schema.cpython-310-aarch64-linux-gnu.so +0 -0
  512. sqlspec/utils/schema.py +485 -0
  513. sqlspec/utils/serializers.cpython-310-aarch64-linux-gnu.so +0 -0
  514. sqlspec/utils/serializers.py +408 -0
  515. sqlspec/utils/singleton.cpython-310-aarch64-linux-gnu.so +0 -0
  516. sqlspec/utils/singleton.py +41 -0
  517. sqlspec/utils/sync_tools.cpython-310-aarch64-linux-gnu.so +0 -0
  518. sqlspec/utils/sync_tools.py +311 -0
  519. sqlspec/utils/text.cpython-310-aarch64-linux-gnu.so +0 -0
  520. sqlspec/utils/text.py +108 -0
  521. sqlspec/utils/type_converters.cpython-310-aarch64-linux-gnu.so +0 -0
  522. sqlspec/utils/type_converters.py +128 -0
  523. sqlspec/utils/type_guards.cpython-310-aarch64-linux-gnu.so +0 -0
  524. sqlspec/utils/type_guards.py +1360 -0
  525. sqlspec/utils/uuids.cpython-310-aarch64-linux-gnu.so +0 -0
  526. sqlspec/utils/uuids.py +225 -0
  527. sqlspec-0.36.0.dist-info/METADATA +205 -0
  528. sqlspec-0.36.0.dist-info/RECORD +531 -0
  529. sqlspec-0.36.0.dist-info/WHEEL +7 -0
  530. sqlspec-0.36.0.dist-info/entry_points.txt +2 -0
  531. sqlspec-0.36.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,850 @@
1
+ """DuckDB ADK store for Google Agent Development Kit.
2
+
3
+ DuckDB is an OLAP database optimized for analytical queries. This adapter provides:
4
+ - Embedded session storage with zero-configuration setup
5
+ - Excellent performance for analytical queries on session data
6
+ - Native JSON type support for flexible state storage
7
+ - Perfect for development, testing, and analytical workloads
8
+
9
+ Notes:
10
+ DuckDB is optimized for OLAP workloads and analytical queries. For highly
11
+ concurrent DML operations (frequent inserts/updates/deletes), consider
12
+ PostgreSQL or other OLTP-optimized databases.
13
+ """
14
+
15
+ import contextlib
16
+ from datetime import datetime, timezone
17
+ from typing import TYPE_CHECKING, Any, Final, cast
18
+
19
+ from sqlspec.extensions.adk import BaseSyncADKStore, EventRecord, SessionRecord
20
+ from sqlspec.extensions.adk.memory.store import BaseSyncADKMemoryStore
21
+ from sqlspec.utils.logging import get_logger
22
+ from sqlspec.utils.serializers import from_json, to_json
23
+
24
+ if TYPE_CHECKING:
25
+ from sqlspec.adapters.duckdb.config import DuckDBConfig
26
+ from sqlspec.extensions.adk import MemoryRecord
27
+
28
+
29
+ __all__ = ("DuckdbADKMemoryStore", "DuckdbADKStore")
30
+
31
+ logger = get_logger("sqlspec.adapters.duckdb.adk.store")
32
+
33
+ DUCKDB_TABLE_NOT_FOUND_ERROR: Final = "does not exist"
34
+
35
+
36
+ class DuckdbADKStore(BaseSyncADKStore["DuckDBConfig"]):
37
+ """DuckDB ADK store for Google Agent Development Kit.
38
+
39
+ Implements session and event storage for Google Agent Development Kit
40
+ using DuckDB's synchronous driver. Provides:
41
+ - Session state management with native JSON type
42
+ - Event history tracking with BLOB-serialized actions
43
+ - Native TIMESTAMP type support
44
+ - Foreign key constraints (manual cascade in delete_session)
45
+ - Columnar storage for analytical queries
46
+
47
+ Args:
48
+ config: DuckDBConfig with extension_config["adk"] settings.
49
+
50
+ Example:
51
+ from sqlspec.adapters.duckdb import DuckDBConfig
52
+ from sqlspec.adapters.duckdb.adk import DuckdbADKStore
53
+
54
+ config = DuckDBConfig(
55
+ database="sessions.ddb",
56
+ extension_config={
57
+ "adk": {
58
+ "session_table": "my_sessions",
59
+ "events_table": "my_events",
60
+ "owner_id_column": "tenant_id INTEGER REFERENCES tenants(id)"
61
+ }
62
+ }
63
+ )
64
+ store = DuckdbADKStore(config)
65
+ store.ensure_tables()
66
+
67
+ session = store.create_session(
68
+ session_id="session-123",
69
+ app_name="my-app",
70
+ user_id="user-456",
71
+ state={"context": "conversation"}
72
+ )
73
+
74
+ Notes:
75
+ - Uses DuckDB native JSON type (not JSONB)
76
+ - TIMESTAMP for date/time storage with microsecond precision
77
+ - BLOB for binary actions data
78
+ - BOOLEAN native type support
79
+ - Columnar storage provides excellent analytical query performance
80
+ - DuckDB doesn't support CASCADE in foreign keys (manual cascade required)
81
+ - Optimized for OLAP workloads; for high-concurrency writes use PostgreSQL
82
+ - Configuration is read from config.extension_config["adk"]
83
+ """
84
+
85
+ __slots__ = ()
86
+
87
+ def __init__(self, config: "DuckDBConfig") -> None:
88
+ """Initialize DuckDB ADK store.
89
+
90
+ Args:
91
+ config: DuckDBConfig instance.
92
+
93
+ Notes:
94
+ Configuration is read from config.extension_config["adk"]:
95
+ - session_table: Sessions table name (default: "adk_sessions")
96
+ - events_table: Events table name (default: "adk_events")
97
+ - owner_id_column: Optional owner FK column DDL (default: None)
98
+ """
99
+ super().__init__(config)
100
+
101
+ def _get_create_sessions_table_sql(self) -> str:
102
+ """Get DuckDB CREATE TABLE SQL for sessions.
103
+
104
+ Returns:
105
+ SQL statement to create adk_sessions table with indexes.
106
+
107
+ Notes:
108
+ - VARCHAR for IDs and names
109
+ - JSON type for state storage (DuckDB native)
110
+ - TIMESTAMP for create_time and update_time
111
+ - CURRENT_TIMESTAMP for defaults
112
+ - Optional owner ID column for multi-tenant scenarios
113
+ - Composite index on (app_name, user_id) for listing
114
+ - Index on update_time DESC for recent session queries
115
+ """
116
+ owner_id_line = ""
117
+ if self._owner_id_column_ddl:
118
+ owner_id_line = f",\n {self._owner_id_column_ddl}"
119
+
120
+ return f"""
121
+ CREATE TABLE IF NOT EXISTS {self._session_table} (
122
+ id VARCHAR PRIMARY KEY,
123
+ app_name VARCHAR NOT NULL,
124
+ user_id VARCHAR NOT NULL{owner_id_line},
125
+ state JSON NOT NULL,
126
+ create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
127
+ update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
128
+ );
129
+ CREATE INDEX IF NOT EXISTS idx_{self._session_table}_app_user ON {self._session_table}(app_name, user_id);
130
+ CREATE INDEX IF NOT EXISTS idx_{self._session_table}_update_time ON {self._session_table}(update_time DESC);
131
+ """
132
+
133
+ def _get_create_events_table_sql(self) -> str:
134
+ """Get DuckDB CREATE TABLE SQL for events.
135
+
136
+ Returns:
137
+ SQL statement to create adk_events table with indexes.
138
+
139
+ Notes:
140
+ - VARCHAR for string fields
141
+ - BLOB for pickled actions
142
+ - JSON for content, grounding_metadata, custom_metadata, long_running_tool_ids_json
143
+ - BOOLEAN for flags
144
+ - Foreign key constraint (DuckDB doesn't support CASCADE)
145
+ - Index on (session_id, timestamp ASC) for ordered event retrieval
146
+ - Manual cascade delete required in delete_session method
147
+ """
148
+ return f"""
149
+ CREATE TABLE IF NOT EXISTS {self._events_table} (
150
+ id VARCHAR PRIMARY KEY,
151
+ session_id VARCHAR NOT NULL,
152
+ app_name VARCHAR NOT NULL,
153
+ user_id VARCHAR NOT NULL,
154
+ invocation_id VARCHAR,
155
+ author VARCHAR,
156
+ actions BLOB,
157
+ long_running_tool_ids_json JSON,
158
+ branch VARCHAR,
159
+ timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
160
+ content JSON,
161
+ grounding_metadata JSON,
162
+ custom_metadata JSON,
163
+ partial BOOLEAN,
164
+ turn_complete BOOLEAN,
165
+ interrupted BOOLEAN,
166
+ error_code VARCHAR,
167
+ error_message VARCHAR,
168
+ FOREIGN KEY (session_id) REFERENCES {self._session_table}(id)
169
+ );
170
+ CREATE INDEX IF NOT EXISTS idx_{self._events_table}_session ON {self._events_table}(session_id, timestamp ASC);
171
+ """
172
+
173
+ def _get_drop_tables_sql(self) -> "list[str]":
174
+ """Get DuckDB DROP TABLE SQL statements.
175
+
176
+ Returns:
177
+ List of SQL statements to drop tables and indexes.
178
+
179
+ Notes:
180
+ Order matters: drop events table (child) before sessions (parent).
181
+ DuckDB automatically drops indexes when dropping tables.
182
+ """
183
+ return [f"DROP TABLE IF EXISTS {self._events_table}", f"DROP TABLE IF EXISTS {self._session_table}"]
184
+
185
+ def create_tables(self) -> None:
186
+ """Create both sessions and events tables if they don't exist."""
187
+ with self._config.provide_connection() as conn:
188
+ conn.execute(self._get_create_sessions_table_sql())
189
+ conn.execute(self._get_create_events_table_sql())
190
+
191
+ def create_session(
192
+ self, session_id: str, app_name: str, user_id: str, state: "dict[str, Any]", owner_id: "Any | None" = None
193
+ ) -> SessionRecord:
194
+ """Create a new session.
195
+
196
+ Args:
197
+ session_id: Unique session identifier.
198
+ app_name: Application name.
199
+ user_id: User identifier.
200
+ state: Initial session state.
201
+ owner_id: Optional owner ID value for owner_id_column (if configured).
202
+
203
+ Returns:
204
+ Created session record.
205
+
206
+ Notes:
207
+ Uses current UTC timestamp for create_time and update_time.
208
+ State is JSON-serialized using SQLSpec serializers.
209
+ """
210
+ now = datetime.now(timezone.utc)
211
+ state_json = to_json(state)
212
+
213
+ params: tuple[Any, ...]
214
+ if self._owner_id_column_name:
215
+ sql = f"""
216
+ INSERT INTO {self._session_table}
217
+ (id, app_name, user_id, {self._owner_id_column_name}, state, create_time, update_time)
218
+ VALUES (?, ?, ?, ?, ?, ?, ?)
219
+ """
220
+ params = (session_id, app_name, user_id, owner_id, state_json, now, now)
221
+ else:
222
+ sql = f"""
223
+ INSERT INTO {self._session_table} (id, app_name, user_id, state, create_time, update_time)
224
+ VALUES (?, ?, ?, ?, ?, ?)
225
+ """
226
+ params = (session_id, app_name, user_id, state_json, now, now)
227
+
228
+ with self._config.provide_connection() as conn:
229
+ conn.execute(sql, params)
230
+ conn.commit()
231
+
232
+ return SessionRecord(
233
+ id=session_id, app_name=app_name, user_id=user_id, state=state, create_time=now, update_time=now
234
+ )
235
+
236
+ def get_session(self, session_id: str) -> "SessionRecord | None":
237
+ """Get session by ID.
238
+
239
+ Args:
240
+ session_id: Session identifier.
241
+
242
+ Returns:
243
+ Session record or None if not found.
244
+
245
+ Notes:
246
+ DuckDB returns datetime objects for TIMESTAMP columns.
247
+ JSON is parsed from database storage.
248
+ """
249
+ sql = f"""
250
+ SELECT id, app_name, user_id, state, create_time, update_time
251
+ FROM {self._session_table}
252
+ WHERE id = ?
253
+ """
254
+
255
+ try:
256
+ with self._config.provide_connection() as conn:
257
+ cursor = conn.execute(sql, (session_id,))
258
+ row = cursor.fetchone()
259
+
260
+ if row is None:
261
+ return None
262
+
263
+ session_id_val, app_name, user_id, state_data, create_time, update_time = row
264
+
265
+ state = from_json(state_data) if state_data else {}
266
+
267
+ return SessionRecord(
268
+ id=session_id_val,
269
+ app_name=app_name,
270
+ user_id=user_id,
271
+ state=state,
272
+ create_time=create_time,
273
+ update_time=update_time,
274
+ )
275
+ except Exception as e:
276
+ if DUCKDB_TABLE_NOT_FOUND_ERROR in str(e):
277
+ return None
278
+ raise
279
+
280
+ def update_session_state(self, session_id: str, state: "dict[str, Any]") -> None:
281
+ """Update session state.
282
+
283
+ Args:
284
+ session_id: Session identifier.
285
+ state: New state dictionary (replaces existing state).
286
+
287
+ Notes:
288
+ This replaces the entire state dictionary.
289
+ Update time is automatically set to current UTC timestamp.
290
+ """
291
+ now = datetime.now(timezone.utc)
292
+ state_json = to_json(state)
293
+
294
+ sql = f"""
295
+ UPDATE {self._session_table}
296
+ SET state = ?, update_time = ?
297
+ WHERE id = ?
298
+ """
299
+
300
+ with self._config.provide_connection() as conn:
301
+ conn.execute(sql, (state_json, now, session_id))
302
+ conn.commit()
303
+
304
+ def delete_session(self, session_id: str) -> None:
305
+ """Delete session and all associated events.
306
+
307
+ Args:
308
+ session_id: Session identifier.
309
+
310
+ Notes:
311
+ DuckDB doesn't support CASCADE in foreign keys, so we manually delete events first.
312
+ """
313
+ delete_events_sql = f"DELETE FROM {self._events_table} WHERE session_id = ?"
314
+ delete_session_sql = f"DELETE FROM {self._session_table} WHERE id = ?"
315
+
316
+ with self._config.provide_connection() as conn:
317
+ conn.execute(delete_events_sql, (session_id,))
318
+ conn.execute(delete_session_sql, (session_id,))
319
+ conn.commit()
320
+
321
+ def list_sessions(self, app_name: str, user_id: str | None = None) -> "list[SessionRecord]":
322
+ """List sessions for an app, optionally filtered by user.
323
+
324
+ Args:
325
+ app_name: Application name.
326
+ user_id: User identifier. If None, lists all sessions for the app.
327
+
328
+ Returns:
329
+ List of session records ordered by update_time DESC.
330
+
331
+ Notes:
332
+ Uses composite index on (app_name, user_id) when user_id is provided.
333
+ """
334
+ if user_id is None:
335
+ sql = f"""
336
+ SELECT id, app_name, user_id, state, create_time, update_time
337
+ FROM {self._session_table}
338
+ WHERE app_name = ?
339
+ ORDER BY update_time DESC
340
+ """
341
+ params: tuple[str, ...] = (app_name,)
342
+ else:
343
+ sql = f"""
344
+ SELECT id, app_name, user_id, state, create_time, update_time
345
+ FROM {self._session_table}
346
+ WHERE app_name = ? AND user_id = ?
347
+ ORDER BY update_time DESC
348
+ """
349
+ params = (app_name, user_id)
350
+
351
+ try:
352
+ with self._config.provide_connection() as conn:
353
+ cursor = conn.execute(sql, params)
354
+ rows = cursor.fetchall()
355
+
356
+ return [
357
+ SessionRecord(
358
+ id=row[0],
359
+ app_name=row[1],
360
+ user_id=row[2],
361
+ state=from_json(row[3]) if row[3] else {},
362
+ create_time=row[4],
363
+ update_time=row[5],
364
+ )
365
+ for row in rows
366
+ ]
367
+ except Exception as e:
368
+ if DUCKDB_TABLE_NOT_FOUND_ERROR in str(e):
369
+ return []
370
+ raise
371
+
372
+ def create_event(
373
+ self,
374
+ event_id: str,
375
+ session_id: str,
376
+ app_name: str,
377
+ user_id: str,
378
+ author: "str | None" = None,
379
+ actions: "bytes | None" = None,
380
+ content: "dict[str, Any] | None" = None,
381
+ **kwargs: Any,
382
+ ) -> EventRecord:
383
+ """Create a new event.
384
+
385
+ Args:
386
+ event_id: Unique event identifier.
387
+ session_id: Session identifier.
388
+ app_name: Application name.
389
+ user_id: User identifier.
390
+ author: Event author (user/assistant/system).
391
+ actions: Pickled actions object.
392
+ content: Event content (JSON).
393
+ **kwargs: Additional optional fields.
394
+
395
+ Returns:
396
+ Created event record.
397
+
398
+ Notes:
399
+ Uses current UTC timestamp if not provided in kwargs.
400
+ JSON fields are serialized using SQLSpec serializers.
401
+ """
402
+ timestamp = kwargs.get("timestamp", datetime.now(timezone.utc))
403
+ content_json = to_json(content) if content else None
404
+ grounding_metadata = kwargs.get("grounding_metadata")
405
+ grounding_metadata_json = to_json(grounding_metadata) if grounding_metadata else None
406
+ custom_metadata = kwargs.get("custom_metadata")
407
+ custom_metadata_json = to_json(custom_metadata) if custom_metadata else None
408
+
409
+ sql = f"""
410
+ INSERT INTO {self._events_table} (
411
+ id, session_id, app_name, user_id, invocation_id, author, actions,
412
+ long_running_tool_ids_json, branch, timestamp, content,
413
+ grounding_metadata, custom_metadata, partial, turn_complete,
414
+ interrupted, error_code, error_message
415
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
416
+ """
417
+
418
+ with self._config.provide_connection() as conn:
419
+ conn.execute(
420
+ sql,
421
+ (
422
+ event_id,
423
+ session_id,
424
+ app_name,
425
+ user_id,
426
+ kwargs.get("invocation_id"),
427
+ author,
428
+ actions,
429
+ kwargs.get("long_running_tool_ids_json"),
430
+ kwargs.get("branch"),
431
+ timestamp,
432
+ content_json,
433
+ grounding_metadata_json,
434
+ custom_metadata_json,
435
+ kwargs.get("partial"),
436
+ kwargs.get("turn_complete"),
437
+ kwargs.get("interrupted"),
438
+ kwargs.get("error_code"),
439
+ kwargs.get("error_message"),
440
+ ),
441
+ )
442
+ conn.commit()
443
+
444
+ return EventRecord(
445
+ id=event_id,
446
+ session_id=session_id,
447
+ app_name=app_name,
448
+ user_id=user_id,
449
+ invocation_id=kwargs.get("invocation_id", ""),
450
+ author=author or "",
451
+ actions=actions or b"",
452
+ long_running_tool_ids_json=kwargs.get("long_running_tool_ids_json"),
453
+ branch=kwargs.get("branch"),
454
+ timestamp=timestamp,
455
+ content=content,
456
+ grounding_metadata=grounding_metadata,
457
+ custom_metadata=custom_metadata,
458
+ partial=kwargs.get("partial"),
459
+ turn_complete=kwargs.get("turn_complete"),
460
+ interrupted=kwargs.get("interrupted"),
461
+ error_code=kwargs.get("error_code"),
462
+ error_message=kwargs.get("error_message"),
463
+ )
464
+
465
+ def get_event(self, event_id: str) -> "EventRecord | None":
466
+ """Get event by ID.
467
+
468
+ Args:
469
+ event_id: Event identifier.
470
+
471
+ Returns:
472
+ Event record or None if not found.
473
+ """
474
+ sql = f"""
475
+ SELECT id, session_id, app_name, user_id, invocation_id, author, actions,
476
+ long_running_tool_ids_json, branch, timestamp, content,
477
+ grounding_metadata, custom_metadata, partial, turn_complete,
478
+ interrupted, error_code, error_message
479
+ FROM {self._events_table}
480
+ WHERE id = ?
481
+ """
482
+
483
+ try:
484
+ with self._config.provide_connection() as conn:
485
+ cursor = conn.execute(sql, (event_id,))
486
+ row = cursor.fetchone()
487
+
488
+ if row is None:
489
+ return None
490
+
491
+ return EventRecord(
492
+ id=row[0],
493
+ session_id=row[1],
494
+ app_name=row[2],
495
+ user_id=row[3],
496
+ invocation_id=row[4],
497
+ author=row[5],
498
+ actions=bytes(row[6]) if row[6] else b"",
499
+ long_running_tool_ids_json=row[7],
500
+ branch=row[8],
501
+ timestamp=row[9],
502
+ content=from_json(row[10]) if row[10] else None,
503
+ grounding_metadata=from_json(row[11]) if row[11] else None,
504
+ custom_metadata=from_json(row[12]) if row[12] else None,
505
+ partial=row[13],
506
+ turn_complete=row[14],
507
+ interrupted=row[15],
508
+ error_code=row[16],
509
+ error_message=row[17],
510
+ )
511
+ except Exception as e:
512
+ if DUCKDB_TABLE_NOT_FOUND_ERROR in str(e):
513
+ return None
514
+ raise
515
+
516
+ def list_events(self, session_id: str) -> "list[EventRecord]":
517
+ """List events for a session ordered by timestamp.
518
+
519
+ Args:
520
+ session_id: Session identifier.
521
+
522
+ Returns:
523
+ List of event records ordered by timestamp ASC.
524
+ """
525
+ sql = f"""
526
+ SELECT id, session_id, app_name, user_id, invocation_id, author, actions,
527
+ long_running_tool_ids_json, branch, timestamp, content,
528
+ grounding_metadata, custom_metadata, partial, turn_complete,
529
+ interrupted, error_code, error_message
530
+ FROM {self._events_table}
531
+ WHERE session_id = ?
532
+ ORDER BY timestamp ASC
533
+ """
534
+
535
+ try:
536
+ with self._config.provide_connection() as conn:
537
+ cursor = conn.execute(sql, (session_id,))
538
+ rows = cursor.fetchall()
539
+
540
+ return [
541
+ EventRecord(
542
+ id=row[0],
543
+ session_id=row[1],
544
+ app_name=row[2],
545
+ user_id=row[3],
546
+ invocation_id=row[4],
547
+ author=row[5],
548
+ actions=bytes(row[6]) if row[6] else b"",
549
+ long_running_tool_ids_json=row[7],
550
+ branch=row[8],
551
+ timestamp=row[9],
552
+ content=from_json(row[10]) if row[10] else None,
553
+ grounding_metadata=from_json(row[11]) if row[11] else None,
554
+ custom_metadata=from_json(row[12]) if row[12] else None,
555
+ partial=row[13],
556
+ turn_complete=row[14],
557
+ interrupted=row[15],
558
+ error_code=row[16],
559
+ error_message=row[17],
560
+ )
561
+ for row in rows
562
+ ]
563
+ except Exception as e:
564
+ if DUCKDB_TABLE_NOT_FOUND_ERROR in str(e):
565
+ return []
566
+ raise
567
+
568
+
569
+ class DuckdbADKMemoryStore(BaseSyncADKMemoryStore["DuckDBConfig"]):
570
+ """DuckDB ADK memory store using synchronous DuckDB driver.
571
+
572
+ Implements memory entry storage for Google Agent Development Kit
573
+ using DuckDB's synchronous driver. Provides:
574
+ - Session memory storage with native JSON type
575
+ - Simple ILIKE search
576
+ - Native TIMESTAMP type support
577
+ - Deduplication via event_id unique constraint
578
+ - Efficient upserts using INSERT OR IGNORE
579
+ - Columnar storage for analytical queries
580
+
581
+ Args:
582
+ config: DuckDBConfig with extension_config["adk"] settings.
583
+
584
+ Example:
585
+ from sqlspec.adapters.duckdb import DuckDBConfig
586
+ from sqlspec.adapters.duckdb.adk.store import DuckdbADKMemoryStore
587
+
588
+ config = DuckDBConfig(
589
+ database="app.ddb",
590
+ extension_config={
591
+ "adk": {
592
+ "memory_table": "adk_memory_entries",
593
+ "memory_max_results": 20,
594
+ }
595
+ }
596
+ )
597
+ store = DuckdbADKMemoryStore(config)
598
+ store.ensure_tables()
599
+
600
+ Notes:
601
+ - Uses DuckDB native JSON type (not JSONB)
602
+ - TIMESTAMP for date/time storage with microsecond precision
603
+ - event_id UNIQUE constraint for deduplication
604
+ - Composite index on (app_name, user_id, timestamp DESC)
605
+ - Columnar storage provides excellent analytical query performance
606
+ - Optimized for OLAP workloads; for high-concurrency writes use PostgreSQL
607
+ - Configuration is read from config.extension_config["adk"]
608
+ """
609
+
610
+ __slots__ = ()
611
+
612
+ def __init__(self, config: "DuckDBConfig") -> None:
613
+ """Initialize DuckDB ADK memory store.
614
+
615
+ Args:
616
+ config: DuckDBConfig instance.
617
+
618
+ Notes:
619
+ Configuration is read from config.extension_config["adk"]:
620
+ - memory_table: Memory table name (default: "adk_memory_entries")
621
+ - memory_use_fts: Enable full-text search when supported (default: False)
622
+ - memory_max_results: Max search results (default: 20)
623
+ - owner_id_column: Optional owner FK column DDL (default: None)
624
+ - enable_memory: Whether memory is enabled (default: True)
625
+ """
626
+ super().__init__(config)
627
+
628
+ def _ensure_fts_extension(self, conn: Any) -> bool:
629
+ """Ensure the DuckDB FTS extension is available for this connection."""
630
+ with contextlib.suppress(Exception):
631
+ conn.execute("INSTALL fts")
632
+
633
+ try:
634
+ conn.execute("LOAD fts")
635
+ except Exception as exc:
636
+ logger.debug("DuckDB FTS extension unavailable: %s", exc)
637
+ return False
638
+
639
+ return True
640
+
641
+ def _create_fts_index(self, conn: Any) -> None:
642
+ """Create FTS index for the memory table."""
643
+ if not self._ensure_fts_extension(conn):
644
+ return
645
+
646
+ try:
647
+ conn.execute(f"PRAGMA create_fts_index('{self._memory_table}', 'id', 'content_text')")
648
+ except Exception as exc:
649
+ logger.debug("Failed to create DuckDB FTS index: %s", exc)
650
+
651
+ def _refresh_fts_index(self, conn: Any) -> None:
652
+ """Rebuild the FTS index to reflect recent changes."""
653
+ if not self._ensure_fts_extension(conn):
654
+ return
655
+
656
+ with contextlib.suppress(Exception):
657
+ conn.execute(f"PRAGMA drop_fts_index('{self._memory_table}')")
658
+
659
+ try:
660
+ conn.execute(f"PRAGMA create_fts_index('{self._memory_table}', 'id', 'content_text')")
661
+ except Exception as exc:
662
+ logger.debug("Failed to refresh DuckDB FTS index: %s", exc)
663
+
664
+ def _get_create_memory_table_sql(self) -> str:
665
+ """Get DuckDB CREATE TABLE SQL for memory entries.
666
+
667
+ Returns:
668
+ SQL statement to create memory table with indexes.
669
+ """
670
+ owner_id_line = ""
671
+ if self._owner_id_column_ddl:
672
+ owner_id_line = f",\n {self._owner_id_column_ddl}"
673
+
674
+ return f"""
675
+ CREATE TABLE IF NOT EXISTS {self._memory_table} (
676
+ id VARCHAR(128) PRIMARY KEY,
677
+ session_id VARCHAR(128) NOT NULL,
678
+ app_name VARCHAR(128) NOT NULL,
679
+ user_id VARCHAR(128) NOT NULL,
680
+ event_id VARCHAR(128) NOT NULL UNIQUE,
681
+ author VARCHAR(256){owner_id_line},
682
+ timestamp TIMESTAMP NOT NULL,
683
+ content_json JSON NOT NULL,
684
+ content_text TEXT NOT NULL,
685
+ metadata_json JSON,
686
+ inserted_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
687
+ );
688
+
689
+ CREATE INDEX IF NOT EXISTS idx_{self._memory_table}_app_user_time
690
+ ON {self._memory_table}(app_name, user_id, timestamp DESC);
691
+
692
+ CREATE INDEX IF NOT EXISTS idx_{self._memory_table}_session
693
+ ON {self._memory_table}(session_id);
694
+ """
695
+
696
+ def _get_drop_memory_table_sql(self) -> "list[str]":
697
+ """Get DuckDB DROP TABLE SQL statements."""
698
+ return [f"DROP TABLE IF EXISTS {self._memory_table}"]
699
+
700
+ def create_tables(self) -> None:
701
+ """Create the memory table and indexes if they don't exist."""
702
+ if not self._enabled:
703
+ return
704
+
705
+ with self._config.provide_connection() as conn:
706
+ conn.execute(self._get_create_memory_table_sql())
707
+ if self._use_fts:
708
+ self._create_fts_index(conn)
709
+
710
+ def insert_memory_entries(self, entries: "list[MemoryRecord]", owner_id: "object | None" = None) -> int:
711
+ """Bulk insert memory entries with deduplication."""
712
+ if not self._enabled:
713
+ msg = "Memory store is disabled"
714
+ raise RuntimeError(msg)
715
+
716
+ if not entries:
717
+ return 0
718
+
719
+ inserted_count = 0
720
+ if self._owner_id_column_name:
721
+ sql = f"""
722
+ INSERT INTO {self._memory_table} (
723
+ id, session_id, app_name, user_id, event_id, author,
724
+ {self._owner_id_column_name}, timestamp, content_json,
725
+ content_text, metadata_json, inserted_at
726
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
727
+ ON CONFLICT(event_id) DO NOTHING RETURNING 1
728
+ """
729
+ else:
730
+ sql = f"""
731
+ INSERT INTO {self._memory_table} (
732
+ id, session_id, app_name, user_id, event_id, author,
733
+ timestamp, content_json, content_text, metadata_json, inserted_at
734
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
735
+ ON CONFLICT(event_id) DO NOTHING RETURNING 1
736
+ """
737
+
738
+ with self._config.provide_connection() as conn:
739
+ for entry in entries:
740
+ params: tuple[Any, ...]
741
+ if self._owner_id_column_name:
742
+ params = (
743
+ entry["id"],
744
+ entry["session_id"],
745
+ entry["app_name"],
746
+ entry["user_id"],
747
+ entry["event_id"],
748
+ entry["author"],
749
+ owner_id,
750
+ entry["timestamp"],
751
+ to_json(entry["content_json"]),
752
+ entry["content_text"],
753
+ to_json(entry["metadata_json"]),
754
+ entry["inserted_at"],
755
+ )
756
+ else:
757
+ params = (
758
+ entry["id"],
759
+ entry["session_id"],
760
+ entry["app_name"],
761
+ entry["user_id"],
762
+ entry["event_id"],
763
+ entry["author"],
764
+ entry["timestamp"],
765
+ to_json(entry["content_json"]),
766
+ entry["content_text"],
767
+ to_json(entry["metadata_json"]),
768
+ entry["inserted_at"],
769
+ )
770
+ result = conn.execute(sql, params)
771
+ inserted_count += len(result.fetchall())
772
+ conn.commit()
773
+ return inserted_count
774
+
775
+ def search_entries(
776
+ self, query: str, app_name: str, user_id: str, limit: "int | None" = None
777
+ ) -> "list[MemoryRecord]":
778
+ """Search memory entries by text query."""
779
+ if not self._enabled:
780
+ msg = "Memory store is disabled"
781
+ raise RuntimeError(msg)
782
+
783
+ if not query:
784
+ return []
785
+
786
+ limit_value = limit or self._max_results
787
+ if self._use_fts:
788
+ sql = f"""
789
+ SELECT * FROM {self._memory_table}
790
+ WHERE app_name = ? AND user_id = ? AND content_text @@ ?
791
+ ORDER BY timestamp DESC
792
+ LIMIT ?
793
+ """
794
+ params = (app_name, user_id, query, limit_value)
795
+ else:
796
+ sql = f"""
797
+ SELECT * FROM {self._memory_table}
798
+ WHERE app_name = ? AND user_id = ? AND content_text ILIKE ?
799
+ ORDER BY timestamp DESC
800
+ LIMIT ?
801
+ """
802
+ params = (app_name, user_id, f"%{query}%", limit_value)
803
+
804
+ with self._config.provide_connection() as conn:
805
+ rows = conn.execute(sql, params).fetchall()
806
+ columns = [col[0] for col in conn.description or []]
807
+ records: list[MemoryRecord] = []
808
+ for row in rows:
809
+ record = cast("MemoryRecord", dict(zip(columns, row, strict=False)))
810
+ content_value = record["content_json"]
811
+ if isinstance(content_value, (str, bytes)):
812
+ record["content_json"] = from_json(content_value)
813
+ metadata_value = record.get("metadata_json")
814
+ if isinstance(metadata_value, (str, bytes)):
815
+ record["metadata_json"] = from_json(metadata_value)
816
+ records.append(record)
817
+ if self._use_fts:
818
+ with self._config.provide_connection() as conn:
819
+ self._refresh_fts_index(conn)
820
+ return records
821
+
822
+ def delete_entries_by_session(self, session_id: str) -> int:
823
+ """Delete all memory entries for a specific session."""
824
+ if not self._enabled:
825
+ msg = "Memory store is disabled"
826
+ raise RuntimeError(msg)
827
+
828
+ sql = f"DELETE FROM {self._memory_table} WHERE session_id = ? RETURNING 1"
829
+ with self._config.provide_connection() as conn:
830
+ result = conn.execute(sql, (session_id,))
831
+ deleted_count = len(result.fetchall())
832
+ conn.commit()
833
+ return deleted_count
834
+
835
+ def delete_entries_older_than(self, days: int) -> int:
836
+ """Delete memory entries older than specified days."""
837
+ if not self._enabled:
838
+ msg = "Memory store is disabled"
839
+ raise RuntimeError(msg)
840
+
841
+ sql = f"""
842
+ DELETE FROM {self._memory_table}
843
+ WHERE inserted_at < (CURRENT_TIMESTAMP - INTERVAL '{days} days')
844
+ RETURNING 1
845
+ """
846
+ with self._config.provide_connection() as conn:
847
+ result = conn.execute(sql)
848
+ deleted_count = len(result.fetchall())
849
+ conn.commit()
850
+ return deleted_count