Todo repository protocol (#8)
This PR contains the work done to decouple the direct use of the `ModelContext` from `SwiftData` from the view model that uses it. In addition, the project transitioned to use Swift 6 and strict concurrency which brought some issues with the unit tests, so they were amended as well. Reviewed-on: rock-n-code/todos-app#8 Co-authored-by: Javier Cicchelli <javier@rock-n-code.com> Co-committed-by: Javier Cicchelli <javier@rock-n-code.com>
This commit was merged in pull request #8.
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
import SwiftData
|
||||
|
||||
/// Extends ModelContext to conform to the TodoRepository protocol.
|
||||
///
|
||||
/// This extension allows ModelContext from SwiftData to be used as a todo repository,
|
||||
/// enabling dependency injection and facilitating unit testing by allowing mock
|
||||
/// repositories to be substituted during tests.
|
||||
///
|
||||
/// The ModelContext methods `delete(_:)` and `insert(_:)` already match the
|
||||
/// TodoRepository protocol requirements, so this extension simply declares conformance
|
||||
/// without requiring additional implementation.
|
||||
extension ModelContext: TodoRepository {}
|
||||
@@ -0,0 +1,28 @@
|
||||
import SwiftData
|
||||
|
||||
/// A protocol defining the interface for a todo repository.
|
||||
///
|
||||
/// This protocol abstracts the underlying data persistence mechanism for todo tasks,
|
||||
/// allowing for dependency injection and easier testing. Implementations handle the
|
||||
/// storage and retrieval of Todo objects.
|
||||
protocol TodoRepository {
|
||||
|
||||
/// Deletes a todo task from the repository.
|
||||
///
|
||||
/// This method removes the specified todo from persistent storage. The deletion
|
||||
/// is typically performed immediately, though the actual persistence may be deferred
|
||||
/// until a save operation occurs depending on the implementation.
|
||||
///
|
||||
/// - Parameter todo: The todo task to delete from the repository.
|
||||
func delete(_ todo: Todo)
|
||||
|
||||
/// Inserts a new todo task into the repository.
|
||||
///
|
||||
/// This method adds a new todo to persistent storage. The todo is typically
|
||||
/// tracked immediately, though the actual persistence may be deferred until a
|
||||
/// save operation occurs depending on the implementation.
|
||||
///
|
||||
/// - Parameter todo: The todo task to insert into the repository.
|
||||
func insert(_ todo: Todo)
|
||||
|
||||
}
|
||||
@@ -57,14 +57,14 @@ extension NewTaskView {
|
||||
|
||||
// MARK: Functions
|
||||
|
||||
/// Saves a new todo task to the SwiftData model context.
|
||||
/// Saves a new todo task to the repository.
|
||||
///
|
||||
/// This function creates a new `Todo` instance with the current property values and inserts it into the provided model context.
|
||||
/// This function creates a new `Todo` instance with the current property values and inserts it into the provided repository.
|
||||
/// The title and note are trimmed of leading and trailing whitespace before saving.
|
||||
/// The `note` property value is only included if it's not empty after trimming.
|
||||
///
|
||||
/// - Parameter modelContext: The SwiftData model context to insert a new todo task.
|
||||
func save(to modelContext: ModelContext) {
|
||||
/// - Parameter repository: The repository to insert a new todo task.
|
||||
func save(to repository: TodoRepository) {
|
||||
let trimmedTitle = title.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
let trimmedNote = note.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
|
||||
@@ -74,7 +74,7 @@ extension NewTaskView {
|
||||
due: due
|
||||
)
|
||||
|
||||
modelContext.insert(todo)
|
||||
repository.insert(todo)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -87,21 +87,21 @@ extension TaskListView {
|
||||
|
||||
/// Deletes tasks at the specified indices.
|
||||
///
|
||||
/// This method removes tasks from the model context after a swipe-to-delete action.
|
||||
/// The deletion is performed through SwiftData's model context, which handles
|
||||
/// This method removes tasks from the repository after a swipe-to-delete action.
|
||||
/// The deletion is performed through the repository, which handles
|
||||
/// persistence and triggers automatic UI updates.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - tasks: The current array of tasks.
|
||||
/// - offsets: The index set of tasks to delete.
|
||||
/// - modelContext: The SwiftData model context to perform the deletion.
|
||||
func deleteTasks(
|
||||
/// - repository: The repository to perform the deletion.
|
||||
func delete(
|
||||
_ tasks: [Todo],
|
||||
at offsets: IndexSet,
|
||||
from modelContext: ModelContext
|
||||
from repository: TodoRepository
|
||||
) {
|
||||
for index in offsets {
|
||||
modelContext.delete(tasks[index])
|
||||
repository.delete(tasks[index])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ struct TaskListView: View {
|
||||
group: viewModel.group,
|
||||
showCompleted: viewModel.showCompleted
|
||||
) { tasks, offsets in
|
||||
viewModel.deleteTasks(
|
||||
viewModel.delete(
|
||||
tasks,
|
||||
at: offsets,
|
||||
from: modelContext
|
||||
|
||||
Reference in New Issue
Block a user