mirror of
https://github.com/basicmachines-co/basic-memory
synced 2026-06-21 13:47:35 +00:00
change entity.path_id to entity.permalink
This commit is contained in:
@@ -25,7 +25,7 @@ def entity_model_from_markdown(file_path: str, markdown: EntityMarkdown) -> Enti
|
||||
model = EntityModel(
|
||||
title=markdown.frontmatter.title,
|
||||
entity_type=markdown.frontmatter.type,
|
||||
path_id=markdown.frontmatter.id,
|
||||
permalink=markdown.frontmatter.id,
|
||||
file_path=file_path,
|
||||
content_type="text/markdown",
|
||||
summary=markdown.content.content,
|
||||
@@ -65,21 +65,21 @@ class EntitySyncService:
|
||||
model = entity_model_from_markdown(file_path, markdown)
|
||||
|
||||
# Mark as incomplete sync
|
||||
model.checksum = None
|
||||
model.checksum = None
|
||||
return await self.entity_repository.add(model)
|
||||
|
||||
async def update_entity_and_observations(
|
||||
self, path_id: str, markdown: EntityMarkdown
|
||||
self, permalink: str, markdown: EntityMarkdown
|
||||
) -> EntityModel:
|
||||
"""First pass: Update entity fields and observations.
|
||||
|
||||
Updates everything except relations and sets null checksum
|
||||
to indicate sync not complete.
|
||||
"""
|
||||
logger.debug(f"Updating entity and observations: {path_id}")
|
||||
db_entity = await self.entity_repository.get_by_path_id(path_id)
|
||||
logger.debug(f"Updating entity and observations: {permalink}")
|
||||
db_entity = await self.entity_repository.get_by_permalink(permalink)
|
||||
if not db_entity:
|
||||
raise EntityNotFoundError(f"Entity not found: {path_id}")
|
||||
raise EntityNotFoundError(f"Entity not found: {permalink}")
|
||||
|
||||
# Update fields from markdown
|
||||
db_entity.title = markdown.frontmatter.title
|
||||
@@ -88,7 +88,7 @@ class EntitySyncService:
|
||||
|
||||
# Clear observations for entity
|
||||
await self.observation_repository.delete_by_fields(entity_id=db_entity.id)
|
||||
|
||||
|
||||
# add new observations
|
||||
observations = [
|
||||
Observation(
|
||||
@@ -122,14 +122,14 @@ class EntitySyncService:
|
||||
checksum: Final checksum to set after relations are updated
|
||||
"""
|
||||
logger.debug(f"Updating relations for entity: {markdown.frontmatter.id}")
|
||||
db_entity = await self.entity_repository.get_by_path_id(markdown.frontmatter.id)
|
||||
db_entity = await self.entity_repository.get_by_permalink(markdown.frontmatter.id)
|
||||
|
||||
# get all entities from relations
|
||||
target_entity_path_ids = [rel.target for rel in markdown.content.relations]
|
||||
target_entities = await self.entity_repository.find_by_path_ids(target_entity_path_ids)
|
||||
target_entity_permalinks = [rel.target for rel in markdown.content.relations]
|
||||
target_entities = await self.entity_repository.find_by_permalinks(target_entity_permalinks)
|
||||
|
||||
# dict by path
|
||||
entity_by_path = {e.path_id: e for e in target_entities}
|
||||
entity_by_path = {e.permalink: e for e in target_entities}
|
||||
|
||||
# Clear and update relations
|
||||
await self.relation_repository.delete_outgoing_relations_from_entity(db_entity.id)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
"""Service for detecting changes between filesystem and database."""
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
from typing import Dict, Sequence, Any
|
||||
from typing import Dict, Sequence
|
||||
|
||||
from loguru import logger
|
||||
|
||||
@@ -10,22 +11,24 @@ from basic_memory.repository.entity_repository import EntityRepository
|
||||
from basic_memory.sync.utils import SyncReport
|
||||
from basic_memory.utils.file_utils import compute_checksum
|
||||
|
||||
|
||||
@dataclass
|
||||
class FileState:
|
||||
"""State of a file including file path, path_id and checksum info."""
|
||||
"""State of a file including file path, permalink and checksum info."""
|
||||
|
||||
file_path: str
|
||||
path_id: str
|
||||
permalink: str
|
||||
checksum: str
|
||||
|
||||
|
||||
@dataclass
|
||||
@dataclass
|
||||
class ScanResult:
|
||||
"""Result of scanning a directory."""
|
||||
|
||||
|
||||
# file_path -> checksum
|
||||
files: Dict[str, str] = field(default_factory=dict)
|
||||
# file_path -> error message
|
||||
errors: Dict[str, str] = field(default_factory=dict)
|
||||
errors: Dict[str, str] = field(default_factory=dict)
|
||||
|
||||
|
||||
class FileChangeScanner:
|
||||
@@ -34,9 +37,7 @@ class FileChangeScanner:
|
||||
The filesystem is treated as the source of truth.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, entity_repository: EntityRepository
|
||||
):
|
||||
def __init__(self, entity_repository: EntityRepository):
|
||||
self.entity_repository = entity_repository
|
||||
|
||||
async def scan_directory(self, directory: Path) -> ScanResult:
|
||||
@@ -70,7 +71,7 @@ class FileChangeScanner:
|
||||
checksum = await compute_checksum(content)
|
||||
|
||||
if checksum: # Only store valid checksums
|
||||
result.files[rel_path] = checksum
|
||||
result.files[rel_path] = checksum
|
||||
else:
|
||||
result.errors[rel_path] = "Failed to compute checksum"
|
||||
|
||||
@@ -85,13 +86,15 @@ class FileChangeScanner:
|
||||
|
||||
return result
|
||||
|
||||
async def find_changes(self, directory: Path, db_file_state: Dict[str, FileState]) -> SyncReport:
|
||||
async def find_changes(
|
||||
self, directory: Path, db_file_state: Dict[str, FileState]
|
||||
) -> SyncReport:
|
||||
"""
|
||||
Find changes between filesystem and database.
|
||||
|
||||
Args:
|
||||
directory: Directory to check
|
||||
db_file_state: dict mapping file_path to DbState(path_id, checksum)
|
||||
db_file_state: dict mapping file_path to DbState(permalink, checksum)
|
||||
|
||||
Returns:
|
||||
SyncReport detailing changes
|
||||
@@ -102,11 +105,11 @@ class FileChangeScanner:
|
||||
|
||||
# Build report
|
||||
report = SyncReport()
|
||||
|
||||
|
||||
# Find new and modified files
|
||||
for file_path, checksum in current_files.items():
|
||||
logger.debug(f"{file_path} ({checksum[:8]})")
|
||||
|
||||
|
||||
if file_path not in db_file_state:
|
||||
report.new.add(file_path)
|
||||
elif checksum != db_file_state[file_path].checksum:
|
||||
@@ -134,9 +137,7 @@ class FileChangeScanner:
|
||||
|
||||
return report
|
||||
|
||||
async def get_db_file_state(
|
||||
self, db_records: Sequence[Entity]
|
||||
) -> Dict[str, FileState]:
|
||||
async def get_db_file_state(self, db_records: Sequence[Entity]) -> Dict[str, FileState]:
|
||||
"""Get file_path and checksums from database.
|
||||
Args:
|
||||
db_records: database records
|
||||
@@ -144,7 +145,12 @@ class FileChangeScanner:
|
||||
Dict mapping file paths to FileState
|
||||
:param db_records: the data from the db
|
||||
"""
|
||||
return {r.file_path: FileState(file_path=r.file_path, path_id=r.path_id, checksum=r.checksum) for r in db_records}
|
||||
return {
|
||||
r.file_path: FileState(
|
||||
file_path=r.file_path, permalink=r.permalink, checksum=r.checksum
|
||||
)
|
||||
for r in db_records
|
||||
}
|
||||
|
||||
async def find_knowledge_changes(self, directory: Path) -> SyncReport:
|
||||
"""Find changes in knowledge directory."""
|
||||
|
||||
@@ -56,10 +56,10 @@ class SyncService:
|
||||
file_path, entity_markdown
|
||||
)
|
||||
else:
|
||||
path_id = entity_markdown.frontmatter.id
|
||||
logger.debug(f"Updating entity_markdown: {path_id}")
|
||||
permalink = entity_markdown.frontmatter.id
|
||||
logger.debug(f"Updating entity_markdown: {permalink}")
|
||||
await self.knowledge_sync_service.update_entity_and_observations(
|
||||
path_id, entity_markdown
|
||||
permalink, entity_markdown
|
||||
)
|
||||
|
||||
# Second pass: Process relations
|
||||
|
||||
Reference in New Issue
Block a user