Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Application/Data/Sources/Common/DataLayerError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ public enum DataLayerError: Error {
case notAuthenticated
case failedToUnlinkLastProvider
case linkCredentialAlreadyInUse
case invalidDevelopmentGoalTitle
case developmentRecordDraftConflict
case invalidData(context: String)

private static let logger = Logger(category: "DataLayerError")
Expand Down
64 changes: 64 additions & 0 deletions Application/Data/Sources/DTO/DevelopmentGoalDTO.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//
// DevelopmentGoalDTO.swift
// Data
//
// Created by opfic on 8/28/26.
//

import Foundation

public struct DevelopmentGoalCreateRequest: Encodable {
public let title: String
public let markdownDescription: String

public init(title: String, markdownDescription: String) {
self.title = title
self.markdownDescription = markdownDescription
}
}

public struct DevelopmentGoalStatusRequest {
public let status: DevelopmentGoalStatus

public init(status: DevelopmentGoalStatus) {
self.status = status
}
}

public struct DevelopmentGoalResponse {
public let id: String
public let title: String
public let markdownDescription: String
public let status: DevelopmentGoalStatus
public let createdAt: Date
public let updatedAt: Date
public let completedAt: Date?

public init(
id: String,
title: String,
markdownDescription: String,
status: DevelopmentGoalStatus,
createdAt: Date,
updatedAt: Date,
completedAt: Date?
) {
self.id = id
self.title = title
self.markdownDescription = markdownDescription
self.status = status
self.createdAt = createdAt
self.updatedAt = updatedAt
self.completedAt = completedAt
}
}

public struct DevelopmentGoalCompletionResponse {
public let goal: DevelopmentGoalResponse
public let records: [DevelopmentRecordResponse]

public init(goal: DevelopmentGoalResponse, records: [DevelopmentRecordResponse]) {
self.goal = goal
self.records = records
}
}
140 changes: 140 additions & 0 deletions Application/Data/Sources/DTO/DevelopmentRecordDTO.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
//
// DevelopmentRecordDTO.swift
// Data
//
// Created by opfic on 8/28/26.
//

import Foundation

public struct DevelopmentRecordDraftRequest: Encodable {
public let title: String
public let markdownContent: String
public let baseVersionId: String?

public init(
title: String,
markdownContent: String,
baseVersionId: String?
) {
self.title = title
self.markdownContent = markdownContent
self.baseVersionId = baseVersionId
}
}

public struct DevelopmentRecordCreateRequest: Encodable {
public let draft: DevelopmentRecordDraftRequest

public init(draft: DevelopmentRecordDraftRequest) {
self.draft = draft
}
}

public struct DevelopmentRecordConfirmationRequest {
public let versionId: String
public let kind: String
public let sourceVersionId: String?

public init(
versionId: String,
kind: String,
sourceVersionId: String?
) {
self.versionId = versionId
self.kind = kind
self.sourceVersionId = sourceVersionId
}
}

public struct DevelopmentRecordRestoreRequest {
public let versionId: String
public let sourceVersionId: String

public init(versionId: String, sourceVersionId: String) {
self.versionId = versionId
self.sourceVersionId = sourceVersionId
}
}

public struct DevelopmentRecordDraftResponse {
public let title: String
public let markdownContent: String
public let baseVersionId: String?
public let updatedAt: Date

public init(
title: String,
markdownContent: String,
baseVersionId: String?,
updatedAt: Date
) {
self.title = title
self.markdownContent = markdownContent
self.baseVersionId = baseVersionId
self.updatedAt = updatedAt
}
}

public struct DevelopmentRecordCurrentVersionResponse {
public let id: String
public let number: Int

public init(id: String, number: Int) {
self.id = id
self.number = number
}
}

public struct DevelopmentRecordResponse {
public let id: String
public let goalId: String
public let currentVersion: DevelopmentRecordCurrentVersionResponse?
public let draft: DevelopmentRecordDraftResponse?
public let createdAt: Date

public init(
id: String,
goalId: String,
currentVersion: DevelopmentRecordCurrentVersionResponse?,
draft: DevelopmentRecordDraftResponse?,
createdAt: Date
) {
self.id = id
self.goalId = goalId
self.currentVersion = currentVersion
self.draft = draft
self.createdAt = createdAt
}
}

public struct DevelopmentRecordVersionResponse {
public let id: String
public let recordId: String
public let number: Int
public let title: String
public let markdownContent: String
public let kind: String
public let sourceVersionId: String?
public let confirmedAt: Date

public init(
id: String,
recordId: String,
number: Int,
title: String,
markdownContent: String,
kind: String,
sourceVersionId: String?,
confirmedAt: Date
) {
self.id = id
self.recordId = recordId
self.number = number
self.title = title
self.markdownContent = markdownContent
self.kind = kind
self.sourceVersionId = sourceVersionId
self.confirmedAt = confirmedAt
}
}
10 changes: 8 additions & 2 deletions Application/Data/Sources/DTO/TodoDTO.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Foundation

public struct TodoRequest: Encodable {
public let id: String
public let goalId: String?
public let isPinned: Bool
public let isCompleted: Bool
public let isChecked: Bool
Expand All @@ -35,9 +36,11 @@ public struct TodoRequest: Encodable {
deletedAt: Date?,
dueDate: Date?,
tags: [String],
category: String
category: String,
goalId: String? = nil
) {
self.id = id
self.goalId = goalId
self.isPinned = isPinned
self.isCompleted = isCompleted
self.isChecked = isChecked
Expand All @@ -55,6 +58,7 @@ public struct TodoRequest: Encodable {

public struct TodoResponse {
public let id: String
public let goalId: String?
public let isPinned: Bool
public let isCompleted: Bool
public let isChecked: Bool
Expand Down Expand Up @@ -83,9 +87,11 @@ public struct TodoResponse {
deletedAt: Date?,
dueDate: Date?,
tags: [String],
category: TodoCategoryResponse
category: TodoCategoryResponse,
goalId: String? = nil
) {
self.id = id
self.goalId = goalId
self.isPinned = isPinned
self.isCompleted = isCompleted
self.isChecked = isChecked
Expand Down
17 changes: 15 additions & 2 deletions Application/Data/Sources/DataAssembler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,22 @@ public final class DataAssembler: Assembler {
TodoMutationEventBusImpl()
}

container.register(DevelopmentGoalRepository.self) {
DevelopmentGoalRepositoryImpl(
service: container.resolve(DevelopmentGoalService.self)
Comment thread
opficdev marked this conversation as resolved.
)
}

container.register(DevelopmentRecordRepository.self) {
DevelopmentRecordRepositoryImpl(
service: container.resolve(DevelopmentRecordService.self)
)
}

container.register(TodoRepository.self) {
TodoRepositoryImpl(
todoService: container.resolve(TodoService.self),
queryService: container.resolve(TodoQueryService.self),
commandService: container.resolve(TodoCommandService.self),
todoCategoryService: container.resolve(TodoCategoryService.self),
store: container.resolve(MemoryCacheStore.self),
updater: container.resolve(WidgetSnapshotUpdater.self),
Expand All @@ -47,7 +60,7 @@ public final class DataAssembler: Assembler {
}

container.register(WidgetTodoSnapshotRepository.self) {
WidgetTodoSnapshotRepositoryImpl(todoService: container.resolve(TodoService.self))
WidgetTodoSnapshotRepositoryImpl(queryService: container.resolve(TodoQueryService.self))
}

container.register(TodoCategoryRepository.self) {
Expand Down
62 changes: 62 additions & 0 deletions Application/Data/Sources/Mapper/DevelopmentGoalMapping.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//
// DevelopmentGoalMapping.swift
// Data
//
// Created by opfic on 8/28/26.
//

import Domain

public extension DevelopmentGoalQuery {
static func fromDomain(_ query: DevelopmentGoal.Query) -> Self {
Self(status: query.status.map(DevelopmentGoalStatus.fromDomain))
}
}

public extension DevelopmentGoalResponse {
func toDomain() throws -> DevelopmentGoal {
try DevelopmentGoal(
id: id,
title: title,
description: markdownDescription,
status: status.toDomain(),
createdAt: createdAt,
updatedAt: updatedAt,
completedAt: completedAt
)
}
}

public extension DevelopmentGoalCompletionResponse {
func toDomain() throws -> DevelopmentGoal.CompletionSnapshot {
try DevelopmentGoal.CompletionSnapshot(
goal: goal.toDomain(),
records: records.map { try $0.toDomain() }
)
}
}

public extension DevelopmentGoalStatus {
static func fromDomain(_ status: DevelopmentGoal.Status) -> Self {
switch status {
case .inProgress:
.inProgress
case .completed:
.completed
case .archived:
.archived
}
}

func toDomain() -> DevelopmentGoal.Status {
switch self {
case .inProgress:
.inProgress
case .completed:
.completed
case .archived:
.archived
}
}

}
Loading
Loading