File tree Expand file tree Collapse file tree 2 files changed +42
-41
lines changed
src/basic_memory/repository Expand file tree Collapse file tree 2 files changed +42
-41
lines changed Original file line number Diff line number Diff line change @@ -292,6 +292,10 @@ async def _ensure_vector_tables(self) -> None:
292292 ) from exc
293293
294294 # --- Chunks table (dimension-independent, may already exist via migration) ---
295+ # Trigger: fresh Postgres projects may not have vector chunk tables yet.
296+ # Why: runtime can bootstrap missing tables, but schema evolution must stay
297+ # in Alembic to avoid concurrent ALTER TABLE deadlocks during indexing.
298+ # Outcome: new installs create the current schema; upgrades rely on migration.
295299 await session .execute (
296300 text (
297301 """
@@ -318,47 +322,6 @@ async def _ensure_vector_tables(self) -> None:
318322 """
319323 )
320324 )
321- await session .execute (
322- text (
323- """
324- ALTER TABLE search_vector_chunks
325- ADD COLUMN IF NOT EXISTS entity_fingerprint TEXT
326- """
327- )
328- )
329- await session .execute (
330- text (
331- """
332- ALTER TABLE search_vector_chunks
333- ADD COLUMN IF NOT EXISTS embedding_model TEXT
334- """
335- )
336- )
337- await session .execute (
338- text (
339- """
340- UPDATE search_vector_chunks
341- SET entity_fingerprint = COALESCE(entity_fingerprint, ''),
342- embedding_model = COALESCE(embedding_model, '')
343- """
344- )
345- )
346- await session .execute (
347- text (
348- """
349- ALTER TABLE search_vector_chunks
350- ALTER COLUMN entity_fingerprint SET NOT NULL
351- """
352- )
353- )
354- await session .execute (
355- text (
356- """
357- ALTER TABLE search_vector_chunks
358- ALTER COLUMN embedding_model SET NOT NULL
359- """
360- )
361- )
362325
363326 # --- Embeddings table (dimension-dependent, created at runtime) ---
364327 # Trigger: provider dimensions may differ from what was previously deployed.
Original file line number Diff line number Diff line change 66"""
77
88import asyncio
9+ from contextlib import asynccontextmanager
910from unittest .mock import AsyncMock , MagicMock , patch
1011
1112import pytest
@@ -169,6 +170,43 @@ async def test_skips_when_already_initialized(self):
169170 assert repo ._vector_tables_initialized is True
170171
171172
173+ class TestEnsureVectorTablesSchemaBootstrapping :
174+ """Guard the runtime setup path against inline schema migration drift."""
175+
176+ @pytest .mark .asyncio
177+ async def test_initialization_never_alters_chunk_table_schema (self , monkeypatch ):
178+ repo = _make_repo (
179+ semantic_enabled = True ,
180+ embedding_provider = StubEmbeddingProvider (),
181+ )
182+ session = AsyncMock ()
183+
184+ @asynccontextmanager
185+ async def fake_scoped_session (session_maker ):
186+ yield session
187+
188+ monkeypatch .setattr (
189+ "basic_memory.repository.postgres_search_repository.db.scoped_session" ,
190+ fake_scoped_session ,
191+ )
192+ monkeypatch .setattr (repo , "_get_existing_embedding_dims" , AsyncMock (return_value = None ))
193+
194+ await repo ._ensure_vector_tables ()
195+
196+ executed_sql = [str (call .args [0 ]) for call in session .execute .await_args_list ]
197+
198+ assert any (
199+ "CREATE TABLE IF NOT EXISTS search_vector_chunks" in sql for sql in executed_sql
200+ )
201+ assert any (
202+ "CREATE TABLE IF NOT EXISTS search_vector_embeddings" in sql
203+ for sql in executed_sql
204+ )
205+ assert not any ("ALTER TABLE search_vector_chunks" in sql for sql in executed_sql )
206+ session .commit .assert_awaited_once ()
207+ assert repo ._vector_tables_initialized is True
208+
209+
172210# --- _run_vector_query empty embedding (line 395-396) ----------------------
173211
174212
You can’t perform that action at this time.
0 commit comments