Files
markitect-main/markitect/spaces/repositories/interfaces.py
tegwick 9b12875681 feat(spaces): implement Phase 0-1 of Information Space Service
Phase 0 - Project Organization:
- Create docs/PROJECT_STRUCTURE.md documenting codebase layout
- Create markitect/core/ with parser, serializer, document_manager, workspace
- Create markitect/schema/ consolidating 6 schema_*.py modules
- Create markitect/storage/ with database module
- Maintain backward compatibility via re-exports from original locations
- Add docs/roadmap/information-space-service/ with README and WORKPLAN

Phase 1 - Foundation (Weeks 1-3):
- Week 1: Core domain models (InformationSpace, SpaceDocument, SpaceConfig,
  SpaceMetadata, SpaceVariable, TransclusionReference, SpaceStatus)
- Week 2: Repository layer with interfaces (ISpaceRepository,
  IDocumentAssociationRepository, IVariableRepository, IReferenceRepository)
  and SQLite implementations with foreign key cascade deletes
- Week 3: SpaceService orchestration layer with full CRUD, document,
  variable, and reference tracking operations

Test coverage: 124 tests (25 model + 63 repository + 36 integration)

Capabilities delivered:
- CAP-001: InformationSpace entity with lifecycle management
- CAP-002: SpaceRepository CRUD with SQLite backing
- CAP-003: Document-Space associations with path-based organization
- CAP-004: Space metadata and configuration schemas
- CAP-005: Database schema with migrations

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-08 02:02:46 +01:00

410 lines
9.5 KiB
Python

