aiteamutils 0.2.164__py3-none-any.whl → 0.2.166__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/database.py
CHANGED
@@ -8,10 +8,11 @@ from typing import (
|
|
8
8
|
List,
|
9
9
|
Optional,
|
10
10
|
AsyncGenerator,
|
11
|
-
Union
|
11
|
+
Union,
|
12
|
+
Tuple
|
12
13
|
)
|
13
14
|
from sqlalchemy.ext.asyncio import AsyncSession
|
14
|
-
from sqlalchemy import select, and_, or_
|
15
|
+
from sqlalchemy import select, and_, or_, join
|
15
16
|
from sqlalchemy.orm import DeclarativeBase, joinedload, selectinload, contains_eager
|
16
17
|
from sqlalchemy.exc import SQLAlchemyError
|
17
18
|
from datetime import datetime
|
@@ -20,12 +21,18 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
|
20
21
|
from fastapi import Request
|
21
22
|
from ulid import ULID
|
22
23
|
from sqlalchemy import MetaData, Table, insert
|
24
|
+
from sqlalchemy.sql.elements import BinaryExpression
|
23
25
|
|
24
26
|
#패키지 라이브러리
|
25
27
|
from .exceptions import ErrorCode, CustomException
|
26
28
|
|
27
29
|
ModelType = TypeVar("ModelType", bound=DeclarativeBase)
|
28
30
|
|
31
|
+
JoinTarget = Union[
|
32
|
+
DeclarativeBase, # 모델
|
33
|
+
Tuple[DeclarativeBase, BinaryExpression] # (모델, 조인 조건)
|
34
|
+
]
|
35
|
+
|
29
36
|
##################
|
30
37
|
# 전처리 #
|
31
38
|
##################
|
@@ -428,7 +435,7 @@ async def list_entities(
|
|
428
435
|
skip: int = 0,
|
429
436
|
limit: int = 100,
|
430
437
|
filters: Optional[List[Dict[str, Any]]] = None,
|
431
|
-
explicit_joins: Optional[List[
|
438
|
+
explicit_joins: Optional[List[JoinTarget]] = None,
|
432
439
|
loading_joins: Optional[List[Any]] = None,
|
433
440
|
order: Optional[List[Dict[str, str]]] = None
|
434
441
|
) -> List[Dict[str, Any]]:
|
@@ -441,31 +448,34 @@ async def list_entities(
|
|
441
448
|
skip: 페이지네이션 시작 위치.
|
442
449
|
limit: 페이지네이션 크기.
|
443
450
|
filters: 필터 조건 딕셔너리.
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
}
|
450
|
-
|
451
|
-
joins: 조인 옵션.
|
452
|
-
예시:
|
453
|
-
joins = [
|
454
|
-
selectinload(YourModel.related_field), # 관련된 필드를 함께 로드
|
455
|
-
joinedload(YourModel.another_related_field) # 다른 관계된 필드를 조인
|
456
|
-
]
|
451
|
+
explicit_joins: 명시적 조인 대상 리스트
|
452
|
+
- 모델만 전달: 기본 outer join
|
453
|
+
- (모델, 조인조건): 조건부 outer join
|
454
|
+
loading_joins: 로딩 조인 옵션 리스트 (joinedload, selectinload 등)
|
455
|
+
order: 정렬 조건 리스트
|
457
456
|
|
458
457
|
Returns:
|
459
458
|
List[Dict[str, Any]]: 쿼리 결과 리스트.
|
460
459
|
"""
|
461
460
|
try:
|
462
461
|
# 기본 쿼리 생성
|
462
|
+
query = select(model)
|
463
|
+
|
464
|
+
# 명시적 조인 적용
|
465
|
+
has_explicit_joins = False
|
463
466
|
if explicit_joins:
|
464
|
-
query = select(model, *explicit_joins)
|
465
467
|
for join_target in explicit_joins:
|
466
|
-
|
467
|
-
|
468
|
-
|
468
|
+
if isinstance(join_target, tuple):
|
469
|
+
target_model, join_condition = join_target
|
470
|
+
query = query.outerjoin(target_model, join_condition)
|
471
|
+
has_explicit_joins = True
|
472
|
+
else:
|
473
|
+
query = query.outerjoin(join_target)
|
474
|
+
|
475
|
+
# 로딩 조인 적용
|
476
|
+
if loading_joins:
|
477
|
+
for join_option in loading_joins:
|
478
|
+
query = query.options(join_option)
|
469
479
|
|
470
480
|
# 필터 조건 적용
|
471
481
|
if filters:
|
@@ -491,8 +501,16 @@ async def list_entities(
|
|
491
501
|
# 페이지네이션 적용
|
492
502
|
query = query.limit(limit).offset(skip)
|
493
503
|
|
504
|
+
# 결과 처리
|
494
505
|
result = await session.execute(query)
|
495
|
-
|
506
|
+
if has_explicit_joins:
|
507
|
+
# 명시적 조인이 있는 경우
|
508
|
+
entities = result.unique().all()
|
509
|
+
return [entity[0] for entity in entities]
|
510
|
+
else:
|
511
|
+
# 기존 방식 유지
|
512
|
+
return result.unique().scalars().all()
|
513
|
+
|
496
514
|
except SQLAlchemyError as e:
|
497
515
|
raise CustomException(
|
498
516
|
ErrorCode.DB_READ_ERROR,
|
@@ -505,28 +523,51 @@ async def get_entity(
|
|
505
523
|
session: AsyncSession,
|
506
524
|
model: Type[ModelType],
|
507
525
|
conditions: Dict[str, Any],
|
508
|
-
explicit_joins: Optional[List[
|
526
|
+
explicit_joins: Optional[List[JoinTarget]] = None,
|
509
527
|
loading_joins: Optional[List[Any]] = None
|
510
528
|
) -> ModelType:
|
529
|
+
"""
|
530
|
+
조건에 맞는 단일 엔티티를 조회합니다.
|
531
|
+
|
532
|
+
Args:
|
533
|
+
session: SQLAlchemy AsyncSession
|
534
|
+
model: SQLAlchemy 모델
|
535
|
+
conditions: 조회 조건
|
536
|
+
explicit_joins: 명시적 조인 대상 리스트
|
537
|
+
- 모델만 전달: 기본 outer join
|
538
|
+
- (모델, 조인조건): 조건부 outer join
|
539
|
+
loading_joins: 로딩 조인 옵션 리스트 (joinedload, selectinload 등)
|
540
|
+
|
541
|
+
Returns:
|
542
|
+
ModelType: 조회된 엔티티 또는 None
|
543
|
+
"""
|
511
544
|
try:
|
545
|
+
# 기본 쿼리 생성
|
512
546
|
query = select(model)
|
513
547
|
|
514
548
|
# 명시적 조인 적용
|
515
549
|
if explicit_joins:
|
516
550
|
for join_target in explicit_joins:
|
517
|
-
|
551
|
+
if isinstance(join_target, tuple):
|
552
|
+
# (모델, 조인조건)이 전달된 경우
|
553
|
+
target_model, join_condition = join_target
|
554
|
+
query = query.outerjoin(target_model, join_condition)
|
555
|
+
else:
|
556
|
+
# 모델만 전달된 경우
|
557
|
+
query = query.outerjoin(join_target)
|
518
558
|
|
519
|
-
# 조인
|
559
|
+
# 로딩 조인 적용
|
520
560
|
if loading_joins:
|
521
561
|
for join_option in loading_joins:
|
522
562
|
query = query.options(join_option)
|
523
563
|
|
564
|
+
# 조건 적용
|
524
565
|
if conditions:
|
525
566
|
for key, value in conditions.items():
|
526
567
|
query = query.where(getattr(model, key) == value)
|
527
568
|
|
528
569
|
result = await session.execute(query)
|
529
|
-
return result.
|
570
|
+
return result.unique().scalars().one_or_none()
|
530
571
|
|
531
572
|
except SQLAlchemyError as e:
|
532
573
|
raise CustomException(
|
aiteamutils/version.py
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
"""버전 정보"""
|
2
|
-
__version__ = "0.2.
|
2
|
+
__version__ = "0.2.166"
|
@@ -4,13 +4,13 @@ aiteamutils/base_repository.py,sha256=Oy2zE1i5qx60Xf1tnsaKLyFWapiPqt5JH8NejwNrPW
|
|
4
4
|
aiteamutils/base_service.py,sha256=JIeRtFn1Ll4Qcq3v88pgS9lmEQLQoVyyOKqYR8n02S4,21192
|
5
5
|
aiteamutils/cache.py,sha256=07xBGlgAwOTAdY5mnMOQJ5EBxVwe8glVD7DkGEkxCtw,1373
|
6
6
|
aiteamutils/config.py,sha256=YdalpJb70-txhGJAS4aaKglEZAFVWgfzw5BXSWpkUz4,3232
|
7
|
-
aiteamutils/database.py,sha256=
|
7
|
+
aiteamutils/database.py,sha256=Kcp_NyXT2DassWovVFBmpFaqgCBzIpP4BRzRhsFKeMM,21892
|
8
8
|
aiteamutils/enums.py,sha256=7WLqlcJqQWtETAga2WAxNp3dJTQIAd2TW-4WzkoHHa8,2498
|
9
9
|
aiteamutils/exceptions.py,sha256=sgIVulllKMM9InTltaB7VD6i7DiQvCoycexsV-BiIBY,16570
|
10
10
|
aiteamutils/files.py,sha256=fxnCu9rErd4vCovMi0jy4adLUiA7rx_q4RdOL4wSgsU,14258
|
11
11
|
aiteamutils/security.py,sha256=McUl3t5Z5SyUDVUHymHdDkYyF4YSeg4g9fFMML4W6Kw,11630
|
12
12
|
aiteamutils/validators.py,sha256=_WHN6jqJQzKM5uPTg-Da8U2qqevS84XeKMkCCF4C_lY,9591
|
13
|
-
aiteamutils/version.py,sha256
|
14
|
-
aiteamutils-0.2.
|
15
|
-
aiteamutils-0.2.
|
16
|
-
aiteamutils-0.2.
|
13
|
+
aiteamutils/version.py,sha256=L8NwAUPTaxDs2LSIrJScDZnaZSAHV_U69VXVSwErXCA,43
|
14
|
+
aiteamutils-0.2.166.dist-info/METADATA,sha256=qy8U-j7_6Pagb_h71FasRTBQVXpzpPf2mHBUPde9q0Y,1743
|
15
|
+
aiteamutils-0.2.166.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
16
|
+
aiteamutils-0.2.166.dist-info/RECORD,,
|
File without changes
|