github.com/wangyougui/gf/v2@v2.6.5/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/wangyougui/gf.
     6  
     7  package gdb
     8  
     9  import (
    10  	"database/sql"
    11  	"fmt"
    12  	"reflect"
    13  
    14  	"github.com/wangyougui/gf/v2/internal/intlog"
    15  
    16  	"github.com/wangyougui/gf/v2/errors/gcode"
    17  	"github.com/wangyougui/gf/v2/errors/gerror"
    18  	"github.com/wangyougui/gf/v2/internal/reflection"
    19  	"github.com/wangyougui/gf/v2/text/gstr"
    20  	"github.com/wangyougui/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  		stm                                           = m.softTimeMaintainer()
    49  		updateData                                    = m.data
    50  		reflectInfo                                   = reflection.OriginTypeAndKind(updateData)
    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 m.unscoped {
    58  		fieldNameUpdate = ""
    59  	}
    60  
    61  	switch reflectInfo.OriginKind {
    62  	case reflect.Map, reflect.Struct:
    63  		var dataMap = anyValueToMapBeforeToRecord(m.data)
    64  		// Automatically update the record updating time.
    65  		if fieldNameUpdate != "" {
    66  			dataValue := stm.GetValueByFieldTypeForCreateOrUpdate(ctx, fieldTypeUpdate, false)
    67  			dataMap[fieldNameUpdate] = dataValue
    68  		}
    69  		updateData = dataMap
    70  
    71  	default:
    72  		updates := gconv.String(m.data)
    73  		// Automatically update the record updating time.
    74  		if fieldNameUpdate != "" {
    75  			dataValue := stm.GetValueByFieldTypeForCreateOrUpdate(ctx, fieldTypeUpdate, false)
    76  			if fieldNameUpdate != "" && !gstr.Contains(updates, fieldNameUpdate) {
    77  				updates += fmt.Sprintf(`,%s=?`, fieldNameUpdate)
    78  				conditionArgs = append([]interface{}{dataValue}, conditionArgs...)
    79  			}
    80  		}
    81  		updateData = updates
    82  	}
    83  	newData, err := m.filterDataForInsertOrUpdate(updateData)
    84  	if err != nil {
    85  		return nil, err
    86  	}
    87  
    88  	if !gstr.ContainsI(conditionStr, " WHERE ") {
    89  		intlog.Printf(
    90  			ctx,
    91  			`sql condition string "%s" has no WHERE for UPDATE operation, fieldNameUpdate: %s`,
    92  			conditionStr, fieldNameUpdate,
    93  		)
    94  		return nil, gerror.NewCode(
    95  			gcode.CodeMissingParameter,
    96  			"there should be WHERE condition statement for UPDATE operation",
    97  		)
    98  	}
    99  
   100  	in := &HookUpdateInput{
   101  		internalParamHookUpdate: internalParamHookUpdate{
   102  			internalParamHook: internalParamHook{
   103  				link: m.getLink(true),
   104  			},
   105  			handler: m.hookHandler.Update,
   106  		},
   107  		Model:     m,
   108  		Table:     m.tables,
   109  		Data:      newData,
   110  		Condition: conditionStr,
   111  		Args:      m.mergeArguments(conditionArgs),
   112  	}
   113  	return in.Next(ctx)
   114  }
   115  
   116  // UpdateAndGetAffected performs update statement and returns the affected rows number.
   117  func (m *Model) UpdateAndGetAffected(dataAndWhere ...interface{}) (affected int64, err error) {
   118  	result, err := m.Update(dataAndWhere...)
   119  	if err != nil {
   120  		return 0, err
   121  	}
   122  	return result.RowsAffected()
   123  }
   124  
   125  // Increment increments a column's value by a given amount.
   126  // The parameter `amount` can be type of float or integer.
   127  func (m *Model) Increment(column string, amount interface{}) (sql.Result, error) {
   128  	return m.getModel().Data(column, &Counter{
   129  		Field: column,
   130  		Value: gconv.Float64(amount),
   131  	}).Update()
   132  }
   133  
   134  // Decrement decrements a column's value by a given amount.
   135  // The parameter `amount` can be type of float or integer.
   136  func (m *Model) Decrement(column string, amount interface{}) (sql.Result, error) {
   137  	return m.getModel().Data(column, &Counter{
   138  		Field: column,
   139  		Value: -gconv.Float64(amount),
   140  	}).Update()
   141  }