205 lines
6.4 KiB
Python
205 lines
6.4 KiB
Python
"""SQLite 实现的项目管理 Repository"""
|
||
|
||
import sqlite3
|
||
from datetime import datetime
|
||
from typing import List, Optional
|
||
|
||
from packages.domain.project_management import (
|
||
Milestone,
|
||
Task,
|
||
TaskIssue,
|
||
TaskPriority,
|
||
TaskStatus,
|
||
)
|
||
|
||
DB_PATH = "tracker.db"
|
||
|
||
|
||
class SQLiteTaskRepository:
|
||
"""基于 SQLite 的任务仓储"""
|
||
|
||
def get_by_id(self, task_id: str) -> Optional[Task]:
|
||
conn = sqlite3.connect(DB_PATH)
|
||
conn.row_factory = sqlite3.Row
|
||
cursor = conn.cursor()
|
||
|
||
cursor.execute("SELECT * FROM tasks WHERE id = ?", (task_id,))
|
||
row = cursor.fetchone()
|
||
conn.close()
|
||
|
||
if not row:
|
||
return None
|
||
|
||
return Task(
|
||
id=str(row["id"]),
|
||
name=row["name"],
|
||
description=row["description"] or "",
|
||
status=TaskStatus(row["status"]) if row["status"] else TaskStatus.PENDING,
|
||
priority=(TaskPriority(row["priority"]) if row["priority"] else TaskPriority.MEDIUM),
|
||
progress=0, # tracker.db 没有 progress 字段
|
||
project_id=row["phase"] or "xiaoxia-saas",
|
||
workspace_id="xiaoxia-workspace",
|
||
assignee_user_id=row["assigned_to"] or "",
|
||
created_at=(datetime.fromisoformat(row["created_at"]) if row["created_at"] else datetime.now()),
|
||
updated_at=datetime.now(),
|
||
)
|
||
|
||
def list_by_project(self, project_id: str, skip: int = 0, limit: int = 100) -> List[Task]:
|
||
conn = sqlite3.connect(DB_PATH)
|
||
conn.row_factory = sqlite3.Row
|
||
cursor = conn.cursor()
|
||
|
||
# 返回所有任务(忽略 project_id 过滤,因为 tracker.db 使用 phase)
|
||
cursor.execute(
|
||
"""
|
||
SELECT * FROM tasks
|
||
ORDER BY created_at DESC
|
||
LIMIT ? OFFSET ?
|
||
""",
|
||
(limit, skip),
|
||
)
|
||
|
||
rows = cursor.fetchall()
|
||
conn.close()
|
||
|
||
tasks = []
|
||
for row in rows:
|
||
tasks.append(
|
||
Task(
|
||
id=str(row["id"]),
|
||
name=row["name"],
|
||
description=row["description"] or "",
|
||
status=(TaskStatus(row["status"]) if row["status"] else TaskStatus.PENDING),
|
||
priority=(TaskPriority(row["priority"]) if row["priority"] else TaskPriority.MEDIUM),
|
||
progress=0,
|
||
project_id=row["phase"] or "xiaoxia-saas",
|
||
workspace_id="xiaoxia-workspace",
|
||
assignee_user_id=row["assigned_to"] or "",
|
||
created_at=(datetime.fromisoformat(row["created_at"]) if row["created_at"] else datetime.now()),
|
||
updated_at=datetime.now(),
|
||
)
|
||
)
|
||
|
||
return tasks
|
||
|
||
def save(self, task: Task) -> Task:
|
||
conn = sqlite3.connect(DB_PATH)
|
||
cursor = conn.cursor()
|
||
|
||
if task.id and task.id.isdigit():
|
||
# 更新现有任务
|
||
cursor.execute(
|
||
"""
|
||
UPDATE tasks
|
||
SET name = ?, description = ?, status = ?, priority = ?, assigned_to = ?
|
||
WHERE id = ?
|
||
""",
|
||
(
|
||
task.name,
|
||
task.description,
|
||
task.status.value,
|
||
task.priority.value,
|
||
task.assignee_user_id,
|
||
task.id,
|
||
),
|
||
)
|
||
else:
|
||
# 创建新任务
|
||
cursor.execute(
|
||
"""
|
||
INSERT INTO tasks (name, description, status, phase, priority, assigned_to, created_at)
|
||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||
""",
|
||
(
|
||
task.name,
|
||
task.description,
|
||
task.status.value,
|
||
task.project_id,
|
||
task.priority.value,
|
||
task.assignee_user_id,
|
||
datetime.now().isoformat(),
|
||
),
|
||
)
|
||
task.id = str(cursor.lastrowid)
|
||
|
||
conn.commit()
|
||
conn.close()
|
||
return task
|
||
|
||
|
||
class SQLiteMilestoneRepository:
|
||
"""基于 SQLite 的里程碑仓储"""
|
||
|
||
def list_by_project(self, project_id: str) -> List[Milestone]:
|
||
conn = sqlite3.connect(DB_PATH)
|
||
conn.row_factory = sqlite3.Row
|
||
cursor = conn.cursor()
|
||
|
||
cursor.execute("SELECT * FROM milestones ORDER BY start_date")
|
||
rows = cursor.fetchall()
|
||
conn.close()
|
||
|
||
milestones = []
|
||
for row in rows:
|
||
milestones.append(
|
||
Milestone(
|
||
id=str(row["id"]),
|
||
name=row["name"],
|
||
description=row["description"] or "",
|
||
target_date=row["end_date"] or "",
|
||
project_id=row["phase"] or "xiaoxia-saas",
|
||
workspace_id="xiaoxia-workspace",
|
||
created_at=(datetime.fromisoformat(row["start_date"]) if row["start_date"] else datetime.now()),
|
||
)
|
||
)
|
||
|
||
return milestones
|
||
|
||
def save(self, milestone: Milestone) -> Milestone:
|
||
conn = sqlite3.connect(DB_PATH)
|
||
cursor = conn.cursor()
|
||
|
||
if milestone.id and milestone.id.isdigit():
|
||
cursor.execute(
|
||
"""
|
||
UPDATE milestones
|
||
SET name = ?, description = ?, end_date = ?
|
||
WHERE id = ?
|
||
""",
|
||
(
|
||
milestone.name,
|
||
milestone.description,
|
||
milestone.target_date,
|
||
milestone.id,
|
||
),
|
||
)
|
||
else:
|
||
cursor.execute(
|
||
"""
|
||
INSERT INTO milestones (name, description, phase, start_date, end_date)
|
||
VALUES (?, ?, ?, ?, ?)
|
||
""",
|
||
(
|
||
milestone.name,
|
||
milestone.description,
|
||
milestone.project_id,
|
||
datetime.now().isoformat(),
|
||
milestone.target_date,
|
||
),
|
||
)
|
||
milestone.id = str(cursor.lastrowid)
|
||
|
||
conn.commit()
|
||
conn.close()
|
||
return milestone
|
||
|
||
|
||
class SQLiteTaskIssueRepository:
|
||
"""空实现 - tracker.db 没有 issues 表"""
|
||
|
||
def list_by_task(self, task_id: str) -> List[TaskIssue]:
|
||
return []
|
||
|
||
def save(self, issue: TaskIssue) -> TaskIssue:
|
||
return issue
|