Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,6 @@ let package = Package(
.product(name: "VaporTesting", package: "vapor", condition: .when(traits: ["ServerVapor"])),
]
),
]
],
swiftLanguageModes: [.v5, .version("6")]
)
2 changes: 1 addition & 1 deletion Sources/Haystack/Bool.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ extension Bool: Val {
}
}

extension Bool: Comparable {
extension Bool: @retroactive Comparable {
public static func < (lhs: Bool, rhs: Bool) -> Bool {
return !lhs && rhs // false is less than true
}
Expand Down
53 changes: 50 additions & 3 deletions Sources/HaystackServer/HaystackServer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ public final class HaystackServer: API, Sendable {
let recordStore: RecordStore
let historyStore: HistoryStore
let watchStore: WatchStore
let navPath: [String]

let onInvokeAction: @Sendable (Haystack.Ref, String, [String: any Haystack.Val]) async throws -> Haystack.Grid
let onEval: @Sendable (String) async throws -> Haystack.Grid
Expand All @@ -15,6 +16,7 @@ public final class HaystackServer: API, Sendable {
recordStore: RecordStore,
historyStore: HistoryStore,
watchStore: WatchStore,
navPath: [String] = ["site", "equip", "point"],
onInvokeAction: @escaping @Sendable (Haystack.Ref, String, [String: any Haystack.Val]) async throws -> Haystack.Grid = { _, _, _ in
GridBuilder().toGrid()
},
Expand All @@ -25,6 +27,7 @@ public final class HaystackServer: API, Sendable {
self.recordStore = recordStore
self.historyStore = historyStore
self.watchStore = watchStore
self.navPath = navPath
self.onInvokeAction = onInvokeAction
self.onEval = onEval
}
Expand Down Expand Up @@ -106,9 +109,52 @@ public final class HaystackServer: API, Sendable {
return gb.toGrid()
}

public func nav(navId _: Haystack.Ref?) async throws -> Haystack.Grid {
// TODO: Implement
return GridBuilder().toGrid()
public func nav(navId parentId: Haystack.Ref?) async throws -> Haystack.Grid {
let gb = Haystack.GridBuilder()
try gb.addCol(name: "navId")
guard navPath.count > 0 else {
return gb.toGrid()
}
guard let parentId = parentId else {
// If no input, just return the first level of navigation
for result in try await recordStore.read(filter: "\(navPath[0])", limit: nil) {
var navResult = result
navResult["navId"] = result["id"]
try gb.addRow(navResult)
}
return gb.toGrid()
}
guard let parentDict = try await recordStore.read(ids: [parentId]).first else {
throw ServerError.idNotFound(parentId)
}
// Find the first component of the navPath that matches a tag on the input dict
var parentNavPathIndex: Int? = nil
for index in 0 ..< navPath.count {
let component = navPath[index]
if parentDict.has(component) {
parentNavPathIndex = index
}
}
guard let parentNavPathIndex = parentNavPathIndex else {
throw ServerError.navPathComponentNotFound(navPath)
}
guard parentNavPathIndex < navPath.count - 1 else {
// Parent is a navPath leaf. No further navigation is possible, so return nothing.
return gb.toGrid()
}
let parentNavComponent = navPath[parentNavPathIndex]
let childNavComponent = navPath[parentNavPathIndex + 1]
// Read children using child component and inferring parent ref tag
let children = try await recordStore.read(
filter: "\(childNavComponent) and \(parentNavComponent)Ref == \(parentId.toZinc())",
limit: nil
)
for child in children {
var navChild = child
navChild["navId"] = child["id"]
try gb.addRow(navChild)
}
return gb.toGrid()
}

public func hisRead(id: Haystack.Ref, range: Haystack.HisReadRange) async throws -> Haystack.Grid {
Expand Down Expand Up @@ -199,5 +245,6 @@ public final class HaystackServer: API, Sendable {

public enum ServerError: Error {
case idNotFound(Haystack.Ref)
case navPathComponentNotFound([String])
case watchNotFound(String)
}
11 changes: 6 additions & 5 deletions Tests/HaystackServerTests/HaystackServerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -198,13 +198,14 @@ struct HaystackServerTests {
watchStore: InMemoryWatchStore()
)

var grid = try await server.nav(navId: Ref("site"))
// TODO: Implement nav
// #expect(grid.compactMap { ($0["id"] as? Ref)?.val }.sorted() == ["equip"])
var grid = try await server.nav(navId: nil)
#expect(grid.compactMap { ($0["navId"] as? Ref)?.val }.sorted() == ["site"])

grid = try await server.nav(navId: Ref("site"))
#expect(grid.compactMap { ($0["navId"] as? Ref)?.val }.sorted() == ["equip"])

grid = try await server.nav(navId: Ref("equip"))
// TODO: Implement nav
// #expect(grid.compactMap { ($0["id"] as? Ref)?.val }.sorted() == ["point"])
#expect(grid.compactMap { ($0["navId"] as? Ref)?.val }.sorted() == ["point"])
}

@Test func hisRead() async throws {
Expand Down
Loading