aiteamutils 0.2.58__py3-none-any.whl → 0.2.60__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aiteamutils/__init__.py +0 -5
- aiteamutils/base_repository.py +36 -190
- aiteamutils/base_service.py +17 -628
- aiteamutils/database.py +40 -199
- aiteamutils/version.py +1 -1
- {aiteamutils-0.2.58.dist-info → aiteamutils-0.2.60.dist-info}/METADATA +1 -1
- aiteamutils-0.2.60.dist-info/RECORD +15 -0
- aiteamutils/dependencies.py +0 -227
- aiteamutils-0.2.58.dist-info/RECORD +0 -16
- {aiteamutils-0.2.58.dist-info → aiteamutils-0.2.60.dist-info}/WHEEL +0 -0
aiteamutils/__init__.py
CHANGED
@@ -21,7 +21,6 @@ from .base_repository import BaseRepository
|
|
21
21
|
from .validators import validate_with
|
22
22
|
from .enums import ActivityType
|
23
23
|
from .version import __version__
|
24
|
-
from .dependencies import setup_dependencies, register_service
|
25
24
|
|
26
25
|
__all__ = [
|
27
26
|
# Base Models
|
@@ -32,10 +31,6 @@ __all__ = [
|
|
32
31
|
# Database
|
33
32
|
"DatabaseService",
|
34
33
|
|
35
|
-
# Dependencies
|
36
|
-
"setup_dependencies",
|
37
|
-
"register_service",
|
38
|
-
|
39
34
|
# Exceptions
|
40
35
|
"CustomException",
|
41
36
|
"ErrorCode",
|
aiteamutils/base_repository.py
CHANGED
@@ -1,208 +1,54 @@
|
|
1
|
-
|
2
|
-
from typing import TypeVar, Generic,
|
3
|
-
from sqlalchemy.orm import DeclarativeBase
|
4
|
-
from sqlalchemy.exc import IntegrityError, SQLAlchemyError
|
5
|
-
from sqlalchemy import select, or_, and_
|
6
|
-
from .exceptions import CustomException, ErrorCode
|
7
|
-
from sqlalchemy.orm import joinedload
|
8
|
-
from sqlalchemy.sql import Select
|
9
|
-
from fastapi import Request
|
1
|
+
#기본 라이브러리
|
2
|
+
from typing import TypeVar, Generic, Type, Any, Dict, List, Optional
|
3
|
+
from sqlalchemy.orm import DeclarativeBase
|
10
4
|
from sqlalchemy.ext.asyncio import AsyncSession
|
5
|
+
from sqlalchemy.exc import SQLAlchemyError
|
6
|
+
from sqlalchemy import select
|
7
|
+
|
8
|
+
#패키지 라이브러리
|
9
|
+
from .exceptions import ErrorCode, CustomException
|
10
|
+
from .database import list_entities
|
11
11
|
|
12
12
|
ModelType = TypeVar("ModelType", bound=DeclarativeBase)
|
13
13
|
|
14
14
|
class BaseRepository(Generic[ModelType]):
|
15
|
-
##################
|
16
|
-
# 1. 초기화 영역 #
|
17
|
-
##################
|
18
15
|
def __init__(self, session: AsyncSession, model: Type[ModelType]):
|
19
|
-
|
20
|
-
Args:
|
21
|
-
session (AsyncSession): 데이터베이스 세션
|
22
|
-
model (Type[ModelType]): 모델 클래스
|
23
|
-
"""
|
24
|
-
self.session = session
|
25
|
-
self.model = model
|
26
|
-
|
27
|
-
@property
|
28
|
-
def session(self):
|
29
|
-
"""현재 세션을 반환합니다."""
|
30
|
-
if self._session is None:
|
16
|
+
if session is None:
|
31
17
|
raise CustomException(
|
32
18
|
ErrorCode.DB_CONNECTION_ERROR,
|
33
19
|
detail="Database session is not set",
|
34
20
|
source_function=f"{self.__class__.__name__}.session"
|
35
21
|
)
|
36
|
-
|
37
|
-
|
38
|
-
@session.setter
|
39
|
-
def session(self, value):
|
40
|
-
"""세션을 설정합니다."""
|
41
|
-
self._session = value
|
42
|
-
|
43
|
-
#######################
|
44
|
-
# 2. CRUD 작업 #
|
45
|
-
#######################
|
46
|
-
async def get(
|
47
|
-
self,
|
48
|
-
ulid: str
|
49
|
-
) -> Optional[Dict[str, Any]]:
|
50
|
-
"""ULID로 엔티티를 조회합니다."""
|
51
|
-
try:
|
52
|
-
stmt = select(self.model).filter_by(ulid=ulid, is_deleted=False)
|
53
|
-
result = await self.session.execute(stmt)
|
54
|
-
entity = result.scalars().unique().first()
|
55
|
-
|
56
|
-
if not entity:
|
57
|
-
raise CustomException(
|
58
|
-
ErrorCode.DB_NO_RESULT,
|
59
|
-
detail=f"{self.model.__tablename__}|ulid|{ulid}",
|
60
|
-
source_function=f"{self.__class__.__name__}.get"
|
61
|
-
)
|
62
|
-
return entity
|
63
|
-
except CustomException as e:
|
64
|
-
e.detail = f"Repository error for {self.model.__tablename__}: {e.detail}"
|
65
|
-
e.source_function = f"{self.__class__.__name__}.get -> {e.source_function}"
|
66
|
-
raise e
|
67
|
-
except SQLAlchemyError as e:
|
22
|
+
if model is None:
|
68
23
|
raise CustomException(
|
69
|
-
ErrorCode.
|
70
|
-
detail=
|
71
|
-
source_function=f"{self.__class__.__name__}.
|
72
|
-
original_error=e
|
24
|
+
ErrorCode.DB_CONNECTION_ERROR,
|
25
|
+
detail="Model is not set",
|
26
|
+
source_function=f"{self.__class__.__name__}.model"
|
73
27
|
)
|
74
28
|
|
29
|
+
self.session = session
|
30
|
+
self.model = model
|
31
|
+
|
32
|
+
@property
|
33
|
+
def session(self) -> AsyncSession:
|
34
|
+
return self._session
|
35
|
+
|
75
36
|
async def list(
|
76
37
|
self,
|
77
38
|
skip: int = 0,
|
78
39
|
limit: int = 100,
|
79
|
-
filters: Dict[str, Any]
|
80
|
-
|
81
|
-
) -> List[
|
82
|
-
"""
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
# 페이지네이션 적용
|
95
|
-
stmt = stmt.limit(limit).offset(skip)
|
96
|
-
|
97
|
-
result = await self.session.execute(stmt)
|
98
|
-
return result.scalars().unique().all()
|
99
|
-
|
100
|
-
except SQLAlchemyError as e:
|
101
|
-
raise CustomException(
|
102
|
-
ErrorCode.DB_QUERY_ERROR,
|
103
|
-
detail=f"Unexpected repository list error in {self.model.__tablename__}: {str(e)}",
|
104
|
-
source_function=f"{self.__class__.__name__}.list",
|
105
|
-
original_error=e,
|
106
|
-
)
|
107
|
-
|
108
|
-
async def create(self, data: Dict[str, Any]) -> ModelType:
|
109
|
-
"""새로운 엔티티를 생성합니다."""
|
110
|
-
try:
|
111
|
-
entity = self.model(**data)
|
112
|
-
self.session.add(entity)
|
113
|
-
await self.session.flush()
|
114
|
-
await self.session.refresh(entity)
|
115
|
-
return entity
|
116
|
-
except IntegrityError as e:
|
117
|
-
await self.session.rollback()
|
118
|
-
self._handle_integrity_error(e, "create", data)
|
119
|
-
except SQLAlchemyError as e:
|
120
|
-
await self.session.rollback()
|
121
|
-
raise CustomException(
|
122
|
-
ErrorCode.DB_CREATE_ERROR,
|
123
|
-
detail=f"Database create error in {self.model.__tablename__}: {str(e)}",
|
124
|
-
source_function=f"{self.__class__.__name__}.create",
|
125
|
-
original_error=e
|
126
|
-
)
|
127
|
-
|
128
|
-
async def update(self, ulid: str, data: Dict[str, Any]) -> Optional[ModelType]:
|
129
|
-
"""기존 엔티티를 수정합니다."""
|
130
|
-
try:
|
131
|
-
stmt = select(self.model).filter_by(ulid=ulid, is_deleted=False)
|
132
|
-
result = await self.session.execute(stmt)
|
133
|
-
entity = result.scalars().first()
|
134
|
-
|
135
|
-
if not entity:
|
136
|
-
raise CustomException(
|
137
|
-
ErrorCode.DB_NO_RESULT,
|
138
|
-
detail=f"{self.model.__tablename__}|ulid|{ulid}",
|
139
|
-
source_function=f"{self.__class__.__name__}.update"
|
140
|
-
)
|
141
|
-
|
142
|
-
for key, value in data.items():
|
143
|
-
setattr(entity, key, value)
|
144
|
-
|
145
|
-
await self.session.flush()
|
146
|
-
await self.session.refresh(entity)
|
147
|
-
return entity
|
148
|
-
|
149
|
-
except IntegrityError as e:
|
150
|
-
await self.session.rollback()
|
151
|
-
self._handle_integrity_error(e, "update", data)
|
152
|
-
except SQLAlchemyError as e:
|
153
|
-
await self.session.rollback()
|
154
|
-
raise CustomException(
|
155
|
-
ErrorCode.DB_UPDATE_ERROR,
|
156
|
-
detail=f"Database update error in {self.model.__tablename__}: {str(e)}",
|
157
|
-
source_function=f"{self.__class__.__name__}.update",
|
158
|
-
original_error=e
|
159
|
-
)
|
160
|
-
|
161
|
-
async def delete(self, ulid: str) -> bool:
|
162
|
-
"""엔티티를 소프트 삭제합니다."""
|
163
|
-
try:
|
164
|
-
stmt = select(self.model).filter_by(ulid=ulid, is_deleted=False)
|
165
|
-
result = await self.session.execute(stmt)
|
166
|
-
entity = result.scalars().first()
|
167
|
-
|
168
|
-
if not entity:
|
169
|
-
raise CustomException(
|
170
|
-
ErrorCode.DB_NO_RESULT,
|
171
|
-
detail=f"{self.model.__tablename__}|ulid|{ulid}",
|
172
|
-
source_function=f"{self.__class__.__name__}.delete"
|
173
|
-
)
|
174
|
-
|
175
|
-
entity.is_deleted = True
|
176
|
-
await self.session.flush()
|
177
|
-
return True
|
178
|
-
|
179
|
-
except SQLAlchemyError as e:
|
180
|
-
await self.session.rollback()
|
181
|
-
raise CustomException(
|
182
|
-
ErrorCode.DB_DELETE_ERROR,
|
183
|
-
detail=f"Database delete error in {self.model.__tablename__}: {str(e)}",
|
184
|
-
source_function=f"{self.__class__.__name__}.delete",
|
185
|
-
original_error=e
|
186
|
-
)
|
187
|
-
|
188
|
-
async def real_delete(self, ulid: str) -> bool:
|
189
|
-
"""엔티티를 실제로 삭제합니다."""
|
190
|
-
try:
|
191
|
-
stmt = select(self.model).filter_by(ulid=ulid)
|
192
|
-
result = await self.session.execute(stmt)
|
193
|
-
entity = result.scalars().first()
|
194
|
-
|
195
|
-
if entity:
|
196
|
-
await self.session.delete(entity)
|
197
|
-
await self.session.flush()
|
198
|
-
return True
|
199
|
-
return False
|
200
|
-
|
201
|
-
except SQLAlchemyError as e:
|
202
|
-
await self.session.rollback()
|
203
|
-
raise CustomException(
|
204
|
-
ErrorCode.DB_DELETE_ERROR,
|
205
|
-
detail=f"Database real delete error in {self.model.__tablename__}: {str(e)}",
|
206
|
-
source_function=f"{self.__class__.__name__}.real_delete",
|
207
|
-
original_error=e
|
208
|
-
)
|
40
|
+
filters: Optional[Dict[str, Any]] = None,
|
41
|
+
joins: Optional[List[Any]] = None
|
42
|
+
) -> List[ModelType]:
|
43
|
+
"""
|
44
|
+
엔티티 목록 조회.
|
45
|
+
"""
|
46
|
+
# 기본 CRUD 작업 호출
|
47
|
+
return await list_entities(
|
48
|
+
session=self.db_session,
|
49
|
+
model=self.model,
|
50
|
+
skip=skip,
|
51
|
+
limit=limit,
|
52
|
+
filters=filters,
|
53
|
+
joins=joins,
|
54
|
+
)
|