@@ -7,6 +7,7 @@ public final class HaystackServer: API, Sendable {
7
7
let recordStore : RecordStore
8
8
let historyStore : HistoryStore
9
9
let watchStore : WatchStore
10
+ let navPath : [ String ]
10
11
11
12
let onInvokeAction : @Sendable ( Haystack . Ref , String , [ String : any Haystack . Val ] ) async throws -> Haystack . Grid
12
13
let onEval : @Sendable ( String) async throws -> Haystack . Grid
@@ -15,6 +16,7 @@ public final class HaystackServer: API, Sendable {
15
16
recordStore: RecordStore ,
16
17
historyStore: HistoryStore ,
17
18
watchStore: WatchStore ,
19
+ navPath: [ String ] = [ " site " , " equip " , " point " ] ,
18
20
onInvokeAction: @escaping @Sendable ( Haystack . Ref , String , [ String : any Haystack . Val ] ) async throws -> Haystack . Grid = { _, _, _ in
19
21
GridBuilder ( ) . toGrid ( )
20
22
} ,
@@ -25,6 +27,7 @@ public final class HaystackServer: API, Sendable {
25
27
self . recordStore = recordStore
26
28
self . historyStore = historyStore
27
29
self . watchStore = watchStore
30
+ self . navPath = navPath
28
31
self . onInvokeAction = onInvokeAction
29
32
self . onEval = onEval
30
33
}
@@ -106,9 +109,52 @@ public final class HaystackServer: API, Sendable {
106
109
return gb. toGrid ( )
107
110
}
108
111
109
- public func nav( navId _: Haystack . Ref ? ) async throws -> Haystack . Grid {
110
- // TODO: Implement
111
- return GridBuilder ( ) . toGrid ( )
112
+ public func nav( navId parentId: Haystack . Ref ? ) async throws -> Haystack . Grid {
113
+ let gb = Haystack . GridBuilder ( )
114
+ try gb. addCol ( name: " navId " )
115
+ guard navPath. count > 0 else {
116
+ return gb. toGrid ( )
117
+ }
118
+ guard let parentId = parentId else {
119
+ // If no input, just return the first level of navigation
120
+ for result in try await recordStore. read ( filter: " \( navPath [ 0 ] ) " , limit: nil ) {
121
+ var navResult = result
122
+ navResult [ " navId " ] = result [ " id " ]
123
+ try gb. addRow ( navResult)
124
+ }
125
+ return gb. toGrid ( )
126
+ }
127
+ guard let parentDict = try await recordStore. read ( ids: [ parentId] ) . first else {
128
+ throw ServerError . idNotFound ( parentId)
129
+ }
130
+ // Find the first component of the navPath that matches a tag on the input dict
131
+ var parentNavPathIndex: Int? = nil
132
+ for index in 0 ..< navPath. count {
133
+ let component = navPath [ index]
134
+ if parentDict. has ( component) {
135
+ parentNavPathIndex = index
136
+ }
137
+ }
138
+ guard let parentNavPathIndex = parentNavPathIndex else {
139
+ throw ServerError . navPathComponentNotFound ( navPath)
140
+ }
141
+ guard parentNavPathIndex < navPath. count - 1 else {
142
+ // Parent is a navPath leaf. No further navigation is possible, so return nothing.
143
+ return gb. toGrid ( )
144
+ }
145
+ let parentNavComponent = navPath [ parentNavPathIndex]
146
+ let childNavComponent = navPath [ parentNavPathIndex + 1 ]
147
+ // Read children using child component and inferring parent ref tag
148
+ let children = try await recordStore. read (
149
+ filter: " \( childNavComponent) and \( parentNavComponent) Ref == \( parentId. toZinc ( ) ) " ,
150
+ limit: nil
151
+ )
152
+ for child in children {
153
+ var navChild = child
154
+ navChild [ " navId " ] = child [ " id " ]
155
+ try gb. addRow ( navChild)
156
+ }
157
+ return gb. toGrid ( )
112
158
}
113
159
114
160
public func hisRead ( id: Haystack . Ref, range: Haystack . HisReadRange) async throws -> Haystack. Grid {
@@ -199,5 +245,6 @@ public final class HaystackServer: API, Sendable {
199
245
200
246
public enum ServerError: Error {
201
247
case idNotFound( Haystack . Ref)
248
+ case navPathComponentNotFound( [ String] )
202
249
case watchNotFound( String)
203
250
}
0 commit comments