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