Browse Source

refactor: extract Aggregate/Ordered protocols and use extension to inject them into models

Sam Jaffe 2 weeks ago
parent
commit
a44ef357fe

+ 0 - 16
Todos/Model/Aggregate.swift

@@ -1,16 +0,0 @@
-//
-//  Aggregate.swift
-//  Todos
-//
-//  Created by Sam Jaffe on 3/5/26.
-//
-
-import Foundation
-
-protocol Aggregate {
-  associatedtype Element
-
-  func move(fromOffsets: IndexSet, toOffset: Int)
-  func remove(_ item: Element)
-  func reindex()
-}

+ 1 - 19
Todos/Model/Project.swift

@@ -10,9 +10,7 @@ import SwiftData
 import SwiftUI
 
 @Model
-final class Project: Codable, Ordered, Aggregate {
-  typealias Element = Task
-
+final class Project: Codable {
   var sortOrder: Int = 0
   var name: String = "New Project"
   var category: String = ""
@@ -24,22 +22,6 @@ final class Project: Codable, Ordered, Aggregate {
     self.sortOrder = sortOrder
   }
 
-  func move(fromOffsets: IndexSet, toOffset: Int) {
-    tasks.move(fromOffsets: fromOffsets, toOffset: toOffset)
-    reindex()
-  }
-
-  func remove(_ item: Element) {
-    tasks.removeAll(where: { $0.id == item.id })
-    reindex()
-  }
-
-  func reindex() {
-    for (index, item) in tasks.enumerated() {
-      item.sortOrder = index
-    }
-  }
-
   func yaml(_ indent: Int = 0) -> String {
     let hdr = String(repeating: "  ", count: indent)
     var rval = hdr + "\(name):\n"

+ 1 - 1
Todos/Model/SubTask.swift

@@ -9,7 +9,7 @@ import Foundation
 import SwiftData
 
 @Model
-final class SubTask: Codable, Ordered {
+final class SubTask: Codable {
   var sortOrder: Int = 0
   var name: String
   var task: Task?

+ 1 - 19
Todos/Model/Task.swift

@@ -10,9 +10,7 @@ import SwiftData
 import SwiftUI
 
 @Model
-final class Task: Codable, Ordered, Aggregate {
-  typealias Element = SubTask
-
+final class Task: Codable {
   var sortOrder: Int = 0
   var name: String
   var project: Project?
@@ -31,22 +29,6 @@ final class Task: Codable, Ordered, Aggregate {
     self.sortOrder = parent?.tasks.count ?? 0
   }
 
-  func move(fromOffsets: IndexSet, toOffset: Int) {
-    subtasks.move(fromOffsets: fromOffsets, toOffset: toOffset)
-    reindex()
-  }
-
-  func remove(_ item: Element) {
-    subtasks.removeAll(where: { $0.id == item.id })
-    reindex()
-  }
-
-  func reindex() {
-    for (index, item) in subtasks.enumerated() {
-      item.sortOrder = index
-    }
-  }
-
   func yaml(_ indent: Int = 0) -> String {
     let hdr = String(repeating: "  ", count: indent)
     let subhdr = hdr + "  # "

+ 57 - 0
Todos/ViewModel/Aggregate.swift

@@ -0,0 +1,57 @@
+//
+//  Aggregate.swift
+//  Todos
+//
+//  Created by Sam Jaffe on 3/5/26.
+//
+
+import Foundation
+import SwiftUI
+
+protocol Aggregate {
+  associatedtype Element
+
+  func move(fromOffsets: IndexSet, toOffset: Int)
+  func remove(_ item: Element)
+  func reindex()
+}
+
+extension Project : Aggregate {
+  typealias Element = Task
+
+  func move(fromOffsets: IndexSet, toOffset: Int) {
+    tasks.move(fromOffsets: fromOffsets, toOffset: toOffset)
+    reindex()
+  }
+
+  func remove(_ item: Element) {
+    tasks.removeAll(where: { $0.id == item.id })
+    reindex()
+  }
+
+  func reindex() {
+    for (index, item) in tasks.enumerated() {
+      item.sortOrder = index
+    }
+  }
+}
+
+extension Task : Aggregate {
+  typealias Element = SubTask
+
+  func move(fromOffsets: IndexSet, toOffset: Int) {
+    subtasks.move(fromOffsets: fromOffsets, toOffset: toOffset)
+    reindex()
+  }
+
+  func remove(_ item: Element) {
+    subtasks.removeAll(where: { $0.id == item.id })
+    reindex()
+  }
+
+  func reindex() {
+    for (index, item) in subtasks.enumerated() {
+      item.sortOrder = index
+    }
+  }
+}

+ 4 - 0
Todos/Model/Ordered.swift

@@ -23,3 +23,7 @@ extension Ordered {
     return lhs.sortOrder.wrappedValue < rhs.sortOrder.wrappedValue
   }
 }
+
+extension Project : Ordered {}
+extension Task : Ordered {}
+extension SubTask : Ordered {}