feat(project): add JsonProjectRepository with JSON file persistence
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
a4b7e1ca7a
commit
42ee2859d6
|
|
@ -0,0 +1,59 @@
|
||||||
|
import json
|
||||||
|
from datetime import datetime
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from app.modules.project.domain.entities import Project
|
||||||
|
from app.modules.project.domain.repositories import ProjectRepository
|
||||||
|
|
||||||
|
|
||||||
|
class JsonProjectRepository(ProjectRepository):
|
||||||
|
def __init__(self, path: Path) -> None:
|
||||||
|
self._path = path
|
||||||
|
|
||||||
|
def _load(self) -> list[dict]:
|
||||||
|
if not self._path.exists():
|
||||||
|
return []
|
||||||
|
return json.loads(self._path.read_text(encoding="utf-8"))
|
||||||
|
|
||||||
|
def _save(self, data: list[dict]) -> None:
|
||||||
|
self._path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
self._path.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _to_dict(p: Project) -> dict:
|
||||||
|
return {
|
||||||
|
"id": p.id,
|
||||||
|
"name": p.name,
|
||||||
|
"design_dir": p.design_dir,
|
||||||
|
"code_dir": p.code_dir,
|
||||||
|
"created_at": p.created_at.isoformat(),
|
||||||
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _from_dict(d: dict) -> Project:
|
||||||
|
return Project(
|
||||||
|
id=d["id"],
|
||||||
|
name=d["name"],
|
||||||
|
design_dir=d["design_dir"],
|
||||||
|
code_dir=d.get("code_dir"),
|
||||||
|
created_at=datetime.fromisoformat(d["created_at"]),
|
||||||
|
)
|
||||||
|
|
||||||
|
def list_all(self) -> list[Project]:
|
||||||
|
return [self._from_dict(d) for d in self._load()]
|
||||||
|
|
||||||
|
def get_by_id(self, project_id: str) -> Project | None:
|
||||||
|
for d in self._load():
|
||||||
|
if d["id"] == project_id:
|
||||||
|
return self._from_dict(d)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def save(self, project: Project) -> None:
|
||||||
|
data = self._load()
|
||||||
|
data = [d for d in data if d["id"] != project.id]
|
||||||
|
data.append(self._to_dict(project))
|
||||||
|
self._save(data)
|
||||||
|
|
||||||
|
def delete(self, project_id: str) -> None:
|
||||||
|
data = [d for d in self._load() if d["id"] != project_id]
|
||||||
|
self._save(data)
|
||||||
44
backend/tests/test_project.py
Normal file
44
backend/tests/test_project.py
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from app.modules.project.domain.entities import Project
|
||||||
|
from app.modules.project.infrastructure.json_repository import JsonProjectRepository
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def repo(tmp_path: Path) -> JsonProjectRepository:
|
||||||
|
return JsonProjectRepository(tmp_path / "projects.json")
|
||||||
|
|
||||||
|
|
||||||
|
def test_empty_repo_returns_empty_list(repo: JsonProjectRepository):
|
||||||
|
assert repo.list_all() == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_save_and_get(repo: JsonProjectRepository):
|
||||||
|
from datetime import datetime
|
||||||
|
p = Project(id="id1", name="test", design_dir="/tmp/d", code_dir=None, created_at=datetime(2026, 1, 1))
|
||||||
|
repo.save(p)
|
||||||
|
assert repo.get_by_id("id1") is not None
|
||||||
|
assert repo.get_by_id("id1").name == "test"
|
||||||
|
|
||||||
|
|
||||||
|
def test_list_all(repo: JsonProjectRepository):
|
||||||
|
from datetime import datetime
|
||||||
|
p1 = Project(id="id1", name="a", design_dir="/d1", code_dir=None, created_at=datetime(2026, 1, 1))
|
||||||
|
p2 = Project(id="id2", name="b", design_dir="/d2", code_dir=None, created_at=datetime(2026, 1, 2))
|
||||||
|
repo.save(p1)
|
||||||
|
repo.save(p2)
|
||||||
|
assert len(repo.list_all()) == 2
|
||||||
|
|
||||||
|
|
||||||
|
def test_delete(repo: JsonProjectRepository):
|
||||||
|
from datetime import datetime
|
||||||
|
p = Project(id="id1", name="test", design_dir="/d", code_dir=None, created_at=datetime(2026, 1, 1))
|
||||||
|
repo.save(p)
|
||||||
|
repo.delete("id1")
|
||||||
|
assert repo.get_by_id("id1") is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_nonexistent_returns_none(repo: JsonProjectRepository):
|
||||||
|
assert repo.get_by_id("nope") is None
|
||||||
Loading…
Reference in New Issue
Block a user