aiteamutils 0.2.137__py3-none-any.whl → 0.2.138__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/base_service.py +54 -20
- aiteamutils/validators.py +2 -63
- aiteamutils/version.py +1 -1
- {aiteamutils-0.2.137.dist-info → aiteamutils-0.2.138.dist-info}/METADATA +1 -1
- {aiteamutils-0.2.137.dist-info → aiteamutils-0.2.138.dist-info}/RECORD +6 -6
- {aiteamutils-0.2.137.dist-info → aiteamutils-0.2.138.dist-info}/WHEEL +0 -0
aiteamutils/base_service.py
CHANGED
@@ -65,6 +65,31 @@ class BaseService(Generic[ModelType]):
|
|
65
65
|
)
|
66
66
|
|
67
67
|
try:
|
68
|
+
# 파일 데이터 분리
|
69
|
+
entity_data_copy = entity_data.copy()
|
70
|
+
separated_files = {}
|
71
|
+
|
72
|
+
# extra_data 내의 파일 필드 분리
|
73
|
+
if 'extra_data' in entity_data_copy and isinstance(entity_data_copy['extra_data'], dict):
|
74
|
+
extra_data = entity_data_copy['extra_data'].copy()
|
75
|
+
file_fields = {k: v for k, v in extra_data.items() if k.endswith('_files')}
|
76
|
+
|
77
|
+
if file_fields and not storage_dir:
|
78
|
+
raise CustomException(
|
79
|
+
ErrorCode.INVALID_INPUT,
|
80
|
+
detail="storage_dir is required for file upload",
|
81
|
+
source_function=f"base_service.{self.__class__.__name__}.create.file_fields"
|
82
|
+
)
|
83
|
+
|
84
|
+
# 파일 필드 분리 및 제거
|
85
|
+
for field_name, files in file_fields.items():
|
86
|
+
if files:
|
87
|
+
separated_files[field_name] = files
|
88
|
+
# extra_data에서 파일 필드 제거
|
89
|
+
del extra_data[field_name]
|
90
|
+
|
91
|
+
entity_data_copy['extra_data'] = extra_data
|
92
|
+
|
68
93
|
async with self.db_session.begin():
|
69
94
|
# 고유 검사 수행
|
70
95
|
if unique_check:
|
@@ -73,35 +98,44 @@ class BaseService(Generic[ModelType]):
|
|
73
98
|
if fk_check:
|
74
99
|
await validate_unique_fields(self.db_session, fk_check, find_value=False)
|
75
100
|
|
76
|
-
#
|
77
|
-
file_keys = [key for key in entity_data.keys() if key.endswith('_files')]
|
78
|
-
file_infos = {}
|
79
|
-
|
80
|
-
if file_keys and not storage_dir:
|
81
|
-
raise CustomException(
|
82
|
-
ErrorCode.INVALID_INPUT,
|
83
|
-
detail="storage_dir is required for file upload",
|
84
|
-
source_function=f"base_service.{self.__class__.__name__}.create.file_keys"
|
85
|
-
)
|
86
|
-
|
87
|
-
# 먼저 엔티티를 생성하여 ULID를 얻음
|
101
|
+
# 엔티티 생성
|
88
102
|
result = await self.repository.create(
|
89
|
-
entity_data=
|
103
|
+
entity_data=entity_data_copy,
|
90
104
|
exclude_entities=exclude_entities
|
91
105
|
)
|
92
106
|
|
93
|
-
# 파일 처리
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
files=
|
107
|
+
# 파일 처리 및 저장
|
108
|
+
file_infos = {}
|
109
|
+
if separated_files:
|
110
|
+
from .files import FileHandler
|
111
|
+
for field_name, files in separated_files.items():
|
112
|
+
saved_files = await FileHandler.save_files(
|
113
|
+
files=files,
|
100
114
|
storage_dir=storage_dir,
|
101
115
|
entity_name=self.model.__tablename__,
|
102
116
|
entity_ulid=result.ulid,
|
103
117
|
db_session=self.db_session
|
104
118
|
)
|
119
|
+
file_infos[field_name] = saved_files
|
120
|
+
|
121
|
+
# extra_data 업데이트
|
122
|
+
if not hasattr(result, 'extra_data'):
|
123
|
+
result.extra_data = {}
|
124
|
+
if not result.extra_data:
|
125
|
+
result.extra_data = {}
|
126
|
+
|
127
|
+
result.extra_data[field_name] = [
|
128
|
+
{
|
129
|
+
'original_name': f['original_name'],
|
130
|
+
'storage_path': f['storage_path'],
|
131
|
+
'mime_type': f['mime_type'],
|
132
|
+
'size': f['size'],
|
133
|
+
'checksum': f['checksum']
|
134
|
+
} for f in saved_files
|
135
|
+
]
|
136
|
+
|
137
|
+
# extra_data 업데이트된 엔티티 저장
|
138
|
+
await self.db_session.flush()
|
105
139
|
|
106
140
|
# 결과 반환
|
107
141
|
if response_model:
|
aiteamutils/validators.py
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
"""유효성 검사 관련 유틸리티 함수들을 모아둔 모듈입니다."""
|
2
2
|
|
3
|
-
from typing import Type, Dict, Any, Callable, TypeVar, Optional, List, Union
|
3
|
+
from typing import Type, Dict, Any, Callable, TypeVar, Optional, List, Union, Annotated
|
4
4
|
from functools import wraps
|
5
5
|
from sqlalchemy import Table
|
6
6
|
from sqlalchemy.ext.asyncio import AsyncSession
|
7
7
|
from fastapi import Request
|
8
8
|
from inspect import signature
|
9
|
-
from pydantic import BaseModel, field_validator
|
9
|
+
from pydantic import BaseModel, field_validator, Field
|
10
10
|
from datetime import datetime, date
|
11
11
|
import re
|
12
12
|
|
@@ -234,64 +234,3 @@ class Validator:
|
|
234
234
|
source_function="Validator.validate_datetime",
|
235
235
|
original_error=str(e)
|
236
236
|
)
|
237
|
-
|
238
|
-
def _create_validator(field_names: tuple[str, ...],
|
239
|
-
validate_func: Callable,
|
240
|
-
field_type: Type,
|
241
|
-
error_code: ErrorCode,
|
242
|
-
source_prefix: str):
|
243
|
-
"""공통 validator 생성 함수
|
244
|
-
Args:
|
245
|
-
field_names: 검증할 필드명들
|
246
|
-
validate_func: 실제 검증을 수행할 함수
|
247
|
-
field_type: 필드 타입 (date 또는 datetime)
|
248
|
-
error_code: 에러 발생시 사용할 에러 코드
|
249
|
-
source_prefix: 에러 발생시 사용할 source_function 접두사
|
250
|
-
"""
|
251
|
-
def decorator(cls):
|
252
|
-
for field_name in field_names:
|
253
|
-
field = cls.model_fields.get(field_name)
|
254
|
-
if field:
|
255
|
-
field.annotation = Optional[field_type]
|
256
|
-
field.default = None
|
257
|
-
|
258
|
-
@field_validator(field_name, mode='before')
|
259
|
-
@classmethod
|
260
|
-
def validate(cls, value: Any, info: Any) -> Any:
|
261
|
-
# 빈 값 처리를 가장 먼저, 더 엄격하게
|
262
|
-
if not value or str(value).strip() == "":
|
263
|
-
return None
|
264
|
-
try:
|
265
|
-
return validate_func(value, field_name)
|
266
|
-
except CustomException as e:
|
267
|
-
raise e
|
268
|
-
except Exception as e:
|
269
|
-
raise CustomException(
|
270
|
-
error_code=error_code,
|
271
|
-
detail=f"{field_name}|{value}",
|
272
|
-
source_function=f"{source_prefix}.{field_name}",
|
273
|
-
original_error=str(e)
|
274
|
-
)
|
275
|
-
setattr(cls, f'validate_{field_name}', validate)
|
276
|
-
return cls
|
277
|
-
return decorator
|
278
|
-
|
279
|
-
def date_validator(*field_names: str):
|
280
|
-
"""날짜 필드 유효성 검사 데코레이터"""
|
281
|
-
return _create_validator(
|
282
|
-
field_names=field_names,
|
283
|
-
validate_func=Validator.validate_date,
|
284
|
-
field_type=date,
|
285
|
-
error_code=ErrorCode.VALIDATION_ERROR,
|
286
|
-
source_prefix="date_validator"
|
287
|
-
)
|
288
|
-
|
289
|
-
def datetime_validator(*field_names: str):
|
290
|
-
"""날짜+시간 필드 유효성 검사 데코레이터"""
|
291
|
-
return _create_validator(
|
292
|
-
field_names=field_names,
|
293
|
-
validate_func=Validator.validate_datetime,
|
294
|
-
field_type=datetime,
|
295
|
-
error_code=ErrorCode.VALIDATION_ERROR,
|
296
|
-
source_prefix="datetime_validator"
|
297
|
-
)
|
aiteamutils/version.py
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
"""버전 정보"""
|
2
|
-
__version__ = "0.2.
|
2
|
+
__version__ = "0.2.138"
|
@@ -1,7 +1,7 @@
|
|
1
1
|
aiteamutils/__init__.py,sha256=kRBpRjark0M8ZwFfmKiMFol6CbIILN3WE4f6_P6iIq0,1089
|
2
2
|
aiteamutils/base_model.py,sha256=0rs4cjnF2ea3Q2vBTj6F64BGk7ZglJsChsS7ne_R_tg,4056
|
3
3
|
aiteamutils/base_repository.py,sha256=Oy2zE1i5qx60Xf1tnsaKLyFWapiPqt5JH8NejwNrPWg,4647
|
4
|
-
aiteamutils/base_service.py,sha256=
|
4
|
+
aiteamutils/base_service.py,sha256=QSUzdIcV88EdmjEF7vMyrN5CjKhS6HTbsoXSp8P9Gag,14432
|
5
5
|
aiteamutils/cache.py,sha256=07xBGlgAwOTAdY5mnMOQJ5EBxVwe8glVD7DkGEkxCtw,1373
|
6
6
|
aiteamutils/config.py,sha256=YdalpJb70-txhGJAS4aaKglEZAFVWgfzw5BXSWpkUz4,3232
|
7
7
|
aiteamutils/database.py,sha256=msvBKtxWeQVOo0v2Q9i2azuTNtnUItuNNar52gdRZTo,20418
|
@@ -9,8 +9,8 @@ aiteamutils/enums.py,sha256=7WLqlcJqQWtETAga2WAxNp3dJTQIAd2TW-4WzkoHHa8,2498
|
|
9
9
|
aiteamutils/exceptions.py,sha256=pgf3ersezObyl17wAO3I2fb8m9t2OzWDX1mSjwAWm2Y,16035
|
10
10
|
aiteamutils/files.py,sha256=tdvivl3XLNv7Al7H1gGFczmrHM8XlQpiZsEc2xQ_UTU,8829
|
11
11
|
aiteamutils/security.py,sha256=McUl3t5Z5SyUDVUHymHdDkYyF4YSeg4g9fFMML4W6Kw,11630
|
12
|
-
aiteamutils/validators.py,sha256=
|
13
|
-
aiteamutils/version.py,sha256=
|
14
|
-
aiteamutils-0.2.
|
15
|
-
aiteamutils-0.2.
|
16
|
-
aiteamutils-0.2.
|
12
|
+
aiteamutils/validators.py,sha256=_WHN6jqJQzKM5uPTg-Da8U2qqevS84XeKMkCCF4C_lY,9591
|
13
|
+
aiteamutils/version.py,sha256=xZySMcOyLEq-gP55_1pxieeIS9BbYr1Tg7GT4OJHMjI,43
|
14
|
+
aiteamutils-0.2.138.dist-info/METADATA,sha256=Hc55YOzeewQdyvH7AGj17BxER6ZiOIptMcPCY87XyXE,1719
|
15
|
+
aiteamutils-0.2.138.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
16
|
+
aiteamutils-0.2.138.dist-info/RECORD,,
|
File without changes
|