GitSpacer / GitSpace

🌌 GitSpace
MIT License
7 stars 0 forks source link

[Feat] Firestore Service 인터페이스를 구현했습니다. #30

Open wontaeyoung opened 6 months ago

wontaeyoung commented 6 months ago

개요

메인 데이터소스인 Firestore를 조작할 수 있는 추상화 기능을 제공하는 Firestore Service 구현했습니다.



공유사항

이전 회의에서 라이브로 공유드린 문서 디코딩 시 런타임 에러가 발생하는 이슈가 Firebase 패키지 버전 업데이트 후 해결된 부분을 확인했습니다.

21 브랜치에서 Firebase 패키지 버전을 업데이트했습니다.



✏️ 작업 사항



사용법

더미 데이터

let chat: Chat = .dummy
let message: Message = .dummy    



문서 생성

/// 지정된 컬렉션에 모델을 생성합니다.
/// - Parameters:
///   - in collection: 모델을 생성할 컬렉션입니다.
///   - with model: 저장할 모델의 인스턴스입니다.
func create<T: GSModel>(
    in collection: FirestoreCollection,
    with model: T
) throws

try service.create(in: .chat, with: chat)

/// 지정된 컬렉션에 모델을 생성합니다.
/// - Parameters:
///   - superCol superCollection: 상위 컬렉션입니다.
///   - superDoc superDocumentID: 상위 문서의 ID입니다.
///   - in collection: 모델을 생성할 컬렉션입니다.
///   - with model: 저장할 모델의 인스턴스입니다.
func create<T: GSModel>(
    superCol superCollection: FirestoreCollection,
    superDoc superDocumentID: String,
    in collection: FirestoreCollection,
    with model: T
) throws

try service.create(
  superCol: .chat,
  superDoc: chat.id,
  in: .message,
  with: message
)



문서 조회

/// 지정된 컬렉션의 모든 문서를 조회합니다.
/// - Parameters:
///   - from collection: 조회할 컬렉션입니다.
/// - Returns: 해당 컬렉션의 모든 모델을 포함하는 배열을 반환합니다.
func fetch<T: GSModel>(
    from collection: FirestoreCollection
) async throws -> [T]

let fetchedChats: [Chat] = try await service.fetch(from: .chat)

/// 지정된 컬렉션과 문서 ID를 사용하여 모델을 조회합니다.
/// - Parameters:
///   - from collection: 조회할 컬렉션입니다.
///   - at documentID: 조회할 문서의 ID입니다.
/// - Returns: 지정된 타입의 모델을 반환합니다.
func fetch<T: GSModel>(
    from collection: FirestoreCollection,
    at documentID: String
) async throws -> T

let fetchedChat: Chat = try await service.fetch(
    from: .chat, 
    at: chat.id
)

/// 지정된 컬렉션의 모든 문서를 조회합니다.
/// - Parameters:
///   - superCol superCollection: 상위 컬렉션입니다.
///   - superDoc superDocumentID: 상위 문서의 ID입니다.
///   - from collection: 조회할 컬렉션입니다.
/// - Returns: 해당 컬렉션의 모든 모델을 포함하는 배열을 반환합니다.
func fetch<T: GSModel>(
    superCol superCollection: FirestoreCollection,
    superDoc superDocumentID: String,
    from collection: FirestoreCollection
) async throws -> [T]

let fetchedMessages: [Message] = try await service.fetch(
  superCol: .chat, 
  superDoc: chat.id,
  from: .knock
)

/// 지정된 컬렉션과 문서 ID를 사용하여 모델을 조회합니다.
/// - Parameters:
///   - superCol superCollection: 상위 컬렉션입니다.
///   - superDoc superDocumentID: 상위 문서의 ID입니다.
///   - from collection: 조회할 컬렉션입니다.
///   - at documentID: 조회할 문서의 ID입니다.
/// - Returns: 지정된 타입의 모델을 반환합니다.
func fetch<T: GSModel>(
    superCol superCollection: FirestoreCollection,
    superDoc superDocumentID: String,
    from collection: FirestoreCollection,
    at documentID: String
) async throws -> T

let fetchedMessage: Message = try await service.fetch(
  superCol: .chat,
  superDoc: chat.id,
  from: .message,
  at: message.id
)

/// 지정된 컬렉션에서 특정 조건을 만족하는 모든 문서를 조회합니다.
/// - 단일 쿼리일 때 사용합니다. 복합 쿼리를 사용하시려면 getCollectionPath로 컬렉션 경로를 설정하고, .query 체이닝으로 원하는 조건을 설정한 뒤 .fetch를 호출해주세요.
/// - Parameters:
///   - from colRef: 조회할 컬렉션입니다.
///   - where field: 조건을 적용할 필드입니다.
///   - by query: 조건으로 적용할 쿼리 연산자입니다.
/// - Returns: 조건을 만족하는 모든 모델을 포함하는 배열을 반환합니다.
func fetch<T: GSModel>(
    from collection: FirestoreCollection,
    where field: any FirestoreFieldProtocol,
    by query: FirestoreQueryOperation
) async throws -> [T]

