WIP: Using project detail for duct size calculations, fix trunk sizes querying database for room data, it's now eagerly loaded.
This commit is contained in:
@@ -41,7 +41,17 @@ extension DatabaseClient.Projects: TestDependencyKey {
|
|||||||
.with(\.$equipment)
|
.with(\.$equipment)
|
||||||
.with(\.$equivalentLengths)
|
.with(\.$equivalentLengths)
|
||||||
.with(\.$rooms)
|
.with(\.$rooms)
|
||||||
.with(\.$trunks, { $0.with(\.$rooms) })
|
.with(
|
||||||
|
\.$trunks,
|
||||||
|
{ trunk in
|
||||||
|
trunk.with(
|
||||||
|
\.$rooms,
|
||||||
|
{
|
||||||
|
$0.with(\.$room)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
.filter(\.$id == id)
|
.filter(\.$id == id)
|
||||||
.first()
|
.first()
|
||||||
else {
|
else {
|
||||||
@@ -51,7 +61,7 @@ extension DatabaseClient.Projects: TestDependencyKey {
|
|||||||
// TODO: Different error ??
|
// TODO: Different error ??
|
||||||
guard let equipmentInfo = model.equipment else { return nil }
|
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(
|
return try .init(
|
||||||
project: model.toDTO(),
|
project: model.toDTO(),
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ extension DatabaseClient.TrunkSizes: TestDependencyKey {
|
|||||||
type: request.type
|
type: request.type
|
||||||
)
|
)
|
||||||
try await model.save(on: database)
|
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(
|
return try .init(
|
||||||
@@ -60,23 +61,30 @@ extension DatabaseClient.TrunkSizes: TestDependencyKey {
|
|||||||
fetch: { projectID in
|
fetch: { projectID in
|
||||||
try await TrunkModel.query(on: database)
|
try await TrunkModel.query(on: database)
|
||||||
.with(\.$project)
|
.with(\.$project)
|
||||||
.with(\.$rooms)
|
.with(\.$rooms, { $0.with(\.$room) })
|
||||||
.filter(\.$project.$id == projectID)
|
.filter(\.$project.$id == projectID)
|
||||||
.all()
|
.all()
|
||||||
.toDTO(on: database)
|
.toDTO()
|
||||||
},
|
},
|
||||||
get: { id in
|
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 nil
|
||||||
}
|
}
|
||||||
return try await model.toDTO(on: database)
|
return try await model.toDTO()
|
||||||
},
|
},
|
||||||
update: { id, updates in
|
update: { id, updates in
|
||||||
guard
|
guard
|
||||||
let model =
|
let model =
|
||||||
try await TrunkModel
|
try await TrunkModel
|
||||||
.query(on: database)
|
.query(on: database)
|
||||||
.with(\.$rooms)
|
.with(\.$rooms, { $0.with(\.$room) })
|
||||||
.filter(\.$id == id)
|
.filter(\.$id == id)
|
||||||
.first()
|
.first()
|
||||||
else {
|
else {
|
||||||
@@ -84,7 +92,7 @@ extension DatabaseClient.TrunkSizes: TestDependencyKey {
|
|||||||
}
|
}
|
||||||
try updates.validate()
|
try updates.validate()
|
||||||
try await model.applyUpdates(updates, on: database)
|
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
|
self.type = type.rawValue
|
||||||
}
|
}
|
||||||
|
|
||||||
func toDTO(on database: any Database) async throws -> TrunkSize.RoomProxy {
|
func toDTO() throws -> TrunkSize.RoomProxy {
|
||||||
guard let room = try await RoomModel.find($room.id, on: database) else {
|
// guard let room = try await RoomModel.find($room.id, on: database) else {
|
||||||
throw NotFoundError()
|
// throw NotFoundError()
|
||||||
}
|
// }
|
||||||
return .init(
|
return .init(
|
||||||
room: try room.toDTO(),
|
room: try room.toDTO(),
|
||||||
registers: registers
|
registers: registers
|
||||||
@@ -251,18 +259,22 @@ final class TrunkModel: Model, @unchecked Sendable {
|
|||||||
self.name = name
|
self.name = name
|
||||||
}
|
}
|
||||||
|
|
||||||
func toDTO(on database: any Database) async throws -> TrunkSize {
|
func toDTO() throws -> TrunkSize {
|
||||||
let rooms = try await withThrowingTaskGroup(of: TrunkSize.RoomProxy.self) { group in
|
// let rooms = try await withThrowingTaskGroup(of: TrunkSize.RoomProxy.self) { group in
|
||||||
for room in self.rooms {
|
// for room in self.rooms {
|
||||||
group.addTask {
|
// group.addTask {
|
||||||
try await room.toDTO(on: database)
|
// try await room.toDTO(on: database)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
return try await group.reduce(into: [TrunkSize.RoomProxy]()) {
|
// return try await group.reduce(into: [TrunkSize.RoomProxy]()) {
|
||||||
$0.append($1)
|
// $0.append($1)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
|
||||||
|
let rooms = try rooms.reduce(into: [TrunkSize.RoomProxy]()) {
|
||||||
|
$0.append(try $1.toDTO())
|
||||||
}
|
}
|
||||||
|
|
||||||
return try .init(
|
return try .init(
|
||||||
@@ -340,17 +352,17 @@ final class TrunkModel: Model, @unchecked Sendable {
|
|||||||
|
|
||||||
extension Array where Element == TrunkModel {
|
extension Array where Element == TrunkModel {
|
||||||
|
|
||||||
func toDTO(on database: any Database) async throws -> [TrunkSize] {
|
func toDTO() throws -> [TrunkSize] {
|
||||||
try await withThrowingTaskGroup(of: TrunkSize.self) { group in
|
// try await withThrowingTaskGroup(of: TrunkSize.self) { group in
|
||||||
for model in self {
|
// for model in self {
|
||||||
group.addTask {
|
// group.addTask {
|
||||||
try await model.toDTO(on: database)
|
// try await model.toDTO(on: database)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
return try await group.reduce(into: [TrunkSize]()) {
|
return try reduce(into: [TrunkSize]()) {
|
||||||
$0.append($1)
|
$0.append(try $1.toDTO())
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,14 @@ import ManualDCore
|
|||||||
|
|
||||||
extension DatabaseClient {
|
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(
|
func calculateDuctSizes(
|
||||||
projectID: Project.ID
|
projectID: Project.ID
|
||||||
) async throws -> (DuctSizes, DuctSizeSharedRequest, [Room]) {
|
) 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(
|
func calculateRoomDuctSizes(
|
||||||
projectID: Project.ID
|
projectID: Project.ID
|
||||||
) async throws -> ([DuctSizes.RoomContainer], DuctSizeSharedRequest) {
|
) 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(
|
func calculateTrunkDuctSizes(
|
||||||
projectID: Project.ID
|
projectID: Project.ID
|
||||||
) async throws -> ([DuctSizes.TrunkContainer], DuctSizeSharedRequest) {
|
) 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 {
|
func sharedDuctRequest(_ projectID: Project.ID) async throws -> DuctSizeSharedRequest {
|
||||||
|
|
||||||
guard let dfrResponse = try await designFrictionRate(projectID: projectID) else {
|
guard let dfrResponse = try await designFrictionRate(projectID: projectID) else {
|
||||||
@@ -107,25 +165,36 @@ extension DatabaseClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func designFrictionRate(
|
func designFrictionRate(
|
||||||
projectID: Project.ID
|
componentLosses: [ComponentPressureLoss],
|
||||||
) async throws -> DesignFrictionRateResponse? {
|
equipmentInfo: EquipmentInfo,
|
||||||
guard let equipmentInfo = try await equipment.fetch(projectID) else {
|
equivalentLengths: EffectiveLength.MaxContainer
|
||||||
return nil
|
) -> DesignFrictionRateResponse? {
|
||||||
}
|
guard let tel = equivalentLengths.total,
|
||||||
|
componentLosses.count > 0
|
||||||
|
else { return nil }
|
||||||
|
|
||||||
let equivalentLengths = try await effectiveLength.fetchMax(projectID)
|
let availableStaticPressure = equipmentInfo.staticPressure - componentLosses.total
|
||||||
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
|
|
||||||
|
|
||||||
return .init(
|
return .init(
|
||||||
designFrictionRate: (availableStaticPressure * 100) / tel,
|
designFrictionRate: (availableStaticPressure * 100) / tel,
|
||||||
equipmentInfo: equipmentInfo,
|
equipmentInfo: equipmentInfo,
|
||||||
telMaxContainer: equivalentLengths
|
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)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,29 +48,72 @@ extension ProjectClient: DependencyKey {
|
|||||||
|
|
||||||
extension DatabaseClient {
|
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 {
|
fileprivate func makePdfRequest(_ projectID: Project.ID) async throws -> PdfClient.Request {
|
||||||
@Dependency(\.manualD) var manualD
|
@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)")
|
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 {
|
guard let frictionRate = frictionRateResponse.frictionRate else {
|
||||||
throw ProjectClientError("Friction rate not found. id: \(projectID)")
|
throw ProjectClientError("Friction rate not found. id: \(projectID)")
|
||||||
}
|
}
|
||||||
let (ductSizes, sharedInfo, rooms) = try await calculateDuctSizes(projectID: projectID)
|
|
||||||
|
|
||||||
return .init(
|
return .init(
|
||||||
project: project,
|
details: projectDetails,
|
||||||
rooms: rooms,
|
|
||||||
componentLosses: frictionRateResponse.componentLosses,
|
|
||||||
ductSizes: ductSizes,
|
ductSizes: ductSizes,
|
||||||
equipmentInfo: sharedInfo.equipmentInfo,
|
shared: shared,
|
||||||
maxSupplyTEL: sharedInfo.maxSupplyLength,
|
frictionRate: frictionRate
|
||||||
maxReturnTEL: sharedInfo.maxReturnLenght,
|
|
||||||
frictionRate: frictionRate,
|
|
||||||
projectSHR: sharedInfo.projectSHR
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user