ContactMerge.swift 65 lignes · 2464 octets
import Foundation

struct MergeFieldChoices: Equatable {
    var fullNameFromId: Int64
    var firstNameFromId: Int64
    var lastNameFromId: Int64
    var companyFromId: Int64
    var jobTitleFromId: Int64
    var websiteFromId: Int64
    var addressFromId: Int64
    var notesMode: NotesMode
    var cardImageFromId: Int64?
    var profileImageFromId: Int64?
    var keepId: Int64
}

enum NotesMode {
    case keepPrimary
    case concat
}

enum ContactMerge {
    /// Kotlin took a `Map<Long, CrmContactEntity>` (insertion-ordered `LinkedHashMap`);
    /// Swift dictionaries are unordered, so the ordered source list is passed instead
    /// and the id lookup is built internally. Union order follows the list order.
    static func merge(
        sources: [CrmContactEntity],
        choices: MergeFieldChoices,
        now: Int64 = Int64(Date().timeIntervalSince1970 * 1000)
    ) -> CrmContactEntity {
        let byId = Dictionary(uniqueKeysWithValues: sources.map { ($0.id, $0) })
        func scalar(_ picker: Int64, _ sel: (CrmContactEntity) -> String?) -> String? {
            sel(byId[picker]!)
        }
        let keep = byId[choices.keepId]!
        let phones = sources.flatMap { $0.phones }.distinctPreservingOrder()
        let emails = sources.flatMap { $0.emails }.distinctPreservingOrder()
        let notes: String?
        switch choices.notesMode {
        case .keepPrimary:
            notes = keep.notes
        case .concat:
            notes = sources
                .compactMap { $0.notes?.nilIfBlank }
                .distinctPreservingOrder()
                .joined(separator: "\n---\n")
                .nilIfBlank
        }
        var merged = keep
        merged.fullName = scalar(choices.fullNameFromId) { $0.fullName }
        merged.firstName = scalar(choices.firstNameFromId) { $0.firstName }
        merged.lastName = scalar(choices.lastNameFromId) { $0.lastName }
        merged.company = scalar(choices.companyFromId) { $0.company }
        merged.jobTitle = scalar(choices.jobTitleFromId) { $0.jobTitle }
        merged.website = scalar(choices.websiteFromId) { $0.website }
        merged.address = scalar(choices.addressFromId) { $0.address }
        merged.notes = notes
        merged.phones = phones
        merged.emails = emails
        merged.phonesText = phones.joined(separator: " ")
        merged.emailsText = emails.joined(separator: " ")
        merged.updatedAt = now
        return merged
    }
}