@@ -23,30 +23,29 @@ var (
23
23
24
24
type Triple struct {
25
25
Direction int // 0 for incoming, 1 for outgoing
26
- Subject string
27
- Predicate string
28
- Object string
26
+ Subject * Node
27
+ Predicate * Predicate
28
+ Object * Node
29
29
}
30
30
31
31
type Node struct {
32
32
Key string
33
33
Type oam.AssetType
34
34
Since time.Time
35
35
Attributes map [string ]string
36
- Properties []Property
36
+ Properties []* Property
37
37
}
38
38
39
39
type Predicate struct {
40
40
Label string
41
41
Type oam.RelationType
42
42
Since time.Time
43
43
Attributes map [string ]string
44
- Properties []Property
44
+ Properties []* Property
45
45
}
46
46
47
47
type Property struct {
48
48
Name string
49
- Value string
50
49
Since time.Time
51
50
Type oam.PropertyType
52
51
Attributes map [string ]string
@@ -55,14 +54,29 @@ type Property struct {
55
54
func ParseTriple (triple string ) (* Triple , error ) {
56
55
tristrs , direction , err := splitTriple (triple )
57
56
if err != nil {
58
- return nil , fmt .Errorf ("invalid triple format: %w" , err )
57
+ return nil , fmt .Errorf ("invalid triple format: %v" , err )
58
+ }
59
+
60
+ subject , err := parseNode (tristrs [0 ])
61
+ if err != nil {
62
+ return nil , fmt .Errorf ("invalid subject: %v" , err )
63
+ }
64
+
65
+ predicate , err := parsePredicate (tristrs [1 ])
66
+ if err != nil {
67
+ return nil , fmt .Errorf ("invalid predicate: %v" , err )
68
+ }
69
+
70
+ object , err := parseNode (tristrs [2 ])
71
+ if err != nil {
72
+ return nil , fmt .Errorf ("invalid object: %v" , err )
59
73
}
60
74
61
75
return & Triple {
62
76
Direction : direction ,
63
- Subject : parts [ 0 ] ,
64
- Predicate : parts [ 1 ] ,
65
- Object : parts [ 2 ] ,
77
+ Subject : subject ,
78
+ Predicate : predicate ,
79
+ Object : object ,
66
80
}, nil
67
81
}
68
82
@@ -71,7 +85,7 @@ func splitTriple(triple string) ([]string, int, error) {
71
85
var tstrs []string
72
86
direction := DirectionOutgoing
73
87
74
- for i := 0 ; i < 3 ; i ++ {
88
+ for _ , i := range [] int { 0 , 1 , 2 } {
75
89
substr := triple [start :]
76
90
77
91
sidx := strings .Index (substr , "<" )
@@ -91,7 +105,9 @@ func splitTriple(triple string) ([]string, int, error) {
91
105
92
106
start += eidx + 1 // Move past the closing angle bracket
93
107
substr = triple [start :]
94
- if i == 0 {
108
+
109
+ switch i {
110
+ case 0 :
95
111
if idx := strings .Index (substr , "<-" ); idx != - 1 && (idx == 0 || idx == 1 ) {
96
112
direction = DirectionIncoming
97
113
start += 2 // Move past the "<-"
@@ -100,7 +116,7 @@ func splitTriple(triple string) ([]string, int, error) {
100
116
} else {
101
117
return nil , direction , fmt .Errorf ("triple must contain a hyphen or '<-' after the subject" )
102
118
}
103
- } else if i == 1 {
119
+ case 1 :
104
120
if idx := strings .Index (substr , "->" ); idx != - 1 && (idx == 0 || idx == 1 ) {
105
121
if direction == DirectionIncoming {
106
122
return nil , direction , fmt .Errorf ("triple cannot have both '<-' and '->'" )
@@ -119,3 +135,153 @@ func splitTriple(triple string) ([]string, int, error) {
119
135
120
136
return tstrs , direction , nil
121
137
}
138
+
139
+ func parseNode (nodestr string ) (* Node , error ) {
140
+ parts := strings .Split (nodestr , "," )
141
+ if len (parts ) == 1 && parts [0 ] == "*" {
142
+ return & Node {
143
+ Key : "*" ,
144
+ Attributes : make (map [string ]string ),
145
+ }, nil
146
+ }
147
+
148
+ node := & Node {Attributes : make (map [string ]string )}
149
+ for i , part := range parts {
150
+ kv := strings .Split (part , ":" )
151
+ if len (kv ) != 2 {
152
+ return nil , fmt .Errorf ("%s must be a key/value pair separated by a ':'" , part )
153
+ }
154
+ k := strings .TrimSpace (kv [0 ])
155
+ v := strings .TrimSpace (kv [1 ])
156
+
157
+ if i == 0 {
158
+ atype , err := keyToAssetType (k )
159
+ if err != nil {
160
+ return nil , err
161
+ }
162
+ node .Type = atype
163
+ node .Key = v
164
+ } else if strings .EqualFold (k , "prop" ) {
165
+ prop , err := parseProperty (v )
166
+ if err != nil {
167
+ return nil , fmt .Errorf ("invalid property: %v" , err )
168
+ }
169
+ node .Properties = append (node .Properties , prop )
170
+ } else if strings .EqualFold (k , "since" ) {
171
+ since , err := time .Parse (time .DateOnly , v )
172
+ if err != nil {
173
+ return nil , err
174
+ }
175
+ node .Since = since
176
+ } else {
177
+ node .Attributes [k ] = v
178
+ }
179
+ }
180
+
181
+ return node , nil
182
+ }
183
+
184
+ func keyToAssetType (key string ) (oam.AssetType , error ) {
185
+ for _ , atype := range oam .AssetList {
186
+ if strings .EqualFold (string (atype ), key ) {
187
+ return atype , nil
188
+ }
189
+ }
190
+ return "" , fmt .Errorf ("%s does not match any asset type" , key )
191
+ }
192
+
193
+ func parsePredicate (predstr string ) (* Predicate , error ) {
194
+ parts := strings .Split (predstr , "," )
195
+ if len (parts ) == 1 && parts [0 ] == "*" {
196
+ return & Predicate {
197
+ Label : "*" ,
198
+ Attributes : make (map [string ]string ),
199
+ }, nil
200
+ }
201
+
202
+ pred := & Predicate {Attributes : make (map [string ]string )}
203
+ for i , part := range parts {
204
+ kv := strings .Split (part , ":" )
205
+ if len (kv ) != 2 {
206
+ return nil , fmt .Errorf ("%s must be a key/value pair separated by a ':'" , part )
207
+ }
208
+ k := strings .TrimSpace (kv [0 ])
209
+ v := strings .TrimSpace (kv [1 ])
210
+
211
+ if i == 0 {
212
+ rtype , err := keyToRelationType (k )
213
+ if err != nil {
214
+ return nil , err
215
+ }
216
+ pred .Type = rtype
217
+ pred .Label = v
218
+ } else if strings .EqualFold (k , "prop" ) {
219
+ prop , err := parseProperty (v )
220
+ if err != nil {
221
+ return nil , fmt .Errorf ("invalid property: %v" , err )
222
+ }
223
+ pred .Properties = append (pred .Properties , prop )
224
+ } else if strings .EqualFold (k , "since" ) {
225
+ since , err := time .Parse (time .DateOnly , v )
226
+ if err != nil {
227
+ return nil , err
228
+ }
229
+ pred .Since = since
230
+ } else {
231
+ pred .Attributes [k ] = v
232
+ }
233
+ }
234
+
235
+ return pred , nil
236
+ }
237
+
238
+ func keyToRelationType (key string ) (oam.RelationType , error ) {
239
+ for _ , rtype := range oam .RelationList {
240
+ if strings .EqualFold (string (rtype ), key ) {
241
+ return rtype , nil
242
+ }
243
+ }
244
+ return "" , fmt .Errorf ("%s does not match any relation type" , key )
245
+ }
246
+
247
+ func parseProperty (propstr string ) (* Property , error ) {
248
+ parts := strings .Split (propstr , "," )
249
+ prop := & Property {Attributes : make (map [string ]string )}
250
+
251
+ for i , part := range parts {
252
+ kv := strings .Split (part , ":" )
253
+ if len (kv ) != 2 {
254
+ return nil , fmt .Errorf ("%s must be a key/value pair separated by a ':'" , part )
255
+ }
256
+ k := strings .TrimSpace (kv [0 ])
257
+ v := strings .TrimSpace (kv [1 ])
258
+
259
+ if i == 0 {
260
+ ptype , err := keyToPropertyType (k )
261
+ if err != nil {
262
+ return nil , err
263
+ }
264
+ prop .Type = ptype
265
+ prop .Name = v
266
+ } else if strings .EqualFold (k , "since" ) {
267
+ since , err := time .Parse (time .DateOnly , v )
268
+ if err != nil {
269
+ return nil , err
270
+ }
271
+ prop .Since = since
272
+ } else {
273
+ prop .Attributes [k ] = v
274
+ }
275
+ }
276
+
277
+ return prop , nil
278
+ }
279
+
280
+ func keyToPropertyType (key string ) (oam.PropertyType , error ) {
281
+ for _ , ptype := range oam .PropertyList {
282
+ if strings .EqualFold (string (ptype ), key ) {
283
+ return ptype , nil
284
+ }
285
+ }
286
+ return "" , fmt .Errorf ("%s does not match any property type" , key )
287
+ }
0 commit comments