feat: Adds some documentation strings in ManualDCore module.
This commit is contained in:
@@ -180,7 +180,7 @@ final class EffectiveLengthModel: Model, @unchecked Sendable {
|
||||
name: name,
|
||||
type: .init(rawValue: type)!,
|
||||
straightLengths: straightLengths,
|
||||
groups: JSONDecoder().decode([EquivalentLength.Group].self, from: groups),
|
||||
groups: JSONDecoder().decode([EquivalentLength.FittingGroup].self, from: groups),
|
||||
createdAt: createdAt!,
|
||||
updatedAt: updatedAt!
|
||||
)
|
||||
|
||||
@@ -46,10 +46,6 @@ extension TrunkSize {
|
||||
}
|
||||
}
|
||||
|
||||
extension ComponentPressureLosses {
|
||||
var totalLosses: Double { values.reduce(0) { $0 + $1 } }
|
||||
}
|
||||
|
||||
extension Array where Element == EffectiveLengthGroup {
|
||||
var totalEffectiveLength: Int {
|
||||
reduce(0) { $0 + $1.effectiveLength }
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import Dependencies
|
||||
import Foundation
|
||||
|
||||
/// Represents component pressure losses used in the friction rate worksheet.
|
||||
///
|
||||
/// These are items such as filter, evaporator-coils, balance-dampers, etc. that
|
||||
/// need to be overcome by the system fan.
|
||||
public struct ComponentPressureLoss: Codable, Equatable, Identifiable, Sendable {
|
||||
|
||||
public let id: UUID
|
||||
@@ -44,7 +48,7 @@ extension ComponentPressureLoss {
|
||||
self.value = value
|
||||
}
|
||||
|
||||
// Return's commonly used default component pressure losses.
|
||||
/// Commonly used default component pressure losses.
|
||||
public static func `default`(projectID: Project.ID) -> [Self] {
|
||||
[
|
||||
.init(projectID: projectID, name: "supply-outlet", value: 0.03),
|
||||
@@ -75,20 +79,7 @@ extension Array where Element == ComponentPressureLoss {
|
||||
}
|
||||
}
|
||||
|
||||
public typealias ComponentPressureLosses = [String: Double]
|
||||
|
||||
#if DEBUG
|
||||
extension ComponentPressureLosses {
|
||||
public static var mock: Self {
|
||||
[
|
||||
"evaporator-coil": 0.2,
|
||||
"filter": 0.1,
|
||||
"supply-outlet": 0.03,
|
||||
"return-grille": 0.03,
|
||||
"balancing-damper": 0.03,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
extension Array where Element == ComponentPressureLoss {
|
||||
public static func mock(projectID: Project.ID) -> Self {
|
||||
@@ -1,5 +1,7 @@
|
||||
import Foundation
|
||||
|
||||
// TODO: These are not used, should they be removed??
|
||||
|
||||
// TODO: Add other description / label for items that have same group & letter, but
|
||||
// different effective length.
|
||||
public struct EffectiveLengthGroup: Codable, Equatable, Sendable {
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import Dependencies
|
||||
import Foundation
|
||||
|
||||
/// Represents the equipment information for a project.
|
||||
///
|
||||
/// This is used in the friction rate worksheet and sizing ducts. It holds on to items
|
||||
/// such as the target static pressure, cooling CFM, and heating CFM for the project.
|
||||
public struct EquipmentInfo: Codable, Equatable, Identifiable, Sendable {
|
||||
public let id: UUID
|
||||
public let projectID: Project.ID
|
||||
|
||||
@@ -1,18 +1,36 @@
|
||||
import Dependencies
|
||||
import Foundation
|
||||
|
||||
// TODO: Not sure how to model effective length groups in the database.
|
||||
// thinking perhaps just have a 'data' field that encoded / decodes
|
||||
// to swift types??
|
||||
/// Represents the equivalent length of a single duct path.
|
||||
///
|
||||
/// These consist of both straight lengths of duct / trunks, as well as the
|
||||
/// equivalent length of duct fittings. They are used to determine the worst
|
||||
/// case total equivalent length of duct that the system fan has to move air
|
||||
/// through.
|
||||
///
|
||||
/// There can be many equivalent lengths saved for a project, however the only
|
||||
/// ones that matter in most calculations are the longest supply path and the
|
||||
/// the longest return path.
|
||||
///
|
||||
/// It is required that project has at least one equivalent length saved for
|
||||
/// the supply and one saved for return, otherwise duct sizes can not be calculated.
|
||||
public struct EquivalentLength: Codable, Equatable, Identifiable, Sendable {
|
||||
|
||||
/// The id of the equivalent length.
|
||||
public let id: UUID
|
||||
/// The project that this equivalent length is associated with.
|
||||
public let projectID: Project.ID
|
||||
/// A unique name / label for this equivalent length.
|
||||
public let name: String
|
||||
/// The type (supply or return) of the equivalent length.
|
||||
public let type: EffectiveLengthType
|
||||
/// The straight lengths of duct for this equivalent length.
|
||||
public let straightLengths: [Int]
|
||||
public let groups: [Group]
|
||||
/// The fitting groups associated with this equivalent length.
|
||||
public let groups: [FittingGroup]
|
||||
/// When this equivalent length was created in the database.
|
||||
public let createdAt: Date
|
||||
/// When this equivalent length was updated in the database.
|
||||
public let updatedAt: Date
|
||||
|
||||
public init(
|
||||
@@ -21,7 +39,7 @@ public struct EquivalentLength: Codable, Equatable, Identifiable, Sendable {
|
||||
name: String,
|
||||
type: EquivalentLength.EffectiveLengthType,
|
||||
straightLengths: [Int],
|
||||
groups: [EquivalentLength.Group],
|
||||
groups: [EquivalentLength.FittingGroup],
|
||||
createdAt: Date,
|
||||
updatedAt: Date
|
||||
) {
|
||||
@@ -38,20 +56,26 @@ public struct EquivalentLength: Codable, Equatable, Identifiable, Sendable {
|
||||
|
||||
extension EquivalentLength {
|
||||
|
||||
/// Represents the data needed to create a new ``EquivalentLength`` in the database.
|
||||
public struct Create: Codable, Equatable, Sendable {
|
||||
|
||||
/// The project that this equivalent length is associated with.
|
||||
public let projectID: Project.ID
|
||||
/// A unique name / label for this equivalent length.
|
||||
public let name: String
|
||||
/// The type (supply or return) of the equivalent length.
|
||||
public let type: EffectiveLengthType
|
||||
/// The straight lengths of duct for this equivalent length.
|
||||
public let straightLengths: [Int]
|
||||
public let groups: [Group]
|
||||
/// The fitting groups associated with this equivalent length.
|
||||
public let groups: [FittingGroup]
|
||||
|
||||
public init(
|
||||
projectID: Project.ID,
|
||||
name: String,
|
||||
type: EquivalentLength.EffectiveLengthType,
|
||||
straightLengths: [Int],
|
||||
groups: [EquivalentLength.Group]
|
||||
groups: [EquivalentLength.FittingGroup]
|
||||
) {
|
||||
self.projectID = projectID
|
||||
self.name = name
|
||||
@@ -61,18 +85,25 @@ extension EquivalentLength {
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the data needed to update an ``EquivalentLength`` in the database.
|
||||
///
|
||||
/// Only the supplied fields are updated.
|
||||
public struct Update: Codable, Equatable, Sendable {
|
||||
|
||||
/// A unique name / label for this equivalent length.
|
||||
public let name: String?
|
||||
/// The type (supply or return) of the equivalent length.
|
||||
public let type: EffectiveLengthType?
|
||||
/// The straight lengths of duct for this equivalent length.
|
||||
public let straightLengths: [Int]?
|
||||
public let groups: [Group]?
|
||||
/// The fitting groups associated with this equivalent length.
|
||||
public let groups: [FittingGroup]?
|
||||
|
||||
public init(
|
||||
name: String? = nil,
|
||||
type: EquivalentLength.EffectiveLengthType? = nil,
|
||||
straightLengths: [Int]? = nil,
|
||||
groups: [EquivalentLength.Group]? = nil
|
||||
groups: [EquivalentLength.FittingGroup]? = nil
|
||||
) {
|
||||
self.name = name
|
||||
self.type = type
|
||||
@@ -81,16 +112,24 @@ extension EquivalentLength {
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the type of equivalent length, either supply or return.
|
||||
public enum EffectiveLengthType: String, CaseIterable, Codable, Sendable {
|
||||
case `return`
|
||||
case supply
|
||||
}
|
||||
|
||||
public struct Group: Codable, Equatable, Sendable {
|
||||
|
||||
/// Represents a Manual-D fitting group.
|
||||
///
|
||||
/// These are defined by Manual-D and convert different types of fittings into
|
||||
/// an equivalent length of straight duct.
|
||||
public struct FittingGroup: Codable, Equatable, Sendable {
|
||||
/// The fitting group number.
|
||||
public let group: Int
|
||||
/// The fitting group letter.
|
||||
public let letter: String
|
||||
/// The equivalent length of the fitting.
|
||||
public let value: Double
|
||||
/// The quantity of the fittings in the path.
|
||||
public let quantity: Int
|
||||
|
||||
public init(
|
||||
@@ -106,11 +145,22 @@ extension EquivalentLength {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Should these not be optional and we just throw an error or return nil from
|
||||
// a database query.
|
||||
|
||||
/// Represents the max ``EquivalentLength``'s for a project.
|
||||
///
|
||||
/// Calculating the duct sizes for a project requires there to be a max supply
|
||||
/// and a max return equivalent length, so this container represents those values
|
||||
/// when they exist in the database.
|
||||
public struct MaxContainer: Codable, Equatable, Sendable {
|
||||
|
||||
/// The longest supply equivalent length.
|
||||
public let supply: EquivalentLength?
|
||||
/// The longest return equivalent length.
|
||||
public let `return`: EquivalentLength?
|
||||
|
||||
public var total: Double? {
|
||||
public var totalEquivalentLength: Double? {
|
||||
guard let supply else { return nil }
|
||||
guard let `return` else { return nil }
|
||||
return supply.totalEquivalentLength + `return`.totalEquivalentLength
|
||||
@@ -124,14 +174,19 @@ extension EquivalentLength {
|
||||
}
|
||||
|
||||
extension EquivalentLength {
|
||||
|
||||
/// The calculated total equivalent length.
|
||||
///
|
||||
/// This is the sum of all the straigth lengths and fitting groups (with quantities).
|
||||
public var totalEquivalentLength: Double {
|
||||
straightLengths.reduce(into: 0.0) { $0 += Double($1) }
|
||||
+ groups.totalEquivalentLength
|
||||
}
|
||||
}
|
||||
|
||||
extension Array where Element == EquivalentLength.Group {
|
||||
extension Array where Element == EquivalentLength.FittingGroup {
|
||||
|
||||
/// The calculated total equivalent length for the fitting groups.
|
||||
public var totalEquivalentLength: Double {
|
||||
reduce(into: 0.0) {
|
||||
$0 += ($1.value * Double($1.quantity))
|
||||
@@ -179,37 +234,6 @@ extension Array where Element == EquivalentLength.Group {
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
public static let mocks: [Self] = [
|
||||
.init(
|
||||
id: UUID(0),
|
||||
projectID: UUID(0),
|
||||
name: "Test Supply - 1",
|
||||
type: .supply,
|
||||
straightLengths: [10, 20, 25],
|
||||
groups: [
|
||||
.init(group: 1, letter: "a", value: 20),
|
||||
.init(group: 2, letter: "b", value: 15, quantity: 2),
|
||||
.init(group: 3, letter: "c", value: 10, quantity: 1),
|
||||
],
|
||||
createdAt: Date(),
|
||||
updatedAt: Date()
|
||||
),
|
||||
.init(
|
||||
id: UUID(1),
|
||||
projectID: UUID(0),
|
||||
name: "Test Return - 1",
|
||||
type: .return,
|
||||
straightLengths: [10, 20, 25],
|
||||
groups: [
|
||||
.init(group: 1, letter: "a", value: 20),
|
||||
.init(group: 2, letter: "b", value: 15, quantity: 2),
|
||||
.init(group: 3, letter: "c", value: 10, quantity: 1),
|
||||
],
|
||||
createdAt: Date(),
|
||||
updatedAt: Date()
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
/// Holds onto values returned when calculating the design
|
||||
/// friction rate for a project.
|
||||
///
|
||||
/// **NOTE:** This is not stored in the database, it is calculated on the fly.
|
||||
public struct FrictionRate: Codable, Equatable, Sendable {
|
||||
/// The available static pressure is the equipment's design static pressure
|
||||
/// minus the ``ComponentPressureLoss``es for the project.
|
||||
public let availableStaticPressure: Double
|
||||
/// The calculated design friction rate value.
|
||||
public let value: Double
|
||||
/// Whether the design friction rate is within a valid range.
|
||||
public var hasErrors: Bool { error != nil }
|
||||
|
||||
public init(
|
||||
@@ -13,6 +19,7 @@ public struct FrictionRate: Codable, Equatable, Sendable {
|
||||
self.value = value
|
||||
}
|
||||
|
||||
/// The error if the design friction rate is out of a valid range.
|
||||
public var error: FrictionRateError? {
|
||||
if value >= 0.18 {
|
||||
return .init(
|
||||
@@ -37,8 +44,13 @@ public struct FrictionRate: Codable, Equatable, Sendable {
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents an error when the ``FrictionRate`` is out of a valid range.
|
||||
///
|
||||
/// This holds onto the reason for the error as well as possible resolutions.
|
||||
public struct FrictionRateError: Error, Equatable, Sendable {
|
||||
/// The reason for the error.
|
||||
public let reason: String
|
||||
/// The possible resolutions to the error.
|
||||
public let resolutions: [String]
|
||||
|
||||
public init(
|
||||
|
||||
@@ -1,16 +1,29 @@
|
||||
import Dependencies
|
||||
import Foundation
|
||||
|
||||
/// Represents a single duct design project / system.
|
||||
///
|
||||
/// Holds items such as project name and address.
|
||||
public struct Project: Codable, Equatable, Identifiable, Sendable {
|
||||
|
||||
/// The unique ID of the project.
|
||||
public let id: UUID
|
||||
/// The name of the project.
|
||||
public let name: String
|
||||
/// The street address of the project.
|
||||
public let streetAddress: String
|
||||
/// The city of the project.
|
||||
public let city: String
|
||||
/// The state of the project.
|
||||
public let state: String
|
||||
/// The zip code of the project.
|
||||
public let zipCode: String
|
||||
/// The global sensible heat ratio for the project.
|
||||
///
|
||||
/// **NOTE:** This is used for calculating the sensible cooling load for rooms.
|
||||
public let sensibleHeatRatio: Double?
|
||||
/// When the project was created in the database.
|
||||
public let createdAt: Date
|
||||
/// When the project was updated in the database.
|
||||
public let updatedAt: Date
|
||||
|
||||
public init(
|
||||
@@ -37,14 +50,20 @@ public struct Project: Codable, Equatable, Identifiable, Sendable {
|
||||
}
|
||||
|
||||
extension Project {
|
||||
|
||||
/// Represents the data needed to create a new project.
|
||||
public struct Create: Codable, Equatable, Sendable {
|
||||
|
||||
/// The name of the project.
|
||||
public let name: String
|
||||
/// The street address of the project.
|
||||
public let streetAddress: String
|
||||
/// The city of the project.
|
||||
public let city: String
|
||||
/// The state of the project.
|
||||
public let state: String
|
||||
/// The zip code of the project.
|
||||
public let zipCode: String
|
||||
/// The global sensible heat ratio for the project.
|
||||
public let sensibleHeatRatio: Double?
|
||||
|
||||
public init(
|
||||
@@ -64,11 +83,19 @@ extension Project {
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents steps that are completed in order to calculate the duct sizes
|
||||
/// for a project.
|
||||
///
|
||||
/// This is primarily used on the web pages to display errors or color of the
|
||||
/// different steps of a project.
|
||||
public struct CompletedSteps: Codable, Equatable, Sendable {
|
||||
|
||||
/// Whether there is ``EquipmentInfo`` for a project.
|
||||
public let equipmentInfo: Bool
|
||||
/// Whether there are ``Room``'s for a project.
|
||||
public let rooms: Bool
|
||||
/// Whether there are ``EquivalentLength``'s for a project.
|
||||
public let equivalentLength: Bool
|
||||
/// Whether there is a ``FrictionRate`` for a project.
|
||||
public let frictionRate: Bool
|
||||
|
||||
public init(
|
||||
@@ -84,13 +111,23 @@ extension Project {
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents project details loaded from the database.
|
||||
///
|
||||
/// This is generally used to perform duct sizing calculations for the
|
||||
/// project, once all the steps have been completed.
|
||||
public struct Detail: Codable, Equatable, Sendable {
|
||||
|
||||
/// The project.
|
||||
public let project: Project
|
||||
/// The component pressure losses for the project.
|
||||
public let componentLosses: [ComponentPressureLoss]
|
||||
/// The equipment info for the project.
|
||||
public let equipmentInfo: EquipmentInfo
|
||||
/// The equivalent lengths for the project.
|
||||
public let equivalentLengths: [EquivalentLength]
|
||||
/// The rooms in the project.
|
||||
public let rooms: [Room]
|
||||
/// The trunk sizes in the project.
|
||||
public let trunks: [TrunkSize]
|
||||
|
||||
public init(
|
||||
@@ -110,13 +147,22 @@ extension Project {
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents fields that can be updated for a project that has already been created.
|
||||
///
|
||||
/// Only fields that are supplied get updated in the database.
|
||||
public struct Update: Codable, Equatable, Sendable {
|
||||
|
||||
/// The name of the project.
|
||||
public let name: String?
|
||||
/// The street address of the project.
|
||||
public let streetAddress: String?
|
||||
/// The city of the project.
|
||||
public let city: String?
|
||||
/// The state of the project.
|
||||
public let state: String?
|
||||
/// The zip code of the project.
|
||||
public let zipCode: String?
|
||||
/// The global sensible heat ratio for the project.
|
||||
public let sensibleHeatRatio: Double?
|
||||
|
||||
public init(
|
||||
|
||||
@@ -1,16 +1,37 @@
|
||||
import Dependencies
|
||||
import Foundation
|
||||
|
||||
/// Represents a room in a project.
|
||||
///
|
||||
/// This contains data such as the heating and cooling load for the
|
||||
/// room, the number of registers in the room, and any rectangular
|
||||
/// duct size calculations stored for the room.
|
||||
public struct Room: Codable, Equatable, Identifiable, Sendable {
|
||||
/// The unique id of the room.
|
||||
public let id: UUID
|
||||
/// The project this room is associated with.
|
||||
public let projectID: Project.ID
|
||||
/// A unique name for the room in the project.
|
||||
public let name: String
|
||||
/// The heating load required for the room (from Manual-J).
|
||||
public let heatingLoad: Double
|
||||
/// The total cooling load required for the room (from Manual-J).
|
||||
public let coolingTotal: Double
|
||||
/// An optional sensible cooling load for the room.
|
||||
///
|
||||
/// **NOTE:** This is generally not set, but calculated from the project wide
|
||||
/// sensible heat ratio.
|
||||
public let coolingSensible: Double?
|
||||
/// The number of registers for the room.
|
||||
public let registerCount: Int
|
||||
/// The rectangular duct size calculations for a room.
|
||||
///
|
||||
/// **NOTE:** These are optionally set after the round sizes have been calculate
|
||||
/// for a room.
|
||||
public let rectangularSizes: [RectangularSize]?
|
||||
/// When the room was created in the database.
|
||||
public let createdAt: Date
|
||||
/// When the room was updated in the database.
|
||||
public let updatedAt: Date
|
||||
|
||||
public init(
|
||||
@@ -39,13 +60,19 @@ public struct Room: Codable, Equatable, Identifiable, Sendable {
|
||||
}
|
||||
|
||||
extension Room {
|
||||
|
||||
/// Represents the data required to create a new room for a project.
|
||||
public struct Create: Codable, Equatable, Sendable {
|
||||
/// The project this room is associated with.
|
||||
public let projectID: Project.ID
|
||||
/// A unique name for the room in the project.
|
||||
public let name: String
|
||||
/// The heating load required for the room (from Manual-J).
|
||||
public let heatingLoad: Double
|
||||
/// The total cooling load required for the room (from Manual-J).
|
||||
public let coolingTotal: Double
|
||||
/// An optional sensible cooling load for the room.
|
||||
public let coolingSensible: Double?
|
||||
/// The number of registers for the room.
|
||||
public let registerCount: Int
|
||||
|
||||
public init(
|
||||
@@ -65,10 +92,17 @@ extension Room {
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a rectangular size calculation that is stored in the
|
||||
/// database for a given room.
|
||||
///
|
||||
/// These are done after the round duct sizes have been calculated and
|
||||
/// can be used to calculate the equivalent rectangular size for a given run.
|
||||
public struct RectangularSize: Codable, Equatable, Identifiable, Sendable {
|
||||
|
||||
/// The unique id of the rectangular size.
|
||||
public let id: UUID
|
||||
/// The register the rectangular size is associated with.
|
||||
public let register: Int?
|
||||
/// The height of the rectangular size, the width gets calculated.
|
||||
public let height: Int
|
||||
|
||||
public init(
|
||||
@@ -82,12 +116,21 @@ extension Room {
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents field that can be updated on a room after it's been created in the database.
|
||||
///
|
||||
/// Only fields that are supplied get updated.
|
||||
public struct Update: Codable, Equatable, Sendable {
|
||||
/// A unique name for the room in the project.
|
||||
public let name: String?
|
||||
/// The heating load required for the room (from Manual-J).
|
||||
public let heatingLoad: Double?
|
||||
/// The total cooling load required for the room (from Manual-J).
|
||||
public let coolingTotal: Double?
|
||||
/// An optional sensible cooling load for the room.
|
||||
public let coolingSensible: Double?
|
||||
/// The number of registers for the room.
|
||||
public let registerCount: Int?
|
||||
/// The rectangular duct size calculations for a room.
|
||||
public let rectangularSizes: [RectangularSize]?
|
||||
|
||||
public init(
|
||||
@@ -120,14 +163,20 @@ extension Room {
|
||||
|
||||
extension Array where Element == Room {
|
||||
|
||||
/// The sum of heating loads for an array of rooms.
|
||||
public var totalHeatingLoad: Double {
|
||||
reduce(into: 0) { $0 += $1.heatingLoad }
|
||||
}
|
||||
|
||||
/// The sum of total cooling loads for an array of rooms.
|
||||
public var totalCoolingLoad: Double {
|
||||
reduce(into: 0) { $0 += $1.coolingTotal }
|
||||
}
|
||||
|
||||
/// The sum of sensible cooling loads for an array of rooms.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - shr: The project wide sensible heat ratio.
|
||||
public func totalCoolingSensible(shr: Double) -> Double {
|
||||
reduce(into: 0) {
|
||||
let sensible = $1.coolingSensible ?? ($1.coolingTotal * shr)
|
||||
@@ -139,38 +188,6 @@ extension Array where Element == Room {
|
||||
#if DEBUG
|
||||
|
||||
extension Room {
|
||||
public static let mocks = [
|
||||
Room(
|
||||
id: UUID(0),
|
||||
projectID: UUID(0),
|
||||
name: "Kitchen",
|
||||
heatingLoad: 12345,
|
||||
coolingTotal: 1234,
|
||||
registerCount: 2,
|
||||
createdAt: Date(),
|
||||
updatedAt: Date()
|
||||
),
|
||||
Room(
|
||||
id: UUID(1),
|
||||
projectID: UUID(1),
|
||||
name: "Bedroom - 1",
|
||||
heatingLoad: 12345,
|
||||
coolingTotal: 1456,
|
||||
registerCount: 1,
|
||||
createdAt: Date(),
|
||||
updatedAt: Date()
|
||||
),
|
||||
Room(
|
||||
id: UUID(2),
|
||||
projectID: UUID(2),
|
||||
name: "Family Room",
|
||||
heatingLoad: 12345,
|
||||
coolingTotal: 1673,
|
||||
registerCount: 3,
|
||||
createdAt: Date(),
|
||||
updatedAt: Date()
|
||||
),
|
||||
]
|
||||
|
||||
public static func mock(projectID: Project.ID) -> [Self] {
|
||||
@Dependency(\.uuid) var uuid
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import Foundation
|
||||
|
||||
/// Represents supported color themes for the website.
|
||||
public enum Theme: String, CaseIterable, Codable, Equatable, Sendable {
|
||||
case aqua
|
||||
case cupcake
|
||||
@@ -13,6 +14,7 @@ public enum Theme: String, CaseIterable, Codable, Equatable, Sendable {
|
||||
case retro
|
||||
case synthwave
|
||||
|
||||
/// Represents dark color themes.
|
||||
public static let darkThemes = [
|
||||
Self.aqua,
|
||||
Self.cyberpunk,
|
||||
@@ -22,6 +24,7 @@ public enum Theme: String, CaseIterable, Codable, Equatable, Sendable {
|
||||
Self.synthwave,
|
||||
]
|
||||
|
||||
/// Represents light color themes.
|
||||
public static let lightThemes = [
|
||||
Self.cupcake,
|
||||
Self.light,
|
||||
|
||||
@@ -1,14 +1,23 @@
|
||||
import Dependencies
|
||||
import Foundation
|
||||
|
||||
// Represents the database model.
|
||||
/// Represents trunk calculations for a project.
|
||||
///
|
||||
/// These are used to size trunk ducts / runs for multiple rooms or registers.
|
||||
public struct TrunkSize: Codable, Equatable, Identifiable, Sendable {
|
||||
|
||||
/// The unique identifier of the trunk size.
|
||||
public let id: UUID
|
||||
/// The project the trunk size is for.
|
||||
public let projectID: Project.ID
|
||||
/// The type of the trunk size (supply or return).
|
||||
public let type: TrunkType
|
||||
/// The rooms / registers associated with the trunk size.
|
||||
public let rooms: [RoomProxy]
|
||||
/// An optional rectangular height used to calculate the equivalent
|
||||
/// rectangular size of the trunk.
|
||||
public let height: Int?
|
||||
/// An optional name / label used for identifying the trunk.
|
||||
public let name: String?
|
||||
|
||||
public init(
|
||||
@@ -29,12 +38,19 @@ public struct TrunkSize: Codable, Equatable, Identifiable, Sendable {
|
||||
}
|
||||
|
||||
extension TrunkSize {
|
||||
/// Represents the data needed to create a new ``TrunkSize`` in the database.
|
||||
public struct Create: Codable, Equatable, Sendable {
|
||||
|
||||
/// The project the trunk size is for.
|
||||
public let projectID: Project.ID
|
||||
/// The type of the trunk size (supply or return).
|
||||
public let type: TrunkType
|
||||
/// The rooms / registers associated with the trunk size.
|
||||
public let rooms: [Room.ID: [Int]]
|
||||
/// An optional rectangular height used to calculate the equivalent
|
||||
/// rectangular size of the trunk.
|
||||
public let height: Int?
|
||||
/// An optional name / label used for identifying the trunk.
|
||||
public let name: String?
|
||||
|
||||
public init(
|
||||
@@ -52,11 +68,19 @@ extension TrunkSize {
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the fields that can be updated on a ``TrunkSize`` in the database.
|
||||
///
|
||||
/// Only supplied fields are updated.
|
||||
public struct Update: Codable, Equatable, Sendable {
|
||||
|
||||
/// The type of the trunk size (supply or return).
|
||||
public let type: TrunkType?
|
||||
/// The rooms / registers associated with the trunk size.
|
||||
public let rooms: [Room.ID: [Int]]?
|
||||
/// An optional rectangular height used to calculate the equivalent
|
||||
/// rectangular size of the trunk.
|
||||
public let height: Int?
|
||||
/// An optional name / label used for identifying the trunk.
|
||||
public let name: String?
|
||||
|
||||
public init(
|
||||
@@ -72,18 +96,29 @@ extension TrunkSize {
|
||||
}
|
||||
}
|
||||
|
||||
public struct RoomProxy: Codable, Equatable, Identifiable, Sendable {
|
||||
/// A container / wrapper around a ``Room`` that is used with a ``TrunkSize``.
|
||||
///
|
||||
/// This is needed because a room can have multiple registers and it is possible
|
||||
/// that a trunk does not serve all registers in that room.
|
||||
@dynamicMemberLookup
|
||||
public struct RoomProxy: Codable, Equatable, Sendable {
|
||||
|
||||
public var id: Room.ID { room.id }
|
||||
/// The room associated with the ``TrunkSize``.
|
||||
public let room: Room
|
||||
/// The specific room registers associated with the ``TrunkSize``.
|
||||
public let registers: [Int]
|
||||
|
||||
public init(room: Room, registers: [Int]) {
|
||||
self.room = room
|
||||
self.registers = registers
|
||||
}
|
||||
|
||||
public subscript<T>(dynamicMember keyPath: KeyPath<Room, T>) -> T {
|
||||
room[keyPath: keyPath]
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the type of a ``TrunkSize``, either supply or return.
|
||||
public enum TrunkType: String, CaseIterable, Codable, Equatable, Sendable {
|
||||
case `return`
|
||||
case supply
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
import Dependencies
|
||||
import Foundation
|
||||
|
||||
// FIX: Remove username.
|
||||
/// Represents a user of the site.
|
||||
///
|
||||
public struct User: Codable, Equatable, Identifiable, Sendable {
|
||||
|
||||
/// The unique id of the user.
|
||||
public let id: UUID
|
||||
/// The user's email address.
|
||||
public let email: String
|
||||
/// When the user was created in the database.
|
||||
public let createdAt: Date
|
||||
/// When the user was updated in the database.
|
||||
public let updatedAt: Date
|
||||
|
||||
public init(
|
||||
@@ -23,10 +28,14 @@ public struct User: Codable, Equatable, Identifiable, Sendable {
|
||||
}
|
||||
|
||||
extension User {
|
||||
/// Represents the data required to create a new user.
|
||||
public struct Create: Codable, Equatable, Sendable {
|
||||
|
||||
/// The user's email address.
|
||||
public let email: String
|
||||
/// The password for the user.
|
||||
public let password: String
|
||||
/// The password confirmation, must match the password.
|
||||
public let confirmPassword: String
|
||||
|
||||
public init(
|
||||
@@ -40,9 +49,13 @@ extension User {
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents data required to login a user.
|
||||
public struct Login: Codable, Equatable, Sendable {
|
||||
/// The user's email address.
|
||||
public let email: String
|
||||
/// The password for the user.
|
||||
public let password: String
|
||||
/// An optional page / route to navigate to after logging in the user.
|
||||
public let next: String?
|
||||
|
||||
public init(email: String, password: String, next: String? = nil) {
|
||||
@@ -52,10 +65,13 @@ extension User {
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a user session token, for a logged in user.
|
||||
public struct Token: Codable, Equatable, Identifiable, Sendable {
|
||||
|
||||
/// The unique id of the token.
|
||||
public let id: UUID
|
||||
/// The user id the token is for.
|
||||
public let userID: User.ID
|
||||
/// The token value.
|
||||
public let value: String
|
||||
|
||||
public init(id: UUID, userID: User.ID, value: String) {
|
||||
|
||||
@@ -2,19 +2,32 @@ import Dependencies
|
||||
import Foundation
|
||||
|
||||
extension User {
|
||||
/// Represents a user's profile. Which contains extra information about a user of the site.
|
||||
public struct Profile: Codable, Equatable, Identifiable, Sendable {
|
||||
|
||||
/// The unique id of the profile
|
||||
public let id: UUID
|
||||
/// The user id the profile is for.
|
||||
public let userID: User.ID
|
||||
/// The user's first name.
|
||||
public let firstName: String
|
||||
/// The user's last name.
|
||||
public let lastName: String
|
||||
/// The user's company name.
|
||||
public let companyName: String
|
||||
/// The user's street address.
|
||||
public let streetAddress: String
|
||||
/// The user's city.
|
||||
public let city: String
|
||||
/// The user's state.
|
||||
public let state: String
|
||||
/// The user's zip code.
|
||||
public let zipCode: String
|
||||
/// An optional theme that the user prefers.
|
||||
public let theme: Theme?
|
||||
/// When the profile was created in the database.
|
||||
public let createdAt: Date
|
||||
/// When the profile was updated in the database.
|
||||
public let updatedAt: Date
|
||||
|
||||
public init(
|
||||
@@ -49,15 +62,25 @@ extension User {
|
||||
|
||||
extension User.Profile {
|
||||
|
||||
/// Represents the data required to create a user profile.
|
||||
public struct Create: Codable, Equatable, Sendable {
|
||||
/// The user id the profile is for.
|
||||
public let userID: User.ID
|
||||
/// The user's first name.
|
||||
public let firstName: String
|
||||
/// The user's last name.
|
||||
public let lastName: String
|
||||
/// The user's company name.
|
||||
public let companyName: String
|
||||
/// The user's street address.
|
||||
public let streetAddress: String
|
||||
/// The user's city.
|
||||
public let city: String
|
||||
/// The user's state.
|
||||
public let state: String
|
||||
/// The user's zip code.
|
||||
public let zipCode: String
|
||||
/// An optional theme that the user prefers.
|
||||
public let theme: Theme?
|
||||
|
||||
public init(
|
||||
@@ -83,14 +106,25 @@ extension User.Profile {
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the fields that can be updated on a user's profile.
|
||||
///
|
||||
/// Only fields that are supplied get updated.
|
||||
public struct Update: Codable, Equatable, Sendable {
|
||||
/// The user's first name.
|
||||
public let firstName: String?
|
||||
/// The user's last name.
|
||||
public let lastName: String?
|
||||
/// The user's company name.
|
||||
public let companyName: String?
|
||||
/// The user's street address.
|
||||
public let streetAddress: String?
|
||||
/// The user's city.
|
||||
public let city: String?
|
||||
/// The user's state.
|
||||
public let state: String?
|
||||
/// The user's zip code.
|
||||
public let zipCode: String?
|
||||
/// An optional theme that the user prefers.
|
||||
public let theme: Theme?
|
||||
|
||||
public init(
|
||||
|
||||
@@ -41,7 +41,7 @@ struct EffectiveLengthsTable: HTML, Sendable {
|
||||
}
|
||||
|
||||
struct EffectiveLengthGroupTable: HTML, Sendable {
|
||||
let groups: [EquivalentLength.Group]
|
||||
let groups: [EquivalentLength.FittingGroup]
|
||||
|
||||
var body: some HTML<HTMLTag.table> {
|
||||
table {
|
||||
|
||||
@@ -169,7 +169,7 @@ extension DatabaseClient {
|
||||
equipmentInfo: EquipmentInfo,
|
||||
equivalentLengths: EquivalentLength.MaxContainer
|
||||
) -> DesignFrictionRateResponse? {
|
||||
guard let tel = equivalentLengths.total,
|
||||
guard let tel = equivalentLengths.totalEquivalentLength,
|
||||
componentLosses.count > 0
|
||||
else { return nil }
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ extension ManualDClient {
|
||||
func frictionRate(details: Project.Detail) async throws -> ProjectClient.FrictionRateResponse {
|
||||
|
||||
let maxContainer = details.maxContainer
|
||||
guard let totalEquivalentLength = maxContainer.total else {
|
||||
guard let totalEquivalentLength = maxContainer.totalEquivalentLength else {
|
||||
return .init(componentLosses: details.componentLosses, equivalentLengths: maxContainer)
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ extension ManualDClient {
|
||||
return .init(componentLosses: componentLosses, equivalentLengths: lengths)
|
||||
}
|
||||
|
||||
guard let totalEquivalentLength = lengths.total else {
|
||||
guard let totalEquivalentLength = lengths.totalEquivalentLength else {
|
||||
return .init(componentLosses: componentLosses, equivalentLengths: lengths)
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@ extension SiteRoute.View.ProjectRoute.EquivalentLengthRoute.StepThree {
|
||||
}
|
||||
}
|
||||
|
||||
var groups: [EquivalentLength.Group] {
|
||||
var groups = [EquivalentLength.Group]()
|
||||
var groups: [EquivalentLength.FittingGroup] {
|
||||
var groups = [EquivalentLength.FittingGroup]()
|
||||
for (n, group) in groupGroups.enumerated() {
|
||||
groups.append(
|
||||
.init(
|
||||
|
||||
@@ -255,9 +255,9 @@ struct StraightLengthField: HTML, Sendable {
|
||||
struct GroupField: HTML, Sendable {
|
||||
|
||||
let style: EquivalentLength.EffectiveLengthType
|
||||
let group: EquivalentLength.Group?
|
||||
let group: EquivalentLength.FittingGroup?
|
||||
|
||||
init(style: EquivalentLength.EffectiveLengthType, group: EquivalentLength.Group? = nil) {
|
||||
init(style: EquivalentLength.EffectiveLengthType, group: EquivalentLength.FittingGroup? = nil) {
|
||||
self.style = style
|
||||
self.group = group
|
||||
}
|
||||
|
||||
@@ -238,7 +238,7 @@ extension ManualDClient {
|
||||
guard let staticPressure = equipmentInfo?.staticPressure else {
|
||||
return nil
|
||||
}
|
||||
guard let totalEquivalentLength = effectiveLength.total else {
|
||||
guard let totalEquivalentLength = effectiveLength.totalEquivalentLength else {
|
||||
return nil
|
||||
}
|
||||
return try await self.frictionRate(
|
||||
|
||||
Reference in New Issue
Block a user