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.
- ac8f31065839703b4e70__mypyc.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/__init__.py +140 -0
- sqlspec/__main__.py +12 -0
- sqlspec/__metadata__.py +14 -0
- sqlspec/_serialization.py +315 -0
- sqlspec/_typing.py +700 -0
- sqlspec/adapters/__init__.py +0 -0
- sqlspec/adapters/adbc/__init__.py +5 -0
- sqlspec/adapters/adbc/_typing.py +82 -0
- sqlspec/adapters/adbc/adk/__init__.py +5 -0
- sqlspec/adapters/adbc/adk/store.py +1273 -0
- sqlspec/adapters/adbc/config.py +295 -0
- sqlspec/adapters/adbc/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/adbc/core.py +735 -0
- sqlspec/adapters/adbc/data_dictionary.py +334 -0
- sqlspec/adapters/adbc/driver.py +529 -0
- sqlspec/adapters/adbc/events/__init__.py +5 -0
- sqlspec/adapters/adbc/events/store.py +285 -0
- sqlspec/adapters/adbc/litestar/__init__.py +5 -0
- sqlspec/adapters/adbc/litestar/store.py +502 -0
- sqlspec/adapters/adbc/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/adbc/type_converter.py +140 -0
- sqlspec/adapters/aiosqlite/__init__.py +25 -0
- sqlspec/adapters/aiosqlite/_typing.py +82 -0
- sqlspec/adapters/aiosqlite/adk/__init__.py +5 -0
- sqlspec/adapters/aiosqlite/adk/store.py +818 -0
- sqlspec/adapters/aiosqlite/config.py +334 -0
- sqlspec/adapters/aiosqlite/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/aiosqlite/core.py +315 -0
- sqlspec/adapters/aiosqlite/data_dictionary.py +208 -0
- sqlspec/adapters/aiosqlite/driver.py +313 -0
- sqlspec/adapters/aiosqlite/events/__init__.py +5 -0
- sqlspec/adapters/aiosqlite/events/store.py +20 -0
- sqlspec/adapters/aiosqlite/litestar/__init__.py +5 -0
- sqlspec/adapters/aiosqlite/litestar/store.py +279 -0
- sqlspec/adapters/aiosqlite/pool.py +533 -0
- sqlspec/adapters/asyncmy/__init__.py +21 -0
- sqlspec/adapters/asyncmy/_typing.py +87 -0
- sqlspec/adapters/asyncmy/adk/__init__.py +5 -0
- sqlspec/adapters/asyncmy/adk/store.py +703 -0
- sqlspec/adapters/asyncmy/config.py +302 -0
- sqlspec/adapters/asyncmy/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/asyncmy/core.py +360 -0
- sqlspec/adapters/asyncmy/data_dictionary.py +124 -0
- sqlspec/adapters/asyncmy/driver.py +383 -0
- sqlspec/adapters/asyncmy/events/__init__.py +5 -0
- sqlspec/adapters/asyncmy/events/store.py +104 -0
- sqlspec/adapters/asyncmy/litestar/__init__.py +5 -0
- sqlspec/adapters/asyncmy/litestar/store.py +296 -0
- sqlspec/adapters/asyncpg/__init__.py +19 -0
- sqlspec/adapters/asyncpg/_typing.py +88 -0
- sqlspec/adapters/asyncpg/adk/__init__.py +5 -0
- sqlspec/adapters/asyncpg/adk/store.py +748 -0
- sqlspec/adapters/asyncpg/config.py +569 -0
- sqlspec/adapters/asyncpg/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/asyncpg/core.py +367 -0
- sqlspec/adapters/asyncpg/data_dictionary.py +162 -0
- sqlspec/adapters/asyncpg/driver.py +487 -0
- sqlspec/adapters/asyncpg/events/__init__.py +6 -0
- sqlspec/adapters/asyncpg/events/backend.py +286 -0
- sqlspec/adapters/asyncpg/events/store.py +40 -0
- sqlspec/adapters/asyncpg/litestar/__init__.py +5 -0
- sqlspec/adapters/asyncpg/litestar/store.py +251 -0
- sqlspec/adapters/bigquery/__init__.py +14 -0
- sqlspec/adapters/bigquery/_typing.py +86 -0
- sqlspec/adapters/bigquery/adk/__init__.py +5 -0
- sqlspec/adapters/bigquery/adk/store.py +827 -0
- sqlspec/adapters/bigquery/config.py +353 -0
- sqlspec/adapters/bigquery/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/bigquery/core.py +715 -0
- sqlspec/adapters/bigquery/data_dictionary.py +128 -0
- sqlspec/adapters/bigquery/driver.py +548 -0
- sqlspec/adapters/bigquery/events/__init__.py +5 -0
- sqlspec/adapters/bigquery/events/store.py +139 -0
- sqlspec/adapters/bigquery/litestar/__init__.py +5 -0
- sqlspec/adapters/bigquery/litestar/store.py +325 -0
- sqlspec/adapters/bigquery/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/bigquery/type_converter.py +107 -0
- sqlspec/adapters/cockroach_asyncpg/__init__.py +24 -0
- sqlspec/adapters/cockroach_asyncpg/_typing.py +72 -0
- sqlspec/adapters/cockroach_asyncpg/adk/__init__.py +3 -0
- sqlspec/adapters/cockroach_asyncpg/adk/store.py +410 -0
- sqlspec/adapters/cockroach_asyncpg/config.py +238 -0
- sqlspec/adapters/cockroach_asyncpg/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/cockroach_asyncpg/core.py +55 -0
- sqlspec/adapters/cockroach_asyncpg/data_dictionary.py +107 -0
- sqlspec/adapters/cockroach_asyncpg/driver.py +144 -0
- sqlspec/adapters/cockroach_asyncpg/events/__init__.py +3 -0
- sqlspec/adapters/cockroach_asyncpg/events/store.py +20 -0
- sqlspec/adapters/cockroach_asyncpg/litestar/__init__.py +3 -0
- sqlspec/adapters/cockroach_asyncpg/litestar/store.py +142 -0
- sqlspec/adapters/cockroach_psycopg/__init__.py +38 -0
- sqlspec/adapters/cockroach_psycopg/_typing.py +129 -0
- sqlspec/adapters/cockroach_psycopg/adk/__init__.py +13 -0
- sqlspec/adapters/cockroach_psycopg/adk/store.py +868 -0
- sqlspec/adapters/cockroach_psycopg/config.py +484 -0
- sqlspec/adapters/cockroach_psycopg/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/cockroach_psycopg/core.py +63 -0
- sqlspec/adapters/cockroach_psycopg/data_dictionary.py +215 -0
- sqlspec/adapters/cockroach_psycopg/driver.py +284 -0
- sqlspec/adapters/cockroach_psycopg/events/__init__.py +6 -0
- sqlspec/adapters/cockroach_psycopg/events/store.py +34 -0
- sqlspec/adapters/cockroach_psycopg/litestar/__init__.py +3 -0
- sqlspec/adapters/cockroach_psycopg/litestar/store.py +325 -0
- sqlspec/adapters/duckdb/__init__.py +25 -0
- sqlspec/adapters/duckdb/_typing.py +81 -0
- sqlspec/adapters/duckdb/adk/__init__.py +14 -0
- sqlspec/adapters/duckdb/adk/store.py +850 -0
- sqlspec/adapters/duckdb/config.py +463 -0
- sqlspec/adapters/duckdb/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/duckdb/core.py +257 -0
- sqlspec/adapters/duckdb/data_dictionary.py +140 -0
- sqlspec/adapters/duckdb/driver.py +430 -0
- sqlspec/adapters/duckdb/events/__init__.py +5 -0
- sqlspec/adapters/duckdb/events/store.py +57 -0
- sqlspec/adapters/duckdb/litestar/__init__.py +5 -0
- sqlspec/adapters/duckdb/litestar/store.py +330 -0
- sqlspec/adapters/duckdb/pool.py +293 -0
- sqlspec/adapters/duckdb/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/duckdb/type_converter.py +118 -0
- sqlspec/adapters/mock/__init__.py +72 -0
- sqlspec/adapters/mock/_typing.py +147 -0
- sqlspec/adapters/mock/config.py +483 -0
- sqlspec/adapters/mock/core.py +319 -0
- sqlspec/adapters/mock/data_dictionary.py +366 -0
- sqlspec/adapters/mock/driver.py +721 -0
- sqlspec/adapters/mysqlconnector/__init__.py +36 -0
- sqlspec/adapters/mysqlconnector/_typing.py +141 -0
- sqlspec/adapters/mysqlconnector/adk/__init__.py +15 -0
- sqlspec/adapters/mysqlconnector/adk/store.py +1060 -0
- sqlspec/adapters/mysqlconnector/config.py +394 -0
- sqlspec/adapters/mysqlconnector/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/mysqlconnector/core.py +303 -0
- sqlspec/adapters/mysqlconnector/data_dictionary.py +235 -0
- sqlspec/adapters/mysqlconnector/driver.py +483 -0
- sqlspec/adapters/mysqlconnector/events/__init__.py +8 -0
- sqlspec/adapters/mysqlconnector/events/store.py +98 -0
- sqlspec/adapters/mysqlconnector/litestar/__init__.py +5 -0
- sqlspec/adapters/mysqlconnector/litestar/store.py +426 -0
- sqlspec/adapters/oracledb/__init__.py +60 -0
- sqlspec/adapters/oracledb/_numpy_handlers.py +141 -0
- sqlspec/adapters/oracledb/_typing.py +182 -0
- sqlspec/adapters/oracledb/_uuid_handlers.py +166 -0
- sqlspec/adapters/oracledb/adk/__init__.py +10 -0
- sqlspec/adapters/oracledb/adk/store.py +2369 -0
- sqlspec/adapters/oracledb/config.py +550 -0
- sqlspec/adapters/oracledb/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/oracledb/core.py +543 -0
- sqlspec/adapters/oracledb/data_dictionary.py +536 -0
- sqlspec/adapters/oracledb/driver.py +1229 -0
- sqlspec/adapters/oracledb/events/__init__.py +16 -0
- sqlspec/adapters/oracledb/events/backend.py +347 -0
- sqlspec/adapters/oracledb/events/store.py +420 -0
- sqlspec/adapters/oracledb/litestar/__init__.py +5 -0
- sqlspec/adapters/oracledb/litestar/store.py +781 -0
- sqlspec/adapters/oracledb/migrations.py +535 -0
- sqlspec/adapters/oracledb/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/oracledb/type_converter.py +211 -0
- sqlspec/adapters/psqlpy/__init__.py +17 -0
- sqlspec/adapters/psqlpy/_typing.py +79 -0
- sqlspec/adapters/psqlpy/adk/__init__.py +5 -0
- sqlspec/adapters/psqlpy/adk/store.py +766 -0
- sqlspec/adapters/psqlpy/config.py +304 -0
- sqlspec/adapters/psqlpy/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/psqlpy/core.py +480 -0
- sqlspec/adapters/psqlpy/data_dictionary.py +126 -0
- sqlspec/adapters/psqlpy/driver.py +438 -0
- sqlspec/adapters/psqlpy/events/__init__.py +6 -0
- sqlspec/adapters/psqlpy/events/backend.py +310 -0
- sqlspec/adapters/psqlpy/events/store.py +20 -0
- sqlspec/adapters/psqlpy/litestar/__init__.py +5 -0
- sqlspec/adapters/psqlpy/litestar/store.py +270 -0
- sqlspec/adapters/psqlpy/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/psqlpy/type_converter.py +113 -0
- sqlspec/adapters/psycopg/__init__.py +32 -0
- sqlspec/adapters/psycopg/_typing.py +164 -0
- sqlspec/adapters/psycopg/adk/__init__.py +10 -0
- sqlspec/adapters/psycopg/adk/store.py +1387 -0
- sqlspec/adapters/psycopg/config.py +576 -0
- sqlspec/adapters/psycopg/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/psycopg/core.py +450 -0
- sqlspec/adapters/psycopg/data_dictionary.py +289 -0
- sqlspec/adapters/psycopg/driver.py +975 -0
- sqlspec/adapters/psycopg/events/__init__.py +20 -0
- sqlspec/adapters/psycopg/events/backend.py +458 -0
- sqlspec/adapters/psycopg/events/store.py +42 -0
- sqlspec/adapters/psycopg/litestar/__init__.py +5 -0
- sqlspec/adapters/psycopg/litestar/store.py +552 -0
- sqlspec/adapters/psycopg/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/psycopg/type_converter.py +93 -0
- sqlspec/adapters/pymysql/__init__.py +21 -0
- sqlspec/adapters/pymysql/_typing.py +71 -0
- sqlspec/adapters/pymysql/adk/__init__.py +5 -0
- sqlspec/adapters/pymysql/adk/store.py +540 -0
- sqlspec/adapters/pymysql/config.py +195 -0
- sqlspec/adapters/pymysql/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/pymysql/core.py +299 -0
- sqlspec/adapters/pymysql/data_dictionary.py +122 -0
- sqlspec/adapters/pymysql/driver.py +259 -0
- sqlspec/adapters/pymysql/events/__init__.py +5 -0
- sqlspec/adapters/pymysql/events/store.py +50 -0
- sqlspec/adapters/pymysql/litestar/__init__.py +5 -0
- sqlspec/adapters/pymysql/litestar/store.py +232 -0
- sqlspec/adapters/pymysql/pool.py +137 -0
- sqlspec/adapters/spanner/__init__.py +40 -0
- sqlspec/adapters/spanner/_typing.py +86 -0
- sqlspec/adapters/spanner/adk/__init__.py +5 -0
- sqlspec/adapters/spanner/adk/store.py +732 -0
- sqlspec/adapters/spanner/config.py +352 -0
- sqlspec/adapters/spanner/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/spanner/core.py +188 -0
- sqlspec/adapters/spanner/data_dictionary.py +120 -0
- sqlspec/adapters/spanner/dialect/__init__.py +6 -0
- sqlspec/adapters/spanner/dialect/_spangres.py +57 -0
- sqlspec/adapters/spanner/dialect/_spanner.py +130 -0
- sqlspec/adapters/spanner/driver.py +373 -0
- sqlspec/adapters/spanner/events/__init__.py +5 -0
- sqlspec/adapters/spanner/events/store.py +187 -0
- sqlspec/adapters/spanner/litestar/__init__.py +5 -0
- sqlspec/adapters/spanner/litestar/store.py +291 -0
- sqlspec/adapters/spanner/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/spanner/type_converter.py +331 -0
- sqlspec/adapters/sqlite/__init__.py +19 -0
- sqlspec/adapters/sqlite/_typing.py +80 -0
- sqlspec/adapters/sqlite/adk/__init__.py +5 -0
- sqlspec/adapters/sqlite/adk/store.py +958 -0
- sqlspec/adapters/sqlite/config.py +280 -0
- sqlspec/adapters/sqlite/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/sqlite/core.py +312 -0
- sqlspec/adapters/sqlite/data_dictionary.py +202 -0
- sqlspec/adapters/sqlite/driver.py +359 -0
- sqlspec/adapters/sqlite/events/__init__.py +5 -0
- sqlspec/adapters/sqlite/events/store.py +20 -0
- sqlspec/adapters/sqlite/litestar/__init__.py +5 -0
- sqlspec/adapters/sqlite/litestar/store.py +316 -0
- sqlspec/adapters/sqlite/pool.py +198 -0
- sqlspec/adapters/sqlite/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/sqlite/type_converter.py +114 -0
- sqlspec/base.py +747 -0
- sqlspec/builder/__init__.py +179 -0
- sqlspec/builder/_base.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_base.py +1022 -0
- sqlspec/builder/_column.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_column.py +521 -0
- sqlspec/builder/_ddl.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_ddl.py +1642 -0
- sqlspec/builder/_delete.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_delete.py +95 -0
- sqlspec/builder/_dml.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_dml.py +365 -0
- sqlspec/builder/_explain.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_explain.py +579 -0
- sqlspec/builder/_expression_wrappers.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_expression_wrappers.py +46 -0
- sqlspec/builder/_factory.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_factory.py +1697 -0
- sqlspec/builder/_insert.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_insert.py +328 -0
- sqlspec/builder/_join.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_join.py +499 -0
- sqlspec/builder/_merge.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_merge.py +821 -0
- sqlspec/builder/_parsing_utils.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_parsing_utils.py +297 -0
- sqlspec/builder/_select.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_select.py +1660 -0
- sqlspec/builder/_temporal.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_temporal.py +139 -0
- sqlspec/builder/_update.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_update.py +173 -0
- sqlspec/builder/_vector_expressions.py +267 -0
- sqlspec/cli.py +911 -0
- sqlspec/config.py +1755 -0
- sqlspec/core/__init__.py +374 -0
- sqlspec/core/_correlation.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/_correlation.py +176 -0
- sqlspec/core/cache.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/cache.py +1069 -0
- sqlspec/core/compiler.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/compiler.py +954 -0
- sqlspec/core/explain.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/explain.py +275 -0
- sqlspec/core/filters.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/filters.py +952 -0
- sqlspec/core/hashing.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/hashing.py +262 -0
- sqlspec/core/metrics.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/metrics.py +83 -0
- sqlspec/core/parameters/__init__.py +71 -0
- sqlspec/core/parameters/_alignment.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/parameters/_alignment.py +270 -0
- sqlspec/core/parameters/_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/parameters/_converter.py +543 -0
- sqlspec/core/parameters/_processor.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/parameters/_processor.py +505 -0
- sqlspec/core/parameters/_registry.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/parameters/_registry.py +206 -0
- sqlspec/core/parameters/_transformers.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/parameters/_transformers.py +292 -0
- sqlspec/core/parameters/_types.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/parameters/_types.py +499 -0
- sqlspec/core/parameters/_validator.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/parameters/_validator.py +180 -0
- sqlspec/core/pipeline.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/pipeline.py +319 -0
- sqlspec/core/query_modifiers.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/query_modifiers.py +437 -0
- sqlspec/core/result/__init__.py +23 -0
- sqlspec/core/result/_base.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/result/_base.py +1121 -0
- sqlspec/core/result/_io.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/result/_io.py +28 -0
- sqlspec/core/splitter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/splitter.py +966 -0
- sqlspec/core/stack.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/stack.py +163 -0
- sqlspec/core/statement.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/statement.py +1503 -0
- sqlspec/core/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/type_converter.py +339 -0
- sqlspec/data_dictionary/__init__.py +22 -0
- sqlspec/data_dictionary/_loader.py +123 -0
- sqlspec/data_dictionary/_registry.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/_registry.py +74 -0
- sqlspec/data_dictionary/_types.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/_types.py +121 -0
- sqlspec/data_dictionary/dialects/__init__.py +21 -0
- sqlspec/data_dictionary/dialects/bigquery.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/dialects/bigquery.py +49 -0
- sqlspec/data_dictionary/dialects/cockroachdb.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/dialects/cockroachdb.py +43 -0
- sqlspec/data_dictionary/dialects/duckdb.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/dialects/duckdb.py +47 -0
- sqlspec/data_dictionary/dialects/mysql.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/dialects/mysql.py +42 -0
- sqlspec/data_dictionary/dialects/oracle.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/dialects/oracle.py +34 -0
- sqlspec/data_dictionary/dialects/postgres.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/dialects/postgres.py +46 -0
- sqlspec/data_dictionary/dialects/spanner.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/dialects/spanner.py +37 -0
- sqlspec/data_dictionary/dialects/sqlite.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/dialects/sqlite.py +42 -0
- sqlspec/data_dictionary/sql/.gitkeep +0 -0
- sqlspec/data_dictionary/sql/bigquery/columns.sql +23 -0
- sqlspec/data_dictionary/sql/bigquery/foreign_keys.sql +34 -0
- sqlspec/data_dictionary/sql/bigquery/indexes.sql +19 -0
- sqlspec/data_dictionary/sql/bigquery/tables.sql +33 -0
- sqlspec/data_dictionary/sql/bigquery/version.sql +3 -0
- sqlspec/data_dictionary/sql/cockroachdb/columns.sql +34 -0
- sqlspec/data_dictionary/sql/cockroachdb/foreign_keys.sql +40 -0
- sqlspec/data_dictionary/sql/cockroachdb/indexes.sql +32 -0
- sqlspec/data_dictionary/sql/cockroachdb/tables.sql +44 -0
- sqlspec/data_dictionary/sql/cockroachdb/version.sql +3 -0
- sqlspec/data_dictionary/sql/duckdb/columns.sql +23 -0
- sqlspec/data_dictionary/sql/duckdb/foreign_keys.sql +36 -0
- sqlspec/data_dictionary/sql/duckdb/indexes.sql +19 -0
- sqlspec/data_dictionary/sql/duckdb/tables.sql +38 -0
- sqlspec/data_dictionary/sql/duckdb/version.sql +3 -0
- sqlspec/data_dictionary/sql/mysql/columns.sql +23 -0
- sqlspec/data_dictionary/sql/mysql/foreign_keys.sql +28 -0
- sqlspec/data_dictionary/sql/mysql/indexes.sql +26 -0
- sqlspec/data_dictionary/sql/mysql/tables.sql +33 -0
- sqlspec/data_dictionary/sql/mysql/version.sql +3 -0
- sqlspec/data_dictionary/sql/oracle/columns.sql +23 -0
- sqlspec/data_dictionary/sql/oracle/foreign_keys.sql +48 -0
- sqlspec/data_dictionary/sql/oracle/indexes.sql +44 -0
- sqlspec/data_dictionary/sql/oracle/tables.sql +25 -0
- sqlspec/data_dictionary/sql/oracle/version.sql +20 -0
- sqlspec/data_dictionary/sql/postgres/columns.sql +34 -0
- sqlspec/data_dictionary/sql/postgres/foreign_keys.sql +40 -0
- sqlspec/data_dictionary/sql/postgres/indexes.sql +56 -0
- sqlspec/data_dictionary/sql/postgres/tables.sql +44 -0
- sqlspec/data_dictionary/sql/postgres/version.sql +3 -0
- sqlspec/data_dictionary/sql/spanner/columns.sql +23 -0
- sqlspec/data_dictionary/sql/spanner/foreign_keys.sql +70 -0
- sqlspec/data_dictionary/sql/spanner/indexes.sql +30 -0
- sqlspec/data_dictionary/sql/spanner/tables.sql +9 -0
- sqlspec/data_dictionary/sql/spanner/version.sql +3 -0
- sqlspec/data_dictionary/sql/sqlite/columns.sql +23 -0
- sqlspec/data_dictionary/sql/sqlite/foreign_keys.sql +22 -0
- sqlspec/data_dictionary/sql/sqlite/indexes.sql +7 -0
- sqlspec/data_dictionary/sql/sqlite/tables.sql +28 -0
- sqlspec/data_dictionary/sql/sqlite/version.sql +3 -0
- sqlspec/driver/__init__.py +32 -0
- sqlspec/driver/_async.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/driver/_async.py +1737 -0
- sqlspec/driver/_common.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/driver/_common.py +1478 -0
- sqlspec/driver/_sql_helpers.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/driver/_sql_helpers.py +148 -0
- sqlspec/driver/_storage_helpers.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/driver/_storage_helpers.py +144 -0
- sqlspec/driver/_sync.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/driver/_sync.py +1710 -0
- sqlspec/exceptions.py +338 -0
- sqlspec/extensions/__init__.py +0 -0
- sqlspec/extensions/adk/__init__.py +70 -0
- sqlspec/extensions/adk/_types.py +51 -0
- sqlspec/extensions/adk/converters.py +172 -0
- sqlspec/extensions/adk/memory/__init__.py +69 -0
- sqlspec/extensions/adk/memory/_types.py +30 -0
- sqlspec/extensions/adk/memory/converters.py +149 -0
- sqlspec/extensions/adk/memory/service.py +217 -0
- sqlspec/extensions/adk/memory/store.py +569 -0
- sqlspec/extensions/adk/migrations/0001_create_adk_tables.py +246 -0
- sqlspec/extensions/adk/migrations/__init__.py +0 -0
- sqlspec/extensions/adk/service.py +225 -0
- sqlspec/extensions/adk/store.py +567 -0
- sqlspec/extensions/events/__init__.py +51 -0
- sqlspec/extensions/events/_channel.py +703 -0
- sqlspec/extensions/events/_hints.py +45 -0
- sqlspec/extensions/events/_models.py +23 -0
- sqlspec/extensions/events/_payload.py +69 -0
- sqlspec/extensions/events/_protocols.py +134 -0
- sqlspec/extensions/events/_queue.py +461 -0
- sqlspec/extensions/events/_store.py +209 -0
- sqlspec/extensions/events/migrations/0001_create_event_queue.py +59 -0
- sqlspec/extensions/events/migrations/__init__.py +3 -0
- sqlspec/extensions/fastapi/__init__.py +19 -0
- sqlspec/extensions/fastapi/extension.py +351 -0
- sqlspec/extensions/fastapi/providers.py +607 -0
- sqlspec/extensions/flask/__init__.py +37 -0
- sqlspec/extensions/flask/_state.py +76 -0
- sqlspec/extensions/flask/_utils.py +71 -0
- sqlspec/extensions/flask/extension.py +519 -0
- sqlspec/extensions/litestar/__init__.py +28 -0
- sqlspec/extensions/litestar/_utils.py +52 -0
- sqlspec/extensions/litestar/channels.py +165 -0
- sqlspec/extensions/litestar/cli.py +102 -0
- sqlspec/extensions/litestar/config.py +90 -0
- sqlspec/extensions/litestar/handlers.py +316 -0
- sqlspec/extensions/litestar/migrations/0001_create_session_table.py +137 -0
- sqlspec/extensions/litestar/migrations/__init__.py +3 -0
- sqlspec/extensions/litestar/plugin.py +671 -0
- sqlspec/extensions/litestar/providers.py +526 -0
- sqlspec/extensions/litestar/store.py +296 -0
- sqlspec/extensions/otel/__init__.py +58 -0
- sqlspec/extensions/prometheus/__init__.py +113 -0
- sqlspec/extensions/starlette/__init__.py +19 -0
- sqlspec/extensions/starlette/_state.py +30 -0
- sqlspec/extensions/starlette/_utils.py +96 -0
- sqlspec/extensions/starlette/extension.py +346 -0
- sqlspec/extensions/starlette/middleware.py +235 -0
- sqlspec/loader.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/loader.py +702 -0
- sqlspec/migrations/__init__.py +36 -0
- sqlspec/migrations/base.py +731 -0
- sqlspec/migrations/commands.py +1232 -0
- sqlspec/migrations/context.py +157 -0
- sqlspec/migrations/fix.py +204 -0
- sqlspec/migrations/loaders.py +443 -0
- sqlspec/migrations/runner.py +1172 -0
- sqlspec/migrations/templates.py +234 -0
- sqlspec/migrations/tracker.py +611 -0
- sqlspec/migrations/utils.py +256 -0
- sqlspec/migrations/validation.py +207 -0
- sqlspec/migrations/version.py +446 -0
- sqlspec/observability/__init__.py +55 -0
- sqlspec/observability/_common.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_common.py +77 -0
- sqlspec/observability/_config.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_config.py +348 -0
- sqlspec/observability/_diagnostics.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_diagnostics.py +74 -0
- sqlspec/observability/_dispatcher.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_dispatcher.py +152 -0
- sqlspec/observability/_formatters/__init__.py +13 -0
- sqlspec/observability/_formatters/_aws.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_formatters/_aws.py +102 -0
- sqlspec/observability/_formatters/_azure.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_formatters/_azure.py +96 -0
- sqlspec/observability/_formatters/_base.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_formatters/_base.py +57 -0
- sqlspec/observability/_formatters/_gcp.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_formatters/_gcp.py +131 -0
- sqlspec/observability/_formatting.py +58 -0
- sqlspec/observability/_observer.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_observer.py +357 -0
- sqlspec/observability/_runtime.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_runtime.py +420 -0
- sqlspec/observability/_sampling.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_sampling.py +188 -0
- sqlspec/observability/_spans.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_spans.py +161 -0
- sqlspec/protocols.py +916 -0
- sqlspec/py.typed +0 -0
- sqlspec/storage/__init__.py +48 -0
- sqlspec/storage/_utils.py +104 -0
- sqlspec/storage/backends/__init__.py +1 -0
- sqlspec/storage/backends/base.py +253 -0
- sqlspec/storage/backends/fsspec.py +529 -0
- sqlspec/storage/backends/local.py +441 -0
- sqlspec/storage/backends/obstore.py +916 -0
- sqlspec/storage/errors.py +104 -0
- sqlspec/storage/pipeline.py +582 -0
- sqlspec/storage/registry.py +301 -0
- sqlspec/typing.py +395 -0
- sqlspec/utils/__init__.py +7 -0
- sqlspec/utils/arrow_helpers.py +318 -0
- sqlspec/utils/config_tools.py +332 -0
- sqlspec/utils/correlation.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/correlation.py +134 -0
- sqlspec/utils/deprecation.py +190 -0
- sqlspec/utils/fixtures.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/fixtures.py +258 -0
- sqlspec/utils/logging.py +222 -0
- sqlspec/utils/module_loader.py +306 -0
- sqlspec/utils/portal.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/portal.py +375 -0
- sqlspec/utils/schema.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/schema.py +485 -0
- sqlspec/utils/serializers.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/serializers.py +408 -0
- sqlspec/utils/singleton.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/singleton.py +41 -0
- sqlspec/utils/sync_tools.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/sync_tools.py +311 -0
- sqlspec/utils/text.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/text.py +108 -0
- sqlspec/utils/type_converters.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/type_converters.py +128 -0
- sqlspec/utils/type_guards.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/type_guards.py +1360 -0
- sqlspec/utils/uuids.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/uuids.py +225 -0
- sqlspec-0.36.0.dist-info/METADATA +205 -0
- sqlspec-0.36.0.dist-info/RECORD +531 -0
- sqlspec-0.36.0.dist-info/WHEEL +7 -0
- sqlspec-0.36.0.dist-info/entry_points.txt +2 -0
- sqlspec-0.36.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,703 @@
|
|
|
1
|
+
"""AsyncMy ADK store for Google Agent Development Kit session/event storage."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from typing import TYPE_CHECKING, Any, Final, cast
|
|
5
|
+
|
|
6
|
+
import asyncmy
|
|
7
|
+
|
|
8
|
+
from sqlspec.extensions.adk import BaseAsyncADKStore, EventRecord, SessionRecord
|
|
9
|
+
from sqlspec.extensions.adk.memory.store import BaseAsyncADKMemoryStore
|
|
10
|
+
from sqlspec.utils.serializers import from_json, to_json
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from datetime import datetime
|
|
14
|
+
|
|
15
|
+
from sqlspec.adapters.asyncmy.config import AsyncmyConfig
|
|
16
|
+
from sqlspec.extensions.adk import MemoryRecord
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
__all__ = ("AsyncmyADKMemoryStore", "AsyncmyADKStore")
|
|
20
|
+
|
|
21
|
+
MYSQL_TABLE_NOT_FOUND_ERROR: Final = 1146
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class AsyncmyADKStore(BaseAsyncADKStore["AsyncmyConfig"]):
|
|
25
|
+
"""MySQL/MariaDB ADK store using AsyncMy driver.
|
|
26
|
+
|
|
27
|
+
Implements session and event storage for Google Agent Development Kit
|
|
28
|
+
using MySQL/MariaDB via the AsyncMy driver. Provides:
|
|
29
|
+
- Session state management with JSON storage
|
|
30
|
+
- Event history tracking with BLOB-serialized actions
|
|
31
|
+
- Microsecond-precision timestamps
|
|
32
|
+
- Foreign key constraints with cascade delete
|
|
33
|
+
- Efficient upserts using ON DUPLICATE KEY UPDATE
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
config: AsyncmyConfig with extension_config["adk"] settings.
|
|
37
|
+
|
|
38
|
+
Example:
|
|
39
|
+
from sqlspec.adapters.asyncmy import AsyncmyConfig
|
|
40
|
+
from sqlspec.adapters.asyncmy.adk import AsyncmyADKStore
|
|
41
|
+
|
|
42
|
+
config = AsyncmyConfig(
|
|
43
|
+
connection_config={"host": "localhost", ...},
|
|
44
|
+
extension_config={
|
|
45
|
+
"adk": {
|
|
46
|
+
"session_table": "my_sessions",
|
|
47
|
+
"events_table": "my_events",
|
|
48
|
+
"owner_id_column": "tenant_id BIGINT NOT NULL REFERENCES tenants(id) ON DELETE CASCADE"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
)
|
|
52
|
+
store = AsyncmyADKStore(config)
|
|
53
|
+
await store.ensure_tables()
|
|
54
|
+
|
|
55
|
+
Notes:
|
|
56
|
+
- MySQL JSON type used (not JSONB) - requires MySQL 5.7.8+
|
|
57
|
+
- TIMESTAMP(6) provides microsecond precision
|
|
58
|
+
- InnoDB engine required for foreign key support
|
|
59
|
+
- State merging handled at application level
|
|
60
|
+
- Configuration is read from config.extension_config["adk"]
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
__slots__ = ()
|
|
64
|
+
|
|
65
|
+
def __init__(self, config: "AsyncmyConfig") -> None:
|
|
66
|
+
"""Initialize AsyncMy ADK store.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
config: AsyncmyConfig instance.
|
|
70
|
+
|
|
71
|
+
Notes:
|
|
72
|
+
Configuration is read from config.extension_config["adk"]:
|
|
73
|
+
- session_table: Sessions table name (default: "adk_sessions")
|
|
74
|
+
- events_table: Events table name (default: "adk_events")
|
|
75
|
+
- owner_id_column: Optional owner FK column DDL (default: None)
|
|
76
|
+
"""
|
|
77
|
+
super().__init__(config)
|
|
78
|
+
|
|
79
|
+
def _parse_owner_id_column_for_mysql(self, column_ddl: str) -> "tuple[str, str]":
|
|
80
|
+
"""Parse owner ID column DDL for MySQL FOREIGN KEY syntax.
|
|
81
|
+
|
|
82
|
+
MySQL ignores inline REFERENCES syntax in column definitions.
|
|
83
|
+
This method extracts the column definition and creates a separate
|
|
84
|
+
FOREIGN KEY constraint.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
column_ddl: Column DDL like "tenant_id BIGINT NOT NULL REFERENCES tenants(id) ON DELETE CASCADE"
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
Tuple of (column_definition, foreign_key_constraint)
|
|
91
|
+
|
|
92
|
+
Example:
|
|
93
|
+
Input: "tenant_id BIGINT NOT NULL REFERENCES tenants(id) ON DELETE CASCADE"
|
|
94
|
+
Output: ("tenant_id BIGINT NOT NULL", "FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE")
|
|
95
|
+
"""
|
|
96
|
+
references_match = re.search(r"\s+REFERENCES\s+(.+)", column_ddl, re.IGNORECASE)
|
|
97
|
+
|
|
98
|
+
if not references_match:
|
|
99
|
+
return (column_ddl.strip(), "")
|
|
100
|
+
|
|
101
|
+
col_def = column_ddl[: references_match.start()].strip()
|
|
102
|
+
fk_clause = references_match.group(1).strip()
|
|
103
|
+
col_name = col_def.split()[0]
|
|
104
|
+
fk_constraint = f"FOREIGN KEY ({col_name}) REFERENCES {fk_clause}"
|
|
105
|
+
|
|
106
|
+
return (col_def, fk_constraint)
|
|
107
|
+
|
|
108
|
+
async def _get_create_sessions_table_sql(self) -> str:
|
|
109
|
+
"""Get MySQL CREATE TABLE SQL for sessions.
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
SQL statement to create adk_sessions table with indexes.
|
|
113
|
+
|
|
114
|
+
Notes:
|
|
115
|
+
- VARCHAR(128) for IDs and names (sufficient for UUIDs and app names)
|
|
116
|
+
- JSON type for state storage (MySQL 5.7.8+)
|
|
117
|
+
- TIMESTAMP(6) with microsecond precision
|
|
118
|
+
- AUTO-UPDATE on update_time
|
|
119
|
+
- Composite index on (app_name, user_id) for listing
|
|
120
|
+
- Index on update_time DESC for recent session queries
|
|
121
|
+
- Optional owner ID column for multi-tenancy
|
|
122
|
+
- MySQL requires explicit FOREIGN KEY syntax (inline REFERENCES is ignored)
|
|
123
|
+
"""
|
|
124
|
+
owner_id_col = ""
|
|
125
|
+
fk_constraint = ""
|
|
126
|
+
|
|
127
|
+
if self._owner_id_column_ddl:
|
|
128
|
+
col_def, fk_def = self._parse_owner_id_column_for_mysql(self._owner_id_column_ddl)
|
|
129
|
+
owner_id_col = f"{col_def},"
|
|
130
|
+
if fk_def:
|
|
131
|
+
fk_constraint = f",\n {fk_def}"
|
|
132
|
+
|
|
133
|
+
return f"""
|
|
134
|
+
CREATE TABLE IF NOT EXISTS {self._session_table} (
|
|
135
|
+
id VARCHAR(128) PRIMARY KEY,
|
|
136
|
+
app_name VARCHAR(128) NOT NULL,
|
|
137
|
+
user_id VARCHAR(128) NOT NULL,
|
|
138
|
+
{owner_id_col}
|
|
139
|
+
state JSON NOT NULL,
|
|
140
|
+
create_time TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
|
141
|
+
update_time TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
|
142
|
+
INDEX idx_{self._session_table}_app_user (app_name, user_id),
|
|
143
|
+
INDEX idx_{self._session_table}_update_time (update_time DESC){fk_constraint}
|
|
144
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
|
145
|
+
"""
|
|
146
|
+
|
|
147
|
+
async def _get_create_events_table_sql(self) -> str:
|
|
148
|
+
"""Get MySQL CREATE TABLE SQL for events.
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
SQL statement to create adk_events table with indexes.
|
|
152
|
+
|
|
153
|
+
Notes:
|
|
154
|
+
- VARCHAR sizes: id(128), session_id(128), invocation_id(256), author(256),
|
|
155
|
+
branch(256), error_code(256), error_message(1024)
|
|
156
|
+
- BLOB for pickled actions (up to 64KB)
|
|
157
|
+
- JSON for content, grounding_metadata, custom_metadata, long_running_tool_ids_json
|
|
158
|
+
- BOOLEAN for partial, turn_complete, interrupted
|
|
159
|
+
- Foreign key to sessions with CASCADE delete
|
|
160
|
+
- Index on (session_id, timestamp ASC) for ordered event retrieval
|
|
161
|
+
"""
|
|
162
|
+
return f"""
|
|
163
|
+
CREATE TABLE IF NOT EXISTS {self._events_table} (
|
|
164
|
+
id VARCHAR(128) PRIMARY KEY,
|
|
165
|
+
session_id VARCHAR(128) NOT NULL,
|
|
166
|
+
app_name VARCHAR(128) NOT NULL,
|
|
167
|
+
user_id VARCHAR(128) NOT NULL,
|
|
168
|
+
invocation_id VARCHAR(256) NOT NULL,
|
|
169
|
+
author VARCHAR(256) NOT NULL,
|
|
170
|
+
actions BLOB NOT NULL,
|
|
171
|
+
long_running_tool_ids_json JSON,
|
|
172
|
+
branch VARCHAR(256),
|
|
173
|
+
timestamp TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
|
174
|
+
content JSON,
|
|
175
|
+
grounding_metadata JSON,
|
|
176
|
+
custom_metadata JSON,
|
|
177
|
+
partial BOOLEAN,
|
|
178
|
+
turn_complete BOOLEAN,
|
|
179
|
+
interrupted BOOLEAN,
|
|
180
|
+
error_code VARCHAR(256),
|
|
181
|
+
error_message VARCHAR(1024),
|
|
182
|
+
FOREIGN KEY (session_id) REFERENCES {self._session_table}(id) ON DELETE CASCADE,
|
|
183
|
+
INDEX idx_{self._events_table}_session (session_id, timestamp ASC)
|
|
184
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
|
185
|
+
"""
|
|
186
|
+
|
|
187
|
+
def _get_drop_tables_sql(self) -> "list[str]":
|
|
188
|
+
"""Get MySQL DROP TABLE SQL statements.
|
|
189
|
+
|
|
190
|
+
Returns:
|
|
191
|
+
List of SQL statements to drop tables and indexes.
|
|
192
|
+
|
|
193
|
+
Notes:
|
|
194
|
+
Order matters: drop events table (child) before sessions (parent).
|
|
195
|
+
MySQL automatically drops indexes when dropping tables.
|
|
196
|
+
"""
|
|
197
|
+
return [f"DROP TABLE IF EXISTS {self._events_table}", f"DROP TABLE IF EXISTS {self._session_table}"]
|
|
198
|
+
|
|
199
|
+
async def create_tables(self) -> None:
|
|
200
|
+
"""Create both sessions and events tables if they don't exist."""
|
|
201
|
+
async with self._config.provide_session() as driver:
|
|
202
|
+
await driver.execute_script(await self._get_create_sessions_table_sql())
|
|
203
|
+
await driver.execute_script(await self._get_create_events_table_sql())
|
|
204
|
+
|
|
205
|
+
async def create_session(
|
|
206
|
+
self, session_id: str, app_name: str, user_id: str, state: "dict[str, Any]", owner_id: "Any | None" = None
|
|
207
|
+
) -> SessionRecord:
|
|
208
|
+
"""Create a new session.
|
|
209
|
+
|
|
210
|
+
Args:
|
|
211
|
+
session_id: Unique session identifier.
|
|
212
|
+
app_name: Application name.
|
|
213
|
+
user_id: User identifier.
|
|
214
|
+
state: Initial session state.
|
|
215
|
+
owner_id: Optional owner ID value for owner_id_column (if configured).
|
|
216
|
+
|
|
217
|
+
Returns:
|
|
218
|
+
Created session record.
|
|
219
|
+
|
|
220
|
+
Notes:
|
|
221
|
+
Uses INSERT with UTC_TIMESTAMP(6) for create_time and update_time.
|
|
222
|
+
State is JSON-serialized before insertion.
|
|
223
|
+
If owner_id_column is configured, owner_id must be provided.
|
|
224
|
+
"""
|
|
225
|
+
state_json = to_json(state)
|
|
226
|
+
|
|
227
|
+
params: tuple[Any, ...]
|
|
228
|
+
if self._owner_id_column_name:
|
|
229
|
+
sql = f"""
|
|
230
|
+
INSERT INTO {self._session_table} (id, app_name, user_id, {self._owner_id_column_name}, state, create_time, update_time)
|
|
231
|
+
VALUES (%s, %s, %s, %s, %s, UTC_TIMESTAMP(6), UTC_TIMESTAMP(6))
|
|
232
|
+
"""
|
|
233
|
+
params = (session_id, app_name, user_id, owner_id, state_json)
|
|
234
|
+
else:
|
|
235
|
+
sql = f"""
|
|
236
|
+
INSERT INTO {self._session_table} (id, app_name, user_id, state, create_time, update_time)
|
|
237
|
+
VALUES (%s, %s, %s, %s, UTC_TIMESTAMP(6), UTC_TIMESTAMP(6))
|
|
238
|
+
"""
|
|
239
|
+
params = (session_id, app_name, user_id, state_json)
|
|
240
|
+
|
|
241
|
+
async with self._config.provide_connection() as conn, conn.cursor() as cursor:
|
|
242
|
+
await cursor.execute(sql, params)
|
|
243
|
+
await conn.commit()
|
|
244
|
+
|
|
245
|
+
return await self.get_session(session_id) # type: ignore[return-value]
|
|
246
|
+
|
|
247
|
+
async def get_session(self, session_id: str) -> "SessionRecord | None":
|
|
248
|
+
"""Get session by ID.
|
|
249
|
+
|
|
250
|
+
Args:
|
|
251
|
+
session_id: Session identifier.
|
|
252
|
+
|
|
253
|
+
Returns:
|
|
254
|
+
Session record or None if not found.
|
|
255
|
+
|
|
256
|
+
Notes:
|
|
257
|
+
MySQL returns datetime objects for TIMESTAMP columns.
|
|
258
|
+
JSON is parsed from database storage.
|
|
259
|
+
"""
|
|
260
|
+
sql = f"""
|
|
261
|
+
SELECT id, app_name, user_id, state, create_time, update_time
|
|
262
|
+
FROM {self._session_table}
|
|
263
|
+
WHERE id = %s
|
|
264
|
+
"""
|
|
265
|
+
|
|
266
|
+
try:
|
|
267
|
+
async with self._config.provide_connection() as conn, conn.cursor() as cursor:
|
|
268
|
+
await cursor.execute(sql, (session_id,))
|
|
269
|
+
row = await cursor.fetchone()
|
|
270
|
+
|
|
271
|
+
if row is None:
|
|
272
|
+
return None
|
|
273
|
+
|
|
274
|
+
session_id_val, app_name, user_id, state_json, create_time, update_time = row
|
|
275
|
+
|
|
276
|
+
return SessionRecord(
|
|
277
|
+
id=session_id_val,
|
|
278
|
+
app_name=app_name,
|
|
279
|
+
user_id=user_id,
|
|
280
|
+
state=from_json(state_json) if isinstance(state_json, str) else state_json,
|
|
281
|
+
create_time=create_time,
|
|
282
|
+
update_time=update_time,
|
|
283
|
+
)
|
|
284
|
+
except asyncmy.errors.ProgrammingError as e: # pyright: ignore[reportAttributeAccessIssue][reportAttributeAccessIssue]
|
|
285
|
+
if "doesn't exist" in str(e) or e.args[0] == MYSQL_TABLE_NOT_FOUND_ERROR:
|
|
286
|
+
return None
|
|
287
|
+
raise
|
|
288
|
+
|
|
289
|
+
async def update_session_state(self, session_id: str, state: "dict[str, Any]") -> None:
|
|
290
|
+
"""Update session state.
|
|
291
|
+
|
|
292
|
+
Args:
|
|
293
|
+
session_id: Session identifier.
|
|
294
|
+
state: New state dictionary (replaces existing state).
|
|
295
|
+
|
|
296
|
+
Notes:
|
|
297
|
+
This replaces the entire state dictionary.
|
|
298
|
+
Uses update_time auto-update trigger.
|
|
299
|
+
"""
|
|
300
|
+
state_json = to_json(state)
|
|
301
|
+
|
|
302
|
+
sql = f"""
|
|
303
|
+
UPDATE {self._session_table}
|
|
304
|
+
SET state = %s
|
|
305
|
+
WHERE id = %s
|
|
306
|
+
"""
|
|
307
|
+
|
|
308
|
+
async with self._config.provide_connection() as conn, conn.cursor() as cursor:
|
|
309
|
+
await cursor.execute(sql, (state_json, session_id))
|
|
310
|
+
await conn.commit()
|
|
311
|
+
|
|
312
|
+
async def delete_session(self, session_id: str) -> None:
|
|
313
|
+
"""Delete session and all associated events (cascade).
|
|
314
|
+
|
|
315
|
+
Args:
|
|
316
|
+
session_id: Session identifier.
|
|
317
|
+
|
|
318
|
+
Notes:
|
|
319
|
+
Foreign key constraint ensures events are cascade-deleted.
|
|
320
|
+
"""
|
|
321
|
+
sql = f"DELETE FROM {self._session_table} WHERE id = %s"
|
|
322
|
+
|
|
323
|
+
async with self._config.provide_connection() as conn, conn.cursor() as cursor:
|
|
324
|
+
await cursor.execute(sql, (session_id,))
|
|
325
|
+
await conn.commit()
|
|
326
|
+
|
|
327
|
+
async def list_sessions(self, app_name: str, user_id: str | None = None) -> "list[SessionRecord]":
|
|
328
|
+
"""List sessions for an app, optionally filtered by user.
|
|
329
|
+
|
|
330
|
+
Args:
|
|
331
|
+
app_name: Application name.
|
|
332
|
+
user_id: User identifier. If None, lists all sessions for the app.
|
|
333
|
+
|
|
334
|
+
Returns:
|
|
335
|
+
List of session records ordered by update_time DESC.
|
|
336
|
+
|
|
337
|
+
Notes:
|
|
338
|
+
Uses composite index on (app_name, user_id) when user_id is provided.
|
|
339
|
+
"""
|
|
340
|
+
if user_id is None:
|
|
341
|
+
sql = f"""
|
|
342
|
+
SELECT id, app_name, user_id, state, create_time, update_time
|
|
343
|
+
FROM {self._session_table}
|
|
344
|
+
WHERE app_name = %s
|
|
345
|
+
ORDER BY update_time DESC
|
|
346
|
+
"""
|
|
347
|
+
params: tuple[str, ...] = (app_name,)
|
|
348
|
+
else:
|
|
349
|
+
sql = f"""
|
|
350
|
+
SELECT id, app_name, user_id, state, create_time, update_time
|
|
351
|
+
FROM {self._session_table}
|
|
352
|
+
WHERE app_name = %s AND user_id = %s
|
|
353
|
+
ORDER BY update_time DESC
|
|
354
|
+
"""
|
|
355
|
+
params = (app_name, user_id)
|
|
356
|
+
|
|
357
|
+
try:
|
|
358
|
+
async with self._config.provide_connection() as conn, conn.cursor() as cursor:
|
|
359
|
+
await cursor.execute(sql, params)
|
|
360
|
+
rows = await cursor.fetchall()
|
|
361
|
+
|
|
362
|
+
return [
|
|
363
|
+
SessionRecord(
|
|
364
|
+
id=row[0],
|
|
365
|
+
app_name=row[1],
|
|
366
|
+
user_id=row[2],
|
|
367
|
+
state=from_json(row[3]) if isinstance(row[3], str) else row[3],
|
|
368
|
+
create_time=row[4],
|
|
369
|
+
update_time=row[5],
|
|
370
|
+
)
|
|
371
|
+
for row in rows
|
|
372
|
+
]
|
|
373
|
+
except asyncmy.errors.ProgrammingError as e: # pyright: ignore[reportAttributeAccessIssue]
|
|
374
|
+
if "doesn't exist" in str(e) or e.args[0] == MYSQL_TABLE_NOT_FOUND_ERROR:
|
|
375
|
+
return []
|
|
376
|
+
raise
|
|
377
|
+
|
|
378
|
+
async def append_event(self, event_record: EventRecord) -> None:
|
|
379
|
+
"""Append an event to a session.
|
|
380
|
+
|
|
381
|
+
Args:
|
|
382
|
+
event_record: Event record to store.
|
|
383
|
+
|
|
384
|
+
Notes:
|
|
385
|
+
Uses UTC_TIMESTAMP(6) for timestamp if not provided.
|
|
386
|
+
JSON fields are serialized before insertion.
|
|
387
|
+
"""
|
|
388
|
+
content_json = to_json(event_record.get("content")) if event_record.get("content") else None
|
|
389
|
+
grounding_metadata_json = (
|
|
390
|
+
to_json(event_record.get("grounding_metadata")) if event_record.get("grounding_metadata") else None
|
|
391
|
+
)
|
|
392
|
+
custom_metadata_json = (
|
|
393
|
+
to_json(event_record.get("custom_metadata")) if event_record.get("custom_metadata") else None
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
sql = f"""
|
|
397
|
+
INSERT INTO {self._events_table} (
|
|
398
|
+
id, session_id, app_name, user_id, invocation_id, author, actions,
|
|
399
|
+
long_running_tool_ids_json, branch, timestamp, content,
|
|
400
|
+
grounding_metadata, custom_metadata, partial, turn_complete,
|
|
401
|
+
interrupted, error_code, error_message
|
|
402
|
+
) VALUES (
|
|
403
|
+
%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s
|
|
404
|
+
)
|
|
405
|
+
"""
|
|
406
|
+
|
|
407
|
+
async with self._config.provide_connection() as conn, conn.cursor() as cursor:
|
|
408
|
+
await cursor.execute(
|
|
409
|
+
sql,
|
|
410
|
+
(
|
|
411
|
+
event_record["id"],
|
|
412
|
+
event_record["session_id"],
|
|
413
|
+
event_record["app_name"],
|
|
414
|
+
event_record["user_id"],
|
|
415
|
+
event_record["invocation_id"],
|
|
416
|
+
event_record["author"],
|
|
417
|
+
event_record["actions"],
|
|
418
|
+
event_record.get("long_running_tool_ids_json"),
|
|
419
|
+
event_record.get("branch"),
|
|
420
|
+
event_record["timestamp"],
|
|
421
|
+
content_json,
|
|
422
|
+
grounding_metadata_json,
|
|
423
|
+
custom_metadata_json,
|
|
424
|
+
event_record.get("partial"),
|
|
425
|
+
event_record.get("turn_complete"),
|
|
426
|
+
event_record.get("interrupted"),
|
|
427
|
+
event_record.get("error_code"),
|
|
428
|
+
event_record.get("error_message"),
|
|
429
|
+
),
|
|
430
|
+
)
|
|
431
|
+
await conn.commit()
|
|
432
|
+
|
|
433
|
+
async def get_events(
|
|
434
|
+
self, session_id: str, after_timestamp: "datetime | None" = None, limit: "int | None" = None
|
|
435
|
+
) -> "list[EventRecord]":
|
|
436
|
+
"""Get events for a session.
|
|
437
|
+
|
|
438
|
+
Args:
|
|
439
|
+
session_id: Session identifier.
|
|
440
|
+
after_timestamp: Only return events after this time.
|
|
441
|
+
limit: Maximum number of events to return.
|
|
442
|
+
|
|
443
|
+
Returns:
|
|
444
|
+
List of event records ordered by timestamp ASC.
|
|
445
|
+
|
|
446
|
+
Notes:
|
|
447
|
+
Uses index on (session_id, timestamp ASC).
|
|
448
|
+
Parses JSON fields and converts BLOB actions to bytes.
|
|
449
|
+
"""
|
|
450
|
+
where_clauses = ["session_id = %s"]
|
|
451
|
+
params: list[Any] = [session_id]
|
|
452
|
+
|
|
453
|
+
if after_timestamp is not None:
|
|
454
|
+
where_clauses.append("timestamp > %s")
|
|
455
|
+
params.append(after_timestamp)
|
|
456
|
+
|
|
457
|
+
where_clause = " AND ".join(where_clauses)
|
|
458
|
+
limit_clause = f" LIMIT {limit}" if limit else ""
|
|
459
|
+
|
|
460
|
+
sql = f"""
|
|
461
|
+
SELECT id, session_id, app_name, user_id, invocation_id, author, actions,
|
|
462
|
+
long_running_tool_ids_json, branch, timestamp, content,
|
|
463
|
+
grounding_metadata, custom_metadata, partial, turn_complete,
|
|
464
|
+
interrupted, error_code, error_message
|
|
465
|
+
FROM {self._events_table}
|
|
466
|
+
WHERE {where_clause}
|
|
467
|
+
ORDER BY timestamp ASC{limit_clause}
|
|
468
|
+
"""
|
|
469
|
+
|
|
470
|
+
try:
|
|
471
|
+
async with self._config.provide_connection() as conn, conn.cursor() as cursor:
|
|
472
|
+
await cursor.execute(sql, params)
|
|
473
|
+
rows = await cursor.fetchall()
|
|
474
|
+
|
|
475
|
+
return [
|
|
476
|
+
EventRecord(
|
|
477
|
+
id=row[0],
|
|
478
|
+
session_id=row[1],
|
|
479
|
+
app_name=row[2],
|
|
480
|
+
user_id=row[3],
|
|
481
|
+
invocation_id=row[4],
|
|
482
|
+
author=row[5],
|
|
483
|
+
actions=bytes(row[6]),
|
|
484
|
+
long_running_tool_ids_json=row[7],
|
|
485
|
+
branch=row[8],
|
|
486
|
+
timestamp=row[9],
|
|
487
|
+
content=from_json(row[10]) if row[10] and isinstance(row[10], str) else row[10],
|
|
488
|
+
grounding_metadata=from_json(row[11]) if row[11] and isinstance(row[11], str) else row[11],
|
|
489
|
+
custom_metadata=from_json(row[12]) if row[12] and isinstance(row[12], str) else row[12],
|
|
490
|
+
partial=row[13],
|
|
491
|
+
turn_complete=row[14],
|
|
492
|
+
interrupted=row[15],
|
|
493
|
+
error_code=row[16],
|
|
494
|
+
error_message=row[17],
|
|
495
|
+
)
|
|
496
|
+
for row in rows
|
|
497
|
+
]
|
|
498
|
+
except asyncmy.errors.ProgrammingError as e: # pyright: ignore[reportAttributeAccessIssue]
|
|
499
|
+
if "doesn't exist" in str(e) or e.args[0] == MYSQL_TABLE_NOT_FOUND_ERROR:
|
|
500
|
+
return []
|
|
501
|
+
raise
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
def _parse_owner_id_column_for_mysql(column_ddl: str) -> "tuple[str, str]":
|
|
505
|
+
"""Parse owner ID column DDL for MySQL FOREIGN KEY syntax.
|
|
506
|
+
|
|
507
|
+
Args:
|
|
508
|
+
column_ddl: Column DDL like "tenant_id BIGINT NOT NULL REFERENCES tenants(id) ON DELETE CASCADE".
|
|
509
|
+
|
|
510
|
+
Returns:
|
|
511
|
+
Tuple of (column_definition, foreign_key_constraint).
|
|
512
|
+
"""
|
|
513
|
+
references_match = re.search(r"\s+REFERENCES\s+(.+)", column_ddl, re.IGNORECASE)
|
|
514
|
+
if not references_match:
|
|
515
|
+
return (column_ddl.strip(), "")
|
|
516
|
+
|
|
517
|
+
col_def = column_ddl[: references_match.start()].strip()
|
|
518
|
+
fk_clause = references_match.group(1).strip()
|
|
519
|
+
col_name = col_def.split()[0]
|
|
520
|
+
fk_constraint = f"FOREIGN KEY ({col_name}) REFERENCES {fk_clause}"
|
|
521
|
+
return (col_def, fk_constraint)
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
class AsyncmyADKMemoryStore(BaseAsyncADKMemoryStore["AsyncmyConfig"]):
|
|
525
|
+
"""MySQL/MariaDB ADK memory store using AsyncMy driver."""
|
|
526
|
+
|
|
527
|
+
__slots__ = ()
|
|
528
|
+
|
|
529
|
+
def __init__(self, config: "AsyncmyConfig") -> None:
|
|
530
|
+
"""Initialize AsyncMy memory store."""
|
|
531
|
+
super().__init__(config)
|
|
532
|
+
|
|
533
|
+
async def _get_create_memory_table_sql(self) -> str:
|
|
534
|
+
"""Get MySQL CREATE TABLE SQL for memory entries."""
|
|
535
|
+
owner_id_line = ""
|
|
536
|
+
fk_constraint = ""
|
|
537
|
+
if self._owner_id_column_ddl:
|
|
538
|
+
col_def, fk_def = _parse_owner_id_column_for_mysql(self._owner_id_column_ddl)
|
|
539
|
+
owner_id_line = f",\n {col_def}"
|
|
540
|
+
if fk_def:
|
|
541
|
+
fk_constraint = f",\n {fk_def}"
|
|
542
|
+
|
|
543
|
+
fts_index = ""
|
|
544
|
+
if self._use_fts:
|
|
545
|
+
fts_index = f",\n FULLTEXT INDEX idx_{self._memory_table}_fts (content_text)"
|
|
546
|
+
|
|
547
|
+
return f"""
|
|
548
|
+
CREATE TABLE IF NOT EXISTS {self._memory_table} (
|
|
549
|
+
id VARCHAR(128) PRIMARY KEY,
|
|
550
|
+
session_id VARCHAR(128) NOT NULL,
|
|
551
|
+
app_name VARCHAR(128) NOT NULL,
|
|
552
|
+
user_id VARCHAR(128) NOT NULL,
|
|
553
|
+
event_id VARCHAR(128) NOT NULL UNIQUE,
|
|
554
|
+
author VARCHAR(256){owner_id_line},
|
|
555
|
+
timestamp TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
|
556
|
+
content_json JSON NOT NULL,
|
|
557
|
+
content_text TEXT NOT NULL,
|
|
558
|
+
metadata_json JSON,
|
|
559
|
+
inserted_at TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
|
560
|
+
INDEX idx_{self._memory_table}_app_user_time (app_name, user_id, timestamp),
|
|
561
|
+
INDEX idx_{self._memory_table}_session (session_id){fts_index}{fk_constraint}
|
|
562
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
|
563
|
+
"""
|
|
564
|
+
|
|
565
|
+
def _get_drop_memory_table_sql(self) -> "list[str]":
|
|
566
|
+
"""Get MySQL DROP TABLE SQL statements."""
|
|
567
|
+
return [f"DROP TABLE IF EXISTS {self._memory_table}"]
|
|
568
|
+
|
|
569
|
+
async def create_tables(self) -> None:
|
|
570
|
+
"""Create the memory table and indexes if they don't exist."""
|
|
571
|
+
if not self._enabled:
|
|
572
|
+
return
|
|
573
|
+
|
|
574
|
+
async with self._config.provide_session() as driver:
|
|
575
|
+
await driver.execute_script(await self._get_create_memory_table_sql())
|
|
576
|
+
|
|
577
|
+
async def insert_memory_entries(self, entries: "list[MemoryRecord]", owner_id: "object | None" = None) -> int:
|
|
578
|
+
"""Bulk insert memory entries with deduplication."""
|
|
579
|
+
if not self._enabled:
|
|
580
|
+
msg = "Memory store is disabled"
|
|
581
|
+
raise RuntimeError(msg)
|
|
582
|
+
|
|
583
|
+
if not entries:
|
|
584
|
+
return 0
|
|
585
|
+
|
|
586
|
+
inserted_count = 0
|
|
587
|
+
if self._owner_id_column_name:
|
|
588
|
+
sql = f"""
|
|
589
|
+
INSERT IGNORE INTO {self._memory_table} (
|
|
590
|
+
id, session_id, app_name, user_id, event_id, author,
|
|
591
|
+
{self._owner_id_column_name}, timestamp, content_json,
|
|
592
|
+
content_text, metadata_json, inserted_at
|
|
593
|
+
) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
|
594
|
+
"""
|
|
595
|
+
else:
|
|
596
|
+
sql = f"""
|
|
597
|
+
INSERT IGNORE INTO {self._memory_table} (
|
|
598
|
+
id, session_id, app_name, user_id, event_id, author,
|
|
599
|
+
timestamp, content_json, content_text, metadata_json, inserted_at
|
|
600
|
+
) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
|
601
|
+
"""
|
|
602
|
+
|
|
603
|
+
async with self._config.provide_connection() as conn:
|
|
604
|
+
async with conn.cursor() as cursor:
|
|
605
|
+
for entry in entries:
|
|
606
|
+
params: tuple[Any, ...]
|
|
607
|
+
if self._owner_id_column_name:
|
|
608
|
+
params = (
|
|
609
|
+
entry["id"],
|
|
610
|
+
entry["session_id"],
|
|
611
|
+
entry["app_name"],
|
|
612
|
+
entry["user_id"],
|
|
613
|
+
entry["event_id"],
|
|
614
|
+
entry["author"],
|
|
615
|
+
owner_id,
|
|
616
|
+
entry["timestamp"],
|
|
617
|
+
to_json(entry["content_json"]),
|
|
618
|
+
entry["content_text"],
|
|
619
|
+
to_json(entry["metadata_json"]),
|
|
620
|
+
entry["inserted_at"],
|
|
621
|
+
)
|
|
622
|
+
else:
|
|
623
|
+
params = (
|
|
624
|
+
entry["id"],
|
|
625
|
+
entry["session_id"],
|
|
626
|
+
entry["app_name"],
|
|
627
|
+
entry["user_id"],
|
|
628
|
+
entry["event_id"],
|
|
629
|
+
entry["author"],
|
|
630
|
+
entry["timestamp"],
|
|
631
|
+
to_json(entry["content_json"]),
|
|
632
|
+
entry["content_text"],
|
|
633
|
+
to_json(entry["metadata_json"]),
|
|
634
|
+
entry["inserted_at"],
|
|
635
|
+
)
|
|
636
|
+
await cursor.execute(sql, params)
|
|
637
|
+
inserted_count += cursor.rowcount
|
|
638
|
+
await conn.commit()
|
|
639
|
+
return inserted_count
|
|
640
|
+
|
|
641
|
+
async def search_entries(
|
|
642
|
+
self, query: str, app_name: str, user_id: str, limit: "int | None" = None
|
|
643
|
+
) -> "list[MemoryRecord]":
|
|
644
|
+
"""Search memory entries by text query."""
|
|
645
|
+
if not self._enabled:
|
|
646
|
+
msg = "Memory store is disabled"
|
|
647
|
+
raise RuntimeError(msg)
|
|
648
|
+
|
|
649
|
+
if not query:
|
|
650
|
+
return []
|
|
651
|
+
|
|
652
|
+
limit_value = limit or self._max_results
|
|
653
|
+
if self._use_fts:
|
|
654
|
+
sql = f"""
|
|
655
|
+
SELECT * FROM {self._memory_table}
|
|
656
|
+
WHERE app_name = %s AND user_id = %s
|
|
657
|
+
AND MATCH(content_text) AGAINST (%s IN NATURAL LANGUAGE MODE)
|
|
658
|
+
ORDER BY timestamp DESC
|
|
659
|
+
LIMIT %s
|
|
660
|
+
"""
|
|
661
|
+
params = (app_name, user_id, query, limit_value)
|
|
662
|
+
else:
|
|
663
|
+
sql = f"""
|
|
664
|
+
SELECT * FROM {self._memory_table}
|
|
665
|
+
WHERE app_name = %s AND user_id = %s AND content_text LIKE %s
|
|
666
|
+
ORDER BY timestamp DESC
|
|
667
|
+
LIMIT %s
|
|
668
|
+
"""
|
|
669
|
+
params = (app_name, user_id, f"%{query}%", limit_value)
|
|
670
|
+
|
|
671
|
+
async with self._config.provide_connection() as conn, conn.cursor() as cursor:
|
|
672
|
+
await cursor.execute(sql, params)
|
|
673
|
+
rows = await cursor.fetchall()
|
|
674
|
+
columns = [col[0] for col in cursor.description or []]
|
|
675
|
+
|
|
676
|
+
return [cast("MemoryRecord", dict(zip(columns, row, strict=False))) for row in rows]
|
|
677
|
+
|
|
678
|
+
async def delete_entries_by_session(self, session_id: str) -> int:
|
|
679
|
+
"""Delete all memory entries for a specific session."""
|
|
680
|
+
if not self._enabled:
|
|
681
|
+
msg = "Memory store is disabled"
|
|
682
|
+
raise RuntimeError(msg)
|
|
683
|
+
|
|
684
|
+
sql = f"DELETE FROM {self._memory_table} WHERE session_id = %s"
|
|
685
|
+
async with self._config.provide_connection() as conn, conn.cursor() as cursor:
|
|
686
|
+
await cursor.execute(sql, (session_id,))
|
|
687
|
+
await conn.commit()
|
|
688
|
+
return cursor.rowcount if cursor.rowcount and cursor.rowcount > 0 else 0
|
|
689
|
+
|
|
690
|
+
async def delete_entries_older_than(self, days: int) -> int:
|
|
691
|
+
"""Delete memory entries older than specified days."""
|
|
692
|
+
if not self._enabled:
|
|
693
|
+
msg = "Memory store is disabled"
|
|
694
|
+
raise RuntimeError(msg)
|
|
695
|
+
|
|
696
|
+
sql = f"""
|
|
697
|
+
DELETE FROM {self._memory_table}
|
|
698
|
+
WHERE inserted_at < (UTC_TIMESTAMP(6) - INTERVAL %s DAY)
|
|
699
|
+
"""
|
|
700
|
+
async with self._config.provide_connection() as conn, conn.cursor() as cursor:
|
|
701
|
+
await cursor.execute(sql, (days,))
|
|
702
|
+
await conn.commit()
|
|
703
|
+
return cursor.rowcount if cursor.rowcount and cursor.rowcount > 0 else 0
|