diff options
| author | Christian Cleberg <[email protected]> | 2026-03-17 23:19:43 -0500 |
|---|---|---|
| committer | Christian Cleberg <[email protected]> | 2026-03-17 23:19:43 -0500 |
| commit | 32ad6cab8d58d99ebd8a28e8fa6e6f4e587cb1e5 (patch) | |
| tree | ee36d421d704e508d5617d803b4c8cbdb4804fe1 /Hutch/Views/Repositories/CommitDetailViewModel.swift | |
| parent | 8f2057c53e9009c2529c9c4849c914666c0e4b40 (diff) | |
| download | hutch-32ad6cab8d58d99ebd8a28e8fa6e6f4e587cb1e5.tar.gz hutch-32ad6cab8d58d99ebd8a28e8fa6e6f4e587cb1e5.tar.bz2 hutch-32ad6cab8d58d99ebd8a28e8fa6e6f4e587cb1e5.zip | |
v1.0
Diffstat (limited to 'Hutch/Views/Repositories/CommitDetailViewModel.swift')
| -rw-r--r-- | Hutch/Views/Repositories/CommitDetailViewModel.swift | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/Hutch/Views/Repositories/CommitDetailViewModel.swift b/Hutch/Views/Repositories/CommitDetailViewModel.swift new file mode 100644 index 0000000..5a8a23d --- /dev/null +++ b/Hutch/Views/Repositories/CommitDetailViewModel.swift @@ -0,0 +1,102 @@ +import Foundation + +// MARK: - Response types (file-private to avoid @MainActor Decodable issues) + +private struct CommitResponse: Decodable, Sendable { + let repository: CommitRepository? +} + +private struct CommitRepository: Decodable, Sendable { + // swiftlint:disable:next identifier_name + let revparse_single: CommitDetail +} + +// MARK: - View Model + +@Observable +@MainActor +final class CommitDetailViewModel { + + let repositoryRid: String + let service: SRHTService + private let client: SRHTClient + + private(set) var commit: CommitDetail? + private(set) var isLoading = false + var error: String? + + init(repositoryRid: String, service: SRHTService, commitId: String, client: SRHTClient) { + self.repositoryRid = repositoryRid + self.service = service + self.commitId = commitId + self.client = client + } + + private let commitId: String + + // MARK: - Query + + private static let query = """ + query commit($rid: ID!, $id: String!) { + repository(rid: $rid) { + revparse_single(revspec: $id) { + id + shortId + author { name email time } + committer { name email time } + message + diff + trailers { name value } + parents { id shortId author { name } } + tree { + entries { + results { id name mode object { type id shortId } } + cursor + } + } + } + } + } + """ + + func loadCommit() async { + guard !isLoading else { return } + isLoading = true + error = nil + + do { + let result = try await executeWithRetry() + commit = result.repository?.revparse_single + } catch { + self.error = error.localizedDescription + } + + isLoading = false + } + + /// Execute the commit query, retrying once after a 1-second delay on 502/503. + private func executeWithRetry() async throws -> CommitResponse { + do { + return try await client.execute( + service: service, + query: Self.query, + variables: [ + "rid": repositoryRid, + "id": commitId + ], + responseType: CommitResponse.self + ) + } catch let SRHTError.httpError(code) where code == 502 || code == 503 { + try await Task.sleep(for: .seconds(1)) + return try await client.execute( + service: service, + query: Self.query, + variables: [ + "rid": repositoryRid, + "id": commitId + ], + responseType: CommitResponse.self + ) + } + } +} |
