forked from cardosofelipe/fast-next-template
fix(knowledge-base): ensure pgvector extension before pool creation
register_vector() requires the vector type to exist in PostgreSQL before it can register the type codec. Move CREATE EXTENSION to a separate _ensure_pgvector_extension() method that runs before pool creation. This fixes the "unknown type: public.vector" error on fresh databases. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -57,6 +57,9 @@ class DatabaseManager:
|
|||||||
async def initialize(self) -> None:
|
async def initialize(self) -> None:
|
||||||
"""Initialize connection pool and create schema."""
|
"""Initialize connection pool and create schema."""
|
||||||
try:
|
try:
|
||||||
|
# First, create pgvector extension (required before register_vector in pool init)
|
||||||
|
await self._ensure_pgvector_extension()
|
||||||
|
|
||||||
self._pool = await asyncpg.create_pool(
|
self._pool = await asyncpg.create_pool(
|
||||||
self._settings.database_url,
|
self._settings.database_url,
|
||||||
min_size=2,
|
min_size=2,
|
||||||
@@ -66,7 +69,7 @@ class DatabaseManager:
|
|||||||
)
|
)
|
||||||
logger.info("Database pool created successfully")
|
logger.info("Database pool created successfully")
|
||||||
|
|
||||||
# Create schema
|
# Create schema (tables and indexes)
|
||||||
await self._create_schema()
|
await self._create_schema()
|
||||||
logger.info("Database schema initialized")
|
logger.info("Database schema initialized")
|
||||||
|
|
||||||
@@ -77,6 +80,19 @@ class DatabaseManager:
|
|||||||
cause=e,
|
cause=e,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def _ensure_pgvector_extension(self) -> None:
|
||||||
|
"""Ensure pgvector extension exists before pool creation.
|
||||||
|
|
||||||
|
This must run before creating the connection pool because
|
||||||
|
register_vector() in _init_connection requires the extension to exist.
|
||||||
|
"""
|
||||||
|
conn = await asyncpg.connect(self._settings.database_url)
|
||||||
|
try:
|
||||||
|
await conn.execute("CREATE EXTENSION IF NOT EXISTS vector")
|
||||||
|
logger.info("pgvector extension ensured")
|
||||||
|
finally:
|
||||||
|
await conn.close()
|
||||||
|
|
||||||
async def _init_connection(self, conn: asyncpg.Connection) -> None: # type: ignore[type-arg]
|
async def _init_connection(self, conn: asyncpg.Connection) -> None: # type: ignore[type-arg]
|
||||||
"""Initialize a connection with pgvector support."""
|
"""Initialize a connection with pgvector support."""
|
||||||
await register_vector(conn)
|
await register_vector(conn)
|
||||||
@@ -84,8 +100,7 @@ class DatabaseManager:
|
|||||||
async def _create_schema(self) -> None:
|
async def _create_schema(self) -> None:
|
||||||
"""Create database schema if not exists."""
|
"""Create database schema if not exists."""
|
||||||
async with self.pool.acquire() as conn:
|
async with self.pool.acquire() as conn:
|
||||||
# Enable pgvector extension
|
# Note: pgvector extension is created in _ensure_pgvector_extension()
|
||||||
await conn.execute("CREATE EXTENSION IF NOT EXISTS vector")
|
|
||||||
|
|
||||||
# Create main embeddings table
|
# Create main embeddings table
|
||||||
await conn.execute("""
|
await conn.execute("""
|
||||||
@@ -286,7 +301,14 @@ class DatabaseManager:
|
|||||||
try:
|
try:
|
||||||
async with self.acquire() as conn, conn.transaction():
|
async with self.acquire() as conn, conn.transaction():
|
||||||
# Wrap in transaction for all-or-nothing batch semantics
|
# Wrap in transaction for all-or-nothing batch semantics
|
||||||
for project_id, collection, content, embedding, chunk_type, metadata in embeddings:
|
for (
|
||||||
|
project_id,
|
||||||
|
collection,
|
||||||
|
content,
|
||||||
|
embedding,
|
||||||
|
chunk_type,
|
||||||
|
metadata,
|
||||||
|
) in embeddings:
|
||||||
content_hash = self.compute_content_hash(content)
|
content_hash = self.compute_content_hash(content)
|
||||||
source_path = metadata.get("source_path")
|
source_path = metadata.get("source_path")
|
||||||
start_line = metadata.get("start_line")
|
start_line = metadata.get("start_line")
|
||||||
@@ -397,7 +419,9 @@ class DatabaseManager:
|
|||||||
source_path=row["source_path"],
|
source_path=row["source_path"],
|
||||||
start_line=row["start_line"],
|
start_line=row["start_line"],
|
||||||
end_line=row["end_line"],
|
end_line=row["end_line"],
|
||||||
file_type=FileType(row["file_type"]) if row["file_type"] else None,
|
file_type=FileType(row["file_type"])
|
||||||
|
if row["file_type"]
|
||||||
|
else None,
|
||||||
metadata=row["metadata"] or {},
|
metadata=row["metadata"] or {},
|
||||||
content_hash=row["content_hash"],
|
content_hash=row["content_hash"],
|
||||||
created_at=row["created_at"],
|
created_at=row["created_at"],
|
||||||
@@ -476,7 +500,9 @@ class DatabaseManager:
|
|||||||
source_path=row["source_path"],
|
source_path=row["source_path"],
|
||||||
start_line=row["start_line"],
|
start_line=row["start_line"],
|
||||||
end_line=row["end_line"],
|
end_line=row["end_line"],
|
||||||
file_type=FileType(row["file_type"]) if row["file_type"] else None,
|
file_type=FileType(row["file_type"])
|
||||||
|
if row["file_type"]
|
||||||
|
else None,
|
||||||
metadata=row["metadata"] or {},
|
metadata=row["metadata"] or {},
|
||||||
content_hash=row["content_hash"],
|
content_hash=row["content_hash"],
|
||||||
created_at=row["created_at"],
|
created_at=row["created_at"],
|
||||||
|
|||||||
Reference in New Issue
Block a user