forked from YaoApp/gou
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmodel.go
188 lines (165 loc) · 4.02 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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
package gou
import (
"fmt"
"io"
"os"
"strings"
"github.com/yaoapp/gou/helper"
"github.com/yaoapp/kun/exception"
"github.com/yaoapp/kun/log"
"github.com/yaoapp/kun/maps"
"github.com/yaoapp/xun/capsule"
)
// Models 已载入模型
var Models = map[string]*Model{}
// SetModelLogger 设定模型 Logger
func SetModelLogger(output io.Writer, level log.Level) {
log.SetLevel(level)
log.SetOutput(output)
}
// LoadModelReturn 加载数据模型
func LoadModelReturn(source string, name string) (model *Model, err error) {
defer func() { err = exception.Catch(recover()) }()
model = LoadModel(source, name)
return model, nil
}
// LoadModel 载入数据模型
func LoadModel(source string, name string) *Model {
var input io.Reader = nil
if strings.HasPrefix(source, "file://") {
filename := strings.TrimPrefix(source, "file://")
file, err := os.Open(filename)
if err != nil {
exception.Err(err, 400).Throw()
}
defer file.Close()
input = file
} else {
input = strings.NewReader(source)
}
metadata := MetaData{}
err := helper.UnmarshalFile(input, &metadata)
if err != nil {
exception.Err(err, 400).Throw()
}
mod := &Model{
Name: name,
Source: source,
MetaData: metadata,
}
// 解析常用数值
columns := map[string]*Column{} // 字段映射表
columnNames := []interface{}{} // 字段名称清单
PrimaryKey := "id" // 字段主键
uniqueColumns := []*Column{} // 唯一字段清单
// 补充字段(软删除)
if mod.MetaData.Option.SoftDeletes {
mod.MetaData.Columns = append(mod.MetaData.Columns, Column{
Label: "删除标记",
Name: "deleted_at",
Type: "timestamp",
Comment: "删除标记",
Nullable: true,
})
}
// 补充时间戳(软删除)
if mod.MetaData.Option.Timestamps {
mod.MetaData.Columns = append(mod.MetaData.Columns,
Column{
Label: "创建时间",
Name: "created_at",
Type: "timestamp",
Comment: "创建时间",
Nullable: true,
},
Column{
Label: "更新时间",
Name: "updated_at",
Type: "timestamp",
Comment: "更新时间",
Nullable: true,
},
)
}
for i, column := range mod.MetaData.Columns {
mod.MetaData.Columns[i].model = mod // 链接所属模型
columns[column.Name] = &mod.MetaData.Columns[i]
columnNames = append(columnNames, column.Name)
if strings.ToLower(column.Type) == "id" {
PrimaryKey = column.Name
}
// 唯一字段
if column.Unique {
uniqueColumns = append(uniqueColumns, columns[column.Name])
}
}
// 唯一索引
for _, index := range mod.MetaData.Indexes {
if strings.ToLower(index.Type) == "unique" {
for _, name := range index.Columns {
col, has := columns[name]
if has {
uniqueColumns = append(uniqueColumns, col)
}
}
}
}
mod.Columns = columns
mod.ColumnNames = columnNames
mod.PrimaryKey = PrimaryKey
mod.UniqueColumns = uniqueColumns
mod.Driver = capsule.Schema().MustGetConnection().Config.Driver
Models[name] = mod
return mod
}
// Reload 更新模型
func (mod *Model) Reload() *Model {
mod = LoadModel(mod.Source, mod.Name)
return mod
}
// Migrate 数据迁移
func (mod *Model) Migrate(force bool) {
table := mod.MetaData.Table.Name
schema := capsule.Schema()
if force {
schema.DropTableIfExists(table)
}
if !schema.MustHasTable(table) {
mod.SchemaTableCreate()
return
}
mod.SchemaTableUpgrade()
}
// Select 读取已加载模型
func Select(name string) *Model {
mod, has := Models[name]
if !has {
exception.New(
fmt.Sprintf("Model:%s; 尚未加载", name),
400,
).Throw()
}
return mod
}
// Validate 数值校验
func (mod *Model) Validate(row maps.MapStrAny) []ValidateResponse {
res := []ValidateResponse{}
for name, value := range row {
column, has := mod.Columns[name]
if !has {
continue
}
// 如果允许为 null
if value == nil && column.Nullable {
continue
}
success, messages := column.Validate(value, row)
if !success {
res = append(res, ValidateResponse{
Column: column.Name,
Messages: messages,
})
}
}
return res
}