"""
Repository interfaces for Information Spaces.
This module defines abstract base classes for space data access,
following the repository pattern for clean separation of concerns.
"""
from abc import ABC, abstractmethod
from typing import List, Optional, Dict, Any
from ..models import (
InformationSpace,
SpaceDocument,
SpaceVariable,
TransclusionReference,
)
class ISpaceRepository(ABC):
"""
Abstract repository interface for InformationSpace persistence.
Implementations should handle CRUD operations for spaces,
including proper transaction management and error handling.
"""
@abstractmethod
def create(self, space: InformationSpace) -> InformationSpace:
"""
Create a new space in the repository.
Args:
space: The space to create
Returns:
The created space with any generated fields populated
Raises:
ValueError: If space with same name already exists
"""
pass
@abstractmethod
def get_by_id(self, space_id: str) -> Optional[InformationSpace]:
"""
Retrieve a space by its ID.
Args:
space_id: The unique space identifier
Returns:
The space if found, None otherwise
"""
pass
@abstractmethod
def get_by_name(self, name: str) -> Optional[InformationSpace]:
"""
Retrieve a space by its unique name.
Args:
name: The space name
Returns:
The space if found, None otherwise
"""
pass
@abstractmethod
def list_all(self, include_archived: bool = False) -> List[InformationSpace]:
"""
List all spaces in the repository.
Args:
include_archived: Whether to include archived spaces
Returns:
List of all spaces
"""
pass
@abstractmethod
def update(self, space: InformationSpace) -> InformationSpace:
"""
Update an existing space.
Args:
space: The space with updated values
Returns:
The updated space
Raises:
ValueError: If space does not exist
"""
pass
@abstractmethod
def delete(self, space_id: str) -> bool:
"""
Delete a space by ID.
Args:
space_id: The space ID to delete
Returns:
True if deleted, False if not found
"""
pass
@abstractmethod
def exists(self, space_id: str) -> bool:
"""
Check if a space exists.
Args:
space_id: The space ID to check
Returns:
True if exists, False otherwise
"""
pass
@abstractmethod
def get_children(self, parent_space_id: str) -> List[InformationSpace]:
"""
Get all child spaces of a parent space.
Args:
parent_space_id: The parent space ID
Returns:
List of child spaces
"""
pass
class IDocumentAssociationRepository(ABC):
"""
Abstract repository interface for SpaceDocument associations.
Manages the relationship between documents and spaces.
"""
@abstractmethod
def add_document(self, document: SpaceDocument) -> SpaceDocument:
"""
Add a document to a space.
Args:
document: The document association to create
Returns:
The created document association
Raises:
ValueError: If document path already exists in space
"""
pass
@abstractmethod
def get_document(self, document_id: str) -> Optional[SpaceDocument]:
"""
Get a document association by ID.
Args:
document_id: The document association ID
Returns:
The document if found, None otherwise
"""
pass
@abstractmethod
def get_by_space_path(self, space_id: str, space_path: str) -> Optional[SpaceDocument]:
"""
Get a document by its path within a space.
Args:
space_id: The space ID
space_path: The path within the space (e.g., "/intro.md")
Returns:
The document if found, None otherwise
"""
pass
@abstractmethod
def list_by_space(self, space_id: str) -> List[SpaceDocument]:
"""
List all documents in a space.
Args:
space_id: The space ID
Returns:
List of documents in the space, ordered by order_index
"""
pass
@abstractmethod
def update_document(self, document: SpaceDocument) -> SpaceDocument:
"""
Update a document association.
Args:
document: The document with updated values
Returns:
The updated document
Raises:
ValueError: If document does not exist
"""
pass
@abstractmethod
def remove_document(self, document_id: str) -> bool:
"""
Remove a document from a space.
Args:
document_id: The document association ID
Returns:
True if removed, False if not found
"""
pass
@abstractmethod
def move_document(self, document_id: str, new_space_path: str) -> SpaceDocument:
"""
Move a document to a new path within the space.
Args:
document_id: The document association ID
new_space_path: The new path within the space
Returns:
The updated document
Raises:
ValueError: If new path already exists
"""
pass
@abstractmethod
def reorder_documents(self, space_id: str, document_ids: List[str]) -> None:
"""
Reorder documents within a space.
Args:
space_id: The space ID
document_ids: Ordered list of document IDs
"""
pass
@abstractmethod
def update_content_hash(self, document_id: str, content_hash: str) -> None:
"""
Update the content hash for change detection.
Args:
document_id: The document association ID
content_hash: New content hash
"""
pass
class IVariableRepository(ABC):
"""
Abstract repository interface for SpaceVariable storage.
Manages space-level variables for transclusion context.
"""
@abstractmethod
def set_variable(self, variable: SpaceVariable) -> SpaceVariable:
"""
Set a variable value.
Args:
variable: The variable to set
Returns:
The saved variable
"""
pass
@abstractmethod
def get_variable(self, space_id: str, name: str) -> Optional[SpaceVariable]:
"""
Get a variable by name.
Args:
space_id: The space ID
name: Variable name
Returns:
The variable if found, None otherwise
"""
pass
@abstractmethod
def list_variables(self, space_id: str, scope: Optional[str] = None) -> List[SpaceVariable]:
"""
List all variables in a space.
Args:
space_id: The space ID
scope: Optional scope filter
Returns:
List of variables
"""
pass
@abstractmethod
def delete_variable(self, space_id: str, name: str) -> bool:
"""
Delete a variable.
Args:
space_id: The space ID
name: Variable name
Returns:
True if deleted, False if not found
"""
pass
class IReferenceRepository(ABC):
"""
Abstract repository interface for TransclusionReference tracking.
Manages the dependency graph for cache invalidation.
"""
@abstractmethod
def add_reference(self, reference: TransclusionReference) -> TransclusionReference:
"""
Add a transclusion reference.
Args:
reference: The reference to add
Returns:
The saved reference
"""
pass
@abstractmethod
def get_references_from(self, source_doc_id: str, space_id: str) -> List[TransclusionReference]:
"""
Get all references from a source document.
Args:
source_doc_id: The source document ID
space_id: The space ID
Returns:
List of references from this document
"""
pass
@abstractmethod
def get_references_to(self, target_doc_id: str, space_id: str) -> List[TransclusionReference]:
"""
Get all references to a target document.
Args:
target_doc_id: The target document ID
space_id: The space ID
Returns:
List of references to this document
"""
pass
@abstractmethod
def clear_references_from(self, source_doc_id: str, space_id: str) -> int:
"""
Clear all references from a source document.
Args:
source_doc_id: The source document ID
space_id: The space ID
Returns:
Number of references deleted
"""
pass
@abstractmethod
def get_dependents(self, document_id: str, space_id: str) -> List[str]:
"""
Get all documents that depend on a given document.
Used for cache invalidation - returns documents that need
to be re-rendered when the target document changes.
Args:
document_id: The document ID
space_id: The space ID
Returns:
List of dependent document IDs
"""
pass