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,766 @@
1
+ """Psqlpy ADK store for Google Agent Development Kit session/event storage."""
2
+
3
+ import re
4
+ from typing import TYPE_CHECKING, Any, Final
5
+
6
+ import psqlpy.exceptions
7
+
8
+ from sqlspec.extensions.adk import BaseAsyncADKStore, EventRecord, SessionRecord
9
+ from sqlspec.extensions.adk.memory.store import BaseAsyncADKMemoryStore
10
+ from sqlspec.utils.logging import get_logger
11
+ from sqlspec.utils.type_guards import has_query_result_metadata
12
+
13
+ if TYPE_CHECKING:
14
+ from datetime import datetime
15
+
16
+ from sqlspec.adapters.psqlpy.config import PsqlpyConfig
17
+ from sqlspec.extensions.adk import MemoryRecord
18
+
19
+
20
+ __all__ = ("PsqlpyADKMemoryStore", "PsqlpyADKStore")
21
+
22
+ logger = get_logger("sqlspec.adapters.psqlpy.adk.store")
23
+
24
+ POSTGRES_TABLE_NOT_FOUND_SQLSTATE: Final = "42P01"
25
+
26
+
27
+ class PsqlpyADKStore(BaseAsyncADKStore["PsqlpyConfig"]):
28
+ """PostgreSQL ADK store using Psqlpy driver.
29
+
30
+ Implements session and event storage for Google Agent Development Kit
31
+ using PostgreSQL via the high-performance Rust-based psqlpy driver.
32
+
33
+ Provides:
34
+ - Session state management with JSONB storage
35
+ - Event history tracking with BYTEA-serialized actions
36
+ - Microsecond-precision timestamps with TIMESTAMPTZ
37
+ - Foreign key constraints with cascade delete
38
+ - Efficient upserts using ON CONFLICT
39
+ - GIN indexes for JSONB queries
40
+ - HOT updates with FILLFACTOR 80
41
+
42
+ Args:
43
+ config: PsqlpyConfig with extension_config["adk"] settings.
44
+
45
+ Example:
46
+ from sqlspec.adapters.psqlpy import PsqlpyConfig
47
+ from sqlspec.adapters.psqlpy.adk import PsqlpyADKStore
48
+
49
+ config = PsqlpyConfig(
50
+ connection_config={"dsn": "postgresql://..."},
51
+ extension_config={
52
+ "adk": {
53
+ "session_table": "my_sessions",
54
+ "events_table": "my_events",
55
+ "owner_id_column": "tenant_id INTEGER NOT NULL REFERENCES tenants(id) ON DELETE CASCADE"
56
+ }
57
+ }
58
+ )
59
+ store = PsqlpyADKStore(config)
60
+ await store.ensure_tables()
61
+
62
+ Notes:
63
+ - PostgreSQL JSONB type used for state (more efficient than JSON)
64
+ - Psqlpy automatically converts Python dicts to/from JSONB
65
+ - TIMESTAMPTZ provides timezone-aware microsecond precision
66
+ - BYTEA for pre-serialized actions from Google ADK
67
+ - GIN index on state for JSONB queries (partial index)
68
+ - FILLFACTOR 80 leaves space for HOT updates
69
+ - Uses PostgreSQL numeric parameter style ($1, $2, $3)
70
+ - Configuration is read from config.extension_config["adk"]
71
+ """
72
+
73
+ __slots__ = ()
74
+
75
+ def __init__(self, config: "PsqlpyConfig") -> None:
76
+ """Initialize Psqlpy ADK store.
77
+
78
+ Args:
79
+ config: PsqlpyConfig instance.
80
+
81
+ Notes:
82
+ Configuration is read from config.extension_config["adk"]:
83
+ - session_table: Sessions table name (default: "adk_sessions")
84
+ - events_table: Events table name (default: "adk_events")
85
+ - owner_id_column: Optional owner FK column DDL (default: None)
86
+ """
87
+ super().__init__(config)
88
+
89
+ async def _get_create_sessions_table_sql(self) -> str:
90
+ """Get PostgreSQL CREATE TABLE SQL for sessions.
91
+
92
+ Returns:
93
+ SQL statement to create adk_sessions table with indexes.
94
+
95
+ Notes:
96
+ - VARCHAR(128) for IDs and names (sufficient for UUIDs and app names)
97
+ - JSONB type for state storage with default empty object
98
+ - TIMESTAMPTZ with microsecond precision
99
+ - FILLFACTOR 80 for HOT updates (reduces table bloat)
100
+ - Composite index on (app_name, user_id) for listing
101
+ - Index on update_time DESC for recent session queries
102
+ - Partial GIN index on state for JSONB queries (only non-empty)
103
+ - Optional owner ID column for multi-tenancy or user references
104
+ """
105
+ owner_id_line = ""
106
+ if self._owner_id_column_ddl:
107
+ owner_id_line = f",\n {self._owner_id_column_ddl}"
108
+
109
+ return f"""
110
+ CREATE TABLE IF NOT EXISTS {self._session_table} (
111
+ id VARCHAR(128) PRIMARY KEY,
112
+ app_name VARCHAR(128) NOT NULL,
113
+ user_id VARCHAR(128) NOT NULL{owner_id_line},
114
+ state JSONB NOT NULL DEFAULT '{{}}'::jsonb,
115
+ create_time TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
116
+ update_time TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
117
+ ) WITH (fillfactor = 80);
118
+
119
+ CREATE INDEX IF NOT EXISTS idx_{self._session_table}_app_user
120
+ ON {self._session_table}(app_name, user_id);
121
+
122
+ CREATE INDEX IF NOT EXISTS idx_{self._session_table}_update_time
123
+ ON {self._session_table}(update_time DESC);
124
+
125
+ CREATE INDEX IF NOT EXISTS idx_{self._session_table}_state
126
+ ON {self._session_table} USING GIN (state)
127
+ WHERE state != '{{}}'::jsonb;
128
+ """
129
+
130
+ async def _get_create_events_table_sql(self) -> str:
131
+ """Get PostgreSQL CREATE TABLE SQL for events.
132
+
133
+ Returns:
134
+ SQL statement to create adk_events table with indexes.
135
+
136
+ Notes:
137
+ - VARCHAR sizes: id(128), session_id(128), invocation_id(256), author(256),
138
+ branch(256), error_code(256), error_message(1024)
139
+ - BYTEA for pre-serialized actions (no size limit)
140
+ - JSONB for content, grounding_metadata, custom_metadata, long_running_tool_ids_json
141
+ - BOOLEAN for partial, turn_complete, interrupted
142
+ - Foreign key to sessions with CASCADE delete
143
+ - Index on (session_id, timestamp ASC) for ordered event retrieval
144
+ """
145
+ return f"""
146
+ CREATE TABLE IF NOT EXISTS {self._events_table} (
147
+ id VARCHAR(128) PRIMARY KEY,
148
+ session_id VARCHAR(128) NOT NULL,
149
+ app_name VARCHAR(128) NOT NULL,
150
+ user_id VARCHAR(128) NOT NULL,
151
+ invocation_id VARCHAR(256),
152
+ author VARCHAR(256),
153
+ actions BYTEA,
154
+ long_running_tool_ids_json JSONB,
155
+ branch VARCHAR(256),
156
+ timestamp TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
157
+ content JSONB,
158
+ grounding_metadata JSONB,
159
+ custom_metadata JSONB,
160
+ partial BOOLEAN,
161
+ turn_complete BOOLEAN,
162
+ interrupted BOOLEAN,
163
+ error_code VARCHAR(256),
164
+ error_message VARCHAR(1024),
165
+ FOREIGN KEY (session_id) REFERENCES {self._session_table}(id) ON DELETE CASCADE
166
+ );
167
+
168
+ CREATE INDEX IF NOT EXISTS idx_{self._events_table}_session
169
+ ON {self._events_table}(session_id, timestamp ASC);
170
+ """
171
+
172
+ def _get_drop_tables_sql(self) -> "list[str]":
173
+ """Get PostgreSQL DROP TABLE SQL statements.
174
+
175
+ Returns:
176
+ List of SQL statements to drop tables and indexes.
177
+
178
+ Notes:
179
+ Order matters: drop events table (child) before sessions (parent).
180
+ PostgreSQL automatically drops indexes when dropping tables.
181
+ """
182
+ return [f"DROP TABLE IF EXISTS {self._events_table}", f"DROP TABLE IF EXISTS {self._session_table}"]
183
+
184
+ async def create_tables(self) -> None:
185
+ """Create both sessions and events tables if they don't exist.
186
+
187
+ Notes:
188
+ Uses driver.execute_script() which handles multiple statements.
189
+ Creates sessions table first, then events table (FK dependency).
190
+ """
191
+ async with self._config.provide_session() as driver:
192
+ await driver.execute_script(await self._get_create_sessions_table_sql())
193
+ await driver.execute_script(await self._get_create_events_table_sql())
194
+
195
+ async def create_session(
196
+ self, session_id: str, app_name: str, user_id: str, state: "dict[str, Any]", owner_id: "Any | None" = None
197
+ ) -> SessionRecord:
198
+ """Create a new session.
199
+
200
+ Args:
201
+ session_id: Unique session identifier.
202
+ app_name: Application name.
203
+ user_id: User identifier.
204
+ state: Initial session state.
205
+ owner_id: Optional owner ID value for owner_id_column (if configured).
206
+
207
+ Returns:
208
+ Created session record.
209
+
210
+ Notes:
211
+ Uses CURRENT_TIMESTAMP for create_time and update_time.
212
+ State is passed as dict and psqlpy converts to JSONB automatically.
213
+ If owner_id_column is configured, owner_id value must be provided.
214
+ """
215
+ async with self._config.provide_connection() as conn: # pyright: ignore[reportAttributeAccessIssue]
216
+ if self._owner_id_column_name:
217
+ sql = f"""
218
+ INSERT INTO {self._session_table}
219
+ (id, app_name, user_id, {self._owner_id_column_name}, state, create_time, update_time)
220
+ VALUES ($1, $2, $3, $4, $5, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
221
+ """
222
+ await conn.execute(sql, [session_id, app_name, user_id, owner_id, state])
223
+ else:
224
+ sql = f"""
225
+ INSERT INTO {self._session_table} (id, app_name, user_id, state, create_time, update_time)
226
+ VALUES ($1, $2, $3, $4, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
227
+ """
228
+ await conn.execute(sql, [session_id, app_name, user_id, state])
229
+
230
+ return await self.get_session(session_id) # type: ignore[return-value]
231
+
232
+ async def get_session(self, session_id: str) -> "SessionRecord | None":
233
+ """Get session by ID.
234
+
235
+ Args:
236
+ session_id: Session identifier.
237
+
238
+ Returns:
239
+ Session record or None if not found.
240
+
241
+ Notes:
242
+ PostgreSQL returns datetime objects for TIMESTAMPTZ columns.
243
+ JSONB is automatically parsed by psqlpy to Python dicts.
244
+ Returns None if table doesn't exist (catches database errors).
245
+ """
246
+ sql = f"""
247
+ SELECT id, app_name, user_id, state, create_time, update_time
248
+ FROM {self._session_table}
249
+ WHERE id = $1
250
+ """
251
+
252
+ try:
253
+ async with self._config.provide_connection() as conn: # pyright: ignore[reportAttributeAccessIssue]
254
+ result = await conn.fetch(sql, [session_id])
255
+ rows: list[dict[str, Any]] = result.result() if result else []
256
+
257
+ if not rows:
258
+ return None
259
+
260
+ row = rows[0]
261
+ return SessionRecord(
262
+ id=row["id"],
263
+ app_name=row["app_name"],
264
+ user_id=row["user_id"],
265
+ state=row["state"],
266
+ create_time=row["create_time"],
267
+ update_time=row["update_time"],
268
+ )
269
+ except psqlpy.exceptions.DatabaseError as e:
270
+ error_msg = str(e).lower()
271
+ if "does not exist" in error_msg or "relation" in error_msg:
272
+ return None
273
+ raise
274
+
275
+ async def update_session_state(self, session_id: str, state: "dict[str, Any]") -> None:
276
+ """Update session state.
277
+
278
+ Args:
279
+ session_id: Session identifier.
280
+ state: New state dictionary (replaces existing state).
281
+
282
+ Notes:
283
+ This replaces the entire state dictionary.
284
+ Uses CURRENT_TIMESTAMP for update_time.
285
+ Psqlpy automatically converts dict to JSONB.
286
+ """
287
+ sql = f"""
288
+ UPDATE {self._session_table}
289
+ SET state = $1, update_time = CURRENT_TIMESTAMP
290
+ WHERE id = $2
291
+ """
292
+
293
+ async with self._config.provide_connection() as conn: # pyright: ignore[reportAttributeAccessIssue]
294
+ await conn.execute(sql, [state, session_id])
295
+
296
+ async def delete_session(self, session_id: str) -> None:
297
+ """Delete session and all associated events (cascade).
298
+
299
+ Args:
300
+ session_id: Session identifier.
301
+
302
+ Notes:
303
+ Foreign key constraint ensures events are cascade-deleted.
304
+ """
305
+ sql = f"DELETE FROM {self._session_table} WHERE id = $1"
306
+
307
+ async with self._config.provide_connection() as conn: # pyright: ignore[reportAttributeAccessIssue]
308
+ await conn.execute(sql, [session_id])
309
+
310
+ async def list_sessions(self, app_name: str, user_id: str | None = None) -> "list[SessionRecord]":
311
+ """List sessions for an app, optionally filtered by user.
312
+
313
+ Args:
314
+ app_name: Application name.
315
+ user_id: User identifier. If None, lists all sessions for the app.
316
+
317
+ Returns:
318
+ List of session records ordered by update_time DESC.
319
+
320
+ Notes:
321
+ Uses composite index on (app_name, user_id) when user_id is provided.
322
+ Returns empty list if table doesn't exist.
323
+ """
324
+ if user_id is None:
325
+ sql = f"""
326
+ SELECT id, app_name, user_id, state, create_time, update_time
327
+ FROM {self._session_table}
328
+ WHERE app_name = $1
329
+ ORDER BY update_time DESC
330
+ """
331
+ params = [app_name]
332
+ else:
333
+ sql = f"""
334
+ SELECT id, app_name, user_id, state, create_time, update_time
335
+ FROM {self._session_table}
336
+ WHERE app_name = $1 AND user_id = $2
337
+ ORDER BY update_time DESC
338
+ """
339
+ params = [app_name, user_id]
340
+
341
+ try:
342
+ async with self._config.provide_connection() as conn: # pyright: ignore[reportAttributeAccessIssue]
343
+ result = await conn.fetch(sql, params)
344
+ rows: list[dict[str, Any]] = result.result() if result else []
345
+
346
+ return [
347
+ SessionRecord(
348
+ id=row["id"],
349
+ app_name=row["app_name"],
350
+ user_id=row["user_id"],
351
+ state=row["state"],
352
+ create_time=row["create_time"],
353
+ update_time=row["update_time"],
354
+ )
355
+ for row in rows
356
+ ]
357
+ except psqlpy.exceptions.DatabaseError as e:
358
+ error_msg = str(e).lower()
359
+ if "does not exist" in error_msg or "relation" in error_msg:
360
+ return []
361
+ raise
362
+
363
+ async def append_event(self, event_record: EventRecord) -> None:
364
+ """Append an event to a session.
365
+
366
+ Args:
367
+ event_record: Event record to store.
368
+
369
+ Notes:
370
+ Uses CURRENT_TIMESTAMP for timestamp if not provided.
371
+ JSONB fields are passed as dicts and psqlpy converts automatically.
372
+ BYTEA actions field stores pre-serialized data from Google ADK.
373
+ """
374
+ content_json = event_record.get("content")
375
+ grounding_metadata_json = event_record.get("grounding_metadata")
376
+ custom_metadata_json = event_record.get("custom_metadata")
377
+
378
+ sql = f"""
379
+ INSERT INTO {self._events_table} (
380
+ id, session_id, app_name, user_id, invocation_id, author, actions,
381
+ long_running_tool_ids_json, branch, timestamp, content,
382
+ grounding_metadata, custom_metadata, partial, turn_complete,
383
+ interrupted, error_code, error_message
384
+ ) VALUES (
385
+ $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18
386
+ )
387
+ """
388
+
389
+ async with self._config.provide_connection() as conn: # pyright: ignore[reportAttributeAccessIssue]
390
+ await conn.execute(
391
+ sql,
392
+ [
393
+ event_record["id"],
394
+ event_record["session_id"],
395
+ event_record["app_name"],
396
+ event_record["user_id"],
397
+ event_record.get("invocation_id"),
398
+ event_record.get("author"),
399
+ event_record.get("actions"),
400
+ event_record.get("long_running_tool_ids_json"),
401
+ event_record.get("branch"),
402
+ event_record["timestamp"],
403
+ content_json,
404
+ grounding_metadata_json,
405
+ custom_metadata_json,
406
+ event_record.get("partial"),
407
+ event_record.get("turn_complete"),
408
+ event_record.get("interrupted"),
409
+ event_record.get("error_code"),
410
+ event_record.get("error_message"),
411
+ ],
412
+ )
413
+
414
+ async def get_events(
415
+ self, session_id: str, after_timestamp: "datetime | None" = None, limit: "int | None" = None
416
+ ) -> "list[EventRecord]":
417
+ """Get events for a session.
418
+
419
+ Args:
420
+ session_id: Session identifier.
421
+ after_timestamp: Only return events after this time.
422
+ limit: Maximum number of events to return.
423
+
424
+ Returns:
425
+ List of event records ordered by timestamp ASC.
426
+
427
+ Notes:
428
+ Uses index on (session_id, timestamp ASC).
429
+ Parses JSONB fields and converts BYTEA actions to bytes.
430
+ Returns empty list if table doesn't exist.
431
+ """
432
+ where_clauses = ["session_id = $1"]
433
+ params: list[Any] = [session_id]
434
+
435
+ if after_timestamp is not None:
436
+ where_clauses.append(f"timestamp > ${len(params) + 1}")
437
+ params.append(after_timestamp)
438
+
439
+ where_clause = " AND ".join(where_clauses)
440
+ limit_clause = f" LIMIT ${len(params) + 1}" if limit else ""
441
+ if limit:
442
+ params.append(limit)
443
+
444
+ sql = f"""
445
+ SELECT id, session_id, app_name, user_id, invocation_id, author, actions,
446
+ long_running_tool_ids_json, branch, timestamp, content,
447
+ grounding_metadata, custom_metadata, partial, turn_complete,
448
+ interrupted, error_code, error_message
449
+ FROM {self._events_table}
450
+ WHERE {where_clause}
451
+ ORDER BY timestamp ASC{limit_clause}
452
+ """
453
+
454
+ try:
455
+ async with self._config.provide_connection() as conn: # pyright: ignore[reportAttributeAccessIssue]
456
+ result = await conn.fetch(sql, params)
457
+ rows: list[dict[str, Any]] = result.result() if result else []
458
+
459
+ return [
460
+ EventRecord(
461
+ id=row["id"],
462
+ session_id=row["session_id"],
463
+ app_name=row["app_name"],
464
+ user_id=row["user_id"],
465
+ invocation_id=row["invocation_id"],
466
+ author=row["author"],
467
+ actions=bytes(row["actions"]) if row["actions"] else b"",
468
+ long_running_tool_ids_json=row["long_running_tool_ids_json"],
469
+ branch=row["branch"],
470
+ timestamp=row["timestamp"],
471
+ content=row["content"],
472
+ grounding_metadata=row["grounding_metadata"],
473
+ custom_metadata=row["custom_metadata"],
474
+ partial=row["partial"],
475
+ turn_complete=row["turn_complete"],
476
+ interrupted=row["interrupted"],
477
+ error_code=row["error_code"],
478
+ error_message=row["error_message"],
479
+ )
480
+ for row in rows
481
+ ]
482
+ except psqlpy.exceptions.DatabaseError as e:
483
+ error_msg = str(e).lower()
484
+ if "does not exist" in error_msg or "relation" in error_msg:
485
+ return []
486
+ raise
487
+
488
+
489
+ PSQLPY_STATUS_REGEX: Final[re.Pattern[str]] = re.compile(r"^([A-Z]+)(?:\s+(\d+))?\s+(\d+)$", re.IGNORECASE)
490
+
491
+
492
+ class PsqlpyADKMemoryStore(BaseAsyncADKMemoryStore["PsqlpyConfig"]):
493
+ """PostgreSQL ADK memory store using Psqlpy driver."""
494
+
495
+ __slots__ = ()
496
+
497
+ def __init__(self, config: "PsqlpyConfig") -> None:
498
+ """Initialize Psqlpy memory store."""
499
+ super().__init__(config)
500
+
501
+ async def _get_create_memory_table_sql(self) -> str:
502
+ """Get PostgreSQL CREATE TABLE SQL for memory entries."""
503
+ owner_id_line = ""
504
+ if self._owner_id_column_ddl:
505
+ owner_id_line = f",\n {self._owner_id_column_ddl}"
506
+
507
+ fts_index = ""
508
+ if self._use_fts:
509
+ fts_index = f"""
510
+ CREATE INDEX IF NOT EXISTS idx_{self._memory_table}_fts
511
+ ON {self._memory_table} USING GIN (to_tsvector('english', content_text));
512
+ """
513
+
514
+ return f"""
515
+ CREATE TABLE IF NOT EXISTS {self._memory_table} (
516
+ id VARCHAR(128) PRIMARY KEY,
517
+ session_id VARCHAR(128) NOT NULL,
518
+ app_name VARCHAR(128) NOT NULL,
519
+ user_id VARCHAR(128) NOT NULL,
520
+ event_id VARCHAR(128) NOT NULL UNIQUE,
521
+ author VARCHAR(256){owner_id_line},
522
+ timestamp TIMESTAMPTZ NOT NULL,
523
+ content_json JSONB NOT NULL,
524
+ content_text TEXT NOT NULL,
525
+ metadata_json JSONB,
526
+ inserted_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
527
+ );
528
+
529
+ CREATE INDEX IF NOT EXISTS idx_{self._memory_table}_app_user_time
530
+ ON {self._memory_table}(app_name, user_id, timestamp DESC);
531
+
532
+ CREATE INDEX IF NOT EXISTS idx_{self._memory_table}_session
533
+ ON {self._memory_table}(session_id);
534
+ {fts_index}
535
+ """
536
+
537
+ def _get_drop_memory_table_sql(self) -> "list[str]":
538
+ """Get PostgreSQL DROP TABLE SQL statements."""
539
+ return [f"DROP TABLE IF EXISTS {self._memory_table}"]
540
+
541
+ async def create_tables(self) -> None:
542
+ """Create the memory table and indexes if they don't exist."""
543
+ if not self._enabled:
544
+ return
545
+
546
+ async with self._config.provide_session() as driver:
547
+ await driver.execute_script(await self._get_create_memory_table_sql())
548
+
549
+ async def insert_memory_entries(self, entries: "list[MemoryRecord]", owner_id: "object | None" = None) -> int:
550
+ """Bulk insert memory entries with deduplication."""
551
+ if not self._enabled:
552
+ msg = "Memory store is disabled"
553
+ raise RuntimeError(msg)
554
+
555
+ if not entries:
556
+ return 0
557
+
558
+ inserted_count = 0
559
+ if self._owner_id_column_name:
560
+ sql = f"""
561
+ INSERT INTO {self._memory_table} (
562
+ id, session_id, app_name, user_id, event_id, author,
563
+ {self._owner_id_column_name}, timestamp, content_json,
564
+ content_text, metadata_json, inserted_at
565
+ ) VALUES (
566
+ $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12
567
+ )
568
+ ON CONFLICT (event_id) DO NOTHING
569
+ """
570
+ else:
571
+ sql = f"""
572
+ INSERT INTO {self._memory_table} (
573
+ id, session_id, app_name, user_id, event_id, author,
574
+ timestamp, content_json, content_text, metadata_json, inserted_at
575
+ ) VALUES (
576
+ $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11
577
+ )
578
+ ON CONFLICT (event_id) DO NOTHING
579
+ """
580
+
581
+ async with self._config.provide_connection() as conn: # pyright: ignore[reportAttributeAccessIssue]
582
+ for entry in entries:
583
+ if self._owner_id_column_name:
584
+ params = [
585
+ entry["id"],
586
+ entry["session_id"],
587
+ entry["app_name"],
588
+ entry["user_id"],
589
+ entry["event_id"],
590
+ entry["author"],
591
+ owner_id,
592
+ entry["timestamp"],
593
+ entry["content_json"],
594
+ entry["content_text"],
595
+ entry["metadata_json"],
596
+ entry["inserted_at"],
597
+ ]
598
+ else:
599
+ params = [
600
+ entry["id"],
601
+ entry["session_id"],
602
+ entry["app_name"],
603
+ entry["user_id"],
604
+ entry["event_id"],
605
+ entry["author"],
606
+ entry["timestamp"],
607
+ entry["content_json"],
608
+ entry["content_text"],
609
+ entry["metadata_json"],
610
+ entry["inserted_at"],
611
+ ]
612
+
613
+ result = await conn.execute(sql, params)
614
+ rows_affected = self._extract_rows_affected(result)
615
+ if rows_affected > 0:
616
+ inserted_count += rows_affected
617
+
618
+ return inserted_count
619
+
620
+ async def search_entries(
621
+ self, query: str, app_name: str, user_id: str, limit: "int | None" = None
622
+ ) -> "list[MemoryRecord]":
623
+ """Search memory entries by text query."""
624
+ if not self._enabled:
625
+ msg = "Memory store is disabled"
626
+ raise RuntimeError(msg)
627
+
628
+ effective_limit = limit if limit is not None else self._max_results
629
+
630
+ try:
631
+ if self._use_fts:
632
+ try:
633
+ return await self._search_entries_fts(query, app_name, user_id, effective_limit)
634
+ except Exception as exc: # pragma: no cover - defensive fallback
635
+ logger.warning("FTS search failed; falling back to simple search: %s", exc)
636
+ return await self._search_entries_simple(query, app_name, user_id, effective_limit)
637
+ except psqlpy.exceptions.DatabaseError as e:
638
+ error_msg = str(e).lower()
639
+ if "does not exist" in error_msg or "relation" in error_msg:
640
+ return []
641
+ raise
642
+
643
+ async def _search_entries_fts(self, query: str, app_name: str, user_id: str, limit: int) -> "list[MemoryRecord]":
644
+ sql = f"""
645
+ SELECT id, session_id, app_name, user_id, event_id, author,
646
+ timestamp, content_json, content_text, metadata_json, inserted_at,
647
+ ts_rank(to_tsvector('english', content_text), plainto_tsquery('english', $1)) as rank
648
+ FROM {self._memory_table}
649
+ WHERE app_name = $2
650
+ AND user_id = $3
651
+ AND to_tsvector('english', content_text) @@ plainto_tsquery('english', $1)
652
+ ORDER BY rank DESC, timestamp DESC
653
+ LIMIT $4
654
+ """
655
+ params = [query, app_name, user_id, limit]
656
+ async with self._config.provide_connection() as conn: # pyright: ignore[reportAttributeAccessIssue]
657
+ result = await conn.fetch(sql, params)
658
+ rows: list[dict[str, Any]] = result.result() if result else []
659
+ return _rows_to_records(rows)
660
+
661
+ async def _search_entries_simple(self, query: str, app_name: str, user_id: str, limit: int) -> "list[MemoryRecord]":
662
+ sql = f"""
663
+ SELECT id, session_id, app_name, user_id, event_id, author,
664
+ timestamp, content_json, content_text, metadata_json, inserted_at
665
+ FROM {self._memory_table}
666
+ WHERE app_name = $1
667
+ AND user_id = $2
668
+ AND content_text ILIKE $3
669
+ ORDER BY timestamp DESC
670
+ LIMIT $4
671
+ """
672
+ pattern = f"%{query}%"
673
+ params = [app_name, user_id, pattern, limit]
674
+ async with self._config.provide_connection() as conn: # pyright: ignore[reportAttributeAccessIssue]
675
+ result = await conn.fetch(sql, params)
676
+ rows: list[dict[str, Any]] = result.result() if result else []
677
+ return _rows_to_records(rows)
678
+
679
+ async def delete_entries_by_session(self, session_id: str) -> int:
680
+ """Delete all memory entries for a specific session."""
681
+ count_sql = f"SELECT COUNT(*) AS count FROM {self._memory_table} WHERE session_id = $1"
682
+ delete_sql = f"DELETE FROM {self._memory_table} WHERE session_id = $1"
683
+
684
+ try:
685
+ async with self._config.provide_connection() as conn: # pyright: ignore[reportAttributeAccessIssue]
686
+ count_result = await conn.fetch(count_sql, [session_id])
687
+ count_rows: list[dict[str, Any]] = count_result.result() if count_result else []
688
+ count = int(count_rows[0]["count"]) if count_rows else 0
689
+ await conn.execute(delete_sql, [session_id])
690
+ return count
691
+ except psqlpy.exceptions.DatabaseError as e:
692
+ error_msg = str(e).lower()
693
+ if "does not exist" in error_msg or "relation" in error_msg:
694
+ return 0
695
+ raise
696
+
697
+ async def delete_entries_older_than(self, days: int) -> int:
698
+ """Delete memory entries older than specified days."""
699
+ count_sql = f"""
700
+ SELECT COUNT(*) AS count FROM {self._memory_table}
701
+ WHERE inserted_at < CURRENT_TIMESTAMP - INTERVAL '{days} days'
702
+ """
703
+ delete_sql = f"""
704
+ DELETE FROM {self._memory_table}
705
+ WHERE inserted_at < CURRENT_TIMESTAMP - INTERVAL '{days} days'
706
+ """
707
+
708
+ try:
709
+ async with self._config.provide_connection() as conn: # pyright: ignore[reportAttributeAccessIssue]
710
+ count_result = await conn.fetch(count_sql, [])
711
+ count_rows: list[dict[str, Any]] = count_result.result() if count_result else []
712
+ count = int(count_rows[0]["count"]) if count_rows else 0
713
+ await conn.execute(delete_sql, [])
714
+ return count
715
+ except psqlpy.exceptions.DatabaseError as e:
716
+ error_msg = str(e).lower()
717
+ if "does not exist" in error_msg or "relation" in error_msg:
718
+ return 0
719
+ raise
720
+
721
+ def _extract_rows_affected(self, result: Any) -> int:
722
+ """Extract rows affected from psqlpy result."""
723
+ try:
724
+ if has_query_result_metadata(result):
725
+ if result.tag:
726
+ return self._parse_command_tag(result.tag)
727
+ if result.status:
728
+ return self._parse_command_tag(result.status)
729
+ if isinstance(result, str):
730
+ return self._parse_command_tag(result)
731
+ except Exception as e:
732
+ logger.debug("Failed to parse psqlpy command tag: %s", e)
733
+ return -1
734
+
735
+ def _parse_command_tag(self, tag: str) -> int:
736
+ """Parse PostgreSQL command tag to extract rows affected."""
737
+ if not tag:
738
+ return -1
739
+
740
+ match = PSQLPY_STATUS_REGEX.match(tag.strip())
741
+ if match:
742
+ command = match.group(1).upper()
743
+ if command == "INSERT" and match.group(3):
744
+ return int(match.group(3))
745
+ if command in {"UPDATE", "DELETE"} and match.group(3):
746
+ return int(match.group(3))
747
+ return -1
748
+
749
+
750
+ def _rows_to_records(rows: "list[dict[str, Any]]") -> "list[MemoryRecord]":
751
+ return [
752
+ {
753
+ "id": row["id"],
754
+ "session_id": row["session_id"],
755
+ "app_name": row["app_name"],
756
+ "user_id": row["user_id"],
757
+ "event_id": row["event_id"],
758
+ "author": row["author"],
759
+ "timestamp": row["timestamp"],
760
+ "content_json": row["content_json"],
761
+ "content_text": row["content_text"],
762
+ "metadata_json": row["metadata_json"],
763
+ "inserted_at": row["inserted_at"],
764
+ }
765
+ for row in rows
766
+ ]