myrmidon / python /src /server /services /projects /versioning_service.py
tek Atrust
chore(deploy): build monolithic server for Hugging Face
d5ef46f
Raw
History Blame Contribute Delete
6.9 kB
# python/src/server/services/projects/versioning_service.py
from typing import Any, cast
from src.server.repositories.base_repository import BaseRepository
from ...config.logfire_config import get_logger
logger = get_logger(__name__)
class VersioningService(BaseRepository):
"""Service class for document versioning operations"""
def __init__(self, supabase_client=None):
"""Initialize with optional supabase client"""
super().__init__(supabase_client)
def create_version(
self,
project_id: str,
field_name: str,
content: dict[str, Any],
change_summary: str | None = None,
change_type: str = "update",
document_id: str | None = None,
created_by: str = "system",
) -> tuple[bool, dict[str, Any]]:
"""
Creates a new version record for a project document field.
"""
# 1. Get latest version number
def _get_latest():
return (
self.supabase_client.table("archon_document_versions")
.select("version_number")
.eq("project_id", project_id)
.eq("field_name", field_name)
.order("version_number", desc=True)
.limit(1)
.execute()
)
success, res = self.execute_query(_get_latest, "Failed to fetch latest version")
latest_version = 0
if success and res.get("data"):
latest_version = res["data"][0].get("version_number", 0)
# 2. Insert new version
new_version_data = {
"project_id": project_id,
"document_id": document_id,
"field_name": field_name,
"content": content,
"version_number": latest_version + 1,
"change_summary": change_summary,
"change_type": change_type,
"created_by": created_by,
}
def _insert():
return self.supabase_client.table("archon_document_versions").insert(new_version_data).execute()
return self.execute_query(_insert, "Failed to create new version")
async def get_version_history(self, project_id: str) -> tuple[bool, dict[str, Any]]:
"""Retrieve the version history for a specific project."""
def _query():
return (
self.supabase_client.table("archon_document_versions")
.select("*")
.eq("project_id", project_id)
.order("created_at", desc=True)
.execute()
)
return self.execute_query(_query, "Failed to fetch version history")
def list_all_versions(self) -> tuple[bool, dict[str, Any]]:
"""List all document versions globally."""
def _query():
return (
self.supabase_client.table("archon_document_versions")
.select("*")
.order("created_at", desc=True)
.limit(100)
.execute()
)
success, res = self.execute_query(_query, "Failed to fetch all versions", require_data=False)
if success:
return True, {"versions": res.get("data", []), "total_count": len(res.get("data", []))}
return False, res
def list_versions(self, project_id: str, field_name: str | None = None) -> tuple[bool, dict[str, Any]]:
"""List version history for a project's JSONB fields."""
def _query():
query = self.supabase_client.table("archon_document_versions").select("*").eq("project_id", project_id)
if field_name:
query = query.eq("field_name", field_name)
return query.order("version_number", desc=True).execute()
success, res = self.execute_query(
_query, f"Failed to fetch versions for project {project_id}", require_data=False
)
if success:
return True, {"versions": res.get("data", []), "total_count": len(res.get("data", []))}
return False, res
def get_version_content(self, project_id: str, field_name: str, version_number: int) -> tuple[bool, dict[str, Any]]:
"""Get a specific version's content."""
def _query():
return (
self.supabase_client.table("archon_document_versions")
.select("content")
.eq("project_id", project_id)
.eq("field_name", field_name)
.eq("version_number", version_number)
.single()
.execute()
)
success, res = self.execute_query(_query, "Failed to fetch version content", require_data=True)
if success:
return True, cast(dict[str, Any], res.get("data"))
return False, res
def restore_version(
self, project_id: str, field_name: str, version_number: int, restored_by: str = "system"
) -> tuple[bool, dict[str, Any]]:
"""Restore a project's JSONB field to a specific version."""
try:
# 1. Get the content from the specific version
success, version_data = self.get_version_content(project_id, field_name, version_number)
if not success:
return False, version_data
content = version_data.get("content")
if content is None:
return False, {"error": "Version content is empty"}
# 2. Update the project table
def _update_project():
return (
self.supabase_client.table("archon_projects")
.update({field_name: content})
.eq("id", project_id)
.execute()
)
proj_success, proj_res = self.execute_query(_update_project, f"Failed to update project {field_name}")
if not proj_success:
return False, proj_res
# 3. Create a new version entry reflecting the restoration
self.create_version(
project_id=project_id,
field_name=field_name,
content=cast(dict[str, Any], content),
change_summary=f"Restored to version {version_number}",
change_type="restore",
created_by=restored_by,
)
return True, {"restored_content": content}
except Exception as e:
return False, {"error": str(e)}
async def get_all_versions(self) -> tuple[bool, dict[str, Any]]:
"""Retrieve all document versions across all projects."""
def _query():
return (
self.supabase_client.table("archon_sources")
.select("*")
.order("created_at", desc=True)
.limit(100)
.execute()
)
return self.execute_query(_query, "Failed to fetch all versions")