Coverage Summary for Class: WorkspaceInviteSyncPlugin (com.georgeci.moneysurfer.data.sync.plugin)

Class Method, % Branch, % Line, % Instruction, %
WorkspaceInviteSyncPlugin 100% (3/3) 83.3% (5/6) 100% (28/28) 99.2% (258/260)
WorkspaceInviteSyncPlugin$applyDoc$1
WorkspaceInviteSyncPlugin$push$2 100% (1/1) 50% (3/6) 100% (10/10) 100% (90/90)
Total 100% (4/4) 66.7% (8/12) 100% (38/38) 99.4% (348/350)


 package com.georgeci.moneysurfer.data.sync.plugin
 import co.touchlab.kermit.Logger
 import com.georgeci.moneysurfer.data.db.dao.WorkspaceInviteDao
 import com.georgeci.moneysurfer.data.remote.WorkspaceInviteDoc
 import com.georgeci.moneysurfer.data.sync.WorkspaceDocumentWriter
 import com.georgeci.moneysurfer.data.sync.toDoc
 import com.georgeci.moneysurfer.data.sync.toEntity
 import com.georgeci.moneysurfer.domain.AppInfo
 import com.georgeci.moneysurfer.domain.logging.redactEmail
 import com.georgeci.moneysurfer.domain.logging.redactUid
 import com.georgeci.moneysurfer.domain.sync.SyncEntityTypes
 import com.georgeci.moneysurfer.sync.api.SyncCollection
 import com.georgeci.moneysurfer.sync.plugin.EntityApplyResult
 import com.georgeci.moneysurfer.sync.plugin.RemoteDocument
 import com.georgeci.moneysurfer.sync.plugin.SyncEntityPlugin
 import com.georgeci.moneysurfer.sync.repository.ConflictMetadata
 import com.georgeci.moneysurfer.sync.repository.ConflictResolver
 import com.georgeci.moneysurfer.sync.repository.PendingMutation
 import org.koin.core.annotation.Single
 import kotlin.time.Instant
 
 @Single(binds = [SyncEntityPlugin::class])
 class WorkspaceInviteSyncPlugin(
     private val writer: WorkspaceDocumentWriter,
     private val appInfo: AppInfo,
     private val conflictResolver: ConflictResolver,
     private val workspaceInviteDao: WorkspaceInviteDao,
 ) : SyncEntityPlugin {
 
     override val entityType: String = SyncEntityTypes.WORKSPACE_INVITE
     override val firestoreCollectionName: String = SyncCollection.WORKSPACE_INVITES
     override val pullPriority: Int = SyncPullPriorities.INVITES
 
     private val log = Logger.withTag("WorkspaceInvitePlugin")
 
     override suspend fun push(mutation: PendingMutation) = writer.pushToCollection(
         mutation = mutation,
         collectionName = SyncCollection.WORKSPACE_INVITES,
         clientVersionCode = appInfo.versionCode,
         strategy = WorkspaceInviteDoc.serializer(),
     ) { ref ->
         workspaceInviteDao.getById(mutation.entityId)
             ?.toDoc()
             ?.copy(clientVersionCode = appInfo.versionCode)
             ?.also { dto ->
                 log.i {
                     "[push:invite] path=${ref.path} email=${dto.email.redactEmail()} " +
                         "status=${dto.status} role=${dto.role} " +
                         "target=${dto.targetUserId.redactUid()} invitedBy=${dto.invitedByUserId.redactUid()} " +
                         "expiresAt=${dto.expiresAt} updatedAt=${dto.updatedAt} ver=${dto.clientVersionCode}"
                 }
             }
     }
 
     override suspend fun applyDoc(doc: RemoteDocument, scopeKey: String): EntityApplyResult {
         val dto = doc.decodeOrNull(WorkspaceInviteDoc.serializer()) ?: return SKIPPED_APPLY_RESULT
         if (dto.deletedAt != null) {
             workspaceInviteDao.delete(doc.id)
             return EntityApplyResult(applied = true, wasConflict = false)
         }
         val local = workspaceInviteDao.getById(doc.id)
         val resolution = conflictResolver.resolve(
             local = local,
             remote = dto.toEntity(id = doc.id, workspaceId = scopeKey),
             metadata = ConflictMetadata(
                 entityType = SyncEntityTypes.WORKSPACE_INVITE,
                 entityId = doc.id,
                 localUpdatedAt = local?.updatedAt?.let(Instant::fromEpochMilliseconds),
                 remoteUpdatedAt = Instant.fromEpochMilliseconds(dto.updatedAt),
             ),
         )
         return applyResolution(resolution) { workspaceInviteDao.upsert(it) }
     }
 }