Skip to content

Commit 5df5b8c

Browse files
committed
updates to triple parsing
1 parent c805063 commit 5df5b8c

File tree

1 file changed

+179
-13
lines changed

1 file changed

+179
-13
lines changed

internal/assoc/triple.go

Lines changed: 179 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,30 +23,29 @@ var (
2323

2424
type Triple struct {
2525
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
2929
}
3030

3131
type Node struct {
3232
Key string
3333
Type oam.AssetType
3434
Since time.Time
3535
Attributes map[string]string
36-
Properties []Property
36+
Properties []*Property
3737
}
3838

3939
type Predicate struct {
4040
Label string
4141
Type oam.RelationType
4242
Since time.Time
4343
Attributes map[string]string
44-
Properties []Property
44+
Properties []*Property
4545
}
4646

4747
type Property struct {
4848
Name string
49-
Value string
5049
Since time.Time
5150
Type oam.PropertyType
5251
Attributes map[string]string
@@ -55,14 +54,29 @@ type Property struct {
5554
func ParseTriple(triple string) (*Triple, error) {
5655
tristrs, direction, err := splitTriple(triple)
5756
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)
5973
}
6074

6175
return &Triple{
6276
Direction: direction,
63-
Subject: parts[0],
64-
Predicate: parts[1],
65-
Object: parts[2],
77+
Subject: subject,
78+
Predicate: predicate,
79+
Object: object,
6680
}, nil
6781
}
6882

@@ -71,7 +85,7 @@ func splitTriple(triple string) ([]string, int, error) {
7185
var tstrs []string
7286
direction := DirectionOutgoing
7387

74-
for i := 0; i < 3; i++ {
88+
for _, i := range []int{0, 1, 2} {
7589
substr := triple[start:]
7690

7791
sidx := strings.Index(substr, "<")
@@ -91,7 +105,9 @@ func splitTriple(triple string) ([]string, int, error) {
91105

92106
start += eidx + 1 // Move past the closing angle bracket
93107
substr = triple[start:]
94-
if i == 0 {
108+
109+
switch i {
110+
case 0:
95111
if idx := strings.Index(substr, "<-"); idx != -1 && (idx == 0 || idx == 1) {
96112
direction = DirectionIncoming
97113
start += 2 // Move past the "<-"
@@ -100,7 +116,7 @@ func splitTriple(triple string) ([]string, int, error) {
100116
} else {
101117
return nil, direction, fmt.Errorf("triple must contain a hyphen or '<-' after the subject")
102118
}
103-
} else if i == 1 {
119+
case 1:
104120
if idx := strings.Index(substr, "->"); idx != -1 && (idx == 0 || idx == 1) {
105121
if direction == DirectionIncoming {
106122
return nil, direction, fmt.Errorf("triple cannot have both '<-' and '->'")
@@ -119,3 +135,153 @@ func splitTriple(triple string) ([]string, int, error) {
119135

120136
return tstrs, direction, nil
121137
}
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

Comments
 (0)