let fetchQueryChats: [Chat] = try await service.fetch(
  from: .chat,
  where: FirestoreField.Chat.createdDate,
  by: .orderBy(type: .descending)
)

/// 지정된 컬렉션에서 특정 조건을 만족하는 모든 문서를 조회합니다.
/// - 단일 쿼리일 때 사용합니다. 복합 쿼리를 사용하시려면 getCollectionPath로 컬렉션 경로를 설정하고, .query 체이닝으로 원하는 조건을 설정한 뒤 .fetch를 호출해주세요.
/// - Parameters:
///   - superCol superCollection: 상위 컬렉션입니다.
///   - superDoc superDocumentID: 상위 문서의 ID입니다.
///   - from colRef: 조회할 컬렉션입니다.
///   - where field: 조건을 적용할 필드입니다.
///   - by query: 조건으로 적용할 쿼리 연산자입니다.
/// - Returns: 조건을 만족하는 모든 모델을 포함하는 배열을 반환합니다.
func fetch<T: GSModel>(
    superCol superCollection: FirestoreCollection,
    superDoc superDocumentID: String,
    from collection: FirestoreCollection,
    where field: any FirestoreFieldProtocol,
    by query: FirestoreQueryOperation
) async throws -> [T]

let fetchQueryMessages: [Message] = try await service.fetch(
  superCol: .chat,
  superDoc: chat.id,
  from: .message,
  where: FirestoreField.Message.isRead,
  by: .equalTo(value: true)
)


복합 쿼리 조회

문서 조회 코드에 명시된 fetchQuery는 단일 쿼리만 가능합니다.

복합 쿼리가 필요한 경우에는 getCollectionPath으로 경로를 가져오고, 체이닝 방식으로 필요한 쿼리를 적용한 뒤 fetch로 조회할 수 있습니다.

let fetchMultiQueryChats: [Chat] = try await service
  .getCollectionPath(from: .chat)
  .query(field: FirestoreField.Chat.createdDate, operation: .orderBy(type: .ascending))
  .query(field: FirestoreField.Chat.knockContentDate, operation: .lessThan(value: Date.now))
  .query(field: FirestoreField.Chat.knockContent, operation: .in(values: ["하이", "반갑습니다"]))
  .fetch()



문서 업데이트

try service.update( in: .chat, at: chat, updating: [FirestoreField.Chat.joinedMemberIDs, .createdDate, .lastContent, .unreadMessageCount] )

/// 지정된 컬렉션의 모델을 업데이트합니다. 모델의 ID를 사용해서 문서를 조회합니다. /// - Parameters: /// - superCol superCollection: 상위 컬렉션입니다. /// - superDoc superDocumentID: 상위 문서의 ID입니다. /// - in collection: 업데이트 모델이 위치한 컬렉션입니다. /// - at model: 업데이트할 모델입니다. /// - updating fields: 업데이트할 필드 리스트입니다. func update<T: GSModel, U: FirestoreFieldProtocol>( superCol superCollection: FirestoreCollection, superDoc superDocumentID: String, in collection: FirestoreCollection, at model: T, updating fields: [U] ) throws

try service.update( superCol: .chat, superDoc: chat.id, in: .message, at: message, updating: [FirestoreField.Message.imageContent, .isRead, .sentDate] )


<br><br>

### 문서 삭제

```swift
/// 지정된 컬렉션의 문서를 찾아서 삭제합니다.
/// - Parameters:
///   - in collection: 삭제할 컬렉션입니다.
///   - at documentID: 삭제할 문서의 ID입니다.
func delete(
    in collection: FirestoreCollection,
    at documentID: String
)

service.delete(in: .chat, at: chat.id)

/// 지정된 컬렉션의 문서를 찾아서 삭제합니다.
/// - Parameters:
///   - superCol superCollection: 상위 컬렉션입니다.
///   - superDoc superDocumentID: 상위 문서의 ID입니다.
///   - in collection: 삭제할 컬렉션입니다.
///   - at documentID: 삭제할 문서의 ID입니다.
func delete(
    superCol superCollection: FirestoreCollection,
    superDoc superDocumentID: String,
    in collection: FirestoreCollection,
    at documentID: String
)

service.delete(
  superCol: .chat,
  superDoc: chat.id,
  in: .message,
  at: message.id
)