Repository: go-gorm/gorm
Pull request #5074 (2022-02-14 19:50:13)

Fixed the use of "or" to be " OR ", to account for words that contain…
Fixed the use of "or" to be " OR ", via a constant, to account for words that contain "or" or "and" (e.g., 'score', 'band') in a sql statement as the name of a DB field. While it doesn't create an error, it's not consistent with how the other " OR " and " AND " are defined and used.

Example Currently:
```
SELECT * FROM `users` WHERE (`users`.`id` <> ? AND `age` <= ?) OR `score` <= ? got SELECT * FROM `users` WHERE (`users`.`id` <> ? AND `age` <= ?) OR (`score` <= ?)
```

is generated but, the last field should not be enclosed in parentheses it should be:
```
SELECT * FROM `users` WHERE (`users`.`id` <> ? AND `age` <= ?) OR `score` <= ? got SELECT * FROM `users` WHERE (`users`.`id` <> ? AND `age` <= ?) OR `score` <= ?
```


<!--
Make sure these boxes checked before submitting your pull request.

For significant changes, please open an issue to make an agreement on an implementation design/plan first before starting it.
-->

- [X] Do only one thing
- [X] Non breaking API changes
- [X] Tested

### What did this pull request do?

<!--
provide a general description of the code changes in your pull request
-->

1. Adds a constant to use " OR " and " AND ", when looking for a 'or' or 'and' in a SQL statement. Also replaced `.ToLower` to `.ToUpper`, to make functionality consistent.
2. Added a few test cases that increased the code coverage to 79.7% of `where.go`


### User Case Description

<!-- Your use case -->
When providing a `clause.Expr{}` and includes a word that contains `or` within it (like `score`), it should not enclose "\`score\` <= ?" in parentheses "(\`score\` <= ?)"

Here is one of the test case that were added to `where_test.go`
```
		{
			[]clause.Interface{clause.Select{}, clause.From{}, clause.Where{
				Exprs: []clause.Expression{clause.Not(clause.Eq{Column: clause.PrimaryColumn, Value: "1"}, clause.Gt{Column: "age", Value: 18}), clause.Or(clause.Expr{SQL: "`score` <= ?", Vars: []interface{}{100}, WithoutParentheses: false})},
			}},
			"SELECT * FROM `users` WHERE (`users`.`id` <> ? AND `age` <= ?) OR `score` <= ?",
			[]interface{}{"1", 18, 100},
		},

```

sammyrnycreal: @daheige Not sure if you will be able to review this PR? Let me know if it makes sense or if I need to make an adjustment.
daheige: For this PR，LGTM！That's a good suggestion. I agree.


