Files
Medios-Macina/Store/_base.py

163 lines
4.9 KiB
Python
Raw Permalink Normal View History

2025-12-11 19:04:02 -08:00
"""Store backend base types.
Concrete store implementations live in the `Store/` package.
"""
from __future__ import annotations
from abc import ABC, abstractmethod
from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple
2025-12-11 23:21:45 -08:00
class Store(ABC):
2026-01-11 03:24:49 -08:00
@classmethod
def config(cls) -> List[Dict[str, Any]]:
"""Return configuration schema for this store.
Returns a list of dicts:
{
"key": "PATH",
"label": "Store Location",
"default": "",
2026-01-11 03:47:25 -08:00
"required": True,
"choices": ["/mnt/media", "/srv/data"]
2026-01-11 03:24:49 -08:00
}
"""
return []
2025-12-11 19:04:02 -08:00
@abstractmethod
def add_file(self, file_path: Path, **kwargs: Any) -> str:
raise NotImplementedError
@abstractmethod
def name(self) -> str:
raise NotImplementedError
2025-12-11 23:21:45 -08:00
def search(self, query: str, **kwargs: Any) -> list[Dict[str, Any]]:
2025-12-11 19:04:02 -08:00
raise NotImplementedError(f"{self.name()} backend does not support searching")
@abstractmethod
def get_file(self, file_hash: str, **kwargs: Any) -> Path | str | None:
raise NotImplementedError
@abstractmethod
def get_metadata(self, file_hash: str, **kwargs: Any) -> Optional[Dict[str, Any]]:
raise NotImplementedError
@abstractmethod
def get_tag(self, file_identifier: str, **kwargs: Any) -> Tuple[List[str], str]:
raise NotImplementedError
@abstractmethod
def add_tag(self, file_identifier: str, tags: List[str], **kwargs: Any) -> bool:
raise NotImplementedError
@abstractmethod
def delete_tag(self, file_identifier: str, tags: List[str], **kwargs: Any) -> bool:
raise NotImplementedError
@abstractmethod
def get_url(self, file_identifier: str, **kwargs: Any) -> List[str]:
raise NotImplementedError
@abstractmethod
def add_url(self, file_identifier: str, url: List[str], **kwargs: Any) -> bool:
raise NotImplementedError
2025-12-20 23:57:44 -08:00
def add_url_bulk(self, items: List[Tuple[str, List[str]]], **kwargs: Any) -> bool:
"""Optional bulk url association.
Backends may override this to batch writes (single transaction / request).
Default behavior is to call add_url() per file.
"""
changed_any = False
2025-12-29 17:05:03 -08:00
for file_identifier, urls in items or []:
2025-12-20 23:57:44 -08:00
try:
ok = self.add_url(file_identifier, urls, **kwargs)
changed_any = changed_any or bool(ok)
except Exception:
continue
return changed_any
def delete_url_bulk(
self,
items: List[Tuple[str,
List[str]]],
**kwargs: Any
) -> bool:
2025-12-20 23:57:44 -08:00
"""Optional bulk url deletion.
Backends may override this to batch writes (single transaction / request).
Default behavior is to call delete_url() per file.
"""
changed_any = False
2025-12-29 17:05:03 -08:00
for file_identifier, urls in items or []:
2025-12-20 23:57:44 -08:00
try:
ok = self.delete_url(file_identifier, urls, **kwargs)
changed_any = changed_any or bool(ok)
except Exception:
continue
return changed_any
def set_note_bulk(self, items: List[Tuple[str, str, str]], **kwargs: Any) -> bool:
"""Optional bulk note set.
Backends may override this to batch writes (single transaction / request).
Default behavior is to call set_note() per file.
"""
changed_any = False
2025-12-29 17:05:03 -08:00
for file_identifier, name, text in items or []:
2025-12-20 23:57:44 -08:00
try:
ok = self.set_note(file_identifier, name, text, **kwargs)
changed_any = changed_any or bool(ok)
except Exception:
continue
return changed_any
2025-12-11 19:04:02 -08:00
@abstractmethod
def delete_url(self, file_identifier: str, url: List[str], **kwargs: Any) -> bool:
raise NotImplementedError
2025-12-12 21:55:38 -08:00
@abstractmethod
def get_note(self, file_identifier: str, **kwargs: Any) -> Dict[str, str]:
"""Get notes for a file.
Returns a mapping of note name/key -> note text.
"""
raise NotImplementedError
@abstractmethod
def set_note(
self,
file_identifier: str,
name: str,
text: str,
**kwargs: Any
) -> bool:
2025-12-12 21:55:38 -08:00
"""Add or replace a named note for a file."""
raise NotImplementedError
2025-12-29 17:05:03 -08:00
def selector(
self,
selected_items: List[Any],
*,
ctx: Any,
stage_is_last: bool = True,
**_kwargs: Any
2025-12-29 17:05:03 -08:00
) -> bool:
2025-12-19 02:29:42 -08:00
"""Optional hook for handling `@N` selection semantics.
Return True if the selection was handled and default behavior should be skipped.
"""
_ = selected_items
_ = ctx
_ = stage_is_last
return False
2025-12-12 21:55:38 -08:00
@abstractmethod
def delete_note(self, file_identifier: str, name: str, **kwargs: Any) -> bool:
"""Delete a named note for a file."""
raise NotImplementedError