|
6 | 6 | from types import SimpleNamespace |
7 | 7 |
|
8 | 8 | import pytest |
| 9 | +import sqlite_vec |
9 | 10 | from sqlalchemy import text |
10 | 11 |
|
11 | 12 | from basic_memory.config import DatabaseBackend |
| 13 | +from basic_memory.models.search import ( |
| 14 | + CREATE_SQLITE_SEARCH_VECTOR_CHUNKS, |
| 15 | + CREATE_SQLITE_SEARCH_VECTOR_CHUNKS_PROJECT_ENTITY, |
| 16 | + CREATE_SQLITE_SEARCH_VECTOR_CHUNKS_UNIQUE, |
| 17 | + create_sqlite_search_vector_embeddings, |
| 18 | +) |
12 | 19 | from basic_memory.repository.semantic_chunking import split_text_into_chunks |
13 | 20 | from basic_memory.schemas.search import SearchRetrievalMode |
14 | 21 |
|
@@ -161,7 +168,55 @@ async def test_sqlite_vector_storage_excludes_unrelated_tables(sqlite_engine_fac |
161 | 168 | if not dbstat_available: |
162 | 169 | pytest.skip("SQLite dbstat is required for physical vector-storage measurement") |
163 | 170 |
|
| 171 | + async with engine.begin() as connection: |
| 172 | + raw_connection = await connection.get_raw_connection() |
| 173 | + driver_connection = raw_connection.driver_connection |
| 174 | + await driver_connection.enable_load_extension(True) |
| 175 | + await driver_connection.load_extension(sqlite_vec.loadable_path()) |
| 176 | + await driver_connection.enable_load_extension(False) |
| 177 | + await connection.execute(CREATE_SQLITE_SEARCH_VECTOR_CHUNKS) |
| 178 | + await connection.execute(CREATE_SQLITE_SEARCH_VECTOR_CHUNKS_PROJECT_ENTITY) |
| 179 | + await connection.execute(CREATE_SQLITE_SEARCH_VECTOR_CHUNKS_UNIQUE) |
| 180 | + await connection.execute(create_sqlite_search_vector_embeddings(4)) |
| 181 | + |
164 | 182 | vector_bytes_before = await vector_storage_size_bytes(engine, storage_case) |
| 183 | + async with engine.connect() as connection: |
| 184 | + vector_relations = set( |
| 185 | + ( |
| 186 | + await connection.execute( |
| 187 | + text( |
| 188 | + "SELECT name FROM sqlite_schema " |
| 189 | + "WHERE tbl_name = 'search_vector_chunks' " |
| 190 | + "OR tbl_name LIKE 'search_vector_embeddings%'" |
| 191 | + ) |
| 192 | + ) |
| 193 | + ).scalars() |
| 194 | + ) |
| 195 | + vector_relations.update( |
| 196 | + ( |
| 197 | + await connection.execute( |
| 198 | + text( |
| 199 | + "SELECT DISTINCT name FROM dbstat " |
| 200 | + "WHERE name = 'search_vector_chunks' " |
| 201 | + "OR name LIKE 'search_vector_embeddings%'" |
| 202 | + ) |
| 203 | + ) |
| 204 | + ).scalars() |
| 205 | + ) |
| 206 | + dbstat_rows = await connection.execute( |
| 207 | + text("SELECT name, SUM(pgsize) FROM dbstat GROUP BY name") |
| 208 | + ) |
| 209 | + dbstat_bytes = dict(dbstat_rows.tuples().all()) |
| 210 | + |
| 211 | + autoindexes = { |
| 212 | + name |
| 213 | + for name in vector_relations |
| 214 | + if name.startswith("sqlite_autoindex_search_vector_embeddings_") |
| 215 | + } |
| 216 | + vector_dbstat_relations = vector_relations.intersection(dbstat_bytes) |
| 217 | + assert autoindexes |
| 218 | + assert autoindexes <= vector_dbstat_relations |
| 219 | + assert vector_bytes_before == sum(dbstat_bytes[name] for name in vector_dbstat_relations) |
165 | 220 |
|
166 | 221 | async with engine.begin() as connection: |
167 | 222 | await connection.execute(text("CREATE TABLE unrelated_payload (content BLOB NOT NULL)")) |
|
0 commit comments