-
Notifications
You must be signed in to change notification settings - Fork 11
/
struct.go
116 lines (99 loc) · 2.35 KB
/
struct.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package triplestore
import (
"fmt"
"math/rand"
"reflect"
"time"
)
const (
predTag = "predicate"
bnodeTag = "bnode"
)
func init() {
rand.Seed(time.Now().UnixNano())
}
// Convert a Struct or ptr to Struct into triples
// using field tags.
// For each struct's field a triple is created:
// - Subject: function first argument
// - Predicate: tag value
// - Literal: actual field value according to field's type
// Unsupported types are ignored
func TriplesFromStruct(sub string, i interface{}, bnodes ...bool) (out []Triple) {
var isBnode bool
if len(bnodes) > 0 {
isBnode = bnodes[0]
}
val := reflect.ValueOf(i)
var ok bool
val, ok = getStructOrPtrToStruct(val)
if !ok {
return
}
st := val.Type()
for i := 0; i < st.NumField(); i++ {
field, fVal := st.Field(i), val.Field(i)
if !fVal.CanInterface() {
continue
}
intValue := reflect.ValueOf(fVal.Interface())
if intValue.Kind() == reflect.Ptr && intValue.IsNil() {
continue
}
pred := field.Tag.Get(predTag)
if tri, ok := buildTripleFromVal(sub, pred, fVal, isBnode); ok {
out = append(out, tri)
}
bnode, embedded := field.Tag.Lookup(bnodeTag)
fVal, ok := getStructOrPtrToStruct(fVal)
if embedded && ok {
if bnode == "" {
bnode = fmt.Sprintf("%x", rand.Uint32())
}
tris := TriplesFromStruct(bnode, fVal.Interface(), true)
out = append(out, tris...)
if embedPred, hasPred := field.Tag.Lookup(predTag); hasPred {
out = append(out, SubjPred(sub, embedPred).Bnode(bnode))
}
continue
}
switch fVal.Kind() {
case reflect.Slice:
length := fVal.Len()
for i := 0; i < length; i++ {
sliceVal := fVal.Index(i)
if tri, ok := buildTripleFromVal(sub, pred, sliceVal, isBnode); ok {
out = append(out, tri)
}
}
}
}
return
}
func buildTripleFromVal(sub, pred string, v reflect.Value, bnode bool) (Triple, bool) {
if !v.CanInterface() {
return nil, false
}
if pred == "" {
return nil, false
}
objLit, err := ObjectLiteral(v.Interface())
if err != nil {
return nil, false
}
if bnode {
return BnodePred(sub, pred).Object(objLit), true
}
return SubjPred(sub, pred).Object(objLit), true
}
func getStructOrPtrToStruct(v reflect.Value) (reflect.Value, bool) {
switch v.Kind() {
case reflect.Struct:
return v, true
case reflect.Ptr:
if v.Elem().Kind() == reflect.Struct {
return v.Elem(), true
}
}
return v, false
}