147 lines
5.0 KiB
Python
147 lines
5.0 KiB
Python
"""
|
|
PostgreSQL WorkspaceMember Repository 实现
|
|
"""
|
|
|
|
from typing import List, Optional
|
|
|
|
import psycopg2
|
|
from psycopg2.extras import RealDictCursor
|
|
|
|
from packages.domain.entities import WorkspaceMember
|
|
from packages.ports.workspace_member_repository import WorkspaceMemberRepository
|
|
|
|
|
|
class PostgresWorkspaceMemberRepository(WorkspaceMemberRepository):
|
|
"""WorkspaceMember 仓储 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, member: WorkspaceMember) -> None:
|
|
"""保存成员"""
|
|
conn = self._get_connection()
|
|
try:
|
|
with conn.cursor() as cur:
|
|
cur.execute(
|
|
"""
|
|
INSERT INTO workspace_members (
|
|
id, workspace_id, user_id, role, invited_by, joined_at
|
|
) VALUES (
|
|
%(id)s, %(workspace_id)s, %(user_id)s, %(role)s,
|
|
%(invited_by)s, %(joined_at)s
|
|
)
|
|
ON CONFLICT (workspace_id, user_id) DO UPDATE SET
|
|
role = EXCLUDED.role
|
|
""",
|
|
{
|
|
"id": member.id,
|
|
"workspace_id": member.workspace_id,
|
|
"user_id": member.user_id,
|
|
"role": member.role,
|
|
"invited_by": member.invited_by,
|
|
"joined_at": member.joined_at,
|
|
},
|
|
)
|
|
conn.commit()
|
|
finally:
|
|
conn.close()
|
|
|
|
def find_by_id(self, member_id: str) -> Optional[WorkspaceMember]:
|
|
"""根据 ID 查找成员"""
|
|
conn = self._get_connection()
|
|
try:
|
|
with conn.cursor() as cur:
|
|
cur.execute("SELECT * FROM workspace_members WHERE id = %s", (member_id,))
|
|
row = cur.fetchone()
|
|
return self._row_to_member(row) if row else None
|
|
finally:
|
|
conn.close()
|
|
|
|
def find_by_workspace_and_user(
|
|
self,
|
|
workspace_id: str,
|
|
user_id: str,
|
|
) -> Optional[WorkspaceMember]:
|
|
"""根据 workspace 和 user 查找成员"""
|
|
conn = self._get_connection()
|
|
try:
|
|
with conn.cursor() as cur:
|
|
cur.execute(
|
|
"SELECT * FROM workspace_members WHERE workspace_id = %s AND user_id = %s",
|
|
(workspace_id, user_id),
|
|
)
|
|
row = cur.fetchone()
|
|
return self._row_to_member(row) if row else None
|
|
finally:
|
|
conn.close()
|
|
|
|
def find_by_user(self, user_id: str) -> List[WorkspaceMember]:
|
|
"""查找用户的所有成员记录"""
|
|
conn = self._get_connection()
|
|
try:
|
|
with conn.cursor() as cur:
|
|
cur.execute(
|
|
"SELECT * FROM workspace_members WHERE user_id = %s ORDER BY joined_at DESC",
|
|
(user_id,),
|
|
)
|
|
rows = cur.fetchall()
|
|
return [self._row_to_member(row) for row in rows]
|
|
finally:
|
|
conn.close()
|
|
|
|
def find_by_workspace(self, workspace_id: str) -> List[WorkspaceMember]:
|
|
"""查找 workspace 的所有成员"""
|
|
conn = self._get_connection()
|
|
try:
|
|
with conn.cursor() as cur:
|
|
cur.execute(
|
|
"SELECT * FROM workspace_members WHERE workspace_id = %s ORDER BY joined_at",
|
|
(workspace_id,),
|
|
)
|
|
rows = cur.fetchall()
|
|
return [self._row_to_member(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 workspace_members WHERE workspace_id = %s",
|
|
(workspace_id,),
|
|
)
|
|
return cur.fetchone()["count"]
|
|
finally:
|
|
conn.close()
|
|
|
|
def delete(self, member_id: str) -> bool:
|
|
"""删除成员"""
|
|
conn = self._get_connection()
|
|
try:
|
|
with conn.cursor() as cur:
|
|
cur.execute("DELETE FROM workspace_members WHERE id = %s", (member_id,))
|
|
deleted = cur.rowcount > 0
|
|
conn.commit()
|
|
return deleted
|
|
finally:
|
|
conn.close()
|
|
|
|
def _row_to_member(self, row: dict) -> WorkspaceMember:
|
|
"""将数据库行转换为 WorkspaceMember 对象"""
|
|
return WorkspaceMember(
|
|
id=row["id"],
|
|
workspace_id=row["workspace_id"],
|
|
user_id=row["user_id"],
|
|
role=row["role"],
|
|
invited_by=row["invited_by"],
|
|
joined_at=row["joined_at"],
|
|
)
|