------------------ Original ------------------
From: sammyrnycreal ***@***.***&gt;
Date: Tue,Feb 15,2022 5:40 AM
To: go-gorm/gorm ***@***.***&gt;
Cc: heige ***@***.***&gt;, Mention ***@***.***&gt;
Subject: Re: [go-gorm/gorm] Fixed the use of "or" to be " OR ", to account for words that contain… (PR #5074)





 
@daheige Not sure if you will be able to review this PR? Let me know if it makes sense or if I need to make an adjustment.
 
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications on the go with GitHub Mobile for iOS or Android. 
You are receiving this because you were mentioned.Message ID: ***@***.***&gt;

Patch:
diff --git a/.github/workflows/invalid_question.yml b/.github/workflows/invalid_question.yml
index dfd2ddd..868bcc3 100644
--- a/.github/workflows/invalid_question.yml
+++ b/.github/workflows/invalid_question.yml
@@ -13,10 +13,10 @@ jobs:
       uses: actions/stale@v4
       with:
         repo-token: ${{ secrets.GITHUB_TOKEN }}
-        stale-issue-message: "This issue has been marked as invalid question, please give more information by following the `Question` template, if you believe there is a bug of GORM, please create a pull request that could reproduce the issue on [https://github.com/go-gorm/playground](https://github.com/go-gorm/playground), the issue will be closed in 2 days if no further activity occurs. most likely your question already answered https://github.com/go-gorm/gorm/issues or described in the document https://gorm.io ✨ [Search Before Asking](https://stackoverflow.com/help/how-to-ask) ✨"
+        stale-issue-message: "This issue has been marked as invalid question, please give more information by following the `Question` template, if you believe there is a bug of GORM, please create a pull request that could reproduce the issue on [https://github.com/go-gorm/playground](https://github.com/go-gorm/playground), the issue will be closed in 30 days if no further activity occurs. most likely your question already answered https://github.com/go-gorm/gorm/issues or described in the document https://gorm.io ✨ [Search Before Asking](https://stackoverflow.com/help/how-to-ask) ✨"
         stale-issue-label: "status:stale"
         days-before-stale: 0
-        days-before-close: 2
+        days-before-close: 30
         remove-stale-when-updated: true
         only-labels: "type:invalid question"
 
diff --git a/.github/workflows/missing_playground.yml b/.github/workflows/missing_playground.yml
index cdb097d..3efc90f 100644
--- a/.github/workflows/missing_playground.yml
+++ b/.github/workflows/missing_playground.yml
@@ -13,9 +13,9 @@ jobs:
       uses: actions/stale@v4
       with:
         repo-token: ${{ secrets.GITHUB_TOKEN }}
-        stale-issue-message: "The issue has been automatically marked as stale as it missing playground pull request link, which is important to help others understand your issue effectively and make sure the issue hasn't been fixed on latest master, checkout [https://github.com/go-gorm/playground](https://github.com/go-gorm/playground) for details. it will be closed in 2 days if no further activity occurs. if you are asking question, please use the `Question` template, most likely your question already answered https://github.com/go-gorm/gorm/issues or described in the document https://gorm.io ✨ [Search Before Asking](https://stackoverflow.com/help/how-to-ask) ✨"
+        stale-issue-message: "The issue has been automatically marked as stale as it missing playground pull request link, which is important to help others understand your issue effectively and make sure the issue hasn't been fixed on latest master, checkout [https://github.com/go-gorm/playground](https://github.com/go-gorm/playground) for details. it will be closed in 30 days if no further activity occurs. if you are asking question, please use the `Question` template, most likely your question already answered https://github.com/go-gorm/gorm/issues or described in the document https://gorm.io ✨ [Search Before Asking](https://stackoverflow.com/help/how-to-ask) ✨"
         stale-issue-label: "status:stale"
         days-before-stale: 0
-        days-before-close: 2
+        days-before-close: 30
         remove-stale-when-updated: true
         only-labels: "type:missing reproduction steps"
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
index d541929..e0be186 100644
--- a/.github/workflows/stale.yml
+++ b/.github/workflows/stale.yml
@@ -13,9 +13,9 @@ jobs:
       uses: actions/stale@v4
       with:
         repo-token: ${{ secrets.GITHUB_TOKEN }}
-        stale-issue-message: "This issue has been automatically marked as stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 30 days"
-        days-before-stale: 60
-        days-before-close: 30
+        stale-issue-message: "This issue has been automatically marked as stale because it has been open 360 days with no activity. Remove stale label or comment or this will be closed in 180 days"
+        days-before-stale: 360
+        days-before-close: 180
         stale-issue-label: "status:stale"
         exempt-issue-labels: 'type:feature,type:with reproduction steps,type:has pull request'
         stale-pr-label: 'status:stale'
diff --git a/association.go b/association.go
index 62c25b7..09e79ca 100644
--- a/association.go
+++ b/association.go
@@ -79,10 +79,10 @@ func (association *Association) Replace(values ...interface{}) error {
 				switch reflectValue.Kind() {
 				case reflect.Slice, reflect.Array:
 					for i := 0; i < reflectValue.Len(); i++ {
-						association.Error = rel.Field.Set(reflectValue.Index(i), reflect.Zero(rel.Field.FieldType).Interface())
+						association.Error = rel.Field.Set(association.DB.Statement.Context, reflectValue.Index(i), reflect.Zero(rel.Field.FieldType).Interface())
 					}
 				case reflect.Struct:
-					association.Error = rel.Field.Set(reflectValue, reflect.Zero(rel.Field.FieldType).Interface())
+					association.Error = rel.Field.Set(association.DB.Statement.Context, reflectValue, reflect.Zero(rel.Field.FieldType).Interface())
 				}
 
 				for _, ref := range rel.References {
@@ -96,12 +96,12 @@ func (association *Association) Replace(values ...interface{}) error {
 				primaryFields []*schema.Field
 				foreignKeys   []string
 				updateMap     = map[string]interface{}{}
-				relValues     = schema.GetRelationsValues(reflectValue, []*schema.Relationship{rel})
+				relValues     = schema.GetRelationsValues(association.DB.Statement.Context, reflectValue, []*schema.Relationship{rel})
 				modelValue    = reflect.New(rel.FieldSchema.ModelType).Interface()
 				tx            = association.DB.Model(modelValue)
 			)
 
-			if _, rvs := schema.GetIdentityFieldValuesMap(relValues, rel.FieldSchema.PrimaryFields); len(rvs) > 0 {
+			if _, rvs := schema.GetIdentityFieldValuesMap(association.DB.Statement.Context, relValues, rel.FieldSchema.PrimaryFields); len(rvs) > 0 {
 				if column, values := schema.ToQueryValues(rel.FieldSchema.Table, rel.FieldSchema.PrimaryFieldDBNames, rvs); len(values) > 0 {
 					tx.Not(clause.IN{Column: column, Values: values})
 				}
@@ -117,7 +117,7 @@ func (association *Association) Replace(values ...interface{}) error {
 				}
 			}
 
-			if _, pvs := schema.GetIdentityFieldValuesMap(reflectValue, primaryFields); len(pvs) > 0 {
+			if _, pvs := schema.GetIdentityFieldValuesMap(association.DB.Statement.Context, reflectValue, primaryFields); len(pvs) > 0 {
 				column, values := schema.ToQueryValues(rel.FieldSchema.Table, foreignKeys, pvs)
 				association.Error = tx.Where(clause.IN{Column: column, Values: values}).UpdateColumns(updateMap).Error
 			}
@@ -143,14 +143,14 @@ func (association *Association) Replace(values ...interface{}) error {
 				}
 			}
 
-			_, pvs := schema.GetIdentityFieldValuesMap(reflectValue, primaryFields)
+			_, pvs := schema.GetIdentityFieldValuesMap(association.DB.Statement.Context, reflectValue, primaryFields)
 			if column, values := schema.ToQueryValues(rel.JoinTable.Table, joinPrimaryKeys, pvs); len(values) > 0 {
 				tx.Where(clause.IN{Column: column, Values: values})
 			} else {
 				return ErrPrimaryKeyRequired
 			}
 
-			_, rvs := schema.GetIdentityFieldValuesMapFromValues(values, relPrimaryFields)
+			_, rvs := schema.GetIdentityFieldValuesMapFromValues(association.DB.Statement.Context, values, relPrimaryFields)
 			if relColumn, relValues := schema.ToQueryValues(rel.JoinTable.Table, joinRelPrimaryKeys, rvs); len(relValues) > 0 {
 				tx.Where(clause.Not(clause.IN{Column: relColumn, Values: relValues}))
 			}
@@ -186,11 +186,11 @@ func (association *Association) Delete(values ...interface{}) error {
 		case schema.BelongsTo:
 			tx := association.DB.Model(reflect.New(rel.Schema.ModelType).Interface())
 
-			_, pvs := schema.GetIdentityFieldValuesMap(reflectValue, rel.Schema.PrimaryFields)
+			_, pvs := schema.GetIdentityFieldValuesMap(association.DB.Statement.Context, reflectValue, rel.Schema.PrimaryFields)
 			pcolumn, pvalues := schema.ToQueryValues(rel.Schema.Table, rel.Schema.PrimaryFieldDBNames, pvs)
 			conds = append(conds, clause.IN{Column: pcolumn, Values: pvalues})
 
-			_, rvs := schema.GetIdentityFieldValuesMapFromValues(values, primaryFields)
+			_, rvs := schema.GetIdentityFieldValuesMapFromValues(association.DB.Statement.Context, values, primaryFields)
 			relColumn, relValues := schema.ToQueryValues(rel.Schema.Table, foreignKeys, rvs)
 			conds = append(conds, clause.IN{Column: relColumn, Values: relValues})
 
@@ -198,11 +198,11 @@ func (association *Association) Delete(values ...interface{}) error {
 		case schema.HasOne, schema.HasMany:
 			tx := association.DB.Model(reflect.New(rel.FieldSchema.ModelType).Interface())
 
-			_, pvs := schema.GetIdentityFieldValuesMap(reflectValue, primaryFields)
+			_, pvs := schema.GetIdentityFieldValuesMap(association.DB.Statement.Context, reflectValue, primaryFields)
 			pcolumn, pvalues := schema.ToQueryValues(rel.FieldSchema.Table, foreignKeys, pvs)
 			conds = append(conds, clause.IN{Column: pcolumn, Values: pvalues})
 
-			_, rvs := schema.GetIdentityFieldValuesMapFromValues(values, rel.FieldSchema.PrimaryFields)
+			_, rvs := schema.GetIdentityFieldValuesMapFromValues(association.DB.Statement.Context, values, rel.FieldSchema.PrimaryFields)
 			relColumn, relValues := schema.ToQueryValues(rel.FieldSchema.Table, rel.FieldSchema.PrimaryFieldDBNames, rvs)
 			conds = append(conds, clause.IN{Column: relColumn, Values: relValues})
 
@@ -228,11 +228,11 @@ func (association *Association) Delete(values ...interface{}) error {
 				}
 			}
 
-			_, pvs := schema.GetIdentityFieldValuesMap(reflectValue, primaryFields)
+			_, pvs := schema.GetIdentityFieldValuesMap(association.DB.Statement.Context, reflectValue, primaryFields)
 			pcolumn, pvalues := schema.ToQueryValues(rel.JoinTable.Table, joinPrimaryKeys, pvs)
 			conds = append(conds, clause.IN{Column: pcolumn, Values: pvalues})
 
-			_, rvs := schema.GetIdentityFieldValuesMapFromValues(values, relPrimaryFields)
+			_, rvs := schema.GetIdentityFieldValuesMapFromValues(association.DB.Statement.Context, values, relPrimaryFields)
 			relColumn, relValues := schema.ToQueryValues(rel.JoinTable.Table, joinRelPrimaryKeys, rvs)
 			conds = append(conds, clause.IN{Column: relColumn, Values: relValues})
 
@@ -241,11 +241,11 @@ func (association *Association) Delete(values ...interface{}) error {
 
 		if association.Error == nil {
 			// clean up deleted values's foreign key
-			relValuesMap, _ := schema.GetIdentityFieldValuesMapFromValues(values, rel.FieldSchema.PrimaryFields)
+			relValuesMap, _ := schema.GetIdentityFieldValuesMapFromValues(association.DB.Statement.Context, values, rel.FieldSchema.PrimaryFields)
 
 			cleanUpDeletedRelations := func(data reflect.Value) {
-				if _, zero := rel.Field.ValueOf(data); !zero {
-					fieldValue := reflect.Indirect(rel.Field.ReflectValueOf(data))
+				if _, zero := rel.Field.ValueOf(association.DB.Statement.Context, data); !zero {
+					fieldValue := reflect.Indirect(rel.Field.ReflectValueOf(association.DB.Statement.Context, data))
 					primaryValues := make([]interface{}, len(rel.FieldSchema.PrimaryFields))
 
 					switch fieldValue.Kind() {
@@ -253,7 +253,7 @@ func (association *Association) Delete(values ...interface{}) error {
 						validFieldValues := reflect.Zero(rel.Field.IndirectFieldType)
 						for i := 0; i < fieldValue.Len(); i++ {
 							for idx, field := range rel.FieldSchema.PrimaryFields {
-								primaryValues[idx], _ = field.ValueOf(fieldValue.Index(i))
+								primaryValues[idx], _ = field.ValueOf(association.DB.Statement.Context, fieldValue.Index(i))
 							}
 
 							if _, ok := relValuesMap[utils.ToStringKey(primaryValues...)]; !ok {
@@ -261,23 +261,23 @@ func (association *Association) Delete(values ...interface{}) error {
 							}
 						}
 
-						association.Error = rel.Field.Set(data, validFieldValues.Interface())
+						association.Error = rel.Field.Set(association.DB.Statement.Context, data, validFieldValues.Interface())
 					case reflect.Struct:
 						for idx, field := range rel.FieldSchema.PrimaryFields {
-							primaryValues[idx], _ = field.ValueOf(fieldValue)
+							primaryValues[idx], _ = field.ValueOf(association.DB.Statement.Context, fieldValue)
 						}
 
 						if _, ok := relValuesMap[utils.ToStringKey(primaryValues...)]; ok {
-							if association.Error = rel.Field.Set(data, reflect.Zero(rel.FieldSchema.ModelType).Interface()); association.Error != nil {
+							if association.Error = rel.Field.Set(association.DB.Statement.Context, data, reflect.Zero(rel.FieldSchema.ModelType).Interface()); association.Error != nil {
 								break
 							}
 
 							if rel.JoinTable == nil {
 								for _, ref := range rel.References {
 									if ref.OwnPrimaryKey || ref.PrimaryValue != "" {
-										association.Error = ref.ForeignKey.Set(fieldValue, reflect.Zero(ref.ForeignKey.FieldType).Interface())
+										association.Error = ref.ForeignKey.Set(association.DB.Statement.Context, fieldValue, reflect.Zero(ref.ForeignKey.FieldType).Interface())
 									} else {
-										association.Error = ref.ForeignKey.Set(data, reflect.Zero(ref.ForeignKey.FieldType).Interface())
+										association.Error = ref.ForeignKey.Set(association.DB.Statement.Context, data, reflect.Zero(ref.ForeignKey.FieldType).Interface())
 									}
 								}
 							}
@@ -329,14 +329,14 @@ func (association *Association) saveAssociation(clear bool, values ...interface{
 			switch rv.Kind() {
 			case reflect.Slice, reflect.Array:
 				if rv.Len() > 0 {
-					association.Error = association.Relationship.Field.Set(source, rv.Index(0).Addr().Interface())
+					association.Error = association.Relationship.Field.Set(association.DB.Statement.Context, source, rv.Index(0).Addr().Interface())
 
 					if association.Relationship.Field.FieldType.Kind() == reflect.Struct {
 						assignBacks = append(assignBacks, assignBack{Source: source, Dest: rv.Index(0)})
 					}
 				}
 			case reflect.Struct:
-				association.Error = association.Relationship.Field.Set(source, rv.Addr().Interface())
+				association.Error = association.Relationship.Field.Set(association.DB.Statement.Context, source, rv.Addr().Interface())
 
 				if association.Relationship.Field.FieldType.Kind() == reflect.Struct {
 					assignBacks = append(assignBacks, assignBack{Source: source, Dest: rv})
@@ -344,7 +344,7 @@ func (association *Association) saveAssociation(clear bool, values ...interface{
 			}
 		case schema.HasMany, schema.Many2Many:
 			elemType := association.Relationship.Field.IndirectFieldType.Elem()
-			fieldValue := reflect.Indirect(association.Relationship.Field.ReflectValueOf(source))
+			fieldValue := reflect.Indirect(association.Relationship.Field.ReflectValueOf(association.DB.Statement.Context, source))
 			if clear {
 				fieldValue = reflect.New(association.Relationship.Field.IndirectFieldType).Elem()
 			}
@@ -373,7 +373,7 @@ func (association *Association) saveAssociation(clear bool, values ...interface{
 			}
 
 			if association.Error == nil {
-				association.Error = association.Relationship.Field.Set(source, fieldValue.Interface())
+				association.Error = association.Relationship.Field.Set(association.DB.Statement.Context, source, fieldValue.Interface())
 			}
 		}
 	}
@@ -421,7 +421,7 @@ func (association *Association) saveAssociation(clear bool, values ...interface{
 			// clear old data
 			if clear && len(values) == 0 {
 				for i := 0; i < reflectValue.Len(); i++ {
-					if err := association.Relationship.Field.Set(reflectValue.Index(i), reflect.New(association.Relationship.Field.IndirectFieldType).Interface()); err != nil {
+					if err := association.Relationship.Field.Set(association.DB.Statement.Context, reflectValue.Index(i), reflect.New(association.Relationship.Field.IndirectFieldType).Interface()); err != nil {
 						association.Error = err
 						break
 					}
@@ -429,7 +429,7 @@ func (association *Association) saveAssociation(clear bool, values ...interface{
 					if association.Relationship.JoinTable == nil {
 						for _, ref := range association.Relationship.References {
 							if !ref.OwnPrimaryKey && ref.PrimaryValue == "" {
-								if err := ref.ForeignKey.Set(reflectValue.Index(i), reflect.Zero(ref.ForeignKey.FieldType).Interface()); err != nil {
+								if err := ref.ForeignKey.Set(association.DB.Statement.Context, reflectValue.Index(i), reflect.Zero(ref.ForeignKey.FieldType).Interface()); err != nil {
 									association.Error = err
 									break
 								}
@@ -453,12 +453,12 @@ func (association *Association) saveAssociation(clear bool, values ...interface{
 	case reflect.Struct:
 		// clear old data
 		if clear && len(values) == 0 {
-			association.Error = association.Relationship.Field.Set(reflectValue, reflect.New(association.Relationship.Field.IndirectFieldType).Interface())
+			association.Error = association.Relationship.Field.Set(association.DB.Statement.Context, reflectValue, reflect.New(association.Relationship.Field.IndirectFieldType).Interface())
 
 			if association.Relationship.JoinTable == nil && association.Error == nil {
 				for _, ref := range association.Relationship.References {
 					if !ref.OwnPrimaryKey && ref.PrimaryValue == "" {
-						association.Error = ref.ForeignKey.Set(reflectValue, reflect.Zero(ref.ForeignKey.FieldType).Interface())
+						association.Error = ref.ForeignKey.Set(association.DB.Statement.Context, reflectValue, reflect.Zero(ref.ForeignKey.FieldType).Interface())
 					}
 				}
 			}
@@ -475,7 +475,7 @@ func (association *Association) saveAssociation(clear bool, values ...interface{
 	}
 
 	for _, assignBack := range assignBacks {
-		fieldValue := reflect.Indirect(association.Relationship.Field.ReflectValueOf(assignBack.Source))
+		fieldValue := reflect.Indirect(association.Relationship.Field.ReflectValueOf(association.DB.Statement.Context, assignBack.Source))
 		if assignBack.Index > 0 {
 			reflect.Indirect(assignBack.Dest).Set(fieldValue.Index(assignBack.Index - 1))
 		} else {
@@ -486,7 +486,7 @@ func (association *Association) saveAssociation(clear bool, values ...interface{
 
 func (association *Association) buildCondition() *DB {
 	var (
-		queryConds = association.Relationship.ToQueryConditions(association.DB.Statement.ReflectValue)
+		queryConds = association.Relationship.ToQueryConditions(association.DB.Statement.Context, association.DB.Statement.ReflectValue)
 		modelValue = reflect.New(association.Relationship.FieldSchema.ModelType).Interface()
 		tx         = association.DB.Model(modelValue)
 	)
diff --git a/callbacks/associations.go b/callbacks/associations.go
index 75bd6c6..d6fd21d 100644
--- a/callbacks/associations.go
+++ b/callbacks/associations.go
@@ -24,8 +24,8 @@ func SaveBeforeAssociations(create bool) func(db *gorm.DB) {
 				setupReferences := func(obj reflect.Value, elem reflect.Value) {
 					for _, ref := range rel.References {
 						if !ref.OwnPrimaryKey {
-							pv, _ := ref.PrimaryKey.ValueOf(elem)
-							db.AddError(ref.ForeignKey.Set(obj, pv))
+							pv, _ := ref.PrimaryKey.ValueOf(db.Statement.Context, elem)
+							db.AddError(ref.ForeignKey.Set(db.Statement.Context, obj, pv))
 
 							if dest, ok := db.Statement.Dest.(map[string]interface{}); ok {
 								dest[ref.ForeignKey.DBName] = pv
@@ -57,8 +57,8 @@ func SaveBeforeAssociations(create bool) func(db *gorm.DB) {
 							break
 						}
 
-						if _, zero := rel.Field.ValueOf(obj); !zero { // check belongs to relation value
-							rv := rel.Field.ReflectValueOf(obj) // relation reflect value
+						if _, zero := rel.Field.ValueOf(db.Statement.Context, obj); !zero { // check belongs to relation value
+							rv := rel.Field.ReflectValueOf(db.Statement.Context, obj) // relation reflect value
 							objs = append(objs, obj)
 							if isPtr {
 								elems = reflect.Append(elems, rv)
@@ -76,8 +76,8 @@ func SaveBeforeAssociations(create bool) func(db *gorm.DB) {
 						}
 					}
 				case reflect.Struct:
-					if _, zero := rel.Field.ValueOf(db.Statement.ReflectValue); !zero {
-						rv := rel.Field.ReflectValueOf(db.Statement.ReflectValue) // relation reflect value
+					if _, zero := rel.Field.ValueOf(db.Statement.Context, db.Statement.ReflectValue); !zero {
+						rv := rel.Field.ReflectValueOf(db.Statement.Context, db.Statement.ReflectValue) // relation reflect value
 						if rv.Kind() != reflect.Ptr {
 							rv = rv.Addr()
 						}
@@ -120,18 +120,18 @@ func SaveAfterAssociations(create bool) func(db *gorm.DB) {
 						obj := db.Statement.ReflectValue.Index(i)
 
 						if reflect.Indirect(obj).Kind() == reflect.Struct {
-							if _, zero := rel.Field.ValueOf(obj); !zero {
-								rv := rel.Field.ReflectValueOf(obj)
+							if _, zero := rel.Field.ValueOf(db.Statement.Context, obj); !zero {
+								rv := rel.Field.ReflectValueOf(db.Statement.Context, obj)
 								if rv.Kind() != reflect.Ptr {
 									rv = rv.Addr()
 								}
 
 								for _, ref := range rel.References {
 									if ref.OwnPrimaryKey {
-										fv, _ := ref.PrimaryKey.ValueOf(obj)
-										db.AddError(ref.ForeignKey.Set(rv, fv))
+										fv, _ := ref.PrimaryKey.ValueOf(db.Statement.Context, obj)
+										db.AddError(ref.ForeignKey.Set(db.Statement.Context, rv, fv))
 									} else if ref.PrimaryValue != "" {
-										db.AddError(ref.ForeignKey.Set(rv, ref.PrimaryValue))
+										db.AddError(ref.ForeignKey.Set(db.Statement.Context, rv, ref.PrimaryValue))
 									}
 								}
 
@@ -149,8 +149,8 @@ func SaveAfterAssociations(create bool) func(db *gorm.DB) {
 						saveAssociations(db, rel, elems.Interface(), selectColumns, restricted, assignmentColumns)
 					}
 				case reflect.Struct:
-					if _, zero := rel.Field.ValueOf(db.Statement.ReflectValue); !zero {
-						f := rel.Field.ReflectValueOf(db.Statement.ReflectValue)
+					if _, zero := rel.Field.ValueOf(db.Statement.Context, db.Statement.ReflectValue); !zero {
+						f := rel.Field.ReflectValueOf(db.Statement.Context, db.Statement.ReflectValue)
 						if f.Kind() != reflect.Ptr {
 							f = f.Addr()
 						}
@@ -158,10 +158,10 @@ func SaveAfterAssociations(create bool) func(db *gorm.DB) {
 						assignmentColumns := make([]string, 0, len(rel.References))
 						for _, ref := range rel.References {
 							if ref.OwnPrimaryKey {
-								fv, _ := ref.PrimaryKey.ValueOf(db.Statement.ReflectValue)
-								ref.ForeignKey.Set(f, fv)
+								fv, _ := ref.PrimaryKey.ValueOf(db.Statement.Context, db.Statement.ReflectValue)
+								ref.ForeignKey.Set(db.Statement.Context, f, fv)
 							} else if ref.PrimaryValue != "" {
-								ref.ForeignKey.Set(f, ref.PrimaryValue)
+								ref.ForeignKey.Set(db.Statement.Context, f, ref.PrimaryValue)
 							}
 							assignmentColumns = append(assignmentColumns, ref.ForeignKey.DBName)
 						}
@@ -185,23 +185,23 @@ func SaveAfterAssociations(create bool) func(db *gorm.DB) {
 				elems := reflect.MakeSlice(reflect.SliceOf(fieldType), 0, 10)
 				identityMap := map[string]bool{}
 				appendToElems := func(v reflect.Value) {
-					if _, zero := rel.Field.ValueOf(v); !zero {
-						f := reflect.Indirect(rel.Field.ReflectValueOf(v))
+					if _, zero := rel.Field.ValueOf(db.Statement.Context, v); !zero {
+						f := reflect.Indirect(rel.Field.ReflectValueOf(db.Statement.Context, v))
 
 						for i := 0; i < f.Len(); i++ {
 							elem := f.Index(i)
 							for _, ref := range rel.References {
 								if ref.OwnPrimaryKey {
-									pv, _ := ref.PrimaryKey.ValueOf(v)
-									ref.ForeignKey.Set(elem, pv)
+									pv, _ := ref.PrimaryKey.ValueOf(db.Statement.Context, v)
+									ref.ForeignKey.Set(db.Statement.Context, elem, pv)
 								} else if ref.PrimaryValue != "" {
-									ref.ForeignKey.Set(elem, ref.PrimaryValue)
+									ref.ForeignKey.Set(db.Statement.Context, elem, ref.PrimaryValue)
 								}
 							}
 
 							relPrimaryValues := make([]interface{}, 0, len(rel.FieldSchema.PrimaryFields))
 							for _, pf := range rel.FieldSchema.PrimaryFields {
-								if pfv, ok := pf.ValueOf(elem); !ok {
+								if pfv, ok := pf.ValueOf(db.Statement.Context, elem); !ok {
 									relPrimaryValues = append(relPrimaryValues, pfv)
 								}
 							}
@@ -260,21 +260,21 @@ func SaveAfterAssociations(create bool) func(db *gorm.DB) {
 					joinValue := reflect.New(rel.JoinTable.ModelType)
 					for _, ref := range rel.References {
 						if ref.OwnPrimaryKey {
-							fv, _ := ref.PrimaryKey.ValueOf(obj)
-							ref.ForeignKey.Set(joinValue, fv)
+							fv, _ := ref.PrimaryKey.ValueOf(db.Statement.Context, obj)
+							ref.ForeignKey.Set(db.Statement.Context, joinValue, fv)
 						} else if ref.PrimaryValue != "" {
-							ref.ForeignKey.Set(joinValue, ref.PrimaryValue)
+							ref.ForeignKey.Set(db.Statement.Context, joinValue, ref.PrimaryValue)
 						} else {
-							fv, _ := ref.PrimaryKey.ValueOf(elem)
-							ref.ForeignKey.Set(joinValue, fv)
+							fv, _ := ref.PrimaryKey.ValueOf(db.Statement.Context, elem)
+							ref.ForeignKey.Set(db.Statement.Context, joinValue, fv)
 						}
 					}
 					joins = reflect.Append(joins, joinValue)
 				}
 
 				appendToElems := func(v reflect.Value) {
-					if _, zero := rel.Field.ValueOf(v); !zero {
-						f := reflect.Indirect(rel.Field.ReflectValueOf(v))
+					if _, zero := rel.Field.ValueOf(db.Statement.Context, v); !zero {
+						f := reflect.Indirect(rel.Field.ReflectValueOf(db.Statement.Context, v))
 
 						for i := 0; i < f.Len(); i++ {
 							elem := f.Index(i)
diff --git a/callbacks/create.go b/callbacks/create.go
index 2911312..b0964e2 100644
--- a/callbacks/create.go
+++ b/callbacks/create.go
@@ -117,9 +117,9 @@ func Create(config *Config) func(db *gorm.DB) {
 							break
 						}
 
-						_, isZero := db.Statement.Schema.PrioritizedPrimaryField.ValueOf(rv)
+						_, isZero := db.Statement.Schema.PrioritizedPrimaryField.ValueOf(db.Statement.Context, rv)
 						if isZero {
-							db.Statement.Schema.PrioritizedPrimaryField.Set(rv, insertID)
+							db.Statement.Schema.PrioritizedPrimaryField.Set(db.Statement.Context, rv, insertID)
 							insertID -= db.Statement.Schema.PrioritizedPrimaryField.AutoIncrementIncrement
 						}
 					}
@@ -130,16 +130,16 @@ func Create(config *Config) func(db *gorm.DB) {
 							break
 						}
 
-						if _, isZero := db.Statement.Schema.PrioritizedPrimaryField.ValueOf(rv); isZero {
-							db.Statement.Schema.PrioritizedPrimaryField.Set(rv, insertID)
+						if _, isZero := db.Statement.Schema.PrioritizedPrimaryField.ValueOf(db.Statement.Context, rv); isZero {
+							db.Statement.Schema.PrioritizedPrimaryField.Set(db.Statement.Context, rv, insertID)
 							insertID += db.Statement.Schema.PrioritizedPrimaryField.AutoIncrementIncrement
 						}
 					}
 				}
 			case reflect.Struct:
-				_, isZero := db.Statement.Schema.PrioritizedPrimaryField.ValueOf(db.Statement.ReflectValue)
+				_, isZero := db.Statement.Schema.PrioritizedPrimaryField.ValueOf(db.Statement.Context, db.Statement.ReflectValue)
 				if isZero {
-					db.Statement.Schema.PrioritizedPrimaryField.Set(db.Statement.ReflectValue, insertID)
+					db.Statement.Schema.PrioritizedPrimaryField.Set(db.Statement.Context, db.Statement.ReflectValue, insertID)
 				}
 			}
 		}
@@ -219,23 +219,23 @@ func ConvertToCreateValues(stmt *gorm.Statement) (values clause.Values) {
 				values.Values[i] = make([]interface{}, len(values.Columns))
 				for idx, column := range values.Columns {
 					field := stmt.Schema.FieldsByDBName[column.Name]
-					if values.Values[i][idx], isZero = field.ValueOf(rv); isZero {
+					if values.Values[i][idx], isZero = field.ValueOf(stmt.Context, rv); isZero {
 						if field.DefaultValueInterface != nil {
 							values.Values[i][idx] = field.DefaultValueInterface
-							field.Set(rv, field.DefaultValueInterface)
+							field.Set(stmt.Context, rv, field.DefaultValueInterface)
 						} else if field.AutoCreateTime > 0 || field.AutoUpdateTime > 0 {
-							field.Set(rv, curTime)
-							values.Values[i][idx], _ = field.ValueOf(rv)
+							field.Set(stmt.Context, rv, curTime)
+							values.Values[i][idx], _ = field.ValueOf(stmt.Context, rv)
 						}
 					} else if field.AutoUpdateTime > 0 && updateTrackTime {
-						field.Set(rv, curTime)
-						values.Values[i][idx], _ = field.ValueOf(rv)
+						field.Set(stmt.Context, rv, curTime)
+						values.Values[i][idx], _ = field.ValueOf(stmt.Context, rv)
 					}
 				}
 
 				for _, field := range stmt.Schema.FieldsWithDefaultDBValue {
 					if v, ok := selectColumns[field.DBName]; (ok && v) || (!ok && !restricted) {
-						if rvOfvalue, isZero := field.ValueOf(rv); !isZero {
+						if rvOfvalue, isZero := field.ValueOf(stmt.Context, rv); !isZero {
 							if len(defaultValueFieldsHavingValue[field]) == 0 {
 								defaultValueFieldsHavingValue[field] = make([]interface{}, rValLen)
 							}
@@ -259,23 +259,23 @@ func ConvertToCreateValues(stmt *gorm.Statement) (values clause.Values) {
 			values.Values = [][]interface{}{make([]interface{}, len(values.Columns))}
 			for idx, column := range values.Columns {
 				field := stmt.Schema.FieldsByDBName[column.Name]
-				if values.Values[0][idx], isZero = field.ValueOf(stmt.ReflectValue); isZero {
+				if values.Values[0][idx], isZero = field.ValueOf(stmt.Context, stmt.ReflectValue); isZero {
 					if field.DefaultValueInterface != nil {
 						values.Values[0][idx] = field.DefaultValueInterface
-						field.Set(stmt.ReflectValue, field.DefaultValueInterface)
+						field.Set(stmt.Context, stmt.ReflectValue, field.DefaultValueInterface)
 					} else if field.AutoCreateTime > 0 || field.AutoUpdateTime > 0 {
-						field.Set(stmt.ReflectValue, curTime)
-						values.Values[0][idx], _ = field.ValueOf(stmt.ReflectValue)
+						field.Set(stmt.Context, stmt.ReflectValue, curTime)
+						values.Values[0][idx], _ = field.ValueOf(stmt.Context, stmt.ReflectValue)
 					}
 				} else if field.AutoUpdateTime > 0 && updateTrackTime {
-					field.Set(stmt.ReflectValue, curTime)
-					values.Values[0][idx], _ = field.ValueOf(stmt.ReflectValue)
+					field.Set(stmt.Context, stmt.ReflectValue, curTime)
+					values.Values[0][idx], _ = field.ValueOf(stmt.Context, stmt.ReflectValue)
 				}
 			}
 
 			for _, field := range stmt.Schema.FieldsWithDefaultDBValue {
 				if v, ok := selectColumns[field.DBName]; (ok && v) || (!ok && !restricted) {
-					if rvOfvalue, isZero := field.ValueOf(stmt.ReflectValue); !isZero {
+					if rvOfvalue, isZero := field.ValueOf(stmt.Context, stmt.ReflectValue); !isZero {
 						values.Columns = append(values.Columns, clause.Column{Name: field.DBName})
 						values.Values[0] = append(values.Values[0], rvOfvalue)
 					}
diff --git a/callbacks/delete.go b/callbacks/delete.go
index 7f1e09c..1fb5261 100644
--- a/callbacks/delete.go
+++ b/callbacks/delete.go
@@ -42,7 +42,7 @@ func DeleteBeforeAssociations(db *gorm.DB) {
 
 			switch rel.Type {
 			case schema.HasOne, schema.HasMany:
-				queryConds := rel.ToQueryConditions(db.Statement.ReflectValue)
+				queryConds := rel.ToQueryConditions(db.Statement.Context, db.Statement.ReflectValue)
 				modelValue := reflect.New(rel.FieldSchema.ModelType).Interface()
 				tx := db.Session(&gorm.Session{NewDB: true}).Model(modelValue)
 				withoutConditions := false
@@ -97,7 +97,7 @@ func DeleteBeforeAssociations(db *gorm.DB) {
 					}
 				}
 
-				_, foreignValues := schema.GetIdentityFieldValuesMap(db.Statement.ReflectValue, foreignFields)
+				_, foreignValues := schema.GetIdentityFieldValuesMap(db.Statement.Context, db.Statement.ReflectValue, foreignFields)
 				column, values := schema.ToQueryValues(table, relForeignKeys, foreignValues)
 				queryConds = append(queryConds, clause.IN{Column: column, Values: values})
 
@@ -123,7 +123,7 @@ func Delete(config *Config) func(db *gorm.DB) {
 			db.Statement.AddClauseIfNotExists(clause.Delete{})
 
 			if db.Statement.Schema != nil {
-				_, queryValues := schema.GetIdentityFieldValuesMap(db.Statement.ReflectValue, db.Statement.Schema.PrimaryFields)
+				_, queryValues := schema.GetIdentityFieldValuesMap(db.Statement.Context, db.Statement.ReflectValue, db.Statement.Schema.PrimaryFields)
 				column, values := schema.ToQueryValues(db.Statement.Table, db.Statement.Schema.PrimaryFieldDBNames, queryValues)
 
 				if len(values) > 0 {
@@ -131,7 +131,7 @@ func Delete(config *Config) func(db *gorm.DB) {
 				}
 
 				if db.Statement.ReflectValue.CanAddr() && db.Statement.Dest != db.Statement.Model && db.Statement.Model != nil {
-					_, queryValues = schema.GetIdentityFieldValuesMap(reflect.ValueOf(db.Statement.Model), db.Statement.Schema.PrimaryFields)
+					_, queryValues = schema.GetIdentityFieldValuesMap(db.Statement.Context, reflect.ValueOf(db.Statement.Model), db.Statement.Schema.PrimaryFields)
 					column, values = schema.ToQueryValues(db.Statement.Table, db.Statement.Schema.PrimaryFieldDBNames, queryValues)
 
 					if len(values) > 0 {
diff --git a/callbacks/preload.go b/callbacks/preload.go
index 41405a2..2363a8c 100644
--- a/callbacks/preload.go
+++ b/callbacks/preload.go
@@ -48,7 +48,7 @@ func preload(db *gorm.DB, rel *schema.Relationship, conds []interface{}, preload
 			}
 		}
 
-		joinIdentityMap, joinForeignValues := schema.GetIdentityFieldValuesMap(reflectValue, foreignFields)
+		joinIdentityMap, joinForeignValues := schema.GetIdentityFieldValuesMap(db.Statement.Context, reflectValue, foreignFields)
 		if len(joinForeignValues) == 0 {
 			return
 		}
@@ -63,11 +63,11 @@ func preload(db *gorm.DB, rel *schema.Relationship, conds []interface{}, preload
 		for i := 0; i < joinResults.Len(); i++ {
 			joinIndexValue := joinResults.Index(i)
 			for idx, field := range joinForeignFields {
-				fieldValues[idx], _ = field.ValueOf(joinIndexValue)
+				fieldValues[idx], _ = field.ValueOf(db.Statement.Context, joinIndexValue)
 			}
 
 			for idx, field := range joinRelForeignFields {
-				joinFieldValues[idx], _ = field.ValueOf(joinIndexValue)
+				joinFieldValues[idx], _ = field.ValueOf(db.Statement.Context, joinIndexValue)
 			}
 
 			if results, ok := joinIdentityMap[utils.ToStringKey(fieldValues...)]; ok {
@@ -76,7 +76,7 @@ func preload(db *gorm.DB, rel *schema.Relationship, conds []interface{}, preload
 			}
 		}
 
-		_, foreignValues = schema.GetIdentityFieldValuesMap(joinResults, joinRelForeignFields)
+		_, foreignValues = schema.GetIdentityFieldValuesMap(db.Statement.Context, joinResults, joinRelForeignFields)
 	} else {
 		for _, ref := range rel.References {
 			if ref.OwnPrimaryKey {
@@ -92,7 +92,7 @@ func preload(db *gorm.DB, rel *schema.Relationship, conds []interface{}, preload
 			}
 		}
 
-		identityMap, foreignValues = schema.GetIdentityFieldValuesMap(reflectValue, foreignFields)
+		identityMap, foreignValues = schema.GetIdentityFieldValuesMap(db.Statement.Context, reflectValue, foreignFields)
 		if len(foreignValues) == 0 {
 			return
 		}
@@ -125,17 +125,17 @@ func preload(db *gorm.DB, rel *schema.Relationship, conds []interface{}, preload
 	case reflect.Struct:
 		switch rel.Type {
 		case schema.HasMany, schema.Many2Many:
-			rel.Field.Set(reflectValue, reflect.MakeSlice(rel.Field.IndirectFieldType, 0, 10).Interface())
+			rel.Field.Set(db.Statement.Context, reflectValue, reflect.MakeSlice(rel.Field.IndirectFieldType, 0, 10).Interface())
 		default:
-			rel.Field.Set(reflectValue, reflect.New(rel.Field.FieldType).Interface())
+			rel.Field.Set(db.Statement.Context, reflectValue, reflect.New(rel.Field.FieldType).Interface())
 		}
 	case reflect.Slice, reflect.Array:
 		for i := 0; i < reflectValue.Len(); i++ {
 			switch rel.Type {
 			case schema.HasMany, schema.Many2Many:
-				rel.Field.Set(reflectValue.Index(i), reflect.MakeSlice(rel.Field.IndirectFieldType, 0, 10).Interface())
+				rel.Field.Set(db.Statement.Context, reflectValue.Index(i), reflect.MakeSlice(rel.Field.IndirectFieldType, 0, 10).Interface())
 			default:
-				rel.Field.Set(reflectValue.Index(i), reflect.New(rel.Field.FieldType).Interface())
+				rel.Field.Set(db.Statement.Context, reflectValue.Index(i), reflect.New(rel.Field.FieldType).Interface())
 			}
 		}
 	}
@@ -143,7 +143,7 @@ func preload(db *gorm.DB, rel *schema.Relationship, conds []interface{}, preload
 	for i := 0; i < reflectResults.Len(); i++ {
 		elem := reflectResults.Index(i)
 		for idx, field := range relForeignFields {
-			fieldValues[idx], _ = field.ValueOf(elem)
+			fieldValues[idx], _ = field.ValueOf(db.Statement.Context, elem)
 		}
 
 		datas, ok := identityMap[utils.ToStringKey(fieldValues...)]
@@ -154,7 +154,7 @@ func preload(db *gorm.DB, rel *schema.Relationship, conds []interface{}, preload
 		}
 
 		for _, data := range datas {
-			reflectFieldValue := rel.Field.ReflectValueOf(data)
+			reflectFieldValue := rel.Field.ReflectValueOf(db.Statement.Context, data)
 			if reflectFieldValue.Kind() == reflect.Ptr && reflectFieldValue.IsNil() {
 				reflectFieldValue.Set(reflect.New(rel.Field.FieldType.Elem()))
 			}
@@ -162,12 +162,12 @@ func preload(db *gorm.DB, rel *schema.Relationship, conds []interface{}, preload
 			reflectFieldValue = reflect.Indirect(reflectFieldValue)
 			switch reflectFieldValue.Kind() {
 			case reflect.Struct:
-				rel.Field.Set(data, elem.Interface())
+				rel.Field.Set(db.Statement.Context, data, elem.Interface())
 			case reflect.Slice, reflect.Array:
 				if reflectFieldValue.Type().Elem().Kind() == reflect.Ptr {
-					rel.Field.Set(data, reflect.Append(reflectFieldValue, elem).Interface())
+					rel.Field.Set(db.Statement.Context, data, reflect.Append(reflectFieldValue, elem).Interface())
 				} else {
-					rel.Field.Set(data, reflect.Append(reflectFieldValue, elem.Elem()).Interface())
+					rel.Field.Set(db.Statement.Context, data, reflect.Append(reflectFieldValue, elem.Elem()).Interface())
 				}
 			}
 		}
diff --git a/callbacks/query.go b/callbacks/query.go
index 4908635..0379885 100644
--- a/callbacks/query.go
+++ b/callbacks/query.go
@@ -40,7 +40,7 @@ func BuildQuerySQL(db *gorm.DB) {
 		if db.Statement.ReflectValue.Kind() == reflect.Struct && db.Statement.ReflectValue.Type() == db.Statement.Schema.ModelType {
 			var conds []clause.Expression
 			for _, primaryField := range db.Statement.Schema.PrimaryFields {
-				if v, isZero := primaryField.ValueOf(db.Statement.ReflectValue); !isZero {
+				if v, isZero := primaryField.ValueOf(db.Statement.Context, db.Statement.ReflectValue); !isZero {
 					conds = append(conds, clause.Eq{Column: clause.Column{Table: db.Statement.Table, Name: primaryField.DBName}, Value: v})
 				}
 			}
diff --git a/callbacks/update.go b/callbacks/update.go
index 511e994..4f07ca3 100644
--- a/callbacks/update.go
+++ b/callbacks/update.go
@@ -21,7 +21,7 @@ func SetupUpdateReflectValue(db *gorm.DB) {
 			if dest, ok := db.Statement.Dest.(map[string]interface{}); ok {
 				for _, rel := range db.Statement.Schema.Relationships.BelongsTo {
 					if _, ok := dest[rel.Name]; ok {
-						rel.Field.Set(db.Statement.ReflectValue, dest[rel.Name])
+						rel.Field.Set(db.Statement.Context, db.Statement.ReflectValue, dest[rel.Name])
 					}
 				}
 			}
@@ -137,13 +137,13 @@ func ConvertToAssignments(stmt *gorm.Statement) (set clause.Set) {
 	case reflect.Slice, reflect.Array:
 		assignValue = func(field *schema.Field, value interface{}) {
 			for i := 0; i < stmt.ReflectValue.Len(); i++ {
-				field.Set(stmt.ReflectValue.Index(i), value)
+				field.Set(stmt.Context, stmt.ReflectValue.Index(i), value)
 			}
 		}
 	case reflect.Struct:
 		assignValue = func(field *schema.Field, value interface{}) {
 			if stmt.ReflectValue.CanAddr() {
-				field.Set(stmt.ReflectValue, value)
+				field.Set(stmt.Context, stmt.ReflectValue, value)
 			}
 		}
 	default:
@@ -165,7 +165,7 @@ func ConvertToAssignments(stmt *gorm.Statement) (set clause.Set) {
 					exprs := make([]clause.Expression, len(stmt.Schema.PrimaryFields))
 					var notZero bool
 					for idx, field := range stmt.Schema.PrimaryFields {
-						value, isZero := field.ValueOf(stmt.ReflectValue.Index(i))
+						value, isZero := field.ValueOf(stmt.Context, stmt.ReflectValue.Index(i))
 						exprs[idx] = clause.Eq{Column: field.DBName, Value: value}
 						notZero = notZero || !isZero
 					}
@@ -178,7 +178,7 @@ func ConvertToAssignments(stmt *gorm.Statement) (set clause.Set) {
 			}
 		case reflect.Struct:
 			for _, field := range stmt.Schema.PrimaryFields {
-				if value, isZero := field.ValueOf(stmt.ReflectValue); !isZero {
+				if value, isZero := field.ValueOf(stmt.Context, stmt.ReflectValue); !isZero {
 					stmt.AddClause(clause.Where{Exprs: []clause.Expression{clause.Eq{Column: field.DBName, Value: value}}})
 				}
 			}
@@ -258,7 +258,7 @@ func ConvertToAssignments(stmt *gorm.Statement) (set clause.Set) {
 				if field := updatingSchema.LookUpField(dbName); field != nil {
 					if !field.PrimaryKey || !updatingValue.CanAddr() || stmt.Dest != stmt.Model {
 						if v, ok := selectColumns[field.DBName]; (ok && v) || (!ok && (!restricted || (!stmt.SkipHooks && field.AutoUpdateTime > 0))) {
-							value, isZero := field.ValueOf(updatingValue)
+							value, isZero := field.ValueOf(stmt.Context, updatingValue)
 							if !stmt.SkipHooks && field.AutoUpdateTime > 0 {
 								if field.AutoUpdateTime == schema.UnixNanosecond {
 									value = stmt.DB.NowFunc().UnixNano()
@@ -278,7 +278,7 @@ func ConvertToAssignments(stmt *gorm.Statement) (set clause.Set) {
 							}
 						}
 					} else {
-						if value, isZero := field.ValueOf(updatingValue); !isZero {
+						if value, isZero := field.ValueOf(stmt.Context, updatingValue); !isZero {
 							stmt.AddClause(clause.Where{Exprs: []clause.Expression{clause.Eq{Column: field.DBName, Value: value}}})
 						}
 					}
diff --git a/clause/where.go b/clause/where.go
index 20a0113..10b6df8 100644
--- a/clause/where.go
+++ b/clause/where.go
@@ -4,6 +4,11 @@ import (
 	"strings"
 )
 
+const (
+	AndWithSpace = " AND "
+	OrWithSpace  = " OR "
+)
+
 // Where where clause
 type Where struct {
 	Exprs []Expression
@@ -26,7 +31,7 @@ func (where Where) Build(builder Builder) {
 		}
 	}
 
-	buildExprs(where.Exprs, builder, " AND ")
+	buildExprs(where.Exprs, builder, AndWithSpace)
 }
 
 func buildExprs(exprs []Expression, builder Builder, joinCond string) {
@@ -35,7 +40,7 @@ func buildExprs(exprs []Expression, builder Builder, joinCond string) {
 	for idx, expr := range exprs {
 		if idx > 0 {
 			if v, ok := expr.(OrConditions); ok && len(v.Exprs) == 1 {
-				builder.WriteString(" OR ")
+				builder.WriteString(OrWithSpace)
 			} else {
 				builder.WriteString(joinCond)
 			}
@@ -46,23 +51,23 @@ func buildExprs(exprs []Expression, builder Builder, joinCond string) {
 			case OrConditions:
 				if len(v.Exprs) == 1 {
 					if e, ok := v.Exprs[0].(Expr); ok {
-						sql := strings.ToLower(e.SQL)
-						wrapInParentheses = strings.Contains(sql, "and") || strings.Contains(sql, "or")
+						sql := strings.ToUpper(e.SQL)
+						wrapInParentheses = strings.Contains(sql, AndWithSpace) || strings.Contains(sql, OrWithSpace)
 					}
 				}
 			case AndConditions:
 				if len(v.Exprs) == 1 {
 					if e, ok := v.Exprs[0].(Expr); ok {
-						sql := strings.ToLower(e.SQL)
-						wrapInParentheses = strings.Contains(sql, "and") || strings.Contains(sql, "or")
+						sql := strings.ToUpper(e.SQL)
+						wrapInParentheses = strings.Contains(sql, AndWithSpace) || strings.Contains(sql, OrWithSpace)
 					}
 				}
 			case Expr:
-				sql := strings.ToLower(v.SQL)
-				wrapInParentheses = strings.Contains(sql, "and") || strings.Contains(sql, "or")
+				sql := strings.ToUpper(v.SQL)
+				wrapInParentheses = strings.Contains(sql, AndWithSpace) || strings.Contains(sql, OrWithSpace)
 			case NamedExpr:
-				sql := strings.ToLower(v.SQL)
-				wrapInParentheses = strings.Contains(sql, "and") || strings.Contains(sql, "or")
+				sql := strings.ToUpper(v.SQL)
+				wrapInParentheses = strings.Contains(sql, AndWithSpace) || strings.Contains(sql, OrWithSpace)
 			}
 		}
 
@@ -110,10 +115,10 @@ type AndConditions struct {
 func (and AndConditions) Build(builder Builder) {
 	if len(and.Exprs) > 1 {
 		builder.WriteByte('(')
-		buildExprs(and.Exprs, builder, " AND ")
+		buildExprs(and.Exprs, builder, AndWithSpace)
 		builder.WriteByte(')')
 	} else {
-		buildExprs(and.Exprs, builder, " AND ")
+		buildExprs(and.Exprs, builder, AndWithSpace)
 	}
 }
 
@@ -131,10 +136,10 @@ type OrConditions struct {
 func (or OrConditions) Build(builder Builder) {
 	if len(or.Exprs) > 1 {
 		builder.WriteByte('(')
-		buildExprs(or.Exprs, builder, " OR ")
+		buildExprs(or.Exprs, builder, OrWithSpace)
 		builder.WriteByte(')')
 	} else {
-		buildExprs(or.Exprs, builder, " OR ")
+		buildExprs(or.Exprs, builder, OrWithSpace)
 	}
 }
 
@@ -156,7 +161,7 @@ func (not NotConditions) Build(builder Builder) {
 
 	for idx, c := range not.Exprs {
 		if idx > 0 {
-			builder.WriteString(" AND ")
+			builder.WriteString(AndWithSpace)
 		}
 
 		if negationBuilder, ok := c.(NegationExpressionBuilder); ok {
@@ -165,8 +170,8 @@ func (not NotConditions) Build(builder Builder) {
 			builder.WriteString("NOT ")
 			e, wrapInParentheses := c.(Expr)
 			if wrapInParentheses {
-				sql := strings.ToLower(e.SQL)
-				if wrapInParentheses = strings.Contains(sql, "and") || strings.Contains(sql, "or"); wrapInParentheses {
+				sql := strings.ToUpper(e.SQL)
+				if wrapInParentheses = strings.Contains(sql, AndWithSpace) || strings.Contains(sql, OrWithSpace); wrapInParentheses {
 					builder.WriteByte('(')
 				}
 			}
diff --git a/finisher_api.go b/finisher_api.go
index 3a17997..d2a8b98 100644
--- a/finisher_api.go
+++ b/finisher_api.go
@@ -83,7 +83,7 @@ func (db *DB) Save(value interface{}) (tx *DB) {
 	case reflect.Struct:
 		if err := tx.Statement.Parse(value); err == nil && tx.Statement.Schema != nil {
 			for _, pf := range tx.Statement.Schema.PrimaryFields {
-				if _, isZero := pf.ValueOf(reflectValue); isZero {
+				if _, isZero := pf.ValueOf(tx.Statement.Context, reflectValue); isZero {
 					return tx.callbacks.Create().Execute(tx)
 				}
 			}
@@ -199,7 +199,7 @@ func (db *DB) FindInBatches(dest interface{}, batchSize int, fc func(tx *DB, bat
 			break
 		}
 
-		primaryValue, _ := result.Statement.Schema.PrioritizedPrimaryField.ValueOf(resultsValue.Index(resultsValue.Len() - 1))
+		primaryValue, _ := result.Statement.Schema.PrioritizedPrimaryField.ValueOf(tx.Statement.Context, resultsValue.Index(resultsValue.Len()-1))
 		queryDB = tx.Clauses(clause.Gt{Column: clause.Column{Table: clause.CurrentTable, Name: clause.PrimaryKey}, Value: primaryValue})
 	}
 
@@ -216,11 +216,11 @@ func (tx *DB) assignInterfacesToValue(values ...interface{}) {
 					switch column := eq.Column.(type) {
 					case string:
 						if field := tx.Statement.Schema.LookUpField(column); field != nil {
-							tx.AddError(field.Set(tx.Statement.ReflectValue, eq.Value))
+							tx.AddError(field.Set(tx.Statement.Context, tx.Statement.ReflectValue, eq.Value))
 						}
 					case clause.Column:
 						if field := tx.Statement.Schema.LookUpField(column.Name); field != nil {
-							tx.AddError(field.Set(tx.Statement.ReflectValue, eq.Value))
+							tx.AddError(field.Set(tx.Statement.Context, tx.Statement.ReflectValue, eq.Value))
 						}
 					}
 				} else if andCond, ok := expr.(clause.AndConditions); ok {
@@ -238,9 +238,9 @@ func (tx *DB) assignInterfacesToValue(values ...interface{}) {
 				case reflect.Struct:
 					for _, f := range s.Fields {
 						if f.Readable {
-							if v, isZero := f.ValueOf(reflectValue); !isZero {
+							if v, isZero := f.ValueOf(tx.Statement.Context, reflectValue); !isZero {
 								if field := tx.Statement.Schema.LookUpField(f.Name); field != nil {
-									tx.AddError(field.Set(tx.Statement.ReflectValue, v))
+									tx.AddError(field.Set(tx.Statement.Context, tx.Statement.ReflectValue, v))
 								}
 							}
 						}
diff --git a/interfaces.go b/interfaces.go
index 44b2fce..ff0ca60 100644
--- a/interfaces.go
+++ b/interfaces.go
@@ -40,14 +40,17 @@ type SavePointerDialectorInterface interface {
 	RollbackTo(tx *DB, name string) error
 }
 
+// TxBeginner tx beginner
 type TxBeginner interface {
 	BeginTx(ctx context.Context, opts *sql.TxOptions) (*sql.Tx, error)
 }
 
+// ConnPoolBeginner conn pool beginner
 type ConnPoolBeginner interface {
 	BeginTx(ctx context.Context, opts *sql.TxOptions) (ConnPool, error)
 }
 
+// TxCommitter tx commiter
 type TxCommitter interface {
 	Commit() error
 	Rollback() error
@@ -58,6 +61,7 @@ type Valuer interface {
 	GormValue(context.Context, *DB) clause.Expr
 }
 
+// GetDBConnector SQL db connector
 type GetDBConnector interface {
 	GetDBConn() (*sql.DB, error)
 }
diff --git a/logger/sql.go b/logger/sql.go
index e0be57c..04a2dbd 100644
--- a/logger/sql.go
+++ b/logger/sql.go
@@ -19,9 +19,9 @@ const (
 	nullStr     = "NULL"
 )
 
-func isPrintable(s []byte) bool {
+func isPrintable(s string) bool {
 	for _, r := range s {
-		if !unicode.IsPrint(rune(r)) {
+		if !unicode.IsPrint(r) {
 			return false
 		}
 	}
@@ -84,8 +84,8 @@ func ExplainSQL(sql string, numericPlaceholder *regexp.Regexp, escaper string, a
 				}
 			}
 		case []byte:
-			if isPrintable(v) {
-				vars[idx] = escaper + strings.Replace(string(v), escaper, "\\"+escaper, -1) + escaper
+			if s := string(v); isPrintable(s) {
+				vars[idx] = escaper + strings.ReplaceAll(s, escaper, "\\"+escaper) + escaper
 			} else {
 				vars[idx] = escaper + "<binary>" + escaper
 			}
diff --git a/migrator.go b/migrator.go
index 2a8b425..5244387 100644
--- a/migrator.go
+++ b/migrator.go
@@ -1,6 +1,8 @@
 package gorm
 
 import (
+	"reflect"
+
 	"gorm.io/gorm/clause"
 	"gorm.io/gorm/schema"
 )
@@ -33,14 +35,23 @@ type ViewOption struct {
 	Query       *DB
 }
 
+// ColumnType column type interface
 type ColumnType interface {
 	Name() string
-	DatabaseTypeName() string
+	DatabaseTypeName() string                 // varchar
+	ColumnType() (columnType string, ok bool) // varchar(64)
+	PrimaryKey() (isPrimaryKey bool, ok bool)
+	AutoIncrement() (isAutoIncrement bool, ok bool)
 	Length() (length int64, ok bool)
 	DecimalSize() (precision int64, scale int64, ok bool)
 	Nullable() (nullable bool, ok bool)
+	Unique() (unique bool, ok bool)
+	ScanType() reflect.Type
+	Comment() (value string, ok bool)
+	DefaultValue() (value string, ok bool)
 }
 
+// Migrator migrator interface
 type Migrator interface {
 	// AutoMigrate
 	AutoMigrate(dst ...interface{}) error
diff --git a/migrator/column_type.go b/migrator/column_type.go
new file mode 100644
index 0000000..cc1331b
--- /dev/null
+++ b/migrator/column_type.go
@@ -0,0 +1,107 @@
+package migrator
+
+import (
+	"database/sql"
+	"reflect"
+)
+
+// ColumnType column type implements ColumnType interface
+type ColumnType struct {
+	SQLColumnType      *sql.ColumnType
+	NameValue          sql.NullString
+	DataTypeValue      sql.NullString
+	ColumnTypeValue    sql.NullString
+	PrimaryKeyValue    sql.NullBool
+	UniqueValue        sql.NullBool
+	AutoIncrementValue sql.NullBool
+	LengthValue        sql.NullInt64
+	DecimalSizeValue   sql.NullInt64
+	ScaleValue         sql.NullInt64
+	NullableValue      sql.NullBool
+	ScanTypeValue      reflect.Type
+	CommentValue       sql.NullString
+	DefaultValueValue  sql.NullString
+}
+
+// Name returns the name or alias of the column.
+func (ct ColumnType) Name() string {
+	if ct.NameValue.Valid {
+		return ct.NameValue.String
+	}
+	return ct.SQLColumnType.Name()
+}
+
+// DatabaseTypeName returns the database system name of the column type. If an empty
+// string is returned, then the driver type name is not supported.
+// Consult your driver documentation for a list of driver data types. Length specifiers
+// are not included.
+// Common type names include "VARCHAR", "TEXT", "NVARCHAR", "DECIMAL", "BOOL",
+// "INT", and "BIGINT".
+func (ct ColumnType) DatabaseTypeName() string {
+	if ct.DataTypeValue.Valid {
+		return ct.DataTypeValue.String
+	}
+	return ct.SQLColumnType.DatabaseTypeName()
+}
+
+// ColumnType returns the database type of the column. lke `varchar(16)`
+func (ct ColumnType) ColumnType() (columnType string, ok bool) {
+	return ct.ColumnTypeValue.String, ct.ColumnTypeValue.Valid
+}
+
+// PrimaryKey returns the column is primary key or not.
+func (ct ColumnType) PrimaryKey() (isPrimaryKey bool, ok bool) {
+	return ct.PrimaryKeyValue.Bool, ct.PrimaryKeyValue.Valid
+}
+
+// AutoIncrement returns the column is auto increment or not.
+func (ct ColumnType) AutoIncrement() (isAutoIncrement bool, ok bool) {
+	return ct.AutoIncrementValue.Bool, ct.AutoIncrementValue.Valid
+}
+
+// Length returns the column type length for variable length column types
+func (ct ColumnType) Length() (length int64, ok bool) {
+	if ct.LengthValue.Valid {
+		return ct.LengthValue.Int64, true
+	}
+	return ct.SQLColumnType.Length()
+}
+
+// DecimalSize returns the scale and precision of a decimal type.
+func (ct ColumnType) DecimalSize() (precision int64, scale int64, ok bool) {
+	if ct.DecimalSizeValue.Valid {
+		return ct.DecimalSizeValue.Int64, ct.ScaleValue.Int64, true
+	}
+	return ct.SQLColumnType.DecimalSize()
+}
+
+// Nullable reports whether the column may be null.
+func (ct ColumnType) Nullable() (nullable bool, ok bool) {
+	if ct.NullableValue.Valid {
+		return ct.NullableValue.Bool, true
+	}
+	return ct.SQLColumnType.Nullable()
+}
+
+// Unique reports whether the column may be unique.
+func (ct ColumnType) Unique() (unique bool, ok bool) {
+	return ct.UniqueValue.Bool, ct.UniqueValue.Valid
+}
+
+// ScanType returns a Go type suitable for scanning into using Rows.Scan.
+func (ct ColumnType) ScanType() reflect.Type {
+	if ct.ScanTypeValue != nil {
+		return ct.ScanTypeValue
+	}
+	return ct.SQLColumnType.ScanType()
+}
+
+// Comment returns the comment of current column.
+func (ct ColumnType) Comment() (value string, ok bool) {
+	return ct.CommentValue.String, ct.CommentValue.Valid
+}
+
+// DefaultValue returns the default value of current column.
+func (ct ColumnType) DefaultValue() (value string, ok bool) {
+	return ct.DefaultValueValue.String, ct.DefaultValueValue.Valid
+}
diff --git a/migrator/migrator.go b/migrator/migrator.go
index 80c4e2b..a50bb3f 100644
--- a/migrator/migrator.go
+++ b/migrator/migrator.go
@@ -30,10 +30,12 @@ type Config struct {
 	gorm.Dialector
 }
 
+// GormDataTypeInterface gorm data type interface
 type GormDataTypeInterface interface {
 	GormDBDataType(*gorm.DB, *schema.Field) string
 }
 
+// RunWithValue run migration with statement value
 func (m Migrator) RunWithValue(value interface{}, fc func(*gorm.Statement) error) error {
 	stmt := &gorm.Statement{DB: m.DB}
 	if m.DB.Statement != nil {
@@ -50,6 +52,7 @@ func (m Migrator) RunWithValue(value interface{}, fc func(*gorm.Statement) error
 	return fc(stmt)
 }
 
+// DataTypeOf return field's db data type
 func (m Migrator) DataTypeOf(field *schema.Field) string {
 	fieldValue := reflect.New(field.IndirectFieldType)
 	if dataTyper, ok := fieldValue.Interface().(GormDataTypeInterface); ok {
@@ -61,6 +64,7 @@ func (m Migrator) DataTypeOf(field *schema.Field) string {
 	return m.Dialector.DataTypeOf(field)
 }
 
+// FullDataTypeOf returns field's db full data type
 func (m Migrator) FullDataTypeOf(field *schema.Field) (expr clause.Expr) {
 	expr.SQL = m.DataTypeOf(field)
 
@@ -85,7 +89,7 @@ func (m Migrator) FullDataTypeOf(field *schema.Field) (expr clause.Expr) {
 	return
 }
 
-// AutoMigrate
+// AutoMigrate auto migrate values
 func (m Migrator) AutoMigrate(values ...interface{}) error {
 	for _, value := range m.ReorderModels(values, true) {
 		tx := m.DB.Session(&gorm.Session{})
@@ -156,12 +160,14 @@ func (m Migrator) AutoMigrate(values ...interface{}) error {
 	return nil
 }
 
+// GetTables returns tables
 func (m Migrator) GetTables() (tableList []string, err error) {
 	err = m.DB.Raw("SELECT TABLE_NAME FROM information_schema.tables where TABLE_SCHEMA=?", m.CurrentDatabase()).
 		Scan(&tableList).Error
 	return
 }
 
+// CreateTable create table in database for values
 func (m Migrator) CreateTable(values ...interface{}) error {
 	for _, value := range m.ReorderModels(values, false) {
 		tx := m.DB.Session(&gorm.Session{})
@@ -252,6 +258,7 @@ func (m Migrator) CreateTable(values ...interface{}) error {
 	return nil
 }
 
+// DropTable drop table for values
 func (m Migrator) DropTable(values ...interface{}) error {
 	values = m.ReorderModels(values, false)
 	for i := len(values) - 1; i >= 0; i-- {
@@ -265,6 +272,7 @@ func (m Migrator) DropTable(values ...interface{}) error {
 	return nil
 }
 
+// HasTable returns table exists or not for value, value could be a struct or string
 func (m Migrator) HasTable(value interface{}) bool {
 	var count int64
 
@@ -276,6 +284,7 @@ func (m Migrator) HasTable(value interface{}) bool {
 	return count > 0
 }
 
+// RenameTable rename table from oldName to newName
 func (m Migrator) RenameTable(oldName, newName interface{}) error {
 	var oldTable, newTable interface{}
 	if v, ok := oldName.(string); ok {
@@ -303,12 +312,13 @@ func (m Migrator) RenameTable(oldName, newName interface{}) error {
 	return m.DB.Exec("ALTER TABLE ? RENAME TO ?", oldTable, newTable).Error
 }
 
-func (m Migrator) AddColumn(value interface{}, field string) error {
+// AddColumn create `name` column for value
+func (m Migrator) AddColumn(value interface{}, name string) error {
 	return m.RunWithValue(value, func(stmt *gorm.Statement) error {
 		// avoid using the same name field
-		f := stmt.Schema.LookUpField(field)
+		f := stmt.Schema.LookUpField(name)
 		if f == nil {
-			return fmt.Errorf("failed to look up field with name: %s", field)
+			return fmt.Errorf("failed to look up field with name: %s", name)
 		}
 
 		if !f.IgnoreMigration {
@@ -322,6 +332,7 @@ func (m Migrator) AddColumn(value interface{}, field string) error {
 	})
 }
 
+// DropColumn drop value's `name` column
 func (m Migrator) DropColumn(value interface{}, name string) error {
 	return m.RunWithValue(value, func(stmt *gorm.Statement) error {
 		if field := stmt.Schema.LookUpField(name); field != nil {
@@ -334,6 +345,7 @@ func (m Migrator) DropColumn(value interface{}, name string) error {
 	})
 }
 
+// AlterColumn alter value's `field` column' type based on schema definition
 func (m Migrator) AlterColumn(value interface{}, field string) error {
 	return m.RunWithValue(value, func(stmt *gorm.Statement) error {
 		if field := stmt.Schema.LookUpField(field); field != nil {
@@ -348,6 +360,7 @@ func (m Migrator) AlterColumn(value interface{}, field string) error {
 	})
 }
 
+// HasColumn check has column `field` for value or not
 func (m Migrator) HasColumn(value interface{}, field string) bool {
 	var count int64
 	m.RunWithValue(value, func(stmt *gorm.Statement) error {
@@ -366,6 +379,7 @@ func (m Migrator) HasColumn(value interface{}, field string) bool {
 	return count > 0
 }
 
+// RenameColumn rename value's field name from oldName to newName
 func (m Migrator) RenameColumn(value interface{}, oldName, newName string) error {
 	return m.RunWithValue(value, func(stmt *gorm.Statement) error {
 		if field := stmt.Schema.LookUpField(oldName); field != nil {
@@ -383,6 +397,7 @@ func (m Migrator) RenameColumn(value interface{}, oldName, newName string) error
 	})
 }
 
+// MigrateColumn migrate column
 func (m Migrator) MigrateColumn(value interface{}, field *schema.Field, columnType gorm.ColumnType) error {
 	// found, smart migrate
 	fullDataType := strings.ToLower(m.DB.Migrator().FullDataTypeOf(field).SQL)
@@ -421,6 +436,30 @@ func (m Migrator) MigrateColumn(value interface{}, field *schema.Field, columnTy
 		}
 	}
 
+	// check unique
+	if unique, ok := columnType.Unique(); ok && unique != field.Unique {
+		// not primary key
+		if !field.PrimaryKey {
+			alterColumn = true
+		}
+	}
+
+	// check default value
+	if v, ok := columnType.DefaultValue(); ok && v != field.DefaultValue {
+		// not primary key
+		if !field.PrimaryKey {
+			alterColumn = true
+		}
+	}
+
+	// check comment
+	if comment, ok := columnType.Comment(); ok && comment != field.Comment {
+		// not primary key
+		if !field.PrimaryKey {
+			alterColumn = true
+		}
+	}
+
 	if alterColumn && !field.IgnoreMigration {
 		return m.DB.Migrator().AlterColumn(value, field.Name)
 	}
@@ -448,7 +487,7 @@ func (m Migrator) ColumnTypes(value interface{}) ([]gorm.ColumnType, error) {
 		}
 
 		for _, c := range rawColumnTypes {
-			columnTypes = append(columnTypes, c)
+			columnTypes = append(columnTypes, ColumnType{SQLColumnType: c})
 		}
 
 		return
@@ -457,10 +496,12 @@ func (m Migrator) ColumnTypes(value interface{}) ([]gorm.ColumnType, error) {
 	return columnTypes, execErr
 }
 
+// CreateView create view
 func (m Migrator) CreateView(name string, option gorm.ViewOption) error {
 	return gorm.ErrNotImplemented
 }
 
+// DropView drop view
 func (m Migrator) DropView(name string) error {
 	return gorm.ErrNotImplemented
 }
@@ -487,6 +528,7 @@ func buildConstraint(constraint *schema.Constraint) (sql string, results []inter
 	return
 }
 
+// GuessConstraintAndTable guess statement's constraint and it's table based on name
 func (m Migrator) GuessConstraintAndTable(stmt *gorm.Statement, name string) (_ *schema.Constraint, _ *schema.Check, table string) {
 	if stmt.Schema == nil {
 		return nil, nil, stmt.Table
@@ -531,6 +573,7 @@ func (m Migrator) GuessConstraintAndTable(stmt *gorm.Statement, name string) (_
 	return nil, nil, stmt.Schema.Table
 }
 
+// CreateConstraint create constraint
 func (m Migrator) CreateConstraint(value interface{}, name string) error {
 	return m.RunWithValue(value, func(stmt *gorm.Statement) error {
 		constraint, chk, table := m.GuessConstraintAndTable(stmt, name)
@@ -554,6 +597,7 @@ func (m Migrator) CreateConstraint(value interface{}, name string) error {
 	})
 }
 
+// DropConstraint drop constraint
 func (m Migrator) DropConstraint(value interface{}, name string) error {
 	return m.RunWithValue(value, func(stmt *gorm.Statement) error {
 		constraint, chk, table := m.GuessConstraintAndTable(stmt, name)
@@ -566,6 +610,7 @@ func (m Migrator) DropConstraint(value interface{}, name string) error {
 	})
 }
 
+// HasConstraint check has constraint or not
 func (m Migrator) HasConstraint(value interface{}, name string) bool {
 	var count int64
 	m.RunWithValue(value, func(stmt *gorm.Statement) error {
@@ -586,6 +631,7 @@ func (m Migrator) HasConstraint(value interface{}, name string) bool {
 	return count > 0
 }
 
+// BuildIndexOptions build index options
 func (m Migrator) BuildIndexOptions(opts []schema.IndexOption, stmt *gorm.Statement) (results []interface{}) {
 	for _, opt := range opts {
 		str := stmt.Quote(opt.DBName)
@@ -607,10 +653,12 @@ func (m Migrator) BuildIndexOptions(opts []schema.IndexOption, stmt *gorm.Statem
 	return
 }
 
+// BuildIndexOptionsInterface build index options interface
 type BuildIndexOptionsInterface interface {
 	BuildIndexOptions([]schema.IndexOption, *gorm.Statement) []interface{}
 }
 
+// CreateIndex create index `name`
 func (m Migrator) CreateIndex(value interface{}, name string) error {
 	return m.RunWithValue(value, func(stmt *gorm.Statement) error {
 		if idx := stmt.Schema.LookIndex(name); idx != nil {
@@ -642,6 +690,7 @@ func (m Migrator) CreateIndex(value interface{}, name string) error {
 	})
 }
 
+// DropIndex drop index `name`
 func (m Migrator) DropIndex(value interface{}, name string) error {
 	return m.RunWithValue(value, func(stmt *gorm.Statement) error {
 		if idx := stmt.Schema.LookIndex(name); idx != nil {
@@ -652,6 +701,7 @@ func (m Migrator) DropIndex(value interface{}, name string) error {
 	})
 }
 
+// HasIndex check has index `name` or not
 func (m Migrator) HasIndex(value interface{}, name string) bool {
 	var count int64
 	m.RunWithValue(value, func(stmt *gorm.Statement) error {
@@ -669,6 +719,7 @@ func (m Migrator) HasIndex(value interface{}, name string) bool {
 	return count > 0
 }
 
+// RenameIndex rename index from oldName to newName
 func (m Migrator) RenameIndex(value interface{}, oldName, newName string) error {
 	return m.RunWithValue(value, func(stmt *gorm.Statement) error {
 		return m.DB.Exec(
@@ -678,6 +729,7 @@ func (m Migrator) RenameIndex(value interface{}, oldName, newName string) error
 	})
 }
 
+// CurrentDatabase returns current database name
 func (m Migrator) CurrentDatabase() (name string) {
 	m.DB.Raw("SELECT DATABASE()").Row().Scan(&name)
 	return
@@ -781,6 +833,7 @@ func (m Migrator) ReorderModels(values []interface{}, autoAdd bool) (results []i
 	return
 }
 
+// CurrentTable returns current statement's table expression
 func (m Migrator) CurrentTable(stmt *gorm.Statement) interface{} {
 	if stmt.TableExpr != nil {
 		return *stmt.TableExpr
diff --git a/scan.go b/scan.go
index b03b79b..0da12da 100644
--- a/scan.go
+++ b/scan.go
@@ -10,6 +10,7 @@ import (
 	"gorm.io/gorm/schema"
 )
 
+// prepareValues prepare values slice
 func prepareValues(values []interface{}, db *DB, columnTypes []*sql.ColumnType, columns []string) {
 	if db.Statement.Schema != nil {
 		for idx, name := range columns {
@@ -54,11 +55,13 @@ func (db *DB) scanIntoStruct(sch *schema.Schema, rows *sql.Rows, reflectValue re
 		if sch == nil {
 			values[idx] = reflectValue.Interface()
 		} else if field := sch.LookUpField(column); field != nil && field.Readable {
-			values[idx] = reflect.New(reflect.PtrTo(field.IndirectFieldType)).Interface()
+			values[idx] = field.NewValuePool.Get()
+			defer field.NewValuePool.Put(values[idx])
 		} else if names := strings.Split(column, "__"); len(names) > 1 {
 			if rel, ok := sch.Relationships.Relations[names[0]]; ok {
 				if field := rel.FieldSchema.LookUpField(strings.Join(names[1:], "__")); field != nil && field.Readable {
-					values[idx] = reflect.New(reflect.PtrTo(field.IndirectFieldType)).Interface()
+					values[idx] = field.NewValuePool.Get()
+					defer field.NewValuePool.Put(values[idx])
 					continue
 				}
 			}
@@ -77,21 +80,21 @@ func (db *DB) scanIntoStruct(sch *schema.Schema, rows *sql.Rows, reflectValue re
 	if sch != nil {
 		for idx, column := range columns {
 			if field := sch.LookUpField(column); field != nil && field.Readable {
-				field.Set(reflectValue, values[idx])
+				field.Set(db.Statement.Context, reflectValue, values[idx])
 			} else if names := strings.Split(column, "__"); len(names) > 1 {
 				if rel, ok := sch.Relationships.Relations[names[0]]; ok {
 					if field := rel.FieldSchema.LookUpField(strings.Join(names[1:], "__")); field != nil && field.Readable {
-						relValue := rel.Field.ReflectValueOf(reflectValue)
-						value := reflect.ValueOf(values[idx]).Elem()
+						relValue := rel.Field.ReflectValueOf(db.Statement.Context, reflectValue)
 
 						if relValue.Kind() == reflect.Ptr && relValue.IsNil() {
-							if value.IsNil() {
+							if value := reflect.ValueOf(values[idx]).Elem(); value.Kind() == reflect.Ptr && value.IsNil() {
 								continue
 							}
+
 							relValue.Set(reflect.New(relValue.Type().Elem()))
 						}
 
-						field.Set(relValue, values[idx])
+						field.Set(db.Statement.Context, relValue, values[idx])
 					}
 				}
 			}
@@ -99,14 +102,17 @@ func (db *DB) scanIntoStruct(sch *schema.Schema, rows *sql.Rows, reflectValue re
 	}
 }
 
+// ScanMode scan data mode
 type ScanMode uint8
 
+// scan modes
 const (
 	ScanInitialized         ScanMode = 1 << 0 // 1
 	ScanUpdate              ScanMode = 1 << 1 // 2
 	ScanOnConflictDoNothing ScanMode = 1 << 2 // 4
 )
 
+// Scan scan rows into db statement
 func Scan(rows *sql.Rows, db *DB, mode ScanMode) {
 	var (
 		columns, _          = rows.Columns()
@@ -138,7 +144,7 @@ func Scan(rows *sql.Rows, db *DB, mode ScanMode) {
 			}
 			scanIntoMap(mapValue, values, columns)
 		}
-	case *[]map[string]interface{}, []map[string]interface{}:
+	case *[]map[string]interface{}:
 		columnTypes, _ := rows.ColumnTypes()
 		for initialized || rows.Next() {
 			prepareValues(values, db, columnTypes, columns)
@@ -149,11 +155,7 @@ func Scan(rows *sql.Rows, db *DB, mode ScanMode) {
 
 			mapValue := map[string]interface{}{}
 			scanIntoMap(mapValue, values, columns)
-			if values, ok := dest.([]map[string]interface{}); ok {
-				values = append(values, mapValue)
-			} else if values, ok := dest.(*[]map[string]interface{}); ok {
-				*values = append(*values, mapValue)
-			}
+			*dest = append(*dest, mapValue)
 		}
 	case *int, *int8, *int16, *int32, *int64,
 		*uint, *uint8, *uint16, *uint32, *uint64, *uintptr,
@@ -174,7 +176,7 @@ func Scan(rows *sql.Rows, db *DB, mode ScanMode) {
 			reflectValue = db.Statement.ReflectValue
 		)
 
-		if reflectValue.Kind() == reflect.Interface {
+		for reflectValue.Kind() == reflect.Interface {
 			reflectValue = reflectValue.Elem()
 		}
 
@@ -244,7 +246,7 @@ func Scan(rows *sql.Rows, db *DB, mode ScanMode) {
 					elem = reflectValue.Index(int(db.RowsAffected))
 					if onConflictDonothing {
 						for _, field := range fields {
-							if _, ok := field.ValueOf(elem); !ok {
+							if _, ok := field.ValueOf(db.Statement.Context, elem); !ok {
 								db.RowsAffected++
 								goto BEGIN
 							}
diff --git a/schema/field.go b/schema/field.go
index 485bbdf..319f369 100644
--- a/schema/field.go
+++ b/schema/field.go
@@ -1,6 +1,7 @@
 package schema
 
 import (
+	"context"
 	"database/sql"
 	"database/sql/driver"
 	"fmt"
@@ -14,12 +15,21 @@ import (
 	"gorm.io/gorm/utils"
 )
 
-type DataType string
-
-type TimeType int64
+// special types' reflect type
+var (
+	TimeReflectType    = reflect.TypeOf(time.Time{})
+	TimePtrReflectType = reflect.TypeOf(&time.Time{})
+	ByteReflectType    = reflect.TypeOf(uint8(0))
+)
 
-var TimeReflectType = reflect.TypeOf(time.Time{})
+type (
+	// DataType GORM data type
+	DataType string
+	// TimeType GORM time type
+	TimeType int64
+)
 
+// GORM time types
 const (
 	UnixTime        TimeType = 1
 	UnixSecond      TimeType = 2
@@ -27,6 +37,7 @@ const (
 	UnixNanosecond  TimeType = 4
 )
 
+// GORM fields types
 const (
 	Bool   DataType = "bool"
 	Int    DataType = "int"
@@ -37,6 +48,7 @@ const (
 	Bytes  DataType = "bytes"
 )
 
+// Field is the representation of model schema's field
 type Field struct {
 	Name                   string
 	DBName                 string
@@ -49,9 +61,9 @@ type Field struct {
 	Creatable              bool
 	Updatable              bool
 	Readable               bool
-	HasDefaultValue        bool
 	AutoCreateTime         TimeType
 	AutoUpdateTime         TimeType
+	HasDefaultValue        bool
 	DefaultValue           string
 	DefaultValueInterface  interface{}
 	NotNull                bool
@@ -60,6 +72,7 @@ type Field struct {
 	Size                   int
 	Precision              int
 	Scale                  int
+	IgnoreMigration        bool
 	FieldType              reflect.Type
 	IndirectFieldType      reflect.Type
 	StructField            reflect.StructField
@@ -68,27 +81,39 @@ type Field struct {
 	Schema                 *Schema
 	EmbeddedSchema         *Schema
 	OwnerSchema            *Schema
-	ReflectValueOf         func(reflect.Value) reflect.Value
-	ValueOf                func(reflect.Value) (value interface{}, zero bool)
-	Set                    func(reflect.Value, interface{}) error
-	IgnoreMigration        bool
+	ReflectValueOf         func(context.Context, reflect.Value) reflect.Value
+	ValueOf                func(context.Context, reflect.Value) (value interface{}, zero bool)
+	Set                    func(context.Context, reflect.Value, interface{}) error
+	Serializer             SerializerInterface
+	NewValuePool           FieldNewValuePool
 }
 
+// ParseField parses reflect.StructField to Field
 func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
-	var err error
+	var (
+		err        error
+		tagSetting = ParseTagSetting(fieldStruct.Tag.Get("gorm"), ";")
+	)
 
 	field := &Field{
 		Name:                   fieldStruct.Name,
+		DBName:                 tagSetting["COLUMN"],
 		BindNames:              []string{fieldStruct.Name},
 		FieldType:              fieldStruct.Type,
 		IndirectFieldType:      fieldStruct.Type,
 		StructField:            fieldStruct,
+		Tag:                    fieldStruct.Tag,
+		TagSettings:            tagSetting,
+		Schema:                 schema,
 		Creatable:              true,
 		Updatable:              true,
 		Readable:               true,
-		Tag:                    fieldStruct.Tag,
-		TagSettings:            ParseTagSetting(fieldStruct.Tag.Get("gorm"), ";"),
-		Schema:                 schema,
+		PrimaryKey:             utils.CheckTruth(tagSetting["PRIMARYKEY"], tagSetting["PRIMARY_KEY"]),
+		AutoIncrement:          utils.CheckTruth(tagSetting["AUTOINCREMENT"]),
+		HasDefaultValue:        utils.CheckTruth(tagSetting["AUTOINCREMENT"]),
+		NotNull:                utils.CheckTruth(tagSetting["NOT NULL"], tagSetting["NOTNULL"]),
+		Unique:                 utils.CheckTruth(tagSetting["UNIQUE"]),
+		Comment:                tagSetting["COMMENT"],
 		AutoIncrementIncrement: 1,
 	}
 
@@ -97,7 +122,7 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
 	}
 
 	fieldValue := reflect.New(field.IndirectFieldType)
-	// if field is valuer, used its value or first fields as data type
+	// if field is valuer, used its value or first field as data type
 	valuer, isValuer := fieldValue.Interface().(driver.Valuer)
 	if isValuer {
 		if _, ok := fieldValue.Interface().(GormDataTypeInterface); !ok {
@@ -105,31 +130,37 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
 				fieldValue = reflect.ValueOf(v)
 			}
 
+			// Use the field struct's first field type as data type, e.g: use `string` for sql.NullString
 			var getRealFieldValue func(reflect.Value)
 			getRealFieldValue = func(v reflect.Value) {
-				rv := reflect.Indirect(v)
-				if rv.Kind() == reflect.Struct && !rv.Type().ConvertibleTo(TimeReflectType) {
-					for i := 0; i < rv.Type().NumField(); i++ {
-						newFieldType := rv.Type().Field(i).Type
+				var (
+					rv     = reflect.Indirect(v)
+					rvType = rv.Type()
+				)
+
+				if rv.Kind() == reflect.Struct && !rvType.ConvertibleTo(TimeReflectType) {
+					for i := 0; i < rvType.NumField(); i++ {
+						for key, value := range ParseTagSetting(rvType.Field(i).Tag.Get("gorm"), ";") {
+							if _, ok := field.TagSettings[key]; !ok {
+								field.TagSettings[key] = value
+							}
+						}
+					}
+
+					for i := 0; i < rvType.NumField(); i++ {
+						newFieldType := rvType.Field(i).Type
 						for newFieldType.Kind() == reflect.Ptr {
 							newFieldType = newFieldType.Elem()
 						}
 
 						fieldValue = reflect.New(newFieldType)
-
-						if rv.Type() != reflect.Indirect(fieldValue).Type() {
+						if rvType != reflect.Indirect(fieldValue).Type() {
 							getRealFieldValue(fieldValue)
 						}
 
 						if fieldValue.IsValid() {
 							return
 						}
-
-						for key, value := range ParseTagSetting(field.IndirectFieldType.Field(i).Tag.Get("gorm"), ";") {
-							if _, ok := field.TagSettings[key]; !ok {
-								field.TagSettings[key] = value
-							}
-						}
 					}
 				}
 			}
@@ -138,19 +169,23 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
 		}
 	}
 
-	if dbName, ok := field.TagSettings["COLUMN"]; ok {
-		field.DBName = dbName
-	}
-
-	if val, ok := field.TagSettings["PRIMARYKEY"]; ok && utils.CheckTruth(val) {
-		field.PrimaryKey = true
-	} else if val, ok := field.TagSettings["PRIMARY_KEY"]; ok && utils.CheckTruth(val) {
-		field.PrimaryKey = true
-	}
-
-	if val, ok := field.TagSettings["AUTOINCREMENT"]; ok && utils.CheckTruth(val) {
-		field.AutoIncrement = true
-		field.HasDefaultValue = true
+	if v, isSerializer := fieldValue.Interface().(SerializerInterface); isSerializer {
+		field.DataType = String
+		field.Serializer = v
+	} else {
+		var serializerName = field.TagSettings["JSON"]
+		if serializerName == "" {
+			serializerName = field.TagSettings["SERIALIZER"]
+		}
+		if serializerName != "" {
+			if serializer, ok := GetSerializer(serializerName); ok {
+				// Set default data type to string for serializer
+				field.DataType = String
+				field.Serializer = serializer
+			} else {
+				schema.err = fmt.Errorf("invalid serializer type %v", serializerName)
+			}
+		}
 	}
 
 	if num, ok := field.TagSettings["AUTOINCREMENTINCREMENT"]; ok {
@@ -176,20 +211,6 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
 		field.Scale, _ = strconv.Atoi(s)
 	}
 
-	if val, ok := field.TagSettings["NOT NULL"]; ok && utils.CheckTruth(val) {
-		field.NotNull = true
-	} else if val, ok := field.TagSettings["NOTNULL"]; ok && utils.CheckTruth(val) {
-		field.NotNull = true
-	}
-
-	if val, ok := field.TagSettings["UNIQUE"]; ok && utils.CheckTruth(val) {
-		field.Unique = true
-	}
-
-	if val, ok := field.TagSettings["COMMENT"]; ok {
-		field.Comment = val
-	}
-
 	// default value is function or null or blank (primary keys)
 	field.DefaultValue = strings.TrimSpace(field.DefaultValue)
 	skipParseDefaultValue := strings.Contains(field.DefaultValue, "(") &&
@@ -225,7 +246,6 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
 		}
 	case reflect.String:
 		field.DataType = String
-
 		if field.HasDefaultValue && !skipParseDefaultValue {
 			field.DefaultValue = strings.Trim(field.DefaultValue, "'")
 			field.DefaultValue = strings.Trim(field.DefaultValue, `"`)
@@ -236,17 +256,15 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
 			field.DataType = Time
 		} else if fieldValue.Type().ConvertibleTo(TimeReflectType) {
 			field.DataType = Time
-		} else if fieldValue.Type().ConvertibleTo(reflect.TypeOf(&time.Time{})) {
+		} else if fieldValue.Type().ConvertibleTo(TimePtrReflectType) {
 			field.DataType = Time
 		}
 	case reflect.Array, reflect.Slice:
-		if reflect.Indirect(fieldValue).Type().Elem() == reflect.TypeOf(uint8(0)) {
+		if reflect.Indirect(fieldValue).Type().Elem() == ByteReflectType && field.DataType == "" {
 			field.DataType = Bytes
 		}
 	}
 
-	field.GORMDataType = field.DataType
-
 	if dataTyper, ok := fieldValue.Interface().(GormDataTypeInterface); ok {
 		field.DataType = DataType(dataTyper.GormDataType())
 	}
@@ -346,8 +364,9 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
 		}
 	}
 
-	if _, ok := field.TagSettings["EMBEDDED"]; field.GORMDataType != Time && field.GORMDataType != Bytes &&
-		(ok || (fieldStruct.Anonymous && !isValuer && (field.Creatable || field.Updatable || field.Readable))) {
+	// Normal anonymous field or having `EMBEDDED` tag
+	if _, ok := field.TagSettings["EMBEDDED"]; ok || (field.GORMDataType != Time && field.GORMDataType != Bytes && !isValuer &&
+		fieldStruct.Anonymous && (field.Creatable || field.Updatable || field.Readable)) {
 		kind := reflect.Indirect(fieldValue).Kind()
 		switch kind {
 		case reflect.Struct:
@@ -410,95 +429,122 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
 
 // create valuer, setter when parse struct
 func (field *Field) setupValuerAndSetter() {
-	// ValueOf
-	switch {
-	case len(field.StructField.Index) == 1:
-		field.ValueOf = func(value reflect.Value) (interface{}, bool) {
-			fieldValue := reflect.Indirect(value).Field(field.StructField.Index[0])
-			return fieldValue.Interface(), fieldValue.IsZero()
-		}
-	case len(field.StructField.Index) == 2 && field.StructField.Index[0] >= 0:
-		field.ValueOf = func(value reflect.Value) (interface{}, bool) {
-			fieldValue := reflect.Indirect(value).Field(field.StructField.Index[0]).Field(field.StructField.Index[1])
-			return fieldValue.Interface(), fieldValue.IsZero()
+	// Setup NewValuePool
+	var fieldValue = reflect.New(field.FieldType).Interface()
+	if field.Serializer != nil {
+		field.NewValuePool = &sync.Pool{
+			New: func() interface{} {
+				return &serializer{
+					Field:      field,
+					Serializer: reflect.New(reflect.Indirect(reflect.ValueOf(field.Serializer)).Type()).Interface().(SerializerInterface),
+				}
+			},
 		}
-	default:
-		field.ValueOf = func(value reflect.Value) (interface{}, bool) {
-			v := reflect.Indirect(value)
+	} else if _, ok := fieldValue.(sql.Scanner); !ok {
+		// set default NewValuePool
+		switch field.IndirectFieldType.Kind() {
+		case reflect.String:
+			field.NewValuePool = stringPool
+		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+			field.NewValuePool = intPool
+		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+			field.NewValuePool = uintPool
+		case reflect.Float32, reflect.Float64:
+			field.NewValuePool = floatPool
+		case reflect.Bool:
+			field.NewValuePool = boolPool
+		default:
+			if field.IndirectFieldType == TimeReflectType {
+				field.NewValuePool = timePool
+			}
+		}
+	}
 
-			for _, idx := range field.StructField.Index {
-				if idx >= 0 {
-					v = v.Field(idx)
-				} else {
-					v = v.Field(-idx - 1)
+	if field.NewValuePool == nil {
+		field.NewValuePool = poolInitializer(reflect.PtrTo(field.IndirectFieldType))
+	}
 
-					if v.Type().Elem().Kind() != reflect.Struct {
-						return nil, true
-					}
+	// ValueOf returns field's value and if it is zero
+	field.ValueOf = func(ctx context.Context, v reflect.Value) (interface{}, bool) {
+		v = reflect.Indirect(v)
+		for _, fieldIdx := range field.StructField.Index {
+			if fieldIdx >= 0 {
+				v = v.Field(fieldIdx)
+			} else {
+				v = v.Field(-fieldIdx - 1)
 
-					if !v.IsNil() {
-						v = v.Elem()
-					} else {
-						return nil, true
-					}
+				if !v.IsNil() {
+					v = v.Elem()
+				} else {
+					return nil, true
 				}
 			}
-			return v.Interface(), v.IsZero()
 		}
+
+		fv, zero := v.Interface(), v.IsZero()
+		return fv, zero
 	}
 
-	// ReflectValueOf
-	switch {
-	case len(field.StructField.Index) == 1:
-		field.ReflectValueOf = func(value reflect.Value) reflect.Value {
-			return reflect.Indirect(value).Field(field.StructField.Index[0])
-		}
-	case len(field.StructField.Index) == 2 && field.StructField.Index[0] >= 0 && field.FieldType.Kind() != reflect.Ptr:
-		field.ReflectValueOf = func(value reflect.Value) reflect.Value {
-			return reflect.Indirect(value).Field(field.StructField.Index[0]).Field(field.StructField.Index[1])
+	if field.Serializer != nil {
+		oldValuerOf := field.ValueOf
+		field.ValueOf = func(ctx context.Context, v reflect.Value) (interface{}, bool) {
+			value, zero := oldValuerOf(ctx, v)
+			if zero {
+				return value, zero
+			}
+
+			s, ok := value.(SerializerValuerInterface)
+			if !ok {
+				s = field.Serializer
+			}
+
+			return serializer{
+				Field:           field,
+				SerializeValuer: s,
+				Destination:     v,
+				Context:         ctx,
+				fieldValue:      value,
+			}, false
 		}
-	default:
-		field.ReflectValueOf = func(value reflect.Value) reflect.Value {
-			v := reflect.Indirect(value)
-			for idx, fieldIdx := range field.StructField.Index {
-				if fieldIdx >= 0 {
-					v = v.Field(fieldIdx)
-				} else {
-					v = v.Field(-fieldIdx - 1)
-				}
+	}
 
-				if v.Kind() == reflect.Ptr {
-					if v.Type().Elem().Kind() == reflect.Struct {
-						if v.IsNil() {
-							v.Set(reflect.New(v.Type().Elem()))
-						}
-					}
+	// ReflectValueOf returns field's reflect value
+	field.ReflectValueOf = func(ctx context.Context, v reflect.Value) reflect.Value {
+		v = reflect.Indirect(v)
+		for idx, fieldIdx := range field.StructField.Index {
+			if fieldIdx >= 0 {
+				v = v.Field(fieldIdx)
+			} else {
+				v = v.Field(-fieldIdx - 1)
 
-					if idx < len(field.StructField.Index)-1 {
-						v = v.Elem()
-					}
+				if v.IsNil() {
+					v.Set(reflect.New(v.Type().Elem()))
+				}
+
+				if idx < len(field.StructField.Index)-1 {
+					v = v.Elem()
 				}
 			}
-			return v
 		}
+		return v
 	}
 
-	fallbackSetter := func(value reflect.Value, v interface{}, setter func(reflect.Value, interface{}) error) (err error) {
+	fallbackSetter := func(ctx context.Context, value reflect.Value, v interface{}, setter func(context.Context, reflect.Value, interface{}) error) (err error) {
 		if v == nil {
-			field.ReflectValueOf(value).Set(reflect.New(field.FieldType).Elem())
+			field.ReflectValueOf(ctx, value).Set(reflect.New(field.FieldType).Elem())
 		} else {
 			reflectV := reflect.ValueOf(v)
 			// Optimal value type acquisition for v
 			reflectValType := reflectV.Type()
 
 			if reflectValType.AssignableTo(field.FieldType) {
-				field.ReflectValueOf(value).Set(reflectV)
+				field.ReflectValueOf(ctx, value).Set(reflectV)
 				return
 			} else if reflectValType.ConvertibleTo(field.FieldType) {
-				field.ReflectValueOf(value).Set(reflectV.Convert(field.FieldType))
+				field.ReflectValueOf(ctx, value).Set(reflectV.Convert(field.FieldType))
 				return
 			} else if field.FieldType.Kind() == reflect.Ptr {
-				fieldValue := field.ReflectValueOf(value)
+				fieldValue := field.ReflectValueOf(ctx, value)
 				fieldType := field.FieldType.Elem()
 
 				if reflectValType.AssignableTo(fieldType) {
@@ -521,13 +567,16 @@ func (field *Field) setupValuerAndSetter() {
 
 			if reflectV.Kind() == reflect.Ptr {
 				if reflectV.IsNil() {
-					field.ReflectValueOf(value).Set(reflect.New(field.FieldType).Elem())
+					field.ReflectValueOf(ctx, value).Set(reflect.New(field.FieldType).Elem())
+				} else if reflectV.Type().Elem().AssignableTo(field.FieldType) {
+					field.ReflectValueOf(ctx, value).Set(reflectV.Elem())
+					return
 				} else {
-					err = setter(value, reflectV.Elem().Interface())
+					err = setter(ctx, value, reflectV.Elem().Interface())
 				}
 			} else if valuer, ok := v.(driver.Valuer); ok {
 				if v, err = valuer.Value(); err == nil {
-					err = setter(value, v)
+					err = setter(ctx, value, v)
 				}
 			} else {
 				return fmt.Errorf("failed to set value %+v to field %s", v, field.Name)
@@ -540,191 +589,201 @@ func (field *Field) setupValuerAndSetter() {
 	// Set
 	switch field.FieldType.Kind() {
 	case reflect.Bool:
-		field.Set = func(value reflect.Value, v interface{}) error {
+		field.Set = func(ctx context.Context, value reflect.Value, v interface{}) error {
 			switch data := v.(type) {
-			case bool:
-				field.ReflectValueOf(value).SetBool(data)
-			case *bool:
-				if data != nil {
-					field.ReflectValueOf(value).SetBool(*data)
-				} else {
-					field.ReflectValueOf(value).SetBool(false)
+			case **bool:
+				if data != nil && *data != nil {
+					field.ReflectValueOf(ctx, value).SetBool(**data)
 				}
+			case bool:
+				field.ReflectValueOf(ctx, value).SetBool(data)
 			case int64:
-				if data > 0 {
-					field.ReflectValueOf(value).SetBool(true)
-				} else {
-					field.ReflectValueOf(value).SetBool(false)
-				}
+				field.ReflectValueOf(ctx, value).SetBool(data > 0)
 			case string:
 				b, _ := strconv.ParseBool(data)
-				field.ReflectValueOf(value).SetBool(b)
+				field.ReflectValueOf(ctx, value).SetBool(b)
 			default:
-				return fallbackSetter(value, v, field.Set)
+				return fallbackSetter(ctx, value, v, field.Set)
 			}
 			return nil
 		}
 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-		field.Set = func(value reflect.Value, v interface{}) (err error) {
+		field.Set = func(ctx context.Context, value reflect.Value, v interface{}) (err error) {
 			switch data := v.(type) {
+			case **int64:
+				if data != nil && *data != nil {
+					field.ReflectValueOf(ctx, value).SetInt(**data)
+				}
 			case int64:
-				field.ReflectValueOf(value).SetInt(data)
+				field.ReflectValueOf(ctx, value).SetInt(data)
 			case int:
-				field.ReflectValueOf(value).SetInt(int64(data))
+				field.ReflectValueOf(ctx, value).SetInt(int64(data))
 			case int8:
-				field.ReflectValueOf(value).SetInt(int64(data))
+				field.ReflectValueOf(ctx, value).SetInt(int64(data))
 			case int16:
-				field.ReflectValueOf(value).SetInt(int64(data))
+				field.ReflectValueOf(ctx, value).SetInt(int64(data))
 			case int32:
-				field.ReflectValueOf(value).SetInt(int64(data))
+				field.ReflectValueOf(ctx, value).SetInt(int64(data))
 			case uint:
-				field.ReflectValueOf(value).SetInt(int64(data))
+				field.ReflectValueOf(ctx, value).SetInt(int64(data))
 			case uint8:
-				field.ReflectValueOf(value).SetInt(int64(data))
+				field.ReflectValueOf(ctx, value).SetInt(int64(data))
 			case uint16:
-				field.ReflectValueOf(value).SetInt(int64(data))
+				field.ReflectValueOf(ctx, value).SetInt(int64(data))
 			case uint32:
-				field.ReflectValueOf(value).SetInt(int64(data))
+				field.ReflectValueOf(ctx, value).SetInt(int64(data))
 			case uint64:
-				field.ReflectValueOf(value).SetInt(int64(data))
+				field.ReflectValueOf(ctx, value).SetInt(int64(data))
 			case float32:
-				field.ReflectValueOf(value).SetInt(int64(data))
+				field.ReflectValueOf(ctx, value).SetInt(int64(data))
 			case float64:
-				field.ReflectValueOf(value).SetInt(int64(data))
+				field.ReflectValueOf(ctx, value).SetInt(int64(data))
 			case []byte:
-				return field.Set(value, string(data))
+				return field.Set(ctx, value, string(data))
 			case string:
 				if i, err := strconv.ParseInt(data, 0, 64); err == nil {
-					field.ReflectValueOf(value).SetInt(i)
+					field.ReflectValueOf(ctx, value).SetInt(i)
 				} else {
 					return err
 				}
 			case time.Time:
 				if field.AutoCreateTime == UnixNanosecond || field.AutoUpdateTime == UnixNanosecond {
-					field.ReflectValueOf(value).SetInt(data.UnixNano())
+					field.ReflectValueOf(ctx, value).SetInt(data.UnixNano())
 				} else if field.AutoCreateTime == UnixMillisecond || field.AutoUpdateTime == UnixMillisecond {
-					field.ReflectValueOf(value).SetInt(data.UnixNano() / 1e6)
+					field.ReflectValueOf(ctx, value).SetInt(data.UnixNano() / 1e6)
 				} else {
-					field.ReflectValueOf(value).SetInt(data.Unix())
+					field.ReflectValueOf(ctx, value).SetInt(data.Unix())
 				}
 			case *time.Time:
 				if data != nil {
 					if field.AutoCreateTime == UnixNanosecond || field.AutoUpdateTime == UnixNanosecond {
-						field.ReflectValueOf(value).SetInt(data.UnixNano())
+						field.ReflectValueOf(ctx, value).SetInt(data.UnixNano())
 					} else if field.AutoCreateTime == UnixMillisecond || field.AutoUpdateTime == UnixMillisecond {
-						field.ReflectValueOf(value).SetInt(data.UnixNano() / 1e6)
+						field.ReflectValueOf(ctx, value).SetInt(data.UnixNano() / 1e6)
 					} else {
-						field.ReflectValueOf(value).SetInt(data.Unix())
+						field.ReflectValueOf(ctx, value).SetInt(data.Unix())
 					}
 				} else {
-					field.ReflectValueOf(value).SetInt(0)
+					field.ReflectValueOf(ctx, value).SetInt(0)
 				}
 			default:
-				return fallbackSetter(value, v, field.Set)
+				return fallbackSetter(ctx, value, v, field.Set)
 			}
 			return err
 		}
 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
-		field.Set = func(value reflect.Value, v interface{}) (err error) {
+		field.Set = func(ctx context.Context, value reflect.Value, v interface{}) (err error) {
 			switch data := v.(type) {
+			case **uint64:
+				if data != nil && *data != nil {
+					field.ReflectValueOf(ctx, value).SetUint(**data)
+				}
 			case uint64:
-				field.ReflectValueOf(value).SetUint(data)
+				field.ReflectValueOf(ctx, value).SetUint(data)
 			case uint:
-				field.ReflectValueOf(value).SetUint(uint64(data))
+				field.ReflectValueOf(ctx, value).SetUint(uint64(data))
 			case uint8:
-				field.ReflectValueOf(value).SetUint(uint64(data))
+				field.ReflectValueOf(ctx, value).SetUint(uint64(data))
 			case uint16:
-				field.ReflectValueOf(value).SetUint(uint64(data))
+				field.ReflectValueOf(ctx, value).SetUint(uint64(data))
 			case uint32:
-				field.ReflectValueOf(value).SetUint(uint64(data))
+				field.ReflectValueOf(ctx, value).SetUint(uint64(data))
 			case int64:
-				field.ReflectValueOf(value).SetUint(uint64(data))
+				field.ReflectValueOf(ctx, value).SetUint(uint64(data))
 			case int:
-				field.ReflectValueOf(value).SetUint(uint64(data))
+				field.ReflectValueOf(ctx, value).SetUint(uint64(data))
 			case int8:
-				field.ReflectValueOf(value).SetUint(uint64(data))
+				field.ReflectValueOf(ctx, value).SetUint(uint64(data))
 			case int16:
-				field.ReflectValueOf(value).SetUint(uint64(data))
+				field.ReflectValueOf(ctx, value).SetUint(uint64(data))
 			case int32:
-				field.ReflectValueOf(value).SetUint(uint64(data))
+				field.ReflectValueOf(ctx, value).SetUint(uint64(data))
 			case float32:
-				field.ReflectValueOf(value).SetUint(uint64(data))
+				field.ReflectValueOf(ctx, value).SetUint(uint64(data))
 			case float64:
-				field.ReflectValueOf(value).SetUint(uint64(data))
+				field.ReflectValueOf(ctx, value).SetUint(uint64(data))
 			case []byte:
-				return field.Set(value, string(data))
+				return field.Set(ctx, value, string(data))
 			case time.Time:
 				if field.AutoCreateTime == UnixNanosecond || field.AutoUpdateTime == UnixNanosecond {
-					field.ReflectValueOf(value).SetUint(uint64(data.UnixNano()))
+					field.ReflectValueOf(ctx, value).SetUint(uint64(data.UnixNano()))
 				} else if field.AutoCreateTime == UnixMillisecond || field.AutoUpdateTime == UnixMillisecond {
-					field.ReflectValueOf(value).SetUint(uint64(data.UnixNano() / 1e6))
+					field.ReflectValueOf(ctx, value).SetUint(uint64(data.UnixNano() / 1e6))
 				} else {
-					field.ReflectValueOf(value).SetUint(uint64(data.Unix()))
+					field.ReflectValueOf(ctx, value).SetUint(uint64(data.Unix()))
 				}
 			case string:
 				if i, err := strconv.ParseUint(data, 0, 64); err == nil {
-					field.ReflectValueOf(value).SetUint(i)
+					field.ReflectValueOf(ctx, value).SetUint(i)
 				} else {
 					return err
 				}
 			default:
-				return fallbackSetter(value, v, field.Set)
+				return fallbackSetter(ctx, value, v, field.Set)
 			}
 			return err
 		}
 	case reflect.Float32, reflect.Float64:
-		field.Set = func(value reflect.Value, v interface{}) (err error) {
+		field.Set = func(ctx context.Context, value reflect.Value, v interface{}) (err error) {
 			switch data := v.(type) {
+			case **float64:
+				if data != nil && *data != nil {
+					field.ReflectValueOf(ctx, value).SetFloat(**data)
+				}
 			case float64:
-				field.ReflectValueOf(value).SetFloat(data)
+				field.ReflectValueOf(ctx, value).SetFloat(data)
 			case float32:
-				field.ReflectValueOf(value).SetFloat(float64(data))
+				field.ReflectValueOf(ctx, value).SetFloat(float64(data))
 			case int64:
-				field.ReflectValueOf(value).SetFloat(float64(data))
+				field.ReflectValueOf(ctx, value).SetFloat(float64(data))
 			case int:
-				field.ReflectValueOf(value).SetFloat(float64(data))
+				field.ReflectValueOf(ctx, value).SetFloat(float64(data))
 			case int8:
-				field.ReflectValueOf(value).SetFloat(float64(data))
+				field.ReflectValueOf(ctx, value).SetFloat(float64(data))
 			case int16:
-				field.ReflectValueOf(value).SetFloat(float64(data))
+				field.ReflectValueOf(ctx, value).SetFloat(float64(data))
 			case int32:
-				field.ReflectValueOf(value).SetFloat(float64(data))
+				field.ReflectValueOf(ctx, value).SetFloat(float64(data))
 			case uint:
-				field.ReflectValueOf(value).SetFloat(float64(data))
+				field.ReflectValueOf(ctx, value).SetFloat(float64(data))
 			case uint8:
-				field.ReflectValueOf(value).SetFloat(float64(data))
+				field.ReflectValueOf(ctx, value).SetFloat(float64(data))
 			case uint16:
-				field.ReflectValueOf(value).SetFloat(float64(data))
+				field.ReflectValueOf(ctx, value).SetFloat(float64(data))
 			case uint32:
-				field.ReflectValueOf(value).SetFloat(float64(data))
+				field.ReflectValueOf(ctx, value).SetFloat(float64(data))
 			case uint64:
-				field.ReflectValueOf(value).SetFloat(float64(data))
+				field.ReflectValueOf(ctx, value).SetFloat(float64(data))
 			case []byte:
-				return field.Set(value, string(data))
+				return field.Set(ctx, value, string(data))
 			case string:
 				if i, err := strconv.ParseFloat(data, 64); err == nil {
-					field.ReflectValueOf(value).SetFloat(i)
+					field.ReflectValueOf(ctx, value).SetFloat(i)
 				} else {
 					return err
 				}
 			default:
-				return fallbackSetter(value, v, field.Set)
+				return fallbackSetter(ctx, value, v, field.Set)
 			}
 			return err
 		}
 	case reflect.String:
-		field.Set = func(value reflect.Value, v interface{}) (err error) {
+		field.Set = func(ctx context.Context, value reflect.Value, v interface{}) (err error) {
 			switch data := v.(type) {
+			case **string:
+				if data != nil && *data != nil {
+					field.ReflectValueOf(ctx, value).SetString(**data)
+				}
 			case string:
-				field.ReflectValueOf(value).SetString(data)
+				field.ReflectValueOf(ctx, value).SetString(data)
 			case []byte:
-				field.ReflectValueOf(value).SetString(string(data))
+				field.ReflectValueOf(ctx, value).SetString(string(data))
 			case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
-				field.ReflectValueOf(value).SetString(utils.ToString(data))
+				field.ReflectValueOf(ctx, value).SetString(utils.ToString(data))
 			case float64, float32:
-				field.ReflectValueOf(value).SetString(fmt.Sprintf("%."+strconv.Itoa(field.Precision)+"f", data))
+				field.ReflectValueOf(ctx, value).SetString(fmt.Sprintf("%."+strconv.Itoa(field.Precision)+"f", data))
 			default:
-				return fallbackSetter(value, v, field.Set)
+				return fallbackSetter(ctx, value, v, field.Set)
 			}
 			return err
 		}
@@ -732,41 +791,49 @@ func (field *Field) setupValuerAndSetter() {
 		fieldValue := reflect.New(field.FieldType)
 		switch fieldValue.Elem().Interface().(type) {
 		case time.Time:
-			field.Set = func(value reflect.Value, v interface{}) error {
+			field.Set = func(ctx context.Context, value reflect.Value, v interface{}) error {
 				switch data := v.(type) {
+				case **time.Time:
+					if data != nil && *data != nil {
+						field.Set(ctx, value, *data)
+					}
 				case time.Time:
-					field.ReflectValueOf(value).Set(reflect.ValueOf(v))
+					field.ReflectValueOf(ctx, value).Set(reflect.ValueOf(v))
 				case *time.Time:
 					if data != nil {
-						field.ReflectValueOf(value).Set(reflect.ValueOf(data).Elem())
+						field.ReflectValueOf(ctx, value).Set(reflect.ValueOf(data).Elem())
 					} else {
-						field.ReflectValueOf(value).Set(reflect.ValueOf(time.Time{}))
+						field.ReflectValueOf(ctx, value).Set(reflect.ValueOf(time.Time{}))
 					}
 				case string:
 					if t, err := now.Parse(data); err == nil {
-						field.ReflectValueOf(value).Set(reflect.ValueOf(t))
+						field.ReflectValueOf(ctx, value).Set(reflect.ValueOf(t))
 					} else {
 						return fmt.Errorf("failed to set string %v to time.Time field %s, failed to parse it as time, got error %v", v, field.Name, err)
 					}
 				default:
-					return fallbackSetter(value, v, field.Set)
+					return fallbackSetter(ctx, value, v, field.Set)
 				}
 				return nil
 			}
 		case *time.Time:
-			field.Set = func(value reflect.Value, v interface{}) error {
+			field.Set = func(ctx context.Context, value reflect.Value, v interface{}) error {
 				switch data := v.(type) {
+				case **time.Time:
+					if data != nil {
+						field.ReflectValueOf(ctx, value).Set(reflect.ValueOf(*data))
+					}
 				case time.Time:
-					fieldValue := field.ReflectValueOf(value)
+					fieldValue := field.ReflectValueOf(ctx, value)
 					if fieldValue.IsNil() {
 						fieldValue.Set(reflect.New(field.FieldType.Elem()))
 					}
 					fieldValue.Elem().Set(reflect.ValueOf(v))
 				case *time.Time:
-					field.ReflectValueOf(value).Set(reflect.ValueOf(v))
+					field.ReflectValueOf(ctx, value).Set(reflect.ValueOf(v))
 				case string:
 					if t, err := now.Parse(data); err == nil {
-						fieldValue := field.ReflectValueOf(value)
+						fieldValue := field.ReflectValueOf(ctx, value)
 						if fieldValue.IsNil() {
 							if v == "" {
 								return nil
@@ -778,27 +845,27 @@ func (field *Field) setupValuerAndSetter() {
 						return fmt.Errorf("failed to set string %v to time.Time field %s, failed to parse it as time, got error %v", v, field.Name, err)
 					}
 				default:
-					return fallbackSetter(value, v, field.Set)
+					return fallbackSetter(ctx, value, v, field.Set)
 				}
 				return nil
 			}
 		default:
 			if _, ok := fieldValue.Elem().Interface().(sql.Scanner); ok {
 				// pointer scanner
-				field.Set = func(value reflect.Value, v interface{}) (err error) {
+				field.Set = func(ctx context.Context, value reflect.Value, v interface{}) (err error) {
 					reflectV := reflect.ValueOf(v)
 					if !reflectV.IsValid() {
-						field.ReflectValueOf(value).Set(reflect.New(field.FieldType).Elem())
+						field.ReflectValueOf(ctx, value).Set(reflect.New(field.FieldType).Elem())
 					} else if reflectV.Type().AssignableTo(field.FieldType) {
-						field.ReflectValueOf(value).Set(reflectV)
+						field.ReflectValueOf(ctx, value).Set(reflectV)
 					} else if reflectV.Kind() == reflect.Ptr {
 						if reflectV.IsNil() || !reflectV.IsValid() {
-							field.ReflectValueOf(value).Set(reflect.New(field.FieldType).Elem())
+							field.ReflectValueOf(ctx, value).Set(reflect.New(field.FieldType).Elem())
 						} else {
-							return field.Set(value, reflectV.Elem().Interface())
+							return field.Set(ctx, value, reflectV.Elem().Interface())
 						}
 					} else {
-						fieldValue := field.ReflectValueOf(value)
+						fieldValue := field.ReflectValueOf(ctx, value)
 						if fieldValue.IsNil() {
 							fieldValue.Set(reflect.New(field.FieldType.Elem()))
 						}
@@ -813,32 +880,61 @@ func (field *Field) setupValuerAndSetter() {
 				}
 			} else if _, ok := fieldValue.Interface().(sql.Scanner); ok {
 				// struct scanner
-				field.Set = func(value reflect.Value, v interface{}) (err error) {
+				field.Set = func(ctx context.Context, value reflect.Value, v interface{}) (err error) {
 					reflectV := reflect.ValueOf(v)
 					if !reflectV.IsValid() {
-						field.ReflectValueOf(value).Set(reflect.New(field.FieldType).Elem())
+						field.ReflectValueOf(ctx, value).Set(reflect.New(field.FieldType).Elem())
 					} else if reflectV.Type().AssignableTo(field.FieldType) {
-						field.ReflectValueOf(value).Set(reflectV)
+						field.ReflectValueOf(ctx, value).Set(reflectV)
 					} else if reflectV.Kind() == reflect.Ptr {
 						if reflectV.IsNil() || !reflectV.IsValid() {
-							field.ReflectValueOf(value).Set(reflect.New(field.FieldType).Elem())
+							field.ReflectValueOf(ctx, value).Set(reflect.New(field.FieldType).Elem())
 						} else {
-							return field.Set(value, reflectV.Elem().Interface())
+							return field.Set(ctx, value, reflectV.Elem().Interface())
 						}
 					} else {
 						if valuer, ok := v.(driver.Valuer); ok {
 							v, _ = valuer.Value()
 						}
 
-						err = field.ReflectValueOf(value).Addr().Interface().(sql.Scanner).Scan(v)
+						err = field.ReflectValueOf(ctx, value).Addr().Interface().(sql.Scanner).Scan(v)
 					}
 					return
 				}
 			} else {
-				field.Set = func(value reflect.Value, v interface{}) (err error) {
-					return fallbackSetter(value, v, field.Set)
+				field.Set = func(ctx context.Context, value reflect.Value, v interface{}) (err error) {
+					return fallbackSetter(ctx, value, v, field.Set)
 				}
 			}
 		}
 	}
+
+	if field.Serializer != nil {
+		var (
+			oldFieldSetter = field.Set
+			sameElemType   bool
+			sameType       = field.FieldType == reflect.ValueOf(field.Serializer).Type()
+		)
+
+		if reflect.ValueOf(field.Serializer).Kind() == reflect.Ptr {
+			sameElemType = field.FieldType == reflect.ValueOf(field.Serializer).Type().Elem()
+		}
+
+		field.Set = func(ctx context.Context, value reflect.Value, v interface{}) (err error) {
+			if s, ok := v.(*serializer); ok {
+				if err = s.Serializer.Scan(ctx, field, value, s.value); err == nil {
+					if sameElemType {
+						field.ReflectValueOf(ctx, value).Set(reflect.ValueOf(s.Serializer).Elem())
+						s.Serializer = reflect.New(reflect.Indirect(reflect.ValueOf(field.Serializer)).Type()).Interface().(SerializerInterface)
+					} else if sameType {
+						field.ReflectValueOf(ctx, value).Set(reflect.ValueOf(s.Serializer))
+						s.Serializer = reflect.New(reflect.Indirect(reflect.ValueOf(field.Serializer)).Type()).Interface().(SerializerInterface)
+					}
+				}
+			} else {
+				err = oldFieldSetter(ctx, value, v)
+			}
+			return
+		}
+	}
 }
diff --git a/schema/interfaces.go b/schema/interfaces.go
index 98abffb..a75a33c 100644
--- a/schema/interfaces.go
+++ b/schema/interfaces.go
@@ -4,22 +4,33 @@ import (
 	"gorm.io/gorm/clause"
 )
 
+// GormDataTypeInterface gorm data type interface
 type GormDataTypeInterface interface {
 	GormDataType() string
 }
 
+// FieldNewValuePool field new scan value pool
+type FieldNewValuePool interface {
+	Get() interface{}
+	Put(interface{})
+}
+
+// CreateClausesInterface create clauses interface
 type CreateClausesInterface interface {
 	CreateClauses(*Field) []clause.Interface
 }
 
+// QueryClausesInterface query clauses interface
 type QueryClausesInterface interface {
 	QueryClauses(*Field) []clause.Interface
 }
 
+// UpdateClausesInterface update clauses interface
 type UpdateClausesInterface interface {
 	UpdateClauses(*Field) []clause.Interface
 }
 
+// DeleteClausesInterface delete clauses interface
 type DeleteClausesInterface interface {
 	DeleteClauses(*Field) []clause.Interface
 }
diff --git a/schema/pool.go b/schema/pool.go
new file mode 100644
index 0000000..f5c7315
--- /dev/null
+++ b/schema/pool.go
@@ -0,0 +1,62 @@
+package schema
+
+import (
+	"reflect"
+	"sync"
+	"time"
+)
+
+// sync pools
+var (
+	normalPool sync.Map
+	stringPool = &sync.Pool{
+		New: func() interface{} {
+			var v string
+			ptrV := &v
+			return &ptrV
+		},
+	}
+	intPool = &sync.Pool{
+		New: func() interface{} {
+			var v int64
+			ptrV := &v
+			return &ptrV
+		},
+	}
+	uintPool = &sync.Pool{
+		New: func() interface{} {
+			var v uint64
+			ptrV := &v
+			return &ptrV
+		},
+	}
+	floatPool = &sync.Pool{
+		New: func() interface{} {
+			var v float64
+			ptrV := &v
+			return &ptrV
+		},
+	}
+	boolPool = &sync.Pool{
+		New: func() interface{} {
+			var v bool
+			ptrV := &v
+			return &ptrV
+		},
+	}
+	timePool = &sync.Pool{
+		New: func() interface{} {
+			var v time.Time
+			ptrV := &v
+			return &ptrV
+		},
+	}
+	poolInitializer = func(reflectType reflect.Type) FieldNewValuePool {
+		v, _ := normalPool.LoadOrStore(reflectType, &sync.Pool{
+			New: func() interface{} {
+				return reflect.New(reflectType).Interface()
+			},
+		})
+		return v.(FieldNewValuePool)
+	}
+)
diff --git a/schema/relationship.go b/schema/relationship.go
index c5d3dca..eae8ab0 100644
--- a/schema/relationship.go
+++ b/schema/relationship.go
@@ -1,6 +1,7 @@
 package schema
 
 import (
+	"context"
 	"fmt"
 	"reflect"
 	"strings"
@@ -576,7 +577,7 @@ func (rel *Relationship) ParseConstraint() *Constraint {
 	return &constraint
 }
 
-func (rel *Relationship) ToQueryConditions(reflectValue reflect.Value) (conds []clause.Expression) {
+func (rel *Relationship) ToQueryConditions(ctx context.Context, reflectValue reflect.Value) (conds []clause.Expression) {
 	table := rel.FieldSchema.Table
 	foreignFields := []*Field{}
 	relForeignKeys := []string{}
@@ -616,7 +617,7 @@ func (rel *Relationship) ToQueryConditions(reflectValue reflect.Value) (conds []
 		}
 	}
 
-	_, foreignValues := GetIdentityFieldValuesMap(reflectValue, foreignFields)
+	_, foreignValues := GetIdentityFieldValuesMap(ctx, reflectValue, foreignFields)
 	column, values := ToQueryValues(table, relForeignKeys, foreignValues)
 
 	conds = append(conds, clause.IN{Column: column, Values: values})
diff --git a/schema/serializer.go b/schema/serializer.go
new file mode 100644
index 0000000..6859753
--- /dev/null
+++ b/schema/serializer.go
@@ -0,0 +1,125 @@
+package schema
+
+import (
+	"context"
+	"database/sql"
+	"database/sql/driver"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"reflect"
+	"strings"
+	"sync"
+	"time"
+)
+
+var serializerMap = sync.Map{}
+
+// RegisterSerializer register serializer
+func RegisterSerializer(name string, serializer SerializerInterface) {
+	serializerMap.Store(strings.ToLower(name), serializer)
+}
+
+// GetSerializer get serializer
+func GetSerializer(name string) (serializer SerializerInterface, ok bool) {
+	v, ok := serializerMap.Load(strings.ToLower(name))
+	if ok {
+		serializer, ok = v.(SerializerInterface)
+	}
+	return serializer, ok
+}
+
+func init() {
+	RegisterSerializer("json", JSONSerializer{})
+	RegisterSerializer("unixtime", UnixSecondSerializer{})
+}
+
+// Serializer field value serializer
+type serializer struct {
+	Field           *Field
+	Serializer      SerializerInterface
+	SerializeValuer SerializerValuerInterface
+	Destination     reflect.Value
+	Context         context.Context
+	value           interface{}
+	fieldValue      interface{}
+}
+
+// Scan implements sql.Scanner interface
+func (s *serializer) Scan(value interface{}) error {
+	s.value = value
+	return nil
+}
+
+// Value implements driver.Valuer interface
+func (s serializer) Value() (driver.Value, error) {
+	return s.SerializeValuer.Value(s.Context, s.Field, s.Destination, s.fieldValue)
+}
+
+// SerializerInterface serializer interface
+type SerializerInterface interface {
+	Scan(ctx context.Context, field *Field, dst reflect.Value, dbValue interface{}) error
+	SerializerValuerInterface
+}
+
+// SerializerValuerInterface serializer valuer interface
+type SerializerValuerInterface interface {
+	Value(ctx context.Context, field *Field, dst reflect.Value, fieldValue interface{}) (interface{}, error)
+}
+
+// JSONSerializer json serializer
+type JSONSerializer struct {
+}
+
+// Scan implements serializer interface
+func (JSONSerializer) Scan(ctx context.Context, field *Field, dst reflect.Value, dbValue interface{}) (err error) {
+	fieldValue := reflect.New(field.FieldType)
+
+	if dbValue != nil {
+		var bytes []byte
+		switch v := dbValue.(type) {
+		case []byte:
+			bytes = v
+		case string:
+			bytes = []byte(v)
+		default:
+			return errors.New(fmt.Sprint("Failed to unmarshal JSONB value:", dbValue))
+		}
+
+		err = json.Unmarshal(bytes, fieldValue.Interface())
+	}
+
+	field.ReflectValueOf(ctx, dst).Set(fieldValue.Elem())
+	return
+}
+
+// Value implements serializer interface
+func (JSONSerializer) Value(ctx context.Context, field *Field, dst reflect.Value, fieldValue interface{}) (interface{}, error) {
+	result, err := json.Marshal(fieldValue)
+	return string(result), err
+}
+
+// UnixSecondSerializer json serializer
+type UnixSecondSerializer struct {
+}
+
+// Scan implements serializer interface
+func (UnixSecondSerializer) Scan(ctx context.Context, field *Field, dst reflect.Value, dbValue interface{}) (err error) {
+	t := sql.NullTime{}
+	if err = t.Scan(dbValue); err == nil {
+		err = field.Set(ctx, dst, t.Time)
+	}
+
+	return
+}
+
+// Value implements serializer interface
+func (UnixSecondSerializer) Value(ctx context.Context, field *Field, dst reflect.Value, fieldValue interface{}) (result interface{}, err error) {
+	switch v := fieldValue.(type) {
+	case int64, int, uint, uint64, int32, uint32, int16, uint16:
+		result = time.Unix(reflect.ValueOf(v).Int(), 0)
+	default:
+		err = fmt.Errorf("invalid field type %#v for UnixSecondSerializer, only int, uint supported", v)
+	}
+	return
+}
diff --git a/schema/utils.go b/schema/utils.go
index e005cc7..2720c53 100644
--- a/schema/utils.go
+++ b/schema/utils.go
@@ -1,6 +1,7 @@
 package schema
 
 import (
+	"context"
 	"reflect"
 	"regexp"
 	"strings"
@@ -59,13 +60,13 @@ func removeSettingFromTag(tag reflect.StructTag, names ...string) reflect.Struct
 }
 
 // GetRelationsValues get relations's values from a reflect value
-func GetRelationsValues(reflectValue reflect.Value, rels []*Relationship) (reflectResults reflect.Value) {
+func GetRelationsValues(ctx context.Context, reflectValue reflect.Value, rels []*Relationship) (reflectResults reflect.Value) {
 	for _, rel := range rels {
 		reflectResults = reflect.MakeSlice(reflect.SliceOf(reflect.PtrTo(rel.FieldSchema.ModelType)), 0, 1)
 
 		appendToResults := func(value reflect.Value) {
-			if _, isZero := rel.Field.ValueOf(value); !isZero {
-				result := reflect.Indirect(rel.Field.ReflectValueOf(value))
+			if _, isZero := rel.Field.ValueOf(ctx, value); !isZero {
+				result := reflect.Indirect(rel.Field.ReflectValueOf(ctx, value))
 				switch result.Kind() {
 				case reflect.Struct:
 					reflectResults = reflect.Append(reflectResults, result.Addr())
@@ -97,7 +98,7 @@ func GetRelationsValues(reflectValue reflect.Value, rels []*Relationship) (refle
 }
 
 // GetIdentityFieldValuesMap get identity map from fields
-func GetIdentityFieldValuesMap(reflectValue reflect.Value, fields []*Field) (map[string][]reflect.Value, [][]interface{}) {
+func GetIdentityFieldValuesMap(ctx context.Context, reflectValue reflect.Value, fields []*Field) (map[string][]reflect.Value, [][]interface{}) {
 	var (
 		results       = [][]interface{}{}
 		dataResults   = map[string][]reflect.Value{}
@@ -110,7 +111,7 @@ func GetIdentityFieldValuesMap(reflectValue reflect.Value, fields []*Field) (map
 		results = [][]interface{}{make([]interface{}, len(fields))}
 
 		for idx, field := range fields {
-			results[0][idx], zero = field.ValueOf(reflectValue)
+			results[0][idx], zero = field.ValueOf(ctx, reflectValue)
 			notZero = notZero || !zero
 		}
 
@@ -135,7 +136,7 @@ func GetIdentityFieldValuesMap(reflectValue reflect.Value, fields []*Field) (map
 			fieldValues := make([]interface{}, len(fields))
 			notZero = false
 			for idx, field := range fields {
-				fieldValues[idx], zero = field.ValueOf(elem)
+				fieldValues[idx], zero = field.ValueOf(ctx, elem)
 				notZero = notZero || !zero
 			}
 
@@ -155,12 +156,12 @@ func GetIdentityFieldValuesMap(reflectValue reflect.Value, fields []*Field) (map
 }
 
 // GetIdentityFieldValuesMapFromValues get identity map from fields
-func GetIdentityFieldValuesMapFromValues(values []interface{}, fields []*Field) (map[string][]reflect.Value, [][]interface{}) {
+func GetIdentityFieldValuesMapFromValues(ctx context.Context, values []interface{}, fields []*Field) (map[string][]reflect.Value, [][]interface{}) {
 	resultsMap := map[string][]reflect.Value{}
 	results := [][]interface{}{}
 
 	for _, v := range values {
-		rm, rs := GetIdentityFieldValuesMap(reflect.Indirect(reflect.ValueOf(v)), fields)
+		rm, rs := GetIdentityFieldValuesMap(ctx, reflect.Indirect(reflect.ValueOf(v)), fields)
 		for k, v := range rm {
 			resultsMap[k] = append(resultsMap[k], v...)
 		}
diff --git a/soft_delete.go b/soft_delete.go
index 4582161..ba6d211 100644
--- a/soft_delete.go
+++ b/soft_delete.go
@@ -135,7 +135,7 @@ func (sd SoftDeleteDeleteClause) ModifyStatement(stmt *Statement) {
 		stmt.SetColumn(sd.Field.DBName, curTime, true)
 
 		if stmt.Schema != nil {
-			_, queryValues := schema.GetIdentityFieldValuesMap(stmt.ReflectValue, stmt.Schema.PrimaryFields)
+			_, queryValues := schema.GetIdentityFieldValuesMap(stmt.Context, stmt.ReflectValue, stmt.Schema.PrimaryFields)
 			column, values := schema.ToQueryValues(stmt.Table, stmt.Schema.PrimaryFieldDBNames, queryValues)
 
 			if len(values) > 0 {
@@ -143,7 +143,7 @@ func (sd SoftDeleteDeleteClause) ModifyStatement(stmt *Statement) {
 			}
 
 			if stmt.ReflectValue.CanAddr() && stmt.Dest != stmt.Model && stmt.Model != nil {
-				_, queryValues = schema.GetIdentityFieldValuesMap(reflect.ValueOf(stmt.Model), stmt.Schema.PrimaryFields)
+				_, queryValues = schema.GetIdentityFieldValuesMap(stmt.Context, reflect.ValueOf(stmt.Model), stmt.Schema.PrimaryFields)
 				column, values = schema.ToQueryValues(stmt.Table, stmt.Schema.PrimaryFieldDBNames, queryValues)
 
 				if len(values) > 0 {
diff --git a/statement.go b/statement.go
index 2321264..cb47177 100644
--- a/statement.go
+++ b/statement.go
@@ -389,7 +389,7 @@ func (stmt *Statement) BuildCondition(query interface{}, args ...interface{}) []
 					for _, field := range s.Fields {
 						selected := selectedColumns[field.DBName] || selectedColumns[field.Name]
 						if selected || (!restricted && field.Readable) {
-							if v, isZero := field.ValueOf(reflectValue); !isZero || selected {
+							if v, isZero := field.ValueOf(stmt.Context, reflectValue); !isZero || selected {
 								if field.DBName != "" {
 									conds = append(conds, clause.Eq{Column: clause.Column{Table: clause.CurrentTable, Name: field.DBName}, Value: v})
 								} else if field.DataType != "" {
@@ -403,7 +403,7 @@ func (stmt *Statement) BuildCondition(query interface{}, args ...interface{}) []
 						for _, field := range s.Fields {
 							selected := selectedColumns[field.DBName] || selectedColumns[field.Name]
 							if selected || (!restricted && field.Readable) {
-								if v, isZero := field.ValueOf(reflectValue.Index(i)); !isZero || selected {
+								if v, isZero := field.ValueOf(stmt.Context, reflectValue.Index(i)); !isZero || selected {
 									if field.DBName != "" {
 										conds = append(conds, clause.Eq{Column: clause.Column{Table: clause.CurrentTable, Name: field.DBName}, Value: v})
 									} else if field.DataType != "" {
@@ -562,7 +562,7 @@ func (stmt *Statement) SetColumn(name string, value interface{}, fromCallbacks .
 
 				switch destValue.Kind() {
 				case reflect.Struct:
-					field.Set(destValue, value)
+					field.Set(stmt.Context, destValue, value)
 				default:
 					stmt.AddError(ErrInvalidData)
 				}
@@ -572,10 +572,10 @@ func (stmt *Statement) SetColumn(name string, value interface{}, fromCallbacks .
 			case reflect.Slice, reflect.Array:
 				if len(fromCallbacks) > 0 {
 					for i := 0; i < stmt.ReflectValue.Len(); i++ {
-						field.Set(stmt.ReflectValue.Index(i), value)
+						field.Set(stmt.Context, stmt.ReflectValue.Index(i), value)
 					}
 				} else {
-					field.Set(stmt.ReflectValue.Index(stmt.CurDestIndex), value)
+					field.Set(stmt.Context, stmt.ReflectValue.Index(stmt.CurDestIndex), value)
 				}
 			case reflect.Struct:
 				if !stmt.ReflectValue.CanAddr() {
@@ -583,7 +583,7 @@ func (stmt *Statement) SetColumn(name string, value interface{}, fromCallbacks .
 					return
 				}
 
-				field.Set(stmt.ReflectValue, value)
+				field.Set(stmt.Context, stmt.ReflectValue, value)
 			}
 		} else {
 			stmt.AddError(ErrInvalidField)
@@ -603,7 +603,7 @@ func (stmt *Statement) Changed(fields ...string) bool {
 
 	selectColumns, restricted := stmt.SelectAndOmitColumns(false, true)
 	changed := func(field *schema.Field) bool {
-		fieldValue, _ := field.ValueOf(modelValue)
+		fieldValue, _ := field.ValueOf(stmt.Context, modelValue)
 		if v, ok := selectColumns[field.DBName]; (ok && v) || (!ok && !restricted) {
 			if v, ok := stmt.Dest.(map[string]interface{}); ok {
 				if fv, ok := v[field.Name]; ok {
@@ -617,7 +617,7 @@ func (stmt *Statement) Changed(fields ...string) bool {
 					destValue = destValue.Elem()
 				}
 
-				changedValue, zero := field.ValueOf(destValue)
+				changedValue, zero := field.ValueOf(stmt.Context, destValue)
 				return !zero && !utils.AssertEqual(changedValue, fieldValue)
 			}
 		}
diff --git a/utils/utils.go b/utils/utils.go
index f00f92b..28ca0da 100644
--- a/utils/utils.go
+++ b/utils/utils.go
@@ -36,17 +36,14 @@ func IsValidDBNameChar(c rune) bool {
 	return !unicode.IsLetter(c) && !unicode.IsNumber(c) && c != '.' && c != '*' && c != '_' && c != '$' && c != '@'
 }
 
-func CheckTruth(val interface{}) bool {
-	if v, ok := val.(bool); ok {
-		return v
-	}
-
-	if v, ok := val.(string); ok {
-		v = strings.ToLower(v)
-		return v != "false"
+// CheckTruth check string true or not
+func CheckTruth(vals ...string) bool {
+	for _, val := range vals {
+		if !strings.EqualFold(val, "false") && val != "" {
+			return true
+		}
 	}
-
-	return !reflect.ValueOf(val).IsZero()
+	return false
 }
 
 func ToStringKey(values ...interface{}) string {


Test patch:
diff --git a/clause/where_test.go b/clause/where_test.go
index 272c7b7..35e3dbe 100644
--- a/clause/where_test.go
+++ b/clause/where_test.go
@@ -66,6 +66,45 @@ func TestWhere(t *testing.T) {
 			"SELECT * FROM `users` WHERE (`age` = ? OR `name` <> ?)",
 			[]interface{}{18, "jinzhu"},
 		},
+		{
+			[]clause.Interface{clause.Select{}, clause.From{}, clause.Where{
+				Exprs: []clause.Expression{clause.Not(clause.Eq{Column: clause.PrimaryColumn, Value: "1"}, clause.Gt{Column: "age", Value: 18}), clause.And(clause.Expr{SQL: "`score` <= ?", Vars: []interface{}{100}, WithoutParentheses: false})},
+			}},
+			"SELECT * FROM `users` WHERE (`users`.`id` <> ? AND `age` <= ?) AND `score` <= ?",
+			[]interface{}{"1", 18, 100},
+		},
+		{
+			[]clause.Interface{clause.Select{}, clause.From{}, clause.Where{
+				Exprs: []clause.Expression{clause.Not(clause.Eq{Column: clause.PrimaryColumn, Value: "1"}, clause.Gt{Column: "age", Value: 18}), clause.Expr{SQL: "`score` <= ?", Vars: []interface{}{100}, WithoutParentheses: false}},
+			}},
+			"SELECT * FROM `users` WHERE (`users`.`id` <> ? AND `age` <= ?) AND `score` <= ?",
+			[]interface{}{"1", 18, 100},
+		},
+		{
+			[]clause.Interface{clause.Select{}, clause.From{}, clause.Where{
+				Exprs: []clause.Expression{clause.Not(clause.Eq{Column: clause.PrimaryColumn, Value: "1"}, clause.Gt{Column: "age", Value: 18}), clause.Or(clause.Expr{SQL: "`score` <= ?", Vars: []interface{}{100}, WithoutParentheses: false})},
+			}},
+			"SELECT * FROM `users` WHERE (`users`.`id` <> ? AND `age` <= ?) OR `score` <= ?",
+			[]interface{}{"1", 18, 100},
+		},
+		{
+			[]clause.Interface{clause.Select{}, clause.From{}, clause.Where{
+				Exprs: []clause.Expression{
+					clause.And(clause.Not(clause.Eq{Column: clause.PrimaryColumn, Value: "1"}),
+						clause.And(clause.Expr{SQL: "`score` <= ?", Vars: []interface{}{100}, WithoutParentheses: false})),
+				},
+			}},
+			"SELECT * FROM `users` WHERE (`users`.`id` <> ? AND `score` <= ?)",
+			[]interface{}{"1", 100},
+		},
+		{
+			[]clause.Interface{clause.Select{}, clause.From{}, clause.Where{
+				Exprs: []clause.Expression{clause.Not(clause.Eq{Column: clause.PrimaryColumn, Value: "1"},
+					clause.And(clause.Expr{SQL: "`score` <= ?", Vars: []interface{}{100}, WithoutParentheses: false}))},
+			}},
+			"SELECT * FROM `users` WHERE (`users`.`id` <> ? AND NOT `score` <= ?)",
+			[]interface{}{"1", 100},
+		},
 	}
 
 	for idx, result := range results {
diff --git a/schema/field_test.go b/schema/field_test.go
index 8fa46b8..300e375 100644
--- a/schema/field_test.go
+++ b/schema/field_test.go
@@ -1,6 +1,7 @@
 package schema_test
 
 import (
+	"context"
 	"database/sql"
 	"reflect"
 	"sync"
@@ -57,7 +58,7 @@ func TestFieldValuerAndSetter(t *testing.T) {
 	}
 
 	for k, v := range newValues {
-		if err := userSchema.FieldsByDBName[k].Set(reflectValue, v); err != nil {
+		if err := userSchema.FieldsByDBName[k].Set(context.Background(), reflectValue, v); err != nil {
 			t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
 		}
 	}
@@ -80,7 +81,7 @@ func TestFieldValuerAndSetter(t *testing.T) {
 	}
 
 	for k, v := range newValues2 {
-		if err := userSchema.FieldsByDBName[k].Set(reflectValue, v); err != nil {
+		if err := userSchema.FieldsByDBName[k].Set(context.Background(), reflectValue, v); err != nil {
 			t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
 		}
 	}
@@ -132,7 +133,7 @@ func TestPointerFieldValuerAndSetter(t *testing.T) {
 	}
 
 	for k, v := range newValues {
-		if err := userSchema.FieldsByDBName[k].Set(reflectValue, v); err != nil {
+		if err := userSchema.FieldsByDBName[k].Set(context.Background(), reflectValue, v); err != nil {
 			t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
 		}
 	}
@@ -151,7 +152,7 @@ func TestPointerFieldValuerAndSetter(t *testing.T) {
 	}
 
 	for k, v := range newValues2 {
-		if err := userSchema.FieldsByDBName[k].Set(reflectValue, v); err != nil {
+		if err := userSchema.FieldsByDBName[k].Set(context.Background(), reflectValue, v); err != nil {
 			t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
 		}
 	}
@@ -202,7 +203,7 @@ func TestAdvancedDataTypeValuerAndSetter(t *testing.T) {
 	}
 
 	for k, v := range newValues {
-		if err := userSchema.FieldsByDBName[k].Set(reflectValue, v); err != nil {
+		if err := userSchema.FieldsByDBName[k].Set(context.Background(), reflectValue, v); err != nil {
 			t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
 		}
 	}
@@ -219,7 +220,7 @@ func TestAdvancedDataTypeValuerAndSetter(t *testing.T) {
 	}
 
 	for k, v := range newValues2 {
-		if err := userSchema.FieldsByDBName[k].Set(reflectValue, v); err != nil {
+		if err := userSchema.FieldsByDBName[k].Set(context.Background(), reflectValue, v); err != nil {
 			t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
 		}
 	}
diff --git a/schema/schema_helper_test.go b/schema/schema_helper_test.go
index 6d2bc66..9abaecb 100644
--- a/schema/schema_helper_test.go
+++ b/schema/schema_helper_test.go
@@ -1,6 +1,7 @@
 package schema_test
 
 import (
+	"context"
 	"fmt"
 	"reflect"
 	"strings"
@@ -203,7 +204,7 @@ func checkSchemaRelation(t *testing.T, s *schema.Schema, relation Relation) {
 func checkField(t *testing.T, s *schema.Schema, value reflect.Value, values map[string]interface{}) {
 	for k, v := range values {
 		t.Run("CheckField/"+k, func(t *testing.T) {
-			fv, _ := s.FieldsByDBName[k].ValueOf(value)
+			fv, _ := s.FieldsByDBName[k].ValueOf(context.Background(), value)
 			tests.AssertEqual(t, v, fv)
 		})
 	}
diff --git a/tests/create_test.go b/tests/create_test.go
index af2abdb..2b23d44 100644
--- a/tests/create_test.go
+++ b/tests/create_test.go
@@ -123,7 +123,7 @@ func TestCreateFromMap(t *testing.T) {
 		{"name": "create_from_map_3", "Age": 20},
 	}
 
-	if err := DB.Model(&User{}).Create(datas).Error; err != nil {
+	if err := DB.Model(&User{}).Create(&datas).Error; err != nil {
 		t.Fatalf("failed to create data from slice of map, got error: %v", err)
 	}
 
diff --git a/tests/go.mod b/tests/go.mod
index 3453f77..1c1fb23 100644
--- a/tests/go.mod
+++ b/tests/go.mod
@@ -3,18 +3,17 @@ module gorm.io/gorm/tests
 go 1.14
 
 require (
-	github.com/denisenkom/go-mssqldb v0.12.0 // indirect
 	github.com/google/uuid v1.3.0
 	github.com/jackc/pgx/v4 v4.15.0 // indirect
 	github.com/jinzhu/now v1.1.4
 	github.com/lib/pq v1.10.4
 	github.com/mattn/go-sqlite3 v1.14.11 // indirect
-	golang.org/x/crypto v0.0.0-20220208233918-bba287dce954 // indirect
-	gorm.io/driver/mysql v1.2.3
-	gorm.io/driver/postgres v1.2.3
-	gorm.io/driver/sqlite v1.2.6
-	gorm.io/driver/sqlserver v1.2.1
-	gorm.io/gorm v1.22.5
+	golang.org/x/crypto v0.0.0-20220214200702-86341886e292 // indirect
+	gorm.io/driver/mysql v1.3.1
+	gorm.io/driver/postgres v1.3.1
+	gorm.io/driver/sqlite v1.3.1
+	gorm.io/driver/sqlserver v1.3.1
+	gorm.io/gorm v1.23.0
 )
 
 replace gorm.io/gorm => ../
diff --git a/tests/migrate_test.go b/tests/migrate_test.go
index aa0a84a..94f562b 100644
--- a/tests/migrate_test.go
+++ b/tests/migrate_test.go
@@ -45,7 +45,7 @@ func TestMigrate(t *testing.T) {
 
 	for _, m := range allModels {
 		if !DB.Migrator().HasTable(m) {
-			t.Fatalf("Failed to create table for %#v---", m)
+			t.Fatalf("Failed to create table for %#v", m)
 		}
 	}
 
@@ -92,7 +92,7 @@ func TestAutoMigrateSelfReferential(t *testing.T) {
 }
 
 func TestSmartMigrateColumn(t *testing.T) {
-	fullSupported := map[string]bool{"mysql": true}[DB.Dialector.Name()]
+	fullSupported := map[string]bool{"mysql": true, "postgres": true}[DB.Dialector.Name()]
 
 	type UserMigrateColumn struct {
 		ID       uint
@@ -313,9 +313,16 @@ func TestMigrateIndexes(t *testing.T) {
 }
 
 func TestMigrateColumns(t *testing.T) {
+	sqlite := DB.Dialector.Name() == "sqlite"
+	sqlserver := DB.Dialector.Name() == "sqlserver"
+
 	type ColumnStruct struct {
 		gorm.Model
-		Name string
+		Name  string
+		Age   int    `gorm:"default:18;comment:my age"`
+		Code  string `gorm:"unique;comment:my code;"`
+		Code2 string
+		Code3 string `gorm:"unique"`
 	}
 
 	DB.Migrator().DropTable(&ColumnStruct{})
@@ -326,13 +333,20 @@ func TestMigrateColumns(t *testing.T) {
 
 	type ColumnStruct2 struct {
 		gorm.Model
-		Name string `gorm:"size:100"`
+		Name  string `gorm:"size:100"`
+		Code  string `gorm:"unique;comment:my code2;default:hello"`
+		Code2 string `gorm:"unique"`
+		// Code3 string
 	}
 
-	if err := DB.Table("column_structs").Migrator().AlterColumn(&ColumnStruct2{}, "Name"); err != nil {
+	if err := DB.Table("column_structs").Migrator().AlterColumn(&ColumnStruct{}, "Name"); err != nil {
 		t.Fatalf("no error should happened when alter column, but got %v", err)
 	}
 
+	if err := DB.Table("column_structs").AutoMigrate(&ColumnStruct2{}); err != nil {
+		t.Fatalf("no error should happened when auto migrate column, but got %v", err)
+	}
+
 	if columnTypes, err := DB.Migrator().ColumnTypes(&ColumnStruct{}); err != nil {
 		t.Fatalf("no error should returns for ColumnTypes")
 	} else {
@@ -340,11 +354,45 @@ func TestMigrateColumns(t *testing.T) {
 		stmt.Parse(&ColumnStruct2{})
 
 		for _, columnType := range columnTypes {
-			if columnType.Name() == "name" {
+			switch columnType.Name() {
+			case "id":
+				if v, ok := columnType.PrimaryKey(); !ok || !v {
+					t.Fatalf("column id primary key should be correct, name: %v, column: %#v", columnType.Name(), columnType)
+				}
+			case "name":
 				dataType := DB.Dialector.DataTypeOf(stmt.Schema.LookUpField(columnType.Name()))
 				if !strings.Contains(strings.ToUpper(dataType), strings.ToUpper(columnType.DatabaseTypeName())) {
-					t.Errorf("column type should be correct, name: %v, length: %v, expects: %v", columnType.Name(), columnType.DatabaseTypeName(), dataType)
+					t.Fatalf("column name type should be correct, name: %v, length: %v, expects: %v, column: %#v", columnType.Name(), columnType.DatabaseTypeName(), dataType, columnType)
+				}
+				if length, ok := columnType.Length(); !sqlite && (!ok || length != 100) {
+					t.Fatalf("column name length should be correct, name: %v, length: %v, expects: %v, column: %#v", columnType.Name(), length, 100, columnType)
+				}
+			case "age":
+				if v, ok := columnType.DefaultValue(); !ok || v != "18" {
+					t.Fatalf("column age default value should be correct, name: %v, column: %#v", columnType.Name(), columnType)
+				}
+				if v, ok := columnType.Comment(); !sqlite && !sqlserver && (!ok || v != "my age") {
+					t.Fatalf("column age comment should be correct, name: %v, column: %#v", columnType.Name(), columnType)
+				}
+			case "code":
+				if v, ok := columnType.Unique(); !ok || !v {
+					t.Fatalf("column code unique should be correct, name: %v, column: %#v", columnType.Name(), columnType)
+				}
+				if v, ok := columnType.DefaultValue(); !sqlserver && (!ok || v != "hello") {
+					t.Fatalf("column code default value should be correct, name: %v, column: %#v", columnType.Name(), columnType)
+				}
+				if v, ok := columnType.Comment(); !sqlite && !sqlserver && (!ok || v != "my code2") {
+					t.Fatalf("column code comment should be correct, name: %v, column: %#v", columnType.Name(), columnType)
+				}
+			case "code2":
+				if v, ok := columnType.Unique(); !sqlserver && (!ok || !v) {
+					t.Fatalf("column code2 unique should be correct, name: %v, column: %#v", columnType.Name(), columnType)
 				}
+			case "code3":
+				// TODO
+				// if v, ok := columnType.Unique(); !ok || v {
+				// 	t.Fatalf("column code unique should be correct, name: %v, column: %#v", columnType.Name(), columnType)
+				// }
 			}
 		}
 	}
diff --git a/tests/serializer_test.go b/tests/serializer_test.go
new file mode 100644
index 0000000..3ed733d
--- /dev/null
+++ b/tests/serializer_test.go
@@ -0,0 +1,71 @@
+package tests_test
+
+import (
+	"bytes"
+	"context"
+	"fmt"
+	"reflect"
+	"strings"
+	"testing"
+	"time"
+
+	"gorm.io/gorm"
+	"gorm.io/gorm/schema"
+	. "gorm.io/gorm/utils/tests"
+)
+
+type SerializerStruct struct {
+	gorm.Model
+	Name            []byte                 `gorm:"json"`
+	Roles           Roles                  `gorm:"serializer:json"`
+	Contracts       map[string]interface{} `gorm:"serializer:json"`
+	CreatedTime     int64                  `gorm:"serializer:unixtime;type:time"` // store time in db, use int as field type
+	EncryptedString EncryptedString
+}
+
+type Roles []string
+type EncryptedString string
+
+func (es *EncryptedString) Scan(ctx context.Context, field *schema.Field, dst reflect.Value, dbValue interface{}) (err error) {
+	switch value := dbValue.(type) {
+	case []byte:
+		*es = EncryptedString(bytes.TrimPrefix(value, []byte("hello")))
+	case string:
+		*es = EncryptedString(strings.TrimPrefix(value, "hello"))
+	default:
+		return fmt.Errorf("unsupported data %v", dbValue)
+	}
+	return nil
+}
+
+func (es EncryptedString) Value(ctx context.Context, field *schema.Field, dst reflect.Value, fieldValue interface{}) (interface{}, error) {
+	return "hello" + string(es), nil
+}
+
+func TestSerializer(t *testing.T) {
+	DB.Migrator().DropTable(&SerializerStruct{})
+	if err := DB.Migrator().AutoMigrate(&SerializerStruct{}); err != nil {
+		t.Fatalf("no error should happen when migrate scanner, valuer struct, got error %v", err)
+	}
+
+	createdAt := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
+
+	data := SerializerStruct{
+		Name:            []byte("jinzhu"),
+		Roles:           []string{"r1", "r2"},
+		Contracts:       map[string]interface{}{"name": "jinzhu", "age": 10},
+		EncryptedString: EncryptedString("pass"),
+		CreatedTime:     createdAt.Unix(),
+	}
+
+	if err := DB.Create(&data).Error; err != nil {
+		t.Fatalf("failed to create data, got error %v", err)
+	}
+
+	var result SerializerStruct
+	if err := DB.First(&result, data.ID).Error; err != nil {
+		t.Fatalf("failed to query data, got error %v", err)
+	}
+
+	AssertEqual(t, result, data)
+}