Skip to content
Snippets Groups Projects
ProcessBannedList.swift 1.7 KiB
Newer Older
import Foundation
import SwiftCSV
import XCTestDynamicOverlay

public struct ProcessBannedList {
    public enum ElementError: Swift.Error {
        case missingUserId
        case invalidUserId(String)
    }

    public enum Error: Swift.Error {
        case invalidData
        case csv(Swift.Error)
    }

    public typealias ForEach = (Result<Data, ElementError>) -> Void
    public typealias Completion = (Result<Void, Error>) -> Void

    public var run: (Data, ForEach, Completion) -> Void

    public func callAsFunction(
        data: Data,
        forEach: ForEach,
        completion: Completion
    ) {
        run(data, forEach, completion)
    }
}

extension ProcessBannedList {
    public static let live = ProcessBannedList { data, forEach, completion in
        guard let csvString = String(data: data, encoding: .utf8) else {
            completion(.failure(.invalidData))
            return
        }
        let csv: EnumeratedCSV
        do {
            csv = try EnumeratedCSV(string: csvString)
        }
        catch {
            completion(.failure(.csv(error)))
            return
        }
        csv.rows.forEach { row in
            guard let userIdString = row.first else {
                forEach(.failure(.missingUserId))
                return
            }
            guard let userId = Data(base64Encoded: userIdString) else {
                forEach(.failure(.invalidUserId(userIdString)))
                return
            }
            forEach(.success(userId))
        }
        completion(.success(()))
    }
}

extension ProcessBannedList {
    public static let unimplemented = ProcessBannedList { _, _, _ in
        let run: () -> Void = XCTUnimplemented("\(Self.self)")
        run()
    }
}