· 6 years ago · Apr 17, 2019, 03:27 PM
1
2<!DOCTYPE html>
3<html>
4 <head>
5 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
6 <style>
7 body {
8 background: black;
9 color: rgb(80, 80, 80);
10 }
11 body, pre, #legend span {
12 font-family: Menlo, monospace;
13 font-weight: bold;
14 }
15 #topbar {
16 background: black;
17 position: fixed;
18 top: 0; left: 0; right: 0;
19 height: 42px;
20 border-bottom: 1px solid rgb(80, 80, 80);
21 }
22 #content {
23 margin-top: 50px;
24 }
25 #nav, #legend {
26 float: left;
27 margin-left: 10px;
28 }
29 #legend {
30 margin-top: 12px;
31 }
32 #nav {
33 margin-top: 10px;
34 }
35 #legend span {
36 margin: 0 5px;
37 }
38 .cov0 { color: rgb(192, 0, 0) }
39.cov1 { color: rgb(128, 128, 128) }
40.cov2 { color: rgb(116, 140, 131) }
41.cov3 { color: rgb(104, 152, 134) }
42.cov4 { color: rgb(92, 164, 137) }
43.cov5 { color: rgb(80, 176, 140) }
44.cov6 { color: rgb(68, 188, 143) }
45.cov7 { color: rgb(56, 200, 146) }
46.cov8 { color: rgb(44, 212, 149) }
47.cov9 { color: rgb(32, 224, 152) }
48.cov10 { color: rgb(20, 236, 155) }
49
50 </style>
51 </head>
52 <body>
53 <div id="topbar">
54 <div id="nav">
55 <select id="files">
56
57 <option value="file0">github.com/jinzhu/gorm/association.go (95.3%)</option>
58
59 <option value="file1">github.com/jinzhu/gorm/callback.go (91.4%)</option>
60
61 <option value="file2">github.com/jinzhu/gorm/callback_create.go (91.2%)</option>
62
63 <option value="file3">github.com/jinzhu/gorm/callback_delete.go (95.0%)</option>
64
65 <option value="file4">github.com/jinzhu/gorm/callback_query.go (91.3%)</option>
66
67 <option value="file5">github.com/jinzhu/gorm/callback_query_preload.go (91.3%)</option>
68
69 <option value="file6">github.com/jinzhu/gorm/callback_row_query.go (100.0%)</option>
70
71 <option value="file7">github.com/jinzhu/gorm/callback_save.go (95.5%)</option>
72
73 <option value="file8">github.com/jinzhu/gorm/callback_update.go (96.2%)</option>
74
75 <option value="file9">github.com/jinzhu/gorm/dialect.go (84.8%)</option>
76
77 <option value="file10">github.com/jinzhu/gorm/dialect_common.go (34.8%)</option>
78
79 <option value="file11">github.com/jinzhu/gorm/dialect_mysql.go (1.2%)</option>
80
81 <option value="file12">github.com/jinzhu/gorm/dialect_postgres.go (3.3%)</option>
82
83 <option value="file13">github.com/jinzhu/gorm/dialect_sqlite3.go (77.3%)</option>
84
85 <option value="file14">github.com/jinzhu/gorm/dialects/mssql/mssql.go (6.3%)</option>
86
87 <option value="file15">github.com/jinzhu/gorm/dialects/postgres/postgres.go (0.0%)</option>
88
89 <option value="file16">github.com/jinzhu/gorm/errors.go (68.2%)</option>
90
91 <option value="file17">github.com/jinzhu/gorm/field.go (91.3%)</option>
92
93 <option value="file18">github.com/jinzhu/gorm/join_table_handler.go (92.4%)</option>
94
95 <option value="file19">github.com/jinzhu/gorm/logger.go (21.4%)</option>
96
97 <option value="file20">github.com/jinzhu/gorm/main.go (83.5%)</option>
98
99 <option value="file21">github.com/jinzhu/gorm/model_struct.go (90.1%)</option>
100
101 <option value="file22">github.com/jinzhu/gorm/scope.go (89.4%)</option>
102
103 <option value="file23">github.com/jinzhu/gorm/search.go (94.2%)</option>
104
105 <option value="file24">github.com/jinzhu/gorm/utils.go (92.1%)</option>
106
107 </select>
108 </div>
109 <div id="legend">
110 <span>not tracked</span>
111
112 <span class="cov0">not covered</span>
113 <span class="cov8">covered</span>
114
115 </div>
116 </div>
117 <div id="content">
118
119 <pre class="file" id="file0" style="display: none">package gorm
120
121import (
122 "errors"
123 "fmt"
124 "reflect"
125)
126
127// Association Mode contains some helper methods to handle relationship things easily.
128type Association struct {
129 Error error
130 scope *Scope
131 column string
132 field *Field
133}
134
135// Find find out all related associations
136func (association *Association) Find(value interface{}) *Association <span class="cov8" title="1">{
137 association.scope.related(value, association.column)
138 return association.setErr(association.scope.db.Error)
139}</span>
140
141// Append append new associations for many2many, has_many, replace current association for has_one, belongs_to
142func (association *Association) Append(values ...interface{}) *Association <span class="cov8" title="1">{
143 if association.Error != nil </span><span class="cov0" title="0">{
144 return association
145 }</span>
146
147 <span class="cov8" title="1">if relationship := association.field.Relationship; relationship.Kind == "has_one" </span><span class="cov8" title="1">{
148 return association.Replace(values...)
149 }</span>
150 <span class="cov8" title="1">return association.saveAssociations(values...)</span>
151}
152
153// Replace replace current associations with new one
154func (association *Association) Replace(values ...interface{}) *Association <span class="cov8" title="1">{
155 if association.Error != nil </span><span class="cov0" title="0">{
156 return association
157 }</span>
158
159 <span class="cov8" title="1">var (
160 relationship = association.field.Relationship
161 scope = association.scope
162 field = association.field.Field
163 newDB = scope.NewDB()
164 )
165
166 // Append new values
167 association.field.Set(reflect.Zero(association.field.Field.Type()))
168 association.saveAssociations(values...)
169
170 // Belongs To
171 if relationship.Kind == "belongs_to" </span><span class="cov8" title="1">{
172 // Set foreign key to be null when clearing value (length equals 0)
173 if len(values) == 0 </span><span class="cov8" title="1">{
174 // Set foreign key to be nil
175 var foreignKeyMap = map[string]interface{}{}
176 for _, foreignKey := range relationship.ForeignDBNames </span><span class="cov8" title="1">{
177 foreignKeyMap[foreignKey] = nil
178 }</span>
179 <span class="cov8" title="1">association.setErr(newDB.Model(scope.Value).UpdateColumn(foreignKeyMap).Error)</span>
180 }
181 } else<span class="cov8" title="1"> {
182 // Polymorphic Relations
183 if relationship.PolymorphicDBName != "" </span><span class="cov8" title="1">{
184 newDB = newDB.Where(fmt.Sprintf("%v = ?", scope.Quote(relationship.PolymorphicDBName)), relationship.PolymorphicValue)
185 }</span>
186
187 // Delete Relations except new created
188 <span class="cov8" title="1">if len(values) > 0 </span><span class="cov8" title="1">{
189 var associationForeignFieldNames, associationForeignDBNames []string
190 if relationship.Kind == "many_to_many" </span><span class="cov8" title="1">{
191 // if many to many relations, get association fields name from association foreign keys
192 associationScope := scope.New(reflect.New(field.Type()).Interface())
193 for idx, dbName := range relationship.AssociationForeignFieldNames </span><span class="cov8" title="1">{
194 if field, ok := associationScope.FieldByName(dbName); ok </span><span class="cov8" title="1">{
195 associationForeignFieldNames = append(associationForeignFieldNames, field.Name)
196 associationForeignDBNames = append(associationForeignDBNames, relationship.AssociationForeignDBNames[idx])
197 }</span>
198 }
199 } else<span class="cov8" title="1"> {
200 // If has one/many relations, use primary keys
201 for _, field := range scope.New(reflect.New(field.Type()).Interface()).PrimaryFields() </span><span class="cov8" title="1">{
202 associationForeignFieldNames = append(associationForeignFieldNames, field.Name)
203 associationForeignDBNames = append(associationForeignDBNames, field.DBName)
204 }</span>
205 }
206
207 <span class="cov8" title="1">newPrimaryKeys := scope.getColumnAsArray(associationForeignFieldNames, field.Interface())
208
209 if len(newPrimaryKeys) > 0 </span><span class="cov8" title="1">{
210 sql := fmt.Sprintf("%v NOT IN (%v)", toQueryCondition(scope, associationForeignDBNames), toQueryMarks(newPrimaryKeys))
211 newDB = newDB.Where(sql, toQueryValues(newPrimaryKeys)...)
212 }</span>
213 }
214
215 <span class="cov8" title="1">if relationship.Kind == "many_to_many" </span><span class="cov8" title="1">{
216 // if many to many relations, delete related relations from join table
217 var sourceForeignFieldNames []string
218
219 for _, dbName := range relationship.ForeignFieldNames </span><span class="cov8" title="1">{
220 if field, ok := scope.FieldByName(dbName); ok </span><span class="cov8" title="1">{
221 sourceForeignFieldNames = append(sourceForeignFieldNames, field.Name)
222 }</span>
223 }
224
225 <span class="cov8" title="1">if sourcePrimaryKeys := scope.getColumnAsArray(sourceForeignFieldNames, scope.Value); len(sourcePrimaryKeys) > 0 </span><span class="cov8" title="1">{
226 newDB = newDB.Where(fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, relationship.ForeignDBNames), toQueryMarks(sourcePrimaryKeys)), toQueryValues(sourcePrimaryKeys)...)
227
228 association.setErr(relationship.JoinTableHandler.Delete(relationship.JoinTableHandler, newDB))
229 }</span>
230 } else<span class="cov8" title="1"> if relationship.Kind == "has_one" || relationship.Kind == "has_many" </span><span class="cov8" title="1">{
231 // has_one or has_many relations, set foreign key to be nil (TODO or delete them?)
232 var foreignKeyMap = map[string]interface{}{}
233 for idx, foreignKey := range relationship.ForeignDBNames </span><span class="cov8" title="1">{
234 foreignKeyMap[foreignKey] = nil
235 if field, ok := scope.FieldByName(relationship.AssociationForeignFieldNames[idx]); ok </span><span class="cov8" title="1">{
236 newDB = newDB.Where(fmt.Sprintf("%v = ?", scope.Quote(foreignKey)), field.Field.Interface())
237 }</span>
238 }
239
240 <span class="cov8" title="1">fieldValue := reflect.New(association.field.Field.Type()).Interface()
241 association.setErr(newDB.Model(fieldValue).UpdateColumn(foreignKeyMap).Error)</span>
242 }
243 }
244 <span class="cov8" title="1">return association</span>
245}
246
247// Delete remove relationship between source & passed arguments, but won't delete those arguments
248func (association *Association) Delete(values ...interface{}) *Association <span class="cov8" title="1">{
249 if association.Error != nil </span><span class="cov0" title="0">{
250 return association
251 }</span>
252
253 <span class="cov8" title="1">var (
254 relationship = association.field.Relationship
255 scope = association.scope
256 field = association.field.Field
257 newDB = scope.NewDB()
258 )
259
260 if len(values) == 0 </span><span class="cov0" title="0">{
261 return association
262 }</span>
263
264 <span class="cov8" title="1">var deletingResourcePrimaryFieldNames, deletingResourcePrimaryDBNames []string
265 for _, field := range scope.New(reflect.New(field.Type()).Interface()).PrimaryFields() </span><span class="cov8" title="1">{
266 deletingResourcePrimaryFieldNames = append(deletingResourcePrimaryFieldNames, field.Name)
267 deletingResourcePrimaryDBNames = append(deletingResourcePrimaryDBNames, field.DBName)
268 }</span>
269
270 <span class="cov8" title="1">deletingPrimaryKeys := scope.getColumnAsArray(deletingResourcePrimaryFieldNames, values...)
271
272 if relationship.Kind == "many_to_many" </span><span class="cov8" title="1">{
273 // source value's foreign keys
274 for idx, foreignKey := range relationship.ForeignDBNames </span><span class="cov8" title="1">{
275 if field, ok := scope.FieldByName(relationship.ForeignFieldNames[idx]); ok </span><span class="cov8" title="1">{
276 newDB = newDB.Where(fmt.Sprintf("%v = ?", scope.Quote(foreignKey)), field.Field.Interface())
277 }</span>
278 }
279
280 // get association's foreign fields name
281 <span class="cov8" title="1">var associationScope = scope.New(reflect.New(field.Type()).Interface())
282 var associationForeignFieldNames []string
283 for _, associationDBName := range relationship.AssociationForeignFieldNames </span><span class="cov8" title="1">{
284 if field, ok := associationScope.FieldByName(associationDBName); ok </span><span class="cov8" title="1">{
285 associationForeignFieldNames = append(associationForeignFieldNames, field.Name)
286 }</span>
287 }
288
289 // association value's foreign keys
290 <span class="cov8" title="1">deletingPrimaryKeys := scope.getColumnAsArray(associationForeignFieldNames, values...)
291 sql := fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, relationship.AssociationForeignDBNames), toQueryMarks(deletingPrimaryKeys))
292 newDB = newDB.Where(sql, toQueryValues(deletingPrimaryKeys)...)
293
294 association.setErr(relationship.JoinTableHandler.Delete(relationship.JoinTableHandler, newDB))</span>
295 } else<span class="cov8" title="1"> {
296 var foreignKeyMap = map[string]interface{}{}
297 for _, foreignKey := range relationship.ForeignDBNames </span><span class="cov8" title="1">{
298 foreignKeyMap[foreignKey] = nil
299 }</span>
300
301 <span class="cov8" title="1">if relationship.Kind == "belongs_to" </span><span class="cov8" title="1">{
302 // find with deleting relation's foreign keys
303 primaryKeys := scope.getColumnAsArray(relationship.AssociationForeignFieldNames, values...)
304 newDB = newDB.Where(
305 fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, relationship.ForeignDBNames), toQueryMarks(primaryKeys)),
306 toQueryValues(primaryKeys)...,
307 )
308
309 // set foreign key to be null if there are some records affected
310 modelValue := reflect.New(scope.GetModelStruct().ModelType).Interface()
311 if results := newDB.Model(modelValue).UpdateColumn(foreignKeyMap); results.Error == nil </span><span class="cov8" title="1">{
312 if results.RowsAffected > 0 </span><span class="cov8" title="1">{
313 scope.updatedAttrsWithValues(foreignKeyMap)
314 }</span>
315 } else<span class="cov0" title="0"> {
316 association.setErr(results.Error)
317 }</span>
318 } else<span class="cov8" title="1"> if relationship.Kind == "has_one" || relationship.Kind == "has_many" </span><span class="cov8" title="1">{
319 // find all relations
320 primaryKeys := scope.getColumnAsArray(relationship.AssociationForeignFieldNames, scope.Value)
321 newDB = newDB.Where(
322 fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, relationship.ForeignDBNames), toQueryMarks(primaryKeys)),
323 toQueryValues(primaryKeys)...,
324 )
325
326 // only include those deleting relations
327 newDB = newDB.Where(
328 fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, deletingResourcePrimaryDBNames), toQueryMarks(deletingPrimaryKeys)),
329 toQueryValues(deletingPrimaryKeys)...,
330 )
331
332 // set matched relation's foreign key to be null
333 fieldValue := reflect.New(association.field.Field.Type()).Interface()
334 association.setErr(newDB.Model(fieldValue).UpdateColumn(foreignKeyMap).Error)
335 }</span>
336 }
337
338 // Remove deleted records from source's field
339 <span class="cov8" title="1">if association.Error == nil </span><span class="cov8" title="1">{
340 if field.Kind() == reflect.Slice </span><span class="cov8" title="1">{
341 leftValues := reflect.Zero(field.Type())
342
343 for i := 0; i < field.Len(); i++ </span><span class="cov8" title="1">{
344 reflectValue := field.Index(i)
345 primaryKey := scope.getColumnAsArray(deletingResourcePrimaryFieldNames, reflectValue.Interface())[0]
346 var isDeleted = false
347 for _, pk := range deletingPrimaryKeys </span><span class="cov8" title="1">{
348 if equalAsString(primaryKey, pk) </span><span class="cov8" title="1">{
349 isDeleted = true
350 break</span>
351 }
352 }
353 <span class="cov8" title="1">if !isDeleted </span><span class="cov8" title="1">{
354 leftValues = reflect.Append(leftValues, reflectValue)
355 }</span>
356 }
357
358 <span class="cov8" title="1">association.field.Set(leftValues)</span>
359 } else<span class="cov8" title="1"> if field.Kind() == reflect.Struct </span><span class="cov8" title="1">{
360 primaryKey := scope.getColumnAsArray(deletingResourcePrimaryFieldNames, field.Interface())[0]
361 for _, pk := range deletingPrimaryKeys </span><span class="cov8" title="1">{
362 if equalAsString(primaryKey, pk) </span><span class="cov8" title="1">{
363 association.field.Set(reflect.Zero(field.Type()))
364 break</span>
365 }
366 }
367 }
368 }
369
370 <span class="cov8" title="1">return association</span>
371}
372
373// Clear remove relationship between source & current associations, won't delete those associations
374func (association *Association) Clear() *Association <span class="cov8" title="1">{
375 return association.Replace()
376}</span>
377
378// Count return the count of current associations
379func (association *Association) Count() int <span class="cov8" title="1">{
380 var (
381 count = 0
382 relationship = association.field.Relationship
383 scope = association.scope
384 fieldValue = association.field.Field.Interface()
385 query = scope.DB()
386 )
387
388 switch relationship.Kind {
389</span> case "many_to_many":
390 </span>query<span class="cov8" title="1"> = relationship.JoinTableHandler.JoinWith(relationship.JoinTableHandle</span><span class="cov8" title="1">r, query, scope.Value)
391 case "has_many", "has_one":
392 primaryKeys := scope.getColumnAsArray(relationship.AssociationForeignFieldNames, scope.Value)
393 query = query.Where(
394 fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, relationship.ForeignDBNames), toQueryMarks(primaryKeys)),
395 toQueryValues(primaryKeys)...,
396 </span>)
397</span> case "belongs_to":
398 primaryKeys := scope.getColumnAsArray(relationship.ForeignFieldNames, scope.Value)
399 query = query.Where(
400 fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, relationship.AssociationForeignDBNames), toQueryMarks(primaryKeys)),
401 toQueryValues(primaryKeys)...,
402 </span>)
403 }
404
405</span> if relationship.PolymorphicType != "" {
406 query = query.Where(
407 fmt.Sprintf("%v.%v = ?", scope.New(fieldValue).QuotedTableName(), scope.Quote(relationship.PolymorphicDBName)),
408 relationship.PolymorphicValue,
409 </span>)
410 }
411
412</span> if err := query.Model(fieldValue).Count(&count).Error; err != nil {
413 </span>association.Error = err
414 <span class="cov8" title="1">}
415</span> return count
416}
417
418// saveAssociations save passed values as associations
419func (association *Association) saveAssociations(values ...interface{}) *Association {
420 var (
421 scope = association.scope
422 field = association.field
423 relationship = field.Relationship
424 )
425
426</span> saveAssociation := func(reflectValue reflect.Value) {
427 // value has to been pointer
428</span> if reflectValue.Kind() != reflect.Ptr {
429 reflectPtr := reflect.New(reflectValue.Type())
430 reflectPtr.Elem().Set(reflectValue)
431 </span>reflectValue = reflectPtr
432 }
433
434 <span class="cov8" title="1">// value has to been saved for many2man</span><span class="cov8" title="1">y
435 if relationship.Kind == "many_to_many" {
436</span> if scope.New(reflectValue.Interface()).PrimaryKeyZero() {
437 </span>association.setErr(scope.NewDB().Save(reflectValue.Interface()).Error)
438 }
439 }
440
441 <span class="cov8" title="1">// Assign Fields
442 var fieldType = field.Field.Type()
443 var setFieldBackToValue, setSliceFieldBackToVal</span><span class="cov0" title="0">ue bool
444 if reflectValue.Type().AssignableTo(fieldType) {
445 </span>field<span class="cov8" title="1">.Set(reflectValue)
446</span> } else if reflectValue.Type().Elem().AssignableTo(fieldType) {
447 // if field's type is struct, then need to set value back to argument after save
448 setFieldBackToValue = true
449 </span>field<span class="cov8" title="1">.Set(reflectValue.Elem())
450</span> } else if fieldType.Kind() == reflect.Slice {
451</span> if reflectValue.Type().AssignableTo(fieldType.Elem()) {
452 </span>field<span class="cov8" title="1">.Set(reflect.Append(field.Field, reflectValue))
453</span> } else if reflectValue.Type().Elem().AssignableTo(fieldType.Elem()) {
454 // if field's type is slice of struct, then need to set value back to argument after save
455 setSliceFieldBackToValue = true
456 </span>field.Set(reflect.Append(field.Field, reflectValue.Elem()))
457 }
458 }
459
460</span> if relationship.Kind == "many_to_many" {
461 </span>assoc<span class="cov8" title="1">iation.setErr(relationship.JoinTableHandler.Add(relationship.JoinTableHandler, scope.NewDB(), scope.Value, reflectValue.Interface()))
462 } else {
463 association.setErr(scope.NewDB().Select(field.Name).Save(scope.Value).Error)
464
465</span> if setFieldBackToValue {
466 </span>refle<span class="cov8" title="1">ctValue.Elem().Set(field.Fiel</span><span class="cov8" title="1">d)
467 } else if setSliceFieldBackToValue {
468 </span>reflectValue.Elem().Set(field.Field.Index(field.Field.Len() - 1))
469 }
470 }
471 }
472
473</span> for _, value := range values {
474 reflectValue := reflect.ValueOf(value)
475 indirectReflectValue := reflect.Indirect(reflectV</span><span class="cov8" title="1">alue)
476 if indirectReflectValue.Kind() == reflect.Struct {
477 </span>saveA<span class="cov8" title="1">ssociation(reflectValue)
478</span> } else if indirectReflectValue.Kind() == reflect.</span><span class="cov8" title="1">Slice {
479 for i := 0; i < indirectReflectValue.Len(); i++ {
480 </span>saveAssociation(indirectReflectValue.Index(i))
481 }
482 } else {
483 </span>association.setErr(errors.New("invalid value type"))
484 }
485 <span class="cov8" title="1">}
486</span> return association
487}
488
489// setErr set e</span><span class="cov8" title="1">rror when the error is not nil. And return Association.
490func (association *Association) setErr(err error) *Association {
491 i</span>f err != nil {
492 <span class="cov8" title="1"> association.Error</span> = err
493 }
494 return association
495}
496</pre>
497
498 <pre class="file" id="file1" style="display: none">package gorm
499
500import "log"
501
502// DefaultCallback default callbacks defined by gorm
503var DefaultCallback = &Callback{}
504
505// Callback is a struct that contains all CRUD callbacks
506// Field `creates` contains callbacks will be call when creating object
507// Field `updates` contains callbacks will be call when updating object
508// Field `deletes` contains callbacks will be call when deleting object
509// Field `queries` contains callbacks will be call when querying object with query methods like Find, First, Related, Association...
510// Field `rowQueries` contains callbacks will be call when querying object with Row, Rows...
511// Field `processors` contains all callback processors, will be used to generate above callbacks in order
512type Callback struct {
513 creates []*func(scope *Scope)
514 updates []*func(scope *Scope)
515 deletes []*func(scope *Scope)
516 queries []*func(scope *Scope)
517 rowQueries []*func(scope *Scope)
518 processors []*CallbackProcessor
519}
520
521// CallbackProcessor contains callback informations
522type CallbackProcessor struct {
523 name string // current callback's name
524 before string // register current callback before a callback
525 after string // register current callback after a callback
526 replace bool // replace callbacks with same name
527 remove bool // delete callbacks with same name
528 kind string // callback type: create, update, delete, query, row_query
529 processor *func(scope *Scope) // callback handler
530 parent *Callback
531}
532
533func (c *Callback) clone() *Callback <span class="cov8" title="1">{
534 return &Callback{
535 creates: c.creates,
536 updates: c.updates,
537 deletes: c.deletes,
538 queries: c.queries,
539 rowQueries: c.rowQueries,
540 processors: c.processors,
541 }
542}</span>
543
544// Create could be used to register callbacks for creating object
545// db.Callback().Create().After("gorm:create").Register("plugin:run_after_create", func(*Scope) {
546// // business logic
547// ...
548//
549// // set error if some thing wrong happened, will rollback the creating
550// scope.Err(errors.New("error"))
551// })
552func (c *Callback) Create() *CallbackProcessor <span class="cov8" title="1">{
553 return &CallbackProcessor{kind: "create", parent: c}
554}</span>
555
556// Update could be used to register callbacks for updating object, refer `Create` for usage
557func (c *Callback) Update() *CallbackProcessor <span class="cov8" title="1">{
558 return &CallbackProcessor{kind: "update", parent: c}
559}</span>
560
561// Delete could be used to register callbacks for deleting object, refer `Create` for usage
562func (c *Callback) Delete() *CallbackProcessor <span class="cov8" title="1">{
563 return &CallbackProcessor{kind: "delete", parent: c}
564}</span>
565
566// Query could be used to register callbacks for querying objects with query methods like `Find`, `First`, `Related`, `Association`...
567// Refer `Create` for usage
568func (c *Callback) Query() *CallbackProcessor <span class="cov8" title="1">{
569 return &CallbackProcessor{kind: "query", parent: c}
570}</span>
571
572// RowQuery could be used to register callbacks for querying objects with `Row`, `Rows`, refer `Create` for usage
573func (c *Callback) RowQuery() *CallbackProcessor <span class="cov8" title="1">{
574 return &CallbackProcessor{kind: "row_query", parent: c}
575}</span>
576
577// After insert a new callback after callback `callbackName`, refer `Callbacks.Create`
578func (cp *CallbackProcessor) After(callbackName string) *CallbackProcessor <span class="cov8" title="1">{
579 cp.after = callbackName
580 return cp
581}</span>
582
583// Before insert a new callback before callback `callbackName`, refer `Callbacks.Create`
584func (cp *CallbackProcessor) Before(callbackName string) *CallbackProcessor <span class="cov8" title="1">{
585 cp.before = callbackName
586 return cp
587}</span>
588
589// Register a new callback, refer `Callbacks.Create`
590func (cp *CallbackProcessor) Register(callbackName string, callback func(scope *Scope)) <span class="cov8" title="1">{
591 if cp.kind == "row_query" </span><span class="cov8" title="1">{
592 if cp.before == "" && cp.after == "" && callbackName != "gorm:row_query" </span><span class="cov0" title="0">{
593 log.Printf("Registing RowQuery callback %v without specify order with Before(), After(), applying Before('gorm:row_query') by default for compatibility...\n", callbackName)
594 cp.before = "gorm:row_query"
595 }</span>
596 }
597
598 <span class="cov8" title="1">cp.name = callbackName
599 cp.processor = &callback
600 cp.parent.processors = append(cp.parent.processors, cp)
601 cp.parent.reorder()</span>
602}
603
604// Remove a registered callback
605// db.Callback().Create().Remove("gorm:update_time_stamp_when_create")
606func (cp *CallbackProcessor) Remove(callbackName string) <span class="cov8" title="1">{
607 log.Printf("[info] removing callback `%v` from %v\n", callbackName, fileWithLineNum())
608 cp.name = callbackName
609 cp.remove = true
610 cp.parent.processors = append(cp.parent.processors, cp)
611 cp.parent.reorder()
612}</span>
613
614// Replace a registered callback with new callback
615// db.Callback().Create().Replace("gorm:update_time_stamp_when_create", func(*Scope) {
616// scope.SetColumn("Created", now)
617// scope.SetColumn("Updated", now)
618// })
619func (cp *CallbackProcessor) Replace(callbackName string, callback func(scope *Scope)) <span class="cov8" title="1">{
620 log.Printf("[info] replacing callback `%v` from %v\n", callbackName, fileWithLineNum())
621 cp.name = callbackName
622 cp.processor = &callback
623 cp.replace = true
624 cp.parent.processors = append(cp.parent.processors, cp)
625 cp.parent.reorder()
626}</span>
627
628// Get registered callback
629// db.Callback().Create().Get("gorm:create")
630func (cp *CallbackProcessor) Get(callbackName string) (callback func(scope *Scope)) <span class="cov0" title="0">{
631 for _, p := range cp.parent.processors </span><span class="cov0" title="0">{
632 if p.name == callbackName && p.kind == cp.kind && !cp.remove </span><span class="cov0" title="0">{
633 return *p.processor
634 }</span>
635 }
636 <span class="cov0" title="0">return nil</span>
637}
638
639// getRIndex get right index from string slice
640func getRIndex(strs []string, str string) int <span class="cov8" title="1">{
641 for i := len(strs) - 1; i >= 0; i-- </span><span class="cov8" title="1">{
642 if strs[i] == str </span><span class="cov8" title="1">{
643 return i
644 }</span>
645 }
646 <span class="cov8" title="1">return -1</span>
647}
648
649// sortProcessors sort callback processors based on its before, after, remove, replace
650func sortProcessors(cps []*CallbackProcessor) []*func(scope *Scope) <span class="cov8" title="1">{
651 var (
652 allNames, sortedNames []string
653 sortCallbackProcessor func(c *CallbackProcessor)
654 )
655
656 for _, cp := range cps </span><span class="cov8" title="1">{
657 // show warning message the callback name already exists
658 if index := getRIndex(allNames, cp.name); index > -1 && !cp.replace && !cp.remove </span><span class="cov0" title="0">{
659 log.Printf("[warning] duplicated callback `%v` from %v\n", cp.name, fileWithLineNum())
660 }</span>
661 <span class="cov8" title="1">allNames = append(allNames, cp.name)</span>
662 }
663
664 <span class="cov8" title="1">sortCallbackProcessor = func(c *CallbackProcessor) </span><span class="cov8" title="1">{
665 if getRIndex(sortedNames, c.name) == -1 </span><span class="cov8" title="1">{ // if not sorted
666 if c.before != "" </span><span class="cov8" title="1">{ // if defined before callback
667 if index := getRIndex(sortedNames, c.before); index != -1 </span><span class="cov8" title="1">{
668 // if before callback already sorted, append current callback just after it
669 sortedNames = append(sortedNames[:index], append([]string{c.name}, sortedNames[index:]...)...)
670 }</span> else<span class="cov8" title="1"> if index := getRIndex(allNames, c.before); index != -1 </span><span class="cov8" title="1">{
671 // if before callback exists but haven't sorted, append current callback to last
672 sortedNames = append(sortedNames, c.name)
673 sortCallbackProcessor(cps[index])
674 }</span>
675 }
676
677 <span class="cov8" title="1">if c.after != "" </span><span class="cov8" title="1">{ // if defined after callback
678 if index := getRIndex(sortedNames, c.after); index != -1 </span><span class="cov8" title="1">{
679 // if after callback already sorted, append current callback just before it
680 sortedNames = append(sortedNames[:index+1], append([]string{c.name}, sortedNames[index+1:]...)...)
681 }</span> else<span class="cov8" title="1"> if index := getRIndex(allNames, c.after); index != -1 </span><span class="cov8" title="1">{
682 // if after callback exists but haven't sorted
683 cp := cps[index]
684 // set after callback's before callback to current callback
685 if cp.before == "" </span><span class="cov8" title="1">{
686 cp.before = c.name
687 }</span>
688 <span class="cov8" title="1">sortCallbackProcessor(cp)</span>
689 }
690 }
691
692 // if current callback haven't been sorted, append it to last
693 <span class="cov8" title="1">if getRIndex(sortedNames, c.name) == -1 </span><span class="cov8" title="1">{
694 sortedNames = append(sortedNames, c.name)
695 }</span>
696 }
697 }
698
699 <span class="cov8" title="1">for _, cp := range cps </span><span class="cov8" title="1">{
700 sortCallbackProcessor(cp)
701 }</span>
702
703 <span class="cov8" title="1">var sortedFuncs []*func(scope *Scope)
704 for _, name := range sortedNames </span><span class="cov8" title="1">{
705 if index := getRIndex(allNames, name); !cps[index].remove </span><span class="cov8" title="1">{
706 sortedFuncs = append(sortedFuncs, cps[index].processor)
707 }</span>
708 }
709
710 <span class="cov8" title="1">return sortedFuncs</span>
711}
712
713// reorder all registered processors, and reset CRUD callbacks
714func (c *Callback) reorder() <span class="cov8" title="1">{
715 var creates, updates, deletes, queries, rowQueries []*CallbackProcessor
716
717 for _, processor := range c.processors </span><span class="cov8" title="1">{
718 if processor.name != "" </span><span class="cov8" title="1">{
719 switch processor.kind </span>{
720 case "create":<span class="cov8" title="1">
721 creates = append(creates, processor)</span>
722 case "update":<span class="cov8" title="1">
723 updates = append(updates, processor)</span>
724 case "delete":<span class="cov8" title="1">
725 deletes = append(deletes, processor)</span>
726 case "query":<span class="cov8" title="1">
727 queries = append(queries, processor)</span>
728 case "row_query":<span class="cov8" title="1">
729 rowQueries = append(rowQueries, processor)</span>
730 }
731 }
732 }
733
734 <span class="cov8" title="1">c.creates = sortProcessors(creates)
735 c.updates = sortProcessors(updates)
736 c.deletes = sortProcessors(deletes)
737 c.queries = sortProcessors(queries)
738 c.rowQueries = sortProcessors(rowQueries)</span>
739}
740</pre>
741
742 <pre class="file" id="file2" style="display: none">package gorm
743
744import (
745 "fmt"
746 "strings"
747)
748
749// Define callbacks for creating
750func init() <span class="cov8" title="1">{
751 DefaultCallback.Create().Register("gorm:begin_transaction", beginTransactionCallback)
752 DefaultCallback.Create().Register("gorm:before_create", beforeCreateCallback)
753 DefaultCallback.Create().Register("gorm:save_before_associations", saveBeforeAssociationsCallback)
754 DefaultCallback.Create().Register("gorm:update_time_stamp", updateTimeStampForCreateCallback)
755 DefaultCallback.Create().Register("gorm:create", createCallback)
756 DefaultCallback.Create().Register("gorm:force_reload_after_create", forceReloadAfterCreateCallback)
757 DefaultCallback.Create().Register("gorm:save_after_associations", saveAfterAssociationsCallback)
758 DefaultCallback.Create().Register("gorm:after_create", afterCreateCallback)
759 DefaultCallback.Create().Register("gorm:commit_or_rollback_transaction", commitOrRollbackTransactionCallback)
760}</span>
761
762// beforeCreateCallback will invoke `BeforeSave`, `BeforeCreate` method before creating
763func beforeCreateCallback(scope *Scope) <span class="cov8" title="1">{
764 if !scope.HasError() </span><span class="cov8" title="1">{
765 scope.CallMethod("BeforeSave")
766 }</span>
767 <span class="cov8" title="1">if !scope.HasError() </span><span class="cov8" title="1">{
768 scope.CallMethod("BeforeCreate")
769 }</span>
770}
771
772// updateTimeStampForCreateCallback will set `CreatedAt`, `UpdatedAt` when creating
773func updateTimeStampForCreateCallback(scope *Scope) <span class="cov8" title="1">{
774 if !scope.HasError() </span><span class="cov8" title="1">{
775 now := NowFunc()
776
777 if createdAtField, ok := scope.FieldByName("CreatedAt"); ok </span><span class="cov8" title="1">{
778 if createdAtField.IsBlank </span><span class="cov8" title="1">{
779 createdAtField.Set(now)
780 }</span>
781 }
782
783 <span class="cov8" title="1">if updatedAtField, ok := scope.FieldByName("UpdatedAt"); ok </span><span class="cov8" title="1">{
784 if updatedAtField.IsBlank </span><span class="cov8" title="1">{
785 updatedAtField.Set(now)
786 }</span>
787 }
788 }
789}
790
791// createCallback the callback used to insert data into database
792func createCallback(scope *Scope) <span class="cov8" title="1">{
793 if !scope.HasError() </span><span class="cov8" title="1">{
794 defer scope.trace(NowFunc())
795
796 var (
797 columns, placeholders []string
798 blankColumnsWithDefaultValue []string
799 )
800
801 for _, field := range scope.Fields() </span><span class="cov8" title="1">{
802 if scope.changeableField(field) </span><span class="cov8" title="1">{
803 if field.IsNormal </span><span class="cov8" title="1">&& !field.IsIgnored {
804 if field.IsBlank && field.HasDefaultValue </span><span class="cov8" title="1">{
805 blankColumnsWithDefaultValue = append(blankColumnsWithDefaultValue, scope.Quote(field.DBName))
806 scope.InstanceSet("gorm:blank_columns_with_default_value", blankColumnsWithDefaultValue)
807 }</span> else<span class="cov8" title="1"> if !field.IsPrimaryKey || !field.IsBlank </span><span class="cov8" title="1">{
808 columns = append(columns, scope.Quote(field.DBName))
809 placeholders = append(placeholders, scope.AddToVars(field.Field.Interface()))
810 }</span>
811 } else<span class="cov8" title="1"> if field.Relationship != nil && field.Relationship.Kind == "belongs_to" </span><span class="cov8" title="1">{
812 for _, foreignKey := range field.Relationship.ForeignDBNames </span><span class="cov8" title="1">{
813 if foreignField, ok := scope.FieldByName(foreignKey); ok && !scope.changeableField(foreignField) </span><span class="cov8" title="1">{
814 columns = append(columns, scope.Quote(foreignField.DBName))
815 placeholders = append(placeholders, scope.AddToVars(foreignField.Field.Interface()))
816 }</span>
817 }
818 }
819 }
820 }
821
822 <span class="cov8" title="1">var (
823 returningColumn = "*"
824 quotedTableName = scope.QuotedTableName()
825 primaryField = scope.PrimaryField()
826 extraOption string
827 insertModifier string
828 )
829
830</span> if str, ok := scope.Get("gorm:insert_option"); ok {
831 </span>extraOption = fmt.Sprint(str)
832 }
833 <span class="cov8" title="1">if str, ok := scope.Get</span><span class="cov8" title="1">("gorm:insert_modifier"); ok {
834 insertModifier = strings.ToUpper(fmt.Sprint(str))
835 </span>if insertModifier == "INTO" {
836 insertModifier = ""
837 <span class="cov8" title="1"> }
838 }
839
840</span> if primaryField != nil {
841 returningColumn = scope.Quote(primaryField.DBName)
842 }
843
844 lastInsertIDReturningSuffix := scope.Dialect().LastInsertIDReturningSuffix(quotedTableName, returningColumn)
845
846 if len(columns) == 0 {
847 </span>scope<span class="cov8" title="1">.Raw(fmt.Sprintf(
848 "INSERT %v INTO %v %v%v%v",
849 addExtraSpaceIfExist(insertModifier),
850 quotedTableName,
851 scope.Dialect().DefaultValueStr(),
852 addExtraSpaceIfExist(extraOption),
853 addExtraSpaceIfExist(lastInsertIDReturningSuffix),
854 ))
855 } else {
856 </span>scope.Raw(fmt.Sprintf(
857 "INSERT %v INTO %v (%v) VALUES (%v)%v%v",
858 addExtraSpaceIfExist(insertModifier),
859 <span class="cov8" title="1"> scope.QuotedTableName(),
860</span> strings.Join(columns, ","),
861</span> strings.Join(placeholders, ","),
862 addExtraSpaceIfExist(extraOption),
863 addExtraSpaceIfExist(lastInsertIDReturningSuffix),
864 ))
865 }
866</span>
867</span> // execute create sql
868 if l</span>astInsertIDReturningSuffix == "" || primaryField == nil {
869 if result, err := scope.SQLDB().Exec(scope.SQL, scope.SQLVars...); scope.Err(err) == nil {
870 // set rows affected count
871 scop<span class="cov0" title="0">e.db.RowsAffected, _ = result.RowsAffected()
872
873</span> // set primary value to primary field
874</span> if primaryField != nil && primaryField.IsBlank {
875 if primaryValue, err := result.LastInsertId(); scope.Err(err) == nil {
876 </span> scope.Err(primaryField.Set(primaryValue))
877 }
878 }
879 }</span>
880 } else {
881 if primaryField.Field.CanAddr() {
882 if err := scope.SQLDB().QueryRow(scope.SQL, scope.SQLVars...).Scan(primaryField.Field.Addr().Interface()); scope.Err(err) == nil {
883 primaryField.IsBlank = false
884 scope.db.RowsAffected = 1
885 }
886 } else {
887</span> scope.Err(ErrUnaddressable)
888 }
889</span> }
890</span> }
891}
892</span>
893//<span class="cov8" title="1"> forceReloadAfterCre</span>ateCallback will reload columns that having default value, and set it back to current object
894func forceReloadAfterCreateCallback(scope *Scope) {
895 if blankColumnsWithDefaultValue, ok := scope.InstanceGet("gorm:blank_columns_with_default_value"); ok {
896 db := scope.DB().New().Table(scope.TableName()).Select(blankColumnsWithDefaultValue.([]string))
897 for _, field := range scope.Fields() {
898 if field.IsPrimaryKey && !field.IsBl<span class="cov8" title="1">ank {
899 db = db.Where(fmt.</span><span class="cov8" title="1">Sprintf("%v = ?", field.DBName), field.Field.Interface())
900 }
901 </span>}
902 <span class="cov8" title="1"> db.Scan(scope.Value)</span><span class="cov8" title="1">
903 }
904}
905</span>
906// afterCreateCallback will invoke `AfterCreate`, `AfterSave` method after creating
907func afterCreateCallback(scope *Scope) {
908 if !scope.HasError() {
909 scope.CallMethod("AfterCreate")
910 }
911 if !scope.HasError() {
912 scope.CallMethod("AfterSave")
913 }
914}
915</pre>
916
917 <pre class="file" id="file3" style="display: none">package gorm
918
919import (
920 "errors"
921 "fmt"
922)
923
924// Define callbacks for deleting
925func init() <span class="cov8" title="1">{
926 DefaultCallback.Delete().Register("gorm:begin_transaction", beginTransactionCallback)
927 DefaultCallback.Delete().Register("gorm:before_delete", beforeDeleteCallback)
928 DefaultCallback.Delete().Register("gorm:delete", deleteCallback)
929 DefaultCallback.Delete().Register("gorm:after_delete", afterDeleteCallback)
930 DefaultCallback.Delete().Register("gorm:commit_or_rollback_transaction", commitOrRollbackTransactionCallback)
931}</span>
932
933// beforeDeleteCallback will invoke `BeforeDelete` method before deleting
934func beforeDeleteCallback(scope *Scope) <span class="cov8" title="1">{
935 if scope.DB().HasBlockGlobalUpdate() && !scope.hasConditions() </span><span class="cov8" title="1">{
936 scope.Err(errors.New("Missing WHERE clause while deleting"))
937 return
938 }</span>
939 <span class="cov8" title="1">if !scope.HasError() </span><span class="cov8" title="1">{
940 scope.CallMethod("BeforeDelete")
941 }</span>
942}
943
944// deleteCallback used to delete data from database or set deleted_at to current time (when using with soft delete)
945func deleteCallback(scope *Scope) <span class="cov8" title="1">{
946 if !scope.HasError() </span><span class="cov8" title="1">{
947 var extraOption string
948 if str, ok := scope.Get("gorm:delete_option"); ok </span><span class="cov0" title="0">{
949 extraOption = fmt.Sprint(str)
950 }</span>
951
952 <span class="cov8" title="1">deletedAtField, hasDeletedAtField := scope.FieldByName("DeletedAt")
953
954 if !scope.Search.Unscoped && hasDeletedAtField </span><span class="cov8" title="1">{
955 scope.Raw(fmt.Sprintf(
956 "UPDATE %v SET %v=%v%v%v",
957 scope.QuotedTableName(),
958 scope.Quote(deletedAtField.DBName),
959 scope.AddToVars(NowFunc()),
960 addExtraSpaceIfExist(scope.CombinedConditionSql()),
961 addExtraSpaceIfExist(extraOption),
962 )).Exec()
963 }</span> else<span class="cov8" title="1"> {
964 scope.Raw(fmt.Sprintf(
965 "DELETE FROM %v%v%v",
966 scope.QuotedTableName(),
967 addExtraSpaceIfExist(scope.CombinedConditionSql()),
968 addExtraSpaceIfExist(extraOption),
969 )).Exec()
970 }</span>
971 }
972}
973
974// afterDeleteCallback will invoke `AfterDelete` method after deleting
975func afterDeleteCallback(scope *Scope) <span class="cov8" title="1">{
976 if !scope.HasError() </span><span class="cov8" title="1">{
977 scope.CallMethod("AfterDelete")
978 }</span>
979}
980</pre>
981
982 <pre class="file" id="file4" style="display: none">package gorm
983
984import (
985 "errors"
986 "fmt"
987 "reflect"
988)
989
990// Define callbacks for querying
991func init() <span class="cov8" title="1">{
992 DefaultCallback.Query().Register("gorm:query", queryCallback)
993 DefaultCallback.Query().Register("gorm:preload", preloadCallback)
994 DefaultCallback.Query().Register("gorm:after_query", afterQueryCallback)
995}</span>
996
997// queryCallback used to query data from database
998func queryCallback(scope *Scope) <span class="cov8" title="1">{
999 if _, skip := scope.InstanceGet("gorm:skip_query_callback"); skip </span><span class="cov8" title="1">{
1000 return
1001 }</span>
1002
1003 <span class="cov8" title="1">//we are only preloading relations, dont touch base model
1004 if _, skip := scope.InstanceGet("gorm:only_preload"); skip {
1005 return
1006 }
1007
1008 defer scope.trace(NowFunc())
1009
1010 var (
1011 isSlice, isPtr bool
1012</span> resultType reflect.Type
1013</span> results = scope.IndirectValue()
1014 )
1015</span>
1016 if orderBy, ok := scope.Get("gorm:order_by_primary_key"); ok {
1017 <span class="cov8" title="1"> if primaryField := scope.PrimaryField(); primaryField !</span><span class="cov8" title="1">= nil {
1018 scope.Search.Order(fmt.Sprintf("%v.%v %v", scope.QuotedTableName(), scope.Quote(primaryField.DBName), orderBy))
1019 </span>}
1020 }
1021
1022</span> if value, ok := scope.Get("gorm:query_destination"); ok {
1023 results = indirect(reflect.ValueOf(value))
1024 }
1025
1026 if kind := results.Kind(); kind == re</span><span class="cov8" title="1">flect.Slice {
1027 isSlice = true
1028 resultType = results.Type().Elem()
1029 r</span>esults.Set(reflect.MakeSlice(results.Type(), 0, 0))
1030
1031</span> if resultType.Kind() == reflect.Ptr {
1032 isPtr = true
1033 </span> resultType = resultType.Elem()
1034 }
1035 <span class="cov8" title="1">} else if kind != reflect.Struct {
1036 scope.Err(errors.New("unsupported destination, should be slice or struct"))
1037 return
1038</span> }
1039
1040</span> scope.prepareQuerySQL()
1041
1042</span> if !scope.HasError() {
1043 <span class="cov8" title="1">scope.db.RowsAffected = 0
1044</span> if str, ok := scope.Get("gorm:query_option"); ok {
1045 scope.SQL += addExtraSpaceIfExist(fmt.Sprint(str))
1046 }
1047
1048</span> if rows, err := scope.SQLDB().Query(scope.SQL, scope.SQLVars...); scope.Err(err) == nil {
1049 defer rows.Close()
1050
1051 columns, _ :</span><span class="cov8" title="1">= rows.Columns()
1052 for rows.Next() {
1053 s</span>cope.db.RowsAffected++
1054
1055 <span class="cov8" title="1">elem := results
1056 if isSlice {
1057 elem = ref</span><span class="cov8" title="1">lect.New(resultType).Elem()
1058 }
1059</span>
1060 sc</span>ope.s<span class="cov8" title="1">can(rows, columns, scope.New(elem.Addr().Interface()).Fields())
1061
1062 if</span> isSlice {
1063 if isPtr {
1064 results.Set(reflect.Append(results, elem.Addr()))
1065 } else {
1066 <span class="cov8" title="1"> results.Set(reflect.Append(res</span><span class="cov0" title="0">ults, elem))
1067 }
1068 </span>}
1069</span> }
1070
1071</span> if err := rows.Err(); err != nil {
1072 scope.Err(err)
1073 } else if scope.db.RowsAffected == 0 && !isSlice {
1074 scope.Err(ErrRecordNotFound)
1075 }
1076 }
1077 }
1078</span>}
1079
1080</span>// afterQueryCallback will invoke `AfterFind` method after querying
1081func afterQueryCallback(scope *Scope) {
1082 if !scope.HasError() {
1083 scope.CallMethod("AfterFind")
1084 }
1085}
1086</pre>
1087
1088 <pre class="file" id="file5" style="display: none">package gorm
1089
1090import (
1091 "errors"
1092 "fmt"
1093 "reflect"
1094 "strconv"
1095 "strings"
1096)
1097
1098// preloadCallback used to preload associations
1099func preloadCallback(scope *Scope) <span class="cov8" title="1">{
1100 if _, skip := scope.InstanceGet("gorm:skip_query_callback"); skip </span><span class="cov8" title="1">{
1101 return
1102 }</span>
1103
1104 <span class="cov8" title="1">if ap, ok := scope.Get("gorm:auto_preload"); ok</span><span class="cov8" title="1"> {
1105 // If gorm:auto_preload IS NOT a bool then auto preload.
1106 </span>// Else if it IS a bool, use the value
1107 if apb, ok := ap.(bool); !ok {
1108 <span class="cov8" title="1"> autoPreload(scope)
1109</span> } else if apb {
1110 </span> autoPreload(scope)
1111 }
1112 <span class="cov8" title="1">}
1113
1114 if scope.Search.preload == nil || scope.HasError() {
1115 return
1116 }
1117
1118</span> var (
1119 preloadedMap = map[string]bool{}
1120 fields = scope.Fields()
1121 )
1122
1123 for _, preload := range scope.Search.preload {
1124 var (
1125</span> preloadFields = strings.Split(preload.schema, ".")
1126 currentScope = scope
1127 currentFields = fields
1128</span> )
1129</span>
1130 for idx, preloadField := range preloadFields {
1131 var currentPreloadConditions []interface{}
1132
1133</span> if currentScope == nil {
1134 continue
1135 }
1136</span>
1137 //</span> if not preloaded
1138 if preloadKey := strings.Join(preloadFields[:idx+1], "."); !preloadedMap[preloadKey] {
1139
1140</span> // assign search conditions to last preload
1141</span> if idx == </span>len(preloadFields)-1 {
1142 currentPreloadConditions = preload.conditions
1143 }
1144
1145</span> for _, field := <span class="cov8" title="1">range currentFields {
1146 if field.Name != preloadField || field.Relationship == nil {
1147</span> continue
1148 }
1149</span>
1150 switch field.Relationship.Kind {
1151</span> case "has_one":
1152 currentScope.handleHasOnePreload(field, currentPreloadConditions)
1153</span> case "ha<span class="cov0" title="0">s_many":
1154 currentScope.handleHasManyPreload(field, curr</span>entPreloadConditions)
1155 case "belongs_to":
1156 currentScope.handleBelongsToPreload(field, currentPreloadConditions)
1157 <span class="cov8" title="1">case "many_to_many":
1158 curr</span>entScope.handleManyToManyPreload(field, currentPreloadConditions)
1159 default:
1160 scope.Err(errors.New("unsupported relation"))
1161 <span class="cov8" title="1"> }
1162</span>
1163 preloadedMap[preloadKey] = true
1164 </span>break
1165 }
1166
1167 if !preloadedMap[preloadKey] {
1168 <span class="cov8" title="1"> scope.Err(fmt.Errorf("can't </span><span class="cov8" title="1">preload field %s for %s", preloadField, currentScope.GetModelStruct().ModelType))
1169 return
1170 }
1171</span> }
1172
1173</span> // preload next level
1174 if idx < len(preloadFields)-1 {
1175 currentScope = currentScope.getColumnAsScope(preloadField)
1176 if currentScope != nil {
1177 currentFields = currentScope.Fields()
1178 }
1179 }
1180</span> }
1181</span> }
1182</span>}
1183
1184fu<span class="cov8" title="1">nc autoPreload(scope *Scope) {
1185</span> for _, field := range scope.Fields() {
1186</span> if field.Relationship == nil {
1187 continue
1188 }
1189</span></span>
1190</span> if val, ok := field.TagSettingsGet("PRELOAD"); ok {
1191 if preload, err := strconv.ParseBool(val); err != nil {
1192 scope.Err(errors.New("invalid preload option"))
1193 <span class="cov8" title="1"> return
1194</span> } else if !preload {
1195 continue
1196 }
1197 }
1198
1199 scope.Search.Preload(field.Name)
1200 }
1201}
1202
1203func (scope *Scope) generatePreloadDBW</span><span class="cov8" title="1">ithConditions(conditions []interface{}) (*DB, []interface{}) {
1204 var (
1205</span> preloadDB = scope.NewDB()
1206 p</span>reloa<span class="cov8" title="1">dConditions []interface{}
1207 )
1208
1209</span> for _, condition := range conditions {
1210 if scopes, ok := condition.(func(*DB) *DB); ok {
1211 <span class="cov8" title="1"> preloadDB = scopes(preloadDB)
1212</span> } else {
1213 preloadConditions = append(preloadConditions, condition)
1214 }
1215 }
1216
1217 return preloadDB, preloadConditions
1218}
1219
1220// handleHasOnePreload use</span><span class="cov0" title="0">d to preload has one associations
1221func (scope *Scope) handleHasOnePreload(field *Field, conditions []interface{}) {
1222 r</span>elation := field.Relationship
1223
1224 // get relations's primary keys
1225 <span class="cov8" title="1">primaryKeys := scope.getColumnAsArray(relation.AssociationForeignFieldNames, scope.Value)
1226 if len(primaryKeys) == 0 {
1227 return
1228 }
1229
1230 // preload conditions
1231</span> preloadDB, preloadConditions := scope.generatePreloadDBWithConditions(conditions)
1232
1233 /</span>/ find relations
1234 query := fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, relation.ForeignDBNames), toQueryMarks(primaryKeys))
1235 <span class="cov8" title="1">values := toQueryValues(primaryKeys)
1236 if relation.PolymorphicType != "" {
1237 query += fmt.Sprintf(" AND %v = ?", scope.Quote(relation.PolymorphicDBName))
1238 values = append(values, relation.PolymorphicValue)
1239 }
1240
1241 results := makeSlice(field.Struct.Type)
1242 scope.Err(preloadDB.Where(query, values...).Find(results, preloadConditions...).Error)
1243
1244 // assign find results
1245</span> var (
1246</span> resultsValue = indirect(reflect.Val</span><span class="cov8" title="1">ueOf(results))
1247 indirectScopeValue = scope.IndirectValue()
1248 )
1249
1250</span> if indirectScopeValue.Kind() == reflect.Slice {
1251 foreignV</span>aluesToResults := make(map[string]reflect.Value)
1252 for i := 0; i < resultsValue.Len(); i++ {
1253 result := resultsValue.Index(i)
1254 foreignValues := toString(getValueFromFields(result, relation.ForeignFieldNames))
1255 fore<span class="cov8" title="1">ignValuesToResults[foreignValues] = result
1256 }
1257</span> for j := 0; j < indirectScopeValue.Len(); j++ {
1258 indirectValue := indirect(indirectScopeValue.Index(j))
1259 </span>valueString := toString(getValueFromFields(indirectValue, relation.AssociationForeignFieldNames))
1260 if result, found := foreignValuesToResults[valueString]; found {
1261 indirectValue.FieldByName(field.Name).Set(result)
1262 }
1263 }
1264 } else {
1265 for i := 0; i < resultsValue.Len(); i++ {
1266 result := resultsValue.Index(i)
1267 scope.Err(field.Set(result))
1268 }
1269 }
1270</span>}
1271
1272</span>// handleHasManyPreload used to preload has many associations
1273func (scope *Scope) handleHasManyPreload(field *Field, conditions []interface{}) {
1274 <span class="cov8" title="1">relation := field.Relationship
1275
1276 // get relations's primary keys
1277 primaryKeys := scope.getColumnAsArray(relation.AssociationForeignFieldNames, scope.Value)
1278 if len(primaryKeys) == 0 {
1279 return
1280</span> }
1281
1282 /</span>/ preload conditions
1283 preloadDB, preloadConditions := scope.generatePreloadDBWithConditions(conditions)
1284
1285 // find relations
1286 query := fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, relation.ForeignDBNames), toQueryMarks(primaryKeys))
1287 values := toQueryValues(primaryKeys)
1288 if relation.PolymorphicType != "" {
1289 query += fmt.Sprintf(" AND %v = ?", scope.Quote(relation.PolymorphicDBName))
1290 values = append(values, relation.PolymorphicValue)
1291 }
1292
1293 results := makeSlice(field.Struct.Type)
1294</span> scope.Err(preloadDB.Where(query, values...).Find(results, preloadConditions...).Error)
1295
1296</span> // assign find results
1297 var (
1298 resultsValue = indirect(reflect.ValueOf(results))
1299 i</span>ndirectScopeValue = scope.IndirectValue()
1300 )
1301
1302</span> if indirectScopeValue.Kind() == reflect.Slice {
1303 preloadMap := make(map[string][]reflect.Value)
1304 for i := 0; i < resultsValue.Len(); i++ {
1305 result := resultsValue.Index(i)
1306</span> foreignValues := getValueFromFields(result, relation.ForeignFieldNames)
1307 p</span>reloa<span class="cov8" title="1">dMap[toString(foreignValues)] = append(preloadMap[toString(foreignValues)], result)
1308 }
1309
1310</span> for j := 0; j < indirectScopeValue.Len(); j++ {
1311 obje<span class="cov8" title="1">ct := indirect(indirectScopeValue.Index(j))
1312 objectRealValue := getValueFromFields(object, relation.AssociationForeignFieldNames)
1313 </span> f := object.FieldByName(field.Name)
1314 if results, ok := preloadMap[toString(objectRealValue)]; ok {
1315 f.Set(reflect.Append(f, results...))
1316 } else {
1317 f.Set(reflect.MakeSlice(f.Type(), 0, 0))
1318 }
1319 }
1320 } else {
1321 scope.Err(field.Set(resultsValue))
1322 }
1323}
1324
1325// handleBelongsToPreload </span><span class="cov8" title="1">used to preload belongs to associations
1326func (scope *Scope) handleBelongsToPreload(field *Field, conditions []interface{}) {
1327 r</span>elation := field.Relationship
1328
1329 // preload conditions
1330 <span class="cov8" title="1">preloadDB, preloadConditions := scope.generatePreloadDBWithConditions(conditions)
1331
1332 // get relations's primary keys
1333 primaryKeys := scope.getColumnAsArray(relation.ForeignFieldNames, scope.Value)
1334 if len(primaryKeys) == 0 {
1335 return
1336 }
1337
1338 // find relations
1339 results := makeSlice(field.Struct.Type)
1340</span> scope.Err(preloadDB.Where(fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, relation.AssociationForeignDBNames), toQueryMarks(primaryKeys)), toQueryValues(primaryKeys)...).Find(results, preloadConditions...).Error)
1341
1342</span> // assign find results
1343 var (
1344</span> resultsValue = indirect(reflect.ValueOf(results))
1345 indirectScopeValue = scope.IndirectValue()
1346</span> )
1347
1348</span> foreignFieldToObjects := make(map[string][]*reflect.Value)
1349 if indi<span class="cov8" title="1">rectScopeValue.Kind() == reflect.Slice {
1350 for j := 0; j < indirectScopeValue.Len(); j++ {
1351 </span>object := indirect(indirectScopeValue.Index(j))
1352 valueString := toString(getValueFromFields(object, relation.ForeignFieldNames))
1353 foreignFieldToObjects[valueString] = append(foreignFieldToObjects[valueString], &object)
1354 }
1355 }
1356
1357 for i := 0; i < resultsValue.Len(); i++ {
1358 result := resultsValue.Index(i)
1359 if indirectScopeValue.Kind() == reflect.Slice {
1360 valueString := toString(getValueFromFields(result, relation.AssociationForeignFieldNames))
1361 if objects, found := foreignFieldToObjects[valueString]; found {
1362 for _, object := range objects {
1363 object.FieldByName(field.Name).Set(result)
1364 }
1365 }
1366 } else {
1367 scope.Err(field.Set(result))
1368</span> }
1369 }
1370}
1371</span>
1372/<span class="cov8" title="1">/ handleManyToManyPreload used to preload many to many associations
1373func (scope *Scope) handleManyToManyPreload(field *Field, </span><span class="cov8" title="1">conditions []interface{}) {
1374 var (
1375 </span>relation = field.Relationship
1376 joinTableHandler = relation.JoinTableHandler
1377 fieldType = field.Struct.Type.Elem()
1378 <span class="cov8" title="1"> foreignKeyValue interface{}
1379 foreignKeyType = reflect.ValueOf(&foreignKeyValue).Type()
1380 linkHash = map[string][]reflect.Value{}
1381 isPtr bool
1382 )
1383
1384 if fieldType.Kind() == reflect.Ptr {
1385</span> isPtr = true
1386 </span>fieldType = fieldType.Elem()
1387 }
1388
1389 var sourceKeys = []string{}
1390 for _, key := range joinTableHandler.SourceForeignKeys() {
1391 sourceKeys = append(sourceKey</span><span class="cov8" title="1">s, key.DBName)
1392 }
1393
1394</span> // preload conditions
1395 <span class="cov8" title="1">preloadDB, preloadConditions := scope.generatePreloadDBWithConditions(conditions)
1396
1397 // generate query with jo</span><span class="cov0" title="0">in table
1398 newScope := scope.New(reflect.New(fieldType).Interface())
1399 p</span>reloadDB = preloadDB.Table(newScope.TableName()).Model(newScope.Value)
1400
1401 if len(preloadDB.search.selects) == 0 {
1402 preloadDB = preloadDB.Select("*")
1403 }
1404</span>
1405 preloadDB = joinTableHandler.JoinWith(joinTableHandler, preloadDB, scope.Value)
1406
1407 // preload inline conditions
1408 if len(preloadConditions) > 0 {
1409 preloadDB = preloadDB.Where(preloadConditions[0], preloadConditions[1:]...)
1410 }
1411
1412</span> rows, err := preloadDB.Rows()
1413
1414</span> if scope.Err(err) != nil {
1415 <span class="cov8" title="1">return
1416 }
1417 defer rows.Close()
1418
1419 columns, _ := rows.Columns()
1420 for rows.Next() {
1421 var (
1422 elem = reflect.New(fieldType).Elem()
1423 fields = scope.New(elem.Addr().Interface()).Fiel</span><span class="cov8" title="1">ds()
1424 )
1425</span>
1426 //</span> register foreign keys in join tables
1427 var joinTableFields []*Field
1428 <span class="cov8" title="1">for _, sourceKey := range sourceKeys {
1429 joinTableFields = append(joinTableFields, &Field{StructField: &StructField{DBName: sourceKey, IsNormal: true}, Field: reflect.New(foreignKeyType).Elem()})
1430 }
1431</span>
1432 s</span>cope.<span class="cov8" title="1">scan(rows, columns, append(fields, joinTableFields...))
1433
1434 s</span>cope.New(elem.Addr().Interface()).
1435 InstanceSet("gorm:skip_query_callback", true).
1436 callCallbacks(scope.db.parent.callbacks.queries)
1437
1438</span> var foreignKeys = make([]interface{}, len(sourceKeys))
1439 </span>// generate hashed forkey keys in join table
1440 for idx, joinTableField := range joinTableFields {
1441 if !joinTableField.Field.IsNil() {
1442 <span class="cov8" title="1"> foreignKeys[idx] = joinTableField.Field.Elem().Interface()
1443 }
1444 }
1445 hashedSourceKeys := toString(foreignKeys)
1446
1447 if isPtr {
1448 linkHash[hashedSourceKeys] = append(linkHash[has</span><span class="cov8" title="1">hedSourceKeys], elem.Addr())
1449 } else {
1450</span> linkHash[hashedSourceKeys] = append(linkHash[hashedSourceKeys], elem)
1451 }</span>
1452 }
1453
1454 <span class="cov8" title="1">if err := rows.Err(); err != nil {
1455</span> scope.Err(err)
1456</span> }
1457
1458 // assign find results
1459 va</span>r (
1460 indir<span class="cov8" title="1">ectScopeValue = scope.IndirectVal</span><span class="cov8" title="1">ue()
1461 fieldsSourceMap = map[string][]reflect.Value{}
1462 foreignFieldNames = []string{}
1463 )</span>
1464
1465</span> for _, dbName := range relation.ForeignFieldNam</span><span class="cov8" title="1">es {
1466 if field, ok := scope.FieldByName(dbName); ok {
1467 foreignFieldNames = append(foreignFieldNa</span><span class="cov0" title="0">mes, field.Name)
1468 }
1469</span> }
1470
1471</span> if indirectScopeValue.Kind() == reflect.Slice {
1472 for j := 0; j < indirectScopeValue.Len(); j++ {
1473 object := indirect(indirectScopeValue.Index(j))
1474 key := toString(getValueFromFields(object, foreignFieldNames))
1475 fieldsSourceMap[key] = append(fieldsSourceMap[key], object.FieldByName(field.Name))
1476 }
1477 } else if indirectScopeValue.IsValid() {
1478 key := toString(getValueFromFields(indirectScopeValue, foreignFieldNames))
1479 fieldsSourceMap[key] = append(fieldsSourceMap[key], indirectScopeValue.FieldByName(field.Name))
1480 }
1481
1482 for source, fields := range fieldsSourceMap {
1483 for _, f := range fields {
1484 //If not 0 this means Value is a pointer and we already added preloaded models to it
1485 if f.Len() != 0 {
1486 continue
1487 }
1488
1489 v := reflect.MakeSlice(f.Type(), 0, 0)
1490 if len(linkHash[source]) > 0 {
1491 v = reflect.Append(f, linkHash[source]...)
1492 }
1493
1494 f.Set(v)
1495 }
1496 }
1497}
1498</pre>
1499
1500 <pre class="file" id="file6" style="display: none">package gorm
1501
1502import "database/sql"
1503
1504// Define callbacks for row query
1505func init() <span class="cov8" title="1">{
1506 DefaultCallback.RowQuery().Register("gorm:row_query", rowQueryCallback)
1507}</span>
1508
1509type RowQueryResult struct {
1510 Row *sql.Row
1511}
1512
1513type RowsQueryResult struct {
1514 Rows *sql.Rows
1515 Error error
1516}
1517
1518// queryCallback used to query data from database
1519func rowQueryCallback(scope *Scope) <span class="cov8" title="1">{
1520 if result, ok := scope.InstanceGet("row_query_result"); ok </span><span class="cov8" title="1">{
1521 scope.prepareQuerySQL()
1522
1523 if rowResult, ok := result.(*RowQueryResult); ok </span><span class="cov8" title="1">{
1524 rowResult.Row = scope.SQLDB().QueryRow(scope.SQL, scope.SQLVars...)
1525 }</span> else<span class="cov8" title="1"> if rowsResult, ok := result.(*RowsQueryResult); ok </span><span class="cov8" title="1">{
1526 rowsResult.Rows, rowsResult.Error = scope.SQLDB().Query(scope.SQL, scope.SQLVars...)
1527 }</span>
1528 }
1529}
1530</pre>
1531
1532 <pre class="file" id="file7" style="display: none">package gorm
1533
1534import (
1535 "reflect"
1536 "strings"
1537)
1538
1539func beginTransactionCallback(scope *Scope) <span class="cov8" title="1">{
1540 scope.Begin()
1541}</span>
1542
1543func commitOrRollbackTransactionCallback(scope *Scope) <span class="cov8" title="1">{
1544 scope.CommitOrRollback()
1545}</span>
1546
1547func saveAssociationCheck(scope *Scope, field *Field) (autoUpdate bool, autoCreate bool, saveReference bool, r *Relationship) <span class="cov8" title="1">{
1548 checkTruth := func(value interface{}) bool </span><span class="cov8" title="1">{
1549 if v, ok := value.(bool); ok && !v </span><span class="cov8" title="1">{
1550 return false
1551 }</span>
1552
1553 <span class="cov8" title="1">if v, ok := value.(string); ok </span><span class="cov8" title="1">{
1554 v = strings.ToLower(v)
1555 return v == "true"
1556</span> }
1557
1558</span> return true
1559 }
1560
1561</span> if scope.changeableField(field) && !field.IsBlank && !field.IsIgnored {
1562 if r = field.Relationship; r != nil {
1563 <span class="cov8" title="1"> autoUpdate, autoCreate, saveReference = true, true, true
1564</span>
1565</span> if value, ok := scope.Get("gorm:save_associations"); ok {
1566 autoUpdate = checkTruth(value)
1567 autoCreate = autoUpdate
1568</span> saveReference = autoUpdate
1569 } else if value, ok := field.TagSettingsGet("SAVE_ASSOCIATIONS"); ok {
1570 </span>autoU<span class="cov8" title="1">pdate = checkTruth(value)
1571</span> autoCreate = autoUpdate
1572 saveReference = autoUpdate
1573 }</span>
1574
1575 <span class="cov8" title="1">if value, ok := scope.Get("gorm:association_autoupdate"); ok </span><span class="cov8" title="1">{
1576 autoUpdate = checkTruth(value)
1577 }</span> else<span class="cov8" title="1"> if value, ok := field.TagSettingsGet("ASSOCIATION_AUTOUPDATE"); </span><span class="cov8" title="1">ok {
1578 autoUpdate = checkTruth(value)
1579 }</span>
1580
1581 <span class="cov8" title="1">if value, ok := scope.Get("gorm:association_autocreate"); ok </span><span class="cov8" title="1">{
1582 autoCreate = checkTruth(value)
1583 }</span> else<span class="cov8" title="1"> if value, ok := field.TagSettingsGet("ASSOCIATION_AUTOCREATE"); </span><span class="cov8" title="1">ok {
1584 autoCreate = checkTruth(value)
1585 }</span>
1586
1587 <span class="cov8" title="1">if value, ok := scope.Get("gorm:association_save_reference"); ok </span><span class="cov0" title="0">{
1588 saveReference = checkTruth(value)
1589 }</span> else<span class="cov8" title="1"> if value, ok := field.TagSettingsGet("ASSOCIATION_SAVE_REFERENCE"); </span><span class="cov0" title="0">ok {
1590 saveReference = checkTruth(value)
1591 }</span>
1592 }
1593 }
1594
1595 <span class="cov8" title="1">return</span>
1596}
1597
1598func saveBeforeAssociationsCallback(scope *Scope) <span class="cov8" title="1">{
1599 for _, field := range scope.Fields() </span><span class="cov8" title="1">{
1600 autoUpdate, autoCreate, saveReference, relationship := saveAssociationCheck(scope, field)
1601
1602 if relationship != nil && relationship.Kind == "belongs_to" </span><span class="cov8" title="1">{
1603 fieldValue := field.Field.Addr().Interface()
1604 newScope := scope.New(fieldValue)
1605
1606 if newScope.PrimaryKeyZero() </span><span class="cov8" title="1">{
1607 if autoCreate </span><span class="cov8" title="1">{
1608 scope.Err(scope.NewDB().Save(fieldValue).Error)
1609 }</span>
1610 } else<span class="cov8" title="1"> if autoUpdate </span><span class="cov8" title="1">{
1611 scope.Err(scope.NewDB().Save(fieldValue).Error)
1612 }</span>
1613
1614 <span class="cov8" title="1">if saveReference </span><span class="cov8" title="1">{
1615 if len(relationship.ForeignFieldNames) != 0 </span><span class="cov8" title="1">{
1616 // set value's foreign key
1617 for idx, fieldName := range relationship.ForeignFieldNames </span><span class="cov8" title="1">{
1618 associationForeignName := relationship.AssociationForeignDBNames[idx]
1619 if foreignField, ok := scope.New(fieldValue).FieldByName(associationForeignName); ok </span><span class="cov8" title="1">{
1620 scope.Err(scope.SetColumn(fieldName, foreignField.Field.Interface()))
1621 }</span>
1622 }
1623 }
1624 }
1625 }
1626 }
1627}
1628
1629func saveAfterAssociationsCallback(scope *Scope) <span class="cov8" title="1">{
1630 for _, field := range scope.Fields() </span><span class="cov8" title="1">{
1631 autoUpdate, autoCreate, saveReference, relationship := saveAssociationCheck(scope, field)
1632
1633 if relationship != nil && (relationship.Kind == "has_one" || relationship.Kind == "has_many" || relationship.Kind == "many_to_many") </span><span class="cov8" title="1">{
1634 value := field.Field
1635
1636 switch value.Kind() </span>{
1637 case reflect.Slice:<span class="cov8" title="1">
1638 for i := 0; i < value.Len(); i++ </span><span class="cov8" title="1">{
1639 newDB := scope.NewDB()
1640 elem := value.Index(i).Addr().Interface()
1641 newScope := newDB.NewScope(elem)
1642
1643 if saveReference </span><span class="cov8" title="1">{
1644 if relationship.JoinTableHandler == nil && len(relationship.ForeignFieldNames) != 0 </span><span class="cov8" title="1">{
1645 for idx, fieldName := range relationship.ForeignFieldNames </span><span class="cov8" title="1">{
1646 associationForeignName := relationship.AssociationForeignDBNames[idx]
1647 if f, ok := scope.FieldByName(associationForeignName); ok </span><span class="cov8" title="1">{
1648 scope.Err(newScope.SetColumn(fieldName, f.Field.Interface()))
1649 }</span>
1650 }
1651 }
1652
1653 <span class="cov8" title="1">if relationship.PolymorphicType != "" </span><span class="cov8" title="1">{
1654 scope.Err(newScope.SetColumn(relationship.PolymorphicType, relationship.PolymorphicValue))
1655 }</span>
1656 }
1657
1658 <span class="cov8" title="1">if newScope.PrimaryKeyZero() </span><span class="cov8" title="1">{
1659 if autoCreate </span><span class="cov8" title="1">{
1660 scope.Err(newDB.Save(elem).Error)
1661 }</span>
1662 } else<span class="cov8" title="1"> if autoUpdate </span><span class="cov8" title="1">{
1663 scope.Err(newDB.Save(elem).Error)
1664 }</span>
1665
1666 <span class="cov8" title="1">if !scope.New(newScope.Value).PrimaryKeyZero() && saveReference </span><span class="cov8" title="1">{
1667 if joinTableHandler := relationship.JoinTableHandler; joinTableHandler != nil </span><span class="cov8" title="1">{
1668 scope.Err(joinTableHandler.Add(joinTableHandler, newDB, scope.Value, newScope.Value))
1669 }</span>
1670 }
1671 }
1672 default:<span class="cov8" title="1">
1673 elem := value.Addr().Interface()
1674 newScope := scope.New(elem)
1675
1676 if saveReference </span><span class="cov8" title="1">{
1677 if len(relationship.ForeignFieldNames) != 0 </span><span class="cov8" title="1">{
1678 for idx, fieldName := range relationship.ForeignFieldNames </span><span class="cov8" title="1">{
1679 associationForeignName := relationship.AssociationForeignDBNames[idx]
1680 if f, ok := scope.FieldByName(associationForeignName); ok </span><span class="cov8" title="1">{
1681 scope.Err(newScope.SetColumn(fieldName, f.Field.Interface()))
1682 }</span>
1683 }
1684 }
1685
1686 <span class="cov8" title="1">if relationship.PolymorphicType != "" </span><span class="cov8" title="1">{
1687 scope.Err(newScope.SetColumn(relationship.PolymorphicType, relationship.PolymorphicValue))
1688 }</span>
1689 }
1690
1691 <span class="cov8" title="1">if newScope.PrimaryKeyZero() </span><span class="cov8" title="1">{
1692 if autoCreate </span><span class="cov8" title="1">{
1693 scope.Err(scope.NewDB().Save(elem).Error)
1694 }</span>
1695 } else<span class="cov8" title="1"> if autoUpdate </span><span class="cov8" title="1">{
1696 scope.Err(scope.NewDB().Save(elem).Error)
1697 }</span>
1698 }
1699 }
1700 }
1701}
1702</pre>
1703
1704 <pre class="file" id="file8" style="display: none">package gorm
1705
1706import (
1707 "errors"
1708 "fmt"
1709 "sort"
1710 "strings"
1711)
1712
1713// Define callbacks for updating
1714func init() <span class="cov8" title="1">{
1715 DefaultCallback.Update().Register("gorm:assign_updating_attributes", assignUpdatingAttributesCallback)
1716 DefaultCallback.Update().Register("gorm:begin_transaction", beginTransactionCallback)
1717 DefaultCallback.Update().Register("gorm:before_update", beforeUpdateCallback)
1718 DefaultCallback.Update().Register("gorm:save_before_associations", saveBeforeAssociationsCallback)
1719 DefaultCallback.Update().Register("gorm:update_time_stamp", updateTimeStampForUpdateCallback)
1720 DefaultCallback.Update().Register("gorm:update", updateCallback)
1721 DefaultCallback.Update().Register("gorm:save_after_associations", saveAfterAssociationsCallback)
1722 DefaultCallback.Update().Register("gorm:after_update", afterUpdateCallback)
1723 DefaultCallback.Update().Register("gorm:commit_or_rollback_transaction", commitOrRollbackTransactionCallback)
1724}</span>
1725
1726// assignUpdatingAttributesCallback assign updating attributes to model
1727func assignUpdatingAttributesCallback(scope *Scope) <span class="cov8" title="1">{
1728 if attrs, ok := scope.InstanceGet("gorm:update_interface"); ok </span><span class="cov8" title="1">{
1729 if updateMaps, hasUpdate := scope.updatedAttrsWithValues(attrs); hasUpdate </span><span class="cov8" title="1">{
1730 scope.InstanceSet("gorm:update_attrs", updateMaps)
1731 }</span> else<span class="cov0" title="0"> {
1732 scope.SkipLeft()
1733 }</span>
1734 }
1735}
1736
1737// beforeUpdateCallback will invoke `BeforeSave`, `BeforeUpdate` method before updating
1738func beforeUpdateCallback(scope *Scope) <span class="cov8" title="1">{
1739 if scope.DB().HasBlockGlobalUpdate() && !scope.hasConditions() </span><span class="cov8" title="1">{
1740 scope.Err(errors.New("Missing WHERE clause while updating"))
1741 return
1742 }</span>
1743 <span class="cov8" title="1">if _, ok := scope.Get("gorm:update_column"); !ok </span><span class="cov8" title="1">{
1744 if !scope.HasError() </span><span class="cov8" title="1">{
1745 scope.CallMethod("BeforeSave")
1746 }</span>
1747 <span class="cov8" title="1">if !scope.HasError() </span><span class="cov8" title="1">{
1748 scope.CallMethod("BeforeUpdate")
1749 }</span>
1750 }
1751}
1752
1753// updateTimeStampForUpdateCallback will set `UpdatedAt` when updating
1754func updateTimeStampForUpdateCallback(scope *Scope) <span class="cov8" title="1">{
1755 if _, ok := scope.Get("gorm:update_column"); !ok </span><span class="cov8" title="1">{
1756 scope.SetColumn("UpdatedAt", NowFunc())
1757 }</span>
1758}
1759
1760// updateCallback the callback used to update data to database
1761func updateCallback(scope *Scope) <span class="cov8" title="1">{
1762 if !scope.HasError() </span><span class="cov8" title="1">{
1763 var sqls []string
1764
1765 if updateAttrs, ok := scope.InstanceGet("gorm:update_attrs"); ok </span><span class="cov8" title="1">{
1766 // Sort the column names so that the generated SQL is the same every time.
1767 updateMap := updateAttrs.(map[string]interface{})
1768 var columns []string
1769 for c := range updateMap </span><span class="cov8" title="1">{
1770 columns = append(columns, c)
1771 }</span>
1772 <span class="cov8" title="1">sort.Strings(columns)
1773
1774 for _, column := range columns </span><span class="cov8" title="1">{
1775 value := updateMap[column]
1776 sqls = append(sqls, fmt.Sprintf("%v = %v", scope.Quote(column), scope.AddToVars(value)))
1777 }</span>
1778 } else<span class="cov8" title="1"> {
1779 for _, field := range scope.Fields() </span><span class="cov8" title="1">{
1780 if scope.changeableField(field) </span><span class="cov8" title="1">{
1781 if !field.IsPrimaryKey && field.IsNormal </span><span class="cov8" title="1">&& (field.Name != "CreatedAt" || !field.IsBlank) {
1782 if !field.IsForeignKey || !field.IsBlank || !field.HasDefaultValue {
1783 </span> sqls<span class="cov8" title="1"> = append(sqls, fmt.Sprintf("%v = %v", scope.Quote(field.DBName), scope.AddToVars(field.Field.Int</span><span class="cov8" title="1">erface())))
1784 }
1785</span> } else if relationship := field.Relationship; relationship != nil && relationship.Kind == "belongs_</span><span class="cov8" title="1">to" {
1786 for _, foreignKey := range relationship.ForeignDBNames {
1787 if foreignField, ok := scope.FieldByName(foreignKey); ok && !scope.changeableField(foreignField) {
1788 </span>sqls = append(sqls,
1789 fmt.Sprintf("%v = %v", scope.Quote(foreignField.DBName), scope.AddToVars(foreignField.Field.Interface())))
1790 }
1791 }
1792 }
1793 }
1794 }
1795 <span class="cov8" title="1">}
1796
1797</span> var extraOption string
1798 i</span>f str, ok := scope.Get("gorm:update_option"); ok {
1799 extraOption = fmt.Sprint(str)
1800 <span class="cov8" title="1">}
1801</span>
1802 if len(sqls) > 0 {
1803 scope.Raw(fmt.Sprintf(
1804 "UPDATE %v SET %v%v%v",
1805 scope.QuotedTableName(),
1806 strings.Join(sqls, ", "),
1807 addExtraSpaceIfExist(scope.CombinedConditionSql()),
1808 </span> addExtraSpaceIfExist(extraOption),
1809 )).Exec()
1810 }
1811 }
1812}
1813
1814// afterUpdateCallback will invoke `AfterUpdate`, </span><span class="cov8" title="1">`AfterSave` method after updating
1815func afterUpdateCallbac</span><span class="cov8" title="1">k(scope *Scope) {
1816 if _, ok := scope.Get("gorm:update_column"); !ok {
1817 i</span>f !scope.HasError() {
1818 <span class="cov8" title="1"> scope.CallMethod("Af</span><span class="cov8" title="1">terUpdate")
1819 }
1820 i</span>f !scope.HasError() {
1821 scope.CallMethod("AfterSave")
1822 }
1823 }
1824}
1825</pre>
1826
1827 <pre class="file" id="file9" style="display: none">package gorm
1828
1829import (
1830 "database/sql"
1831 "fmt"
1832 "reflect"
1833 "strconv"
1834 "strings"
1835)
1836
1837// Dialect interface contains behaviors that differ across SQL database
1838type Dialect interface {
1839 // GetName get dialect's name
1840 GetName() string
1841
1842 // SetDB set db for dialect
1843 SetDB(db SQLCommon)
1844
1845 // BindVar return the placeholder for actual values in SQL statements, in many dbs it is "?", Postgres using $1
1846 BindVar(i int) string
1847 // Quote quotes field name to avoid SQL parsing exceptions by using a reserved word as a field name
1848 Quote(key string) string
1849 // DataTypeOf return data's sql type
1850 DataTypeOf(field *StructField) string
1851
1852 // HasIndex check has index or not
1853 HasIndex(tableName string, indexName string) bool
1854 // HasForeignKey check has foreign key or not
1855 HasForeignKey(tableName string, foreignKeyName string) bool
1856 // RemoveIndex remove index
1857 RemoveIndex(tableName string, indexName string) error
1858 // HasTable check has table or not
1859 HasTable(tableName string) bool
1860 // HasColumn check has column or not
1861 HasColumn(tableName string, columnName string) bool
1862 // ModifyColumn modify column's type
1863 ModifyColumn(tableName string, columnName string, typ string) error
1864
1865 // LimitAndOffsetSQL return generated SQL with Limit and Offset, as mssql has special case
1866 LimitAndOffsetSQL(limit, offset interface{}) string
1867 // SelectFromDummyTable return select values, for most dbs, `SELECT values` just works, mysql needs `SELECT value FROM DUAL`
1868 SelectFromDummyTable() string
1869 // LastInsertIdReturningSuffix most dbs support LastInsertId, but postgres needs to use `RETURNING`
1870 LastInsertIDReturningSuffix(tableName, columnName string) string
1871 // DefaultValueStr
1872 DefaultValueStr() string
1873
1874 // BuildKeyName returns a valid key name (foreign key, index key) for the given table, field and reference
1875 BuildKeyName(kind, tableName string, fields ...string) string
1876
1877 // CurrentDatabase return current database name
1878 CurrentDatabase() string
1879}
1880
1881var dialectsMap = map[string]Dialect{}
1882
1883func newDialect(name string, db SQLCommon) Dialect <span class="cov8" title="1">{
1884 if value, ok := dialectsMap[name]; ok </span><span class="cov8" title="1">{
1885 dialect := reflect.New(reflect.TypeOf(value).Elem()).Interface().(Dialect)
1886 dialect.SetDB(db)
1887 return dialect
1888 }</span>
1889
1890 <span class="cov8" title="1">fmt.Printf("`%v` is not officially supported, running under compatibility mode.\n", name)
1891 commontDialect := &commonDialect{}
1892 commontDialect.SetDB(db)
1893 return commontDialect</span>
1894}
1895
1896// RegisterDialect register new dialect
1897func RegisterDialect(name string, dialect Dialect) <span class="cov8" title="1">{
1898 dialectsMap[name] = dialect
1899}</span>
1900
1901// GetDialect gets the dialect for the specified dialect name
1902func GetDialect(name string) (dialect Dialect, ok bool) {
1903 dialect, ok = dialectsMap[name]
1904 return
1905}
1906
1907// ParseFieldStructForDialect get field's sql data type
1908var ParseFieldStructForDialect = func(field *StructField, dialect Dialect) (fieldValue reflect.Value, sqlType string, size int, additionalType string) {
1909 // Get redirected field type
1910</span> var (
1911 </span>reflectType = field.Struct.Type
1912 dataType, _ = field.TagSettingsGet("TYPE")
1913 )
1914
1915 for reflectType.Kind() == reflect.Ptr {
1916 reflectType = reflectType.Elem()
1917 }
1918
1919</span> // Get redirected field value
1920 f</span>ieldValue = reflect.Indirect(reflect.New(reflectType))
1921
1922 if gormDataType, ok := fieldValue.Interface().(interface {
1923 <span class="cov8" title="1"> GormDataType(Dial</span><span class="cov8" title="1">ect) string
1924 }); ok {
1925 dataType = gormDataType.GormDataType(dialect</span><span class="cov8" title="1">)
1926 }
1927
1928</span> // Get scanner's real value
1929 if </span>dataType == "" {
1930 var getScannerValue func(reflect.Value)
1931 <span class="cov8" title="1">getScannerValue = func(valu</span>e reflect.Value) {
1932 fieldValue = value
1933 if _, isScanner := reflect.New(fieldValue.Type()).Interface().(sql.Scanner); isScanner && fieldValue.Kind() == reflect.Struct {
1934 getScannerValue(fieldValue.Field(0))
1935 <span class="cov8" title="1"> }
1936</span> }
1937 </span>getSc<span class="cov8" title="1">annerValue(fieldValue)
1938 }
1939
1940</span> // Default Size
1941 if num, ok := field.TagSettingsGet("SIZE"); ok {
1942 <span class="cov8" title="1"> size, _ = strconv.Atoi(num)
1943 } else {
1944</span> size = 255
1945 }</span>
1946
1947 <span class="cov8" title="1">// Default type from tag setting
1948</span> notNull, _ := field.TagSettingsGet("NOT NULL")
1949 unique, _ := field.TagSettingsGet("UNIQUE")
1950 additionalType = notNull + " " + unique
1951 if value, ok := field.TagSettingsGet</span><span class="cov0" title="0">("DEFAULT"); ok {
1952 additionalType = additionalType + " DEFAULT " + value
1953 }
1954
1955</span> <span class="cov0" title="0">if value, ok := field.TagSettingsGet("COMME</span>NT"); ok {
1956 additionalType = additionalType + " COMMENT " + value
1957 }
1958
1959 return fieldValue, dataType, size, strings.TrimSpace(additionalType)
1960}
1961
1962func currentDatabaseAndTable(dialect Dialect, tableName string) (string, string) {
1963 if strings.Contains(tableName, ".") {
1964 splitStrings := strings.SplitN(tableName, ".", 2)
1965 return splitStrings[0], splitStrings[1]
1966 }
1967 return dialect.CurrentDatabase(), tableName
1968}
1969</pre>
1970
1971 <pre class="file" id="file10" style="display: none">package gorm
1972
1973import (
1974 "fmt"
1975 "reflect"
1976 "regexp"
1977 "strconv"
1978 "strings"
1979 "time"
1980)
1981
1982// DefaultForeignKeyNamer contains the default foreign key name generator method
1983type DefaultForeignKeyNamer struct {
1984}
1985
1986type commonDialect struct {
1987 db SQLCommon
1988 DefaultForeignKeyNamer
1989}
1990
1991func init() <span class="cov8" title="1">{
1992 RegisterDialect("common", &commonDialect{})
1993}</span>
1994
1995func (commonDialect) GetName() string <span class="cov0" title="0">{
1996 return "common"
1997}</span>
1998
1999func (s *commonDialect) SetDB(db SQLCommon) <span class="cov8" title="1">{
2000 s.db = db
2001}</span>
2002
2003func (commonDialect) BindVar(i int) string <span class="cov8" title="1">{
2004 return "$$$" // ?
2005}</span>
2006
2007func (commonDialect) Quote(key string) string <span class="cov8" title="1">{
2008 return fmt.Sprintf(`"%s"`, key)
2009}</span>
2010
2011func (s *commonDialect) fieldCanAutoIncrement(field *StructField) bool <span class="cov8" title="1">{
2012 if value, ok := field.TagSettingsGet("AUTO_INCREMENT"); </span><span class="cov8" title="1">ok {
2013 return strings.ToLower(value) != "false"
2014 }</span>
2015 <span class="cov8" title="1">return field.IsPrimaryKey</span>
2016}
2017
2018func (s *commonDialect) DataTypeOf(field *StructField) string <span class="cov0" title="0">{
2019 var dataValue, sqlType, size, additionalType = ParseFieldStructForDialect(field, s)
2020
2021 if sqlType == "" </span><span class="cov0" title="0">{
2022 switch dataValue.Kind() </span>{
2023 case reflect.Bool:<span class="cov0" title="0">
2024 sqlType = "BOOLEAN"</span>
2025 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr:<span class="cov0" title="0">
2026 if s.fieldCanAutoIncrement(field) </span><span class="cov0" title="0">{
2027 sqlType = "INTEGER AUTO_INCREMENT"
2028 }</span> else<span class="cov0" title="0"> {
2029 sqlType = "INTEGER"
2030 }</span>
2031 case reflect.Int64, reflect.Uint64:<span class="cov0" title="0">
2032 if s.fieldCanAutoIncrement(field) </span><span class="cov0" title="0">{
2033 sqlType = "BIGINT AUTO_INCREMENT"
2034 }</span> else<span class="cov0" title="0"> {
2035 sqlType = "BIGINT"
2036 }</span>
2037 case reflect.Float32, reflect.Float64:<span class="cov0" title="0">
2038 sqlType = "FLOAT"</span>
2039 case reflect.String:<span class="cov0" title="0">
2040 if size > 0 && size < 65532 </span><span class="cov0" title="0">{
2041 sqlType = fmt.Sprintf("VARCHAR(%d)", size)
2042 }</span> else<span class="cov0" title="0"> {
2043 sqlType = "VARCHAR(65532)"
2044 }</span>
2045 case reflect.Struct:<span class="cov0" title="0">
2046 if _, ok := dataValue.Interface().(time.Time); ok </span><span class="cov0" title="0">{
2047 sqlType = "TIMESTAMP"
2048 }</span>
2049 default:<span class="cov0" title="0">
2050 if _, ok := dataValue.Interface().([]byte); ok </span><span class="cov0" title="0">{
2051 if size > 0 && size < 65532 </span><span class="cov0" title="0">{
2052 sqlType = fmt.Sprintf("BINARY(%d)", size)
2053 }</span> else<span class="cov0" title="0"> {
2054 sqlType = "BINARY(65532)"
2055 }</span>
2056 }
2057 }
2058 }
2059
2060 <span class="cov0" title="0">if sqlType == "" </span><span class="cov0" title="0">{
2061 panic(fmt.Sprintf("invalid sql type %s (%s) for commonDialect", dataValue.Type().Name(), dataValue.Kind().String()))</span>
2062 }
2063
2064 <span class="cov0" title="0">if strings.TrimSpace(additionalType) == "" </span><span class="cov0" title="0">{
2065 return sqlType
2066 }</span>
2067 <span class="cov0" title="0">return fmt.Sprintf("%v %v", sqlType, additionalType)</span>
2068}
2069
2070func (s commonDialect) HasIndex(tableName string, indexName string) bool <span class="cov0" title="0">{
2071 var count int
2072 currentDatabase, tableName := currentDatabaseAndTable(&s, tableName)
2073 s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.STATISTICS WHERE table_schema = ? AND table_name = ? AND index_name = ?", currentDatabase, tableName, indexName).Scan(&count)
2074 return count > 0
2075}</span>
2076
2077func (s commonDialect) RemoveIndex(tableName string, indexName string) error <span class="cov8" title="1">{
2078 _, err := s.db.Exec(fmt.Sprintf("DROP INDEX %v", indexName))
2079 return err
2080}</span>
2081
2082func (s commonDialect) HasForeignKey(tableName string, foreignKeyName string) bool <span class="cov0" title="0">{
2083 return false
2084}</span>
2085
2086func (s commonDialect) HasTable(tableName string) bool <span class="cov0" title="0">{
2087 var count int
2088 currentDatabase, tableName := currentDatabaseAndTable(&s, tableName)
2089 s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = ? AND table_name = ?", currentDatabase, tableName).Scan(&count)
2090 return count > 0
2091}</span>
2092
2093func (s commonDialect) HasColumn(tableName string, columnName string) bool <span class="cov0" title="0">{
2094 var count int
2095 currentDatabase, tableName := currentDatabaseAndTable(&s, tableName)
2096 s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = ? AND table_name = ? AND column_name = ?", currentDatabase, tableName, columnName).Scan(&count)
2097 return count > 0
2098}</span>
2099
2100func (s commonDialect) ModifyColumn(tableName string, columnName string, typ string) error <span class="cov0" title="0">{
2101 _, err := s.db.Exec(fmt.Sprintf("ALTER TABLE %v ALTER COLUMN %v TYPE %v", tableName, columnName, typ))
2102 return err
2103}</span>
2104
2105func (s commonDialect) CurrentDatabase() (name string) <span class="cov0" title="0">{
2106 s.db.QueryRow("SELECT DATABASE()").Scan(&name)
2107 return
2108}</span>
2109
2110func (commonDialect) LimitAndOffsetSQL(limit, offset interface{}) (sql string) <span class="cov8" title="1">{
2111 if limit != nil </span><span class="cov8" title="1">{
2112 if parsedLimit, err := strconv.ParseInt(fmt.Sprint(limit), 0, 0); err == nil && parsedLimit >= 0 </span><span class="cov8" title="1">{
2113 sql += fmt.Sprintf(" LIMIT %d", parsedLimit)
2114 }</span>
2115 }
2116 <span class="cov8" title="1">if offset != nil </span><span class="cov8" title="1">{
2117 if parsedOffset, err := strconv.ParseInt(fmt.Sprint(offset), 0, 0); err == nil && parsedOffset >= 0 </span><span class="cov8" title="1">{
2118 sql += fmt.Sprintf(" OFFSET %d", parsedOffset)
2119 }</span>
2120 }
2121 <span class="cov8" title="1">return</span>
2122}
2123
2124func (commonDialect) SelectFromDummyTable() string <span class="cov8" title="1">{
2125 return ""
2126}</span>
2127
2128func (commonDialect) LastInsertIDReturningSuffix(tableName, columnName string) string <span class="cov8" title="1">{
2129 return ""
2130}</span>
2131
2132func (commonDialect) DefaultValueStr() string <span class="cov8" title="1">{
2133 return "DEFAULT VALUES"
2134}</span>
2135
2136// BuildKeyName returns a valid key name (foreign key, index key) for the given table, field and reference
2137func (DefaultForeignKeyNamer) BuildKeyName(kind, tableName string, fields ...string) string <span class="cov8" title="1">{
2138 keyName := fmt.Sprintf("%s_%s_%s", kind, tableName, strings.Join(fields, "_"))
2139 keyName = regexp.MustCompile("[^a-zA-Z0-9]+").ReplaceAllString(keyName, "_")
2140 return keyName
2141}</span>
2142
2143// IsByteArrayOrSlice returns true of the reflected value is an array or slice
2144func IsByteArrayOrSlice(value reflect.Value) bool <span class="cov8" title="1">{
2145 return (value.Kind() == reflect.Array || value.Kind() == reflect.Slice) && value.Type().Elem() == reflect.TypeOf(uint8(0))
2146}</span>
2147</pre>
2148
2149 <pre class="file" id="file11" style="display: none">package gorm
2150
2151import (
2152 "crypto/sha1"
2153 "fmt"
2154 "reflect"
2155 "regexp"
2156 "strconv"
2157 "strings"
2158 "time"
2159 "unicode/utf8"
2160)
2161
2162type mysql struct {
2163 commonDialect
2164}
2165
2166func init() <span class="cov8" title="1">{
2167 RegisterDialect("mysql", &mysql{})
2168}</span>
2169
2170func (mysql) GetName() string <span class="cov0" title="0">{
2171 return "mysql"
2172}</span>
2173
2174func (mysql) Quote(key string) string <span class="cov0" title="0">{
2175 return fmt.Sprintf("`%s`", key)
2176}</span>
2177
2178// Get Data Type for MySQL Dialect
2179func (s *mysql) DataTypeOf(field *StructField) string <span class="cov0" title="0">{
2180 var dataValue, sqlType, size, additionalType = ParseFieldStructForDialect(field, s)
2181
2182 // MySQL allows only one auto increment column per table, and it must
2183 // be a KEY column.
2184 if _, ok := field.TagSettingsGet("AUTO_INCREMENT"); </span><span class="cov0" title="0">ok {
2185 if _, ok = field.TagSettingsGet("INDEX"); !ok && !field.IsPrimaryK</span><span class="cov0" title="0">ey {
2186 field.TagSettingsDelete("AUTO_INCREMENT")
2187 }</span>
2188 }
2189
2190 <span class="cov0" title="0">if sqlType == "" </span><span class="cov0" title="0">{
2191 switch dataValue.Kind() </span>{
2192 case reflect.Bool:<span class="cov0" title="0">
2193 sqlType = "boolean"</span>
2194 case reflect.Int8:<span class="cov0" title="0">
2195 if s.fieldCanAutoIncrement(field) </span><span class="cov0" title="0">{
2196 field.TagSettingsSet("AUTO_INCREMENT", "AUTO_INCREMENT")
2197 sqlType = "tinyint AUTO_INCREMENT"
2198 }</span> else<span class="cov0" title="0"> {
2199 sqlType = "tinyint"
2200 }</span>
2201 case reflect.Int, reflect.Int16, reflect.Int32:<span class="cov0" title="0">
2202 if s.fieldCanAutoIncrement(field) </span><span class="cov0" title="0">{
2203 field.TagSettingsSet("AUTO_INCREMENT", "AUTO_INCREMENT")
2204 sqlType = "int AUTO_INCREMENT"
2205 }</span> else<span class="cov0" title="0"> {
2206 sqlType = "int"
2207 }</span>
2208 case reflect.Uint8:<span class="cov0" title="0">
2209 if s.fieldCanAutoIncrement(field) </span><span class="cov0" title="0">{
2210 field.TagSettingsSet("AUTO_INCREMENT", "AUTO_INCREMENT")
2211 sqlType = "tinyint unsigned AUTO_INCREMENT"
2212 }</span> else<span class="cov0" title="0"> {
2213 sqlType = "tinyint unsigned"
2214 }</span>
2215 case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uintptr:<span class="cov0" title="0">
2216 if s.fieldCanAutoIncrement(field) </span><span class="cov0" title="0">{
2217 field.TagSettingsSet("AUTO_INCREMENT", "AUTO_INCREMENT")
2218 sqlType = "int unsigned AUTO_INCREMENT"
2219 }</span> else<span class="cov0" title="0"> {
2220 sqlType = "int unsigned"
2221 }</span>
2222 case reflect.Int64:<span class="cov0" title="0">
2223 if s.fieldCanAutoIncrement(field) </span><span class="cov0" title="0">{
2224 field.TagSettingsSet("AUTO_INCREMENT", "AUTO_INCREMENT")
2225 sqlType = "bigint AUTO_INCREMENT"
2226 }</span> else<span class="cov0" title="0"> {
2227 sqlType = "bigint"
2228 }</span>
2229 case reflect.Uint64:<span class="cov0" title="0">
2230 if s.fieldCanAutoIncrement(field) </span><span class="cov0" title="0">{
2231 field.TagSettingsSet("AUTO_INCREMENT", "AUTO_INCREMENT")
2232 sqlType = "bigint unsigned AUTO_INCREMENT"
2233 }</span> else<span class="cov0" title="0"> {
2234 sqlType = "bigint unsigned"
2235 }</span>
2236 case reflect.Float32, reflect.Float64:<span class="cov0" title="0">
2237 sqlType = "double"</span>
2238 case reflect.String:<span class="cov0" title="0">
2239 if size > 0 && size < 65532 </span><span class="cov0" title="0">{
2240 sqlType = fmt.Sprintf("varchar(%d)", size)
2241 }</span> else<span class="cov0" title="0"> {
2242 sqlType = "longtext"
2243 }</span>
2244 case reflect.Struct:<span class="cov0" title="0">
2245 if _, ok := dataValue.Interface().(time.Time); ok </span><span class="cov0" title="0">{
2246 precision := ""
2247 if p, ok := field.TagSettingsGet("PRECISION"); </span><span class="cov0" title="0">ok {
2248 precision = fmt.Sprintf("(%s)", p)
2249 }</span>
2250
2251 <span class="cov0" title="0">if _, ok := field.TagSettingsGet("NOT NULL"); </span><span class="cov0" title="0">ok {
2252 sqlType = fmt.Sprintf("timestamp%v", precision)
2253 }</span> else<span class="cov0" title="0"> {
2254 sqlType = fmt.Sprintf("timestamp%v NULL", precision)
2255 }</span>
2256 }
2257 default:<span class="cov0" title="0">
2258 if IsByteArrayOrSlice(dataValue) </span><span class="cov0" title="0">{
2259 if size > 0 && size < 65532 </span><span class="cov0" title="0">{
2260 sqlType = fmt.Sprintf("varbinary(%d)", size)
2261 }</span> else<span class="cov0" title="0"> {
2262 sqlType = "longblob"
2263 }</span>
2264 }
2265 }
2266 }
2267
2268 <span class="cov0" title="0">if sqlType == "" </span><span class="cov0" title="0">{
2269 panic(fmt.Sprintf("invalid sql type %s (%s) for mysql", dataValue.Type().Name(), dataValue.Kind().String()))</span>
2270 }
2271
2272 <span class="cov0" title="0">if strings.TrimSpace(additionalType) == "" </span><span class="cov0" title="0">{
2273 return sqlType
2274 }</span>
2275 <span class="cov0" title="0">return fmt.Sprintf("%v %v", sqlType, additionalType)</span>
2276}
2277
2278func (s mysql) RemoveIndex(tableName string, indexName string) error <span class="cov0" title="0">{
2279 _, err := s.db.Exec(fmt.Sprintf("DROP INDEX %v ON %v", indexName, s.Quote(tableName)))
2280 return err
2281}</span>
2282
2283func (s mysql) ModifyColumn(tableName string, columnName string, typ string) error <span class="cov0" title="0">{
2284 _, err := s.db.Exec(fmt.Sprintf("ALTER TABLE %v MODIFY COLUMN %v %v", tableName, columnName, typ))
2285 return err
2286}</span>
2287
2288func (s mysql) LimitAndOffsetSQL(limit, offset interface{}) (sql string) <span class="cov0" title="0">{
2289 if limit != nil </span><span class="cov0" title="0">{
2290 if parsedLimit, err := strconv.ParseInt(fmt.Sprint(limit), 0, 0); err == nil && parsedLimit >= 0 </span><span class="cov0" title="0">{
2291 sql += fmt.Sprintf(" LIMIT %d", parsedLimit)
2292
2293 if offset != nil </span><span class="cov0" title="0">{
2294 if parsedOffset, err := strconv.ParseInt(fmt.Sprint(offset), 0, 0); err == nil && parsedOffset >= 0 </span><span class="cov0" title="0">{
2295 sql += fmt.Sprintf(" OFFSET %d", parsedOffset)
2296 }</span>
2297 }
2298 }
2299 }
2300 <span class="cov0" title="0">return</span>
2301}
2302
2303func (s mysql) HasForeignKey(tableName string, foreignKeyName string) bool <span class="cov0" title="0">{
2304 var count int
2305 currentDatabase, tableName := currentDatabaseAndTable(&s, tableName)
2306 s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_SCHEMA=? AND TABLE_NAME=? AND CONSTRAINT_NAME=? AND CONSTRAINT_TYPE='FOREIGN KEY'", currentDatabase, tableName, foreignKeyName).Scan(&count)
2307 return count > 0
2308}</span>
2309
2310func (s mysql) CurrentDatabase() (name string) <span class="cov0" title="0">{
2311 s.db.QueryRow("SELECT DATABASE()").Scan(&name)
2312 return
2313}</span>
2314
2315func (mysql) SelectFromDummyTable() string <span class="cov0" title="0">{
2316 return "FROM DUAL"
2317}</span>
2318
2319func (s mysql) BuildKeyName(kind, tableName string, fields ...string) string <span class="cov0" title="0">{
2320 keyName := s.commonDialect.BuildKeyName(kind, tableName, fields...)
2321 if utf8.RuneCountInString(keyName) <= 64 </span><span class="cov0" title="0">{
2322 return keyName
2323 }</span>
2324 <span class="cov0" title="0">h := sha1.New()
2325 h.Write([]byte(keyName))
2326 bs := h.Sum(nil)
2327
2328 // sha1 is 40 characters, keep first 24 characters of destination
2329 destRunes := []rune(regexp.MustCompile("[^a-zA-Z0-9]+").ReplaceAllString(fields[0], "_"))
2330 if len(destRunes) > 24 </span><span class="cov0" title="0">{
2331 destRunes = destRunes[:24]
2332 }</span>
2333
2334 <span class="cov0" title="0">return fmt.Sprintf("%s%x", string(destRunes), bs)</span>
2335}
2336
2337func (mysql) DefaultValueStr() string <span class="cov0" title="0">{
2338 return "VALUES()"
2339}</span>
2340</pre>
2341
2342 <pre class="file" id="file12" style="display: none">package gorm
2343
2344import (
2345 "encoding/json"
2346 "fmt"
2347 "reflect"
2348 "strings"
2349 "time"
2350)
2351
2352type postgres struct {
2353 commonDialect
2354}
2355
2356func init() <span class="cov8" title="1">{
2357 RegisterDialect("postgres", &postgres{})
2358 RegisterDialect("cloudsqlpostgres", &postgres{})
2359}</span>
2360
2361func (postgres) GetName() string <span class="cov0" title="0">{
2362 return "postgres"
2363}</span>
2364
2365func (postgres) BindVar(i int) string <span class="cov0" title="0">{
2366 return fmt.Sprintf("$%v", i)
2367}</span>
2368
2369func (s *postgres) DataTypeOf(field *StructField) string <span class="cov0" title="0">{
2370 var dataValue, sqlType, size, additionalType = ParseFieldStructForDialect(field, s)
2371
2372 if sqlType == "" </span><span class="cov0" title="0">{
2373 switch dataValue.Kind() </span>{
2374 case reflect.Bool:<span class="cov0" title="0">
2375 sqlType = "boolean"</span>
2376 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uintptr:<span class="cov0" title="0">
2377 if s.fieldCanAutoIncrement(field) </span><span class="cov0" title="0">{
2378 field.TagSettingsSet("AUTO_INCREMENT", "AUTO_INCREMENT")
2379 sqlType = "serial"
2380 }</span> else<span class="cov0" title="0"> {
2381 sqlType = "integer"
2382 }</span>
2383 case reflect.Int64, reflect.Uint32, reflect.Uint64:<span class="cov0" title="0">
2384 if s.fieldCanAutoIncrement(field) </span><span class="cov0" title="0">{
2385 field.TagSettingsSet("AUTO_INCREMENT", "AUTO_INCREMENT")
2386 sqlType = "bigserial"
2387 }</span> else<span class="cov0" title="0"> {
2388 sqlType = "bigint"
2389 }</span>
2390 case reflect.Float32, reflect.Float64:<span class="cov0" title="0">
2391 sqlType = "numeric"</span>
2392 case reflect.String:<span class="cov0" title="0">
2393 if _, ok := field.TagSettingsGet("SIZE"); !</span><span class="cov0" title="0">ok {
2394 size = 0 // if SIZE haven't been set, use `text` as the default type, as there are no performance different
2395 }</span>
2396
2397 <span class="cov0" title="0">if size > 0 && size < 65532 </span><span class="cov0" title="0">{
2398 sqlType = fmt.Sprintf("varchar(%d)", size)
2399 }</span> else<span class="cov0" title="0"> {
2400 sqlType = "text"
2401 }</span>
2402 case reflect.Struct:<span class="cov0" title="0">
2403 if _, ok := dataValue.Interface().(time.Time); ok </span><span class="cov0" title="0">{
2404 sqlType = "timestamp with time zone"
2405 }</span>
2406 case reflect.Map:<span class="cov0" title="0">
2407 if dataValue.Type().Name() == "Hstore" </span><span class="cov0" title="0">{
2408 sqlType = "hstore"
2409 }</span>
2410 default:<span class="cov0" title="0">
2411 if IsByteArrayOrSlice(dataValue) </span><span class="cov0" title="0">{
2412 sqlType = "bytea"
2413
2414 if isUUID(dataValue) </span><span class="cov0" title="0">{
2415 sqlType = "uuid"
2416 }</span>
2417
2418 <span class="cov0" title="0">if isJSON(dataValue) </span><span class="cov0" title="0">{
2419 sqlType = "jsonb"
2420 }</span>
2421 }
2422 }
2423 }
2424
2425 <span class="cov0" title="0">if sqlType == "" </span><span class="cov0" title="0">{
2426 panic(fmt.Sprintf("invalid sql type %s (%s) for postgres", dataValue.Type().Name(), dataValue.Kind().String()))</span>
2427 }
2428
2429 <span class="cov0" title="0">if strings.TrimSpace(additionalType) == "" </span><span class="cov0" title="0">{
2430 return sqlType
2431 }</span>
2432 <span class="cov0" title="0">return fmt.Sprintf("%v %v", sqlType, additionalType)</span>
2433}
2434
2435func (s postgres) HasIndex(tableName string, indexName string) bool <span class="cov0" title="0">{
2436 var count int
2437 s.db.QueryRow("SELECT count(*) FROM pg_indexes WHERE tablename = $1 AND indexname = $2 AND schemaname = CURRENT_SCHEMA()", tableName, indexName).Scan(&count)
2438 return count > 0
2439}</span>
2440
2441func (s postgres) HasForeignKey(tableName string, foreignKeyName string) bool <span class="cov0" title="0">{
2442 var count int
2443 s.db.QueryRow("SELECT count(con.conname) FROM pg_constraint con WHERE $1::regclass::oid = con.conrelid AND con.conname = $2 AND con.contype='f'", tableName, foreignKeyName).Scan(&count)
2444 return count > 0
2445}</span>
2446
2447func (s postgres) HasTable(tableName string) bool <span class="cov0" title="0">{
2448 var count int
2449 s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.tables WHERE table_name = $1 AND table_type = 'BASE TABLE' AND table_schema = CURRENT_SCHEMA()", tableName).Scan(&count)
2450 return count > 0
2451}</span>
2452
2453func (s postgres) HasColumn(tableName string, columnName string) bool <span class="cov0" title="0">{
2454 var count int
2455 s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.columns WHERE table_name = $1 AND column_name = $2 AND table_schema = CURRENT_SCHEMA()", tableName, columnName).Scan(&count)
2456 return count > 0
2457}</span>
2458
2459func (s postgres) CurrentDatabase() (name string) <span class="cov0" title="0">{
2460 s.db.QueryRow("SELECT CURRENT_DATABASE()").Scan(&name)
2461 return
2462}</span>
2463
2464func (s postgres) LastInsertIDReturningSuffix(tableName, key string) string <span class="cov0" title="0">{
2465 return fmt.Sprintf("RETURNING %v.%v", tableName, key)
2466}</span>
2467
2468func (postgres) SupportLastInsertID() bool <span class="cov0" title="0">{
2469 return false
2470}</span>
2471
2472func isUUID(value reflect.Value) bool <span class="cov0" title="0">{
2473 if value.Kind() != reflect.Array || value.Type().Len() != 16 </span><span class="cov0" title="0">{
2474 return false
2475 }</span>
2476 <span class="cov0" title="0">typename := value.Type().Name()
2477 lower := strings.ToLower(typename)
2478 return "uuid" == lower || "guid" == lower</span>
2479}
2480
2481func isJSON(value reflect.Value) bool <span class="cov0" title="0">{
2482 _, ok := value.Interface().(json.RawMessage)
2483 return ok
2484}</span>
2485</pre>
2486
2487 <pre class="file" id="file13" style="display: none">package gorm
2488
2489import (
2490 "fmt"
2491 "reflect"
2492 "strings"
2493 "time"
2494)
2495
2496type sqlite3 struct {
2497 commonDialect
2498}
2499
2500func init() <span class="cov8" title="1">{
2501 RegisterDialect("sqlite3", &sqlite3{})
2502}</span>
2503
2504func (sqlite3) GetName() string <span class="cov8" title="1">{
2505 return "sqlite3"
2506}</span>
2507
2508// Get Data Type for Sqlite Dialect
2509func (s *sqlite3) DataTypeOf(field *StructField) string <span class="cov8" title="1">{
2510 var dataValue, sqlType, size, additionalType = ParseFieldStructForDialect(field, s)
2511
2512 if sqlType == "" </span><span class="cov8" title="1">{
2513 switch dataValue.Kind() </span>{
2514 case reflect.Bool:<span class="cov8" title="1">
2515 sqlType = "bool"</span>
2516 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr:<span class="cov8" title="1">
2517 if s.fieldCanAutoIncrement(field) </span><span class="cov8" title="1">{
2518 field.TagSettingsSet("AUTO_INCREMENT", "AUTO_INCREMENT")
2519 sqlType = "integer primary key autoincrement"
2520 }</span> else<span class="cov8" title="1"> {
2521 sqlType = "integer"
2522 }</span>
2523 case reflect.Int64, reflect.Uint64:<span class="cov8" title="1">
2524 if s.fieldCanAutoIncrement(field) </span><span class="cov8" title="1">{
2525 field.TagSettingsSet("AUTO_INCREMENT", "AUTO_INCREMENT")
2526 sqlType = "integer primary key autoincrement"
2527 }</span> else<span class="cov8" title="1"> {
2528 sqlType = "bigint"
2529 }</span>
2530 case reflect.Float32, reflect.Float64:<span class="cov8" title="1">
2531 sqlType = "real"</span>
2532 case reflect.String:<span class="cov8" title="1">
2533 if size > 0 && size < 65532 </span><span class="cov8" title="1">{
2534 sqlType = fmt.Sprintf("varchar(%d)", size)
2535 }</span> else<span class="cov0" title="0"> {
2536 sqlType = "text"
2537 }</span>
2538 case reflect.Struct:<span class="cov8" title="1">
2539 if _, ok := dataValue.Interface().(time.Time); ok </span><span class="cov8" title="1">{
2540 sqlType = "datetime"
2541 }</span>
2542 default:<span class="cov8" title="1">
2543 if IsByteArrayOrSlice(dataValue) </span><span class="cov8" title="1">{
2544 sqlType = "blob"
2545 }</span>
2546 }
2547 }
2548
2549 <span class="cov8" title="1">if sqlType == "" </span><span class="cov0" title="0">{
2550 panic(fmt.Sprintf("invalid sql type %s (%s) for sqlite3", dataValue.Type().Name(), dataValue.Kind().String()))</span>
2551 }
2552
2553 <span class="cov8" title="1">if strings.TrimSpace(additionalType) == "" </span><span class="cov8" title="1">{
2554 return sqlType
2555 }</span>
2556 <span class="cov8" title="1">return fmt.Sprintf("%v %v", sqlType, additionalType)</span>
2557}
2558
2559func (s sqlite3) HasIndex(tableName string, indexName string) bool <span class="cov8" title="1">{
2560 var count int
2561 s.db.QueryRow(fmt.Sprintf("SELECT count(*) FROM sqlite_master WHERE tbl_name = ? AND sql LIKE '%%INDEX %v ON%%'", indexName), tableName).Scan(&count)
2562 return count > 0
2563}</span>
2564
2565func (s sqlite3) HasTable(tableName string) bool <span class="cov8" title="1">{
2566 var count int
2567 s.db.QueryRow("SELECT count(*) FROM sqlite_master WHERE type='table' AND name=?", tableName).Scan(&count)
2568 return count > 0
2569}</span>
2570
2571func (s sqlite3) HasColumn(tableName string, columnName string) bool <span class="cov8" title="1">{
2572 var count int
2573 s.db.QueryRow(fmt.Sprintf("SELECT count(*) FROM sqlite_master WHERE tbl_name = ? AND (sql LIKE '%%\"%v\" %%' OR sql LIKE '%%%v %%');\n", columnName, columnName), tableName).Scan(&count)
2574 return count > 0
2575}</span>
2576
2577func (s sqlite3) CurrentDatabase() (name string) <span class="cov0" title="0">{
2578 var (
2579 ifaces = make([]interface{}, 3)
2580 pointers = make([]*string, 3)
2581 i int
2582 )
2583 for i = 0; i < 3; i++ </span><span class="cov0" title="0">{
2584 ifaces[i] = &pointers[i]
2585 }</span>
2586 <span class="cov0" title="0">if err := s.db.QueryRow("PRAGMA database_list").Scan(ifaces...); err != nil </span><span class="cov0" title="0">{
2587 return
2588 }</span>
2589 <span class="cov0" title="0">if pointers[1] != nil </span><span class="cov0" title="0">{
2590 name = *pointers[1]
2591 }</span>
2592 <span class="cov0" title="0">return</span>
2593}
2594</pre>
2595
2596 <pre class="file" id="file14" style="display: none">package mssql
2597
2598import (
2599 "database/sql/driver"
2600 "encoding/json"
2601 "errors"
2602 "fmt"
2603 "reflect"
2604 "strconv"
2605 "strings"
2606 "time"
2607
2608 // Importing mssql driver package only in dialect file, otherwide not needed
2609 _ "github.com/denisenkom/go-mssqldb"
2610 "github.com/jinzhu/gorm"
2611</span>)
2612</span>
2613</span>func setIdentityInsert(scope *gorm.Scope) {
2614 if scope.Dialect().GetName() == "mssql" {
2615 fo</span>r _, field := range scope.PrimaryFields() {
2616 if _, ok := field.TagSettingsGet("AUTO_INCREMENT"); ok && !field.IsBlank {
2617 scope.NewDB().Exec(fmt.Sprintf("SET IDENTITY_INSERT %v ON", scope.TableName()))
2618 scope.InstanceSet("mssql:identity_insert_on", true)
2619 }
2620 }
2621 }
2622</span>}
2623</span>
2624fun</span>c turnOffIdentityInsert(scope *gorm.Scope) {
2625 if scope.Dialect().GetName() == "mssql" {
2626 if _, ok := scope.InstanceGet("mssql:identity_insert_on"); ok {
2627 scope.NewDB().Exec(fmt.Sprintf("SET IDENTITY_INSERT %v OFF", scope.TableName()))
2628 }
2629 }
2630}
2631
2632f</span>unc init() {
2633 gorm.DefaultCallback.Create().After("gorm:begin_transaction").Register("mssql:set_identity_insert", setIdentityInsert)
2634 gorm.DefaultCallback.Create().Before("gorm:commit_or_rollback_transaction").Register("mssql:turn_off_identity_insert", turnOffIdentityInsert)
2635 gorm.RegisterDialect("mssql", &mssql{})
2636}
2637
2638type mssql struct {
2639 db gorm.SQLCommon
2640 gorm.DefaultForeignKeyNamer
2641}</span>
2642
2643func (mssql) GetName() string {
2644 return "mssql"
2645}</span>
2646
2647func (s *mssql) SetDB(db gorm.SQLCo<span class="cov0" title="0">mmon) {
2648 s.db = db
2649}</span>
2650
2651func (mssql) BindVar(i int) string {
2652 return "$$$" // ?
2653}</span>
2654
2655func (mssql) Quote(key string) string {
2656 return fmt.Sprintf(`[%s]`, key)
2657}
2658
2659</span>func (s *mssql) DataTypeOf</span>(field *gorm.StructField) string {
2660 var dataValue, sqlT<span class="cov0" title="0">ype, size, additionalType = gorm.ParseFieldStructForDialect(field, s)
2661
2662</span> if sqlType == "" {
2663 switch dataValue.Kind() {
2664</span> case reflect.Bool:
2665 sqlType = "bit"
2666 ca</span>se re<span class="cov0" title="0">flect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr:
2667 if s.fieldCanAutoIncrement(field) {
2668 </span>field.TagSettingsSet("AUTO_INCREMENT", "AUTO_INCREMENT")
2669 sqlType = "int IDENTITY(1,1)"
2670 } else {
2671</span> sqlType = "int"
2672 }
2673 ca</span>se re<span class="cov0" title="0">flect.Int64, reflect.Uint64:
2674 if s.fieldCanAutoIncrement(field) {
2675 </span>field.TagSettingsSet("AUTO_INCREMENT", "AUTO_INCREMENT")
2676 sqlType = "bigint IDENTITY(1,1)"
2677 } else {
2678</span> sqlType = "bigint"<span class="cov0" title="0">
2679 }
2680</span> case reflect.Float32, reflect.Float64:
2681 s</span>qlTyp<span class="cov0" title="0">e = "float"
2682 case reflect.String:
2683 i</span>f size > 0 && size < 8000 {
2684 sqlType = fmt.Spri<span class="cov0" title="0">ntf("nvarchar(%d)", size)
2685 } else {
2686</span> sqlType = "nvarchar(max)"
2687 }</span>
2688 case ref<span class="cov0" title="0">lect.Struct:
2689 if _, ok := dataValue.Interface().(tim</span><span class="cov0" title="0">e.Time); ok {
2690 sqlType = "datetimeoffset"
2691</span> }
2692 def</span>ault:<span class="cov0" title="0">
2693 if gorm.IsByteArrayOrSlice(dataValue) {
2694 i</span>f size > 0 && size < 8000 {
2695 sqlType = fmt.Sprintf("varbinary(%d)", size)
2696 } else {
2697 sqlType = "varbinary(max)"
2698 }
2699 <span class="cov0" title="0"> }
2700</span> }
2701</span> }
2702
2703 <span class="cov0" title="0">if sqlType == "" {
2704</span> panic(fmt.Sprintf("invalid sql type %s (%s) for mssql", dataValue.Type().Name(), dataValue.Kind().String()))
2705 }</span>
2706
2707</span> if strings.TrimSpace(additionalType) == "" {
2708 return sqlType
2709 }
2710 return fmt.Sprintf("%v %v", sqlType, additionalType)
2711</span>}
2712
2713</span>f<span class="cov0" title="0">unc (s mssql) fieldCanAut</span>oIncrement(field *gorm.StructField) bool {
2714 if value, ok := field.TagSettingsGet("AUTO_INCREMENT"); ok {
2715 return value != "FALSE"
2716 }
2717 return field.IsPrimaryKey
2718}
2719
2720f</span>unc (s mssql) HasIndex(tableName string, indexName string) bool {
2721 var count int
2722 s.db.QueryRow("SELECT count(*) FROM sys.indexes WHERE name=? AND obj<span class="cov0" title="0">ect_id=OBJECT_ID(?)", indexName, tableName).Scan(&count)
2723 return count > 0
2724}
2725
2726</span>func (s mssql) RemoveIndex(tableName string, indexName string) error {
2727 _, err := s.db.Exec(fmt.Sprintf("DROP INDEX %v ON %v", indexName, s.Quote(<span class="cov0" title="0">tableName)))
2728 return err
2729}</span>
2730
2731func (s mssql) HasForeignKey(tableName string, <span class="cov0" title="0">foreignKeyName string) bool {
2732 var count int
2733 currentDatabase, tableName := currentDatabaseAndTable(&s, tableName)
2734 s.db.QueryRow(`SELECT count(*)
2735 FROM sys.foreign_keys as F inner join sys.tables as T on F.parent_object_id=T.object_id
2736 </span> inner join information_schema.tables as I on I.TABLE_NAME = T.name
2737 WHERE F.name = ?
2738 AND T.Name = ? AND I.TABLE_CATALOG = ?;`, foreignKeyName, tableNa<span class="cov0" title="0">me, currentDatabase).Scan(&count)
2739 return count > 0
2740}
2741
2742func (s mssql) HasTable(tableName string) bool {
2743 </span>var count int
2744 currentDatabase, tableName := currentDatabaseAndTable(&s, tableName)
2745 s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.tables WHERE table_name = ?<span class="cov0" title="0"> AND table_catalog = ?", tableName, currentDatabase).Scan(&count)
2746 return count > 0
2747}
2748
2749</span>func (s mssql) HasColumn(tableName string, columnName string) bool {
2750 var count int
2751 currentDatabase, tableName := currentDatabaseAndTable(&s, tableName)
2752 s.db.QueryRow("SELECT count(*) FROM information_schema.columns WHERE table_catalog = ? AND table_name = ? AND column_name = ?", currentDatabase, tableName, columnName).Scan(&count)
2753 </span>return count > 0
2754}
2755
2756func (s mssql) Mod</span><span class="cov0" title="0">ifyColumn(tableName string, columnName string, typ string) error {
2757 _, err := s.db.Exec(fmt.Sprintf("ALTER TABLE %v ALTER COLUMN %v %v", tableName, columnName, typ))
2758</span> return err
2759}
2760</span>
2761f<span class="cov0" title="0">unc (s mssql) Cu</span><span class="cov0" title="0">rrentDatabase() (name string) {
2762 s.db.QueryRow("SELECT DB_NAME() AS [Current Database]").Scan(&name)
2763</span> return
2764</span>}
2765
2766func</span> (mssql) LimitAndOffsetSQL(limit, offset interface{}) (sql string) {
2767 if<span class="cov0" title="0"> offset != nil {
2768</span> if parsedOffset, err := strconv.ParseInt(fmt.Sprint(offset), 0, 0); err == nil && parsedOffset >= 0 {
2769 sql += fmt.Sprintf(" OFFSET %d ROWS", parsedOffset)
2770 <span class="cov0" title="0"> }
2771</span> }
2772 if limit != nil {
2773 if parsedLimit, err := strconv.ParseInt(f<span class="cov0" title="0">mt.Sprint(limit), 0, 0); err == nil && parsedLimit >= 0 {
2774 if sql == "" {
2775 </span> // add default zero offset
2776 sql += " OFFSET 0 ROWS"
2777 }
2778 sql += fmt.Sprintf(" FETCH NEXT %d ROWS ONLY", parsedLimit)
2779 </span> }
2780 }
2781 return
2782}
2783
2784</span>func (mssql) SelectFromDummyTable() string {
2785 return ""
2786}
2787</span>
2788func (mssql) LastInsertIDReturningSuffix(tableName, columnName string) string {
2789 r</span>eturn ""
2790}<span class="cov0" title="0">
2791</span>
2792func (mssql) DefaultValueStr() string {
2793 return "DEFAULT VALUES"
2794}
2795
2796func currentDatabaseAndTable(dialect gorm.Dialect, tableName string) (string, string) {
2797 if strings.Contains(tableName, ".") {
2798 splitStrings := strings.SplitN(tableName, ".", 2)
2799 return splitStrings[0], splitStrings[1]
2800 }
2801 return dialect.CurrentDatabase(), tableName
2802}
2803
2804// JSON type to support easy handling of JSON data in character table fields
2805// using golang json.RawMessage for deferred decoding/encoding
2806type JSON struct {
2807 json.RawMessage
2808}
2809
2810// Value get value of JSON
2811func (j JSON) Value() (driver.Value, error) {
2812 if len(j.RawMessage) == 0 {
2813 return nil, nil
2814 }
2815 return j.MarshalJSON()
2816}
2817
2818// Scan scan value into JSON
2819func (j *JSON) Scan(value interface{}) error {
2820 str, ok := value.(string)
2821 if !ok {
2822 return errors.New(fmt.Sprint("Failed to unmarshal JSONB value (strcast):", value))
2823 }
2824 bytes := []byte(str)
2825 return json.Unmarshal(bytes, j)
2826}
2827</pre>
2828
2829 <pre class="file" id="file15" style="display: none">package postgres
2830
2831import (
2832 "database/sql"
2833 "database/sql/driver"
2834
2835 "encoding/json"
2836 "errors"
2837 "fmt"
2838 _ "github.com/lib/pq"
2839 "github.com/lib/pq/hstore"
2840)
2841
2842type Hstore map[string]*string
2843
2844// Value get value of Hstore
2845func (h Hstore) Value() (driver.Value, error) <span class="cov0" title="0">{
2846 hstore := hstore.Hstore{Map: map[string]sql.NullString{}}
2847 if len(h) == 0 </span><span class="cov0" title="0">{
2848 return nil, nil
2849 }</span>
2850
2851 <span class="cov0" title="0">for key, value := range h </span><span class="cov0" title="0">{
2852 var s sql.NullString
2853 if value != nil </span><span class="cov0" title="0">{
2854 s.String = *value
2855 s.Valid = true
2856 }</span>
2857 <span class="cov0" title="0">hstore.Map[key] = s</span>
2858 }
2859 <span class="cov0" title="0">return hstore.Value()</span>
2860}
2861
2862// Scan scan value into Hstore
2863func (h *Hstore) Scan(value interface{}) error <span class="cov0" title="0">{
2864 hstore := hstore.Hstore{}
2865
2866 if err := hstore.Scan(value); err != nil </span><span class="cov0" title="0">{
2867 return err
2868 }</span>
2869
2870 <span class="cov0" title="0">if len(hstore.Map) == 0 </span><span class="cov0" title="0">{
2871 return nil
2872 }</span>
2873
2874 <span class="cov0" title="0">*h = Hstore{}
2875 for k := range hstore.Map </span><span class="cov0" title="0">{
2876 if hstore.Map[k].Valid </span><span class="cov0" title="0">{
2877 s := hstore.Map[k].String
2878 (*h)[k] = &s
2879 }</span> else<span class="cov0" title="0"> {
2880 (*h)[k] = nil
2881 }</span>
2882 }
2883
2884 <span class="cov0" title="0">return nil</span>
2885}
2886
2887// Jsonb Postgresql's JSONB data type
2888type Jsonb struct {
2889 json.RawMessage
2890}
2891
2892// Value get value of Jsonb
2893func (j Jsonb) Value() (driver.Value, error) <span class="cov0" title="0">{
2894 if len(j.RawMessage) == 0 </span><span class="cov0" title="0">{
2895 return nil, nil
2896 }</span>
2897 <span class="cov0" title="0">return j.MarshalJSON()</span>
2898}
2899
2900// Scan scan value into Jsonb
2901func (j *Jsonb) Scan(value interface{}) error <span class="cov0" title="0">{
2902 bytes, ok := value.([]byte)
2903 if !ok </span><span class="cov0" title="0">{
2904 return errors.New(fmt.Sprint("Failed to unmarshal JSONB value:", value))
2905 }</span>
2906
2907 <span class="cov0" title="0">return json.Unmarshal(bytes, j)</span>
2908}
2909</pre>
2910
2911 <pre class="file" id="file16" style="display: none">package gorm
2912
2913import (
2914 "errors"
2915 "strings"
2916)
2917
2918var (
2919 // ErrRecordNotFound returns a "record not found error". Occurs only when attempting to query the database with a struct; querying with a slice won't return this error
2920 ErrRecordNotFound = errors.New("record not found")
2921 // ErrInvalidSQL occurs when you attempt a query with invalid SQL
2922 ErrInvalidSQL = errors.New("invalid SQL")
2923 // ErrInvalidTransaction occurs when you are trying to `Commit` or `Rollback`
2924 ErrInvalidTransaction = errors.New("no valid transaction")
2925 // ErrCantStartTransaction can't start transaction when you are trying to start one with `Begin`
2926 ErrCantStartTransaction = errors.New("can't start transaction")
2927 // ErrUnaddressable unaddressable value
2928 ErrUnaddressable = errors.New("using unaddressable value")
2929)
2930
2931// Errors contains all happened errors
2932type Errors []error
2933
2934// IsRecordNotFoundError returns true if error contains a RecordNotFound error
2935func IsRecordNotFoundError(err error) bool <span class="cov0" title="0">{
2936 if errs, ok := err.(Errors); ok </span><span class="cov0" title="0">{
2937 for _, err := range errs </span><span class="cov0" title="0">{
2938 if err == ErrRecordNotFound </span><span class="cov0" title="0">{
2939 return true
2940 }</span>
2941 }
2942 }
2943 <span class="cov0" title="0">return err == ErrRecordNotFound</span>
2944}
2945
2946// GetErrors gets all errors that have occurred and returns a slice of errors (Error type)
2947func (errs Errors) GetErrors() []error <span class="cov0" title="0">{
2948 return errs
2949}</span>
2950
2951// Add adds an error to a given slice of errors
2952func (errs Errors) Add(newErrors ...error) Errors <span class="cov8" title="1">{
2953 for _, err := range newErrors </span><span class="cov8" title="1">{
2954 if err == nil </span><span class="cov0" title="0">{
2955 continue</span>
2956 }
2957
2958 <span class="cov8" title="1">if errors, ok := err.(Errors); ok </span><span class="cov8" title="1">{
2959 errs = errs.Add(errors...)
2960 }</span> else<span class="cov8" title="1"> {
2961 ok = true
2962 for _, e := range errs </span><span class="cov8" title="1">{
2963 if err == e </span><span class="cov8" title="1">{
2964 ok = false
2965 }</span>
2966 }
2967 <span class="cov8" title="1">if ok </span><span class="cov8" title="1">{
2968 errs = append(errs, err)
2969 }</span>
2970 }
2971 }
2972 <span class="cov8" title="1">return errs</span>
2973}
2974
2975// Error takes a slice of all errors that have occurred and returns it as a formatted string
2976func (errs Errors) Error() string <span class="cov8" title="1">{
2977 var errors = []string{}
2978 for _, e := range errs </span><span class="cov8" title="1">{
2979 errors = append(errors, e.Error())
2980 }</span>
2981 <span class="cov8" title="1">return strings.Join(errors, "; ")</span>
2982}
2983</pre>
2984
2985 <pre class="file" id="file17" style="display: none">package gorm
2986
2987import (
2988 "database/sql"
2989 "database/sql/driver"
2990 "errors"
2991 "fmt"
2992 "reflect"
2993)
2994
2995// Field model field definition
2996type Field struct {
2997 *StructField
2998 IsBlank bool
2999 Field reflect.Value
3000}
3001
3002// Set set a value to the field
3003func (field *Field) Set(val</span><span class="cov0" title="0">ue interface{}) (err error) {
3004 if !field.Field.IsValid() {
3005 </span>return errors.New("field value not valid")
3006 }
3007
3008</span> if !field.Field.CanAddr() {
3009 </span>return ErrUnaddressable
3010 }
3011
3012 reflect</span><span class="cov8" title="1">Value, ok := value.(reflect.Value)
3013 if !ok {
3014 </span>reflectValue = reflect.ValueOf(value)
3015 }
3016
3017 fieldValue := field.Field
3018</span> if reflectValue.IsValid() {
3019</span> if reflectValue.Type().ConvertibleTo(fieldValue.Type()) {
3020 </span>field<span class="cov8" title="1">Value.Set(reflectValue.Convert(fieldValue.Type()))
3021 } else {
3022</span> if fieldValue.Kind() ==</span><span class="cov8" title="1"> reflect.Ptr {
3023 if fieldValue.IsNil() {
3024 </span>fieldValue.Set(reflect.New(field.Struct.Type.Elem()))
3025 <span class="cov8" title="1">}
3026</span> fieldValue = fieldValue.Elem()
3027 }
3028
3029</span> if reflectValue.Type().ConvertibleTo(fieldValue.Type()) {
3030 </span>field<span class="cov8" title="1">Value.Set(reflectValue.Convert(fieldValue.Type()))
3031</span> } else if scanner, ok := fieldValue.Addr().Interface().(sql.Scanner); ok {
3032 </span>v := <span class="cov0" title="0">reflectValue.Interface()
3033 if valuer, ok := v.(driver.Valuer); ok {
3034 </span> if v, err = valuer.Value(); err == nil {
3035 err = scanner.Scan(v)
3036 }
3037 } else {
3038 </span> err = scanner.Scan(v)
3039 }
3040 <span class="cov8" title="1"> } else {
3041 err = f</span>mt.Errorf("could not convert argument of field %s from %s to %s", field.Name, reflectValue.Type(), fieldValue.Type())
3042 }
3043 }
3044 } else {
3045 field.Field.Set(reflect.Zero(field.Field.Type()))
3046 }
3047
3048 field.IsBlank = isBlank(field.Field)
3049 return err
3050}
3051</pre>
3052
3053 <pre class="file" id="file18" style="display: none">package gorm
3054
3055import (
3056 "errors"
3057 "fmt"
3058 "reflect"
3059 "strings"
3060)
3061
3062// JoinTableHandlerInterface is an interface for how to handle many2many relations
3063type JoinTableHandlerInterface interface {
3064 // initialize join table handler
3065 Setup(relationship *Relationship, tableName string, source reflect.Type, destination reflect.Type)
3066 // Table return join table's table name
3067 Table(db *DB) string
3068 // Add create relationship in join table for source and destination
3069 Add(handler JoinTableHandlerInterface, db *DB, source interface{}, destination interface{}) error
3070 // Delete delete relationship in join table for sources
3071 Delete(handler JoinTableHandlerInterface, db *DB, sources ...interface{}) error
3072 // JoinWith query with `Join` conditions
3073 JoinWith(handler JoinTableHandlerInterface, db *DB, source interface{}) *DB
3074 // SourceForeignKeys return source foreign keys
3075 SourceForeignKeys() []JoinTableForeignKey
3076 // DestinationForeignKeys return destination foreign keys
3077 DestinationForeignKeys() []JoinTableForeignKey
3078}
3079
3080// JoinTableForeignKey join table foreign key struct
3081type JoinTableForeignKey struct {
3082 DBName string
3083 AssociationDBName string
3084}
3085
3086// JoinTableSource is a struct that contains model type and foreign keys
3087type JoinTableSource struct {
3088 ModelType reflect.Type
3089 ForeignKeys []JoinTableForeignKey
3090}
3091
3092// JoinTableHandler default join table handler
3093type JoinTableHandler struct {
3094 TableName string `sql:"-"`
3095 Source JoinTableSource `sql:"-"`
3096 Destination JoinTableSource `sql:"-"`
3097}
3098
3099// SourceForeignKeys return source foreign keys
3100func (s *JoinTableHandler) SourceForeignKeys() []JoinTableForeignKey <span class="cov8" title="1">{
3101 return s.Source.ForeignKeys
3102}</span>
3103
3104// DestinationForeignKeys return destination foreign keys
3105func (s *JoinTableHandler) DestinationForeignKeys() []JoinTableForeignKey <span class="cov0" title="0">{
3106 return s.Destination.ForeignKeys
3107}</span>
3108
3109// Setup initialize a default join table handler
3110func (s *JoinTableHandler) Setup(relationship *Relationship, tableName string, source reflect.Type, destination reflect.Type) <span class="cov8" title="1">{
3111 s.TableName = tableName
3112
3113 s.Source = JoinTableSource{ModelType: source}
3114 s.Source.ForeignKeys = []JoinTableForeignKey{}
3115 for idx, dbName := range relationship.ForeignFieldNames </span><span class="cov8" title="1">{
3116 s.Source.ForeignKeys = append(s.Source.ForeignKeys, JoinTableForeignKey{
3117 DBName: relationship.ForeignDBNames[idx],
3118 AssociationDBName: dbName,
3119 })
3120 }</span>
3121
3122 <span class="cov8" title="1">s.Destination = JoinTableSource{ModelType: destination}
3123 s.Destination.ForeignKeys = []JoinTableForeignKey{}
3124 for idx, dbName := range relationship.AssociationForeignFieldNames </span><span class="cov8" title="1">{
3125 s.Destination.ForeignKeys = append(s.Destination.ForeignKeys, JoinTableForeignKey{
3126 DBName: relationship.AssociationForeignDBNames[idx],
3127 AssociationDBName: dbName,
3128 })
3129 }</span>
3130}
3131
3132// Table return join table's table name
3133func (s JoinTableHandler) Table(db *DB) string <span class="cov8" title="1">{
3134 return DefaultTableNameHandler(db, s.TableName)
3135}</span>
3136
3137func (s JoinTableHandler) updateConditionMap(conditionMap map[string]interface{}, db *DB, joinTableSources []JoinTableSource, sources ...interface{}) <span class="cov8" title="1">{
3138 for _, source := range sources </span><span class="cov8" title="1">{
3139 scope := db.NewScope(source)
3140 modelType := scope.GetModelStruct().ModelType
3141
3142 for _, joinTableSource := range joinTableSources </span><span class="cov8" title="1">{
3143 if joinTableSource.ModelType == modelType </span><span class="cov8" title="1">{
3144 for _, foreignKey := range joinTableSource.ForeignKeys </span><span class="cov8" title="1">{
3145 if field, ok := scope.FieldByName(foreignKey.AssociationDBName); ok </span><span class="cov8" title="1">{
3146 conditionMap[foreignKey.DBName] = field.Field.Interface()
3147 }</span>
3148 }
3149 <span class="cov8" title="1">break</span>
3150 }
3151 }
3152 }
3153}
3154
3155// Add create relationship in join table for source and destination
3156func (s JoinTableHandler) Add(handler JoinTableHandlerInterface, db *DB, source interface{}, destination interface{}) error <span class="cov8" title="1">{
3157 var (
3158 scope = db.NewScope("")
3159 conditionMap = map[string]interface{}{}
3160 )
3161
3162 // Update condition map for source
3163 s.updateConditionMap(conditionMap, db, []JoinTableSource{s.Source}, source)
3164
3165 // Update condition map for destination
3166 s.updateConditionMap(conditionMap, db, []JoinTableSource{s.Destination}, destination)
3167
3168 var assignColumns, binVars, conditions []string
3169 var values []interface{}
3170 for key, value := range conditionMap </span><span class="cov8" title="1">{
3171 assignColumns = append(assignColumns, scope.Quote(key))
3172 binVars = append(binVars, `?`)
3173 conditions = append(conditions, fmt.Sprintf("%v = ?", scope.Quote(key)))
3174 values = append(values, value)
3175 }</span>
3176
3177 <span class="cov8" title="1">for _, value := range values </span><span class="cov8" title="1">{
3178 values = append(values, value)
3179 }</span>
3180
3181 <span class="cov8" title="1">quotedTable := scope.Quote(handler.Table(db))
3182 sql := fmt.Sprintf(
3183 "INSERT INTO %v (%v) SELECT %v %v WHERE NOT EXISTS (SELECT * FROM %v WHERE %v)",
3184 quotedTable,
3185 strings.Join(assignColumns, ","),
3186 strings.Join(binVars, ","),
3187 scope.Dialect().SelectFromDummyTable(),
3188 quotedTable,
3189 strings.Join(conditions, " AND "),
3190 )
3191
3192 return db.Exec(sql, values...).Error</span>
3193}
3194
3195// Delete delete relationship in join table for sources
3196func (s JoinTableHandler) Delete(handler JoinTableHandlerInterface, db *DB, sources ...interface{}) error <span class="cov8" title="1">{
3197 var (
3198 scope = db.NewScope(nil)
3199 conditions []string
3200 values []interface{}
3201 conditionMap = map[string]interface{}{}
3202 )
3203
3204 s.updateConditionMap(conditionMap, db, []JoinTableSource{s.Source, s.Destination}, sources...)
3205
3206 for key, value := range conditionMap </span><span class="cov0" title="0">{
3207 conditions = append(conditions, fmt.Sprintf("%v = ?", scope.Quote(key)))
3208 values = append(values, value)
3209 }</span>
3210
3211 <span class="cov8" title="1">return db.Table(handler.Table(db)).Where(strings.Join(conditions, " AND "), values...).Delete("").Error</span>
3212}
3213
3214// JoinWith query with `Join` conditions
3215func (s JoinTableHandler) JoinWith(handler JoinTableHandlerInterface, db *DB, source interface{}) *DB <span class="cov8" title="1">{
3216 var (
3217 scope = db.NewScope(source)
3218 tableName = handler.Table(db)
3219 quotedTableName = scope.Quote(tableName)
3220 joinConditions []string
3221 values []interface{}
3222 )
3223
3224 if s.Source.ModelType == scope.GetModelStruct().ModelType </span><span class="cov8" title="1">{
3225 destinationTableName := db.NewScope(reflect.New(s.Destination.ModelType).Interface()).QuotedTableName()
3226 for _, foreignKey := range s.Destination.ForeignKeys </span><span class="cov8" title="1">{
3227 joinConditions = append(joinConditions, fmt.Sprintf("%v.%v = %v.%v", quotedTableName, scope.Quote(foreignKey.DBName), destinationTableName, scope.Quote(foreignKey.AssociationDBName)))
3228 }</span>
3229
3230 <span class="cov8" title="1">var foreignDBNames []string
3231 var foreignFieldNames []string
3232
3233 for _, foreignKey := range s.Source.ForeignKeys </span><span class="cov8" title="1">{
3234 foreignDBNames = append(foreignDBNames, foreignKey.DBName)
3235 if field, ok := scope.FieldByName(foreignKey.AssociationDBName); ok </span><span class="cov8" title="1">{
3236 foreignFieldNames = append(foreignFieldNames, field.Name)
3237 }</span>
3238 }
3239
3240 <span class="cov8" title="1">foreignFieldValues := scope.getColumnAsArray(foreignFieldNames, scope.Value)
3241
3242 var condString string
3243 if len(foreignFieldValues) > 0 </span><span class="cov8" title="1">{
3244 var quotedForeignDBNames []string
3245 for _, dbName := range foreignDBNames </span><span class="cov8" title="1">{
3246 quotedForeignDBNames = append(quotedForeignDBNames, tableName+"."+dbName)
3247 }</span>
3248
3249 <span class="cov8" title="1">condString = fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, quotedForeignDBNames), toQueryMarks(foreignFieldValues))
3250
3251 keys := scope.getColumnAsArray(foreignFieldNames, scope.Value)
3252 values = append(values, toQueryValues(keys))</span>
3253 } else<span class="cov8" title="1"> {
3254 condString = fmt.Sprintf("1 <> 1")
3255 }</span>
3256
3257 <span class="cov8" title="1">return db.Joins(fmt.Sprintf("INNER JOIN %v ON %v", quotedTableName, strings.Join(joinConditions, " AND "))).
3258 Where(condString, toQueryValues(foreignFieldValues)...)</span>
3259 }
3260
3261 <span class="cov0" title="0">db.Error = errors.New("wrong source type for join table handler")
3262 return db</span>
3263}
3264</pre>
3265
3266 <pre class="file" id="file19" style="display: none">package gorm
3267
3268import (
3269 "database/sql/driver"
3270 "fmt"
3271 "log"
3272 "os"
3273 "reflect"
3274 "regexp"
3275 "strconv"
3276 "time"
3277 "unicode"
3278)
3279
3280var (
3281 defaultLogger = Logger{log.New(os.Stdout, "\r\n", 0)}
3282 sqlRegexp = regexp.MustCompile(`\?`)
3283 numericPlaceHolderRegexp = regexp.MustCompile(`\$\d+`)
3284)
3285
3286func isPrintable(s string) bool <span class="cov0" title="0">{
3287 for _, r := range s </span><span class="cov0" title="0">{
3288 if !unicode.IsPrint(r) </span><span class="cov0" title="0">{
3289 return false
3290 }</span>
3291 }
3292 <span class="cov0" title="0">return true</span>
3293}
3294
3295var LogFormatter = func(values ...interface{}) (messages []interface{}) <span class="cov8" title="1">{
3296 if len(values) > 1 </span><span class="cov8" title="1">{
3297 var (
3298 sql string
3299 formattedValues []string
3300 level = values[0]
3301 currentTime = "\n\033[33m[" + NowFunc().Format("2006-01-02 15:04:05") + "]\033[0m"
3302 source = fmt.Sprintf("\033[35m(%v)\033[0m", values[1])
3303 )
3304
3305 messages = []interface{}{source, currentTime}
3306
3307 if level == "sql" </span><span class="cov0" title="0">{
3308 // duration
3309 messages = append(messages, fmt.Sprintf(" \033[36;1m[%.2fms]\033[0m ", float64(values[2].(time.Duration).Nanoseconds()/1e4)/100.0))
3310 // sql
3311
3312 for _, value := range values[4].([]interface{}) </span><span class="cov0" title="0">{
3313 indirectValue := reflect.Indirect(reflect.ValueOf(value))
3314 if indirectValue.IsValid() </span><span class="cov0" title="0">{
3315 value = indirectValue.Interface()
3316 if t, ok := value.(time.Time); ok </span><span class="cov0" title="0">{
3317 formattedValues = append(formattedValues, fmt.Sprintf("'%v'", t.Format("2006-01-02 15:04:05")))
3318 }</span> else<span class="cov0" title="0"> if b, ok := value.([]byte); ok </span><span class="cov0" title="0">{
3319 if str := string(b); isPrintable(str) </span><span class="cov0" title="0">{
3320 formattedValues = append(formattedValues, fmt.Sprintf("'%v'", str))
3321 }</span> else<span class="cov0" title="0"> {
3322 formattedValues = append(formattedValues, "'<binary>'")
3323 }</span>
3324 } else<span class="cov0" title="0"> if r, ok := value.(driver.Valuer); ok </span><span class="cov0" title="0">{
3325 if value, err := r.Value(); err == nil && value != nil </span><span class="cov0" title="0">{
3326 formattedValues = append(formattedValues, fmt.Sprintf("'%v'", value))
3327 }</span> else<span class="cov0" title="0"> {
3328 formattedValues = append(formattedValues, "NULL")
3329 }</span>
3330 } else<span class="cov0" title="0"> {
3331 switch value.(type) {
3332 </span>case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64, bool:
3333 for<span class="cov0" title="0">mattedValues = append(formattedValues, fmt.Sprintf("%v", value))
3334 default:
3335 </span> formattedValues = append(formattedValues, fmt.Sprintf("'%v'", value))
3336 }
3337 }
3338 } else {
3339 <span class="cov0" title="0"> formattedValues = append(formattedValues, "NULL")
3340</span> }
3341 }
3342</span>
3343 // differentiate between $n placeholders or else treat like ?
3344 if</span> numericPlaceHolderRegexp.MatchString(values[3].(string)) {
3345 sql =<span class="cov0" title="0"> values[3].(string)
3346 for index, value := range formattedValues {
3347 placeholder := fmt.Sprintf(`\$%d([^\d]|$)`, index+1)
3348</span> sql = regexp.MustCompile(placeholder).ReplaceAllString(sql, value+"$1")
3349 }
3350</span> } else {
3351 fo</span>rmattedValuesLength := len(formattedValues)
3352 for index, value := range sqlRegexp.Split(values[3].(string), -1) {
3353 sql += value
3354 if index < formattedValuesLength {
3355 <span class="cov0" title="0"> sql += formattedValues[index]
3356 }
3357</span> }
3358 }
3359
3360 messages = append(messages, sql)
3361 </span>messages = append(messages, fmt.Sprintf(" \n\033[36;31m[%v]\033[0m ", strconv.FormatInt(values[5].(int64), 10)+" rows affected or returned "))
3362 } else {
3363 messages = append(messages, "\033[31;1m")
3364 <span class="cov8" title="1"> mess</span>ages = append(messages, values[2:]...)
3365 messages = append(messages, "\033[0m")
3366 }
3367 }
3368
3369 return
3370}
3371
3372type logger interface {
3373 Print(v ...interface{})
3374}
3375
3376// LogWriter log writer interface
3377type LogWriter interface {
3378 Println(v ...interface{})
3379}
3380
3381// Logger default logger
3382type Logger struct {
3383 LogWriter
3384}</span>
3385
3386// Print format & print log
3387func (logger Logger) Print(values ...interface{}) {
3388 logger.Println(LogFormatter(values...)...)
3389}
3390</pre>
3391
3392 <pre class="file" id="file20" style="display: none">package gorm
3393
3394import (
3395 "database/sql"
3396 "errors"
3397 "fmt"
3398 "reflect"
3399 "strings"
3400 "sync"
3401 "time"
3402)
3403
3404// DB contains information for current db connection
3405type DB struct {
3406 sync.RWMutex
3407 Value interface{}
3408 Error error
3409 RowsAffected int64
3410
3411 // single db
3412 db SQLCommon
3413 blockGlobalUpdate bool
3414 logMode logModeValue
3415 logger logger
3416 search *search
3417 values sync.Map
3418
3419 // global db
3420 parent *DB
3421 callbacks *Callback
3422 dialect Dialect
3423 singularTable bool
3424}
3425
3426type logModeValue int
3427
3428const (
3429 defaultLogMode logModeValue = iota
3430 noLogMode
3431 detailedLogMode
3432)
3433
3434// Open initialize a new db connection, need to import driver first, e.g:
3435//
3436// import _ "gi</span><span class="cov8" title="1">thub.com/go-sql-driver/mysql"
3437// func main() {
3438// db, err := gorm.Open("mysql", "user:password@/dbname?charset=utf8&parseTime=True&loc=Local")
3439//</span> }
3440/<span class="cov8" title="1">/ GORM has wrapped some drivers, for easier to remember driver's import path, so you could import the mysql driver with
3441// import _ "github.com/jinzhu/gorm/dialects/mysql"
3442// // import _ "github.com/jinzhu/gorm/dialects/postgres"
3443// // import _ "github.com/ji</span>nzhu/gorm/dialects/sqlite"
3444// // impo<span class="cov8" title="1">rt _ "github.com/jinzhu/gorm/dialects/mssql"
3445func Open(dialect string, args ...interface{}) (db *DB, err error) {
3446 if len(args) == 0 {</span><span class="cov8" title="1">
3447 err = errors.New("invalid database source")
3448 r</span>eturn<span class="cov0" title="0"> nil, err
3449</span> }
3450 var source string
3451 va</span>r dbSQL SQLCommon
3452 v<span class="cov8" title="1">ar ownDbSQL bool
3453</span>
3454 switch value :</span>= args[0].(type) {
3455 case string:
3456 var driver = dialect
3457 <span class="cov8" title="1"> if len(args) == 1 {
3458 source = value
3459 } else if len(args) >= 2 {
3460 driver = value
3461 source = args[1].(string)
3462 }
3463 dbSQL, err = sql.Open(driver, source)
3464 ownDbSQL = true
3465 case SQLCommon</span><span class="cov0" title="0">:
3466 dbSQL = value
3467 </span>ownDbSQL = false
3468 default:
3469 <span class="cov8" title="1"> return nil, fmt.Errorf("invalid</span><span class="cov8" title="1"> database source: %v is not a valid type", value)
3470 }
3471</span>
3472 db</span> = &DB{
3473 db: dbSQL,
3474 <span class="cov8" title="1"> logge</span>r: defaultLogger,
3475 callbacks: DefaultCallback,
3476 dialect: newDialect(dialect, dbSQL),
3477 }
3478 db.parent = db
3479 if err != nil {
3480 return
3481 }
3482 // Send a ping to make sure the database connection is alive.
3483 </span>if d, ok := dbSQL.(*sql.DB); ok {
3484 if err = d.Ping(); err != nil && ownDbSQL {
3485 d.Close()
3486 }
3487 }
3488 return
3489}
3490
3491// New clone a new db connection withou</span><span class="cov8" title="1">t search conditions
3492func (s *DB) New() *DB {
3493 c</span>lone := s.clone()
3494 <span class="cov0" title="0">clone.search = nil
3495</span> clone.Value = nil
3496 return clone
3497}
3498
3499type closer interface {
3500 Close() error
3501}
3502
3503</span>// Close close current db connection. If database connection is not an io.Closer, returns an error.
3504func (s *DB) Close() error {
3505 if db, ok := s.parent.db.(closer)<span class="cov8" title="1">; ok {
3506 return db.Close()
3507 </span>}
3508 return errors.New("can't close current db")
3509}
3510
3511// DB get `*sql.DB` from current connection
3512/</span>/ If the underlying database connection is not a *sql.DB, returns nil
3513func (s *DB) DB() *sql.DB {
3514 db, _ := s.db.(*sql.DB)
3515 return db
3516}
3517
3518// CommonDB return the underlying `*sql.DB` or `*sql.Tx` instance, mainly intended to allow coexistence with legacy non-GORM code.
3519func (s *DB) CommonDB() SQLCommon {
3520 </span>return s.db
3521}
3522
3523// Dialect get dialect
3524func (s *DB) Dialect() Dialect {
3525 </span>return s.dialect
3526}
3527
3528// Callback return `Callbacks` contain<span class="cov0" title="0">er, you could add/change/delete callbacks with it
3529// db.C</span><span class="cov0" title="0">allback().Create().Register("update_created_at", updateCreated)
3530// Refer https://jinzhu.github.io/gorm/development.html#callbacks
3531fu</span>nc (s<span class="cov0" title="0"> *DB) Callback() *Callback {
3532 s.parent.callbacks = s.parent.callbacks.clone()
3533 r</span>eturn s.parent.callbacks
3534}<span class="cov0" title="0">
3535</span>
3536// SetLogger replace default logger
3537func (s *DB) SetLogger(log logger) {
3538 s.logger = log
3539}
3540
3541// LogMode set log mode, `true` for detailed logs, `false` for no log, default, will only print error logs
3542f</span>unc (s *DB) LogMode(enable bool) *DB {
3543 if enable {
3544 s.logMode = detailedLogMode
3545 } else {
3546 s.logMode = noLogMode
3547 </span>}
3548 return s
3549}
3550
3551// BlockGlobalUpdate if true, generates an error on update/delete without where clause.
3552// This is to prevent eventual error with empty objects updates/deletions
3553f</span>unc (s *DB) BlockGlobalUpdate(enable bool) *DB {
3554 s.blockGlobalUpdate = enable
3555 return s
3556}
3557
3558// HasBlockGlobalUpdate return state of block
3559func (s *DB) HasBlockGlobalUpdate() bool {
3560 </span>return s.blockGlobalUpdate
3561}
3562
3563// SingularTable use singular t<span class="cov8" title="1">able by default
3564func (s *DB) SingularTable(enable bool) {
3565 s.parent.Lock()
3566 defer s.parent.Unlock()
3567 s.parent.singularTable = enable
3568}
3569
3570</span>// NewScope create a scope for current operation
3571func (s *DB) NewScope(value interface{}) *Scope {
3572 dbClone := s.clone()
3573 dbClone.Value = value
3574 </span>scope := &Scope{db: dbClone, Value: value}
3575 if s.search != nil {
3576 scope.Search = s.search.clone()
3577 } else {
3578 scope.Search = &search{}
3579 </span>}
3580 return scope
3581}
3582
3583// QueryExpr returns the query as expr object
3584f</span>unc (s *DB) QueryExpr() *expr {
3585 scope := s.NewScope(s.Value)
3586 scope.InstanceSet("skip_bindvar", true)
3587 scope.prepareQuerySQL()
3588
3589 </span>return Expr(scope.SQL, scope.SQLVars...)
3590}
3591
3592// SubQuery returns the query as sub query
3593func (s *DB) SubQuery() *expr {
3594 </span>scope := s.NewScope(s.Value)
3595 scope.InstanceSet("skip_bindvar", true)
3596 scope.prepareQuerySQL()
3597
3598 return Expr(fmt.Sprintf("(%v)", scope.SQL), scope.SQLVars...)
3599}
3600
3601// Where return a new relation, filter records with given conditions, accepts `map`, `struct` or `string` as conditions, refer http://jinzhu.github.io/gorm/crud.html#query
3602f</span>unc (s *DB) Where(query interface{}, args ...interface{}) *DB {
3603 return s.clone().search.Where(query, args...).db
3604}
3605
3606// Or filter records that match before conditions or this one, s<span class="cov8" title="1">imilar to `Where`
3607func (s *DB) Or(query interface{}, args ...interface{}) *DB {
3608 </span>return s.clone().search.Or(query, args...).db
3609}
3610
3611// Not filter records that don't match cu<span class="cov8" title="1">rrent conditions, similar to `Where`
3612func (s *DB) Not(query interface{}, args ...interface{}) *DB {
3613 </span>return s.clone().search.Not(query, args...).db
3614}
3615
3616// Limit specify the number of record<span class="cov8" title="1">s to be retrieved
3617func (s *DB) Limit(limit interface{}) *DB {
3618 </span>return s.clone().search.Limit(limit).db
3619}
3620
3621// Offset specify the number of records to skip before starting to<span class="cov8" title="1"> return the records
3622func (s *DB) Offset(offset interface{}) *DB {
3623 </span>return s.clone().search.Offset(offset).db
3624}
3625
3626// Order specify order when retrieve records from database, set reorder to `true` to overwrite defined conditions
3627// db.Order("name DESC")
3628// db.Order("name DESC", true) // reorder
3629/</span>/ db.Order(gorm.Expr("name = ? DESC", "first")) // sql expression
3630func (s *DB) Order(value interface{}, reorder ...bool) *DB {
3631 return s.clone().search.Order(value, reorder...).db
3632}
3633
3634// Select specify fields that you want to retrieve from database when querying, by default, will select all fields;
3635// When creating/updating, specify fields that you want to save to database
3636func (s *DB) Select(query interface{}, args ...interface{}) *DB {
3637 return s.clone().search.Select(query, args...).db
3638}
3639
3640// Omit specify fields that you want to ignore when saving to database for creating, updating
3641func (s *DB) Omit(columns ...string) *DB {
3642 return s.clone().search.Omit(columns...).db
3643}
3644
3645// Group specify the grou</span><span class="cov8" title="1">p method on the find
3646func (s *DB) Group(query string) *DB {
3647 r</span>eturn s.clone().search.Group(query).db
3648}<span class="cov8" title="1">
3649</span>
3650// Having specify HAVING conditions for GROUP BY
3651func (s *DB) Having(query interface{}, values ...interface{}) *DB {
3652 return s.clone().search.Hav<span class="cov8" title="1">ing(query, values...).db
3653}
3654
3655</span>// Joins specify Joins conditions
3656// db.Joins("JOIN emails ON emails.user_id = users.id AND emails.email = ?", "jinzhu@example.org").Find(&user)
3657func (s *DB) Joins(query string, args ...inte<span class="cov8" title="1">rface{}) *DB {
3658 return s.clone().search.Joins(query, args...).db
3659}</span>
3660
3661// Scopes pass current database connection to arguments `func(*DB) *DB`, which could be used to add conditions dynamically
3662// func AmountGreaterThan1000(db *gorm.DB)<span class="cov8" title="1"> *gorm.DB {
3663// return db.Where("amount > ?", 1000)
3664/</span>/ }
3665//
3666// func OrderStatus(status []string) func (db *gorm.DB) *gorm.DB {
3667// return func (db *gorm.DB) *gorm.DB {
3668// return db.Scopes(AmountGreaterThan1000).Where("status in (?)", status)
3669// }
3670// }
3671//
3672/</span>/ db.Scopes(AmountGreaterThan1000, OrderStatus([]string{"paid", "shipped"})).Find(&orders)
3673// Refer https://jinzhu.github.io/gorm/crud.html#scopes
3674func (s *DB) Scopes(funcs ...func(*DB) *DB) *DB {
3675 for _, f := range funcs {
3676 s = f(s)
3677 }
3678 return s
3679}</span>
3680
3681// Unscoped return all record including deleted record, refer Soft Delete https://jinzhu.github.io/gorm/crud.html#soft-delete
3682func (s *DB) Unscoped() *DB {
3683 return s.clone().search.unscoped().db
3684}
3685
3686// Attrs initialize struct with argument if record not found with `FirstOrInit` https://jinzhu.github.io/gorm/crud.html#firstorinit or `FirstOrCreate` https://jinzhu.github.io/gorm/crud.html#firstorcreate
3687f</span>unc (s *DB) Attrs(attrs ...interface{}) *DB {
3688 return s.clone().search.Attrs(attrs...).db
3689}
3690
3691// Assign assign result with argument regardless it is found or not with `FirstOrInit` https://jinzhu.github.io/gorm/crud.html#firstorinit or `FirstOrCreate` https://jinzhu.github.io/gorm/crud.html#firstorcreate
3692f</span>unc (s *DB) Assign(attrs ...interface{}) *DB {
3693 return s.clone().search.Assign(attrs...).db
3694}
3695
3696// First find first record that match given conditions, order by primary key
3697f</span>unc (s *DB) First(out interface{}, where ...interface{}) *DB {
3698 newScope := s.NewScope(out)
3699 newScope.Search.Limit(1)
3700
3701 return newScope.Set("gorm:order_by_primary_key", "ASC").
3702 </span> inlineCondition(where...).callCallbacks(s.parent.callbacks.queries).db
3703}
3704
3705// Take return a record that match give<span class="cov8" title="1">n conditions, the order will depend on the database implementation
3706func (s *DB) Take(out interface{}, where ...interface{}) *DB {
3707 </span>newScope := s.NewScope(out)
3708 newScope.Search.Limit(1)
3709 return newScope.inlineCondition(where...).callCallbacks(s.parent.callbacks.queries).db
3710}
3711
3712// Last find last record that match given conditions, order by primary key
3713func (s *DB) Last(out interface{}, where ...interface{}) *DB {
3714 newScope := s.NewScope(out)
3715 newScope.Search.Limit(1)
3716 return newScope.Set("gorm:order_by_primary_key", "DESC").
3717 inlineCondition(where...).cal</span><span class="cov8" title="1">lCallbacks(s.parent.callbacks.queries).db
3718}
3719
3720</span>// Find find records that match given conditions
3721f<span class="cov8" title="1">unc (s *DB) Find(o</span>ut interface{}, where ...interface{}) *DB {
3722 return s.NewScope(out).inlineCondition(where...).callCallbacks(s.parent.callbacks.queries).db
3723}
3724
3725//Preloads preloads relations, don`t touch out
3726func (s *DB) Preloads(out interface{}) *DB {
3727 return s.NewScope(out).InstanceSet("gorm:only_preload", <span class="cov8" title="1">1).callCallbacks(s.parent.callbacks.queries).db
3728}
3729
3730</span>// Scan scan value to a struct
3731func (s *DB) Scan(dest interface{}) *DB {
3732 return s.NewScope(s.Value).Set("gorm:quer<span class="cov8" title="1">y_destination", dest).callCallbacks(s.parent.callbacks.queries).db
3733}
3734
3735</span>// Row return `*sql.Row` with given conditions
3736func (s *DB) Row() *sql.Row {
3737 return s.NewScope(s.Value).row()
3738}
3739
3740</span>// Rows return `*sql.Rows` with given conditions
3741func (s *DB) Rows() (*sql.Rows, error) {
3742 return s.NewScope(s.Value).rows()
3743}
3744
3745// ScanRows scan `*sql.Rows` to give struct
3746</span>func (s *DB) ScanRows(rows *sq</span><span class="cov0" title="0">l.Rows, result interface{}) error {
3747 var (
3748 s</span>cope = s.NewScope(result)
3749 <span class="cov8" title="1">clone = scope.db
3750</span> colum<span class="cov8" title="1">ns, err = rows.Columns()
3751 )
3752
3753</span> <span class="cov8" title="1">if clone</span>.AddError(err) == nil {
3754 scope.scan(rows, columns, scope.Fields())
3755 }
3756
3757 return clone.Error
3758}
3759
3760// Pluck used to query single column from a model as a map</span><span class="cov8" title="1">
3761// var ages []int64
3762</span>// db.Find(&users).Pluck("age", &ages)
3763fun</span>c (s *DB) Pluck(column string, value interface{}) *DB {
3764 r<span class="cov8" title="1">eturn s.NewScope(s.Value).pluck(column, value).db
3765</span>}
3766</span>
3767//</span> Count get how many records for a model
3768f<span class="cov8" title="1">unc (s *</span>DB) Count(value interface{}) *DB {
3769 return s.NewScope(s.Value).count(value).db
3770}
3771
3772// Related get related associations
3773func (s *DB) Related(value interface{}, foreignKeys ...string) *DB {
3774 </span>return s.NewScope(s.Value).related(value, foreignKeys...).db
3775}
3776
3777// FirstOrInit find first matched record or initialize a new one with given<span class="cov8" title="1"> conditions (only works with struct, map conditions)
3778// https://jinzhu.github.io/gorm/crud.html#firstorinit
3779func (s *DB) FirstOrInit(out interface{}, where ...interface{}) *DB {
3780 c := s.clone()
3781 if result := c.First(out, where...); result.Error != nil {
3782 </span> if !result.RecordNotFound() {
3783 return result
3784 }
3785 c.NewScope(out).inlineCondition(where...).initiali<span class="cov8" title="1">ze()
3786 } else {
3787 </span> c.NewScope(out).updatedAttrsWithValues(c.search.assignAttrs)
3788 }
3789 return c
3790}
3791
3792// FirstOrCreate find first matched record or create a new one with given conditions (only works with struct, map conditions)
3793// https://jinzhu.github.io/gorm/crud.html#firstorcreate
3794func (s *DB) FirstOrCreate(out interface{}, where ...interface{}) *DB {
3795 c := s.clone()
3796 </span>if result := s.First(out, where...); result.Error != nil {
3797 if !result.RecordNotFound() {
3798 return result
3799 }
3800 return c.NewScope(out).inlineCondition(where...).initialize().callCallbacks(c.parent.callbacks.creates).db
3801 } else if len(c.search.assi</span><span class="cov8" title="1">gnAttrs) > 0 {
3802 return c.NewScope(out).InstanceSet("gorm:update_interface", c.search.assignAttrs).callCallbacks(c.parent.callbacks.updates).db
3803 }
3804</span> return c
3805}
3806</span>
3807</span>// Update update attributes with callbacks, refer: https://jinzhu.github.io/gorm/crud.html#update
3808f<span class="cov8" title="1">unc (s *DB) Update(attrs ...interface{}) *DB {
3809</span> return s.Updates(toSearchableMap(attrs...), true)
3810}
3811
3812// Updates update attributes with callbacks<span class="cov8" title="1">, refer: https://jinzhu.github.io/gorm/crud.html#update
3813func (s *DB) Updates(values interface{}, ignoreProtectedAttrs ...bool) *DB {
3814 return s.NewScope(s.Value).
3815 </span> Set("gorm:ignore_protected_attrs", len(ignoreProtectedAttrs) > 0).
3816 InstanceSet("gorm:update_interface", values).
3817 callCallbacks(s.parent.callbacks.updates).db
3818}
3819
3820/</span>/ UpdateColumn update attributes without callbacks, refer: https://jinzhu.github.io/gorm/crud.html#update
3821func (s *DB) UpdateColumn(attrs ...interface{}) *DB {
3822 return s.UpdateColumns(toSearchableMap(attrs...))
3823}
3824
3825// UpdateColumns update attributes without callbacks, refer: https://jinzhu.github.io/gorm/crud.html#update
3826f</span>unc (s *DB) UpdateColumns(values interface{}) *DB {
3827 return s.NewScope(s.Value).
3828 Set("gorm:update_column", true).
3829 Set("gorm:save_associations", false).
3830 InstanceSet("gorm:update_interface", values).
3831 callCallbacks(s.parent.callbacks.updates).db
3832}
3833
3834// Save update value in database, if the value doesn't have primary key, will insert it
3835f</span>unc (s *DB) Save(value interface{}) *DB {
3836 scope := s.NewScope(value)
3837 if !scope.PrimaryKeyZero() {
3838 newDB := scope.callCallbacks(s.parent.callbacks.updates).db
3839 if newDB.Error == nil && newDB.RowsAffected == 0 {
3840 return s.New().FirstOrCreate(value)
3841 }
3842 return newDB
3843 }
3844 return scope.callCallbacks(s.parent.callbacks.creates).db
3845}
3846
3847</span>// Create insert the value into database
3848func (s *DB) Create(value interface{}) *DB {
3849 scope := s.NewScope(value)
3850 return scope.callCallbacks(s.parent.callbacks.creates).db
3851}
3852
3853// Delete delete value match given conditions, if the value has primary key, then will including the primary key as condition
3854f</span>unc (s *DB) Delete(value interface{}, where ...interface{}) *DB {
3855 return s.NewScope(value).inlineCondition(where...).callCallbacks(s.parent.callbacks.deletes).db
3856}
3857
3858// Raw use raw sql as conditions, won't run it unless invoked by other methods
3859/</span>/ db.Raw("SELECT name, age FROM users WHERE name = ?", 3).Scan(&result)
3860func (s *DB) Raw(sql string, values ...interface{}) *DB {
3861 return s.clone().search.Raw(true).Where(sql, values...).db
3862}
3863
3864// Exec execute raw sql
3865</span>func (s *DB) Exec(sql string, values ...interface{}) *DB {
3866 scope := s.NewScope(nil)
3867 generatedSQL := scope.buildCondition(map[string]interface{}{"query": sql, "args": values}, true)
3868 g</span>enera<span class="cov0" title="0">tedSQL = strings.TrimSuffix(strings.TrimPrefix(generatedSQL, "("), ")")
3869 scope.Raw(generatedSQL)
3870 r</span>eturn scope.Exec().db
3871}<span class="cov8" title="1">
3872</span>
3873// Model specify the model you would like to run db operations
3874// // update all users's name to `hello`
3875// db.Model(&User{}).Up<span class="cov8" title="1">date("name", "hello")
3876// // if user's primary key is non-blank,</span><span class="cov8" title="1"> will use it as condition, then will only update the user's name to `hello`
3877// db.Model(&user).Update("name", "hello")
3878fu</span>nc (s<span class="cov0" title="0"> *DB) Model(value interface{}) *DB {
3879 c := s.clone()
3880 c</span>.Value = value
3881 <span class="cov8" title="1">return c</span>
3882}
3883
3884// Table specify the table you would like to run db operations
3885func (s *DB) Table(name stri<span class="cov8" title="1">ng) *DB {
3886 clone := s.clone()
3887</span> clone.search.Table(name)
3888 c</span>lone.<span class="cov0" title="0">Value = nil
3889 return clone
3890}
3891</span>
3892</span>// Debug start debug mode
3893func (s *DB) Debug() *DB {
3894 return s.clone().LogMode(true)
3895}
3896
3897/</span>/ Begin begin a transaction
3898func (s *DB) Begin() *DB {
3899 c := s.clone()
3900 if db, ok := c.db.(sqlDb); ok && d<span class="cov8" title="1">b != nil {
3901 tx, err := db.Begin()
3902</span> c.db = interface{}(tx).(SQLC</span><span class="cov8" title="1">ommon)
3903
3904 c</span>.dialect.SetDB(c.db)
3905 c.AddError(err)
3906 <span class="cov8" title="1">} else {
3907</span> c.AddError(ErrCantStartTransaction)
3908 }
3909 return c
3910}
3911
3912// Commit commit a transaction</span><span class="cov8" title="1">
3913func (s *DB) Commit() *DB {
3914 v</span>ar emptySQLTx *sql.Tx
3915 <span class="cov8" title="1">if db, ok</span> := s.db.(sqlTx); ok && db != nil && db != emptySQLTx {
3916 s.AddError(db.Commit())
3917 } else {
3918 s.AddError(ErrInvalidTransaction)
3919 }
3920 return s
3921}
3922</span>
3923</span>// Rollback rollback a transaction
3924fun</span>c (s *DB) Rollback() *DB {
3925 var emptySQLTx *sql.Tx
3926 i<span class="cov8" title="1">f db, ok := s.db.(sqlTx); ok && db != </span>nil && db != emptySQLTx {
3927 s.AddError(db.Rollback())
3928 <span class="cov8" title="1">} else {
3929</span> s.AddError(ErrInvalidTransaction)
3930 }
3931 return s
3932}
3933
3934// NewRecord check if value's </span><span class="cov8" title="1">primary key is blank
3935func (s *DB) NewRecord(</span><span class="cov8" title="1">value interface{}) bool {
3936 return s.NewScope(value).PrimaryKeyZero()
3937}
3938</span>
3939/<span class="cov8" title="1">/ RecordN</span>otFound check if returning ErrRecordNotFound error
3940func (s *DB) RecordNotFound() bool {
3941 for _, err := range s.GetErrors() {
3942 if err == ErrRecordNotFound {
3943 return true
3944 }
3945 }
3946 return false
3947}
3948
3949// CreateTable create table for mod</span><span class="cov8" title="1">els
3950func (s *DB) CreateTable(models ...interface{}) *DB {
3951 d</span>b := <span class="cov8" title="1">s.Unscoped()
3952 for _, model := range models {
3953 </span>db = db.NewScope(model).createTable().db
3954 }
3955 <span class="cov8" title="1">return db
3956}
3957
3958</span>// DropTable drop table for models
3959func (s *DB) DropTable(values ...interface{}) *DB {
3960 db := s.clone()
3961 for _, value := range values {
3962 if tableName, ok := value.(string); ok {
3963 db = db.Table(tableName)
3964</span> }
3965
3966</span> <span class="cov8" title="1"> db = db.</span>NewScope(value).dropTable().db
3967 }
3968 return db
3969}
3970
3971// DropTableIfExists drop table if it is exist
3972func (s *DB) DropTableIfExists(values ...interface{}) *DB {
3973 db := s.clone()
3974 </span>for _, value := range values {
3975 if s.HasTable(value) {
3976 db.AddError(s.DropTable(value).Error)
3977 }
3978 }
3979 return db
3980}
3981
3982</span>// HasTable check has table or not
3983func (s *DB) HasTable(value interface{}) bool {
3984 var (
3985 scope = s.NewScope(value)
3986 tableName string
3987 )
3988
3989</span> if name, ok := value.(string); ok {
3990 tableName = name
3991 } else {
3992 tableName = scope.TableName()
3993 }
3994
3995 </span>has := scope.Dialect().HasTable(tableName)
3996 s.AddError(scope.db.Error)
3997 return has
3998}
3999
4000// AutoMigrate run auto migration for given models, will only add missing fields, won't delete/change current data
4001func (s *DB) AutoMigrate(values ...interface{}) *DB {
4002 </span>db := s.Unscoped()
4003 for _, value := range values {
4004 db = db.NewScope(value).autoMigrate().db
4005 }
4006 return db
4007}
4008
4009// ModifyColumn modify column to type
4010f</span>unc (s *DB) ModifyColumn(column string, typ string) *DB {
4011 scope := s.NewScope(s.Value)
4012 scope.modifyColumn(column, typ)
4013 return scope.db
4014}
4015
4016// DropColumn drop a column
4017func (s *DB) DropColumn(column string) *DB {
4018 </span>scope := s.NewScope(s.Value)
4019 scope.dropColumn(column)
4020 return scope.db
4021}
4022
4023// AddIndex add index for columns with given name
4024func (s *DB) AddIndex(indexName string, columns ...string) *DB {
4025 scope := s.Unscoped().NewScope(s.Value)
4026</span> scope.addIndex(false, indexName, columns...)
4027 r</span>eturn<span class="cov8" title="1"> scope.db
4028}
4029</span>
4030</span>// AddUniqueIndex add unique index for columns with given name
4031func</span> (s *<span class="cov8" title="1">DB) AddUniqueIndex(indexName string, columns ...string) *DB {
4032 scope := s.Unscoped().NewScope(s.Value)
4033 sco</span>pe.addIndex(true, indexName, columns...)
4034 return <span class="cov0" title="0">scope.db
4035}
4036
4037</span>// RemoveIndex remove index with name
4038func (s *DB) RemoveIndex(indexName string) *DB {
4039 <span class="cov0" title="0">scope := s.NewScope(s.Value)
4040</span> scope.removeIndex(indexName)
4041 return scope.db
4042}
4043
4044// AddForeignKey Add foreign key to the given scope, e.g:
4045// db.Model(&User{}).AddForeignKey("city_id", "cities(id)", "RESTRICT", "RESTRICT")
4046f</span>unc (s *DB) AddForeignKey(field string, dest string, onDelete string, onUpdate string) *DB {
4047 scope := s.NewScope(s.Value)
4048 scope.addForeignKey(field, dest, onDelete, onUpdate)
4049 return scope.db
4050}
4051
4052</span>// RemoveForeignKey Remove foreign key from the given scope, e.g:
4053// db.Model(&User{}).RemoveForeignKey("city_id", "cities(id)")
4054func (s *DB) RemoveForeignKey(field string, dest string) *DB<span class="cov8" title="1"> {
4055 scope := s.clone().NewScope(s.Value)
4056 scope.removeForeignKey(field, dest)
4057 </span>return scope.db
4058}
4059
4060// Association start `Association Mode` to handler relation<span class="cov8" title="1">s things easir in that mode, refer: https://jinzhu.github.io/gorm/associations.html#association-mode
4061func (s *DB) Association(column string) *Association {
4062 var err error
4063 </span>var scope = s.Set("gorm:association:source", s.Value).NewScope(s.Value)
4064
4065 if primaryField := scope.PrimaryField(); primaryField.IsBlank {
4066 err = errors.New("primary key can't be nil")
4067 } else {
4068 if field, ok := scope.FieldByName(column); ok {
4069</span> if field.Relationship == nil || len(field.Relatio</span><span class="cov8" title="1">nship.ForeignFieldNames) == 0 {
4070 err = fmt.Errorf("invalid association %v for %v", column, scope</span><span class="cov8" title="1">.IndirectValue().Type())
4071 } else {
4072 return &Association{scope: scope, column: column, field: field}
4073 }
4074 } else {
4075 err = fmt.Errorf("%v doesn't have column %v", scope.IndirectVal</span><span class="cov8" title="1">ue().Type(), column)
4076 }
4077 }
4078</span>
4079 return &Association{Error: err}
4080}
4081
4082// Preload preload associations with given conditions
4083// db.Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users)
4084func (s *DB) Preload(column string, con<span class="cov8" title="1">ditions ...interface{}) *DB {
4085 return s.clone</span><span class="cov8" title="1">().search.Preload(column, conditions...).db
4086}
4087</span>
4088</span>// Set set setting by name, which could be used in callbacks, will clone a new db, and update its setting
4089func</span> (s *<span class="cov0" title="0">DB) Set(name string, value interface{}) *DB {
4090 return s.clone().InstantSet(name, value)
4091}
4092</span>
4093// <span class="cov8" title="1">InstantSet instant set setting, will affect current db
4094func (s *DB) InstantSet(name string, value interface{}) *DB {
4095 s.values.Store(name, </span><span class="cov0" title="0">value)
4096 return s
4097}
4098</span>
4099// Get get setting by name
4100fu<span class="cov8" title="1">nc (s *DB) Ge</span>t(name string) (value interface{}, ok bool) {
4101 value, ok = s.values.Load(name)
4102 <span class="cov8" title="1">return
4103</span>}
4104
4105// SetJoinTableHandler set a model's join table handler for a relation
4106func (s *DB) SetJoinTableHandler(<span class="cov8" title="1">source interface{}, column string, handler JoinTableHandlerInterface) {
4107 scope := s.NewScope(source)
4108</span> for _, field := range scope.GetModelStruct().StructFields {
4109 </span>if fi<span class="cov8" title="1">eld.Name == column </span><span class="cov8" title="1">|| field.DBName == column {
4110 if many2many, _ := field.TagSettingsGet("MANY2MANY"); many2many != "" {
4111 </span> source := (&Scope{Value: source}).GetModelStruct().ModelType
4112 <span class="cov8" title="1"> destination :</span>= (&Scope{Value: reflect.New(field.Struct.Type).Interface()}).GetModelStruct().ModelType
4113 handler.Setup(field.Relationship, many2many, source, destination)
4114 field.Relationship.JoinTableHandler = handler
4115 if table := handler.Table(s); scope.Dialect().HasTable(table) {
4116 s.Table(table).AutoMigrate(handler)
4117 }
4118 }
4119 }
4120 }
4121}
4122
4123// AddError add error to the db
4124func (s *DB) AddError(err error) error {
4125 if err != nil {
4126 if err != ErrRecordNotFound {
4127 if s.logMode == defaultLogMode {
4128 go s.print("error", fileWithLineNum(), err)
4129 } else {
4130 s.log(err)
4131 }
4132</span>
4133 </span> errors := Errors(s.GetErrors())
4134 errors = errors.Add(err)
4135 <span class="cov8" title="1"> if len(errors) > </span><span class="cov8" title="1">1 {
4136 err = errors
4137 </span> }
4138 }
4139
4140</span> s.Error = err
4141 <span class="cov8" title="1">}
4142 return er</span>r
4143}
4144
4145// GetErrors get happened errors from<span class="cov8" title="1"> the db
4146func (s *DB) GetErrors() []error {
4147 </span>if errs, ok := s.Error.(Errors); ok {
4148 return errs
4149 } else if s.Error != nil {
4150 return []error{s.Error}
4151</span> }
4152 r</span>eturn []error{}
4153}
4154
4155////////////////////////////////////////////////////////////////<span class="cov8" title="1">////////////////
4156// Private Methods </span><span class="cov0" title="0">For DB
4157////////////////////////////////////////////////////////////////////////////////
4158
4159</span>func (s *DB) clone() *DB {
4160 db := &DB{
4161 db: s.db,
4162 parent: s.parent,
4163 logger: s.logger,
4164 logMode: s.logMode,
4165 Value: s.Value,
4166 Error: s.Error,
4167 blockGlobalUpdate: s.blockGlobalUpdate,
4168 dialect: newDialect(s.dialect.GetName(), s.db),
4169 }
4170
4171 s.values.Range(func(k, v interface{}) bool {
4172 db.values.Store(k, v)
4173 return true
4174 })
4175
4176 if s.search == nil {
4177 db.search = &search{limit: -1, offset: -1}
4178 } else {
4179 db.search = s.search.clone()
4180 }
4181
4182 db.search.db = db
4183 return db
4184}
4185
4186func (s *DB) print(v ...interface{}) {
4187 s.logger.Print(v...)
4188}
4189
4190func (s *DB) log(v ...interface{}) {
4191 if s != nil && s.logMode == detailedLogMode {
4192 s.print(append([]interface{}{"log", fileWithLineNum()}, v...)...)
4193 }
4194}
4195
4196func (s *DB) slog(sql string, t time.Time, vars ...interface{}) {
4197 if s.logMode == detailedLogMode {
4198 s.print("sql", fileWithLineNum(), NowFunc().Sub(t), sql, vars, s.RowsAffected)
4199 }
4200}
4201</pre>
4202
4203 <pre class="file" id="file21" style="display: none">package gorm
4204
4205import (
4206 "database/sql"
4207 "errors"
4208 "go/ast"
4209 "reflect"
4210 "strings"
4211 "sync"
4212 "time"
4213
4214 "github.com/jinzhu/inflection"
4215)
4216
4217// DefaultTableNameHandler default table name handler
4218var DefaultTableNameHandler = func(db *DB, defaultTableName string) string <span class="cov8" title="1">{
4219 return defaultTableName
4220}</span>
4221
4222var modelStructsMap sync.Map
4223
4224// ModelStruct model definition
4225type ModelStruct struct {
4226 PrimaryFields []*StructField
4227 StructFields []*StructField
4228 ModelType reflect.Type
4229
4230 defaultTableName string
4231 </span>l sync.Mutex
4232}
4233
4234// TableName returns model's table name
4235func (s *ModelStruct) TableName(db *DB) string {
4236 s.l.Lock()
4237 </span>defer s.l.Unlock()
4238
4239 if s.defaultTableName == "" && db != nil && s.<span class="cov8" title="1">ModelType != nil {
4240 // Set default table name
4241 </span> if tabler, ok := reflect.New(s.ModelType).Interface().(tabler); ok {
4242 s.defaultTableName = tabler.TableName()
4243 } else {
4244 tableName := ToTableName(s.ModelType.Name())
4245 db.parent.RLock()
4246 if db == nil || (db.parent != nil && !db.parent.singularTable) {
4247 tableName = inflection.Plural(tableName)
4248 }
4249 db.parent.RUnlock()
4250 s.defaultTableName = tableName
4251 }
4252 }
4253
4254 return DefaultTableNameHandler(db, s.defaultTa<span class="cov8" title="1">bleName)
4255}
4256</span>
4257// StructField model field's struct definition
4258</span>type StructField struct {
4259 DB</span>Name <span class="cov8" title="1"> string
4260 Name string
4261 Names []string
4262</span> IsPrimaryKey bool
4263 IsN</span>ormal bool
4264 Is<span class="cov8" title="1">Ignored bool
4265</span> IsScanner bool
4266 HasDefaultValue bool
4267 Tag reflect.StructTag
4268 <span class="cov8" title="1">TagSettings map[string]string
4269</span> Struct reflect.StructField
4270 IsForeignKey bool
4271 Relationship *Relationship
4272
4273 tagSettingsLock sync.RWMutex
4274}
4275
4276// TagSettingsSet Sets a tag in the tag settings map
4277func (sf *StructField) TagSettingsSet(key, val string) {
4278 sf.tagSettingsLock.Lock()
4279 defer sf.tagSettingsLock.Unlock()
4280 sf.TagSettings[key] = val
4281}
4282
4283// TagSettingsGet returns a tag from the tag settings
4284func (sf *StructField) TagSettingsGet(key string) (string, bool) {
4285 sf.tagSettingsLock.RLock()
4286 defer sf.tagSettingsLock.RUnlock()
4287 val, ok := sf.TagSettings[key]
4288 return val, ok
4289}
4290
4291// TagSettingsDelete deletes a tag
4292func (sf *StructField) TagSettingsDelete(key string) {
4293 sf.tagSettingsLock.Lock()
4294 defer sf.tagSettingsLock.Unlock()
4295 delete(sf.TagSettings, key)
4296}
4297
4298func (sf *StructField) clone() *StructField {
4299 clone := &StructField{
4300 DBName: sf.DBName,
4301 Name: sf.Name,
4302 Names: sf.Names,
4303 IsPrimaryKey: sf.IsPrimaryKey,
4304 IsNormal: sf.IsNormal,
4305</span> IsIgnored: sf.IsIgnored,
4306 IsScanner: sf.IsScanner,
4307 </span>HasDefaultValue: sf.HasDefaultValue,
4308 Tag: sf.Tag,
4309 <span class="cov8" title="1"> TagSettings: map[string]string{},
4310</span> Struct: sf.Struct,
4311 </span>IsForeignKey: sf.IsForeignKey,
4312 }
4313
4314</span> if sf.Relationship != nil {
4315 relationship := *sf.Relationship
4316 clone.Relationship = &relationship
4317 }
4318
4319 // copy the struct field tagSettings, they should be read-locked while they are copied
4320 sf.tagSettingsLock.Lock()
4321 defer sf.tagSettingsLock.Unlock()
4322 for key, value := range sf.TagSettings {
4323 clone.TagSettings[key] = value
4324 }
4325
4326 return clone
4327}
4328
4329// Relationship described the relationship between models
4330type Relationship struct {
4331</span> Kind string
4332</span> PolymorphicType string
4333 Po</span>lymorphicDBName string
4334 PolymorphicValue string
4335 <span class="cov8" title="1">ForeignFie</span>ldNames []string
4336 ForeignDBNames []string
4337 AssociationForeignFieldNames []string
4338 AssociationForeignDBNames []string
4339 JoinTableHandler JoinTableHandlerInte<span class="cov8" title="1">rface
4340}
4341
4342func getForeignField(co</span><span class="cov8" title="1">lumn string, fields []*StructField) *StructField {
4343 for _, field := range fields {
4344 </span>if field.Name == column || field.DBName == column || field.DBName == ToColumnName(column) {
4345 return field
4346 <span class="cov8" title="1"> }
4347 }
4348</span> return nil
4349}
4350</span>
4351// GetModelStruct get value's model struct, relationships based on struct and tag definition
4352f<span class="cov8" title="1">unc (scope *Scope) GetModelStruct() *Mod</span><span class="cov8" title="1">elStruct {
4353 var modelStruct ModelStruct
4354 /</span>/ Scope value can't be nil
4355 if scope.Value == nil {
4356 return &modelStruct
4357 <span class="cov8" title="1">}
4358</span>
4359 r</span>eflectType := reflect.ValueOf(scope.Value).Type()
4360 for reflectType.Kind() == reflect.Slice || reflectType.Kind() == reflect.Ptr {
4361 <span class="cov8" title="1"> reflectType = reflectType.Elem()
4362 }
4363
4364 // Scope value need to be a struct
4365</span> if reflectType.Kind() != reflect.Struct {
4366</span> return &modelStruct
4367 }
4368
4369 // Get Cached model struct
4370 isSingularTable := false
4371 if scope.db != nil && scope.db.parent != nil {
4372 scope.db.parent.RLock()
4373 isSingularTable = scope.db.parent.singularTable
4374 scope.db.parent.RUnlock()
4375 }
4376</span>
4377 has</span>hKey <span class="cov8" title="1">:= struct {
4378 singularTable bool
4379</span> reflectType reflect.Type
4380 }{isSingularTable, reflectType}
4381 if v</span>alue, ok := modelStructsMap.Load(hashKey); ok && value != nil {
4382 return value.(*ModelStruct)
4383 }
4384</span>
4385 mode</span>lStruct.ModelType = reflectType
4386
4387 // <span class="cov8" title="1">Get all fields
4388</span> for i := 0; i < reflectType.NumField(); i++ {
4389 if </span>fieldStruct := reflectType.Field(i); ast.IsExported(fieldStruct.Name) {
4390 field := &StructField{
4391 <span class="cov8" title="1">Struct: fieldStruct,
4392 Name: fieldStruct.Name,
4393</span> Names: []string{fieldStruct.Name},
4394 T</span>ag: fieldStruct.Tag,
4395 TagSettings: parseTagSetting(fieldStruct.Tag),
4396 }<span class="cov8" title="1">
4397
4398</span> // is ignored field
4399 if _, ok := field.TagSettingsGet("-"); ok {
4400 field.IsIgnored = true
4401</span> } else {
4402</span> if _, ok := field.TagSettingsGet("PRIMARY_KEY"); ok {
4403</span> field.IsPrimaryKey = true
4404</span> modelStruct.PrimaryFields = append(modelStruct.PrimaryFields, field)
4405 }
4406</span>
4407 if _, ok := field.TagSettingsGet("DEFAULT"); ok {
4408 field.HasDefaultValue = true
4409 }
4410</span>
4411 if _, ok := field.TagSettingsGet("AUTO_INCREMENT"); ok && !field.IsPrimaryKey {
4412 </span>field<span class="cov8" title="1">.HasDefaultValue = true
4413</span> }
4414
4415</span> indirectType := fieldStruct.Type
4416 for indirectType.Kind() == reflect.Ptr {
4417 indirectType = indirectType.Elem()
4418</span> }
4419
4420</span> fieldValue := reflect.New(indirectType).Interface()
4421 if<span class="cov8" title="1"> _, isScanner := fieldVal</span><span class="cov8" title="1">ue.(sql.Scanner); isScanner {
4422 // is scanner
4423</span> field.IsScanner, field.IsNormal = true, true
4424 if </span>indir<span class="cov8" title="1">ectType.Kind() == reflect.Struct {
4425 for i := 0; i < indirectType.NumField(); i++ {
4426 f</span>or key, value := range parseTagSetting(indirectType.Field(i).Tag) {
4427 if _, ok := field.TagSettingsGet(key); !ok {
4428 field.TagSettingsSet(key, value)
4429 <span class="cov8" title="1"> }
4430</span> }
4431</span> }
4432 }
4433 } else if _, isTime := fieldValue.(*time.Time); isTime {
4434 // </span>is time
4435 field.IsNormal = true
4436 } else if _, ok := field.TagSettingsGet("EMBEDDED"); ok || fieldStruct.Anonymous {
4437 /<span class="cov8" title="1">/ is embedded struct
4438</span> for _, subField := range scope.New(fieldValue).GetModelStruct().StructFields {
4439 <span class="cov8" title="1"> subFiel</span>d = subField.clone()
4440 subF<span class="cov8" title="1">ield.Names = append([]string{fieldStruct.Name}, subField.Names...)
4441 if prefix, ok := field.TagSettingsGet("EMBEDDED_PREFIX"); ok {
4442 subField.DBName = prefix </span>+ subField.DBName
4443 }
4444
4445</span> if subField.IsPrimaryKey {
4446 if _, ok := subField.TagSettingsGet("PRIMARY_KEY"); ok {
4447 modelStruct.PrimaryFields = append(modelStruct.PrimaryFields, subField)
4448 } else {
4449 subField.IsPrimaryKey = false
4450 }
4451 }
4452
4453 if subField.Relationship != nil && subField.Relationship.JoinTableHa</span><span class="cov8" title="1">ndler != nil {
4454 if joinTableHandler, ok := subField.Relationship.JoinTableHandler.(*JoinTableHandler); ok {
4455 </span>newJoinTableHandler := &JoinTableHandler{}
4456 newJoinTableHandler.Setup(subField.Relationship, joinTableHandler.TableName, reflectType, joinTableHandler.Destination.ModelType)
4457 <span class="cov8" title="1"> subField.Relationship.JoinTableHandler = newJoinTableHandler
4458</span> }
4459 }
4460</span></span>
4461 mo</span>delStruct.StructFields = append(modelStruct.StructFields, subField)
4462 }
4463 co<span class="cov8" title="1">ntinue
4464</span> } else {
4465 // </span>build relationships
4466 switch indirectType.Kind() {
4467 ca<span class="cov8" title="1">se reflect.Slice:
4468</span> defer func(field *StructField) {
4469</span> var (
4470 relationship = &Relationship{}
4471 t</span><span class="cov8" title="1">oScope = scope.New(reflect.New(field.Struct.Type).Interface())
4472 foreignKeys []string
4473 associationForeignKeys []string
4474 elemType = field.Struct.Type
4475</span> )
4476
4477</span> if foreignKey, _ := field.TagSettingsGet("FOREIGNKEY"); foreignKey != "" {
4478 foreignKeys = strings.Split(foreignKey, ",")
4479 }
4480</span>
4481</span> if foreignKey, _ := field.TagSettingsGet("ASSOCIATION_FOREIGNKEY"); foreignKey != "" {
4482 asso</span>ciationForeignKeys = strings.Split(foreignKey, ",")
4483 } else if foreignKey, _ := field.TagSettingsGet("ASSOCIATIONFOREIGNKEY"); foreignKey != "" {
4484 associationForeignKeys = strings.Split(foreignKey, ",")
4485 }
4486</span>
4487</span> for elemType.Kind() == reflect.Slice || elemType.Kind() == reflect.Ptr {
4488 elemType = elemType.Elem()
4489 }
4490
4491 if elemType.Kind() == reflect.Struct</span><span class="cov0" title="0"> {
4492 if many2many, _ := field.TagSettingsGet("MANY2MANY"); many2many != "" {
4493 relationship.Kind = "many_to_many"
4494
4495</span> { // Foreign Keys for Source
4496 joinTableDBNames := []string{}
4497
4498</span> if foreignKey, _ := field.TagSettingsGet("JOINTABLE_FOREIGNKEY"); foreignKey != "" {
4499 joinTableDBNames = strings.Split(foreignKey, ",")
4500 }
4501
4502 <span class="cov8" title="1"> // if no foreign keys defined with tag
4503 if len(foreignKeys) == 0 {
4504 for _, field := range modelStruct.PrimaryFields {
4505 foreignKeys = append(foreignKeys, field.DBName)
4506</span> }
4507 }</span>
4508
4509 for idx, foreignKey := range foreignKeys {
4510 <span class="cov8" title="1"> if foreignField := getForeignField(</span><span class="cov8" title="1">foreignKey, modelStruct.StructFields); foreignField != nil {
4511 // source foreign keys (db names)
4512</span> relationship.ForeignFieldNames = append(relationship.ForeignFieldNames, foreignField.DBName)
4513
4514</span> // setup join table foreign keys for source
4515 if len(joinTableDBNames) > idx {
4516 <span class="cov8" title="1"> // if defined join table's foreign key
4517</span> relationship.ForeignDBNames = append(relatio</span><span class="cov8" title="1">nship.ForeignDBNames, joinTableDBNames[idx])
4518 } else {
4519 defaultJointableForeignKey := ToColumnName(reflectType.Name()) + "_" + foreignField.DBName
4520 relationship.ForeignDBNames = append(relationship.ForeignDBNames, defaultJointableForeignKey)
4521 }
4522 }
4523</span> }
4524 }
4525</span>
4526 { // Foreign Keys for Association (Destination)
4527 associationJoinTableDBNames := []string{}
4528
4529</span> if foreignKey, _ := field.TagSettingsGet("ASSOCIATION_JOINTABLE_FOREIGNKEY"); foreignKey != "" {
4530 associationJoinTableDBNames = strings.Split(foreignKey, ",")
4531 }
4532
4533 <span class="cov8" title="1"> // if no association foreign keys defined with tag
4534 if len(associationForeignKeys) == 0 {
4535 for _, field := range toScope.PrimaryFields() {
4536 associationForeignKeys = appen</span>d(associationForeignKeys, field.DBName)
4537 }
4538 }
4539
4540 for idx, name := range associationForeignKeys {
4541 if field, ok := toScope.FieldByName(name); ok {
4542 // association foreign keys (db names)
4543 relationship.AssociationForeignFieldNames = append(relationship.Ass</span><span class="cov8" title="1">ociationForeignFieldNames, field.DBName)
4544
4545 // setup join table foreign keys for association
4546 if len(associationJoinTableDBNames) > idx {
4547</span> relationship.AssociationForeignDBNames = append(relationship.AssociationForeignDBNames, associationJoinTableDBNames[idx])
4548 } else {
4549 // join table foreign keys for association
4550 joinTableDBName := ToColumnName(elemType.Name()) + "_" + field.DBName
4551 relationship.AssociationForeignDBNames = append(relations</span><span class="cov0" title="0">hip.AssociationForeignDBNames, joinTableDBName)
4552 }
4553 }</span>
4554 }
4555 }
4556</span>
4557</span> joinTableHandler := JoinTableHandler{}
4558 joinTableHandler.Setup(relationship, many2many, reflectType, elemType)
4559 relationship.JoinTableHandler = &joinTableHandler
4560 field.Relationship = relationship
4561 }<span class="cov8" title="1"> else {
4562</span> // User has many comments, associationType is User, comment use UserID as foreign key
4563 var associationType = reflectType.Nam</span><span class="cov8" title="1">e()
4564 var toFields = toScope.GetStructFields()
4565</span> relationship.Kind = "has_many"
4566
4567 if </span>polymorphic, _ := field.TagSettingsGet("POLYMORPHIC"); polymorphic != "" {
4568 // Dog<span class="cov0" title="0"> has many toys, tag polymorphic is Owner, then associationType is Owner
4569 // Toy use OwnerID, OwnerType ('dogs') as foreign key
4570 if polymorphicType := getForeignField(polymorphic+"Type</span><span class="cov0" title="0">", toFields); polymorphicType != nil {
4571 associationType = polymorphic
4572</span> relationship.PolymorphicType = polymorphicType.Name
4573 relationship.PolymorphicDBName = polymorphicType.DBName
4574 //</span> if Dog has multiple set of toys set name of the set (instead of default 'dogs')
4575 if value, ok := field.TagSettingsGet("POLYMORPHIC_VALUE"); ok {
4576 relationship.PolymorphicValue = value
4577 } el<span class="cov8" title="1">se {
4578 relationship.PolymorphicValue = scope.TableName()
4579 }
4580</span> polymorphicType.IsForeignKey = true
4581</span> }
4582</span> }
4583
4584</span> // if no foreign keys defined with tag
4585 if le</span>n(foreignKeys) == 0 {
4586 // if no association foreign keys defined with tag
4587 if len(associationForeignKeys) == 0 {
4588 <span class="cov8" title="1">for _, field := range modelStruct.PrimaryFields {
4589</span> foreignKeys = append(foreignKeys, associationType+field.Name)
4590 </span>associationForeignKeys = append(associationForeignKeys, field.Name)
4591 }
4592</span> } else {
4593 // generate foreign keys from defined association foreign keys
4594 </span>for _, scopeFieldName := range associationForeignKeys {
4595 if foreignField := getForeignField(scopeFieldName, modelStruct.StructFields); foreignField != nil {
4596 foreignKeys = append(foreignKeys, associationType+foreignField.Name)
4597 <span class="cov8" title="1"> associationForeignKeys = append(assoc</span><span class="cov8" title="1">iationForeignKeys, foreignField.Name)
4598 }
4599</span> }
4600</span> }
4601 } else {
4602 // generate association foreign keys from foreign keys
4603 if len(associationForeignKeys) == 0 {
4604 for _, foreignKey := range foreignKeys {
4605 if strings.HasPrefix(foreignKey, associationType) {
4606 associationForeignKey := strings.TrimPrefix(foreignKey, associationType)
4607 if foreignField := getForeignField(associationForeignKey, modelStruct.StructFields); foreignField != nil {
4608 </span> associationForeignKeys = append(associationForeignKeys, associationForeignKey)
4609 }
4610 }
4611 }
4612 <span class="cov8" title="1"> if len(associationForeignKeys) == 0 && len</span><span class="cov8" title="1">(foreignKeys) == 1 {
4613 associationForeignKeys = []string{scope.PrimaryKey()}
4614 </span> }
4615 } else if len(foreignKeys) != len(associationForeignKeys) {
4616 sc<span class="cov8" title="1">ope.Err(errors.New("invalid foreign keys, should have same length"))
4617 return
4618 </span> }
4619 }
4620
4621 for idx, foreignKey := range</span><span class="cov8" title="1"> foreignKeys {
4622 if foreignField := getForeignField(foreignKey, toFields); foreignField != nil {
4623 if associationField := getForeignField(associationForeignKeys[idx], modelStruct.StructFields); associationField != nil {
4624 // source foreign keys
4625 foreignField.IsForeignKey = true
4626 relationship.AssociationForeignFieldNames = append(relationship.AssociationForeignFieldNames, associationField.Name)
4627 relationship.AssociationForeignDBNames = append(relationship.AssociationForeignDBNames, associationField.DBName)
4628
4629 // association foreign keys
4630 relationship.ForeignFieldNames = append(relationship.ForeignFieldNames, foreignField.Name)
4631 relationship.ForeignDBNames = append(relationship.ForeignDBNames, foreignField.DBName)
4632 }
4633 }
4634</span> }
4635
4636</span> if len(relationship.ForeignFieldNames) != 0 {
4637 <span class="cov8" title="1"> field.Relationship = relationship
4638</span> }
4639 </span>}
4640</span> } else {
4641 </span>field.IsNormal = true
4642 }
4643 }<span class="cov8" title="1">(field)
4644</span> case reflect.Struct:
4645 defer func(field *StructField) {
4646 var (
4647</span> // user has one profile, associationType is User, profile use UserID as foreign key
4648 // user belongs to profile, associationType is Profile, user use ProfileID as foreign key
4649 associationType = reflectType.Name()
4650 relationship = &Relationship{}
4651 toScope = scope.New(reflect.New(field.Stru</span><span class="cov8" title="1">ct.Type).Interface())
4652 toFields = toScope.GetStructFields()
4653 ta</span>gFore<span class="cov8" title="1">ignKeys []string
4654 tagAssociationForeignKeys []string
4655 )
4656</span>
4657</span> if foreignKey, _ := field.TagSettingsGet("FOREIGNKEY"); foreignKey != "" {
4658 tagForeignKeys = strings.Split(foreignKey, ",")
4659 }
4660
4661 <span class="cov8" title="1">if foreignKey, _ := field.TagSettingsGet("ASSOCIATION_FOREIGNKEY"); foreignKey != "" {
4662 tagAssociationForeignKeys = strings.Split(foreignKey, ",")
4663 } else if foreignKey, _ := field.TagSettingsGet("ASSOCIATIONFOREIGNKEY"); foreignKey != "" {
4664 tagAssociationForeignKeys = strings.Split(foreignKey, ",")
4665 }
4666</span>
4667 if polymorphic, _ := field.TagSettings</span><span class="cov8" title="1">Get("POLYMORPHIC"); polymorphic != "" {
4668 // Cat has one toy, tag polymorphic is Owner, then associ</span><span class="cov8" title="1">ationType is Owner
4669 // Toy use OwnerID, OwnerType ('cats') as foreign key
4670 if polymorphicType := getForeignField(polymorphic+"Type", toFields); polymorphicType != nil {
4671 as</span>sociationType = polymorphic
4672 relati<span class="cov0" title="0">onship.PolymorphicType = polymorphicType.Name
4673 relationship.PolymorphicDBName = polymorphicType.DBName
4674 // if Cat has several different types of toys set name for each (</span><span class="cov0" title="0">instead of default 'cats')
4675 if value, ok := field.TagSettingsGet("POLYMORPHIC_VALUE"); ok {
4676</span> relationship.PolymorphicValue = value
4677 } else {
4678 re</span>lationship.PolymorphicValue = scope.TableName()
4679 }
4680 polymorphicType.IsForeignKey = true
4681 }
4682 }
4683
4684</span> // Has One
4685</span> {
4686</span> var foreignKeys = tagForeignKeys
4687 var associationForeignKeys = tagAssociationForeignKeys
4688</span> // if no foreign keys defined with tag
4689 if le</span>n(foreignKeys) == 0 {
4690 // if no association foreign keys defined with tag
4691 if len(associationForeignKeys) == 0 {
4692 <span class="cov8" title="1">for _, primaryField := range modelStruct.PrimaryFields {
4693</span> foreignKeys = append(foreignKeys, associationType+primaryField.Name)
4694 </span>associationForeignKeys = append(associationForeignKeys, primaryField.Name)
4695 }
4696</span> } else {
4697 // generate foreign keys form association foreign keys
4698 </span>for _, associationForeignKey := range tagAssociationForeignKeys {
4699 if foreignField := getForeignField(associationForeignKey, modelStruct.StructFields); foreignField != nil {
4700 foreignKeys = append(foreignKeys, associationType+foreignField.Name)
4701 <span class="cov8" title="1"> associationForeignKeys = append(assoc</span><span class="cov8" title="1">iationForeignKeys, foreignField.Name)
4702 }
4703</span> }
4704</span> }
4705 } else {
4706 // generate association foreign keys from foreign keys
4707 if len(associationForeignKeys) == 0 {
4708 for _, foreignKey := range foreignKeys {
4709 if strings.HasPrefix(foreignKey, associationType) {
4710 associationForeignKey := strings.TrimPrefix(foreignKey, associationType)
4711 if foreignField := getForeignField(associationForeignKey, modelStruct.StructFields); foreignField != nil {
4712 </span> associationForeignKeys = append(associationForeignKeys, associationForeignKey)
4713 }
4714 }
4715 }
4716 if len(associationForeignKeys) == 0 && len(foreignKeys) == 1 {
4717 <span class="cov8" title="1"> associationForeignKeys = []string{scope.</span><span class="cov8" title="1">PrimaryKey()}
4718 }
4719 } else if len(foreignKeys) != len(associationForeignKeys) {
4720 </span> sco<span class="cov8" title="1">pe.Err(errors.New("invalid foreign keys, should have same length"))
4721 return
4722 }
4723 }
4724
4725</span> for idx, foreignKey := range foreignKeys {
4726 if foreignField := getForeignField(f</span><span class="cov8" title="1">oreignKey, toFields); foreignField != nil {
4727 if scopeField := getForeignField(associationForeignKe</span><span class="cov8" title="1">ys[idx], modelStruct.StructFields); scopeField != nil {
4728 foreignField.IsForeignKey = true
4729 // source foreign keys
4730 </span>relationship.AssociationForeignFieldNames = append(relationship.AssociationForeignFieldNames, scopeField.Name)
4731 rela<span class="cov0" title="0">tionship.AssociationForeignDBNames = append(relationship.AssociationForeignDBNames, scopeField.DBName)
4732
4733 // association foreign keys
4734</span> relationship.ForeignFieldNames = append(relationship.ForeignFieldNames, foreignField.Name</span><span class="cov0" title="0">)
4735 relationship.ForeignDBNames = append(relationship.ForeignDBNames, foreignField.DBName)
4736 }
4737 }
4738</span> }
4739 }
4740
4741 if len(relationship.ForeignFieldNames) != 0 {
4742 relationship.Kind = "has_one"
4743</span> field.Relationship = relationship
4744</span> } else {
4745</span> var foreignKeys = tagForeignKeys
4746 var associationForeignKeys = tagAssociationForeignKeys
4747</span>
4748 if le</span>n(foreignKeys) == 0 {
4749 // generate foreign keys & association foreign keys
4750 if len(associationForeignKeys) == 0 {
4751 <span class="cov8" title="1">for _, primaryField := range toScope.PrimaryFields() {
4752</span> foreignKeys = append(foreignKeys, field.Name+primaryField.Name)
4753 </span>associationForeignKeys = append(associationForeignKeys, primaryField.Name)
4754 }
4755</span> } else {
4756 // generate foreign keys with association foreign keys
4757 </span>for _, associationForeignKey := range associationForeignKeys {
4758 if foreignField := getForeignField(associationForeignKey, toFields); foreignField != nil {
4759 foreignKeys = append(foreignKeys, field.Name+foreignField.Name)
4760 <span class="cov8" title="1"> associationForeignKeys = append(assoc</span><span class="cov8" title="1">iationForeignKeys, foreignField.Name)
4761 }
4762</span> }
4763</span> }
4764 } else {
4765 // generate foreign keys & association foreign keys
4766 if len(associationForeignKeys) == 0 {
4767 for _, foreignKey := range foreignKeys {
4768 if strings.HasPrefix(foreignKey, field.Name) {
4769 associationForeignKey := strings.TrimPrefix(foreignKey, field.Name)
4770 if foreignField := getForeignField(associationForeignKey, toFields); foreignField != nil {
4771 associationForeignKeys = append(associationForeignKeys, associationForeignKey)
4772 </span> }
4773 }
4774 }
4775 if len(associationForeignKeys) == 0 && len(foreignKeys) == 1 {
4776 <span class="cov8" title="1"> associationForeignKeys = []string{toScope</span><span class="cov8" title="1">.PrimaryKey()}
4777 }
4778 } else if len(foreignKeys) != len(associationForeignKeys) {
4779 </span> scope.Err(errors.New("invalid foreign keys, should have same length"))
4780 return
4781 }
4782 }
4783
4784</span> for idx, foreignKey := range foreignKeys {
4785 if foreignField := getForeignField(foreignKey, modelStruct.StructFields); foreignField != nil {
4786 if associationField := getForeignField(associationForeignKeys[idx], toFields); associationField != nil {
4787 foreignField.IsForeignKey = true
4788
4789 <span class="cov8" title="1"> // association foreign keys
4790</span> relationship.AssociationForeignFieldNames = append(relationship.AssociationForeignFieldNames, associationField.Name)
4791 </span> <span class="cov8" title="1"> relationship.AssociationForeignDBNames = append(relationship.AssociationForeignDBNames, associationField.DBName)
4792
4793 </span> // source foreign keys
4794 relationship.ForeignFieldNames = append(relationship.ForeignFieldNames, foreignField.Name)
4795 <span class="cov8" title="1"> relationship.ForeignDBNames = append(relationship.ForeignD</span>BNames, foreignField.DBName)
4796 }
4797 }
4798 }
4799
4800</span> if len(relationship.ForeignFieldNames) != 0 {
4801</span> relationship.Kind = "belongs_to"
4802 field.Relationship = relationship
4803 </span> }
4804 }
4805 }(field)
4806 <span class="cov8" title="1"> default:
4807 field.IsNormal = true
4808 }
4809</span> }
4810 }
4811
4812 // Even it is ignored, also possible to decode db value int<span class="cov8" title="1">o the field
4813 if value, ok := field.TagSettingsGet("COLUMN"); ok {
4814 </span> field.DBName = value
4815 } else {
4816 field.DBName = ToColumnName(fieldStruct.Name)
4817 }
4818
4819</span> modelStruct.StructFields = append(modelStruct.StructFields, field)
4820 }
4821</span> }
4822
4823 if len(modelStruc</span><span class="cov8" title="1">t.PrimaryFields) == 0 {
4824 if field := getForeignField("id", modelStruct.StructFields); field != nil {
4825 f</span>ield.<span class="cov8" title="1">IsPrimaryKey = true
4826 modelStruct.PrimaryFields = append(modelStruct.PrimaryFields, field)
4827 }
4828</span> }
4829
4830 <span class="cov8" title="1">modelStructsMa</span>p.Store(hashKey, &modelStruct)
4831
4832 return &modelStruct
4833}
4834
4835// GetStructFields get model's field structs
4836func (scope *Scope) GetStructFields() (fields []*StructField) {
4837 return scope.GetModelStruct().StructFields
4838}
4839
4840func parseTagSetting(tags reflect.StructTag) map[string]string {
4841 setting := map[string]string{}
4842 for _, str := range []string{tags.Get("sql"), tags.Get("gorm")} {
4843 if str == "" {
4844 continue
4845 }
4846 tags := strings.Split(str, ";")
4847 for _, value := range tags {
4848 v := strings.Split(value, ":")
4849 k := strings.TrimSpace(strings.ToUpper(v[0]))
4850 if len(v) >= 2 {
4851 setting[k] = strings.Join(v[1:], ":")
4852 } else {
4853 setting[k] = k
4854 }
4855 }
4856 }
4857 return setting
4858}
4859</pre>
4860
4861 <pre class="file" id="file22" style="display: none">package gorm
4862
4863import (
4864 "bytes"
4865 "database/sql"
4866 "database/sql/driver"
4867 "errors"
4868 "fmt"
4869 "reflect"
4870 "regexp"
4871 "strings"
4872 "time"
4873)
4874
4875// Scope contain current operation's information when you perform any operation on the database
4876type Scope struct {
4877 Search *search
4878 Value interface{}
4879 SQL string
4880 SQLVars []interface{}
4881 db *DB
4882 instanceID string
4883 primaryKeyField *Field
4884 skipLeft bool
4885 fields *[]*Field
4886 selectAttrs *[]string
4887}
4888
4889// IndirectValue return scope's reflect value's indirect value
4890func (scope *Scope) IndirectValue() reflect.Value <span class="cov8" title="1">{
4891 return indirect(reflect.ValueOf(scope.Value))
4892}</span>
4893
4894// New create a new Scope without search information
4895func (scope *Scope) New(value interface{}) *Scope <span class="cov8" title="1">{
4896 return &Scope{db: scope.NewDB(), Search: &search{}, Value: value}
4897}</span>
4898
4899////////////////////////////////////////////////////////////////////////////////
4900// Scope DB
4901////////////////////////////////////////////////////////////////////////////////
4902
4903// DB return scope's DB connection
4904func (scope *Scope) DB() *DB <span class="cov8" title="1">{
4905 return scope.db
4906}</span>
4907
4908// NewDB create a new DB without search information
4909func (scope *Scope) NewDB() *DB <span class="cov8" title="1">{
4910 if scope.db != nil </span><span class="cov8" title="1">{
4911 db := scope.db.clone()
4912 db.search = nil
4913 db.Value = nil
4914 return db
4915 }</span>
4916 <span class="cov0" title="0">return nil</span>
4917}
4918
4919// SQLDB return *sql.DB
4920func (scope *Scope) SQLDB() SQLCommon <span class="cov8" title="1">{
4921 return scope.db.db
4922}</span>
4923
4924// Dialect get dialect
4925func (scope *Scope) Dialect() Dialect <span class="cov8" title="1">{
4926 return scope.db.dialect
4927}</span>
4928
4929// Quote used to quote string to escape them for database
4930func (scope *Scope) Quote(str string) string <span class="cov8" title="1">{
4931 if strings.Contains(str, ".") {
4932</span> newStrs := []string{}
4933 for _, str := range strings.Split(str, ".") </span><span class="cov8" title="1">{
4934 newStrs = append(newStrs, scope.Dialect().Quote(str))
4935 }</span>
4936 <span class="cov8" title="1">return strings.Join(newStrs, ".")</span>
4937 }
4938
4939 <span class="cov8" title="1">return scope.Dialect().Quote(str)</span>
4940}
4941
4942// Err add error to Scope
4943func (scope *Scope) Err(err error) error <span class="cov8" title="1">{
4944 if err != nil </span><span class="cov8" title="1">{
4945 scope.db.AddError(err)
4946 }</span>
4947 <span class="cov8" title="1">return err</span>
4948}
4949
4950// HasError check if there are any error
4951func (scope *Scope) HasError() bool <span class="cov8" title="1">{
4952 return scope.db.Error != nil
4953}</span>
4954
4955// Log print log message
4956func (scope *Scope) Log(v ...interface{}) <span class="cov0" title="0">{
4957 scope.db.log(v...)
4958}</span>
4959
4960// SkipLeft skip remaining callbacks
4961func (scope *Scope) SkipLeft() <span class="cov0" title="0">{
4962 scope.skipLeft = true
4963}</span>
4964
4965// Fields get value's fields
4966func (scope *Scope) Fields() []*Field <span class="cov8" title="1">{
4967 if scope.fields == nil </span><span class="cov8" title="1">{
4968 var (
4969 fields []*Field
4970 indirectScopeValue = scope.IndirectValue()
4971 isStruct = indirectScopeValue.Kind() == reflect.Struct
4972 )
4973
4974 for _, structField := range scope.GetModelStruct().StructFields </span><span class="cov8" title="1">{
4975 if isStruct </span><span class="cov8" title="1">{
4976 fieldValue := indirectScopeValue
4977 for _, name := range structField.Names </span><span class="cov8" title="1">{
4978 if fieldValue.Kind() == reflect.Ptr && fieldValue.IsNil() </span><span class="cov8" title="1">{
4979 fieldValue.Set(reflect.New(fieldValue.Type().Elem()))
4980 }</span>
4981 <span class="cov8" title="1">fieldValue = reflect.Indirect(fieldValue).FieldByName(name)</span>
4982 }
4983 <span class="cov8" title="1">fields = append(fields, &Field{StructField: structField, Field: fieldValue, IsBlank: isBlank(fieldValue)})</span>
4984 } else<span class="cov8" title="1"> {
4985 fields = append(fields, &Field{StructField: structField, IsBlank: true})
4986 }</span>
4987 }
4988 <span class="cov8" title="1">scope.fields = &fields</span>
4989 }
4990
4991 <span class="cov8" title="1">return *scope.fields</span>
4992}
4993
4994// FieldByName find `gorm.Field` with field name or db name
4995func (scope *Scope) FieldByName(name string) (field *Field, ok bool) <span class="cov8" title="1">{
4996 var (
4997 dbName = ToColumnName(name)
4998 mostMatchedField *Field
4999 )
5000
5001 for _, field := range scope.Fields() </span><span class="cov8" title="1">{
5002 if field.Name == name || field.DBName == name </span><span class="cov8" title="1">{
5003 return field, true
5004 }</span>
5005 <span class="cov8" title="1">if field.DBName == dbName </span><span class="cov8" title="1">{
5006 mostMatchedField = field
5007 }</span>
5008 }
5009 <span class="cov8" title="1">return mostMatchedField, mostMatchedField != nil</span>
5010}
5011
5012// PrimaryFields return scope's primary fields
5013func (scope *Scope) PrimaryFields() (fields []*Field) <span class="cov8" title="1">{
5014 for _, field := range scope.Fields() </span><span class="cov8" title="1">{
5015 if field.IsPrimaryKey </span><span class="cov8" title="1">{
5016 fields = append(fields, field)
5017 }</span>
5018 }
5019 <span class="cov8" title="1">return fields</span>
5020}
5021
5022// PrimaryField return scope's main primary field, if defined more that one primary fields, will return the one having column name `id` or the first one
5023func (scope *Scope) PrimaryField() *Field <span class="cov8" title="1">{
5024 if primaryFields := scope.GetModelStruct().PrimaryFields; len(primaryFields) > 0 </span><span class="cov8" title="1">{
5025 if len(primaryFields) > 1 </span><span class="cov0" title="0">{
5026 if field, ok := scope.FieldByName("id"); ok </span><span class="cov0" title="0">{
5027 return field
5028 }</span>
5029 }
5030 <span class="cov8" title="1">return scope.PrimaryFields()[0]</span>
5031 }
5032 <span class="cov8" title="1">return nil</span>
5033}
5034
5035// PrimaryKey get main primary field's db name
5036func (scope *Scope) PrimaryKey() string <span class="cov8" title="1">{
5037 if field := scope.PrimaryField(); field != nil </span><span class="cov8" title="1">{
5038 return field.DBName
5039 }</span>
5040 <span class="cov8" title="1">return ""</span>
5041}
5042
5043// PrimaryKeyZero check main primary field's value is blank or not
5044func (scope *Scope) PrimaryKeyZero() bool <span class="cov8" title="1">{
5045 field := scope.PrimaryField()
5046 return field == nil || field.IsBlank
5047}</span>
5048
5049// PrimaryKeyValue get the primary key's value
5050func (scope *Scope) PrimaryKeyValue() interface{} <span class="cov8" title="1">{
5051 if field := scope.PrimaryField(); field != nil && field.Field.IsValid() </span><span class="cov8" title="1">{
5052 return field.Field.Interface()
5053 }</span>
5054 <span class="cov0" title="0">return 0</span>
5055}
5056
5057// HasColumn to check if has column
5058func (scope *Scope) HasColumn(column string) bool <span class="cov0" title="0">{
5059 for _, field := range scope.GetStructFields() </span><span class="cov0" title="0">{
5060 if field.IsNormal && (field.Name == column || field.DBName == column) </span><span class="cov0" title="0">{
5061 return true
5062 }</span>
5063 }
5064 <span class="cov0" title="0">return false</span>
5065}
5066
5067// SetColumn to set the column's value, column could be field or field's name/dbname
5068func (scope *Scope) SetColumn(column interface{}, value interface{}) error <span class="cov8" title="1">{
5069 var updateAttrs = map[string]interface{}{}
5070 if attrs, ok := scope.InstanceGet("gorm:update_attrs"); ok </span><span class="cov8" title="1">{
5071 updateAttrs = attrs.(map[string]interface{})
5072 defer scope.InstanceSet("gorm:update_attrs", updateAttrs)
5073 }</span>
5074
5075 <span class="cov8" title="1">if field, ok := column.(*Field); ok </span><span class="cov0" title="0">{
5076 updateAttrs[field.DBName] = value
5077 return field.Set(value)
5078 }</span> else<span class="cov8" title="1"> if name, ok := column.(string); ok </span><span class="cov8" title="1">{
5079 var (
5080 dbName = ToDBName(name)
5081 mostMatchedField *Field
5082 )
5083 for _, field := range scope.Fields() </span><span class="cov8" title="1">{
5084 if field.DBName == value </span><span class="cov0" title="0">{
5085 updateAttrs[field.DBName] = value
5086 return field.Set(value)
5087 }</span>
5088 <span class="cov8" title="1">if (field.DBName == dbName) || (field.Name == name && mostMatchedField == nil) </span><span class="cov8" title="1">{
5089 mostMatchedField = field
5090 }</span>
5091 }
5092
5093 <span class="cov8" title="1">if mostMatchedField != nil </span><span class="cov8" title="1">{
5094 updateAttrs[mostMatchedField.DBName] = value
5095 return mostMatchedField.Set(value)
5096 }</span>
5097 }
5098 <span class="cov8" title="1">return errors.New("could not convert column to field")</span>
5099}
5100
5101// CallMethod call scope value's method, if it is a slice, will call its element's method one by one
5102func (scope *Scope) CallMethod(methodName string) <span class="cov8" title="1">{
5103 if scope.Value == nil </span><span class="cov8" title="1">{
5104 return
5105 }</span>
5106
5107 <span class="cov8" title="1">if indirectScopeValue := scope.IndirectValue(); indirectScopeValue.Kind() == reflect.Slice </span><span class="cov8" title="1">{
5108 for i := 0; i < indirectScopeValue.Len(); i++ </span><span class="cov8" title="1">{
5109 scope.callMethod(methodName, indirectScopeValue.Index(i))
5110 }</span>
5111 } else<span class="cov8" title="1"> {
5112 scope.callMethod(methodName, indirectScopeValue)
5113 }</span>
5114}
5115
5116// AddToVars add value as sql's vars, used to prevent SQL injection
5117func (scope *Scope) AddToVars(value interface{}) string <span class="cov8" title="1">{
5118 _, skipBindVar := scope.InstanceGet("skip_bindvar")
5119
5120 if expr, ok := value.(*expr); ok </span><span class="cov8" title="1">{
5121 exp := expr.expr
5122 for _, arg := range expr.args </span><span class="cov8" title="1">{
5123 if skipBindVar </span><span class="cov0" title="0">{
5124 scope.AddToVars(arg)
5125 }</span> else<span class="cov8" title="1"> {
5126 exp = strings.Replace(exp, "?", scope.AddToVars(arg), 1)
5127 }</span>
5128 }
5129 <span class="cov8" title="1">return exp</span>
5130 }
5131
5132 <span class="cov8" title="1">scope.SQLVars = append(scope.SQLVars, value)
5133
5134 if skipBindVar </span><span class="cov8" title="1">{
5135 return "?"
5136 }</span>
5137 <span class="cov8" title="1">return scope.Dialect().BindVar(len(scope.SQLVars))</span>
5138}
5139
5140// SelectAttrs return selected attributes
5141func (scope *Scope) SelectAttrs() []string <span class="cov8" title="1">{
5142 if scope.selectAttrs == nil </span><span class="cov8" title="1">{
5143 attrs := []string{}
5144 for _, value := range scope.Search.selects </span><span class="cov8" title="1">{
5145 if str, ok := value.(string); ok </span><span class="cov8" title="1">{
5146 attrs = append(attrs, str)
5147 }</span> else<span class="cov8" title="1"> if strs, ok := value.([]string); ok </span><span class="cov0" title="0">{
5148 attrs = append(attrs, strs...)
5149 }</span> else<span class="cov8" title="1"> if strs, ok := value.([]interface{}); ok </span><span class="cov8" title="1">{
5150 for _, str := range strs </span><span class="cov8" title="1">{
5151 attrs = append(attrs, fmt.Sprintf("%v", str))
5152 }</span>
5153 }
5154 }
5155 <span class="cov8" title="1">scope.selectAttrs = &attrs</span>
5156 }
5157 <span class="cov8" title="1">return *scope.selectAttrs</span>
5158}
5159
5160// OmitAttrs return omitted attributes
5161func (scope *Scope) OmitAttrs() []string <span class="cov8" title="1">{
5162 return scope.Search.omits
5163}</span>
5164
5165type tabler interface {
5166 TableName() string
5167}
5168
5169type dbTabler interface {
5170 TableName(*DB) string
5171}
5172
5173// TableName return table name
5174func (scope *Scope) TableName() string <span class="cov8" title="1">{
5175 if scope.Search != nil && len(scope.Search.tableName) > 0 </span><span class="cov8" title="1">{
5176 return scope.Search.tableName
5177 }</span>
5178
5179 <span class="cov8" title="1">if tabler, ok := scope.Value.(tabler); ok </span><span class="cov8" title="1">{
5180 return tabler.TableName()
5181 }</span>
5182
5183 <span class="cov8" title="1">if tabler, ok := scope.Value.(dbTabler); ok </span><span class="cov0" title="0">{
5184 return tabler.TableName(scope.db)
5185 }</span>
5186
5187 <span class="cov8" title="1">return scope.GetModelStruct().TableName(scope.db.Model(scope.Value))</span>
5188}
5189
5190// QuotedTableName return quoted table name
5191func (scope *Scope) QuotedTableName() (name string) <span class="cov8" title="1">{
5192 if scope.Search != nil && len(scope.Search.tableName) > 0 </span><span class="cov8" title="1">{
5193 if strings.Contains(scope.Search.tableName, " ") {
5194</span> return scope.Search.tableName
5195 }</span>
5196 <span class="cov8" title="1">return scope.Quote(scope.Search.tableName)</span>
5197 }
5198
5199 <span class="cov8" title="1">return scope.Quote(scope.TableName())</span>
5200}
5201
5202// CombinedConditionSql return combined condition sql
5203func (scope *Scope) CombinedConditionSql() string <span class="cov8" title="1">{
5204 joinSQL := scope.joinsSQL()
5205 whereSQL := scope.whereSQL()
5206 if scope.Search.raw </span><span class="cov8" title="1">{
5207 whereSQL = strings.TrimSuffix(strings.TrimPrefix(whereSQL, "WHERE ("), ")")
5208 }</span>
5209 <span class="cov8" title="1">return joinSQL + whereSQL + scope.groupSQL() +
5210 scope.havingSQL() + scope.orderSQL() + scope.limitAndOffsetSQL()</span>
5211}
5212
5213// Raw set raw sql
5214func (scope *Scope) Raw(sql string) *Scope <span class="cov8" title="1">{
5215 scope.SQL = strings.Replace(sql, "$$$", "?", -1)
5216 return scope
5217}</span>
5218
5219// Exec perform generated SQL
5220func (scope *Scope) Exec() *Scope <span class="cov8" title="1">{
5221 defer scope.trace(NowFunc())
5222
5223 if !scope.HasError() </span><span class="cov8" title="1">{
5224 if result, err := scope.SQLDB().Exec(scope.SQL, scope.SQLVars...); scope.Err(err) == nil </span><span class="cov8" title="1">{
5225 if count, err := result.RowsAffected(); scope.Err(err) == nil </span><span class="cov8" title="1">{
5226 scope.db.RowsAffected = count
5227 }</span>
5228 }
5229 }
5230 <span class="cov8" title="1">return scope</span>
5231}
5232
5233// Set set value by name
5234func (scope *Scope) Set(name string, value interface{}) *Scope <span class="cov8" title="1">{
5235 scope.db.InstantSet(name, value)
5236 return scope
5237}</span>
5238
5239// Get get setting by name
5240func (scope *Scope) Get(name string) (interface{}, bool) <span class="cov8" title="1">{
5241 return scope.db.Get(name)
5242}</span>
5243
5244// InstanceID get InstanceID for scope
5245func (scope *Scope) InstanceID() string <span class="cov8" title="1">{
5246 if scope.instanceID == "" </span><span class="cov8" title="1">{
5247 scope.instanceID = fmt.Sprintf("%v%v", &scope, &scope.db)
5248 }</span>
5249 <span class="cov8" title="1">return scope.instanceID</span>
5250}
5251
5252// InstanceSet set instance setting for current operation, but not for operations in callbacks, like saving associations callback
5253func (scope *Scope) InstanceSet(name string, value interface{}) *Scope <span class="cov8" title="1">{
5254 return scope.Set(name+scope.InstanceID(), value)
5255}</span>
5256
5257// InstanceGet get instance setting from current operation
5258func (scope *Scope) InstanceGet(name string) (interface{}, bool) <span class="cov8" title="1">{
5259 return scope.Get(name + scope.InstanceID())
5260}</span>
5261
5262// Begin start a transaction
5263func (scope *Scope) Begin() *Scope <span class="cov8" title="1">{
5264 if db, ok := scope.SQLDB().(sqlDb); ok </span><span class="cov8" title="1">{
5265 if tx, err := db.Begin(); err == nil </span><span class="cov8" title="1">{
5266 scope.db.db = interface{}(tx).(SQLCommon)
5267 scope.InstanceSet("gorm:started_transaction", true)
5268 }</span>
5269 }
5270 <span class="cov8" title="1">return scope</span>
5271}
5272
5273// CommitOrRollback commit current transaction if no error happened, otherwise will rollback it
5274func (scope *Scope) CommitOrRollback() *Scope <span class="cov8" title="1">{
5275 if _, ok := scope.InstanceGet("gorm:started_transaction"); ok </span><span class="cov8" title="1">{
5276 if db, ok := scope.db.db.(sqlTx); ok </span><span class="cov8" title="1">{
5277 if scope.HasError() </span><span class="cov8" title="1">{
5278 db.Rollback()
5279 }</span> else<span class="cov8" title="1"> {
5280 scope.Err(db.Commit())
5281 }</span>
5282 <span class="cov8" title="1">scope.db.db = scope.db.parent.db</span>
5283 }
5284 }
5285 <span class="cov8" title="1">return scope</span>
5286}
5287
5288////////////////////////////////////////////////////////////////////////////////
5289// Private Methods For *gorm.Scope
5290////////////////////////////////////////////////////////////////////////////////
5291
5292func (scope *Scope) callMethod(methodName string, reflectValue reflect.Value) <span class="cov8" title="1">{
5293 // Only get address from non-pointer
5294 if reflectValue.CanAddr() && reflectValue.Kind() != reflect.Ptr </span><span class="cov8" title="1">{
5295 reflectValue = reflectValue.Addr()
5296 }</span>
5297
5298 <span class="cov8" title="1">if methodValue := reflectValue.MethodByName(methodName); methodValue.IsValid() </span><span class="cov8" title="1">{
5299 switch method := methodValue.Interface().(type) </span>{
5300 case func():<span class="cov8" title="1">
5301 method()</span>
5302 case func(*Scope):<span class="cov0" title="0">
5303 method(scope)</span>
5304 case func(*DB):<span class="cov8" title="1">
5305 newDB := scope.NewDB()
5306 method(newDB)
5307 scope.Err(newDB.Error)</span>
5308 case func() error:<span class="cov8" title="1">
5309 scope.Err(method())</span>
5310 case func(*Scope) error:<span class="cov0" title="0">
5311 scope.Err(method(scope))</span>
5312 case func(*DB) error:<span class="cov0" title="0">
5313 newDB := scope.NewDB()
5314 scope.Err(method(newDB))
5315 scope.Err(newDB.Error)</span>
5316 default:<span class="cov0" title="0">
5317 scope.Err(fmt.Errorf("unsupported function %v", methodName))</span>
5318 }
5319 }
5320}
5321
5322var (
5323 columnRegexp = regexp.MustCompile("^[a-zA-Z\\d]+(\\.[a-zA-Z\\d]+)*$") // only match string like `name`, `users.name`
5324 isNumberRegexp = regexp.MustCompile("^\\s*\\d+\\s*$") // match if string is number
5325 comparisonRegexp = regexp.MustCompile("(?i) (=|<>|(>|<)(=?)|LIKE|IS|IN) ")
5326 countingQueryRegexp = regexp.MustCompile("(?i)^count(.+)$")
5327)
5328
5329func (scope *Scope) quoteIfPossible(str string) string <span class="cov8" title="1">{
5330 if columnRegexp.MatchString(str) </span><span class="cov8" title="1">{
5331 return scope.Quote(str)
5332 }</span>
5333 <span class="cov8" title="1">return str</span>
5334}
5335
5336func (scope *Scope) scan(rows *sql.Rows, columns []string, fields []*Field) <span class="cov8" title="1">{
5337 var (
5338 ignored interface{}
5339 values = make([]interface{}, len(columns))
5340 selectFields []*Field
5341 selectedColumnsMap = map[string]int{}
5342 resetFields = map[int]*Field{}
5343 )
5344
5345 for index, column := range columns </span><span class="cov8" title="1">{
5346 values[index] = &ignored
5347
5348 selectFields = fields
5349 offset := 0
5350</span> if idx, ok := selectedColumnsMap[column]; ok {
5351 </span>offset = idx + 1
5352 selectFields = selectFields[offset:]
5353 <span class="cov8" title="1">}
5354</span>
5355</span> for fieldIndex, field := range selectFi</span><span class="cov8" title="1">elds {
5356 if field.DBName == column {
5357 i</span>f fie<span class="cov8" title="1">ld.Field.Kind() == reflect.Ptr {
5358 values[index] = field.Field.Addr().Interface()
5359 } else {
5360 reflectValue := reflect.New(reflect.PtrTo(field.Struct.Type))
5361 reflectValue.Elem().Set(field.Field.Addr())
5362 </span>values[index] = reflectValue.Interface()
5363 resetFields[index] = field
5364 <span class="cov8" title="1">}
5365
5366 selectedColumnsMap</span><span class="cov8" title="1">[column] = offset + fieldIndex
5367
5368</span> if field.IsNormal {
5369 break
5370 }
5371 }
5372 }
5373 <span class="cov8" title="1">}
5374
5375 scope.Err(rows.Scan(values...))
5376</span>
5377</span> for index, field := range resetFields {
5378 i</span>f v := reflect.ValueOf(values[index]).Elem().Elem(); v.IsValid() {
5379 field.Field.Set(v)
5380 }
5381 }
5382}
5383
5384f</span>unc (scope *Scope) primaryCondition(value interface{}) string {
5385 return fmt.Sprintf("(%v.%v = %v)", scope.QuotedTableName(), scope.Quote(scope.PrimaryKey()), value)
5386}
5387
5388func (scope *Scope) buildCondition(clause map[string]interface{}, include bool) (str string) {
5389 var (
5390 quotedTableName = scope.QuotedTableName()
5391 quotedPrimaryKey = scope.Quote(scope.PrimaryKey())
5392 equalSQL = "="
5393 inSQL = "IN"
5394 )
5395
5396</span> // If building not conditions
5397 if !include {
5398 </span>equalSQL = "<>"
5399 inSQL = "NOT IN"
5400 <span class="cov8" title="1">}
5401</span>
5402 switch value := clause["query"].(type) {
5403</span> case sql.NullInt64:
5404 return fmt.Sprintf("(%v.%v %s %v)", quotedTableName, quotedPrimaryKey, equalSQL, value.</span>Int64)
5405 case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
5406 return fmt.Sprintf("(%v.%v %s %v)", quotedTableNa</span><span class="cov8" title="1">me, quotedPrimaryKey, equalSQL, value)
5407 case []int, []int8, []int16, []int32, []int64, []uint, []uint8, []uint16, []uint32, []uint64, []string, []interface{}:
5408 i</span>f !include && reflect.ValueOf(value).Len() == 0 {
5409 <span class="cov8" title="1"> return
5410 }
5411</span> str = fmt.S<span class="cov8" title="1">printf("(%v.%v %s (?))", quotedTableName, quotedPrimaryKey, inSQL)
5412 clause["args"] = []interface{}{value}</span><span class="cov8" title="1">
5413 case string:
5414 i</span>f isNumberRegexp.MatchString(value) {
5415 return fmt.Sprintf("(%v.%v %s %v)", quotedTableName, quotedPrimaryKey, equalSQL, scope.AddToVars(value))
5416 <span class="cov8" title="1">}
5417</span>
5418</span> if value != "" {
5419</span> if !include {
5420 i</span>f com<span class="cov8" title="1">parisonRegexp.MatchString(value) {
5421 str = fmt.Sprintf("NOT (%v)", value)
5422 }</span> else {
5423 str <span class="cov8" title="1">= fmt.Sprintf("(%v.%v NOT IN (?))", quotedTableName, scope.Quote(value))
5424 }
5425 }</span> else {
5426 str = fmt.Sprintf("(%v)", value)
5427 }
5428 }
5429 case map[string]interface{}:
5430</span> var sqls []string</span><span class="cov8" title="1">
5431 for key, value := range value {
5432 i</span>f val<span class="cov8" title="1">ue != nil {
5433 sqls = appen</span><span class="cov8" title="1">d(sqls, fmt.Sprintf("(%v.%v %s %v)", quotedTableName, scope.Quote(key), equalSQL, scope.AddToVars(value)))
5434 } else {
5435 i</span>f !in<span class="cov8" title="1">clude {
5436 sqls = append(sqls, fmt.Sprintf("(%v.%v IS NOT NULL)", quotedTableName, scope.Quote(key)))
5437 }</span> else {
5438 sqls = append(sqls, fmt.Sprintf("(%v.%v IS NULL)", quotedTableName, scope.Quote(key)))
5439 }
5440 <span class="cov8" title="1"> }
5441</span> }
5442 return strings.Join(sqls, " AND ")
5443 case interface{}:
5444 var sqls []string
5445 newScope := scope.New(value)
5446</span>
5447 if len(newScope.Fields()) == 0 {
5448 </span>scope.Err(fmt.Errorf("invalid query condition: %v", value))
5449 return
5450 <span class="cov8" title="1">}
5451</span> scopeQuotedTableName := newScope.Quoted</span><span class="cov8" title="1">TableName()
5452 for _, field := range newScope.Fields() {
5453 i</span>f !field.IsIgnored && !field.IsBlank {
5454 sqls = append(sqls, fmt.Sprintf("(%v.%v %s %v)", scopeQuotedTableName, scope.Quote(field.DBName), equalSQL, scope.AddToVars(field.Field.Interface())))
5455 <span class="cov8" title="1"> }
5456</span> }
5457 return strings.Join(sqls, " AND ")
5458 default</span>:
5459 scope.Err(fmt.Errorf("invalid query condition: %v", value))
5460 return
5461 <span class="cov8" title="1">}
5462
5463 replacements := []string{</span><span class="cov8" title="1">}
5464 args := clause["args"].([]interface{})
5465 for _, arg := range args {
5466</span> var err error
5467 switch reflect.ValueOf(arg).Kind() {
5468</span> case reflect.Slice: // For where("id in (?)", []int64{1,2})
5469 if scanner, ok := interface{}(arg).(driver.Valuer); ok {
5470 </span>arg, <span class="cov8" title="1">err = scanner.Value()
5471</span> replacements = append(replacements, scope.AddToVars(arg))
5472 }</span> else<span class="cov8" title="1"> if b, ok := arg.([]byte); ok {
5473</span> replacements = append(replacements, scope.AddToVars(b))
5474 } else if as, ok := ar</span><span class="cov0" title="0">g.([][]interface{}); ok {
5475 var tempMarks []string
5476 for _, a := range as </span><span class="cov0" title="0">{
5477 var arrayMarks []string
5478 f</span>or _, v := range a {
5479 arrayMarks = append(arrayMarks, scope.AddToVars(v))
5480 <span class="cov0" title="0">}
5481</span>
5482 i</span>f len(arrayMarks) > 0 {
5483 tempMarks = append(tempMarks, fmt.Sprintf("(%v)", strings.Join(arrayMarks, ",")))
5484 }
5485 <span class="cov0" title="0">}
5486</span>
5487 i</span>f len(tempMarks) > 0 {
5488 repl<span class="cov8" title="1">acements = append(replacements, strings.Join(tempMark</span><span class="cov8" title="1">s, ","))
5489 }
5490 } else if values := reflect.ValueOf</span><span class="cov8" title="1">(arg); values.Len() > 0 {
5491 var tempMarks []string
5492 f</span>or i := 0; i < values.Len(); i++ {
5493 <span class="cov8" title="1"> tempMarks = append(tempMarks, scope.AddToVars(values.Index(i).In</span>terface()))
5494 }
5495 replacements = append(replacements, strings.Join(tempMarks, ","))
5496 }</span> else {
5497 replac<span class="cov8" title="1">ements = append(replacements, scope.AddToVars(Expr("NULL")))
5498 }
5499</span> default:
5500 i</span>f valuer, ok := interface{}(arg).(driver.Valuer); ok {
5501 arg, err = valuer.Value()
5502 <span class="cov8" title="1">}
5503</span>
5504 replacements = append(replacements, scope.AddToVars(arg))
5505 <span class="cov8" title="1">}
5506</span>
5507 i</span>f err != nil {
5508 scope.Err(err)
5509 }
5510 <span class="cov8" title="1">}
5511
5512 buff := bytes.NewBuffe</span><span class="cov8" title="1">r([]byte{})
5513 i := 0
5514</span> for _, s := range str {
5515 if s == '?' && len(replacements) > i {
5516 </span>buff.<span class="cov8" title="1">WriteString(replacements[i])
5517 i++
5518 }</span> else {
5519 buff.WriteRune(s)
5520 }
5521 <span class="cov8" title="1">}
5522
5523 str = </span>buff.String()
5524
5525 return
5526}
5527
5528</span>func (scope *<span class="cov8" title="1">Scope) buildSelectQuery(clause map[string]interface{}) (str string) {
5529 switch value</span> := clause["query"].(type) {
5530 case string:
5531 str = value
5532</span> case []string:
5533 str = strings.Join(value, ", ")
5534 <span class="cov8" title="1">}
5535
5536 args := clause["args"].([</span><span class="cov8" title="1">]interface{})
5537 replacements := []string{}
5538</span> for _, arg := range <span class="cov0" title="0">args {
5539 switch reflect.ValueOf(arg).Kind() {
5540 case reflect.Slice:
5541 values := reflect.ValueOf(arg)
5542</span> var tempMarks []string
5543 f</span>or i := 0; i < values.Len(); i++ {
5544 <span class="cov0" title="0"> tempMarks = append(tempMarks, scope.AddToVars(values.Index(i).In</span>terface()))
5545 }
5546 replacements = append(replacements, strings.Join(tempM</span><span class="cov0" title="0">arks, ","))
5547 default:
5548 i</span>f valuer, ok := interface{}(arg).(driver.Valuer); ok {
5549 <span class="cov8" title="1"> arg, _ = valuer.Value()
5550</span> }
5551 replacements = append(replacements, scope.AddToVars(arg))
5552 }
5553 <span class="cov8" title="1">}
5554
5555 buff := bytes.NewBuff</span><span class="cov8" title="1">er([]byte{})
5556 i := 0
5557</span> for pos, char := range str {
5558 if str[pos] == '?' {
5559 </span>buff.<span class="cov8" title="1">WriteString(replacements[i])
5560 i++
5561 }</span> else {
5562 buff.WriteRune(char)
5563 }
5564 <span class="cov8" title="1">}
5565
5566 str = </span>buff.String()
5567
5568 return
5569}
5570
5571func (scope *Scope) whereSQL() (sql string) {
5572 var (
5573 quotedTableName = scope.QuotedTableName()
5574 deletedAtField, hasDeletedAtField = scope.FieldByName("DeletedAt")
5575 primaryConditions, andConditions, orConditions []string
5576 )
5577</span>
5578 if !scope.Search.Unscoped && hasDeletedAtField {
5579 </span>sql := fmt.Sprintf("%v.%v IS NULL", quotedTableName, scope.Quote(deletedAtField.DBName))
5580 primaryConditions = append(primaryConditions, sql)
5581 <span class="cov8" title="1">}
5582</span>
5583</span> if !scope.PrimaryKeyZero() {
5584 for _, field := range scope.PrimaryFields() {
5585 </span>sql := fmt.Sprintf("%v.%v = %v", quotedTableName, scope.Quote(field.DBName), scope.AddToVars(field.Field.Interface()))
5586 primaryConditions = append(primaryConditions, sql)
5587 }
5588 <span class="cov8" title="1">}
5589</span>
5590</span> for _, clause := range scope.Search.whereConditions {
5591 i</span>f sql := scope.buildCondition(clause, true); sql != "" {
5592 andConditions = append(andConditions, sql)
5593 }
5594 <span class="cov8" title="1">}
5595</span>
5596</span> for _, clause := range scope.Search.orConditions {
5597 i</span>f sql := scope.buildCondition(clause, true); sql != "" {
5598 orConditions = append(orConditions, sql)
5599 }
5600 <span class="cov8" title="1">}
5601</span>
5602</span> for _, clause := range scope.Search.notConditions {
5603 i</span>f sql := scope.buildCondition(clause, false); sql != "" {
5604 andConditions = append(andConditions, sql)
5605 }
5606 <span class="cov8" title="1">}
5607
5608 orSQL := strings.Join(or</span><span class="cov8" title="1">Conditions, " OR ")
5609 combinedSQL := stri</span><span class="cov8" title="1">ngs.Join(andConditions, " AND ")
5610 if len(combinedSQL) > 0 {
5611 i</span>f len(orSQL) > 0 {
5612 comb<span class="cov8" title="1">inedSQL = combinedSQL + " OR " + orSQL
5613 }
5614 }</span> else {
5615 combinedSQL = orSQL
5616 <span class="cov8" title="1">}
5617</span>
5618 if len(primaryConditions)</span><span class="cov8" title="1"> > 0 {
5619 sql = "WHERE " + strings.Join(primaryConditions, " AND ")
5620 i</span>f len(combinedSQL) > 0 {
5621 sql <span class="cov8" title="1">= sql + " AND (" + combin</span><span class="cov8" title="1">edSQL + ")"
5622 }
5623 }</span> else if len(combinedSQL) > 0 {
5624 <span class="cov8" title="1"> sql =</span> "WHERE " + combinedSQL
5625 }
5626 return
5627}
5628
5629</span>func (scope *Scope) selectSQL() string {
5630</span> if len(scope.Search.selects) == 0 {
5631 i</span>f len(scope.Search.joinConditions) > 0 {
5632 <span class="cov8" title="1"> return fm</span>t.Sprintf("%v.*", scope.QuotedTableName())
5633 }
5634 <span class="cov8" title="1"> return "*"
5635</span> }
5636 return scope.buildSelectQuery(scope.Search.selects)
5637}
5638
5639</span>func (scope *Scope) orderSQL() string {
5640 i</span>f len(scope.Search.orders) == 0 || scope.Search.ignoreOrderQuery {
5641 return ""
5642 <span class="cov8" title="1">}
5643
5644</span> var orders []string
5645</span> for _, order := range scope.Search.orders {
5646 i</span>f str<span class="cov8" title="1">, ok := order.(string); ok {
5647</span> orders = append(orders, scope.quoteIfPossible(str))
5648 } else if expr, ok := order.(*e</span><span class="cov8" title="1">xpr); ok {
5649 exp := expr.expr
5650 f</span>or _, arg := range expr.args {
5651 <span class="cov8" title="1"> exp = strings.Replace(exp, </span>"?", scope.AddToVars(arg), 1)
5652 }
5653 orders = append(orders, exp)
5654 <span class="cov8" title="1"> }
5655</span> }
5656 return " ORDER BY " + strings.Join(orders, ",")
5657}
5658
5659f</span>unc (scope *Scope) limitAndOffsetSQL() string {
5660 return scope.Dialect().LimitAndOffsetSQL(scope.Search.limit, scope.Search.offset)
5661}
5662
5663</span>func (scope *Scope) groupSQL() string {
5664 i</span>f len(scope.Search.group) == 0 {
5665 <span class="cov8" title="1"> return ""
5666</span> }
5667 return " GROUP BY " + scope.Search.group
5668}
5669
5670</span>func (scope *Scope) havingSQL() string {
5671 i</span>f len(scope.Search.havingConditions) == 0 {
5672 return ""
5673 <span class="cov8" title="1">}
5674
5675</span> var andConditions []string
5676</span> for _, clause := range scope.Search.havingConditions {
5677 i</span>f sql := scope.buildCondition(clause, true); sql != "" {
5678 andConditions = append(andConditions, sql)
5679 }
5680 <span class="cov8" title="1">}
5681
5682</span> combinedSQL := strings.Join(andConditions, " AND ")
5683 i</span>f len(combinedSQL) == 0 {
5684 return ""
5685 <span class="cov8" title="1">}
5686</span>
5687 return " HAVING " + combinedSQL
5688}
5689
5690func (scope *Scope) joinsSQL() string {
5691</span> var joinConditions []string
5692</span> for _, clause := range scope.Search.joinConditions {
5693 i</span>f sql := scope.buildCondition(clause, true); sql != "" {
5694 joinConditions = append(joinConditions, strings.TrimSuffix(strings.TrimPrefix(sql, "("), ")"))
5695 }
5696 <span class="cov8" title="1">}
5697</span>
5698 return strings.Join(joinConditions, " ") + " "
5699}
5700
5701</span>func (scope *Scope) prepareQuerySQL() {
5702 i</span>f sco<span class="cov8" title="1">pe.Search.raw {
5703 scope.Raw(scope.CombinedConditionSql())
5704 }</span> else {
5705 <span class="cov8" title="1"> scope</span>.Raw(fmt.Sprintf("SELECT %v FROM %v %v", scope.selectSQL(), scope.QuotedTableName(), scope.CombinedConditionSql()))
5706 }
5707 return
5708}
5709
5710</span>func (scope *Scope) inlineCondition(values ...interface{}) *Scope {
5711 i</span>f len(values) > 0 {
5712 <span class="cov8" title="1"> scope.Searc</span>h.Where(values[0], values[1:]...)
5713 }
5714 return scope
5715}
5716
5717</span>func (scope *Scope) callCallbacks(funcs []*func(s *Scope)) *Scope {
5718 defer func() {
5719</span> if err</span> := recover(); err != nil {
5720 if db, ok := scope.db.db.(sqlTx); ok {
5721 db.Rollback()
5722 <span class="cov8" title="1"> }
5723</span> panic(err)
5724 }
5725 }()
5726 for _, f := range funcs {
5727 (*f)(scope)
5728 if scope.skipLeft {
5729</span> break
5730 }
5731</span> }
5732 return scope
5733</span>}
5734</span>
5735func</span> convertInterfaceToMap(values interface{}, withIgnoredField bool) map[string]interface{} {
5736 var attrs = map[string]interface{}{}
5737
5738 switch value := values.(type) {
5739 case map[string]interface{}:
5740 return value
5741</span> case []interface{}<span class="cov0" title="0">:
5742 for _, v := range value {
5743</span> for key, value := range convertInterfaceToMap(v, withIgnoredField) {
5744 </span>attrs[key] = value
5745 }
5746 }
5747</span> case interface{}:
5748</span> reflectValue := reflect.ValueOf(values)
5749
5750</span> switch reflectValue.Kind() {
5751 case reflect.Map:
5752 for _, key := range reflectValue.MapKeys() {
5753 <span class="cov8" title="1"> attrs[ToC</span>olumnName(key.Interface().(string))] = reflectValue.MapIndex(key).Interface()
5754 }
5755 default:
5756 for _, field := range (&Scope{Value: values}).Fields() {
5757 if !field.IsBlank && (withIgnoredField || !fiel</span><span class="cov8" title="1">d.IsIgnored) {
5758 attrs[field.DBName] = field.Field.Interface()
5759 </span> }
5760 }
5761 <span class="cov8" title="1"> }
5762 }
5763 return attrs
5764</span>}
5765</span>
5766</span>func (scope *Scope) updatedAttrsWithValues(value interface{}) (results map[string]interface{}, hasUpdate bool) {
5767 if scope.IndirectValue().Kind() != reflect.Struct {
5768 re</span>turn <span class="cov8" title="1">convertInterfaceToMap(value, false), true
5769 }
5770
5771</span> results = map[string]interface{}{}
5772
5773</span> for key, value := range convertInterfaceToMap(value, true) {
5774 if f</span>ield,<span class="cov8" title="1"> ok := scope.FieldByName(key); ok && scope.changeableField(field) {
5775 if _, ok := value.(*expr); ok {
5776 ha</span>sUpdate = true
5777 results[field.DBName] = value
5778 } else {
5779 err := field.Set(value)
5780 if field.IsNormal && !field.IsIgnored {
5781 <span class="cov8" title="1"> ha</span>sUpdate = true
5782 if err == ErrUnaddressable {
5783 results[field.DBName] = value
5784 } else {
5785 results[field.DBName] = field.Field.Interface()
5786 }
5787 }
5788 }
5789 }
5790 }
5791 return
5792}</span>
5793
5794func (scope *Scope) row() *sql.Row {
5795 defer scope.trace(NowFunc())
5796
5797 result := &RowQueryResult{}
5798 scope.InstanceSet("row_query_result", result)
5799 scope.callCallbacks(scope.db.parent.callbacks.rowQueries)
5800
5801 return result.Row
5802}</span>
5803
5804func (scope *Scope) rows() (*sql.Rows, e<span class="cov8" title="1">rror) {
5805 defer scope.trace(NowFunc())
5806</span>
5807 r</span>esult := &RowsQueryResult{}
5808 <span class="cov8" title="1">scope.InstanceSet("row_query_result", result)
5809 scope.callCallbacks(scope.db.parent.callbacks.rowQueries)
5810
5811</span> return result.Rows, result.Error
5812}
5813
5814func (scope *Scope) initialize() *Scope {
5815 for _, clause := range</span><span class="cov0" title="0"> scope.Search.whereConditions {
5816 scope.updatedAttrsWithValues(clause["query"])
5817 }</span>
5818 scope.updatedAttrsWithValues(scope.Search.initAttrs)
5819 <span class="cov8" title="1">scope.updatedAttrsWithValues(scope.Search.ass</span><span class="cov8" title="1">ignAttrs)
5820 return scope
5821}
5822</span>
5823f<span class="cov8" title="1">unc (scope *Scope) isQueryForColumn(query interface{}, col</span><span class="cov8" title="1">umn string) bool {
5824 queryStr := strings.ToLower(fmt.Sprint(query))
5825 i</span>f queryStr == column {
5826 return true
5827 <span class="cov0" title="0">}
5828</span>
5829 if strings.HasSuffix(queryStr, "as "+column) {
5830 return true
5831 }
5832
5833</span> if strings.HasSuffix(queryStr, "as "+scope.Quote(column)) {
5834 return true
5835 }</span>
5836
5837 <span class="cov8" title="1">return false
5838</span>}
5839
5840</span>func (scope *Scope) pluck(column string, value interface{}) *Scope {
5841 <span class="cov8" title="1">dest := reflect.Indirect(reflect.ValueOf(value))
5842 if dest.Kind() != reflect</span><span class="cov8" title="1">.Slice {
5843 scope.Err(fmt.Errorf("results should be a slice, not %s", dest.Kind()))
5844 return scope
5845</span> }
5846
5847 if query, ok := scope.Search.selects["query"]; !ok || !scope.isQueryForColumn(query, column) {
5848 s</span>cope.Search.Select(column)
5849 }
5850
5851</span> rows, err := scope.rows()
5852 if</span> scope.Err(err) == nil {
5853 defer rows.Close()
5854 <span class="cov8" title="1"> for rows.Ne</span>xt() {
5855 elem := reflect.New(dest.Type().Elem()).Interface()
5856 scope.Err(rows.Scan(elem))
5857 dest.Set(reflect.Append(dest, reflect.ValueOf(ele<span class="cov8" title="1">m).Elem()))
5858 }
5859</span>
5860</span> if err := rows.Err(); err != nil {
5861 scope.Err(err)
5862 }</span>
5863 }
5864 re</span>turn scope
5865}
5866
5867func (scope *Scope) count(value interface{}) *Scope {
5868 if query, ok</span> := scope.Search.selects["query"]; !ok || !countingQueryRegexp.MatchString(fmt.Sprint(query)) {
5869 if len(scope.Search.group) != 0 {
5870 if len(scope.Search.havingConditions) != 0 {
5871 scope.prepareQuerySQL()
5872 scope.Search = &search{}
5873 scope.Search.Select("count(*)")
5874 scope.Search.Table(fmt.Sprintf("( %s ) AS count_table", sc</span><span class="cov8" title="1">ope.SQL))
5875 } else {
5876 </span> scope.Search.Select("count(*) FROM ( SELECT count(*) as name ")
5877 scope.Search.group += " ) AS count_table"
5878 <span class="cov8" title="1"> }
5879</span> } else {
5880 scope.Search.Select("count(*)")
5881 }
5882 }
5883 scope.Search.ignoreOrd</span><span class="cov8" title="1">erQuery = true
5884 scope.Err(scope.row().Scan(value))
5885 r</span>eturn scope
5886}
5887
5888func (scope *Scope) typeName() string {
5889 typ := scope.IndirectValue().Type()
5890</span>
5891</span> for typ.Kind() == reflect.Slice || typ.Kind() ==</span><span class="cov8" title="1"> reflect.Ptr {
5892 typ = typ.Elem()
5893 }
5894</span>
5895 r<span class="cov8" title="1">eturn typ.Na</span>me()
5896}
5897
5898/<span class="cov8" title="1">/ trace print sql log
5899</span>func (scope *Scope) trace(t time.Time) {
5900</span> if len(scope.SQL) > 0 {
5901 s</span>cope.db.slog(scope.SQL, t, scope.SQLVars...)
5902 }
5903}
5904
5905</span>func (scope *Scope) changeableField(field *Field) bool {
5906 if selectAttrs := scope.SelectAttrs(); len(selectAttrs) > 0 {
5907 for _, attr := range selectAttrs {
5908 if field.Name == attr || field.DBName == attr {
5909 return true
5910 }
5911 }
5912</span> return false
5913 }
5914
5915 for _, attr := range </span><span class="cov8" title="1">scope.OmitAttrs() {
5916 if field.Name == attr || field.DBName == attr {
5917</span> return false
5918</span> }
5919 }
5920
5921</span></span> return true
5922</span>}
5923</span>
5924func (s</span>cope *Scope) related(value interface{}, foreignKeys ...string) *Scope {
5925 toScope := scope.db.NewScope(value)
5926 tx :<span class="cov8" title="1">= scope.db.Set("gorm:associatio</span>n:source", scope.Value)
5927
5928</span> for _, foreignKey := range append(foreignKeys, toScope.typeNa</span><span class="cov8" title="1">me()+"Id", scope.typeName()+"Id") {
5929 fromField, _ := scope.FieldByName(foreignKey)
5930</span> toField, _ := toScope.FieldByName(foreignKey)
5931
5932</span> if fromField != nil {
5933 if relationship := fromField.Relationship; relationship != nil {
5934 i<span class="cov8" title="1">f relationship.Kind == "many_to_many" </span><span class="cov8" title="1">{
5935 joinTableHandler := relationship.JoinTableHandler
5936 s</span>cope.Err(joinTableHandler.JoinWith(joinTableHandler, tx, scope.Value).Find(value).Error)
5937 }<span class="cov8" title="1"> else if relationship.Kind == "</span>belongs_to" {
5938 for idx, foreignKey := range relationship.ForeignDBNames {
5939 if <span class="cov8" title="1">field, ok := scope.FieldByName(foreignKey); ok {
5940 tx = tx.Where(fmt.Sprintf("%v = ?", scope.Quote(relationship.AssociationForeignDBNames[idx])), field.Field.Interface())
5941 }
5942 </span> }
5943 <span class="cov8" title="1"> scope.Err(</span>tx.Find(value).Error)
5944 } el<span class="cov8" title="1">se if relationship.</span><span class="cov8" title="1">Kind == "has_many" || relationship.Kind == "has_one" {
5945 for idx, foreignKey := range relationship.ForeignDBNames {
5946 if field, ok := scope.FieldByName(relationship.AssociationForeignDBNames[idx]); ok {
5947 tx = tx.Where(fmt.Sprintf("%v = ?", scope.Quote(foreignKey)), field.Field.Interface())
5948 </span> }
5949 }
5950
5951 <span class="cov0" title="0"> if relationship.PolymorphicType != "" {
5952 tx = tx</span>.Where(fmt.Sprintf("%v = ?", scope.Quote(relationship.PolymorphicDBName)), relationship.PolymorphicValue)
5953 }
5954 scope.Err(tx.Find(value).Error)
5955 }
5956 } else {
5957 sql := fmt.Sprintf("%v = ?", scope.Quote(toScope.PrimaryKey()))
5958 scop</span><span class="cov8" title="1">e.Err(tx.Where(sql, fromField.Field.Interface()).Find(value).Error)
5959 }
5960 </span> return scope
5961 <span class="cov0" title="0"> } else if toField != nil {
5962</span> sql := fmt.Sprintf("%v = ?", scope.Quote(toField.DBName))
5963 scope.Err(tx.Where(sql, scope.PrimaryKeyValue()).Find(value).Error)
5964 return scope
5965 }
5966</span> }
5967
5968 scope.Err(fmt.Errorf("invalid association</span><span class="cov8" title="1"> %v", foreignKeys))
5969 return scope
5970}
5971
5972// getTableOptions return the table options string or an empty</span><span class="cov8" title="1"> string if the table options does not exist
5973func (scope *Scope) getTableOptions() string {
5974</span> tableOptions, ok := scope.Get("gorm:table_options")
5975 if !ok {
5976 return ""
5977 }
5978 return " " + tableOptions.(string)
5979}
5980
5981</span>func (scope *Scope) createJoinTable(field *StructField) {
5982 if relationship := field.Relationship; relationship != nil && relationship.JoinTableHandler != nil {
5983 j<span class="cov8" title="1">oinTableHandler := relationship.JoinTableHandler
5984</span> joinTable := joinTableHandler.Table(scope.db)
5985</span> if !scope.Dialect().HasTable(joinTable) {
5986 toScope := &Scope{Value: reflect.New(field.Struct.Type).Interface()}
5987
5988 var sqlTypes, primaryKeys []string
5989 for idx, fieldName := range relationship.ForeignFieldNames {
5990 if field, ok := scope.FieldByName(fieldName); ok {
5991 </span>foreignKeyStruct := field.clone()
5992 foreignKeyStruct.IsPrimaryKey = false
5993 foreignKeyStruct.TagSettingsSet("IS_JOINTABLE_FOREIGNKEY", "true")
5994 <span class="cov8" title="1"> foreignKeyStruct.TagSettingsDelete("AUTO_INCREMENT")
5995</span> sqlTypes = append(sqlTypes, scope.Quote(relationship.ForeignDBNames[idx])+" "+scope.Dialect().DataTypeOf(foreignKeyStruct))
5996 <span class="cov8" title="1"> primaryKeys = append(primaryKeys, scope.Quote(relationshi</span>p.ForeignDBNames[idx]))
5997 }
5998 }
5999
6000 for idx, fieldName := range relationsh<span class="cov8" title="1">ip.AssociationForeignFieldNames {
6001 if field, ok := toScope.FieldByName(fieldName); ok {
6002 foreignKeyStruct := field.clone()
6003 foreignKeyStruct.IsPrimaryKey = false
6004 foreignKeyStruct.TagSettingsSet("IS_JOINTABLE_FOREIGNK</span><span class="cov8" title="1">EY", "true")
6005 foreignKeyStruc</span><span class="cov8" title="1">t.TagSettingsDelete("AUTO_INCREMENT")
6006 sqlTypes = append(sqlTypes, scope.Quote(relationship.AssociationForeignDBNames[idx])+" "+scope.Dialect().DataTypeOf(foreignKeyStruct))
6007 primaryKeys = append(primaryKeys, scope.Quote(relationship.AssociationForeignDBNames[idx]))
6008 }
6009 }
6010
6011 scope.Err(scope.NewDB().Exec(fmt.Sprintf("CREATE TABLE %v (%</span><span class="cov8" title="1">v, PRIMARY KEY (%v))%s", scope.Quote(joinTable), strings.Join(sqlTypes, ","), strings.Join(primaryKeys, ","), scope.getTableOptions())).Error)
6012 }
6013 sc</span>ope.NewDB().Table(joinTable).AutoMigrate(joinTableHandler)
6014 }
6015}
6016</span>
6017func (scope *Scope) createTable() *Scope {
6018 v<span class="cov8" title="1">ar tags []string
6019</span> var primaryKeys []string
6020 va</span>r primaryKeyInColumnType = false
6021 f<span class="cov8" title="1">or _, field := range scope.G</span>etModelStruct().StructFields {
6022 if field.IsNormal {
6023 sqlTag := scope.Dialect().DataTypeOf(field)
6024
6025 // Check if the primary key constraint was specif</span><span class="cov8" title="1">ied as
6026 // part of the column type. If so, we can only support
6027 </span> // one column as the primary key.
6028 if strings.Contains(strings.ToLower(sqlTag), "primary key") {
6029 <span class="cov8" title="1"> primaryKeyInColumnType = true
6030 }
6031
6032 tags = app</span>end(tags, scope.Quote(field.DBName)+" "+sqlTag)
6033 }
6034
6035 if field.IsPrimaryKey {
6036 primaryKeys = append(primaryKeys, scope.Quote(field.DBName))
6037 }
6038 </span> scope.createJoinTable(field)
6039 }
6040
6041 var primaryKeyStr string
6042 </span>if len(primaryKeys) > 0 && !primaryKeyInColumnType {
6043 primaryKeyStr = fmt.Sprintf(", PRIMARY KEY (%v)", strings.Join(primaryKeys, ","))
6044 }
6045
6046 </span>scope.Raw(fmt.Sprintf("CREATE TABLE %v (%v %v)%s", scope.QuotedTableName(), strings.Join(tags, ","), primaryKeyStr, scope.getTableOptions())).Exec()
6047
6048 scope.autoIndex()
6049 return scope
6050</span>}
6051
6052</span>func (scope *Scope) dropTable() *Scope {
6053 <span class="cov8" title="1">scope.Raw(fmt.Sprintf("DROP TABLE %v%s", scope.QuotedTableName(), scope.getTableOptions())).Exec()
6054 return scope
6055</span>}
6056
6057</span>func (scope *Scope) modifyColumn(column string, typ string) {
6058 <span class="cov8" title="1">scope.db.AddError(scope.Dialect().ModifyColumn(scope.QuotedTableName(), scope.Quote(column), typ))
6059}
6060</span>
6061fu</span>nc (scope *Scope) dropColumn(column string) {
6062 scope.Raw(fmt.Sprintf("ALTER TABLE %v DROP COLUMN %v", scope.QuotedTableName(), scope.Quote(column))).Exec()
6063}<span class="cov8" title="1">
6064</span>
6065func (scope *Scope) addIndex(unique bool, indexName string, column ...string) {
6066 if scope.Dialect().HasIndex(scope.TableName(), indexName) {
6067 return
6068 }
6069
6070 var columns []string
6071</span> for _, name := range column {
6072 </span>columns = append(columns, scope.quoteIfPossible(name))
6073 <span class="cov0" title="0">}
6074
6075</span> sqlCreate := "CREATE INDEX"
6076 if unique {
6077 sqlCreate = "CREATE UNIQUE INDEX"
6078 }
6079
6080 scope.Raw(fmt.Sprintf("%s %v ON %v(%v) %v", sqlCreate, indexNa</span><span class="cov0" title="0">me, scope.QuotedTableName(), strings.Join(columns, ", "), scope.whereSQL())).Exec()
6081}
6082
6083</span>f<span class="cov0" title="0">unc (scope *Scope) addForeignKey(field string, dest string, onDelete string, onUpdate string) {
6084 // Compatible with old generated key
6085</span> keyName := scope.Dialect().BuildKeyName(scope.TableName(), field, dest, "foreign")
6086
6087 if scope.Dialect().HasForeignKey(scope.TableName(<span class="cov8" title="1">), keyName) {
6088 return
6089 </span>}
6090 var query = `ALTER TABLE %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s ON DELETE %s ON UPDATE %s;`
6091 scope.Raw(fmt.Sprintf(query, scope.Quote<span class="cov8" title="1">dTableName(), scope.quoteIfPossible(keyName), scope.quoteIfPossible(field), dest, onDelete, onUpdate)).Exec()
6092}
6093
6094func (scope *Scope) removeForeignKey(field string, dest string) {
6095 keyName := scope.Dialect().BuildKeyName(</span><span class="cov8" title="1">scope.TableName(), field, dest, "foreign")
6096 if !scope.Dialect().HasForeignKey(scope.TableName(), keyName) {
6097 </span>retur<span class="cov8" title="1">n
6098 }
6099</span> var mysql mysql
6100</span> var query string
6101</span> if scope.Dialect().GetName() == mysql.GetName() {
6102 query = `ALTER TABLE %s DROP FOREIGN KEY %s;`
6103 } el</span>se {
6104 query = `ALTER TABLE %s DROP CONSTRAINT %s;`
6105 }
6106</span>
6107 s<span class="cov8" title="1">cope.Raw(fmt.Spri</span>ntf(query, scope.QuotedTableName(), scope.quoteIfPossible(keyName))).Exec()
6108}
6109
6110</span>func (scope *Scope) removeIndex(indexName string) {
6111 scope.Dialect().RemoveIndex(scope.TableName(), indexName)
6112}
6113
6114func (scope *Scope) autoMigrate() *Scope {
6115 tableName := scope.TableName()
6116 quotedTableName := scope.QuotedTableName()
6117</span>
6118</span> if !scope.Dialect().HasTable(tableName) {
6119 scope.createTable()
6120 } else {
6121</span> for _, field := range scope.GetMode</span><span class="cov8" title="1">lStruct().StructFields {
6122 if !scope.Dialect().HasColumn(tableName, field.DBName) {
6123 i</span>f field.IsNormal {
6124 <span class="cov8" title="1"> sqlTag := scope.Dialect().DataTypeOf(field)
6125</span> scope.Raw(fmt.Sprintf("ALTER TABLE %v ADD %v %v;", quotedTableName, scope.Quote(field.DBName), sqlTag)).Exec()
6126 }
6127 }
6128 <span class="cov8" title="1"> scope.createJoinTable(field)
6129</span> }
6130 scope.autoIndex()
6131 }
6132</span> return scope
6133</span>}
6134
6135</span>func<span class="cov8" title="1"> (scope *Scope) autoIndex() *Scope {
6136</span> var indexes = map[string][]string{}
6137 var uniqueIndexes = map[string][]string{}
6138
6139 for _, field := range scope.GetStructFields() {
6140 <span class="cov8" title="1"> if name, ok := field.TagSettingsGe</span><span class="cov8" title="1">t("INDEX"); ok {
6141 names := strings.Split(name, ",")
6142</span>
6143 </span>for _, name := range names {
6144 if name == "INDEX" || name == "" {
6145 name = scope.Dialect().BuildKeyName("idx", scope.TableName(), field.DBName)
6146 <span class="cov8" title="1"> }
6147</span> indexes[name] = append(indexes[name], field.DBName)
6148</span> }
6149 }</span>
6150
6151 if name, ok := field.TagSettingsGet("UNIQUE_INDEX"); ok {
6152 <span class="cov8" title="1"> names := s</span>trings.Split(name, ",")
6153
6154 for _, name := range names {
6155 if name == "UNIQUE_INDEX" || name == "" {
6156 name = scope.Dialect().Bu</span><span class="cov8" title="1">ildKeyName("uix", scope.TableName(), field.DBName)
6157 }
6158 uniqueIndexes[name] = append(uniqueIndexes[name], field.DBName)
6159 }
6160</span> }
6161 }
6162</span>
6163 for name, columns := range indexes {
6164 if db := scope.NewDB().Table(scope.TableName()).Model(scope.Value).AddIndex(name, columns...); db.Error != nil {
6165 scope.db.AddError(db.Error)
6166</span> }
6167 }
6168</span>
6169 for n</span>ame, columns := range uniqueIndexes {
6170 if <span class="cov8" title="1">db := scope.NewDB().Table(scope.TableName(</span>)).Model(scope.Value).AddUniqueIndex(name, columns...); db.Error != nil {
6171 scope.db.AddError(db.Error)
6172 }
6173 }
6174</span>
6175 retu</span>rn scope
6176}
6177
6178func (scope *Scope) getColumnAsArray(columns []string, values ...interface{}) (results [][]interface{}) {
6179 resultMap := make(map[string][]interface{})
6180 for _, value := range values {
6181</span> indirectValue := indirect(reflect.ValueOf(value))
6182
6183</span> switch indirectValue.Kind() {
6184 cas</span>e reflect.Slice:
6185 f<span class="cov8" title="1">or i := 0; i < indirectValue.Len(); i++ {
6186</span> var result []interface{}
6187 var object = indirect(indirectValue.Index(i))
6188 <span class="cov8" title="1"> var hasValu</span><span class="cov8" title="1">e = false
6189 for _, column := range columns {
6190 </span> field := object.FieldByName(column)
6191 if hasValue || !isBlank(field) {
6192 hasValue = true
6193 }
6194 <span class="cov8" title="1"> re</span>sult = append(result, field.Interface())
6195 }
6196
6197 if hasValue {
6198 h := fmt.Sprint(result...)
6199 if _, exist := resultMap[h]; !exist {
6200 resultMap[h] = result
6201</span> }
6202 }
6203</span> }
6204 case reflect.Struct:
6205</span> var result []interface{}
6206 v</span>ar hasValue = false
6207 for _, column := range columns {
6208 <span class="cov8" title="1"> field := indirectValue.FieldByName(column)
6209 if hasValue || !isBlank(field) {
6210 hasValue = true
6211 }
6212</span> result = append(result, field.Interface())
6213 }
6214
6215</span> if hasValue {
6216</span> h := fmt.Sprint(result...)
6217</span> if _, exist := resultMap[h]; !exist {
6218 resultMap[h] = result
6219 }
6220</span> }
6221 }
6222</span> }
6223 for _, v := range resultMap {
6224 res</span>ults = append(results, v)
6225 }
6226 re<span class="cov8" title="1">turn
6227</span>}
6228
6229func (scope *Scope) getColumnAsScope(column string) *Scope {
6230</span> indirectScopeValue := scope.IndirectValue()
6231
6232</span> switch indirectScopeValue.Kind() {
6233 <span class="cov8" title="1">case refle</span>ct.Slice:
6234 if fieldStruct, ok := scope.GetModelStruct().ModelType.FieldByName(column); ok {
6235 fieldType := fieldStruct.Type
6236 if fieldType.Kind() == reflect.Slice |<span class="cov8" title="1">| fieldType.Kind() == reflect.Ptr {
6237 fieldType = fieldType.Elem()
6238 }
6239
6240 resultsMap := map[interface{}]bool{}
6241 </span> results := reflect.New(reflect.SliceOf(reflect.PtrTo(fieldType))).Elem()
6242
6243 for i := 0; i < indirectScopeValue.Len(); i++ {
6244 result := indirect(indirect(indirectScopeValue.Index(i)).FieldByName(column))
6245
6246 if result.Kind() == reflect.Slice {
6247 for j := 0; j < result.Len(); j++ {
6248 if elem := result.Index(j); elem.CanAddr() && resultsMap[elem.Addr()] != true {
6249 resultsMap[elem.Addr()] = true
6250 results = reflect.Append(results, elem.Addr())
6251 }
6252 }
6253 } else if result.CanAddr() && resultsMap[result.Addr()] != true {
6254 resultsMap[result.Addr()] = true
6255 results = reflect.Append(results, result.Addr())
6256 }
6257 }
6258 return scope.New(results.Interface())
6259 }
6260 case reflect.Struct:
6261 if field := indirectScopeValue.FieldByName(column); field.CanAddr() {
6262 return scope.New(field.Addr().Interface())
6263 }
6264 }
6265 return nil
6266}
6267
6268func (scope *Scope) hasConditions() bool {
6269 return !scope.PrimaryKeyZero() ||
6270 len(scope.Search.whereConditions) > 0 ||
6271 len(scope.Search.orConditions) > 0 ||
6272 len(scope.Search.notConditions) > 0
6273}
6274</pre>
6275
6276 <pre class="file" id="file23" style="display: none">package gorm
6277
6278import (
6279 "fmt"
6280)
6281
6282type search struct {
6283 db *DB
6284 whereConditions []map[string]interface{}
6285 orConditions []map[string]interface{}
6286 notConditions []map[string]interface{}
6287 havingConditions []map[string]interface{}
6288 joinConditions []map[string]interface{}
6289 initAttrs []interface{}
6290 assignAttrs []interface{}
6291 selects map[string]interface{}
6292 omits []string
6293 orders []interface{}
6294 preload []searchPreload
6295 offset interface{}
6296 limit interface{}
6297 group string
6298 tableName string
6299 raw bool
6300 Unscoped bool
6301 ignoreOrderQuery bool
6302}
6303
6304type searchPreload struct {
6305 schema string
6306 conditions []interface{}
6307}
6308
6309func (s *search) clone() *search <span class="cov8" title="1">{
6310 clone := *s
6311 return &clone
6312}</span>
6313
6314func (s *search) Where(query interface{}, values ...interface{}) *search <span class="cov8" title="1">{
6315 s.whereConditions = append(s.whereConditions, map[string]interface{}{"query": query, "args": values})
6316 return s
6317}</span>
6318
6319func (s *search) Not(query interface{}, values ...interface{}) *search <span class="cov8" title="1">{
6320 s.notConditions = append(s.notConditions, map[string]interface{}{"query": query, "args": values})
6321 return s
6322}</span>
6323
6324func (s *search) Or(query interface{}, values ...interface{}) *search <span class="cov8" title="1">{
6325 s.orConditions = append(s.orConditions, map[string]interface{}{"query": query, "args": values})
6326 return s
6327}</span>
6328
6329func (s *search) Attrs(attrs ...interface{}) *search <span class="cov8" title="1">{
6330 s.initAttrs = append(s.initAttrs, toSearchableMap(attrs...))
6331 return s
6332}</span>
6333
6334func (s *search) Assign(attrs ...interface{}) *search <span class="cov8" title="1">{
6335 s.assignAttrs = append(s.assignAttrs, toSearchableMap(attrs...))
6336 return s
6337}</span>
6338
6339func (s *search) Order(value interface{}, reorder ...bool) *search <span class="cov8" title="1">{
6340 if len(reorder) > 0 && reorder[0] </span><span class="cov8" title="1">{
6341 s.orders = []interface{}{}
6342 }</span>
6343
6344 <span class="cov8" title="1">if value != nil && value != "" </span><span class="cov8" title="1">{
6345 s.orders = append(s.orders, value)
6346 }</span>
6347 <span class="cov8" title="1">return s</span>
6348}
6349
6350func (s *search) Select(query interface{}, args ...interface{}) *search <span class="cov8" title="1">{
6351 s.selects = map[string]interface{}{"query": query, "args": args}
6352 return s
6353}</span>
6354
6355func (s *search) Omit(columns ...string) *search <span class="cov8" title="1">{
6356 s.omits = columns
6357 return s
6358}</span>
6359
6360func (s *search) Limit(limit interface{}) *search <span class="cov8" title="1">{
6361 s.limit = limit
6362 return s
6363}</span>
6364
6365func (s *search) Offset(offset interface{}) *search <span class="cov8" title="1">{
6366 s.offset = offset
6367 return s
6368}</span>
6369
6370func (s *search) Group(query string) *search <span class="cov8" title="1">{
6371 s.group = s.getInterfaceAsSQL(query)
6372 return s
6373}</span>
6374
6375func (s *search) Having(query interface{}, values ...interface{}) *search <span class="cov8" title="1">{
6376 if val, ok := query.(*expr); ok </span><span class="cov0" title="0">{
6377 s.havingConditions = append(s.havingConditions, map[string]interface{}{"query": val.expr, "args": val.args})
6378 }</span> else<span class="cov8" title="1"> {
6379 s.havingConditions = append(s.havingConditions, map[string]interface{}{"query": query, "args": values})
6380 }</span>
6381 <span class="cov8" title="1">return s</span>
6382}
6383
6384func (s *search) Joins(query string, values ...interface{}) *search <span class="cov8" title="1">{
6385 s.joinConditions = append(s.joinConditions, map[string]interface{}{"query": query, "args": values})
6386 return s
6387}</span>
6388
6389func (s *search) Preload(schema string, values ...interface{}) *search <span class="cov8" title="1">{
6390 var preloads []searchPreload
6391 for _, preload := range s.preload </span><span class="cov8" title="1">{
6392 if preload.schema != schema </span><span class="cov8" title="1">{
6393 preloads = append(preloads, preload)
6394 }</span>
6395 }
6396 <span class="cov8" title="1">preloads = append(preloads, searchPreload{schema, values})
6397 s.preload = preloads
6398 return s</span>
6399}
6400
6401func (s *search) Raw(b bool) *search <span class="cov8" title="1">{
6402 s.raw = b
6403 return s
6404}</span>
6405
6406func (s *search) unscoped() *search <span class="cov8" title="1">{
6407 s.Unscoped = true
6408 return s
6409}</span>
6410
6411func (s *search) Table(name string) *search <span class="cov8" title="1">{
6412 s.tableName = name
6413 return s
6414}</span>
6415
6416func (s *search) getInterfaceAsSQL(value interface{}) (str string) <span class="cov8" title="1">{
6417 switch value.(type) </span>{
6418 case string, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:<span class="cov8" title="1">
6419 str = fmt.Sprintf("%v", value)</span>
6420 default:<span class="cov0" title="0">
6421 s.db.AddError(ErrInvalidSQL)</span>
6422 }
6423
6424 <span class="cov8" title="1">if str == "-1" </span><span class="cov0" title="0">{
6425 return ""
6426 }</span>
6427 <span class="cov8" title="1">return</span>
6428}
6429</pre>
6430
6431 <pre class="file" id="file24" style="display: none">package gorm
6432
6433import (
6434 "database/sql/driver"
6435 "fmt"
6436 "reflect"
6437 "regexp"
6438 "runtime"
6439 "strings"
6440 "sync"
6441 "time"
6442)
6443
6444// NowFunc returns current time, this function is exported in order to be able
6445// to give the flexibility to the developer to customize it according to their
6446// needs, e.g:
6447// gorm.NowFunc = func() time.Time {
6448// return time.Now().UTC()
6449// }
6450var NowFunc = func() time.Time {
6451 return time.Now()
6452}
6453
6454</span>// Copied from golint
6455var commonInitialisms = []string{"API", "ASCII", "CPU", "CSS", "DNS", "EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", "LHS", "QPS", "RAM", "RHS", "RPC", "SLA", "SMTP", "SSH", "TLS", "TTL", "UID", "UI", "UUID", "URI", "URL", "UTF8", "VM", "XML", "XSRF", "XSS"}
6456var commonInitialismsReplacer *strings.Replacer
6457
6458var goSrcRegexp = regexp.MustCompile(`jinzhu/gorm(@.*)?/.*.go`)
6459var goTestRegexp = regexp.MustCompile(`jinzhu/gorm(@.*)?/.*test.go`)
6460
6461func init() {
6462 var commonI<span class="cov8" title="1">nitialismsForReplacer []string
6463 for _, initialism := range commonInitialisms {
6464 commonInitialismsForReplacer = append(common</span><span class="cov8" title="1">InitialismsForReplacer, initialism, strings.Title(strings.ToLower(initialism)))
6465 }
6466 c</span>ommonInitialismsReplacer = strings.NewReplacer(commonInitialismsForReplacer...)
6467}<span class="cov8" title="1">
6468</span>
6469type safeMap struct {
6470 m map[string]string
6471 l *sync.RWMutex
6472}
6473
6474func (s *safeMap) Set(key string, value string) {
6475 s.l.Lock()
6476 defer s.l.Unlock()
6477 s.m[key] = value
6478}
6479
6480</span>func (s *safeMap) Get(key string) string {
6481 s.l.RLock()
6482 defer s.l.RUnlock()
6483 return s.m[key]
6484}
6485
6486</span>func newSafeMap() *safeMap {
6487 return &safeMap{l: new(syn<span class="cov8" title="1">c.RWMutex), m: make(map[string]string)}
6488}
6489
6490</span>// SQL expression
6491type expr struct {
6492 expr string
6493 args []interface{}
6494}
6495
6496// Expr generate raw SQL expression, for example:
6497// DB.Model(&product).Update("price", gorm.Expr("price * ? + ?", 2, 100))
6498func Expr(expression string, args ...interface{}) *expr {
6499 return &expr{expr: expression, args: args}
6500}
6501
6502func indirect(reflectValue reflec</span><span class="cov8" title="1">t.Value) reflect.Value {
6503 for reflectValue.Kind() == reflect.Ptr {
6504 </span>reflectValue = reflectValue.Elem()
6505 }
6506 <span class="cov8" title="1">return reflect</span><span class="cov8" title="1">Value
6507}
6508
6509</span>func toQueryMarks(primaryValues [][]interface{}) string {
6510 <span class="cov8" title="1">var results []string
6511
6512 for _, primaryValue := range primaryValues {
6513 var marks []string
6514 for range primaryValue {
6515 marks = append(marks, "?")
6516 }
6517</span>
6518 if len(ma</span><span class="cov8" title="1">rks) > 1 {
6519 results = append(resu</span><span class="cov8" title="1">lts, fmt.Sprintf("(%v)", strings.Join(marks, ",")))
6520 } else {
6521</span> results = append(results, strings.Join(marks, ""))
6522 }
6523</span> }
6524</span> return strings.Join(results, ",")
6525}
6526</span>
6527</span>func toQueryCondition(scope *Scope, columns []string) string {
6528 var newC<span class="cov8" title="1">olumns []string
6529 for _, column := range columns {
6530 newColumns = append(newColumns, scope.Quote(</span><span class="cov8" title="1">column))
6531 }
6532
6533</span> if len(columns) > 1 {
6534 return<span class="cov8" title="1"> fmt.Sprintf("(%v)", strings.Join(newColumns, ","))
6535 }
6536 return strings.Join(newColumns, ",")
6537}
6538</span>
6539func toQueryValues(va</span>lues [][]interface{}) (results []interface{}) {
6540 for _, value := range values {
6541 for _, v := range value {
6542 <span class="cov8" title="1"> results = append(results, v)
6543 }
6544 }
6545 return
6546}
6547</span>
6548func fileWithLineNum() string {
6549 for i := 2; i < 15; i++ {
6550 _, file, line, ok := runtime.Caller(i)
6551 if ok && (!goSrcRegexp.MatchString(file) || goTestRegexp.MatchString(file)) {
6552 return fmt.Sprintf("%v:%v", file, line)
6553 }
6554 }
6555 return ""
6556}
6557
6558func isBlank(value reflect.Value) bool {
6559 </span>switch value.Kind() {
6560 case reflect.String:
6561 return value.Len() == 0
6562 case reflect.Bool:
6563</span> return !value.Bool()
6564 c</span>ase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
6565 <span class="cov8" title="1"> return value.Int()</span> == 0
6566 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
6567 return value.Uint() == 0
6568 case reflect.Float32, reflect.Float64:
6569 return value.Float() == 0
6570 case reflect.Interface, reflect.Ptr:
6571 return value.IsNil()
6572</span> }
6573
6574</span> return reflect.DeepEqual(value.Interface(), reflect.Zero(value.Type()).Interface())
6575}
6576</span>
6577fu<span class="cov8" title="1">nc toSearchableMap</span><span class="cov0" title="0">(attrs ...interface{}) (result interface{}) {
6578 if len(attrs) > 1 {
6579 i</span>f str<span class="cov8" title="1">, ok := attrs[0].(string); ok {
6580 result = map[string]interface{}{str: attrs[1]}
6581 }</span>
6582 } else if len(attrs) == 1 {
6583 <span class="cov8" title="1"> if attr, ok := attrs[0].(map[str</span>ing]interface{}); ok {
6584 result = attr
6585 }
6586
6587 if attr, ok := attrs[0].(interface{}); ok {
6588 result = attr
6589</span> }
6590 }</span>
6591 return
6592}<span class="cov8" title="1">
6593</span>
6594fu</span>nc equalAsString(a interface{}, b interface{}) bool {
6595 <span class="cov8" title="1">return toString(a) == toString(b)
6596</span>}
6597
6598func toString(str interface{}) string {
6599 if values, ok := str.([]inter</span><span class="cov8" title="1">face{}); ok {
6600 var results []string
6601</span> for _, value := range values {
6602 </span>results = append(results, toString(value))
6603 }
6604 <span class="cov8" title="1"> retur</span>n strings.Join(results, "_")
6605 } else if bytes, ok := str.([]byte); ok {
6606 return string(bytes)
6607 } else if reflectValue := ref<span class="cov8" title="1">lect.Indirect(reflect.ValueOf(str)); reflectValue.IsValid() {
6608 return fmt.Sprintf("%v"</span><span class="cov8" title="1">, reflectValue.Interface())
6609 }
6610 return ""
6611</span>}
6612
6613</span>func makeSlice(elemType reflect.Type) interface{} {
6614 <span class="cov0" title="0">if elemTy</span>pe.Kind() == reflect.Slice {
6615 elemType = elemType.Elem()
6616 }
6617 sliceType := reflect.SliceOf(elemType)<span class="cov8" title="1">
6618 slice := reflect.New</span>(sliceType)
6619 slice.Elem().Set(ref<span class="cov8" title="1">lect.MakeSlice(sliceType, 0, 0))
6620 return slice.Interface()</span>
6621}
6622
6623</span>func strInSlice(a string, list []string) bool {
6624 for _, b := range list {</span>
6625 if b == a {
6626 return true
6627</span> }
6628 }
6629</span> return false
6630}
6631</span>
6632// getValueFromFields return given fields's value
6633f<span class="cov8" title="1">unc getValueFromFields(value reflect.Value, fieldNames []string) (results []interfa</span>ce{}) {
6634 // If value is a nil pointer, Indirect returns a zero Value!
6635 // Therefor we need to check for a zero value,
6636 // as FieldByName could panic
6637 if indirectValue :</span><span class="cov8" title="1">= reflect.Indirect(value); indirectValue.IsValid() {
6638 for _, fieldName := range fieldNames</span><span class="cov8" title="1"> {
6639 if fieldValue := reflect.Indirect(indirectValue.FieldByName(fieldName)); fieldValue.IsValid() {
6640 </span> result := fieldValue.Interface()
6641 if <span class="cov8" title="1">r, ok := result.(dri</span><span class="cov8" title="1">ver.Valuer); ok {
6642 result, _ = r.Value()
6643</span> }
6644 </span> results = append(results, result)
6645 }
6646 <span class="cov8" title="1">}
6647</span> }
6648 re</span>turn
6649}
6650
6651</span>func addExtraSpaceIfExist(str string) string {
6652 if str != "" {
6653 return " " + str
6654 }
6655 </span>return ""
6656}
6657</pre>
6658
6659 </div>
6660 </body>
6661 <script>
6662 (function() {
6663 var files = document.getElementById('files');
6664 var visible;
6665 files.addEventListener('change', onChange, false);
6666 function select(part) {
6667 if (visible)
6668 visible.style.display = 'none';
6669 visible = document.getElementById(part);
6670 if (!visible)
6671 return;
6672 files.value = part;
6673 visible.style.display = 'block';
6674 location.hash = part;
6675 }
6676 function onChange() {
6677 select(files.value);
6678 window.scrollTo(0, 0);
6679 }
6680 if (location.hash != "") {
6681 select(location.hash.substr(1));
6682 }
6683 if (!visible) {
6684 select("file0");
6685 }
6686 })();
6687 </script>
6688</html>