update_entity

This commit is contained in:
phernandez
2025-01-06 22:15:41 -06:00
parent c320f64b53
commit 9c125aa5db
7 changed files with 249 additions and 201 deletions
@@ -1,6 +1,7 @@
"""Entity operations for knowledge service."""
from typing import Sequence, List
from datetime import datetime, UTC
from typing import Sequence, List, Dict, Any, Optional
from loguru import logger
@@ -63,6 +64,72 @@ class EntityOperations:
return created
async def update_entity(
self,
path_id: str,
content: Optional[str] = None,
metadata: Optional[Dict[str, Any]] = None,
**update_fields: Any
) -> EntityModel:
"""Update an entity's content and metadata.
Args:
path_id: Entity's path ID
content: Optional new content
metadata: Optional metadata updates
**update_fields: Additional entity fields to update
Returns:
Updated entity
Raises:
EntityNotFoundError: If entity doesn't exist
"""
logger.debug(f"Updating entity with path_id: {path_id}")
# Get existing entity
entity = await self.entity_service.get_by_path_id(path_id)
if not entity:
raise EntityNotFoundError(f"Entity not found: {path_id}")
try:
# Build update data
update_data = {}
# Add any direct field updates
if update_fields:
update_data.update(update_fields)
# Handle metadata update
if metadata is not None:
# Update existing metadata
new_metadata = dict(entity.entity_metadata or {})
new_metadata.update(metadata)
update_data["entity_metadata"] = new_metadata
# Update entity in database if we have changes
if update_data:
entity = await self.entity_service.update_entity(
entity.path_id, update_data
)
# Always write file if we have any updates
if update_data or content is not None:
_, checksum = await self.file_operations.write_entity_file(
entity=entity,
content=content
)
# Update checksum in DB
entity = await self.entity_service.update_entity(
entity.path_id, {"checksum": checksum}
)
return entity
except Exception as e:
logger.error(f"Failed to update entity: {e}")
raise
async def delete_entity(self, path_id: str) -> bool:
"""Delete entity and its file."""
logger.debug(f"Deleting entity: {path_id}")
@@ -1,11 +1,11 @@
"""Main knowledge service implementation."""
from pathlib import Path
from typing import List, Sequence, Tuple
from typing import List, Sequence, Tuple, Dict, Any, Optional
from loguru import logger
from basic_memory.markdown.knowledge_writer import KnowledgeWriter
from basic_memory.markdown.note_writer import NoteWriter
from basic_memory.models import Entity as EntityModel
from basic_memory.schemas import Entity as EntitySchema
from basic_memory.schemas import Relation as RelationSchema
@@ -19,7 +19,6 @@ from .file_operations import FileOperations
from .entity_operations import EntityOperations
from .relation_operations import RelationOperations
from .observation_operations import ObservationOperations
from ...markdown.note_writer import NoteWriter
class KnowledgeService:
@@ -31,7 +30,7 @@ class KnowledgeService:
- Entity CRUD operations
- Relations between entities
- Observations about entities
Acts as the main coordinator for all knowledge operations, ensuring
consistency between database and filesystem.
"""
@@ -46,39 +45,37 @@ class KnowledgeService:
note_writer: NoteWriter,
base_path: Path,
):
self.base_path = base_path
# Initialize operations in dependency order
self.file_ops = FileOperations(
entity_service=entity_service,
file_service=file_service,
knowledge_writer=knowledge_writer,
note_writer=note_writer,
base_path=base_path
base_path=base_path,
)
self.entity_ops = EntityOperations(
entity_service=entity_service,
file_operations=self.file_ops
entity_service=entity_service, file_operations=self.file_ops
)
self.relation_ops = RelationOperations(
relation_service=relation_service,
entity_service=entity_service,
file_operations=self.file_ops
file_operations=self.file_ops,
)
self.observation_ops = ObservationOperations(
observation_service=observation_service,
entity_service=entity_service,
file_operations=self.file_ops
file_operations=self.file_ops,
)
# Entity operations
async def get_entity_by_path_id(self, path_id: str) -> EntityModel:
return await self.entity_ops.get_by_path_id(path_id)
async def create_entity(self, entity: EntitySchema) -> EntityModel:
"""Create a new entity."""
return await self.entity_ops.create_entity(entity)
@@ -87,6 +84,28 @@ class KnowledgeService:
"""Create multiple entities."""
return await self.entity_ops.create_entities(entities)
async def update_entity(
self,
path_id: str,
content: Optional[str] = None,
metadata: Optional[Dict[str, Any]] = None,
**update_fields: Any,
) -> EntityModel:
"""Update an entity's content and metadata.
Args:
path_id: Entity's path ID
content: Optional new content
metadata: Optional metadata updates
**update_fields: Additional entity fields to update
Returns:
Updated entity
"""
return await self.entity_ops.update_entity(
path_id=path_id, content=content, metadata=metadata, **update_fields
)
async def delete_entity(self, path_id: str) -> bool:
"""Delete an entity and its file."""
return await self.entity_ops.delete_entity(path_id)
@@ -114,19 +133,12 @@ class KnowledgeService:
# Observation operations
async def add_observations(
self,
path_id: str,
observations: List[ObservationCreate],
context: str | None = None
self, path_id: str, observations: List[ObservationCreate], context: str | None = None
) -> EntityModel:
"""Add observations to an entity."""
return await self.observation_ops.add_observations(path_id, observations, context)
async def delete_observations(
self,
path_id: str,
observations: List[str]
) -> EntityModel:
async def delete_observations(self, path_id: str, observations: List[str]) -> EntityModel:
"""Delete observations from an entity."""
return await self.observation_ops.delete_observations(path_id, observations)
@@ -138,4 +150,4 @@ class KnowledgeService:
async def write_entity_file(self, entity: EntityModel) -> Path:
"""Write entity to filesystem."""
path, _ = await self.file_ops.write_entity_file(entity)
return path
return path