Files
xiaoxia-saas/packages/adapters/postgres/project_repository.py
T
2026-06-21 06:52:19 +08:00

137 lines
4.7 KiB
Python

"""
PostgreSQL Project Repository 实现
"""
from typing import List, Optional
import psycopg2
from psycopg2.extras import RealDictCursor
from packages.domain.entities import Project
from packages.ports.project_repository import ProjectRepository
class PostgresProjectRepository(ProjectRepository):
"""Project 仓储 PostgreSQL 实现"""
def __init__(self, connection_string: str):
self.connection_string = connection_string
def _get_connection(self):
"""获取数据库连接(使用连接池)"""
from packages.adapters.postgres.connection_pool import PooledConnection
return PooledConnection()
def save(self, project: Project) -> None:
"""保存项目"""
conn = self._get_connection()
try:
with conn.cursor() as cur:
cur.execute(
"""
INSERT INTO projects (
id, workspace_id, name, description, status,
created_by, created_at, updated_at
) VALUES (
%(id)s, %(workspace_id)s, %(name)s, %(description)s, %(status)s,
%(created_by)s, %(created_at)s, %(updated_at)s
)
ON CONFLICT (id) DO UPDATE SET
name = EXCLUDED.name,
description = EXCLUDED.description,
status = EXCLUDED.status,
updated_at = EXCLUDED.updated_at
""",
{
"id": project.id,
"workspace_id": project.workspace_id,
"name": project.name,
"description": project.description,
"status": project.status,
"created_by": project.created_by,
"created_at": project.created_at,
"updated_at": project.updated_at,
},
)
conn.commit()
finally:
conn.close()
def find_by_id(self, project_id: str) -> Optional[Project]:
"""根据 ID 查找项目"""
conn = self._get_connection()
try:
with conn.cursor() as cur:
cur.execute("SELECT * FROM projects WHERE id = %s", (project_id,))
row = cur.fetchone()
return self._row_to_project(row) if row else None
finally:
conn.close()
def find_by_workspace(self, workspace_id: str) -> List[Project]:
"""根据 workspace 查找所有项目"""
conn = self._get_connection()
try:
with conn.cursor() as cur:
cur.execute(
"SELECT * FROM projects WHERE workspace_id = %s ORDER BY created_at DESC",
(workspace_id,),
)
rows = cur.fetchall()
return [self._row_to_project(row) for row in rows]
finally:
conn.close()
def find_by_creator(self, user_id: str) -> List[Project]:
"""根据创建者查找项目"""
conn = self._get_connection()
try:
with conn.cursor() as cur:
cur.execute(
"SELECT * FROM projects WHERE created_by = %s ORDER BY created_at DESC",
(user_id,),
)
rows = cur.fetchall()
return [self._row_to_project(row) for row in rows]
finally:
conn.close()
def count_by_workspace(self, workspace_id: str) -> int:
"""统计 workspace 的项目数量"""
conn = self._get_connection()
try:
with conn.cursor() as cur:
cur.execute(
"SELECT COUNT(*) FROM projects WHERE workspace_id = %s",
(workspace_id,),
)
return cur.fetchone()["count"]
finally:
conn.close()
def delete(self, project_id: str) -> bool:
"""删除项目"""
conn = self._get_connection()
try:
with conn.cursor() as cur:
cur.execute("DELETE FROM projects WHERE id = %s", (project_id,))
deleted = cur.rowcount > 0
conn.commit()
return deleted
finally:
conn.close()
def _row_to_project(self, row: dict) -> Project:
"""将数据库行转换为 Project 对象"""
return Project(
id=row["id"],
workspace_id=row["workspace_id"],
name=row["name"],
description=row["description"],
status=row["status"],
created_by=row["created_by"],
created_at=row["created_at"],
updated_at=row["updated_at"],
)