Files
xiaoxia-saas/packages/adapters/postgres/workspace_member_repository.py
T
Xiaoxia AI 8095539dd4
Deploy / Deploy Staging (push) Failing after 6s
Deploy / Deploy Production (push) Has been skipped
Tests / test (push) Failing after 21s
Tests / lint (push) Failing after 21s
feat(repository): add PostgreSQL repositories for Workspace and Member
- Implement PostgresWorkspaceRepository with full CRUD
- Implement PostgresWorkspaceMemberRepository with query methods
- Support find_by_user, find_by_workspace, count_by_workspace
- Use upsert pattern (INSERT ... ON CONFLICT DO UPDATE)
- Proper connection management and cleanup
- Add __init__.py to export all PostgreSQL repositories

Phase 4 Task 35/68 completed
2026-06-17 08:22:45 +08:00

139 lines
4.9 KiB
Python

"""
PostgreSQL WorkspaceMember Repository 实现
"""
from typing import Optional, List
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):
return psycopg2.connect(self.connection_string, cursor_factory=RealDictCursor)
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"],
)