lock TagSettings structure when modified
The map is modified in different places in the code which results in race conditions on execution. This commit locks the map with read-write lock when it is modified
This commit is contained in:
		
							parent
							
								
									6ed508ec6a
								
							
						
					
					
						commit
						ce2592b5ae
					
				@ -94,7 +94,7 @@ func autoPreload(scope *Scope) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if val, ok := field.TagSettings["PRELOAD"]; ok {
 | 
			
		||||
		if val, ok := field.TagSettingsGet("PRELOAD"); ok {
 | 
			
		||||
			if preload, err := strconv.ParseBool(val); err != nil {
 | 
			
		||||
				scope.Err(errors.New("invalid preload option"))
 | 
			
		||||
				return
 | 
			
		||||
 | 
			
		||||
@ -36,26 +36,26 @@ func saveAssociationCheck(scope *Scope, field *Field) (autoUpdate bool, autoCrea
 | 
			
		||||
			if value, ok := scope.Get("gorm:save_associations"); ok {
 | 
			
		||||
				autoUpdate = checkTruth(value)
 | 
			
		||||
				autoCreate = autoUpdate
 | 
			
		||||
			} else if value, ok := field.TagSettings["SAVE_ASSOCIATIONS"]; ok {
 | 
			
		||||
			} else if value, ok := field.TagSettingsGet("SAVE_ASSOCIATIONS"); ok {
 | 
			
		||||
				autoUpdate = checkTruth(value)
 | 
			
		||||
				autoCreate = autoUpdate
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if value, ok := scope.Get("gorm:association_autoupdate"); ok {
 | 
			
		||||
				autoUpdate = checkTruth(value)
 | 
			
		||||
			} else if value, ok := field.TagSettings["ASSOCIATION_AUTOUPDATE"]; ok {
 | 
			
		||||
			} else if value, ok := field.TagSettingsGet("ASSOCIATION_AUTOUPDATE"); ok {
 | 
			
		||||
				autoUpdate = checkTruth(value)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if value, ok := scope.Get("gorm:association_autocreate"); ok {
 | 
			
		||||
				autoCreate = checkTruth(value)
 | 
			
		||||
			} else if value, ok := field.TagSettings["ASSOCIATION_AUTOCREATE"]; ok {
 | 
			
		||||
			} else if value, ok := field.TagSettingsGet("ASSOCIATION_AUTOCREATE"); ok {
 | 
			
		||||
				autoCreate = checkTruth(value)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if value, ok := scope.Get("gorm:association_save_reference"); ok {
 | 
			
		||||
				saveReference = checkTruth(value)
 | 
			
		||||
			} else if value, ok := field.TagSettings["ASSOCIATION_SAVE_REFERENCE"]; ok {
 | 
			
		||||
			} else if value, ok := field.TagSettingsGet("ASSOCIATION_SAVE_REFERENCE"); ok {
 | 
			
		||||
				saveReference = checkTruth(value)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										10
									
								
								dialect.go
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								dialect.go
									
									
									
									
									
								
							@ -77,7 +77,7 @@ var ParseFieldStructForDialect = func(field *StructField, dialect Dialect) (fiel
 | 
			
		||||
	// Get redirected field type
 | 
			
		||||
	var (
 | 
			
		||||
		reflectType = field.Struct.Type
 | 
			
		||||
		dataType    = field.TagSettings["TYPE"]
 | 
			
		||||
		dataType, _ = field.TagSettingsGet("TYPE")
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	for reflectType.Kind() == reflect.Ptr {
 | 
			
		||||
@ -106,15 +106,17 @@ var ParseFieldStructForDialect = func(field *StructField, dialect Dialect) (fiel
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Default Size
 | 
			
		||||
	if num, ok := field.TagSettings["SIZE"]; ok {
 | 
			
		||||
	if num, ok := field.TagSettingsGet("SIZE"); ok {
 | 
			
		||||
		size, _ = strconv.Atoi(num)
 | 
			
		||||
	} else {
 | 
			
		||||
		size = 255
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Default type from tag setting
 | 
			
		||||
	additionalType = field.TagSettings["NOT NULL"] + " " + field.TagSettings["UNIQUE"]
 | 
			
		||||
	if value, ok := field.TagSettings["DEFAULT"]; ok {
 | 
			
		||||
	notNull, _ := field.TagSettingsGet("NOT NULL")
 | 
			
		||||
	unique, _ := field.TagSettingsGet("UNIQUE")
 | 
			
		||||
	additionalType = notNull + " " + unique
 | 
			
		||||
	if value, ok := field.TagSettingsGet("DEFAULT"); ok {
 | 
			
		||||
		additionalType = additionalType + " DEFAULT " + value
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -39,7 +39,7 @@ func (commonDialect) Quote(key string) string {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *commonDialect) fieldCanAutoIncrement(field *StructField) bool {
 | 
			
		||||
	if value, ok := field.TagSettings["AUTO_INCREMENT"]; ok {
 | 
			
		||||
	if value, ok := field.TagSettingsGet("AUTO_INCREMENT"); ok {
 | 
			
		||||
		return strings.ToLower(value) != "false"
 | 
			
		||||
	}
 | 
			
		||||
	return field.IsPrimaryKey
 | 
			
		||||
 | 
			
		||||
@ -33,9 +33,9 @@ func (s *mysql) DataTypeOf(field *StructField) string {
 | 
			
		||||
 | 
			
		||||
	// MySQL allows only one auto increment column per table, and it must
 | 
			
		||||
	// be a KEY column.
 | 
			
		||||
	if _, ok := field.TagSettings["AUTO_INCREMENT"]; ok {
 | 
			
		||||
		if _, ok = field.TagSettings["INDEX"]; !ok && !field.IsPrimaryKey {
 | 
			
		||||
			delete(field.TagSettings, "AUTO_INCREMENT")
 | 
			
		||||
	if _, ok := field.TagSettingsGet("AUTO_INCREMENT"); ok {
 | 
			
		||||
		if _, ok = field.TagSettingsGet("INDEX"); !ok && !field.IsPrimaryKey {
 | 
			
		||||
			field.TagSettingsDelete("AUTO_INCREMENT")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -45,42 +45,42 @@ func (s *mysql) DataTypeOf(field *StructField) string {
 | 
			
		||||
			sqlType = "boolean"
 | 
			
		||||
		case reflect.Int8:
 | 
			
		||||
			if s.fieldCanAutoIncrement(field) {
 | 
			
		||||
				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
 | 
			
		||||
				field.TagSettingsSet("AUTO_INCREMENT", "AUTO_INCREMENT")
 | 
			
		||||
				sqlType = "tinyint AUTO_INCREMENT"
 | 
			
		||||
			} else {
 | 
			
		||||
				sqlType = "tinyint"
 | 
			
		||||
			}
 | 
			
		||||
		case reflect.Int, reflect.Int16, reflect.Int32:
 | 
			
		||||
			if s.fieldCanAutoIncrement(field) {
 | 
			
		||||
				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
 | 
			
		||||
				field.TagSettingsSet("AUTO_INCREMENT", "AUTO_INCREMENT")
 | 
			
		||||
				sqlType = "int AUTO_INCREMENT"
 | 
			
		||||
			} else {
 | 
			
		||||
				sqlType = "int"
 | 
			
		||||
			}
 | 
			
		||||
		case reflect.Uint8:
 | 
			
		||||
			if s.fieldCanAutoIncrement(field) {
 | 
			
		||||
				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
 | 
			
		||||
				field.TagSettingsSet("AUTO_INCREMENT", "AUTO_INCREMENT")
 | 
			
		||||
				sqlType = "tinyint unsigned AUTO_INCREMENT"
 | 
			
		||||
			} else {
 | 
			
		||||
				sqlType = "tinyint unsigned"
 | 
			
		||||
			}
 | 
			
		||||
		case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uintptr:
 | 
			
		||||
			if s.fieldCanAutoIncrement(field) {
 | 
			
		||||
				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
 | 
			
		||||
				field.TagSettingsSet("AUTO_INCREMENT", "AUTO_INCREMENT")
 | 
			
		||||
				sqlType = "int unsigned AUTO_INCREMENT"
 | 
			
		||||
			} else {
 | 
			
		||||
				sqlType = "int unsigned"
 | 
			
		||||
			}
 | 
			
		||||
		case reflect.Int64:
 | 
			
		||||
			if s.fieldCanAutoIncrement(field) {
 | 
			
		||||
				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
 | 
			
		||||
				field.TagSettingsSet("AUTO_INCREMENT", "AUTO_INCREMENT")
 | 
			
		||||
				sqlType = "bigint AUTO_INCREMENT"
 | 
			
		||||
			} else {
 | 
			
		||||
				sqlType = "bigint"
 | 
			
		||||
			}
 | 
			
		||||
		case reflect.Uint64:
 | 
			
		||||
			if s.fieldCanAutoIncrement(field) {
 | 
			
		||||
				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
 | 
			
		||||
				field.TagSettingsSet("AUTO_INCREMENT", "AUTO_INCREMENT")
 | 
			
		||||
				sqlType = "bigint unsigned AUTO_INCREMENT"
 | 
			
		||||
			} else {
 | 
			
		||||
				sqlType = "bigint unsigned"
 | 
			
		||||
@ -96,11 +96,11 @@ func (s *mysql) DataTypeOf(field *StructField) string {
 | 
			
		||||
		case reflect.Struct:
 | 
			
		||||
			if _, ok := dataValue.Interface().(time.Time); ok {
 | 
			
		||||
				precision := ""
 | 
			
		||||
				if p, ok := field.TagSettings["PRECISION"]; ok {
 | 
			
		||||
				if p, ok := field.TagSettingsGet("PRECISION"); ok {
 | 
			
		||||
					precision = fmt.Sprintf("(%s)", p)
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if _, ok := field.TagSettings["NOT NULL"]; ok {
 | 
			
		||||
				if _, ok := field.TagSettingsGet("NOT NULL"); ok {
 | 
			
		||||
					sqlType = fmt.Sprintf("timestamp%v", precision)
 | 
			
		||||
				} else {
 | 
			
		||||
					sqlType = fmt.Sprintf("timestamp%v NULL", precision)
 | 
			
		||||
 | 
			
		||||
@ -34,14 +34,14 @@ func (s *postgres) DataTypeOf(field *StructField) string {
 | 
			
		||||
			sqlType = "boolean"
 | 
			
		||||
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uintptr:
 | 
			
		||||
			if s.fieldCanAutoIncrement(field) {
 | 
			
		||||
				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
 | 
			
		||||
				field.TagSettingsSet("AUTO_INCREMENT", "AUTO_INCREMENT")
 | 
			
		||||
				sqlType = "serial"
 | 
			
		||||
			} else {
 | 
			
		||||
				sqlType = "integer"
 | 
			
		||||
			}
 | 
			
		||||
		case reflect.Int64, reflect.Uint32, reflect.Uint64:
 | 
			
		||||
			if s.fieldCanAutoIncrement(field) {
 | 
			
		||||
				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
 | 
			
		||||
				field.TagSettingsSet("AUTO_INCREMENT", "AUTO_INCREMENT")
 | 
			
		||||
				sqlType = "bigserial"
 | 
			
		||||
			} else {
 | 
			
		||||
				sqlType = "bigint"
 | 
			
		||||
@ -49,7 +49,7 @@ func (s *postgres) DataTypeOf(field *StructField) string {
 | 
			
		||||
		case reflect.Float32, reflect.Float64:
 | 
			
		||||
			sqlType = "numeric"
 | 
			
		||||
		case reflect.String:
 | 
			
		||||
			if _, ok := field.TagSettings["SIZE"]; !ok {
 | 
			
		||||
			if _, ok := field.TagSettingsGet("SIZE"); !ok {
 | 
			
		||||
				size = 0 // if SIZE haven't been set, use `text` as the default type, as there are no performance different
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -29,14 +29,14 @@ func (s *sqlite3) DataTypeOf(field *StructField) string {
 | 
			
		||||
			sqlType = "bool"
 | 
			
		||||
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr:
 | 
			
		||||
			if s.fieldCanAutoIncrement(field) {
 | 
			
		||||
				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
 | 
			
		||||
				field.TagSettingsSet("AUTO_INCREMENT", "AUTO_INCREMENT")
 | 
			
		||||
				sqlType = "integer primary key autoincrement"
 | 
			
		||||
			} else {
 | 
			
		||||
				sqlType = "integer"
 | 
			
		||||
			}
 | 
			
		||||
		case reflect.Int64, reflect.Uint64:
 | 
			
		||||
			if s.fieldCanAutoIncrement(field) {
 | 
			
		||||
				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
 | 
			
		||||
				field.TagSettingsSet("AUTO_INCREMENT", "AUTO_INCREMENT")
 | 
			
		||||
				sqlType = "integer primary key autoincrement"
 | 
			
		||||
			} else {
 | 
			
		||||
				sqlType = "bigint"
 | 
			
		||||
 | 
			
		||||
@ -14,7 +14,7 @@ import (
 | 
			
		||||
func setIdentityInsert(scope *gorm.Scope) {
 | 
			
		||||
	if scope.Dialect().GetName() == "mssql" {
 | 
			
		||||
		for _, field := range scope.PrimaryFields() {
 | 
			
		||||
			if _, ok := field.TagSettings["AUTO_INCREMENT"]; ok && !field.IsBlank {
 | 
			
		||||
			if _, ok := field.TagSettingsGet("AUTO_INCREMENT"); ok && !field.IsBlank {
 | 
			
		||||
				scope.NewDB().Exec(fmt.Sprintf("SET IDENTITY_INSERT %v ON", scope.TableName()))
 | 
			
		||||
				scope.InstanceSet("mssql:identity_insert_on", true)
 | 
			
		||||
			}
 | 
			
		||||
@ -66,14 +66,14 @@ func (s *mssql) DataTypeOf(field *gorm.StructField) string {
 | 
			
		||||
			sqlType = "bit"
 | 
			
		||||
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr:
 | 
			
		||||
			if s.fieldCanAutoIncrement(field) {
 | 
			
		||||
				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
 | 
			
		||||
				field.TagSettingsSet("AUTO_INCREMENT", "AUTO_INCREMENT")
 | 
			
		||||
				sqlType = "int IDENTITY(1,1)"
 | 
			
		||||
			} else {
 | 
			
		||||
				sqlType = "int"
 | 
			
		||||
			}
 | 
			
		||||
		case reflect.Int64, reflect.Uint64:
 | 
			
		||||
			if s.fieldCanAutoIncrement(field) {
 | 
			
		||||
				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
 | 
			
		||||
				field.TagSettingsSet("AUTO_INCREMENT", "AUTO_INCREMENT")
 | 
			
		||||
				sqlType = "bigint IDENTITY(1,1)"
 | 
			
		||||
			} else {
 | 
			
		||||
				sqlType = "bigint"
 | 
			
		||||
@ -112,7 +112,7 @@ func (s *mssql) DataTypeOf(field *gorm.StructField) string {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s mssql) fieldCanAutoIncrement(field *gorm.StructField) bool {
 | 
			
		||||
	if value, ok := field.TagSettings["AUTO_INCREMENT"]; ok {
 | 
			
		||||
	if value, ok := field.TagSettingsGet("AUTO_INCREMENT"); ok {
 | 
			
		||||
		return value != "FALSE"
 | 
			
		||||
	}
 | 
			
		||||
	return field.IsPrimaryKey
 | 
			
		||||
 | 
			
		||||
@ -43,7 +43,7 @@ func TestCalculateField(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	if field, ok := scope.FieldByName("embedded_name"); !ok {
 | 
			
		||||
		t.Errorf("should find embedded field")
 | 
			
		||||
	} else if _, ok := field.TagSettings["NOT NULL"]; !ok {
 | 
			
		||||
	} else if _, ok := field.TagSettingsGet("NOT NULL"); !ok {
 | 
			
		||||
		t.Errorf("should find embedded field's tag settings")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								main.go
									
									
									
									
									
								
							@ -685,7 +685,7 @@ func (s *DB) SetJoinTableHandler(source interface{}, column string, handler Join
 | 
			
		||||
	scope := s.NewScope(source)
 | 
			
		||||
	for _, field := range scope.GetModelStruct().StructFields {
 | 
			
		||||
		if field.Name == column || field.DBName == column {
 | 
			
		||||
			if many2many := field.TagSettings["MANY2MANY"]; many2many != "" {
 | 
			
		||||
			if many2many, _ := field.TagSettingsGet("MANY2MANY"); many2many != "" {
 | 
			
		||||
				source := (&Scope{Value: source}).GetModelStruct().ModelType
 | 
			
		||||
				destination := (&Scope{Value: reflect.New(field.Struct.Type).Interface()}).GetModelStruct().ModelType
 | 
			
		||||
				handler.Setup(field.Relationship, many2many, source, destination)
 | 
			
		||||
 | 
			
		||||
@ -81,6 +81,30 @@ type StructField struct {
 | 
			
		||||
	Struct          reflect.StructField
 | 
			
		||||
	IsForeignKey    bool
 | 
			
		||||
	Relationship    *Relationship
 | 
			
		||||
 | 
			
		||||
	tagSettingsLock sync.RWMutex
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TagSettingsSet Sets a tag in the tag settings map
 | 
			
		||||
func (s *StructField) TagSettingsSet(key, val string) {
 | 
			
		||||
	s.tagSettingsLock.Lock()
 | 
			
		||||
	defer s.tagSettingsLock.Unlock()
 | 
			
		||||
	s.TagSettings[key] = val
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TagSettingsGet returns a tag from the tag settings
 | 
			
		||||
func (s *StructField) TagSettingsGet(key string) (string, bool) {
 | 
			
		||||
	s.tagSettingsLock.RLock()
 | 
			
		||||
	defer s.tagSettingsLock.RUnlock()
 | 
			
		||||
	val, ok := s.TagSettings[key]
 | 
			
		||||
	return val, ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TagSettingsDelete deletes a tag
 | 
			
		||||
func (s *StructField) TagSettingsDelete(key string) {
 | 
			
		||||
	s.tagSettingsLock.Lock()
 | 
			
		||||
	defer s.tagSettingsLock.Unlock()
 | 
			
		||||
	delete(s.TagSettings, key)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (structField *StructField) clone() *StructField {
 | 
			
		||||
@ -104,6 +128,9 @@ func (structField *StructField) clone() *StructField {
 | 
			
		||||
		clone.Relationship = &relationship
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// copy the struct field tagSettings, they should be read-locked while they are copied
 | 
			
		||||
	structField.tagSettingsLock.Lock()
 | 
			
		||||
	defer structField.tagSettingsLock.Unlock()
 | 
			
		||||
	for key, value := range structField.TagSettings {
 | 
			
		||||
		clone.TagSettings[key] = value
 | 
			
		||||
	}
 | 
			
		||||
@ -170,19 +197,19 @@ func (scope *Scope) GetModelStruct() *ModelStruct {
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// is ignored field
 | 
			
		||||
			if _, ok := field.TagSettings["-"]; ok {
 | 
			
		||||
			if _, ok := field.TagSettingsGet("-"); ok {
 | 
			
		||||
				field.IsIgnored = true
 | 
			
		||||
			} else {
 | 
			
		||||
				if _, ok := field.TagSettings["PRIMARY_KEY"]; ok {
 | 
			
		||||
				if _, ok := field.TagSettingsGet("PRIMARY_KEY"); ok {
 | 
			
		||||
					field.IsPrimaryKey = true
 | 
			
		||||
					modelStruct.PrimaryFields = append(modelStruct.PrimaryFields, field)
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if _, ok := field.TagSettings["DEFAULT"]; ok {
 | 
			
		||||
				if _, ok := field.TagSettingsGet("DEFAULT"); ok {
 | 
			
		||||
					field.HasDefaultValue = true
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if _, ok := field.TagSettings["AUTO_INCREMENT"]; ok && !field.IsPrimaryKey {
 | 
			
		||||
				if _, ok := field.TagSettingsGet("AUTO_INCREMENT"); ok && !field.IsPrimaryKey {
 | 
			
		||||
					field.HasDefaultValue = true
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
@ -198,8 +225,8 @@ func (scope *Scope) GetModelStruct() *ModelStruct {
 | 
			
		||||
					if indirectType.Kind() == reflect.Struct {
 | 
			
		||||
						for i := 0; i < indirectType.NumField(); i++ {
 | 
			
		||||
							for key, value := range parseTagSetting(indirectType.Field(i).Tag) {
 | 
			
		||||
								if _, ok := field.TagSettings[key]; !ok {
 | 
			
		||||
									field.TagSettings[key] = value
 | 
			
		||||
								if _, ok := field.TagSettingsGet(key); !ok {
 | 
			
		||||
									field.TagSettingsSet(key, value)
 | 
			
		||||
								}
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
@ -207,17 +234,17 @@ func (scope *Scope) GetModelStruct() *ModelStruct {
 | 
			
		||||
				} else if _, isTime := fieldValue.(*time.Time); isTime {
 | 
			
		||||
					// is time
 | 
			
		||||
					field.IsNormal = true
 | 
			
		||||
				} else if _, ok := field.TagSettings["EMBEDDED"]; ok || fieldStruct.Anonymous {
 | 
			
		||||
				} else if _, ok := field.TagSettingsGet("EMBEDDED"); ok || fieldStruct.Anonymous {
 | 
			
		||||
					// is embedded struct
 | 
			
		||||
					for _, subField := range scope.New(fieldValue).GetModelStruct().StructFields {
 | 
			
		||||
						subField = subField.clone()
 | 
			
		||||
						subField.Names = append([]string{fieldStruct.Name}, subField.Names...)
 | 
			
		||||
						if prefix, ok := field.TagSettings["EMBEDDED_PREFIX"]; ok {
 | 
			
		||||
						if prefix, ok := field.TagSettingsGet("EMBEDDED_PREFIX"); ok {
 | 
			
		||||
							subField.DBName = prefix + subField.DBName
 | 
			
		||||
						}
 | 
			
		||||
 | 
			
		||||
						if subField.IsPrimaryKey {
 | 
			
		||||
							if _, ok := subField.TagSettings["PRIMARY_KEY"]; ok {
 | 
			
		||||
							if _, ok := subField.TagSettingsGet("PRIMARY_KEY"); ok {
 | 
			
		||||
								modelStruct.PrimaryFields = append(modelStruct.PrimaryFields, subField)
 | 
			
		||||
							} else {
 | 
			
		||||
								subField.IsPrimaryKey = false
 | 
			
		||||
@ -248,13 +275,13 @@ func (scope *Scope) GetModelStruct() *ModelStruct {
 | 
			
		||||
								elemType               = field.Struct.Type
 | 
			
		||||
							)
 | 
			
		||||
 | 
			
		||||
							if foreignKey := field.TagSettings["FOREIGNKEY"]; foreignKey != "" {
 | 
			
		||||
							if foreignKey, _ := field.TagSettingsGet("FOREIGNKEY"); foreignKey != "" {
 | 
			
		||||
								foreignKeys = strings.Split(foreignKey, ",")
 | 
			
		||||
							}
 | 
			
		||||
 | 
			
		||||
							if foreignKey := field.TagSettings["ASSOCIATION_FOREIGNKEY"]; foreignKey != "" {
 | 
			
		||||
							if foreignKey, _ := field.TagSettingsGet("ASSOCIATION_FOREIGNKEY"); foreignKey != "" {
 | 
			
		||||
								associationForeignKeys = strings.Split(foreignKey, ",")
 | 
			
		||||
							} else if foreignKey := field.TagSettings["ASSOCIATIONFOREIGNKEY"]; foreignKey != "" {
 | 
			
		||||
							} else if foreignKey, _ := field.TagSettingsGet("ASSOCIATIONFOREIGNKEY"); foreignKey != "" {
 | 
			
		||||
								associationForeignKeys = strings.Split(foreignKey, ",")
 | 
			
		||||
							}
 | 
			
		||||
 | 
			
		||||
@ -263,13 +290,13 @@ func (scope *Scope) GetModelStruct() *ModelStruct {
 | 
			
		||||
							}
 | 
			
		||||
 | 
			
		||||
							if elemType.Kind() == reflect.Struct {
 | 
			
		||||
								if many2many := field.TagSettings["MANY2MANY"]; many2many != "" {
 | 
			
		||||
								if many2many, _ := field.TagSettingsGet("MANY2MANY"); many2many != "" {
 | 
			
		||||
									relationship.Kind = "many_to_many"
 | 
			
		||||
 | 
			
		||||
									{ // Foreign Keys for Source
 | 
			
		||||
										joinTableDBNames := []string{}
 | 
			
		||||
 | 
			
		||||
										if foreignKey := field.TagSettings["JOINTABLE_FOREIGNKEY"]; foreignKey != "" {
 | 
			
		||||
										if foreignKey, _ := field.TagSettingsGet("JOINTABLE_FOREIGNKEY"); foreignKey != "" {
 | 
			
		||||
											joinTableDBNames = strings.Split(foreignKey, ",")
 | 
			
		||||
										}
 | 
			
		||||
 | 
			
		||||
@ -300,7 +327,7 @@ func (scope *Scope) GetModelStruct() *ModelStruct {
 | 
			
		||||
									{ // Foreign Keys for Association (Destination)
 | 
			
		||||
										associationJoinTableDBNames := []string{}
 | 
			
		||||
 | 
			
		||||
										if foreignKey := field.TagSettings["ASSOCIATION_JOINTABLE_FOREIGNKEY"]; foreignKey != "" {
 | 
			
		||||
										if foreignKey, _ := field.TagSettingsGet("ASSOCIATION_JOINTABLE_FOREIGNKEY"); foreignKey != "" {
 | 
			
		||||
											associationJoinTableDBNames = strings.Split(foreignKey, ",")
 | 
			
		||||
										}
 | 
			
		||||
 | 
			
		||||
@ -338,7 +365,7 @@ func (scope *Scope) GetModelStruct() *ModelStruct {
 | 
			
		||||
									var toFields = toScope.GetStructFields()
 | 
			
		||||
									relationship.Kind = "has_many"
 | 
			
		||||
 | 
			
		||||
									if polymorphic := field.TagSettings["POLYMORPHIC"]; polymorphic != "" {
 | 
			
		||||
									if polymorphic, _ := field.TagSettingsGet("POLYMORPHIC"); polymorphic != "" {
 | 
			
		||||
										// Dog has many toys, tag polymorphic is Owner, then associationType is Owner
 | 
			
		||||
										// Toy use OwnerID, OwnerType ('dogs') as foreign key
 | 
			
		||||
										if polymorphicType := getForeignField(polymorphic+"Type", toFields); polymorphicType != nil {
 | 
			
		||||
@ -346,7 +373,7 @@ func (scope *Scope) GetModelStruct() *ModelStruct {
 | 
			
		||||
											relationship.PolymorphicType = polymorphicType.Name
 | 
			
		||||
											relationship.PolymorphicDBName = polymorphicType.DBName
 | 
			
		||||
											// if Dog has multiple set of toys set name of the set (instead of default 'dogs')
 | 
			
		||||
											if value, ok := field.TagSettings["POLYMORPHIC_VALUE"]; ok {
 | 
			
		||||
											if value, ok := field.TagSettingsGet("POLYMORPHIC_VALUE"); ok {
 | 
			
		||||
												relationship.PolymorphicValue = value
 | 
			
		||||
											} else {
 | 
			
		||||
												relationship.PolymorphicValue = scope.TableName()
 | 
			
		||||
@ -428,17 +455,17 @@ func (scope *Scope) GetModelStruct() *ModelStruct {
 | 
			
		||||
								tagAssociationForeignKeys []string
 | 
			
		||||
							)
 | 
			
		||||
 | 
			
		||||
							if foreignKey := field.TagSettings["FOREIGNKEY"]; foreignKey != "" {
 | 
			
		||||
							if foreignKey, _ := field.TagSettingsGet("FOREIGNKEY"); foreignKey != "" {
 | 
			
		||||
								tagForeignKeys = strings.Split(foreignKey, ",")
 | 
			
		||||
							}
 | 
			
		||||
 | 
			
		||||
							if foreignKey := field.TagSettings["ASSOCIATION_FOREIGNKEY"]; foreignKey != "" {
 | 
			
		||||
							if foreignKey, _ := field.TagSettingsGet("ASSOCIATION_FOREIGNKEY"); foreignKey != "" {
 | 
			
		||||
								tagAssociationForeignKeys = strings.Split(foreignKey, ",")
 | 
			
		||||
							} else if foreignKey := field.TagSettings["ASSOCIATIONFOREIGNKEY"]; foreignKey != "" {
 | 
			
		||||
							} else if foreignKey, _ := field.TagSettingsGet("ASSOCIATIONFOREIGNKEY"); foreignKey != "" {
 | 
			
		||||
								tagAssociationForeignKeys = strings.Split(foreignKey, ",")
 | 
			
		||||
							}
 | 
			
		||||
 | 
			
		||||
							if polymorphic := field.TagSettings["POLYMORPHIC"]; polymorphic != "" {
 | 
			
		||||
							if polymorphic, _ := field.TagSettingsGet("POLYMORPHIC"); polymorphic != "" {
 | 
			
		||||
								// Cat has one toy, tag polymorphic is Owner, then associationType is Owner
 | 
			
		||||
								// Toy use OwnerID, OwnerType ('cats') as foreign key
 | 
			
		||||
								if polymorphicType := getForeignField(polymorphic+"Type", toFields); polymorphicType != nil {
 | 
			
		||||
@ -446,7 +473,7 @@ func (scope *Scope) GetModelStruct() *ModelStruct {
 | 
			
		||||
									relationship.PolymorphicType = polymorphicType.Name
 | 
			
		||||
									relationship.PolymorphicDBName = polymorphicType.DBName
 | 
			
		||||
									// if Cat has several different types of toys set name for each (instead of default 'cats')
 | 
			
		||||
									if value, ok := field.TagSettings["POLYMORPHIC_VALUE"]; ok {
 | 
			
		||||
									if value, ok := field.TagSettingsGet("POLYMORPHIC_VALUE"); ok {
 | 
			
		||||
										relationship.PolymorphicValue = value
 | 
			
		||||
									} else {
 | 
			
		||||
										relationship.PolymorphicValue = scope.TableName()
 | 
			
		||||
@ -584,7 +611,7 @@ func (scope *Scope) GetModelStruct() *ModelStruct {
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Even it is ignored, also possible to decode db value into the field
 | 
			
		||||
			if value, ok := field.TagSettings["COLUMN"]; ok {
 | 
			
		||||
			if value, ok := field.TagSettingsGet("COLUMN"); ok {
 | 
			
		||||
				field.DBName = value
 | 
			
		||||
			} else {
 | 
			
		||||
				field.DBName = ToDBName(fieldStruct.Name)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										12
									
								
								scope.go
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								scope.go
									
									
									
									
									
								
							@ -1113,8 +1113,8 @@ func (scope *Scope) createJoinTable(field *StructField) {
 | 
			
		||||
				if field, ok := scope.FieldByName(fieldName); ok {
 | 
			
		||||
					foreignKeyStruct := field.clone()
 | 
			
		||||
					foreignKeyStruct.IsPrimaryKey = false
 | 
			
		||||
					foreignKeyStruct.TagSettings["IS_JOINTABLE_FOREIGNKEY"] = "true"
 | 
			
		||||
					delete(foreignKeyStruct.TagSettings, "AUTO_INCREMENT")
 | 
			
		||||
					foreignKeyStruct.TagSettingsSet("IS_JOINTABLE_FOREIGNKEY", "true")
 | 
			
		||||
					foreignKeyStruct.TagSettingsDelete("AUTO_INCREMENT")
 | 
			
		||||
					sqlTypes = append(sqlTypes, scope.Quote(relationship.ForeignDBNames[idx])+" "+scope.Dialect().DataTypeOf(foreignKeyStruct))
 | 
			
		||||
					primaryKeys = append(primaryKeys, scope.Quote(relationship.ForeignDBNames[idx]))
 | 
			
		||||
				}
 | 
			
		||||
@ -1124,8 +1124,8 @@ func (scope *Scope) createJoinTable(field *StructField) {
 | 
			
		||||
				if field, ok := toScope.FieldByName(fieldName); ok {
 | 
			
		||||
					foreignKeyStruct := field.clone()
 | 
			
		||||
					foreignKeyStruct.IsPrimaryKey = false
 | 
			
		||||
					foreignKeyStruct.TagSettings["IS_JOINTABLE_FOREIGNKEY"] = "true"
 | 
			
		||||
					delete(foreignKeyStruct.TagSettings, "AUTO_INCREMENT")
 | 
			
		||||
					foreignKeyStruct.TagSettingsSet("IS_JOINTABLE_FOREIGNKEY", "true")
 | 
			
		||||
					foreignKeyStruct.TagSettingsDelete("AUTO_INCREMENT")
 | 
			
		||||
					sqlTypes = append(sqlTypes, scope.Quote(relationship.AssociationForeignDBNames[idx])+" "+scope.Dialect().DataTypeOf(foreignKeyStruct))
 | 
			
		||||
					primaryKeys = append(primaryKeys, scope.Quote(relationship.AssociationForeignDBNames[idx]))
 | 
			
		||||
				}
 | 
			
		||||
@ -1254,7 +1254,7 @@ func (scope *Scope) autoIndex() *Scope {
 | 
			
		||||
	var uniqueIndexes = map[string][]string{}
 | 
			
		||||
 | 
			
		||||
	for _, field := range scope.GetStructFields() {
 | 
			
		||||
		if name, ok := field.TagSettings["INDEX"]; ok {
 | 
			
		||||
		if name, ok := field.TagSettingsGet("INDEX"); ok {
 | 
			
		||||
			names := strings.Split(name, ",")
 | 
			
		||||
 | 
			
		||||
			for _, name := range names {
 | 
			
		||||
@ -1265,7 +1265,7 @@ func (scope *Scope) autoIndex() *Scope {
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if name, ok := field.TagSettings["UNIQUE_INDEX"]; ok {
 | 
			
		||||
		if name, ok := field.TagSettingsGet("UNIQUE_INDEX"); ok {
 | 
			
		||||
			names := strings.Split(name, ",")
 | 
			
		||||
 | 
			
		||||
			for _, name := range names {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user