aiteamutils 0.2.164__py3-none-any.whl → 0.2.165__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[Any]] = None,
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
- filters = {
446
- "search": {"field": "username", "operator": "like", "value": "%admin%"},
447
- "name": {"field": "name", "operator": "like", "value": "%John%"},
448
- "role_ulid": {"field": "role_ulid", "operator": "eq", "value": "1234"}
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
+ # 명시적 조인 적용
463
465
  if explicit_joins:
464
- query = select(model, *explicit_joins)
465
466
  for join_target in explicit_joins:
466
- query = query.outerjoin(join_target)
467
- else:
468
- query = select(model)
467
+ if isinstance(join_target, tuple):
468
+ # (모델, 조인조건)이 전달된 경우
469
+ target_model, join_condition = join_target
470
+ query = query.outerjoin(target_model, join_condition)
471
+ else:
472
+ # 모델만 전달된 경우
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:
@@ -505,28 +515,51 @@ async def get_entity(
505
515
  session: AsyncSession,
506
516
  model: Type[ModelType],
507
517
  conditions: Dict[str, Any],
508
- explicit_joins: Optional[List[Any]] = None,
518
+ explicit_joins: Optional[List[JoinTarget]] = None,
509
519
  loading_joins: Optional[List[Any]] = None
510
520
  ) -> ModelType:
521
+ """
522
+ 조건에 맞는 단일 엔티티를 조회합니다.
523
+
524
+ Args:
525
+ session: SQLAlchemy AsyncSession
526
+ model: SQLAlchemy 모델
527
+ conditions: 조회 조건
528
+ explicit_joins: 명시적 조인 대상 리스트
529
+ - 모델만 전달: 기본 outer join
530
+ - (모델, 조인조건): 조건부 outer join
531
+ loading_joins: 로딩 조인 옵션 리스트 (joinedload, selectinload 등)
532
+
533
+ Returns:
534
+ ModelType: 조회된 엔티티 또는 None
535
+ """
511
536
  try:
537
+ # 기본 쿼리 생성
512
538
  query = select(model)
513
539
 
514
540
  # 명시적 조인 적용
515
541
  if explicit_joins:
516
542
  for join_target in explicit_joins:
517
- query = query.outerjoin(join_target)
543
+ if isinstance(join_target, tuple):
544
+ # (모델, 조인조건)이 전달된 경우
545
+ target_model, join_condition = join_target
546
+ query = query.outerjoin(target_model, join_condition)
547
+ else:
548
+ # 모델만 전달된 경우
549
+ query = query.outerjoin(join_target)
518
550
 
519
- # 조인 로딩 적용
551
+ # 로딩 조인 적용
520
552
  if loading_joins:
521
553
  for join_option in loading_joins:
522
554
  query = query.options(join_option)
523
555
 
556
+ # 조건 적용
524
557
  if conditions:
525
558
  for key, value in conditions.items():
526
559
  query = query.where(getattr(model, key) == value)
527
560
 
528
561
  result = await session.execute(query)
529
- return result.scalars().unique().one_or_none()
562
+ return result.unique().scalars().one_or_none()
530
563
 
531
564
  except SQLAlchemyError as e:
532
565
  raise CustomException(
aiteamutils/version.py CHANGED
@@ -1,2 +1,2 @@
1
1
  """버전 정보"""
2
- __version__ = "0.2.164"
2
+ __version__ = "0.2.165"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aiteamutils
3
- Version: 0.2.164
3
+ Version: 0.2.165
4
4
  Summary: AI Team Utilities
5
5
  Project-URL: Homepage, https://github.com/yourusername/aiteamutils
6
6
  Project-URL: Issues, https://github.com/yourusername/aiteamutils/issues
@@ -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=msvBKtxWeQVOo0v2Q9i2azuTNtnUItuNNar52gdRZTo,20418
7
+ aiteamutils/database.py,sha256=090b9M3o3nYsckVlfybC5LV7wUXS6n0Pve2yDOF_Y48,21669
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=-1PoiD8Z2iKKFhSAXH5iLm2cqOxR9FYl9lzaqFbsdAA,43
14
- aiteamutils-0.2.164.dist-info/METADATA,sha256=ex8xQEve_D8XGz7Kqk4yhcazmGqE8fxYzKqOVkbBp5E,1743
15
- aiteamutils-0.2.164.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
16
- aiteamutils-0.2.164.dist-info/RECORD,,
13
+ aiteamutils/version.py,sha256=TC_spO53XsoBjGPdVSQjcP1vTh3Fno23EerP6g6nB58,43
14
+ aiteamutils-0.2.165.dist-info/METADATA,sha256=lRRin2H5r_RB8ha8ciB7hZo4fl-2M1C-L-c9V7SwOXA,1743
15
+ aiteamutils-0.2.165.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
16
+ aiteamutils-0.2.165.dist-info/RECORD,,