feat: Begins live database client tests.
All checks were successful
CI / Linux Tests (push) Successful in 5m35s
All checks were successful
CI / Linux Tests (push) Successful in 5m35s
This commit is contained in:
@@ -1,9 +0,0 @@
|
||||
import Foundation
|
||||
|
||||
public struct ProjectClientError: Error {
|
||||
public let reason: String
|
||||
|
||||
public init(_ reason: String) {
|
||||
self.reason = reason
|
||||
}
|
||||
}
|
||||
@@ -18,9 +18,12 @@ extension DependencyValues {
|
||||
/// for the view controller to render views.
|
||||
@DependencyClient
|
||||
public struct ProjectClient: Sendable {
|
||||
public var calculateDuctSizes: @Sendable (Project.ID) async throws -> DuctSizes
|
||||
|
||||
/// Calculates the room duct sizes for the given project.
|
||||
public var calculateRoomDuctSizes:
|
||||
@Sendable (Project.ID) async throws -> [DuctSizes.RoomContainer]
|
||||
|
||||
/// Calculates the trunk duct sizes for the given project.
|
||||
public var calculateTrunkDuctSizes:
|
||||
@Sendable (Project.ID) async throws -> [DuctSizes.TrunkContainer]
|
||||
|
||||
@@ -28,6 +31,14 @@ public struct ProjectClient: Sendable {
|
||||
@Sendable (User.ID, Project.Create) async throws -> CreateProjectResponse
|
||||
|
||||
public var frictionRate: @Sendable (Project.ID) async throws -> FrictionRateResponse
|
||||
public var generatePdf: @Sendable (Project.ID) async throws -> Response
|
||||
|
||||
public func calculateDuctSizes(_ projectID: Project.ID) async throws -> DuctSizes {
|
||||
.init(
|
||||
rooms: try await calculateRoomDuctSizes(projectID),
|
||||
trunks: try await calculateTrunkDuctSizes(projectID)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension ProjectClient: TestDependencyKey {
|
||||
|
||||
@@ -9,32 +9,18 @@ extension DatabaseClient {
|
||||
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]) {
|
||||
@Dependency(\.manualD) var manualD
|
||||
|
||||
let shared = try await sharedDuctRequest(projectID)
|
||||
let rooms = try await rooms.fetch(projectID)
|
||||
|
||||
return try await (
|
||||
manualD.calculateDuctSizes(
|
||||
.init(
|
||||
rooms: rooms,
|
||||
trunks: trunkSizes.fetch(projectID),
|
||||
sharedRequest: shared
|
||||
trunks: calculateTrunkDuctSizes(details: details, shared: shared)
|
||||
),
|
||||
shared,
|
||||
rooms
|
||||
shared
|
||||
)
|
||||
}
|
||||
|
||||
func calculateRoomDuctSizes(
|
||||
details: Project.Detail
|
||||
) async throws -> ([DuctSizes.RoomContainer], DuctSizeSharedRequest) {
|
||||
) async throws -> (rooms: [DuctSizes.RoomContainer], shared: DuctSizeSharedRequest) {
|
||||
@Dependency(\.manualD) var manualD
|
||||
|
||||
let shared = try sharedDuctRequest(details: details)
|
||||
@@ -42,54 +28,29 @@ extension DatabaseClient {
|
||||
return (rooms, shared)
|
||||
}
|
||||
|
||||
func calculateRoomDuctSizes(
|
||||
projectID: Project.ID
|
||||
) async throws -> ([DuctSizes.RoomContainer], DuctSizeSharedRequest) {
|
||||
@Dependency(\.manualD) var manualD
|
||||
|
||||
let shared = try await sharedDuctRequest(projectID)
|
||||
|
||||
return try await (
|
||||
manualD.calculateRoomSizes(
|
||||
rooms: rooms.fetch(projectID),
|
||||
sharedRequest: shared
|
||||
),
|
||||
shared
|
||||
)
|
||||
}
|
||||
|
||||
func calculateTrunkDuctSizes(
|
||||
details: Project.Detail
|
||||
) async throws -> ([DuctSizes.TrunkContainer], DuctSizeSharedRequest) {
|
||||
details: Project.Detail,
|
||||
shared: DuctSizeSharedRequest? = nil
|
||||
) async throws -> [DuctSizes.TrunkContainer] {
|
||||
@Dependency(\.manualD) var manualD
|
||||
|
||||
let shared = try sharedDuctRequest(details: details)
|
||||
let trunks = try await manualD.calculateTrunkSizes(
|
||||
let sharedRequest: DuctSizeSharedRequest
|
||||
if let shared {
|
||||
sharedRequest = shared
|
||||
} else {
|
||||
sharedRequest = try sharedDuctRequest(details: details)
|
||||
}
|
||||
|
||||
return 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) {
|
||||
@Dependency(\.manualD) var manualD
|
||||
|
||||
let shared = try await sharedDuctRequest(projectID)
|
||||
|
||||
return try await (
|
||||
manualD.calculateTrunkSizes(
|
||||
rooms: rooms.fetch(projectID),
|
||||
trunks: trunkSizes.fetch(projectID),
|
||||
sharedRequest: shared
|
||||
),
|
||||
shared
|
||||
sharedRequest: sharedRequest
|
||||
)
|
||||
}
|
||||
|
||||
func sharedDuctRequest(details: Project.Detail) throws -> DuctSizeSharedRequest {
|
||||
let projectSHR = try details.project.ensuredSHR()
|
||||
|
||||
guard
|
||||
let dfrResponse = designFrictionRate(
|
||||
componentLosses: details.componentLosses,
|
||||
@@ -100,10 +61,6 @@ extension DatabaseClient {
|
||||
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(
|
||||
@@ -115,32 +72,6 @@ extension DatabaseClient {
|
||||
)
|
||||
}
|
||||
|
||||
func sharedDuctRequest(_ projectID: Project.ID) async throws -> DuctSizeSharedRequest {
|
||||
|
||||
guard let dfrResponse = try await designFrictionRate(projectID: projectID) else {
|
||||
throw ProjectClientError("Project not complete.")
|
||||
}
|
||||
|
||||
let ensuredTEL = try dfrResponse.ensureMaxContainer()
|
||||
|
||||
return try await .init(
|
||||
equipmentInfo: dfrResponse.equipmentInfo,
|
||||
maxSupplyLength: ensuredTEL.supply,
|
||||
maxReturnLenght: ensuredTEL.return,
|
||||
designFrictionRate: dfrResponse.designFrictionRate,
|
||||
projectSHR: ensuredSHR(projectID)
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
// Fetches the project sensible heat ratio or throws an error if it's nil.
|
||||
func ensuredSHR(_ projectID: Project.ID) async throws -> Double {
|
||||
guard let projectSHR = try await projects.getSensibleHeatRatio(projectID) else {
|
||||
throw ProjectClientError("Project sensible heat ratio not set.")
|
||||
}
|
||||
return projectSHR
|
||||
}
|
||||
|
||||
// Internal container.
|
||||
struct DesignFrictionRateResponse: Equatable, Sendable {
|
||||
|
||||
@@ -183,18 +114,13 @@ extension DatabaseClient {
|
||||
|
||||
}
|
||||
|
||||
func designFrictionRate(
|
||||
projectID: Project.ID
|
||||
) async throws -> DesignFrictionRateResponse? {
|
||||
}
|
||||
|
||||
guard let equipmentInfo = try await equipment.fetch(projectID) else {
|
||||
return nil
|
||||
extension Project {
|
||||
func ensuredSHR() throws -> Double {
|
||||
guard let shr = sensibleHeatRatio else {
|
||||
throw ProjectClientError("Sensible heat ratio not set on project id: \(id)")
|
||||
}
|
||||
|
||||
return try await designFrictionRate(
|
||||
componentLosses: componentLosses.fetch(projectID),
|
||||
equipmentInfo: equipmentInfo,
|
||||
equivalentLengths: equivalentLengths.fetchMax(projectID)
|
||||
)
|
||||
return shr
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
import DatabaseClient
|
||||
import Dependencies
|
||||
import ManualDClient
|
||||
import ManualDCore
|
||||
import PdfClient
|
||||
|
||||
extension DatabaseClient {
|
||||
|
||||
/// Generate a pdf request for the given project.
|
||||
func makePdfRequest(_ projectID: Project.ID) async throws -> PdfClient.Request {
|
||||
@Dependency(\.manualD) var manualD
|
||||
|
||||
guard let projectDetails = try await projects.detail(projectID) else {
|
||||
throw ProjectClientError.notFound(.project(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.notFound(.frictionRate(projectID))
|
||||
}
|
||||
|
||||
return .init(
|
||||
details: projectDetails,
|
||||
ductSizes: ductSizes,
|
||||
shared: shared,
|
||||
frictionRate: frictionRate
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension PdfClient.Request {
|
||||
fileprivate 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
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -15,14 +15,17 @@ extension ProjectClient: DependencyKey {
|
||||
@Dependency(\.fileClient) var fileClient
|
||||
|
||||
return .init(
|
||||
calculateDuctSizes: { projectID in
|
||||
try await database.calculateDuctSizes(projectID: projectID).0
|
||||
},
|
||||
calculateRoomDuctSizes: { projectID in
|
||||
try await database.calculateRoomDuctSizes(projectID: projectID).0
|
||||
guard let details = try await database.projects.detail(projectID) else {
|
||||
throw ProjectClientError.notFound(.project(projectID))
|
||||
}
|
||||
return try await database.calculateRoomDuctSizes(details: details).rooms
|
||||
},
|
||||
calculateTrunkDuctSizes: { projectID in
|
||||
try await database.calculateTrunkDuctSizes(projectID: projectID).0
|
||||
guard let details = try await database.projects.detail(projectID) else {
|
||||
throw ProjectClientError.notFound(.project(projectID))
|
||||
}
|
||||
return try await database.calculateTrunkDuctSizes(details: details)
|
||||
},
|
||||
createProject: { userID, request in
|
||||
let project = try await database.projects.create(userID, request)
|
||||
@@ -58,50 +61,3 @@ extension ProjectClient: DependencyKey {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension DatabaseClient {
|
||||
|
||||
fileprivate func makePdfRequest(_ projectID: Project.ID) async throws -> PdfClient.Request {
|
||||
@Dependency(\.manualD) var manualD
|
||||
|
||||
guard let projectDetails = try await projects.detail(projectID) else {
|
||||
throw ProjectClientError("Project not found. id: \(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)")
|
||||
}
|
||||
|
||||
return .init(
|
||||
details: projectDetails,
|
||||
ductSizes: ductSizes,
|
||||
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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
35
Sources/ProjectClient/ProjectClientError.swift
Normal file
35
Sources/ProjectClient/ProjectClientError.swift
Normal file
@@ -0,0 +1,35 @@
|
||||
import Foundation
|
||||
import ManualDCore
|
||||
|
||||
public struct ProjectClientError: Error {
|
||||
public let reason: String
|
||||
|
||||
public init(_ reason: String) {
|
||||
self.reason = reason
|
||||
}
|
||||
|
||||
static func notFound(_ notFound: NotFound) -> Self {
|
||||
.init(notFound.reason)
|
||||
}
|
||||
|
||||
enum NotFound {
|
||||
case project(Project.ID)
|
||||
case frictionRate(Project.ID)
|
||||
|
||||
var reason: String {
|
||||
switch self {
|
||||
case .project(let id):
|
||||
return "Project not found. id: \(id)"
|
||||
case .frictionRate(let id):
|
||||
return """
|
||||
Friction unable to be calculated. id: \(id)
|
||||
|
||||
This usually means that not all the required steps have been completed.
|
||||
|
||||
Calculating the friction rate requires the component pressure losses to be set and
|
||||
have a max equivalent length for both the supply and return.
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user