feat: Adds createMany for rooms, in prep for parsing / uploading a csv file of room loads.
All checks were successful
CI / Linux Tests (push) Successful in 7m0s

This commit is contained in:
2026-02-04 21:06:05 -05:00
parent 10dd0dac82
commit 5f03056534
6 changed files with 87 additions and 70 deletions

View File

@@ -6,16 +6,14 @@
"version": "os-provided",
"ppa": "false"
},
"ghcr.io/swift-server-community/swift-devcontainer-features/jemalloc:1": { },
"ghcr.io/swift-server-community/swift-devcontainer-features/swift-format:0": { },
"ghcr.io/swift-server-community/swift-devcontainer-features/foundationnetworking:1": {},
"ghcr.io/devcontainers-extra/features/markdownlint-cli2:1": {},
"ghcr.io/jsburckhardt/devcontainer-features/just:1": {},
"ghcr.io/rocker-org/devcontainer-features/pandoc:1": {},
//"ghcr.io/devcontainers/features/docker-in-docker:2": {},
"ghcr.io/wxw-matt/devcontainer-features/apt:latest": {
"packages": "weasyprint gnupg2 tmux"
}
},
"ghcr.io/swift-server-community/swift-devcontainer-features/jemalloc:1": { },
},
"runArgs": [
"--cap-add=SYS_PTRACE",
@@ -23,9 +21,20 @@
"seccomp=unconfined"
],
"remoteEnv": {
"TERM": "xterm-256color"
// Set TERM, prevents problems when "xterm-ghostty" get's passed from host,
// which causes weird typing and display problems.
"TERM": "xterm-256color",
// Less backtrace error warnings from swift.
"SWIFT_BACKTRACE": "enable=no"
},
"remoteUser": "swift",
"forwardPorts": [8080],
"mounts": [
{
"type": "bind",
"source": "${localEnv:HOME}/.local/share/nvim",
"target": "/home/swift/.local/share/nvim"
}
]
}

View File

@@ -90,6 +90,7 @@ public struct DatabaseClient: Sendable {
@DependencyClient
public struct Rooms: Sendable {
public var create: @Sendable (Room.Create) async throws -> Room
public var createMany: @Sendable ([Room.Create]) async throws -> [Room]
public var delete: @Sendable (Room.ID) async throws -> Void
public var deleteRectangularSize:
@Sendable (Room.ID, Room.RectangularSize.ID) async throws -> Room

View File

@@ -15,6 +15,13 @@ extension DatabaseClient.Rooms: TestDependencyKey {
try await model.validateAndSave(on: database)
return try model.toDTO()
},
createMany: { rooms in
try await rooms.asyncMap { request in
let model = try request.toModel()
try await model.validateAndSave(on: database)
return try model.toDTO()
}
},
delete: { id in
guard let model = try await RoomModel.find(id, on: database) else {
throw NotFoundError()

View File

@@ -0,0 +1,41 @@
import Foundation
extension Sequence {
// Taken from: https://forums.swift.org/t/are-there-any-kind-of-asyncmap-method-for-a-normal-sequence/77354/7
func asyncMap<Result: Sendable>(
_ transform: @escaping @Sendable (Element) async throws -> Result
) async rethrows -> [Result] where Element: Sendable {
try await withThrowingTaskGroup(of: (Int, Result).self) { group in
var i = 0
var iterator = self.makeIterator()
var results = [Result?]()
results.reserveCapacity(underestimatedCount)
func submitTask() throws {
try Task.checkCancellation()
if let element = iterator.next() {
results.append(nil)
group.addTask { [i] in try await (i, transform(element)) }
i += 1
}
}
// Add initial tasks
for _ in 0..<ProcessInfo.processInfo.processorCount {
try submitTask()
}
// Submit more tasks as results complete
while let (index, result) = try await group.next() {
results[index] = result
try submitTask()
}
return results.compactMap { $0 }
}
}
}

14
TODO.md
View File

@@ -5,14 +5,14 @@
- [x] Add postgres / mysql support
- [ ] Opensource / license ??
- [ ] Figure out domain to host (currently thinking ductcalc.pro)
- [ ] Logo / navbar name may have to change if it's not duct-calc.
- [ ] MainPage meta items will have to change also
- [ ] Logo / navbar name may have to change if it's not duct-calc.
- [ ] MainPage meta items will have to change also
- [ ] Add ability for either sensible or total load while specifying a room load.
- CoolCalc current version specifies the sensible cooling for a room break down,
and currently we require the total load and calculate sensible based on project
shr.
- CoolCalc current version specifies the sensible cooling for a room break down,
and currently we require the total load and calculate sensible based on project
shr.
- [ ] Add ability to associate room load / airflow with another room.
- [ ] Trunk size form, room / register selection is wonky when labels are long.
- They will overlap each other making it difficult to read / decipher which checkbox belongs
to which label.
- They will overlap each other making it difficult to read / decipher which checkbox belongs
to which label.
- [ ] Add select all rooms for trunks, useful for sizing main supply or return trunks.

View File

@@ -43,6 +43,22 @@ struct RoomTests {
}
}
@Test
func createMany() async throws {
try await withTestUserAndProject { _, project in
@Dependency(\.database.rooms) var rooms
let created = try await rooms.createMany([
.init(projectID: project.id, name: "Test 1", heatingLoad: 1234, coolingTotal: 1234),
.init(projectID: project.id, name: "Test 2", heatingLoad: 1234, coolingTotal: 1234),
])
#expect(created.count == 2)
#expect(created[0].name == "Test 1")
#expect(created[1].name == "Test 2")
}
}
@Test
func notFound() async throws {
try await withDatabase {
@@ -128,61 +144,4 @@ struct RoomTests {
// }
}
}
// @Test(
// arguments: [
// Room.Update(
// name: "",
// heatingLoad: 12345,
// coolingTotal: 12344,
// coolingSensible: nil,
// registerCount: 1
// ),
// Room.Update(
// name: "Test",
// heatingLoad: -12345,
// coolingTotal: 12344,
// coolingSensible: nil,
// registerCount: 1
// ),
// Room.Update(
// name: "Test",
// heatingLoad: 12345,
// coolingTotal: -12344,
// coolingSensible: nil,
// registerCount: 1
// ),
// Room.Update(
// name: "Test",
// heatingLoad: 12345,
// coolingTotal: 12344,
// coolingSensible: -123,
// registerCount: 1
// ),
// Room.Update(
// name: "Test",
// heatingLoad: 12345,
// coolingTotal: 12344,
// coolingSensible: nil,
// registerCount: -1
// ),
// Room.Update(
// name: "",
// heatingLoad: -12345,
// coolingTotal: -12344,
// coolingSensible: -1,
// registerCount: -1
// ),
// ]
// )
// func updateValidations(room: Room.Update) throws {
// #expect(throws: (any Error).self) {
// // do {
// try room.validate()
// // } catch {
// // print("\(error)")
// // throw error
// // }
// }
// }
}