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,732 @@
1
+ """Spanner ADK store."""
2
+
3
+ from collections.abc import Iterable
4
+ from datetime import datetime, timedelta, timezone
5
+ from typing import TYPE_CHECKING, Any, ClassVar, Protocol, cast
6
+
7
+ from google.cloud.spanner_v1 import param_types
8
+
9
+ from sqlspec.adapters.spanner.config import SpannerSyncConfig
10
+ from sqlspec.adapters.spanner.type_converter import bytes_to_spanner, spanner_to_bytes
11
+ from sqlspec.extensions.adk import BaseSyncADKStore, EventRecord, SessionRecord
12
+ from sqlspec.extensions.adk.memory.store import BaseSyncADKMemoryStore
13
+ from sqlspec.protocols import SpannerParamTypesProtocol
14
+ from sqlspec.utils.serializers import from_json, to_json
15
+
16
+ if TYPE_CHECKING:
17
+ from google.cloud.spanner_v1.database import Database
18
+ from google.cloud.spanner_v1.transaction import Transaction
19
+
20
+ from sqlspec.config import ADKConfig
21
+ from sqlspec.extensions.adk import MemoryRecord
22
+ SPANNER_PARAM_TYPES: SpannerParamTypesProtocol = cast("SpannerParamTypesProtocol", param_types)
23
+
24
+ __all__ = ("SpannerSyncADKMemoryStore", "SpannerSyncADKStore")
25
+
26
+
27
+ def _json_param_type() -> Any:
28
+ try:
29
+ return SPANNER_PARAM_TYPES.JSON
30
+ except AttributeError:
31
+ return SPANNER_PARAM_TYPES.STRING
32
+
33
+
34
+ class _SpannerWriteJob:
35
+ __slots__ = ("_statements",)
36
+
37
+ def __init__(self, statements: "list[tuple[str, dict[str, Any], dict[str, Any]]]") -> None:
38
+ self._statements = statements
39
+
40
+ def __call__(self, transaction: "Transaction") -> None:
41
+ for sql, params, types in self._statements:
42
+ transaction.execute_update(sql, params=params, param_types=types) # type: ignore[no-untyped-call]
43
+
44
+
45
+ class SpannerSyncADKStore(BaseSyncADKStore[SpannerSyncConfig]):
46
+ """Spanner ADK store backed by synchronous Spanner client."""
47
+
48
+ connector_name: ClassVar[str] = "spanner"
49
+
50
+ def __init__(self, config: SpannerSyncConfig) -> None:
51
+ super().__init__(config)
52
+ adk_config = cast("dict[str, Any]", config.extension_config.get("adk", {}))
53
+ self._shard_count: int = int(adk_config.get("shard_count", 0)) if adk_config.get("shard_count") else 0
54
+ self._session_table_options: str | None = adk_config.get("session_table_options")
55
+ self._events_table_options: str | None = adk_config.get("events_table_options")
56
+ self._expires_index_options: str | None = adk_config.get("expires_index_options")
57
+
58
+ def _database(self) -> "Database":
59
+ return self._config.get_database()
60
+
61
+ def _run_read(
62
+ self, sql: str, params: "dict[str, Any] | None" = None, types: "dict[str, Any] | None" = None
63
+ ) -> "list[Any]":
64
+ with self._config.provide_connection() as snapshot:
65
+ result_set = cast("Any", snapshot).execute_sql(sql, params=params, param_types=types)
66
+ return list(result_set)
67
+
68
+ def _run_write(self, statements: "list[tuple[str, dict[str, Any], dict[str, Any]]]") -> None:
69
+ self._database().run_in_transaction(_SpannerWriteJob(statements)) # type: ignore[no-untyped-call]
70
+
71
+ def _session_param_types(self, include_owner: bool) -> "dict[str, Any]":
72
+ json_type = _json_param_type()
73
+ types: dict[str, Any] = {
74
+ "id": SPANNER_PARAM_TYPES.STRING,
75
+ "app_name": SPANNER_PARAM_TYPES.STRING,
76
+ "user_id": SPANNER_PARAM_TYPES.STRING,
77
+ "state": json_type,
78
+ }
79
+ if include_owner and self._owner_id_column_name:
80
+ types["owner_id"] = SPANNER_PARAM_TYPES.STRING
81
+ return types
82
+
83
+ def _event_param_types(self, has_branch: bool) -> "dict[str, Any]":
84
+ json_type = _json_param_type()
85
+ types: dict[str, Any] = {
86
+ "id": SPANNER_PARAM_TYPES.STRING,
87
+ "session_id": SPANNER_PARAM_TYPES.STRING,
88
+ "app_name": SPANNER_PARAM_TYPES.STRING,
89
+ "user_id": SPANNER_PARAM_TYPES.STRING,
90
+ "author": SPANNER_PARAM_TYPES.STRING,
91
+ "actions": SPANNER_PARAM_TYPES.BYTES,
92
+ "long_running_tool_ids_json": json_type,
93
+ "invocation_id": SPANNER_PARAM_TYPES.STRING,
94
+ "timestamp": SPANNER_PARAM_TYPES.TIMESTAMP,
95
+ "content": json_type,
96
+ "grounding_metadata": json_type,
97
+ "custom_metadata": json_type,
98
+ "partial": SPANNER_PARAM_TYPES.BOOL,
99
+ "turn_complete": SPANNER_PARAM_TYPES.BOOL,
100
+ "interrupted": SPANNER_PARAM_TYPES.BOOL,
101
+ "error_code": SPANNER_PARAM_TYPES.STRING,
102
+ "error_message": SPANNER_PARAM_TYPES.STRING,
103
+ }
104
+ if has_branch:
105
+ types["branch"] = SPANNER_PARAM_TYPES.STRING
106
+ return types
107
+
108
+ def _decode_state(self, raw: Any) -> Any:
109
+ if isinstance(raw, str):
110
+ return from_json(raw)
111
+ return raw
112
+
113
+ def _decode_json(self, raw: Any) -> Any:
114
+ if raw is None:
115
+ return None
116
+ if isinstance(raw, str):
117
+ return from_json(raw)
118
+ return raw
119
+
120
+ def create_session(
121
+ self, session_id: str, app_name: str, user_id: str, state: "dict[str, Any]", owner_id: "Any | None" = None
122
+ ) -> SessionRecord:
123
+ state_json = to_json(state)
124
+ params: dict[str, Any] = {"id": session_id, "app_name": app_name, "user_id": user_id, "state": state_json}
125
+ columns = "id, app_name, user_id, state, create_time, update_time"
126
+ values = "@id, @app_name, @user_id, @state, PENDING_COMMIT_TIMESTAMP(), PENDING_COMMIT_TIMESTAMP()"
127
+ if self._owner_id_column_name:
128
+ params["owner_id"] = owner_id
129
+ columns = f"id, app_name, user_id, {self._owner_id_column_name}, state, create_time, update_time"
130
+ values = (
131
+ "@id, @app_name, @user_id, @owner_id, @state, PENDING_COMMIT_TIMESTAMP(), PENDING_COMMIT_TIMESTAMP()"
132
+ )
133
+
134
+ sql = f"""
135
+ INSERT INTO {self._session_table} ({columns})
136
+ VALUES ({values})
137
+ """
138
+ self._run_write([(sql, params, self._session_param_types(self._owner_id_column_name is not None))])
139
+
140
+ return {
141
+ "id": session_id,
142
+ "app_name": app_name,
143
+ "user_id": user_id,
144
+ "state": state,
145
+ "create_time": datetime.now(timezone.utc),
146
+ "update_time": datetime.now(timezone.utc),
147
+ }
148
+
149
+ def get_session(self, session_id: str) -> "SessionRecord | None":
150
+ sql = f"""
151
+ SELECT id, app_name, user_id, state, create_time, update_time{", " + self._owner_id_column_name if self._owner_id_column_name else ""}
152
+ FROM {self._session_table}
153
+ WHERE id = @id
154
+ """
155
+ if self._shard_count > 1:
156
+ sql = f"{sql} AND shard_id = MOD(FARM_FINGERPRINT(@id), {self._shard_count})"
157
+ sql = f"{sql} LIMIT 1"
158
+ params = {"id": session_id}
159
+ rows = self._run_read(sql, params, {"id": SPANNER_PARAM_TYPES.STRING})
160
+ if not rows:
161
+ return None
162
+
163
+ row = rows[0]
164
+ state_value = self._decode_state(row[3])
165
+ record: SessionRecord = {
166
+ "id": row[0],
167
+ "app_name": row[1],
168
+ "user_id": row[2],
169
+ "state": state_value,
170
+ "create_time": row[4],
171
+ "update_time": row[5],
172
+ }
173
+ return record
174
+
175
+ def update_session_state(self, session_id: str, state: "dict[str, Any]") -> None:
176
+ params = {"id": session_id, "state": to_json(state)}
177
+ json_type = _json_param_type()
178
+ sql = f"""
179
+ UPDATE {self._session_table}
180
+ SET state = @state, update_time = PENDING_COMMIT_TIMESTAMP()
181
+ WHERE id = @id
182
+ """
183
+ if self._shard_count > 1:
184
+ sql = f"{sql} AND shard_id = MOD(FARM_FINGERPRINT(@id), {self._shard_count})"
185
+ self._run_write([(sql, params, {"id": SPANNER_PARAM_TYPES.STRING, "state": json_type})])
186
+
187
+ def list_sessions(self, app_name: str, user_id: "str | None" = None) -> "list[SessionRecord]":
188
+ sql = f"""
189
+ SELECT id, app_name, user_id, state, create_time, update_time{", " + self._owner_id_column_name if self._owner_id_column_name else ""}
190
+ FROM {self._session_table}
191
+ WHERE app_name = @app_name
192
+ """
193
+ params: dict[str, Any] = {"app_name": app_name}
194
+ types: dict[str, Any] = {"app_name": SPANNER_PARAM_TYPES.STRING}
195
+ if user_id is not None:
196
+ sql = f"{sql} AND user_id = @user_id"
197
+ params["user_id"] = user_id
198
+ types["user_id"] = SPANNER_PARAM_TYPES.STRING
199
+ if self._shard_count > 1:
200
+ sql = f"{sql} AND shard_id = MOD(FARM_FINGERPRINT(id), {self._shard_count})"
201
+
202
+ rows = self._run_read(sql, params, types)
203
+ records: list[SessionRecord] = []
204
+ for row in rows:
205
+ state_value = self._decode_state(row[3])
206
+ record: SessionRecord = {
207
+ "id": row[0],
208
+ "app_name": row[1],
209
+ "user_id": row[2],
210
+ "state": state_value,
211
+ "create_time": row[4],
212
+ "update_time": row[5],
213
+ }
214
+ records.append(record)
215
+ return records
216
+
217
+ def delete_session(self, session_id: str) -> None:
218
+ shard_clause = (
219
+ f" AND shard_id = MOD(FARM_FINGERPRINT(@session_id), {self._shard_count})" if self._shard_count > 1 else ""
220
+ )
221
+ delete_events_sql = f"DELETE FROM {self._events_table} WHERE session_id = @session_id{shard_clause}"
222
+ delete_session_sql = f"DELETE FROM {self._session_table} WHERE id = @session_id{shard_clause}"
223
+ params = {"session_id": session_id}
224
+ types = {"session_id": SPANNER_PARAM_TYPES.STRING}
225
+ self._run_write([(delete_events_sql, params, types), (delete_session_sql, params, types)])
226
+
227
+ def create_event(
228
+ self,
229
+ event_id: str,
230
+ session_id: str,
231
+ app_name: str,
232
+ user_id: str,
233
+ author: "str | None" = None,
234
+ actions: "bytes | None" = None,
235
+ content: "dict[str, Any] | None" = None,
236
+ **kwargs: Any,
237
+ ) -> EventRecord:
238
+ branch = kwargs.get("branch")
239
+ long_running_serialized = (
240
+ to_json(kwargs.get("long_running_tool_ids_json"))
241
+ if kwargs.get("long_running_tool_ids_json") is not None
242
+ else None
243
+ )
244
+ content_serialized = to_json(content) if content is not None else None
245
+ grounding_serialized = (
246
+ to_json(kwargs.get("grounding_metadata")) if kwargs.get("grounding_metadata") is not None else None
247
+ )
248
+ custom_serialized = (
249
+ to_json(kwargs.get("custom_metadata")) if kwargs.get("custom_metadata") is not None else None
250
+ )
251
+ params: dict[str, Any] = {
252
+ "id": event_id,
253
+ "session_id": session_id,
254
+ "app_name": app_name,
255
+ "user_id": user_id,
256
+ "author": author,
257
+ "actions": bytes_to_spanner(actions),
258
+ "long_running_tool_ids_json": long_running_serialized,
259
+ "timestamp": datetime.now(timezone.utc),
260
+ "content": content_serialized,
261
+ "grounding_metadata": grounding_serialized,
262
+ "custom_metadata": custom_serialized,
263
+ "invocation_id": kwargs.get("invocation_id"),
264
+ "partial": kwargs.get("partial"),
265
+ "turn_complete": kwargs.get("turn_complete"),
266
+ "interrupted": kwargs.get("interrupted"),
267
+ "error_code": kwargs.get("error_code"),
268
+ "error_message": kwargs.get("error_message"),
269
+ }
270
+ branch = kwargs.get("branch")
271
+ columns = [
272
+ "id",
273
+ "session_id",
274
+ "app_name",
275
+ "user_id",
276
+ "author",
277
+ "actions",
278
+ "long_running_tool_ids_json",
279
+ "timestamp",
280
+ "content",
281
+ "grounding_metadata",
282
+ "custom_metadata",
283
+ "invocation_id",
284
+ "partial",
285
+ "turn_complete",
286
+ "interrupted",
287
+ "error_code",
288
+ "error_message",
289
+ ]
290
+ values = [
291
+ "@id",
292
+ "@session_id",
293
+ "@app_name",
294
+ "@user_id",
295
+ "@author",
296
+ "@actions",
297
+ "@long_running_tool_ids_json",
298
+ "PENDING_COMMIT_TIMESTAMP()",
299
+ "@content",
300
+ "@grounding_metadata",
301
+ "@custom_metadata",
302
+ "@invocation_id",
303
+ "@partial",
304
+ "@turn_complete",
305
+ "@interrupted",
306
+ "@error_code",
307
+ "@error_message",
308
+ ]
309
+ has_branch = branch is not None
310
+ if has_branch:
311
+ params["branch"] = branch
312
+ columns.append("branch")
313
+ values.append("@branch")
314
+
315
+ sql = f"""
316
+ INSERT INTO {self._events_table} ({", ".join(columns)})
317
+ VALUES ({", ".join(values)})
318
+ """
319
+ self._run_write([(sql, params, self._event_param_types(has_branch))])
320
+
321
+ record: EventRecord = {
322
+ "id": event_id,
323
+ "session_id": session_id,
324
+ "app_name": app_name,
325
+ "user_id": user_id,
326
+ "author": author or "",
327
+ "actions": actions or b"",
328
+ "long_running_tool_ids_json": long_running_serialized,
329
+ "branch": branch,
330
+ "timestamp": params["timestamp"],
331
+ "content": from_json(content_serialized) if content_serialized else None,
332
+ "grounding_metadata": from_json(grounding_serialized) if grounding_serialized else None,
333
+ "custom_metadata": from_json(custom_serialized) if custom_serialized else None,
334
+ "invocation_id": kwargs.get("invocation_id", ""),
335
+ "partial": kwargs.get("partial"),
336
+ "turn_complete": kwargs.get("turn_complete"),
337
+ "interrupted": kwargs.get("interrupted"),
338
+ "error_code": kwargs.get("error_code"),
339
+ "error_message": kwargs.get("error_message"),
340
+ }
341
+ return record
342
+
343
+ def list_events(self, session_id: str) -> "list[EventRecord]":
344
+ sql = f"""
345
+ SELECT id, session_id, app_name, user_id, author, actions, long_running_tool_ids_json, branch,
346
+ timestamp, content, grounding_metadata, custom_metadata, invocation_id, partial,
347
+ turn_complete, interrupted, error_code, error_message
348
+ FROM {self._events_table}
349
+ WHERE session_id = @session_id
350
+ """
351
+ if self._shard_count > 1:
352
+ sql = f"{sql} AND shard_id = MOD(FARM_FINGERPRINT(@session_id), {self._shard_count})"
353
+ sql = f"{sql} ORDER BY timestamp ASC"
354
+ params = {"session_id": session_id}
355
+ types = {"session_id": SPANNER_PARAM_TYPES.STRING}
356
+ rows = self._run_read(sql, params, types)
357
+ return [
358
+ {
359
+ "id": row[0],
360
+ "session_id": row[1],
361
+ "app_name": row[2],
362
+ "user_id": row[3],
363
+ "invocation_id": row[12] or "",
364
+ "author": row[4] or "",
365
+ "actions": spanner_to_bytes(row[5]) or b"",
366
+ "long_running_tool_ids_json": row[6],
367
+ "branch": row[7],
368
+ "timestamp": row[8],
369
+ "content": self._decode_json(row[9]),
370
+ "grounding_metadata": self._decode_json(row[10]),
371
+ "custom_metadata": self._decode_json(row[11]),
372
+ "partial": row[13],
373
+ "turn_complete": row[14],
374
+ "interrupted": row[15],
375
+ "error_code": row[16],
376
+ "error_message": row[17],
377
+ }
378
+ for row in rows
379
+ ]
380
+
381
+ def create_tables(self) -> None:
382
+ database = self._database()
383
+ existing_tables = {t.table_id for t in database.list_tables()} # type: ignore[no-untyped-call]
384
+
385
+ ddl_statements: list[str] = []
386
+ if self._session_table not in existing_tables:
387
+ ddl_statements.append(self._get_create_sessions_table_sql())
388
+ if self._events_table not in existing_tables:
389
+ ddl_statements.append(self._get_create_events_table_sql())
390
+
391
+ if ddl_statements:
392
+ database.update_ddl(ddl_statements).result(300) # type: ignore[no-untyped-call]
393
+
394
+ def _get_create_sessions_table_sql(self) -> str:
395
+ owner_line = ""
396
+ if self._owner_id_column_ddl:
397
+ owner_line = f",\n {self._owner_id_column_ddl}"
398
+ shard_column = ""
399
+ pk = "PRIMARY KEY (id)"
400
+ if self._shard_count > 1:
401
+ shard_column = f",\n shard_id INT64 AS (MOD(FARM_FINGERPRINT(id), {self._shard_count})) STORED"
402
+ pk = "PRIMARY KEY (shard_id, id)"
403
+ options = ""
404
+ if self._session_table_options:
405
+ options = f"\nOPTIONS ({self._session_table_options})"
406
+ return f"""
407
+ CREATE TABLE {self._session_table} (
408
+ id STRING(128) NOT NULL,
409
+ app_name STRING(128) NOT NULL,
410
+ user_id STRING(128) NOT NULL{owner_line},
411
+ state JSON NOT NULL,
412
+ create_time TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true),
413
+ update_time TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true){shard_column}
414
+ ) {pk}{options}
415
+ """
416
+
417
+ def _get_create_events_table_sql(self) -> str:
418
+ shard_column = ""
419
+ pk = "PRIMARY KEY (session_id, timestamp, id)"
420
+ if self._shard_count > 1:
421
+ shard_column = f",\n shard_id INT64 AS (MOD(FARM_FINGERPRINT(session_id), {self._shard_count})) STORED"
422
+ pk = "PRIMARY KEY (shard_id, session_id, timestamp, id)"
423
+ options = ""
424
+ if self._events_table_options:
425
+ options = f"\nOPTIONS ({self._events_table_options})"
426
+ return f"""
427
+ CREATE TABLE {self._events_table} (
428
+ id STRING(128) NOT NULL,
429
+ session_id STRING(128) NOT NULL,
430
+ app_name STRING(128) NOT NULL,
431
+ user_id STRING(128) NOT NULL,
432
+ invocation_id STRING(128),
433
+ author STRING(64),
434
+ actions BYTES(MAX),
435
+ long_running_tool_ids_json JSON,
436
+ branch STRING(64),
437
+ timestamp TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true),
438
+ content JSON,
439
+ grounding_metadata JSON,
440
+ custom_metadata JSON,
441
+ partial BOOL,
442
+ turn_complete BOOL,
443
+ interrupted BOOL,
444
+ error_code STRING(64),
445
+ error_message STRING(255){shard_column}
446
+ ) {pk}{options}
447
+ """
448
+
449
+ def _get_drop_tables_sql(self) -> "list[str]":
450
+ return [f"DROP TABLE {self._events_table}", f"DROP TABLE {self._session_table}"]
451
+
452
+
453
+ class _SpannerMemoryWriteJob:
454
+ __slots__ = ("_statements",)
455
+
456
+ def __init__(self, statements: "list[tuple[str, dict[str, Any], dict[str, Any]]]") -> None:
457
+ self._statements = statements
458
+
459
+ def __call__(self, transaction: "Transaction") -> None:
460
+ for sql, params, types in self._statements:
461
+ transaction.execute_update(sql, params=params, param_types=types) # type: ignore[no-untyped-call]
462
+
463
+
464
+ class _SpannerMemoryUpdateJob:
465
+ __slots__ = ("_params", "_sql", "_types")
466
+
467
+ def __init__(self, sql: str, params: "dict[str, Any]", types: "dict[str, Any]") -> None:
468
+ self._sql = sql
469
+ self._params = params
470
+ self._types = types
471
+
472
+ def __call__(self, transaction: "Transaction") -> int:
473
+ return int(transaction.execute_update(self._sql, params=self._params, param_types=self._types)) # type: ignore[no-untyped-call]
474
+
475
+
476
+ class _SpannerReadProtocol(Protocol):
477
+ def execute_sql(
478
+ self, sql: str, params: "dict[str, Any] | None" = None, param_types: "dict[str, Any] | None" = None
479
+ ) -> Iterable[Any]: ...
480
+
481
+
482
+ class SpannerSyncADKMemoryStore(BaseSyncADKMemoryStore[SpannerSyncConfig]):
483
+ """Spanner ADK memory store backed by synchronous Spanner client."""
484
+
485
+ connector_name: ClassVar[str] = "spanner"
486
+
487
+ def __init__(self, config: SpannerSyncConfig) -> None:
488
+ super().__init__(config)
489
+ adk_config = cast("ADKConfig", config.extension_config.get("adk", {}))
490
+ shard_count = adk_config.get("shard_count")
491
+ self._shard_count = int(shard_count) if isinstance(shard_count, int) else 0
492
+
493
+ def _database(self) -> "Database":
494
+ return self._config.get_database()
495
+
496
+ def _run_read(
497
+ self, sql: str, params: "dict[str, Any] | None" = None, types: "dict[str, Any] | None" = None
498
+ ) -> "list[Any]":
499
+ with self._config.provide_connection() as snapshot:
500
+ reader = cast("_SpannerReadProtocol", snapshot)
501
+ result_set = reader.execute_sql(sql, params=params, param_types=types)
502
+ return list(result_set)
503
+
504
+ def _run_write(self, statements: "list[tuple[str, dict[str, Any], dict[str, Any]]]") -> None:
505
+ self._database().run_in_transaction(_SpannerMemoryWriteJob(statements)) # type: ignore[no-untyped-call]
506
+
507
+ def _execute_update(self, sql: str, params: "dict[str, Any]", types: "dict[str, Any]") -> int:
508
+ return int(self._database().run_in_transaction(_SpannerMemoryUpdateJob(sql, params, types))) # type: ignore[no-untyped-call]
509
+
510
+ def _memory_param_types(self, include_owner: bool) -> "dict[str, Any]":
511
+ types: dict[str, Any] = {
512
+ "id": SPANNER_PARAM_TYPES.STRING,
513
+ "session_id": SPANNER_PARAM_TYPES.STRING,
514
+ "app_name": SPANNER_PARAM_TYPES.STRING,
515
+ "user_id": SPANNER_PARAM_TYPES.STRING,
516
+ "event_id": SPANNER_PARAM_TYPES.STRING,
517
+ "author": SPANNER_PARAM_TYPES.STRING,
518
+ "timestamp": SPANNER_PARAM_TYPES.TIMESTAMP,
519
+ "content_json": _json_param_type(),
520
+ "content_text": SPANNER_PARAM_TYPES.STRING,
521
+ "metadata_json": _json_param_type(),
522
+ "inserted_at": SPANNER_PARAM_TYPES.TIMESTAMP,
523
+ }
524
+ if include_owner and self._owner_id_column_name:
525
+ types["owner_id"] = SPANNER_PARAM_TYPES.STRING
526
+ return types
527
+
528
+ def _decode_json(self, raw: Any) -> Any:
529
+ if raw is None:
530
+ return None
531
+ if isinstance(raw, str):
532
+ return from_json(raw)
533
+ return raw
534
+
535
+ def create_tables(self) -> None:
536
+ if not self._enabled:
537
+ return
538
+
539
+ database = self._database()
540
+ existing_tables = {t.table_id for t in database.list_tables()} # type: ignore[no-untyped-call]
541
+
542
+ ddl_statements: list[str] = []
543
+ if self._memory_table not in existing_tables:
544
+ ddl_statements.extend(self._get_create_memory_table_sql())
545
+
546
+ if ddl_statements:
547
+ database.update_ddl(ddl_statements).result(300) # type: ignore[no-untyped-call]
548
+
549
+ def _get_create_memory_table_sql(self) -> "list[str]":
550
+ owner_line = ""
551
+ if self._owner_id_column_ddl:
552
+ owner_line = f",\n {self._owner_id_column_ddl}"
553
+
554
+ fts_column_line = ""
555
+ fts_index = ""
556
+ if self._use_fts:
557
+ fts_column_line = "\n content_tokens TOKENLIST AS (TOKENIZE_FULLTEXT(content_text)) HIDDEN"
558
+ fts_index = f"CREATE SEARCH INDEX idx_{self._memory_table}_fts ON {self._memory_table}(content_tokens)"
559
+
560
+ shard_column = ""
561
+ pk = "PRIMARY KEY (id)"
562
+ if self._shard_count > 1:
563
+ shard_column = f",\n shard_id INT64 AS (MOD(FARM_FINGERPRINT(id), {self._shard_count})) STORED"
564
+ pk = "PRIMARY KEY (shard_id, id)"
565
+
566
+ table_sql = f"""
567
+ CREATE TABLE {self._memory_table} (
568
+ id STRING(128) NOT NULL,
569
+ session_id STRING(128) NOT NULL,
570
+ app_name STRING(128) NOT NULL,
571
+ user_id STRING(128) NOT NULL,
572
+ event_id STRING(128) NOT NULL,
573
+ author STRING(256){owner_line},
574
+ timestamp TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true),
575
+ content_json JSON NOT NULL,
576
+ content_text STRING(MAX) NOT NULL,
577
+ metadata_json JSON,
578
+ inserted_at TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true){fts_column_line}{shard_column}
579
+ ) {pk}
580
+ """
581
+
582
+ app_user_idx = (
583
+ f"CREATE INDEX idx_{self._memory_table}_app_user_time "
584
+ f"ON {self._memory_table}(app_name, user_id, timestamp DESC)"
585
+ )
586
+ session_idx = f"CREATE INDEX idx_{self._memory_table}_session ON {self._memory_table}(session_id)"
587
+
588
+ statements = [table_sql, app_user_idx, session_idx]
589
+ if fts_index:
590
+ statements.append(fts_index)
591
+ return statements
592
+
593
+ def insert_memory_entries(self, entries: "list[MemoryRecord]", owner_id: "object | None" = None) -> int:
594
+ if not self._enabled:
595
+ msg = "Memory store is disabled"
596
+ raise RuntimeError(msg)
597
+
598
+ if not entries:
599
+ return 0
600
+
601
+ inserted_count = 0
602
+ statements: list[tuple[str, dict[str, Any], dict[str, Any]]] = []
603
+
604
+ owner_column = f", {self._owner_id_column_name}" if self._owner_id_column_name else ""
605
+ owner_param = ", @owner_id" if self._owner_id_column_name else ""
606
+
607
+ insert_sql = f"""
608
+ INSERT INTO {self._memory_table} (
609
+ id, session_id, app_name, user_id, event_id, author{owner_column},
610
+ timestamp, content_json, content_text, metadata_json, inserted_at
611
+ ) VALUES (
612
+ @id, @session_id, @app_name, @user_id, @event_id, @author{owner_param},
613
+ @timestamp, @content_json, @content_text, @metadata_json, @inserted_at
614
+ )
615
+ """
616
+
617
+ for entry in entries:
618
+ if self._event_exists(entry["event_id"]):
619
+ continue
620
+ params = {
621
+ "id": entry["id"],
622
+ "session_id": entry["session_id"],
623
+ "app_name": entry["app_name"],
624
+ "user_id": entry["user_id"],
625
+ "event_id": entry["event_id"],
626
+ "author": entry["author"],
627
+ "timestamp": entry["timestamp"],
628
+ "content_json": to_json(entry["content_json"]),
629
+ "content_text": entry["content_text"],
630
+ "metadata_json": to_json(entry["metadata_json"]) if entry["metadata_json"] is not None else None,
631
+ "inserted_at": entry["inserted_at"],
632
+ }
633
+ if self._owner_id_column_name:
634
+ params["owner_id"] = str(owner_id) if owner_id is not None else None
635
+ statements.append((insert_sql, params, self._memory_param_types(self._owner_id_column_name is not None)))
636
+ inserted_count += 1
637
+
638
+ if statements:
639
+ self._run_write(statements)
640
+ return inserted_count
641
+
642
+ def _event_exists(self, event_id: str) -> bool:
643
+ sql = f"SELECT event_id FROM {self._memory_table} WHERE event_id = @event_id LIMIT 1"
644
+ rows = self._run_read(sql, {"event_id": event_id}, {"event_id": SPANNER_PARAM_TYPES.STRING})
645
+ return bool(rows)
646
+
647
+ def search_entries(
648
+ self, query: str, app_name: str, user_id: str, limit: "int | None" = None
649
+ ) -> "list[MemoryRecord]":
650
+ if not self._enabled:
651
+ msg = "Memory store is disabled"
652
+ raise RuntimeError(msg)
653
+
654
+ effective_limit = limit if limit is not None else self._max_results
655
+
656
+ if self._use_fts:
657
+ return self._search_entries_fts(query, app_name, user_id, effective_limit)
658
+ return self._search_entries_simple(query, app_name, user_id, effective_limit)
659
+
660
+ def _search_entries_fts(self, query: str, app_name: str, user_id: str, limit: int) -> "list[MemoryRecord]":
661
+ sql = f"""
662
+ SELECT id, session_id, app_name, user_id, event_id, author,
663
+ timestamp, content_json, content_text, metadata_json, inserted_at
664
+ FROM {self._memory_table}
665
+ WHERE app_name = @app_name
666
+ AND user_id = @user_id
667
+ AND SEARCH(content_tokens, @query)
668
+ ORDER BY timestamp DESC
669
+ LIMIT @limit
670
+ """
671
+ params = {"app_name": app_name, "user_id": user_id, "query": query, "limit": limit}
672
+ types = {
673
+ "app_name": SPANNER_PARAM_TYPES.STRING,
674
+ "user_id": SPANNER_PARAM_TYPES.STRING,
675
+ "query": SPANNER_PARAM_TYPES.STRING,
676
+ "limit": SPANNER_PARAM_TYPES.INT64,
677
+ }
678
+ rows = self._run_read(sql, params, types)
679
+ return self._rows_to_records(rows)
680
+
681
+ def _search_entries_simple(self, query: str, app_name: str, user_id: str, limit: int) -> "list[MemoryRecord]":
682
+ sql = f"""
683
+ SELECT id, session_id, app_name, user_id, event_id, author,
684
+ timestamp, content_json, content_text, metadata_json, inserted_at
685
+ FROM {self._memory_table}
686
+ WHERE app_name = @app_name
687
+ AND user_id = @user_id
688
+ AND LOWER(content_text) LIKE @pattern
689
+ ORDER BY timestamp DESC
690
+ LIMIT @limit
691
+ """
692
+ pattern = f"%{query.lower()}%"
693
+ params = {"app_name": app_name, "user_id": user_id, "pattern": pattern, "limit": limit}
694
+ types = {
695
+ "app_name": SPANNER_PARAM_TYPES.STRING,
696
+ "user_id": SPANNER_PARAM_TYPES.STRING,
697
+ "pattern": SPANNER_PARAM_TYPES.STRING,
698
+ "limit": SPANNER_PARAM_TYPES.INT64,
699
+ }
700
+ rows = self._run_read(sql, params, types)
701
+ return self._rows_to_records(rows)
702
+
703
+ def delete_entries_by_session(self, session_id: str) -> int:
704
+ sql = f"DELETE FROM {self._memory_table} WHERE session_id = @session_id"
705
+ params = {"session_id": session_id}
706
+ types = {"session_id": SPANNER_PARAM_TYPES.STRING}
707
+ return self._execute_update(sql, params, types)
708
+
709
+ def delete_entries_older_than(self, days: int) -> int:
710
+ cutoff = datetime.now(timezone.utc) - timedelta(days=days)
711
+ sql = f"DELETE FROM {self._memory_table} WHERE inserted_at < @cutoff"
712
+ params = {"cutoff": cutoff}
713
+ types = {"cutoff": SPANNER_PARAM_TYPES.TIMESTAMP}
714
+ return self._execute_update(sql, params, types)
715
+
716
+ def _rows_to_records(self, rows: "list[Any]") -> "list[MemoryRecord]":
717
+ return [
718
+ {
719
+ "id": row[0],
720
+ "session_id": row[1],
721
+ "app_name": row[2],
722
+ "user_id": row[3],
723
+ "event_id": row[4],
724
+ "author": row[5],
725
+ "timestamp": row[6],
726
+ "content_json": self._decode_json(row[7]),
727
+ "content_text": row[8],
728
+ "metadata_json": self._decode_json(row[9]),
729
+ "inserted_at": row[10],
730
+ }
731
+ for row in rows
732
+ ]