diff --git a/Sources/DatabaseClient/Interface.swift b/Sources/DatabaseClient/Interface.swift index 6c85b68..b003db9 100644 --- a/Sources/DatabaseClient/Interface.swift +++ b/Sources/DatabaseClient/Interface.swift @@ -74,7 +74,7 @@ extension DatabaseClient.Migrations: DependencyKey { EquipmentInfo.Migrate(), Room.Migrate(), EffectiveLength.Migrate(), - DuctSizing.TrunkSize.Migrate(), + TrunkSize.Migrate(), ] } ) diff --git a/Sources/DatabaseClient/TrunkSizes.swift b/Sources/DatabaseClient/TrunkSizes.swift index 37f9d7c..8a31fea 100644 --- a/Sources/DatabaseClient/TrunkSizes.swift +++ b/Sources/DatabaseClient/TrunkSizes.swift @@ -7,13 +7,13 @@ import ManualDCore extension DatabaseClient { @DependencyClient public struct TrunkSizes: Sendable { - public var create: @Sendable (DuctSizing.TrunkSize.Create) async throws -> DuctSizing.TrunkSize - public var delete: @Sendable (DuctSizing.TrunkSize.ID) async throws -> Void - public var fetch: @Sendable (Project.ID) async throws -> [DuctSizing.TrunkSize] - public var get: @Sendable (DuctSizing.TrunkSize.ID) async throws -> DuctSizing.TrunkSize? + public var create: @Sendable (TrunkSize.Create) async throws -> TrunkSize + public var delete: @Sendable (TrunkSize.ID) async throws -> Void + public var fetch: @Sendable (Project.ID) async throws -> [TrunkSize] + public var get: @Sendable (TrunkSize.ID) async throws -> TrunkSize? public var update: - @Sendable (DuctSizing.TrunkSize.ID, DuctSizing.TrunkSize.Update) async throws -> - DuctSizing.TrunkSize + @Sendable (TrunkSize.ID, TrunkSize.Update) async throws -> + TrunkSize } } @@ -26,7 +26,7 @@ extension DatabaseClient.TrunkSizes: TestDependencyKey { try request.validate() let trunk = request.toModel() - var roomProxies = [DuctSizing.TrunkSize.RoomProxy]() + var roomProxies = [TrunkSize.RoomProxy]() try await trunk.save(on: database) @@ -90,7 +90,7 @@ extension DatabaseClient.TrunkSizes: TestDependencyKey { } } -extension DuctSizing.TrunkSize.Create { +extension TrunkSize.Create { func validate() throws(ValidationError) { guard rooms.count > 0 else { @@ -113,7 +113,7 @@ extension DuctSizing.TrunkSize.Create { } } -extension DuctSizing.TrunkSize.Update { +extension TrunkSize.Update { func validate() throws(ValidationError) { if let rooms { guard rooms.count > 0 else { @@ -128,7 +128,7 @@ extension DuctSizing.TrunkSize.Update { } } -extension DuctSizing.TrunkSize { +extension TrunkSize { struct Migrate: AsyncMigration { let name = "CreateTrunkSize" @@ -192,7 +192,7 @@ final class TrunkRoomModel: Model, @unchecked Sendable { trunkID: TrunkModel.IDValue, roomID: RoomModel.IDValue, registers: [Int], - type: DuctSizing.TrunkSize.TrunkType + type: TrunkSize.TrunkType ) { self.id = id $trunk.id = trunkID @@ -201,7 +201,7 @@ final class TrunkRoomModel: Model, @unchecked Sendable { self.type = type.rawValue } - func toDTO(on database: any Database) async throws -> DuctSizing.TrunkSize.RoomProxy { + func toDTO(on database: any Database) async throws -> TrunkSize.RoomProxy { guard let room = try await RoomModel.find($room.id, on: database) else { throw NotFoundError() } @@ -240,7 +240,7 @@ final class TrunkModel: Model, @unchecked Sendable { init( id: UUID? = nil, projectID: Project.ID, - type: DuctSizing.TrunkSize.TrunkType, + type: TrunkSize.TrunkType, height: Int? = nil, name: String? = nil ) { @@ -251,15 +251,15 @@ final class TrunkModel: Model, @unchecked Sendable { self.name = name } - func toDTO(on database: any Database) async throws -> DuctSizing.TrunkSize { - let rooms = try await withThrowingTaskGroup(of: DuctSizing.TrunkSize.RoomProxy.self) { group in + func toDTO(on database: any Database) async throws -> TrunkSize { + let rooms = try await withThrowingTaskGroup(of: TrunkSize.RoomProxy.self) { group in for room in self.rooms { group.addTask { try await room.toDTO(on: database) } } - return try await group.reduce(into: [DuctSizing.TrunkSize.RoomProxy]()) { + return try await group.reduce(into: [TrunkSize.RoomProxy]()) { $0.append($1) } @@ -277,7 +277,7 @@ final class TrunkModel: Model, @unchecked Sendable { } func applyUpdates( - _ updates: DuctSizing.TrunkSize.Update, + _ updates: TrunkSize.Update, on database: any Database ) async throws { if let type = updates.type, type.rawValue != self.type { @@ -340,15 +340,15 @@ final class TrunkModel: Model, @unchecked Sendable { extension Array where Element == TrunkModel { - func toDTO(on database: any Database) async throws -> [DuctSizing.TrunkSize] { - try await withThrowingTaskGroup(of: DuctSizing.TrunkSize.self) { group in + func toDTO(on database: any Database) async throws -> [TrunkSize] { + try await withThrowingTaskGroup(of: TrunkSize.self) { group in for model in self { group.addTask { try await model.toDTO(on: database) } } - return try await group.reduce(into: [DuctSizing.TrunkSize]()) { + return try await group.reduce(into: [TrunkSize]()) { $0.append($1) } } diff --git a/Sources/ManualDClient/Helpers.swift b/Sources/ManualDClient/Helpers.swift index 2969d2f..ee77d61 100644 --- a/Sources/ManualDClient/Helpers.swift +++ b/Sources/ManualDClient/Helpers.swift @@ -14,7 +14,7 @@ extension Room { } } -extension DuctSizing.TrunkSize.RoomProxy { +extension TrunkSize.RoomProxy { // We need to make sure if registers got removed after a trunk // was already made / saved that we do not include registers that @@ -35,7 +35,7 @@ extension DuctSizing.TrunkSize.RoomProxy { } } -extension DuctSizing.TrunkSize { +extension TrunkSize { var totalHeatingLoad: Double { rooms.reduce(into: 0) { $0 += $1.totalHeatingLoad } diff --git a/Sources/ManualDCore/DuctSizing.swift b/Sources/ManualDCore/DuctSizing.swift index 39074b6..36f31d0 100644 --- a/Sources/ManualDCore/DuctSizing.swift +++ b/Sources/ManualDCore/DuctSizing.swift @@ -114,7 +114,7 @@ extension DuctSizing { self.ductSize = ductSize } - public subscript(dynamicMember keyPath: KeyPath) -> T { + public subscript(dynamicMember keyPath: KeyPath) -> T { trunk[keyPath: keyPath] } @@ -122,99 +122,4 @@ extension DuctSizing { ductSize[keyPath: keyPath] } } - - // TODO: Add an optional label that the user can set. - - // Represents the database model. - public struct TrunkSize: Codable, Equatable, Identifiable, Sendable { - - public let id: UUID - public let projectID: Project.ID - public let type: TrunkType - public let rooms: [RoomProxy] - public let height: Int? - public let name: String? - - public init( - id: UUID, - projectID: Project.ID, - type: DuctSizing.TrunkSize.TrunkType, - rooms: [DuctSizing.TrunkSize.RoomProxy], - height: Int? = nil, - name: String? = nil - ) { - self.id = id - self.projectID = projectID - self.type = type - self.rooms = rooms - self.height = height - self.name = name - } - } - -} - -extension DuctSizing.TrunkSize { - public struct Create: Codable, Equatable, Sendable { - - public let projectID: Project.ID - public let type: TrunkType - public let rooms: [Room.ID: [Int]] - public let height: Int? - public let name: String? - - public init( - projectID: Project.ID, - type: DuctSizing.TrunkSize.TrunkType, - rooms: [Room.ID: [Int]], - height: Int? = nil, - name: String? = nil - ) { - self.projectID = projectID - self.type = type - self.rooms = rooms - self.height = height - self.name = name - } - } - - public struct Update: Codable, Equatable, Sendable { - - public let type: TrunkType? - public let rooms: [Room.ID: [Int]]? - public let height: Int? - public let name: String? - - public init( - type: DuctSizing.TrunkSize.TrunkType? = nil, - rooms: [Room.ID: [Int]]? = nil, - height: Int? = nil, - name: String? = nil - ) { - self.type = type - self.rooms = rooms - self.height = height - self.name = name - } - } - - // TODO: Make registers non-optional - public struct RoomProxy: Codable, Equatable, Identifiable, Sendable { - - public var id: Room.ID { room.id } - public let room: Room - public let registers: [Int] - - public init(room: Room, registers: [Int]) { - self.room = room - self.registers = registers - } - } - - public enum TrunkType: String, CaseIterable, Codable, Equatable, Sendable { - case `return` - case supply - - public static let allCases = [Self.supply, .return] - } } diff --git a/Sources/ManualDCore/Routes/ViewRoute.swift b/Sources/ManualDCore/Routes/ViewRoute.swift index ebd82a3..ca5be24 100644 --- a/Sources/ManualDCore/Routes/ViewRoute.swift +++ b/Sources/ManualDCore/Routes/ViewRoute.swift @@ -668,9 +668,9 @@ extension SiteRoute.View.ProjectRoute { } public enum TrunkRoute: Equatable, Sendable { - case delete(DuctSizing.TrunkSize.ID) + case delete(TrunkSize.ID) case submit(TrunkSizeForm) - case update(DuctSizing.TrunkSize.ID, TrunkSizeForm) + case update(TrunkSize.ID, TrunkSizeForm) public static let rootPath = "trunk" @@ -678,7 +678,7 @@ extension SiteRoute.View.ProjectRoute { Route(.case(Self.delete)) { Path { rootPath - DuctSizing.TrunkSize.ID.parser() + TrunkSize.ID.parser() } Method.delete } @@ -690,7 +690,7 @@ extension SiteRoute.View.ProjectRoute { Body { FormData { Field("projectID") { Project.ID.parser() } - Field("type") { DuctSizing.TrunkSize.TrunkType.parser() } + Field("type") { TrunkSize.TrunkType.parser() } Optionally { Field("height") { Int.parser() } @@ -708,13 +708,13 @@ extension SiteRoute.View.ProjectRoute { Route(.case(Self.update)) { Path { rootPath - DuctSizing.TrunkSize.ID.parser() + TrunkSize.ID.parser() } Method.patch Body { FormData { Field("projectID") { Project.ID.parser() } - Field("type") { DuctSizing.TrunkSize.TrunkType.parser() } + Field("type") { TrunkSize.TrunkType.parser() } Optionally { Field("height") { Int.parser() } } @@ -732,17 +732,43 @@ extension SiteRoute.View.ProjectRoute { } public struct RoomRectangularForm: Equatable, Sendable { + public let id: Room.RectangularSize.ID? public let register: Int public let height: Int + + public init( + id: Room.RectangularSize.ID? = nil, + register: Int, + height: Int + ) { + self.id = id + self.register = register + self.height = height + } } public struct TrunkSizeForm: Equatable, Sendable { + public let projectID: Project.ID - public let type: DuctSizing.TrunkSize.TrunkType + public let type: TrunkSize.TrunkType public let height: Int? public let name: String? public let rooms: [String] + + public init( + projectID: Project.ID, + type: TrunkSize.TrunkType, + height: Int? = nil, + name: String? = nil, + rooms: [String] + ) { + self.projectID = projectID + self.type = type + self.height = height + self.name = name + self.rooms = rooms + } } } } diff --git a/Sources/ManualDCore/TrunkSize.swift b/Sources/ManualDCore/TrunkSize.swift new file mode 100644 index 0000000..819b7f4 --- /dev/null +++ b/Sources/ManualDCore/TrunkSize.swift @@ -0,0 +1,93 @@ +import Foundation + +// Represents the database model. +public struct TrunkSize: Codable, Equatable, Identifiable, Sendable { + + public let id: UUID + public let projectID: Project.ID + public let type: TrunkType + public let rooms: [RoomProxy] + public let height: Int? + public let name: String? + + public init( + id: UUID, + projectID: Project.ID, + type: TrunkType, + rooms: [RoomProxy], + height: Int? = nil, + name: String? = nil + ) { + self.id = id + self.projectID = projectID + self.type = type + self.rooms = rooms + self.height = height + self.name = name + } +} + +extension TrunkSize { + public struct Create: Codable, Equatable, Sendable { + + public let projectID: Project.ID + public let type: TrunkType + public let rooms: [Room.ID: [Int]] + public let height: Int? + public let name: String? + + public init( + projectID: Project.ID, + type: TrunkType, + rooms: [Room.ID: [Int]], + height: Int? = nil, + name: String? = nil + ) { + self.projectID = projectID + self.type = type + self.rooms = rooms + self.height = height + self.name = name + } + } + + public struct Update: Codable, Equatable, Sendable { + + public let type: TrunkType? + public let rooms: [Room.ID: [Int]]? + public let height: Int? + public let name: String? + + public init( + type: TrunkType? = nil, + rooms: [Room.ID: [Int]]? = nil, + height: Int? = nil, + name: String? = nil + ) { + self.type = type + self.rooms = rooms + self.height = height + self.name = name + } + } + + // TODO: Make registers non-optional + public struct RoomProxy: Codable, Equatable, Identifiable, Sendable { + + public var id: Room.ID { room.id } + public let room: Room + public let registers: [Int] + + public init(room: Room, registers: [Int]) { + self.room = room + self.registers = registers + } + } + + public enum TrunkType: String, CaseIterable, Codable, Equatable, Sendable { + case `return` + case supply + + public static let allCases = [Self.supply, .return] + } +} diff --git a/Sources/ProjectClient/Internal/ManualDClient+calculateDuctSizes.swift b/Sources/ProjectClient/Internal/ManualDClient+calculateDuctSizes.swift index e529e7d..c09f78b 100644 --- a/Sources/ProjectClient/Internal/ManualDClient+calculateDuctSizes.swift +++ b/Sources/ProjectClient/Internal/ManualDClient+calculateDuctSizes.swift @@ -16,7 +16,7 @@ extension ManualDClient { func calculateDuctSizes( rooms: [Room], - trunks: [DuctSizing.TrunkSize], + trunks: [TrunkSize], sharedRequest: DuctSizeSharedRequest, logger: Logger? = nil ) async throws -> ProjectClient.DuctSizeResponse { @@ -93,7 +93,7 @@ extension ManualDClient { func calculateTrunkSizes( rooms: [Room], - trunks: [DuctSizing.TrunkSize], + trunks: [TrunkSize], sharedRequest: DuctSizeSharedRequest, logger: Logger? = nil ) async throws -> [DuctSizing.TrunkContainer] { @@ -190,7 +190,7 @@ extension Room { } } -extension DuctSizing.TrunkSize.RoomProxy { +extension TrunkSize.RoomProxy { // We need to make sure if registers got removed after a trunk // was already made / saved that we do not include registers that @@ -211,7 +211,7 @@ extension DuctSizing.TrunkSize.RoomProxy { } } -extension DuctSizing.TrunkSize { +extension TrunkSize { var totalHeatingLoad: Double { rooms.reduce(into: 0) { $0 += $1.totalHeatingLoad } diff --git a/Sources/ViewController/Extensions/TrunkSizeForm+extensions.swift b/Sources/ViewController/Extensions/TrunkSizeForm+extensions.swift index 163607f..b1057c2 100644 --- a/Sources/ViewController/Extensions/TrunkSizeForm+extensions.swift +++ b/Sources/ViewController/Extensions/TrunkSizeForm+extensions.swift @@ -4,7 +4,7 @@ import ManualDCore extension SiteRoute.View.ProjectRoute.DuctSizingRoute.TrunkSizeForm { - func toCreate(logger: Logger? = nil) throws -> DuctSizing.TrunkSize.Create { + func toCreate(logger: Logger? = nil) throws -> TrunkSize.Create { try .init( projectID: projectID, type: type, @@ -14,7 +14,7 @@ extension SiteRoute.View.ProjectRoute.DuctSizingRoute.TrunkSizeForm { ) } - func toUpdate(logger: Logger? = nil) throws -> DuctSizing.TrunkSize.Update { + func toUpdate(logger: Logger? = nil) throws -> TrunkSize.Update { try .init( type: type, rooms: makeRooms(logger: logger), diff --git a/Sources/ViewController/Views/DuctSizing/TrunkSizeForm.swift b/Sources/ViewController/Views/DuctSizing/TrunkSizeForm.swift index 82521dc..b4a5b78 100644 --- a/Sources/ViewController/Views/DuctSizing/TrunkSizeForm.swift +++ b/Sources/ViewController/Views/DuctSizing/TrunkSizeForm.swift @@ -17,7 +17,7 @@ struct TrunkSizeForm: HTML, Sendable { let rooms: [DuctSizing.RoomContainer] let dismiss: Bool - var trunk: DuctSizing.TrunkSize? { + var trunk: TrunkSize? { container?.trunk } @@ -56,7 +56,7 @@ struct TrunkSizeForm: HTML, Sendable { label(.class("select w-full")) { span(.class("label")) { "Type" } select(.name("type")) { - for type in DuctSizing.TrunkSize.TrunkType.allCases { + for type in TrunkSize.TrunkType.allCases { option(.value(type.rawValue)) { type.rawValue.capitalized } .attributes(.selected, when: trunk?.type == type) } @@ -121,7 +121,7 @@ struct TrunkSizeForm: HTML, Sendable { } -extension Array where Element == DuctSizing.TrunkSize.RoomProxy { +extension Array where Element == TrunkSize.RoomProxy { func hasRoom(_ room: DuctSizing.RoomContainer) -> Bool { first { $0.id == room.roomID