github.com/gogf/gf/v2@v2.7.4/database/gdb/gdb_model_update.go (about)

     1  // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/gogf/gf.
     6  
     7  package gdb
     8  
     9  import (
    10  	"database/sql"
    11  	"fmt"
    12  	"reflect"
    13  
    14  	"github.com/gogf/gf/v2/errors/gcode"
    15  	"github.com/gogf/gf/v2/errors/gerror"
    16  	"github.com/gogf/gf/v2/internal/empty"
    17  	"github.com/gogf/gf/v2/internal/intlog"
    18  	"github.com/gogf/gf/v2/internal/reflection"
    19  	"github.com/gogf/gf/v2/text/gstr"
    20  	"github.com/gogf/gf/v2/util/gconv"
    21  )
    22  
    23  // Update does "UPDATE ... " statement for the model.
    24  //
    25  // If the optional parameter `dataAndWhere` is given, the dataAndWhere[0] is the updated data field,
    26  // and dataAndWhere[1:] is treated as where condition fields.
    27  // Also see Model.Data and Model.Where functions.
    28  func (m *Model) Update(dataAndWhere ...interface{}) (result sql.Result, err error) {
    29  	var ctx = m.GetCtx()
    30  	if len(dataAndWhere) > 0 {
    31  		if len(dataAndWhere) > 2 {
    32  			return m.Data(dataAndWhere[0]).Where(dataAndWhere[1], dataAndWhere[2:]...).Update()
    33  		} else if len(dataAndWhere) == 2 {
    34  			return m.Data(dataAndWhere[0]).Where(dataAndWhere[1]).Update()
    35  		} else {
    36  			return m.Data(dataAndWhere[0]).Update()
    37  		}
    38  	}
    39  	defer func() {
    40  		if err == nil {
    41  			m.checkAndRemoveSelectCache(ctx)
    42  		}
    43  	}()
    44  	if m.data == nil {
    45  		return nil, gerror.NewCode(gcode.CodeMissingParameter, "updating table with empty data")
    46  	}
    47  	var (
    48  		newData                                       interface{}
    49  		stm                                           = m.softTimeMaintainer()
    50  		reflectInfo                                   = reflection.OriginTypeAndKind(m.data)
    51  		conditionWhere, conditionExtra, conditionArgs = m.formatCondition(ctx, false, false)
    52  		conditionStr                                  = conditionWhere + conditionExtra
    53  		fieldNameUpdate, fieldTypeUpdate              = stm.GetFieldNameAndTypeForUpdate(
    54  			ctx, "", m.tablesInit,
    55  		)
    56  	)
    57  	if fieldNameUpdate != "" && (m.unscoped || m.isFieldInFieldsEx(fieldNameUpdate)) {
    58  		fieldNameUpdate = ""
    59  	}
    60  
    61  	newData, err = m.filterDataForInsertOrUpdate(m.data)
    62  	if err != nil {
    63  		return nil, err
    64  	}
    65  
    66  	switch reflectInfo.OriginKind {
    67  	case reflect.Map, reflect.Struct:
    68  		var dataMap = anyValueToMapBeforeToRecord(newData)
    69  		// Automatically update the record updating time.
    70  		if fieldNameUpdate != "" && empty.IsNil(dataMap[fieldNameUpdate]) {
    71  			dataValue := stm.GetValueByFieldTypeForCreateOrUpdate(ctx, fieldTypeUpdate, false)
    72  			dataMap[fieldNameUpdate] = dataValue
    73  		}
    74  		newData = dataMap
    75  
    76  	default:
    77  		var updateStr = gconv.String(newData)
    78  		// Automatically update the record updating time.
    79  		if fieldNameUpdate != "" && !gstr.Contains(updateStr, fieldNameUpdate) {
    80  			dataValue := stm.GetValueByFieldTypeForCreateOrUpdate(ctx, fieldTypeUpdate, false)
    81  			updateStr += fmt.Sprintf(`,%s=?`, fieldNameUpdate)
    82  			conditionArgs = append([]interface{}{dataValue}, conditionArgs...)
    83  		}
    84  		newData = updateStr
    85  	}
    86  
    87  	if !gstr.ContainsI(conditionStr, " WHERE ") {
    88  		intlog.Printf(
    89  			ctx,
    90  			`sql condition string "%s" has no WHERE for UPDATE operation, fieldNameUpdate: %s`,
    91  			conditionStr, fieldNameUpdate,
    92  		)
    93  		return nil, gerror.NewCode(
    94  			gcode.CodeMissingParameter,
    95  			"there should be WHERE condition statement for UPDATE operation",
    96  		)
    97  	}
    98  
    99  	in := &HookUpdateInput{
   100  		internalParamHookUpdate: internalParamHookUpdate{
   101  			internalParamHook: internalParamHook{
   102  				link: m.getLink(true),
   103  			},
   104  			handler: m.hookHandler.Update,
   105  		},
   106  		Model:     m,
   107  		Table:     m.tables,
   108  		Data:      newData,
   109  		Condition: conditionStr,
   110  		Args:      m.mergeArguments(conditionArgs),
   111  	}
   112  	return in.Next(ctx)
   113  }
   114  
   115  // UpdateAndGetAffected performs update statement and returns the affected rows number.
   116  func (m *Model) UpdateAndGetAffected(dataAndWhere ...interface{}) (affected int64, err error) {
   117  	result, err := m.Update(dataAndWhere...)
   118  	if err != nil {
   119  		return 0, err
   120  	}
   121  	return result.RowsAffected()
   122  }
   123  
   124  // Increment increments a column's value by a given amount.
   125  // The parameter `amount` can be type of float or integer.
   126  func (m *Model) Increment(column string, amount interface{}) (sql.Result, error) {
   127  	return m.getModel().Data(column, &Counter{
   128  		Field: column,
   129  		Value: gconv.Float64(amount),
   130  	}).Update()
   131  }
   132  
   133  // Decrement decrements a column's value by a given amount.
   134  // The parameter `amount` can be type of float or integer.
   135  func (m *Model) Decrement(column string, amount interface{}) (sql.Result, error) {
   136  	return m.getModel().Data(column, &Counter{
   137  		Field: column,
   138  		Value: -gconv.Float64(amount),
   139  	}).Update()
   140  }