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,992 @@
1
+ """SQLite sync ADK store for Google Agent Development Kit session/event storage."""
2
+
3
+ import sqlite3
4
+ from datetime import datetime, timezone
5
+ from typing import TYPE_CHECKING, Any, Final
6
+
7
+ from sqlspec.extensions.adk import BaseAsyncADKStore, EventRecord, SessionRecord
8
+ from sqlspec.extensions.adk.memory.store import BaseAsyncADKMemoryStore
9
+ from sqlspec.utils.logging import get_logger
10
+ from sqlspec.utils.serializers import from_json, to_json
11
+ from sqlspec.utils.sync_tools import async_, run_
12
+
13
+ if TYPE_CHECKING:
14
+ import logging
15
+
16
+ from sqlspec.adapters.sqlite.config import SqliteConfig
17
+ from sqlspec.extensions.adk import MemoryRecord
18
+
19
+
20
+ SECONDS_PER_DAY = 86400.0
21
+ JULIAN_EPOCH = 2440587.5
22
+ SQLITE_TABLE_NOT_FOUND_ERROR: Final = "no such table"
23
+
24
+ __all__ = ("SqliteADKMemoryStore", "SqliteADKStore")
25
+
26
+ logger: "logging.Logger" = get_logger("sqlspec.adapters.sqlite.adk.store")
27
+
28
+
29
+ def _datetime_to_julian(dt: datetime) -> float:
30
+ """Convert datetime to Julian Day number for SQLite storage.
31
+
32
+ Args:
33
+ dt: Datetime to convert (must be UTC-aware).
34
+
35
+ Returns:
36
+ Julian Day number as REAL.
37
+
38
+ Notes:
39
+ Julian Day number is days since November 24, 4714 BCE (proleptic Gregorian).
40
+ This enables direct comparison with julianday('now') in SQL queries.
41
+ """
42
+ if dt.tzinfo is None:
43
+ dt = dt.replace(tzinfo=timezone.utc)
44
+ epoch = datetime(1970, 1, 1, tzinfo=timezone.utc)
45
+ delta_days = (dt - epoch).total_seconds() / SECONDS_PER_DAY
46
+ return JULIAN_EPOCH + delta_days
47
+
48
+
49
+ def _julian_to_datetime(julian: float) -> datetime:
50
+ """Convert Julian Day number back to datetime.
51
+
52
+ Args:
53
+ julian: Julian Day number.
54
+
55
+ Returns:
56
+ UTC-aware datetime.
57
+ """
58
+ days_since_epoch = julian - JULIAN_EPOCH
59
+ timestamp = days_since_epoch * SECONDS_PER_DAY
60
+ return datetime.fromtimestamp(timestamp, tz=timezone.utc)
61
+
62
+
63
+ class SqliteADKStore(BaseAsyncADKStore["SqliteConfig"]):
64
+ """SQLite ADK store using synchronous SQLite driver.
65
+
66
+ Implements session and event storage for Google Agent Development Kit
67
+ using SQLite via the synchronous sqlite3 driver. Uses Litestar's sync_to_thread
68
+ utility to provide an async interface compatible with the Store protocol.
69
+
70
+ Provides:
71
+ - Session state management with JSON storage (as TEXT)
72
+ - Event history tracking with full-event JSON storage
73
+ - Julian Day timestamps (REAL) for efficient date operations
74
+ - Foreign key constraints with cascade delete
75
+ - Atomic event+state writes via append_event_and_update_state
76
+ - PRAGMA optimization profile for file-based databases
77
+
78
+ Args:
79
+ config: SqliteConfig instance with extension_config["adk"] settings.
80
+
81
+ Example:
82
+ from sqlspec.adapters.sqlite import SqliteConfig
83
+ from sqlspec.adapters.sqlite.adk import SqliteADKStore
84
+
85
+ config = SqliteConfig(
86
+ database=":memory:",
87
+ extension_config={
88
+ "adk": {
89
+ "session_table": "my_sessions",
90
+ "events_table": "my_events",
91
+ "owner_id_column": "tenant_id INTEGER REFERENCES tenants(id) ON DELETE CASCADE"
92
+ }
93
+ }
94
+ )
95
+ store = SqliteADKStore(config)
96
+ await store.ensure_tables()
97
+
98
+ Notes:
99
+ - JSON stored as TEXT with SQLSpec serializers (msgspec/orjson/stdlib)
100
+ - Timestamps as REAL (Julian day: julianday('now'))
101
+ - Full event stored as JSON TEXT in event_data column
102
+ - PRAGMA foreign_keys = ON (enable per connection)
103
+ - Configuration is read from config.extension_config["adk"]
104
+ """
105
+
106
+ __slots__ = ()
107
+
108
+ def __init__(self, config: "SqliteConfig") -> None:
109
+ """Initialize SQLite ADK store.
110
+
111
+ Args:
112
+ config: SqliteConfig instance.
113
+
114
+ Notes:
115
+ Configuration is read from config.extension_config["adk"]:
116
+ - session_table: Sessions table name (default: "adk_sessions")
117
+ - events_table: Events table name (default: "adk_events")
118
+ - owner_id_column: Optional owner FK column DDL (default: None)
119
+ """
120
+ super().__init__(config)
121
+
122
+ def _apply_pragmas(self, connection: Any) -> None:
123
+ """Apply PRAGMA optimization profile for this connection.
124
+
125
+ Args:
126
+ connection: SQLite connection.
127
+
128
+ Notes:
129
+ Enables foreign keys and applies performance PRAGMAs.
130
+ For file-based databases, adds cache_size, mmap_size,
131
+ and journal_size_limit optimizations.
132
+ """
133
+ connection.execute("PRAGMA foreign_keys = ON")
134
+ connection.execute("PRAGMA cache_size = -64000")
135
+ connection.execute("PRAGMA mmap_size = 30000000")
136
+ connection.execute("PRAGMA journal_size_limit = 67108864")
137
+
138
+ async def _get_create_sessions_table_sql(self) -> str:
139
+ """Get SQLite CREATE TABLE SQL for sessions.
140
+
141
+ Returns:
142
+ SQL statement to create adk_sessions table with indexes.
143
+
144
+ Notes:
145
+ - TEXT for IDs, names, and JSON state
146
+ - REAL for Julian Day timestamps
147
+ - Optional owner ID column for multi-tenant scenarios
148
+ - Composite index on (app_name, user_id)
149
+ - Index on update_time DESC for recent session queries
150
+ """
151
+ owner_id_line = ""
152
+ if self._owner_id_column_ddl:
153
+ owner_id_line = f",\n {self._owner_id_column_ddl}"
154
+
155
+ return f"""
156
+ CREATE TABLE IF NOT EXISTS {self._session_table} (
157
+ id TEXT PRIMARY KEY,
158
+ app_name TEXT NOT NULL,
159
+ user_id TEXT NOT NULL{owner_id_line},
160
+ state TEXT NOT NULL DEFAULT '{{}}',
161
+ create_time REAL NOT NULL,
162
+ update_time REAL NOT NULL
163
+ );
164
+ CREATE INDEX IF NOT EXISTS idx_{self._session_table}_app_user
165
+ ON {self._session_table}(app_name, user_id);
166
+ CREATE INDEX IF NOT EXISTS idx_{self._session_table}_update_time
167
+ ON {self._session_table}(update_time DESC);
168
+ """
169
+
170
+ async def _get_create_events_table_sql(self) -> str:
171
+ """Get SQLite CREATE TABLE SQL for events.
172
+
173
+ Returns:
174
+ SQL statement to create adk_events table with indexes.
175
+
176
+ Notes:
177
+ - TEXT for IDs and indexed scalars
178
+ - TEXT for full event JSON (event_data)
179
+ - REAL for Julian Day timestamps
180
+ - Foreign key to sessions with CASCADE delete
181
+ - Index on (session_id, timestamp ASC)
182
+ """
183
+ return f"""
184
+ CREATE TABLE IF NOT EXISTS {self._events_table} (
185
+ id TEXT PRIMARY KEY,
186
+ session_id TEXT NOT NULL,
187
+ invocation_id TEXT,
188
+ author TEXT,
189
+ timestamp REAL NOT NULL,
190
+ event_data TEXT NOT NULL,
191
+ FOREIGN KEY (session_id) REFERENCES {self._session_table}(id) ON DELETE CASCADE
192
+ );
193
+ CREATE INDEX IF NOT EXISTS idx_{self._events_table}_session
194
+ ON {self._events_table}(session_id, timestamp ASC);
195
+ """
196
+
197
+ def _get_drop_tables_sql(self) -> "list[str]":
198
+ """Get SQLite DROP TABLE SQL statements.
199
+
200
+ Returns:
201
+ List of SQL statements to drop tables and indexes.
202
+
203
+ Notes:
204
+ Order matters: drop events table (child) before sessions (parent).
205
+ SQLite automatically drops indexes when dropping tables.
206
+ """
207
+ return [f"DROP TABLE IF EXISTS {self._events_table}", f"DROP TABLE IF EXISTS {self._session_table}"]
208
+
209
+ def _create_tables(self) -> None:
210
+ """Synchronous implementation of create_tables."""
211
+ with self._config.provide_session() as driver:
212
+ self._apply_pragmas(driver.connection)
213
+ driver.execute_script(run_(self._get_create_sessions_table_sql)())
214
+ driver.execute_script(run_(self._get_create_events_table_sql)())
215
+
216
+ async def create_tables(self) -> None:
217
+ """Create both sessions and events tables if they don't exist."""
218
+ await async_(self._create_tables)()
219
+
220
+ def _create_session(
221
+ self, session_id: str, app_name: str, user_id: str, state: "dict[str, Any]", owner_id: "Any | None" = None
222
+ ) -> SessionRecord:
223
+ """Synchronous implementation of create_session."""
224
+ now = datetime.now(timezone.utc)
225
+ now_julian = _datetime_to_julian(now)
226
+ state_json = to_json(state)
227
+
228
+ params: tuple[Any, ...]
229
+ if self._owner_id_column_name:
230
+ sql = f"""
231
+ INSERT INTO {self._session_table}
232
+ (id, app_name, user_id, {self._owner_id_column_name}, state, create_time, update_time)
233
+ VALUES (?, ?, ?, ?, ?, ?, ?)
234
+ """
235
+ params = (session_id, app_name, user_id, owner_id, state_json, now_julian, now_julian)
236
+ else:
237
+ sql = f"""
238
+ INSERT INTO {self._session_table} (id, app_name, user_id, state, create_time, update_time)
239
+ VALUES (?, ?, ?, ?, ?, ?)
240
+ """
241
+ params = (session_id, app_name, user_id, state_json, now_julian, now_julian)
242
+
243
+ with self._config.provide_connection() as conn:
244
+ self._apply_pragmas(conn)
245
+ conn.execute(sql, params)
246
+ conn.commit()
247
+
248
+ return SessionRecord(
249
+ id=session_id, app_name=app_name, user_id=user_id, state=state, create_time=now, update_time=now
250
+ )
251
+
252
+ async def create_session(
253
+ self, session_id: str, app_name: str, user_id: str, state: "dict[str, Any]", owner_id: "Any | None" = None
254
+ ) -> SessionRecord:
255
+ """Create a new session.
256
+
257
+ Args:
258
+ session_id: Unique session identifier.
259
+ app_name: Application name.
260
+ user_id: User identifier.
261
+ state: Initial session state.
262
+ owner_id: Optional owner ID value for owner ID column.
263
+
264
+ Returns:
265
+ Created session record.
266
+
267
+ Notes:
268
+ Uses Julian Day for create_time and update_time.
269
+ State is always JSON-serialized (empty dict becomes '{}', never NULL).
270
+ If owner_id_column is configured, owner_id is inserted into that column.
271
+ """
272
+ return await async_(self._create_session)(session_id, app_name, user_id, state, owner_id)
273
+
274
+ def _get_session(self, session_id: str) -> "SessionRecord | None":
275
+ """Synchronous implementation of get_session."""
276
+ sql = f"""
277
+ SELECT id, app_name, user_id, state, create_time, update_time
278
+ FROM {self._session_table}
279
+ WHERE id = ?
280
+ """
281
+
282
+ try:
283
+ with self._config.provide_connection() as conn:
284
+ self._apply_pragmas(conn)
285
+ cursor = conn.execute(sql, (session_id,))
286
+ row = cursor.fetchone()
287
+
288
+ if row is None:
289
+ return None
290
+
291
+ return SessionRecord(
292
+ id=row[0],
293
+ app_name=row[1],
294
+ user_id=row[2],
295
+ state=from_json(row[3]) if row[3] else {},
296
+ create_time=_julian_to_datetime(row[4]),
297
+ update_time=_julian_to_datetime(row[5]),
298
+ )
299
+ except sqlite3.OperationalError as exc:
300
+ if SQLITE_TABLE_NOT_FOUND_ERROR in str(exc):
301
+ return None
302
+ raise
303
+
304
+ async def get_session(self, session_id: str) -> "SessionRecord | None":
305
+ """Get session by ID.
306
+
307
+ Args:
308
+ session_id: Session identifier.
309
+
310
+ Returns:
311
+ Session record or None if not found.
312
+
313
+ Notes:
314
+ SQLite returns Julian Day (REAL) for timestamps.
315
+ JSON is parsed from TEXT storage.
316
+ """
317
+ return await async_(self._get_session)(session_id)
318
+
319
+ def _update_session_state(self, session_id: str, state: "dict[str, Any]") -> None:
320
+ """Synchronous implementation of update_session_state."""
321
+ now_julian = _datetime_to_julian(datetime.now(timezone.utc))
322
+ state_json = to_json(state)
323
+
324
+ sql = f"""
325
+ UPDATE {self._session_table}
326
+ SET state = ?, update_time = ?
327
+ WHERE id = ?
328
+ """
329
+
330
+ with self._config.provide_connection() as conn:
331
+ self._apply_pragmas(conn)
332
+ conn.execute(sql, (state_json, now_julian, session_id))
333
+ conn.commit()
334
+
335
+ async def update_session_state(self, session_id: str, state: "dict[str, Any]") -> None:
336
+ """Update session state.
337
+
338
+ Args:
339
+ session_id: Session identifier.
340
+ state: New state dictionary (replaces existing state).
341
+
342
+ Notes:
343
+ This replaces the entire state dictionary.
344
+ Updates update_time to current Julian Day.
345
+ Empty dict is serialized as '{}', never NULL.
346
+ """
347
+ await async_(self._update_session_state)(session_id, state)
348
+
349
+ def _list_sessions(self, app_name: str, user_id: "str | None") -> "list[SessionRecord]":
350
+ """Synchronous implementation of list_sessions."""
351
+ if user_id is None:
352
+ sql = f"""
353
+ SELECT id, app_name, user_id, state, create_time, update_time
354
+ FROM {self._session_table}
355
+ WHERE app_name = ?
356
+ ORDER BY update_time DESC
357
+ """
358
+ params: tuple[str, ...] = (app_name,)
359
+ else:
360
+ sql = f"""
361
+ SELECT id, app_name, user_id, state, create_time, update_time
362
+ FROM {self._session_table}
363
+ WHERE app_name = ? AND user_id = ?
364
+ ORDER BY update_time DESC
365
+ """
366
+ params = (app_name, user_id)
367
+
368
+ try:
369
+ with self._config.provide_connection() as conn:
370
+ self._apply_pragmas(conn)
371
+ cursor = conn.execute(sql, params)
372
+ rows = cursor.fetchall()
373
+
374
+ return [
375
+ SessionRecord(
376
+ id=row[0],
377
+ app_name=row[1],
378
+ user_id=row[2],
379
+ state=from_json(row[3]) if row[3] else {},
380
+ create_time=_julian_to_datetime(row[4]),
381
+ update_time=_julian_to_datetime(row[5]),
382
+ )
383
+ for row in rows
384
+ ]
385
+ except sqlite3.OperationalError as exc:
386
+ if SQLITE_TABLE_NOT_FOUND_ERROR in str(exc):
387
+ return []
388
+ raise
389
+
390
+ async def list_sessions(self, app_name: str, user_id: str | None = None) -> "list[SessionRecord]":
391
+ """List sessions for an app, optionally filtered by user.
392
+
393
+ Args:
394
+ app_name: Application name.
395
+ user_id: User identifier. If None, lists all sessions for the app.
396
+
397
+ Returns:
398
+ List of session records ordered by update_time DESC.
399
+
400
+ Notes:
401
+ Uses composite index on (app_name, user_id) when user_id is provided.
402
+ """
403
+ return await async_(self._list_sessions)(app_name, user_id)
404
+
405
+ def _delete_session(self, session_id: str) -> None:
406
+ """Synchronous implementation of delete_session."""
407
+ sql = f"DELETE FROM {self._session_table} WHERE id = ?"
408
+
409
+ with self._config.provide_connection() as conn:
410
+ self._apply_pragmas(conn)
411
+ conn.execute(sql, (session_id,))
412
+ conn.commit()
413
+
414
+ async def delete_session(self, session_id: str) -> None:
415
+ """Delete session and all associated events (cascade).
416
+
417
+ Args:
418
+ session_id: Session identifier.
419
+
420
+ Notes:
421
+ Foreign key constraint ensures events are cascade-deleted.
422
+ """
423
+ await async_(self._delete_session)(session_id)
424
+
425
+ def _append_event(self, event_record: EventRecord) -> None:
426
+ """Synchronous implementation of append_event."""
427
+ timestamp_julian = _datetime_to_julian(event_record["timestamp"])
428
+ event_data_json = to_json(event_record["event_json"])
429
+
430
+ sql = f"""
431
+ INSERT INTO {self._events_table} (
432
+ id, session_id, invocation_id, author, timestamp, event_data
433
+ ) VALUES (?, ?, ?, ?, ?, ?)
434
+ """
435
+
436
+ import uuid
437
+
438
+ event_id = str(uuid.uuid4())
439
+
440
+ with self._config.provide_connection() as conn:
441
+ self._apply_pragmas(conn)
442
+ conn.execute(
443
+ sql,
444
+ (
445
+ event_id,
446
+ event_record["session_id"],
447
+ event_record["invocation_id"],
448
+ event_record["author"],
449
+ timestamp_julian,
450
+ event_data_json,
451
+ ),
452
+ )
453
+ conn.commit()
454
+
455
+ async def append_event(self, event_record: EventRecord) -> None:
456
+ """Append an event to a session.
457
+
458
+ Args:
459
+ event_record: Event record with 5 keys: session_id, invocation_id,
460
+ author, timestamp, event_json.
461
+
462
+ Notes:
463
+ Uses Julian Day for timestamp.
464
+ event_json dict is serialized to TEXT as event_data column.
465
+ """
466
+ await async_(self._append_event)(event_record)
467
+
468
+ def _append_event_and_update_state(
469
+ self, event_record: EventRecord, session_id: str, state: "dict[str, Any]"
470
+ ) -> SessionRecord:
471
+ """Synchronous implementation of append_event_and_update_state."""
472
+ import uuid
473
+
474
+ timestamp_julian = _datetime_to_julian(event_record["timestamp"])
475
+ event_data_json = to_json(event_record["event_json"])
476
+ now_julian = _datetime_to_julian(datetime.now(timezone.utc))
477
+ state_json = to_json(state)
478
+ event_id = str(uuid.uuid4())
479
+
480
+ insert_sql = f"""
481
+ INSERT INTO {self._events_table} (
482
+ id, session_id, invocation_id, author, timestamp, event_data
483
+ ) VALUES (?, ?, ?, ?, ?, ?)
484
+ """
485
+
486
+ update_sql = f"""
487
+ UPDATE {self._session_table}
488
+ SET state = ?, update_time = ?
489
+ WHERE id = ?
490
+ RETURNING id, app_name, user_id, state, create_time, update_time
491
+ """
492
+
493
+ with self._config.provide_connection() as conn:
494
+ self._apply_pragmas(conn)
495
+ conn.execute(
496
+ insert_sql,
497
+ (
498
+ event_id,
499
+ event_record["session_id"],
500
+ event_record["invocation_id"],
501
+ event_record["author"],
502
+ timestamp_julian,
503
+ event_data_json,
504
+ ),
505
+ )
506
+ cursor = conn.execute(update_sql, (state_json, now_julian, session_id))
507
+ row = cursor.fetchone()
508
+ conn.commit()
509
+
510
+ if row is None:
511
+ msg = f"Session {session_id} not found during append_event_and_update_state."
512
+ raise ValueError(msg)
513
+
514
+ return SessionRecord(
515
+ id=row[0],
516
+ app_name=row[1],
517
+ user_id=row[2],
518
+ state=from_json(row[3]) if row[3] else {},
519
+ create_time=_julian_to_datetime(row[4]),
520
+ update_time=_julian_to_datetime(row[5]),
521
+ )
522
+
523
+ async def append_event_and_update_state(
524
+ self, event_record: EventRecord, session_id: str, state: "dict[str, Any]"
525
+ ) -> SessionRecord:
526
+ """Atomically append an event and update the session's durable state.
527
+
528
+ Inserts the event and updates the session state + update_time in a
529
+ single transaction, returning the updated SessionRecord via RETURNING.
530
+
531
+ Args:
532
+ event_record: Event record to store.
533
+ session_id: Session identifier whose state should be updated.
534
+ state: Post-append durable state snapshot (temp: keys already
535
+ stripped by the service layer).
536
+ """
537
+ return await async_(self._append_event_and_update_state)(event_record, session_id, state)
538
+
539
+ def _get_events(
540
+ self, session_id: str, after_timestamp: "datetime | None" = None, limit: "int | None" = None
541
+ ) -> "list[EventRecord]":
542
+ """Synchronous implementation of get_events."""
543
+ where_clauses = ["session_id = ?"]
544
+ params: list[Any] = [session_id]
545
+
546
+ if after_timestamp is not None:
547
+ where_clauses.append("timestamp > ?")
548
+ params.append(_datetime_to_julian(after_timestamp))
549
+
550
+ where_clause = " AND ".join(where_clauses)
551
+ limit_clause = f" LIMIT {limit}" if limit else ""
552
+
553
+ sql = f"""
554
+ SELECT id, session_id, invocation_id, author, timestamp, event_data
555
+ FROM {self._events_table}
556
+ WHERE {where_clause}
557
+ ORDER BY timestamp ASC{limit_clause}
558
+ """
559
+
560
+ try:
561
+ with self._config.provide_connection() as conn:
562
+ self._apply_pragmas(conn)
563
+ cursor = conn.execute(sql, params)
564
+ rows = cursor.fetchall()
565
+
566
+ return [
567
+ EventRecord(
568
+ session_id=row[1],
569
+ invocation_id=row[2],
570
+ author=row[3],
571
+ timestamp=_julian_to_datetime(row[4]),
572
+ event_json=from_json(row[5]) if row[5] else {},
573
+ )
574
+ for row in rows
575
+ ]
576
+ except sqlite3.OperationalError as exc:
577
+ if SQLITE_TABLE_NOT_FOUND_ERROR in str(exc):
578
+ return []
579
+ raise
580
+
581
+ async def get_events(
582
+ self, session_id: str, after_timestamp: "datetime | None" = None, limit: "int | None" = None
583
+ ) -> "list[EventRecord]":
584
+ """Get events for a session.
585
+
586
+ Args:
587
+ session_id: Session identifier.
588
+ after_timestamp: Only return events after this time.
589
+ limit: Maximum number of events to return.
590
+
591
+ Returns:
592
+ List of event records ordered by timestamp ASC.
593
+
594
+ Notes:
595
+ Uses index on (session_id, timestamp ASC).
596
+ Parses event_data TEXT back to dict for event_json field.
597
+ """
598
+ return await async_(self._get_events)(session_id, after_timestamp, limit)
599
+
600
+
601
+ class SqliteADKMemoryStore(BaseAsyncADKMemoryStore["SqliteConfig"]):
602
+ """SQLite ADK memory store using synchronous SQLite driver.
603
+
604
+ Implements memory entry storage for Google Agent Development Kit
605
+ using SQLite via the synchronous sqlite3 driver. Provides:
606
+ - Session memory storage with JSON as TEXT
607
+ - Simple LIKE search (simple strategy)
608
+ - Optional FTS5 full-text search (sqlite_fts5 strategy)
609
+ - Julian Day timestamps (REAL) for efficient date operations
610
+ - Deduplication via event_id unique constraint
611
+ - Efficient upserts using INSERT OR IGNORE
612
+
613
+ Args:
614
+ config: SqliteConfig with extension_config["adk"] settings.
615
+
616
+ Example:
617
+ from sqlspec.adapters.sqlite import SqliteConfig
618
+ from sqlspec.adapters.sqlite.adk import SqliteADKMemoryStore
619
+
620
+ config = SqliteConfig(
621
+ database="app.db",
622
+ extension_config={
623
+ "adk": {
624
+ "memory_table": "adk_memory_entries",
625
+ "memory_use_fts": False,
626
+ "memory_max_results": 20,
627
+ }
628
+ }
629
+ )
630
+ store = SqliteADKMemoryStore(config)
631
+ store.ensure_tables()
632
+
633
+ Notes:
634
+ - JSON stored as TEXT with SQLSpec serializers
635
+ - REAL for Julian Day timestamps
636
+ - event_id UNIQUE constraint for deduplication
637
+ - Composite index on (app_name, user_id, timestamp DESC)
638
+ - Optional FTS5 virtual table for full-text search
639
+ - Configuration is read from config.extension_config["adk"]
640
+ """
641
+
642
+ __slots__ = ()
643
+
644
+ def __init__(self, config: "SqliteConfig") -> None:
645
+ """Initialize SQLite ADK memory store.
646
+
647
+ Args:
648
+ config: SqliteConfig instance.
649
+
650
+ Notes:
651
+ Configuration is read from config.extension_config["adk"]:
652
+ - memory_table: Memory table name (default: "adk_memory_entries")
653
+ - memory_use_fts: Enable full-text search when supported (default: False)
654
+ - memory_max_results: Max search results (default: 20)
655
+ - owner_id_column: Optional owner FK column DDL (default: None)
656
+ - enable_memory: Whether memory is enabled (default: True)
657
+ """
658
+ super().__init__(config)
659
+
660
+ async def _get_create_memory_table_sql(self) -> str:
661
+ """Get SQLite CREATE TABLE SQL for memory entries.
662
+
663
+ Returns:
664
+ SQL statement to create memory table with indexes.
665
+
666
+ Notes:
667
+ - TEXT for IDs, names, and JSON content
668
+ - REAL for Julian Day timestamps
669
+ - UNIQUE constraint on event_id for deduplication
670
+ - Composite index on (app_name, user_id, timestamp DESC)
671
+ - Optional owner ID column for multi-tenancy
672
+ - Optional FTS5 virtual table for full-text search
673
+ """
674
+ owner_id_line = ""
675
+ if self._owner_id_column_ddl:
676
+ owner_id_line = f",\n {self._owner_id_column_ddl}"
677
+
678
+ fts_table = ""
679
+ if self._use_fts:
680
+ fts_table = f"""
681
+ CREATE VIRTUAL TABLE IF NOT EXISTS {self._memory_table}_fts USING fts5(
682
+ content_text,
683
+ content={self._memory_table},
684
+ content_rowid=rowid
685
+ );
686
+
687
+ CREATE TRIGGER IF NOT EXISTS {self._memory_table}_ai AFTER INSERT ON {self._memory_table} BEGIN
688
+ INSERT INTO {self._memory_table}_fts(rowid, content_text) VALUES (new.rowid, new.content_text);
689
+ END;
690
+
691
+ CREATE TRIGGER IF NOT EXISTS {self._memory_table}_ad AFTER DELETE ON {self._memory_table} BEGIN
692
+ INSERT INTO {self._memory_table}_fts({self._memory_table}_fts, rowid, content_text)
693
+ VALUES('delete', old.rowid, old.content_text);
694
+ END;
695
+
696
+ CREATE TRIGGER IF NOT EXISTS {self._memory_table}_au AFTER UPDATE ON {self._memory_table} BEGIN
697
+ INSERT INTO {self._memory_table}_fts({self._memory_table}_fts, rowid, content_text)
698
+ VALUES('delete', old.rowid, old.content_text);
699
+ INSERT INTO {self._memory_table}_fts(rowid, content_text) VALUES (new.rowid, new.content_text);
700
+ END;
701
+ """
702
+
703
+ return f"""
704
+ CREATE TABLE IF NOT EXISTS {self._memory_table} (
705
+ id TEXT PRIMARY KEY,
706
+ session_id TEXT NOT NULL,
707
+ app_name TEXT NOT NULL,
708
+ user_id TEXT NOT NULL,
709
+ event_id TEXT NOT NULL UNIQUE,
710
+ author TEXT{owner_id_line},
711
+ timestamp REAL NOT NULL,
712
+ content_json TEXT NOT NULL,
713
+ content_text TEXT NOT NULL,
714
+ metadata_json TEXT,
715
+ inserted_at REAL NOT NULL
716
+ );
717
+
718
+ CREATE INDEX IF NOT EXISTS idx_{self._memory_table}_app_user_time
719
+ ON {self._memory_table}(app_name, user_id, timestamp DESC);
720
+
721
+ CREATE INDEX IF NOT EXISTS idx_{self._memory_table}_session
722
+ ON {self._memory_table}(session_id);
723
+ {fts_table}
724
+ """
725
+
726
+ def _get_drop_memory_table_sql(self) -> "list[str]":
727
+ """Get SQLite DROP TABLE SQL statements.
728
+
729
+ Returns:
730
+ List of SQL statements to drop the memory table and FTS table.
731
+
732
+ Notes:
733
+ SQLite automatically drops indexes when dropping tables.
734
+ FTS5 virtual table must be dropped separately if it exists.
735
+ """
736
+ statements = [f"DROP TABLE IF EXISTS {self._memory_table}"]
737
+ if self._use_fts:
738
+ statements.insert(0, f"DROP TABLE IF EXISTS {self._memory_table}_fts")
739
+ return statements
740
+
741
+ def _enable_foreign_keys(self, connection: Any) -> None:
742
+ """Enable foreign key constraints for this connection.
743
+
744
+ Args:
745
+ connection: SQLite connection.
746
+
747
+ Notes:
748
+ SQLite requires PRAGMA foreign_keys = ON per connection.
749
+ """
750
+ connection.execute("PRAGMA foreign_keys = ON")
751
+
752
+ def _create_tables(self) -> None:
753
+ """Create the memory table and indexes if they don't exist.
754
+
755
+ Skips table creation if memory store is disabled.
756
+ """
757
+ if not self._enabled:
758
+ return
759
+
760
+ with self._config.provide_session() as driver:
761
+ self._enable_foreign_keys(driver.connection)
762
+ driver.execute_script(run_(self._get_create_memory_table_sql)())
763
+
764
+ async def create_tables(self) -> None:
765
+ """Create tables if they don't exist."""
766
+ await async_(self._create_tables)()
767
+
768
+ def _insert_memory_entries(self, entries: "list[MemoryRecord]", owner_id: "object | None" = None) -> int:
769
+ """Bulk insert memory entries with deduplication.
770
+
771
+ Uses INSERT OR IGNORE to skip duplicates based on event_id
772
+ unique constraint.
773
+
774
+ Args:
775
+ entries: List of memory records to insert.
776
+ owner_id: Optional owner ID value for owner_id_column (if configured).
777
+
778
+ Returns:
779
+ Number of entries actually inserted (excludes duplicates).
780
+
781
+ Raises:
782
+ RuntimeError: If memory store is disabled.
783
+ """
784
+ if not self._enabled:
785
+ msg = "Memory store is disabled"
786
+ raise RuntimeError(msg)
787
+
788
+ if not entries:
789
+ return 0
790
+
791
+ inserted_count = 0
792
+ with self._config.provide_connection() as conn:
793
+ self._enable_foreign_keys(conn)
794
+
795
+ for entry in entries:
796
+ timestamp_julian = _datetime_to_julian(entry["timestamp"])
797
+ inserted_at_julian = _datetime_to_julian(entry["inserted_at"])
798
+ content_json_str = to_json(entry["content_json"])
799
+ metadata_json_str = to_json(entry["metadata_json"]) if entry["metadata_json"] else None
800
+
801
+ if self._owner_id_column_name:
802
+ sql = f"""
803
+ INSERT OR IGNORE INTO {self._memory_table}
804
+ (id, session_id, app_name, user_id, event_id, author,
805
+ {self._owner_id_column_name}, timestamp, content_json,
806
+ content_text, metadata_json, inserted_at)
807
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
808
+ """
809
+ params: tuple[Any, ...] = (
810
+ entry["id"],
811
+ entry["session_id"],
812
+ entry["app_name"],
813
+ entry["user_id"],
814
+ entry["event_id"],
815
+ entry["author"],
816
+ owner_id,
817
+ timestamp_julian,
818
+ content_json_str,
819
+ entry["content_text"],
820
+ metadata_json_str,
821
+ inserted_at_julian,
822
+ )
823
+ else:
824
+ sql = f"""
825
+ INSERT OR IGNORE INTO {self._memory_table}
826
+ (id, session_id, app_name, user_id, event_id, author,
827
+ timestamp, content_json, content_text, metadata_json, inserted_at)
828
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
829
+ """
830
+ params = (
831
+ entry["id"],
832
+ entry["session_id"],
833
+ entry["app_name"],
834
+ entry["user_id"],
835
+ entry["event_id"],
836
+ entry["author"],
837
+ timestamp_julian,
838
+ content_json_str,
839
+ entry["content_text"],
840
+ metadata_json_str,
841
+ inserted_at_julian,
842
+ )
843
+
844
+ cursor = conn.execute(sql, params)
845
+ if cursor.rowcount > 0:
846
+ inserted_count += 1
847
+
848
+ conn.commit()
849
+
850
+ return inserted_count
851
+
852
+ async def insert_memory_entries(self, entries: "list[MemoryRecord]", owner_id: "object | None" = None) -> int:
853
+ """Bulk insert memory entries with deduplication."""
854
+ return await async_(self._insert_memory_entries)(entries, owner_id)
855
+
856
+ def _search_entries(
857
+ self, query: str, app_name: str, user_id: str, limit: "int | None" = None
858
+ ) -> "list[MemoryRecord]":
859
+ """Search memory entries by text query.
860
+
861
+ Args:
862
+ query: Text query to search for.
863
+ app_name: Application name to filter by.
864
+ user_id: User ID to filter by.
865
+ limit: Maximum number of results (defaults to max_results config).
866
+
867
+ Returns:
868
+ List of matching memory records ordered by relevance/timestamp.
869
+
870
+ Raises:
871
+ RuntimeError: If memory store is disabled.
872
+ """
873
+ if not self._enabled:
874
+ msg = "Memory store is disabled"
875
+ raise RuntimeError(msg)
876
+
877
+ effective_limit = limit if limit is not None else self._max_results
878
+
879
+ if self._use_fts:
880
+ try:
881
+ return self._search_entries_fts(query, app_name, user_id, effective_limit)
882
+ except Exception as exc: # pragma: no cover - defensive fallback
883
+ logger.warning("FTS search failed; falling back to simple search: %s", exc)
884
+ return self._search_entries_simple(query, app_name, user_id, effective_limit)
885
+
886
+ async def search_entries(
887
+ self, query: str, app_name: str, user_id: str, limit: "int | None" = None
888
+ ) -> "list[MemoryRecord]":
889
+ """Search memory entries by text query."""
890
+ return await async_(self._search_entries)(query, app_name, user_id, limit)
891
+
892
+ def _search_entries_fts(self, query: str, app_name: str, user_id: str, limit: int) -> "list[MemoryRecord]":
893
+ sql = f"""
894
+ SELECT m.id, m.session_id, m.app_name, m.user_id, m.event_id, m.author,
895
+ m.timestamp, m.content_json, m.content_text, m.metadata_json, m.inserted_at
896
+ FROM {self._memory_table} m
897
+ JOIN {self._memory_table}_fts fts ON m.rowid = fts.rowid
898
+ WHERE m.app_name = ?
899
+ AND m.user_id = ?
900
+ AND fts.content_text MATCH ?
901
+ ORDER BY m.timestamp DESC
902
+ LIMIT ?
903
+ """
904
+ params: tuple[Any, ...] = (app_name, user_id, query, limit)
905
+ return self._fetch_records(sql, params)
906
+
907
+ def _search_entries_simple(self, query: str, app_name: str, user_id: str, limit: int) -> "list[MemoryRecord]":
908
+ sql = f"""
909
+ SELECT id, session_id, app_name, user_id, event_id, author,
910
+ timestamp, content_json, content_text, metadata_json, inserted_at
911
+ FROM {self._memory_table}
912
+ WHERE app_name = ?
913
+ AND user_id = ?
914
+ AND content_text LIKE ?
915
+ ORDER BY timestamp DESC
916
+ LIMIT ?
917
+ """
918
+ pattern = f"%{query}%"
919
+ params = (app_name, user_id, pattern, limit)
920
+ return self._fetch_records(sql, params)
921
+
922
+ def _fetch_records(self, sql: str, params: "tuple[Any, ...]") -> "list[MemoryRecord]":
923
+ with self._config.provide_connection() as conn:
924
+ self._enable_foreign_keys(conn)
925
+ cursor = conn.execute(sql, params)
926
+ rows = cursor.fetchall()
927
+ return [
928
+ {
929
+ "id": row[0],
930
+ "session_id": row[1],
931
+ "app_name": row[2],
932
+ "user_id": row[3],
933
+ "event_id": row[4],
934
+ "author": row[5],
935
+ "timestamp": _julian_to_datetime(row[6]),
936
+ "content_json": from_json(row[7]) if row[7] else {},
937
+ "content_text": row[8],
938
+ "metadata_json": from_json(row[9]) if row[9] else None,
939
+ "inserted_at": _julian_to_datetime(row[10]),
940
+ }
941
+ for row in rows
942
+ ]
943
+
944
+ def _delete_entries_by_session(self, session_id: str) -> int:
945
+ """Delete all memory entries for a specific session.
946
+
947
+ Args:
948
+ session_id: Session ID to delete entries for.
949
+
950
+ Returns:
951
+ Number of entries deleted.
952
+ """
953
+ sql = f"DELETE FROM {self._memory_table} WHERE session_id = ?"
954
+
955
+ with self._config.provide_connection() as conn:
956
+ self._enable_foreign_keys(conn)
957
+ cursor = conn.execute(sql, (session_id,))
958
+ deleted_count = cursor.rowcount
959
+ conn.commit()
960
+
961
+ return deleted_count
962
+
963
+ async def delete_entries_by_session(self, session_id: str) -> int:
964
+ """Delete all memory entries for a specific session."""
965
+ return await async_(self._delete_entries_by_session)(session_id)
966
+
967
+ def _delete_entries_older_than(self, days: int) -> int:
968
+ """Delete memory entries older than specified days.
969
+
970
+ Used for TTL cleanup operations.
971
+
972
+ Args:
973
+ days: Number of days to retain entries.
974
+
975
+ Returns:
976
+ Number of entries deleted.
977
+ """
978
+ cutoff_julian = _datetime_to_julian(datetime.now(timezone.utc)) - days
979
+
980
+ sql = f"DELETE FROM {self._memory_table} WHERE inserted_at < ?"
981
+
982
+ with self._config.provide_connection() as conn:
983
+ self._enable_foreign_keys(conn)
984
+ cursor = conn.execute(sql, (cutoff_julian,))
985
+ deleted_count = cursor.rowcount
986
+ conn.commit()
987
+
988
+ return deleted_count
989
+
990
+ async def delete_entries_older_than(self, days: int) -> int:
991
+ """Delete memory entries older than specified days."""
992
+ return await async_(self._delete_entries_older_than)(days)