This repository has been archived by the owner on Aug 21, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
model.go
125 lines (97 loc) · 2.24 KB
/
model.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
117
118
119
120
121
122
123
124
125
package gondolier
import (
"reflect"
"strings"
)
const (
tagname = "gondolier"
)
var (
knownTypes = []string{"time.Time",
"sql.NullBool",
"sql.NullFloat64",
"sql.NullInt64",
"sql.NullString"}
)
// MetaModel is the description of a model for migration.
type MetaModel struct {
ModelName string
Fields []MetaField
}
// MetaField is the description of one field of a model for migration.
type MetaField struct {
Name string
Tags []MetaTag
}
// MetaTag is the description of a tag for a model field.
type MetaTag struct {
Name string
Value string
}
func buildMetaModel(model interface{}) MetaModel {
return MetaModel{getModelName(model),
getModelFields(model)}
}
func getModelName(model interface{}) string {
t := reflect.TypeOf(model)
kind := t.Kind()
if kind == reflect.Ptr {
t = t.Elem()
kind = t.Kind()
}
if kind != reflect.Struct {
panic("Passed type is not a struct")
}
if t.Kind() == reflect.Ptr {
return t.Elem().Name()
}
return t.Name()
}
func getModelFields(model interface{}) []MetaField {
val := reflect.ValueOf(model)
if val.Kind() == reflect.Ptr {
val = val.Elem()
}
fields := make([]MetaField, 0)
for i := 0; i < val.NumField(); i++ {
field := val.Type().Field(i)
tag := field.Tag.Get(tagname)
kind := field.Type.Kind()
if tag == "" || tag == "-" {
continue
}
if (kind == reflect.Struct || kind == reflect.Ptr || kind == reflect.Interface) &&
!isKnownType(field.Type.String()) {
panic("The type for field '" + field.Name + "' is invalid")
}
fields = append(fields, MetaField{field.Name, parseTag(tag)})
}
return fields
}
func parseTag(tag string) []MetaTag {
tags := make([]MetaTag, 0)
elements := strings.Split(tag, ";")
for _, e := range elements {
e = strings.TrimSpace(e)
if e == "" {
continue
}
nv := strings.Split(e, ":")
if len(nv) == 1 {
tags = append(tags, MetaTag{"", strings.TrimSpace(nv[0])})
} else if len(nv) == 2 {
tags = append(tags, MetaTag{strings.TrimSpace(nv[0]), strings.TrimSpace(nv[1])})
} else {
panic("Too many or too few meta field tag separators")
}
}
return tags
}
func isKnownType(typename string) bool {
for _, knownType := range knownTypes {
if typename == knownType {
return true
}
}
return false
}