feat: Begin using Tagged types
All checks were successful
CI / Linux Tests (push) Successful in 5m23s
All checks were successful
CI / Linux Tests (push) Successful in 5m23s
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"originHash" : "c3efcfd33bc1490f59ae406e4e5292027b2d01cafee9fc625652213505df50fb",
|
"originHash" : "300df15f5af26da69cfcf959d16ee1b9eada6101dc105a17fc01ddd244d476b4",
|
||||||
"pins" : [
|
"pins" : [
|
||||||
{
|
{
|
||||||
"identity" : "async-http-client",
|
"identity" : "async-http-client",
|
||||||
@@ -397,6 +397,15 @@
|
|||||||
"version" : "1.6.3"
|
"version" : "1.6.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swift-tagged",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/pointfreeco/swift-tagged",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "3907a9438f5b57d317001dc99f3f11b46882272b",
|
||||||
|
"version" : "0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"identity" : "swift-url-routing",
|
"identity" : "swift-url-routing",
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ let package = Package(
|
|||||||
.package(url: "https://github.com/apple/swift-nio.git", from: "2.65.0"),
|
.package(url: "https://github.com/apple/swift-nio.git", from: "2.65.0"),
|
||||||
.package(url: "https://github.com/pointfreeco/swift-dependencies", from: "1.0.0"),
|
.package(url: "https://github.com/pointfreeco/swift-dependencies", from: "1.0.0"),
|
||||||
.package(url: "https://github.com/pointfreeco/swift-snapshot-testing", from: "1.12.0"),
|
.package(url: "https://github.com/pointfreeco/swift-snapshot-testing", from: "1.12.0"),
|
||||||
|
.package(url: "https://github.com/pointfreeco/swift-tagged", from: "0.6.0"),
|
||||||
.package(url: "https://github.com/pointfreeco/swift-url-routing.git", from: "0.6.2"),
|
.package(url: "https://github.com/pointfreeco/swift-url-routing.git", from: "0.6.2"),
|
||||||
.package(url: "https://github.com/pointfreeco/vapor-routing.git", from: "0.1.3"),
|
.package(url: "https://github.com/pointfreeco/vapor-routing.git", from: "0.1.3"),
|
||||||
.package(url: "https://github.com/pointfreeco/swift-case-paths.git", from: "1.6.0"),
|
.package(url: "https://github.com/pointfreeco/swift-case-paths.git", from: "1.6.0"),
|
||||||
@@ -61,6 +62,12 @@ let package = Package(
|
|||||||
.product(name: "Vapor", package: "vapor"),
|
.product(name: "Vapor", package: "vapor"),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
|
.testTarget(
|
||||||
|
name: "ApiRouteTests",
|
||||||
|
dependencies: [
|
||||||
|
.target(name: "ManualDCore")
|
||||||
|
]
|
||||||
|
),
|
||||||
.target(
|
.target(
|
||||||
name: "AuthClient",
|
name: "AuthClient",
|
||||||
dependencies: [
|
dependencies: [
|
||||||
@@ -137,22 +144,17 @@ let package = Package(
|
|||||||
.target(
|
.target(
|
||||||
name: "ManualDCore",
|
name: "ManualDCore",
|
||||||
dependencies: [
|
dependencies: [
|
||||||
|
.product(name: "CasePaths", package: "swift-case-paths"),
|
||||||
.product(name: "Dependencies", package: "swift-dependencies"),
|
.product(name: "Dependencies", package: "swift-dependencies"),
|
||||||
.product(name: "Fluent", package: "fluent"),
|
.product(name: "Fluent", package: "fluent"),
|
||||||
|
.product(name: "Tagged", package: "swift-tagged"),
|
||||||
.product(name: "URLRouting", package: "swift-url-routing"),
|
.product(name: "URLRouting", package: "swift-url-routing"),
|
||||||
.product(name: "CasePaths", package: "swift-case-paths"),
|
|
||||||
]
|
|
||||||
),
|
|
||||||
.testTarget(
|
|
||||||
name: "ApiRouteTests",
|
|
||||||
dependencies: [
|
|
||||||
.target(name: "ManualDCore")
|
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
.target(
|
.target(
|
||||||
name: "ManualDClient",
|
name: "ManualDClient",
|
||||||
dependencies: [
|
dependencies: [
|
||||||
"ManualDCore",
|
.target(name: "ManualDCore"),
|
||||||
.product(name: "Dependencies", package: "swift-dependencies"),
|
.product(name: "Dependencies", package: "swift-dependencies"),
|
||||||
.product(name: "DependenciesMacros", package: "swift-dependencies"),
|
.product(name: "DependenciesMacros", package: "swift-dependencies"),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ struct DependenciesMiddleware: AsyncMiddleware {
|
|||||||
try await values.yield {
|
try await values.yield {
|
||||||
try await withDependencies {
|
try await withDependencies {
|
||||||
$0.apiController = apiController
|
$0.apiController = apiController
|
||||||
$0.authClient = .live(on: request)
|
$0.auth = .live(on: request)
|
||||||
$0.database = database
|
$0.database = database
|
||||||
// $0.dateFormatter = .liveValue
|
// $0.dateFormatter = .liveValue
|
||||||
$0.viewController = viewController
|
$0.viewController = viewController
|
||||||
|
|||||||
@@ -5,17 +5,23 @@ import ManualDCore
|
|||||||
import Vapor
|
import Vapor
|
||||||
|
|
||||||
extension DependencyValues {
|
extension DependencyValues {
|
||||||
public var authClient: AuthClient {
|
/// Authentication dependency, for handling authentication tasks.
|
||||||
|
public var auth: AuthClient {
|
||||||
get { self[AuthClient.self] }
|
get { self[AuthClient.self] }
|
||||||
set { self[AuthClient.self] = newValue }
|
set { self[AuthClient.self] = newValue }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents authentication tasks that are used in the application.
|
||||||
@DependencyClient
|
@DependencyClient
|
||||||
public struct AuthClient: Sendable {
|
public struct AuthClient: Sendable {
|
||||||
|
/// Create a new user and log them in.
|
||||||
public var createAndLogin: @Sendable (User.Create) async throws -> User
|
public var createAndLogin: @Sendable (User.Create) async throws -> User
|
||||||
|
/// Get the current user.
|
||||||
public var currentUser: @Sendable () throws -> User
|
public var currentUser: @Sendable () throws -> User
|
||||||
|
/// Login a user.
|
||||||
public var login: @Sendable (User.Login) async throws -> User
|
public var login: @Sendable (User.Login) async throws -> User
|
||||||
|
/// Logout a user.
|
||||||
public var logout: @Sendable () throws -> Void
|
public var logout: @Sendable () throws -> Void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,22 +4,33 @@ import FluentKit
|
|||||||
import ManualDCore
|
import ManualDCore
|
||||||
|
|
||||||
extension DependencyValues {
|
extension DependencyValues {
|
||||||
|
/// The database dependency.
|
||||||
public var database: DatabaseClient {
|
public var database: DatabaseClient {
|
||||||
get { self[DatabaseClient.self] }
|
get { self[DatabaseClient.self] }
|
||||||
set { self[DatabaseClient.self] = newValue }
|
set { self[DatabaseClient.self] = newValue }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents the database interactions used by the application.
|
||||||
@DependencyClient
|
@DependencyClient
|
||||||
public struct DatabaseClient: Sendable {
|
public struct DatabaseClient: Sendable {
|
||||||
|
/// Database migrations.
|
||||||
public var migrations: Migrations
|
public var migrations: Migrations
|
||||||
|
/// Interactions with the projects table.
|
||||||
public var projects: Projects
|
public var projects: Projects
|
||||||
|
/// Interactions with the rooms table.
|
||||||
public var rooms: Rooms
|
public var rooms: Rooms
|
||||||
|
/// Interactions with the equipment table.
|
||||||
public var equipment: Equipment
|
public var equipment: Equipment
|
||||||
|
/// Interactions with the component losses table.
|
||||||
public var componentLosses: ComponentLosses
|
public var componentLosses: ComponentLosses
|
||||||
|
/// Interactions with the equivalent lengths table.
|
||||||
public var equivalentLengths: EquivalentLengths
|
public var equivalentLengths: EquivalentLengths
|
||||||
|
/// Interactions with the users table.
|
||||||
public var users: Users
|
public var users: Users
|
||||||
|
/// Interactions with the user profiles table.
|
||||||
public var userProfiles: UserProfiles
|
public var userProfiles: UserProfiles
|
||||||
|
/// Interactions with the trunk sizes table.
|
||||||
public var trunkSizes: TrunkSizes
|
public var trunkSizes: TrunkSizes
|
||||||
|
|
||||||
@DependencyClient
|
@DependencyClient
|
||||||
@@ -147,23 +158,3 @@ extension DatabaseClient: TestDependencyKey {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension DatabaseClient.Migrations: DependencyKey {
|
|
||||||
public static let testValue = Self()
|
|
||||||
|
|
||||||
public static let liveValue = Self(
|
|
||||||
all: {
|
|
||||||
[
|
|
||||||
Project.Migrate(),
|
|
||||||
User.Migrate(),
|
|
||||||
User.Token.Migrate(),
|
|
||||||
User.Profile.Migrate(),
|
|
||||||
ComponentPressureLoss.Migrate(),
|
|
||||||
EquipmentInfo.Migrate(),
|
|
||||||
Room.Migrate(),
|
|
||||||
EquivalentLength.Migrate(),
|
|
||||||
TrunkSize.Migrate(),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|||||||
22
Sources/DatabaseClient/Internal/Migrations.swift
Normal file
22
Sources/DatabaseClient/Internal/Migrations.swift
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import Dependencies
|
||||||
|
import ManualDCore
|
||||||
|
|
||||||
|
extension DatabaseClient.Migrations: DependencyKey {
|
||||||
|
public static let testValue = Self()
|
||||||
|
|
||||||
|
public static let liveValue = Self(
|
||||||
|
all: {
|
||||||
|
[
|
||||||
|
Project.Migrate(),
|
||||||
|
User.Migrate(),
|
||||||
|
User.Token.Migrate(),
|
||||||
|
User.Profile.Migrate(),
|
||||||
|
ComponentPressureLoss.Migrate(),
|
||||||
|
EquipmentInfo.Migrate(),
|
||||||
|
Room.Migrate(),
|
||||||
|
EquivalentLength.Migrate(),
|
||||||
|
TrunkSize.Migrate(),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import Foundation
|
|||||||
import Vapor
|
import Vapor
|
||||||
|
|
||||||
extension DependencyValues {
|
extension DependencyValues {
|
||||||
|
/// Dependency used for file operations.
|
||||||
public var fileClient: FileClient {
|
public var fileClient: FileClient {
|
||||||
get { self[FileClient.self] }
|
get { self[FileClient.self] }
|
||||||
set { self[FileClient.self] = newValue }
|
set { self[FileClient.self] = newValue }
|
||||||
@@ -14,9 +15,27 @@ extension DependencyValues {
|
|||||||
public struct FileClient: Sendable {
|
public struct FileClient: Sendable {
|
||||||
public typealias OnCompleteHandler = @Sendable () async throws -> Void
|
public typealias OnCompleteHandler = @Sendable () async throws -> Void
|
||||||
|
|
||||||
public var writeFile: @Sendable (String, String) async throws -> Void
|
/// Write contents to a file.
|
||||||
public var removeFile: @Sendable (String) async throws -> Void
|
///
|
||||||
public var streamFile: @Sendable (String, @escaping OnCompleteHandler) async throws -> Response
|
/// > Warning: This will overwrite a file if it exists.
|
||||||
|
public var writeFile: @Sendable (_ contents: String, _ path: String) async throws -> Void
|
||||||
|
/// Remove a file.
|
||||||
|
public var removeFile: @Sendable (_ path: String) async throws -> Void
|
||||||
|
/// Stream a file.
|
||||||
|
public var streamFile:
|
||||||
|
@Sendable (_ path: String, @escaping OnCompleteHandler) async throws -> Response
|
||||||
|
|
||||||
|
/// Stream a file at the given path.
|
||||||
|
///
|
||||||
|
/// - Paramters:
|
||||||
|
/// - path: The path to the file to stream.
|
||||||
|
/// - onComplete: Completion handler to run when done streaming the file.
|
||||||
|
public func streamFile(
|
||||||
|
at path: String,
|
||||||
|
onComplete: @escaping OnCompleteHandler = {}
|
||||||
|
) async throws -> Response {
|
||||||
|
try await streamFile(path, onComplete)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension FileClient: TestDependencyKey {
|
extension FileClient: TestDependencyKey {
|
||||||
|
|||||||
@@ -97,16 +97,16 @@ func roundSize(_ size: Double) throws -> Int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func velocity(cfm: Int, roundSize: Int) -> Int {
|
func velocity(cfm: CFM, roundSize: Int) -> Int {
|
||||||
let cfm = Double(cfm)
|
let cfm = Double(cfm.rawValue)
|
||||||
let roundSize = Double(roundSize)
|
let roundSize = Double(roundSize)
|
||||||
let velocity = cfm / (pow(roundSize / 24, 2) * 3.14)
|
let velocity = cfm / (pow(roundSize / 24, 2) * 3.14)
|
||||||
return Int(round(velocity))
|
return Int(round(velocity))
|
||||||
}
|
}
|
||||||
|
|
||||||
func flexSize(_ request: ManualDClient.DuctSizeRequest) throws -> Int {
|
func flexSize(_ cfm: CFM, _ frictionRate: DesignFrictionRate) throws -> Int {
|
||||||
let cfm = pow(Double(request.designCFM), 0.4)
|
let cfm = pow(Double(cfm.rawValue), 0.4)
|
||||||
let fr = pow(request.frictionRate / 1.76, 0.2)
|
let fr = pow(frictionRate.rawValue / 1.76, 0.2)
|
||||||
let size = 0.55 * (cfm / fr)
|
let size = 0.55 * (cfm / fr)
|
||||||
return try roundSize(size)
|
return try roundSize(size)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import Logging
|
|||||||
import ManualDCore
|
import ManualDCore
|
||||||
|
|
||||||
extension DependencyValues {
|
extension DependencyValues {
|
||||||
|
/// Dependency that performs manual-d duct sizing calculations.
|
||||||
public var manualD: ManualDClient {
|
public var manualD: ManualDClient {
|
||||||
get { self[ManualDClient.self] }
|
get { self[ManualDClient.self] }
|
||||||
set { self[ManualDClient.self] = newValue }
|
set { self[ManualDClient.self] = newValue }
|
||||||
@@ -15,12 +16,24 @@ extension DependencyValues {
|
|||||||
///
|
///
|
||||||
@DependencyClient
|
@DependencyClient
|
||||||
public struct ManualDClient: Sendable {
|
public struct ManualDClient: Sendable {
|
||||||
public var ductSize: @Sendable (DuctSizeRequest) async throws -> DuctSizeResponse
|
public var ductSize: @Sendable (CFM, DesignFrictionRate) async throws -> DuctSizeResponse
|
||||||
public var frictionRate: @Sendable (FrictionRateRequest) async throws -> FrictionRate
|
public var frictionRate: @Sendable (FrictionRateRequest) async throws -> FrictionRate
|
||||||
public var totalEquivalentLength: @Sendable (TotalEquivalentLengthRequest) async throws -> Int
|
|
||||||
public var rectangularSize:
|
public var rectangularSize:
|
||||||
@Sendable (RectangularSizeRequest) async throws -> RectangularSizeResponse
|
@Sendable (RectangularSizeRequest) async throws -> RectangularSizeResponse
|
||||||
|
|
||||||
|
public func ductSize(
|
||||||
|
cfm designCFM: Int,
|
||||||
|
frictionRate designFrictionRate: Double
|
||||||
|
) async throws -> DuctSizeResponse {
|
||||||
|
try await ductSize(.init(rawValue: designCFM), .init(rawValue: designFrictionRate))
|
||||||
|
}
|
||||||
|
|
||||||
|
public func ductSize(
|
||||||
|
cfm designCFM: Double,
|
||||||
|
frictionRate designFrictionRate: Double
|
||||||
|
) async throws -> DuctSizeResponse {
|
||||||
|
try await ductSize(.init(rawValue: Int(designCFM)), .init(rawValue: designFrictionRate))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ManualDClient: TestDependencyKey {
|
extension ManualDClient: TestDependencyKey {
|
||||||
@@ -29,19 +42,6 @@ extension ManualDClient: TestDependencyKey {
|
|||||||
|
|
||||||
extension ManualDClient {
|
extension ManualDClient {
|
||||||
|
|
||||||
public struct DuctSizeRequest: Codable, Equatable, Sendable {
|
|
||||||
public let designCFM: Int
|
|
||||||
public let frictionRate: Double
|
|
||||||
|
|
||||||
public init(
|
|
||||||
designCFM: Int,
|
|
||||||
frictionRate: Double
|
|
||||||
) {
|
|
||||||
self.designCFM = designCFM
|
|
||||||
self.frictionRate = frictionRate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct DuctSizeResponse: Codable, Equatable, Sendable {
|
public struct DuctSizeResponse: Codable, Equatable, Sendable {
|
||||||
|
|
||||||
public let calculatedSize: Double
|
public let calculatedSize: Double
|
||||||
@@ -82,31 +82,14 @@ extension ManualDClient {
|
|||||||
public struct FrictionRateResponse: Codable, Equatable, Sendable {
|
public struct FrictionRateResponse: Codable, Equatable, Sendable {
|
||||||
|
|
||||||
public let availableStaticPressure: Double
|
public let availableStaticPressure: Double
|
||||||
public let frictionRate: Double
|
public let frictionRate: DesignFrictionRate
|
||||||
|
|
||||||
public init(availableStaticPressure: Double, frictionRate: Double) {
|
public init(availableStaticPressure: Double, frictionRate: DesignFrictionRate) {
|
||||||
self.availableStaticPressure = availableStaticPressure
|
self.availableStaticPressure = availableStaticPressure
|
||||||
self.frictionRate = frictionRate
|
self.frictionRate = frictionRate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct TotalEquivalentLengthRequest: Codable, Equatable, Sendable {
|
|
||||||
|
|
||||||
public let trunkLengths: [Int]
|
|
||||||
public let runoutLengths: [Int]
|
|
||||||
public let effectiveLengthGroups: [EffectiveLengthGroup]
|
|
||||||
|
|
||||||
public init(
|
|
||||||
trunkLengths: [Int],
|
|
||||||
runoutLengths: [Int],
|
|
||||||
effectiveLengthGroups: [EffectiveLengthGroup]
|
|
||||||
) {
|
|
||||||
self.trunkLengths = trunkLengths
|
|
||||||
self.runoutLengths = runoutLengths
|
|
||||||
self.effectiveLengthGroups = effectiveLengthGroups
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct RectangularSizeRequest: Codable, Equatable, Sendable {
|
public struct RectangularSizeRequest: Codable, Equatable, Sendable {
|
||||||
public let roundSize: Int
|
public let roundSize: Int
|
||||||
public let height: Int
|
public let height: Int
|
||||||
|
|||||||
@@ -4,19 +4,19 @@ import ManualDCore
|
|||||||
|
|
||||||
extension ManualDClient: DependencyKey {
|
extension ManualDClient: DependencyKey {
|
||||||
public static let liveValue: Self = .init(
|
public static let liveValue: Self = .init(
|
||||||
ductSize: { request in
|
ductSize: { cfm, frictionRate in
|
||||||
guard request.designCFM > 0 else {
|
guard cfm > 0 else {
|
||||||
throw ManualDError(message: "Design CFM should be greater than 0.")
|
throw ManualDError(message: "Design CFM should be greater than 0.")
|
||||||
}
|
}
|
||||||
let fr = pow(request.frictionRate, 0.5)
|
let fr = pow(frictionRate.rawValue, 0.5)
|
||||||
let ductulatorSize = pow(Double(request.designCFM) / (3.12 * fr), 0.38)
|
let ductulatorSize = pow(Double(cfm.rawValue) / (3.12 * fr), 0.38)
|
||||||
let finalSize = try roundSize(ductulatorSize)
|
let finalSize = try roundSize(ductulatorSize)
|
||||||
let flexSize = try flexSize(request)
|
let flexSize = try flexSize(cfm, frictionRate)
|
||||||
return .init(
|
return .init(
|
||||||
calculatedSize: ductulatorSize,
|
calculatedSize: ductulatorSize,
|
||||||
finalSize: finalSize,
|
finalSize: finalSize,
|
||||||
flexSize: flexSize,
|
flexSize: flexSize,
|
||||||
velocity: velocity(cfm: request.designCFM, roundSize: finalSize)
|
velocity: velocity(cfm: cfm, roundSize: finalSize)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
frictionRate: { request in
|
frictionRate: { request in
|
||||||
@@ -28,14 +28,17 @@ extension ManualDClient: DependencyKey {
|
|||||||
let totalComponentLosses = request.componentPressureLosses.total
|
let totalComponentLosses = request.componentPressureLosses.total
|
||||||
let availableStaticPressure = request.externalStaticPressure - totalComponentLosses
|
let availableStaticPressure = request.externalStaticPressure - totalComponentLosses
|
||||||
let frictionRate = availableStaticPressure * 100.0 / Double(request.totalEffectiveLength)
|
let frictionRate = availableStaticPressure * 100.0 / Double(request.totalEffectiveLength)
|
||||||
return .init(availableStaticPressure: availableStaticPressure, value: frictionRate)
|
return .init(
|
||||||
},
|
availableStaticPressure: availableStaticPressure,
|
||||||
totalEquivalentLength: { request in
|
value: .init(rawValue: frictionRate)
|
||||||
let trunkLengths = request.trunkLengths.reduce(0) { $0 + $1 }
|
)
|
||||||
let runoutLengths = request.runoutLengths.reduce(0) { $0 + $1 }
|
|
||||||
let groupLengths = request.effectiveLengthGroups.totalEffectiveLength
|
|
||||||
return trunkLengths + runoutLengths + groupLengths
|
|
||||||
},
|
},
|
||||||
|
// totalEquivalentLength: { request in
|
||||||
|
// let trunkLengths = request.trunkLengths.reduce(0) { $0 + $1 }
|
||||||
|
// let runoutLengths = request.runoutLengths.reduce(0) { $0 + $1 }
|
||||||
|
// let groupLengths = request.effectiveLengthGroups.totalEffectiveLength
|
||||||
|
// return trunkLengths + runoutLengths + groupLengths
|
||||||
|
// },
|
||||||
rectangularSize: { request in
|
rectangularSize: { request in
|
||||||
let width = (Double.pi * (pow(Double(request.roundSize) / 2.0, 2.0))) / Double(request.height)
|
let width = (Double.pi * (pow(Double(request.roundSize) / 2.0, 2.0))) / Double(request.height)
|
||||||
return .init(height: request.height, width: Int(width.rounded(.toNearestOrEven)))
|
return .init(height: request.height, width: Int(width.rounded(.toNearestOrEven)))
|
||||||
|
|||||||
@@ -1,4 +1,17 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
import Tagged
|
||||||
|
|
||||||
|
extension Tagged where RawValue == Double {
|
||||||
|
public func string(digits: Int = 2) -> String {
|
||||||
|
rawValue.string(digits: digits)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Tagged where RawValue == Int {
|
||||||
|
public func string() -> String {
|
||||||
|
rawValue.string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extension Double {
|
extension Double {
|
||||||
|
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ public struct FrictionRate: Codable, Equatable, Sendable {
|
|||||||
/// minus the ``ComponentPressureLoss``es for the project.
|
/// minus the ``ComponentPressureLoss``es for the project.
|
||||||
public let availableStaticPressure: Double
|
public let availableStaticPressure: Double
|
||||||
/// The calculated design friction rate value.
|
/// The calculated design friction rate value.
|
||||||
public let value: Double
|
public let value: DesignFrictionRate
|
||||||
/// Whether the design friction rate is within a valid range.
|
/// Whether the design friction rate is within a valid range.
|
||||||
public var hasErrors: Bool { error != nil }
|
public var hasErrors: Bool { error != nil }
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
availableStaticPressure: Double,
|
availableStaticPressure: Double,
|
||||||
value: Double
|
value: DesignFrictionRate
|
||||||
) {
|
) {
|
||||||
self.availableStaticPressure = availableStaticPressure
|
self.availableStaticPressure = availableStaticPressure
|
||||||
self.value = value
|
self.value = value
|
||||||
|
|||||||
7
Sources/ManualDCore/TaggedTypes.swift
Normal file
7
Sources/ManualDCore/TaggedTypes.swift
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import Tagged
|
||||||
|
|
||||||
|
public enum CFMTag {}
|
||||||
|
public typealias CFM = Tagged<CFMTag, Int>
|
||||||
|
|
||||||
|
public enum DesignFrictionRateTag {}
|
||||||
|
public typealias DesignFrictionRate = Tagged<DesignFrictionRateTag, Double>
|
||||||
@@ -52,7 +52,8 @@ extension ManualDClient {
|
|||||||
let coolingCFM = coolingPercent * Double(sharedRequest.equipmentInfo.coolingCFM)
|
let coolingCFM = coolingPercent * Double(sharedRequest.equipmentInfo.coolingCFM)
|
||||||
let designCFM = DuctSizes.DesignCFM(heating: heatingCFM, cooling: coolingCFM)
|
let designCFM = DuctSizes.DesignCFM(heating: heatingCFM, cooling: coolingCFM)
|
||||||
let sizes = try await self.ductSize(
|
let sizes = try await self.ductSize(
|
||||||
.init(designCFM: Int(designCFM.value), frictionRate: sharedRequest.designFrictionRate)
|
cfm: designCFM.value,
|
||||||
|
frictionRate: sharedRequest.designFrictionRate
|
||||||
)
|
)
|
||||||
|
|
||||||
for n in 1...room.registerCount {
|
for n in 1...room.registerCount {
|
||||||
@@ -111,7 +112,8 @@ extension ManualDClient {
|
|||||||
let coolingCFM = coolingPercent * Double(sharedRequest.equipmentInfo.coolingCFM)
|
let coolingCFM = coolingPercent * Double(sharedRequest.equipmentInfo.coolingCFM)
|
||||||
let designCFM = DuctSizes.DesignCFM(heating: heatingCFM, cooling: coolingCFM)
|
let designCFM = DuctSizes.DesignCFM(heating: heatingCFM, cooling: coolingCFM)
|
||||||
let sizes = try await self.ductSize(
|
let sizes = try await self.ductSize(
|
||||||
.init(designCFM: Int(designCFM.value), frictionRate: sharedRequest.designFrictionRate)
|
cfm: designCFM.value,
|
||||||
|
frictionRate: sharedRequest.designFrictionRate
|
||||||
)
|
)
|
||||||
var width: Int? = nil
|
var width: Int? = nil
|
||||||
if let height = trunk.height {
|
if let height = trunk.height {
|
||||||
|
|||||||
@@ -42,13 +42,10 @@ extension ProjectClient: DependencyKey {
|
|||||||
request: database.makePdfRequest(projectID)
|
request: database.makePdfRequest(projectID)
|
||||||
)
|
)
|
||||||
|
|
||||||
let response = try await fileClient.streamFile(
|
let response = try await fileClient.streamFile(at: pdfResponse.pdfPath) {
|
||||||
pdfResponse.pdfPath,
|
try await fileClient.removeFile(pdfResponse.htmlPath)
|
||||||
{
|
try await fileClient.removeFile(pdfResponse.pdfPath)
|
||||||
try await fileClient.removeFile(pdfResponse.htmlPath)
|
}
|
||||||
try await fileClient.removeFile(pdfResponse.pdfPath)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
response.headers.replaceOrAdd(name: .contentType, value: "application/octet-stream")
|
response.headers.replaceOrAdd(name: .contentType, value: "application/octet-stream")
|
||||||
response.headers.replaceOrAdd(
|
response.headers.replaceOrAdd(
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import Elementary
|
import Elementary
|
||||||
|
import Tagged
|
||||||
|
|
||||||
public struct Badge<Inner: HTML>: HTML, Sendable where Inner: Sendable {
|
public struct Badge<Inner: HTML>: HTML, Sendable where Inner: Sendable {
|
||||||
|
|
||||||
@@ -25,4 +26,12 @@ extension Badge where Inner == Number {
|
|||||||
public init(number: Double, digits: Int = 2) {
|
public init(number: Double, digits: Int = 2) {
|
||||||
self.inner = Number(number, digits: digits)
|
self.inner = Number(number, digits: digits)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public init<T>(number: Tagged<T, Int>) {
|
||||||
|
self.inner = Number(number.rawValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
public init<T>(number: Tagged<T, Double>, digits: Int = 2) {
|
||||||
|
self.inner = Number(number.rawValue, digits: digits)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,14 +54,14 @@ extension ViewController: DependencyKey {
|
|||||||
extension ViewController.Request {
|
extension ViewController.Request {
|
||||||
|
|
||||||
func currentUser() throws -> User {
|
func currentUser() throws -> User {
|
||||||
@Dependency(\.authClient.currentUser) var currentUser
|
@Dependency(\.auth.currentUser) var currentUser
|
||||||
return try currentUser()
|
return try currentUser()
|
||||||
}
|
}
|
||||||
|
|
||||||
func authenticate(
|
func authenticate(
|
||||||
_ login: User.Login
|
_ login: User.Login
|
||||||
) async throws -> User {
|
) async throws -> User {
|
||||||
@Dependency(\.authClient) var auth
|
@Dependency(\.auth) var auth
|
||||||
return try await auth.login(login)
|
return try await auth.login(login)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ extension ViewController.Request {
|
|||||||
func createAndAuthenticate(
|
func createAndAuthenticate(
|
||||||
_ signup: User.Create
|
_ signup: User.Create
|
||||||
) async throws -> User {
|
) async throws -> User {
|
||||||
@Dependency(\.authClient) var auth
|
@Dependency(\.auth) var auth
|
||||||
return try await auth.createAndLogin(signup)
|
return try await auth.createAndLogin(signup)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,59 +24,13 @@ struct ManualDClientTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
func ductSize() async throws {
|
func ductSize() async throws {
|
||||||
let response = try await manualD.ductSize(
|
let response = try await manualD.ductSize(88, 0.06)
|
||||||
.init(designCFM: 88, frictionRate: 0.06)
|
|
||||||
)
|
|
||||||
#expect(numberFormatter.string(for: response.calculatedSize) == "6.07")
|
#expect(numberFormatter.string(for: response.calculatedSize) == "6.07")
|
||||||
#expect(response.finalSize == 7)
|
#expect(response.finalSize == 7)
|
||||||
#expect(response.flexSize == 7)
|
#expect(response.flexSize == 7)
|
||||||
#expect(response.velocity == 329)
|
#expect(response.velocity == 329)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Test
|
|
||||||
// func frictionRate() async throws {
|
|
||||||
// let response = try await manualD.frictionRate(
|
|
||||||
// .init(
|
|
||||||
// externalStaticPressure: 0.5,
|
|
||||||
// componentPressureLosses: .mock,
|
|
||||||
// totalEffectiveLength: 185
|
|
||||||
// )
|
|
||||||
// )
|
|
||||||
// #expect(numberFormatter.string(for: response.availableStaticPressure) == "0.11")
|
|
||||||
// #expect(numberFormatter.string(for: response.frictionRate) == "0.06")
|
|
||||||
// }
|
|
||||||
|
|
||||||
// @Test
|
|
||||||
// func frictionRateFails() async throws {
|
|
||||||
// await #expect(throws: ManualDError.self) {
|
|
||||||
// _ = try await manualD.frictionRate(
|
|
||||||
// .init(
|
|
||||||
// externalStaticPressure: 0.5,
|
|
||||||
// componentPressureLosses: .mock,
|
|
||||||
// totalEffectiveLength: 0
|
|
||||||
// )
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Test
|
|
||||||
func totalEffectiveLength() async throws {
|
|
||||||
let response = try await manualD.totalEquivalentLength(
|
|
||||||
.init(
|
|
||||||
trunkLengths: [25],
|
|
||||||
runoutLengths: [10],
|
|
||||||
effectiveLengthGroups: [
|
|
||||||
// NOTE: These are made up and may not correspond to actual manual-d group tel's.
|
|
||||||
EffectiveLengthGroup(group: 1, letter: "a", effectiveLength: 20, category: .supply),
|
|
||||||
EffectiveLengthGroup(group: 2, letter: "a", effectiveLength: 30, category: .supply),
|
|
||||||
EffectiveLengthGroup(group: 3, letter: "a", effectiveLength: 10, category: .supply),
|
|
||||||
EffectiveLengthGroup(group: 12, letter: "a", effectiveLength: 10, category: .supply),
|
|
||||||
]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
#expect(response == 105)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
func equivalentRectangularDuct() async throws {
|
func equivalentRectangularDuct() async throws {
|
||||||
let response = try await manualD.rectangularSize(.init(round: 7, height: 8))
|
let response = try await manualD.rectangularSize(.init(round: 7, height: 8))
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ struct ViewControllerTests {
|
|||||||
func login() async throws {
|
func login() async throws {
|
||||||
try await withDependencies {
|
try await withDependencies {
|
||||||
$0.viewController = .liveValue
|
$0.viewController = .liveValue
|
||||||
$0.authClient = .failing
|
$0.auth = .failing
|
||||||
} operation: {
|
} operation: {
|
||||||
@Dependency(\.viewController) var viewController
|
@Dependency(\.viewController) var viewController
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ struct ViewControllerTests {
|
|||||||
func signup() async throws {
|
func signup() async throws {
|
||||||
try await withDependencies {
|
try await withDependencies {
|
||||||
$0.viewController = .liveValue
|
$0.viewController = .liveValue
|
||||||
$0.authClient = .failing
|
$0.auth = .failing
|
||||||
} operation: {
|
} operation: {
|
||||||
@Dependency(\.viewController) var viewController
|
@Dependency(\.viewController) var viewController
|
||||||
|
|
||||||
@@ -163,7 +163,7 @@ struct ViewControllerTests {
|
|||||||
|
|
||||||
return try await withDependencies {
|
return try await withDependencies {
|
||||||
$0.viewController = .liveValue
|
$0.viewController = .liveValue
|
||||||
$0.authClient.currentUser = { user }
|
$0.auth.currentUser = { user }
|
||||||
$0.database.userProfiles.fetch = { _ in profile }
|
$0.database.userProfiles.fetch = { _ in profile }
|
||||||
$0.manualD = .liveValue
|
$0.manualD = .liveValue
|
||||||
try await updateDependencies(&$0)
|
try await updateDependencies(&$0)
|
||||||
|
|||||||
Reference in New Issue
Block a user