use db defaults for created_at

This commit is contained in:
phernandez
2024-12-10 14:53:51 -06:00
parent 90a5414c58
commit 61a8cfcf0a
3 changed files with 125 additions and 44 deletions
+21 -24
View File
@@ -9,6 +9,11 @@ from uuid import uuid4
from annotated_types import Gt, Len
from pydantic import BaseModel, Field, model_validator, ConfigDict
# Base output model for SQLAlchemy attribute conversion
class SQLAlchemyOut(BaseModel):
"""Base class for models that read from SQLAlchemy attributes."""
model_config = ConfigDict(from_attributes=True)
# Base Models
class ObservationIn(BaseModel):
"""Schema for creating a single observation."""
@@ -21,16 +26,15 @@ class ObservationsIn(BaseModel):
observations: List[ObservationIn]
model_config = ConfigDict(populate_by_name=True)
class ObservationOut(ObservationIn):
class ObservationOut(ObservationIn, SQLAlchemyOut):
"""Schema for observation data returned from the service."""
id: int
model_config = ConfigDict(from_attributes=True)
class ObservationsOut(BaseModel):
class ObservationsOut(SQLAlchemyOut):
"""Schema for bulk observation operation results."""
entity_id: str = Field(alias="entityId")
observations: List[ObservationOut]
model_config = ConfigDict(populate_by_name=True, from_attributes=True)
model_config = ConfigDict(populate_by_name=True)
class RelationIn(BaseModel):
"""
@@ -44,13 +48,13 @@ class RelationIn(BaseModel):
model_config = ConfigDict(populate_by_name=True)
class RelationOut(BaseModel):
class RelationOut(SQLAlchemyOut):
id: int
from_id: str = Field(alias="fromId")
to_id: str = Field(alias="toId")
relation_type: str = Field(alias="relationType")
context: Optional[str] = None
model_config = ConfigDict(from_attributes=True, populate_by_name=True)
model_config = ConfigDict(populate_by_name=True)
class EntityBase(BaseModel):
id: str = Field(default=None) # Allow None during creation
@@ -81,13 +85,13 @@ class EntityIn(EntityBase):
"""
observations: List[ObservationIn] = []
relations: List[RelationIn] = []
model_config = ConfigDict(populate_by_name=True, from_attributes=True)
model_config = ConfigDict(populate_by_name=True)
class EntityOut(EntityBase):
class EntityOut(EntityBase, SQLAlchemyOut):
"""Schema for entity data returned from the service."""
observations: List[ObservationOut] = []
relations: List[RelationOut] = []
model_config = ConfigDict(populate_by_name=True, from_attributes=True)
model_config = ConfigDict(populate_by_name=True)
# Tool Input Schemas
class CreateEntitiesInput(BaseModel):
@@ -121,40 +125,33 @@ class DeleteObservationsInput(BaseModel):
deletions: List[Dict[str, Any]] # TODO: Make this more specific
# Tool Response Schemas
class CreateEntitiesResponse(BaseModel):
class CreateEntitiesResponse(SQLAlchemyOut):
"""Response for create_entities tool."""
entities: List[EntityOut]
model_config = ConfigDict(from_attributes=True)
class SearchNodesResponse(BaseModel):
class SearchNodesResponse(SQLAlchemyOut):
"""Response for search_nodes tool."""
matches: List[EntityOut]
query: str
model_config = ConfigDict(from_attributes=True)
class OpenNodesResponse(BaseModel):
class OpenNodesResponse(SQLAlchemyOut):
"""Response for open_nodes tool."""
entities: List[EntityOut]
model_config = ConfigDict(from_attributes=True)
class AddObservationsResponse(BaseModel):
class AddObservationsResponse(SQLAlchemyOut):
"""Response for add_observations tool."""
entity_id: str
added_observations: List[ObservationOut]
model_config = ConfigDict(from_attributes=True)
class CreateRelationsResponse(BaseModel):
class CreateRelationsResponse(SQLAlchemyOut):
"""Response for create_relations tool."""
relations: List[RelationOut]
model_config = ConfigDict(from_attributes=True)
class DeleteEntitiesResponse(BaseModel):
class DeleteEntitiesResponse(SQLAlchemyOut):
"""Response for delete_entities tool."""
deleted: List[str]
model_config = ConfigDict(from_attributes=True)
class DeleteObservationsResponse(BaseModel):
class DeleteObservationsResponse(SQLAlchemyOut):
"""Response for delete_observations tool."""
entity_id: str
deleted: List[str]
model_config = ConfigDict(from_attributes=True)
deleted: List[str]
+21 -19
View File
@@ -1,11 +1,10 @@
"""Service for managing entities in the database."""
from datetime import datetime, UTC
from pathlib import Path
from typing import List
from typing import List, Dict, Any
from basic_memory.repository.entity_repository import EntityRepository
from basic_memory.schemas import EntityIn, ObservationIn
from basic_memory.models import Entity, Observation
from basic_memory.schemas import EntityIn
from basic_memory.models import Entity
from basic_memory.fileio import EntityNotFoundError
from loguru import logger
from . import ServiceError
@@ -34,22 +33,10 @@ class EntityService:
raise
async def create_entity(self, entity: EntityIn) -> Entity:
"""Create a new entity in the database.
Note: ID is generated by the EntityIn validator before reaching this method.
"""
"""Create a new entity in the database."""
logger.debug(f"Creating entity in DB: {entity.id}")
try:
# Create base entity first
base_data = {
"id": entity.id, # Include the generated ID
"name": entity.name,
"entity_type": entity.entity_type,
"created_at": datetime.now(UTC),
}
logger.debug(f"Base entity data: {base_data}")
created_entity = await self.entity_repo.create(base_data)
created_entity = await self.entity_repo.create(entity.model_dump())
logger.debug(f"Created base entity: {created_entity.id}")
await self.entity_repo.refresh(created_entity, ['observations', 'outgoing_relations', 'incoming_relations'])
@@ -60,6 +47,22 @@ class EntityService:
logger.exception(f"Failed to create entity: {entity.id}")
raise
async def update_entity(self, entity_id: str, update_data: Dict[str, Any]) -> Entity:
"""Update an entity's fields."""
logger.debug(f"Updating entity {entity_id} with data: {update_data}")
try:
updated = await self.entity_repo.update(entity_id, update_data)
if not updated:
raise EntityNotFoundError(f"Entity not found: {entity_id}")
logger.debug(f"Updated entity: {updated.id}")
return updated
except EntityNotFoundError:
raise
except Exception as e:
logger.exception(f"Failed to update entity: {entity_id}")
raise
async def get_entity(self, entity_id: str) -> Entity:
"""Get entity by ID."""
logger.debug(f"Getting entity by ID: {entity_id}")
@@ -77,7 +80,6 @@ class EntityService:
logger.exception(f"Failed to get entity: {entity_id}")
raise
# TODO name is not unique
async def get_by_name(self, name: str) -> Entity:
"""Get entity by name."""
logger.debug(f"Getting entity by name: {name}")