diff --git a/Sources/DatabaseClient/Projects.swift b/Sources/DatabaseClient/Projects.swift index 0d845e1..0aacecd 100644 --- a/Sources/DatabaseClient/Projects.swift +++ b/Sources/DatabaseClient/Projects.swift @@ -41,7 +41,17 @@ extension DatabaseClient.Projects: TestDependencyKey { .with(\.$equipment) .with(\.$equivalentLengths) .with(\.$rooms) - .with(\.$trunks, { $0.with(\.$rooms) }) + .with( + \.$trunks, + { trunk in + trunk.with( + \.$rooms, + { + $0.with(\.$room) + } + ) + } + ) .filter(\.$id == id) .first() else { @@ -51,7 +61,7 @@ extension DatabaseClient.Projects: TestDependencyKey { // TODO: Different error ?? guard let equipmentInfo = model.equipment else { return nil } - let trunks = try await model.trunks.toDTO(on: database) + let trunks = try model.trunks.toDTO() return try .init( project: model.toDTO(), diff --git a/Sources/DatabaseClient/TrunkSizes.swift b/Sources/DatabaseClient/TrunkSizes.swift index 8a31fea..be4f850 100644 --- a/Sources/DatabaseClient/TrunkSizes.swift +++ b/Sources/DatabaseClient/TrunkSizes.swift @@ -41,7 +41,8 @@ extension DatabaseClient.TrunkSizes: TestDependencyKey { type: request.type ) try await model.save(on: database) - try await roomProxies.append(model.toDTO(on: database)) + // TODO: This `model.toDTO()` may not work now, need to check. + try await roomProxies.append(model.toDTO()) } return try .init( @@ -60,23 +61,30 @@ extension DatabaseClient.TrunkSizes: TestDependencyKey { fetch: { projectID in try await TrunkModel.query(on: database) .with(\.$project) - .with(\.$rooms) + .with(\.$rooms, { $0.with(\.$room) }) .filter(\.$project.$id == projectID) .all() - .toDTO(on: database) + .toDTO() }, get: { id in - guard let model = try await TrunkModel.find(id, on: database) else { + guard + let model = + try await TrunkModel + .query(on: database) + .with(\.$rooms, { $0.with(\.$room) }) + .filter(\.$id == id) + .first() + else { return nil } - return try await model.toDTO(on: database) + return try await model.toDTO() }, update: { id, updates in guard let model = try await TrunkModel .query(on: database) - .with(\.$rooms) + .with(\.$rooms, { $0.with(\.$room) }) .filter(\.$id == id) .first() else { @@ -84,7 +92,7 @@ extension DatabaseClient.TrunkSizes: TestDependencyKey { } try updates.validate() try await model.applyUpdates(updates, on: database) - return try await model.toDTO(on: database) + return try model.toDTO() } ) } @@ -201,10 +209,10 @@ final class TrunkRoomModel: Model, @unchecked Sendable { self.type = type.rawValue } - func toDTO(on database: any Database) async throws -> TrunkSize.RoomProxy { - guard let room = try await RoomModel.find($room.id, on: database) else { - throw NotFoundError() - } + func toDTO() throws -> TrunkSize.RoomProxy { + // guard let room = try await RoomModel.find($room.id, on: database) else { + // throw NotFoundError() + // } return .init( room: try room.toDTO(), registers: registers @@ -251,18 +259,22 @@ final class TrunkModel: Model, @unchecked Sendable { self.name = name } - 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: [TrunkSize.RoomProxy]()) { - $0.append($1) - } + func toDTO() 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: [TrunkSize.RoomProxy]()) { + // $0.append($1) + // } + // + // } + let rooms = try rooms.reduce(into: [TrunkSize.RoomProxy]()) { + $0.append(try $1.toDTO()) } return try .init( @@ -340,17 +352,17 @@ final class TrunkModel: Model, @unchecked Sendable { extension Array where Element == TrunkModel { - 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) - } - } + func toDTO() 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: [TrunkSize]()) { - $0.append($1) - } + return try reduce(into: [TrunkSize]()) { + $0.append(try $1.toDTO()) } } + // } } diff --git a/Sources/ProjectClient/Internal/DatabaseClient+calculateDuctSizes.swift b/Sources/ProjectClient/Internal/DatabaseClient+calculateDuctSizes.swift index b0cac46..5e81d2a 100644 --- a/Sources/ProjectClient/Internal/DatabaseClient+calculateDuctSizes.swift +++ b/Sources/ProjectClient/Internal/DatabaseClient+calculateDuctSizes.swift @@ -5,6 +5,14 @@ import ManualDCore extension DatabaseClient { + func calculateDuctSizes( + details: Project.Detail + ) async throws -> (DuctSizes, DuctSizeSharedRequest) { + let (rooms, shared) = try await calculateRoomDuctSizes(details: details) + let (trunks, _) = try await calculateTrunkDuctSizes(details: details) + return (.init(rooms: rooms, trunks: trunks), shared) + } + func calculateDuctSizes( projectID: Project.ID ) async throws -> (DuctSizes, DuctSizeSharedRequest, [Room]) { @@ -24,6 +32,16 @@ extension DatabaseClient { ) } + func calculateRoomDuctSizes( + details: Project.Detail + ) async throws -> ([DuctSizes.RoomContainer], DuctSizeSharedRequest) { + @Dependency(\.manualD) var manualD + + let shared = try sharedDuctRequest(details: details) + let rooms = try await manualD.calculateRoomSizes(rooms: details.rooms, sharedRequest: shared) + return (rooms, shared) + } + func calculateRoomDuctSizes( projectID: Project.ID ) async throws -> ([DuctSizes.RoomContainer], DuctSizeSharedRequest) { @@ -40,6 +58,20 @@ extension DatabaseClient { ) } + func calculateTrunkDuctSizes( + details: Project.Detail + ) async throws -> ([DuctSizes.TrunkContainer], DuctSizeSharedRequest) { + @Dependency(\.manualD) var manualD + + let shared = try sharedDuctRequest(details: details) + let trunks = try await manualD.calculateTrunkSizes( + rooms: details.rooms, + trunks: details.trunks, + sharedRequest: shared + ) + return (trunks, shared) + } + func calculateTrunkDuctSizes( projectID: Project.ID ) async throws -> ([DuctSizes.TrunkContainer], DuctSizeSharedRequest) { @@ -57,6 +89,32 @@ extension DatabaseClient { ) } + func sharedDuctRequest(details: Project.Detail) throws -> DuctSizeSharedRequest { + guard + let dfrResponse = designFrictionRate( + componentLosses: details.componentLosses, + equipmentInfo: details.equipmentInfo, + equivalentLengths: details.maxContainer + ) + else { + throw ProjectClientError("Project not complete.") + } + + guard let projectSHR = details.project.sensibleHeatRatio else { + throw ProjectClientError("Project sensible heat ratio not set.") + } + + let ensuredTEL = try dfrResponse.ensureMaxContainer() + + return .init( + equipmentInfo: dfrResponse.equipmentInfo, + maxSupplyLength: ensuredTEL.supply, + maxReturnLenght: ensuredTEL.return, + designFrictionRate: dfrResponse.designFrictionRate, + projectSHR: projectSHR + ) + } + func sharedDuctRequest(_ projectID: Project.ID) async throws -> DuctSizeSharedRequest { guard let dfrResponse = try await designFrictionRate(projectID: projectID) else { @@ -107,25 +165,36 @@ extension DatabaseClient { } func designFrictionRate( - projectID: Project.ID - ) async throws -> DesignFrictionRateResponse? { - guard let equipmentInfo = try await equipment.fetch(projectID) else { - return nil - } + componentLosses: [ComponentPressureLoss], + equipmentInfo: EquipmentInfo, + equivalentLengths: EffectiveLength.MaxContainer + ) -> DesignFrictionRateResponse? { + guard let tel = equivalentLengths.total, + componentLosses.count > 0 + else { return nil } - let equivalentLengths = try await effectiveLength.fetchMax(projectID) - guard let tel = equivalentLengths.total else { return nil } - - let componentLosses = try await componentLoss.fetch(projectID) - guard componentLosses.count > 0 else { return nil } - - let availableStaticPressure = - equipmentInfo.staticPressure - componentLosses.total + let availableStaticPressure = equipmentInfo.staticPressure - componentLosses.total return .init( designFrictionRate: (availableStaticPressure * 100) / tel, equipmentInfo: equipmentInfo, telMaxContainer: equivalentLengths ) + + } + + func designFrictionRate( + projectID: Project.ID + ) async throws -> DesignFrictionRateResponse? { + + guard let equipmentInfo = try await equipment.fetch(projectID) else { + return nil + } + + return try await designFrictionRate( + componentLosses: componentLoss.fetch(projectID), + equipmentInfo: equipmentInfo, + equivalentLengths: effectiveLength.fetchMax(projectID) + ) } } diff --git a/Sources/ProjectClient/Live.swift b/Sources/ProjectClient/Live.swift index 292c223..cf160b4 100644 --- a/Sources/ProjectClient/Live.swift +++ b/Sources/ProjectClient/Live.swift @@ -48,29 +48,72 @@ extension ProjectClient: DependencyKey { extension DatabaseClient { + // fileprivate func makePdfRequest(_ projectID: Project.ID) async throws -> PdfClient.Request { + // @Dependency(\.manualD) var manualD + // + // guard let project = try await projects.get(projectID) else { + // throw ProjectClientError("Project not found. id: \(projectID)") + // } + // let frictionRateResponse = try await manualD.frictionRate(projectID: projectID) + // guard let frictionRate = frictionRateResponse.frictionRate else { + // throw ProjectClientError("Friction rate not found. id: \(projectID)") + // } + // let (ductSizes, sharedInfo, rooms) = try await calculateDuctSizes(projectID: projectID) + // + // return .init( + // project: project, + // rooms: rooms, + // componentLosses: frictionRateResponse.componentLosses, + // ductSizes: ductSizes, + // equipmentInfo: sharedInfo.equipmentInfo, + // maxSupplyTEL: sharedInfo.maxSupplyLength, + // maxReturnTEL: sharedInfo.maxReturnLenght, + // frictionRate: frictionRate, + // projectSHR: sharedInfo.projectSHR + // ) + // } + fileprivate func makePdfRequest(_ projectID: Project.ID) async throws -> PdfClient.Request { @Dependency(\.manualD) var manualD - guard let project = try await projects.get(projectID) else { + guard let projectDetails = try await projects.detail(projectID) else { throw ProjectClientError("Project not found. id: \(projectID)") } - let frictionRateResponse = try await manualD.frictionRate(projectID: projectID) + + let (ductSizes, shared) = try await calculateDuctSizes(details: projectDetails) + + let frictionRateResponse = try await manualD.frictionRate(details: projectDetails) guard let frictionRate = frictionRateResponse.frictionRate else { throw ProjectClientError("Friction rate not found. id: \(projectID)") } - let (ductSizes, sharedInfo, rooms) = try await calculateDuctSizes(projectID: projectID) return .init( - project: project, - rooms: rooms, - componentLosses: frictionRateResponse.componentLosses, + details: projectDetails, ductSizes: ductSizes, - equipmentInfo: sharedInfo.equipmentInfo, - maxSupplyTEL: sharedInfo.maxSupplyLength, - maxReturnTEL: sharedInfo.maxReturnLenght, - frictionRate: frictionRate, - projectSHR: sharedInfo.projectSHR + shared: shared, + frictionRate: frictionRate ) } } + +extension PdfClient.Request { + init( + details: Project.Detail, + ductSizes: DuctSizes, + shared: DuctSizeSharedRequest, + frictionRate: FrictionRate + ) { + self.init( + project: details.project, + rooms: details.rooms, + componentLosses: details.componentLosses, + ductSizes: ductSizes, + equipmentInfo: details.equipmentInfo, + maxSupplyTEL: shared.maxSupplyLength, + maxReturnTEL: shared.maxReturnLenght, + frictionRate: frictionRate, + projectSHR: shared.projectSHR + ) + } +}