// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved. // // This Source Code Form is subject to the terms of the MIT License. // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. package gdb import ( "database/sql" "errors" "github.com/gogf/gf/os/gtime" "github.com/gogf/gf/text/gstr" "github.com/gogf/gf/util/gconv" "github.com/gogf/gf/util/gutil" "reflect" ) // Batch sets the batch operation number for the model. func (m *Model) Batch(batch int) *Model { model := m.getModel() model.batch = batch return model } // Data sets the operation data for the model. // The parameter can be type of string/map/gmap/slice/struct/*struct, etc. // Eg: // Data("uid=10000") // Data("uid", 10000) // Data("uid=? AND name=?", 10000, "john") // Data(g.Map{"uid": 10000, "name":"john"}) // Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"}) func (m *Model) Data(data ...interface{}) *Model { model := m.getModel() if len(data) > 1 { s := gconv.String(data[0]) if gstr.Contains(s, "?") { model.data = s model.extraArgs = data[1:] } else { m := make(map[string]interface{}) for i := 0; i < len(data); i += 2 { m[gconv.String(data[i])] = data[i+1] } model.data = m } } else { switch params := data[0].(type) { case Result: model.data = params.List() case Record: model.data = params.Map() case List: model.data = params case Map: model.data = params default: rv := reflect.ValueOf(params) kind := rv.Kind() if kind == reflect.Ptr { rv = rv.Elem() kind = rv.Kind() } switch kind { case reflect.Slice, reflect.Array: list := make(List, rv.Len()) for i := 0; i < rv.Len(); i++ { list[i] = DataToMapDeep(rv.Index(i).Interface()) } model.data = list case reflect.Map: model.data = DataToMapDeep(data[0]) case reflect.Struct: if v, ok := data[0].(apiMapStrAny); ok { model.data = v.MapStrAny() } else if v, ok := data[0].(apiInterfaces); ok { array := v.Interfaces() list := make(List, len(array)) for i := 0; i < len(array); i++ { list[i] = DataToMapDeep(array[i]) } model.data = list } else { model.data = DataToMapDeep(data[0]) } default: model.data = data[0] } } } return model } // Insert does "INSERT INTO ..." statement for the model. // The optional parameter is the same as the parameter of Model.Data function, // see Model.Data. func (m *Model) Insert(data ...interface{}) (result sql.Result, err error) { if len(data) > 0 { return m.Data(data...).Insert() } return m.doInsertWithOption(gINSERT_OPTION_DEFAULT, data...) } // InsertIgnore does "INSERT IGNORE INTO ..." statement for the model. // The optional parameter is the same as the parameter of Model.Data function, // see Model.Data. func (m *Model) InsertIgnore(data ...interface{}) (result sql.Result, err error) { if len(data) > 0 { return m.Data(data...).Insert() } return m.doInsertWithOption(gINSERT_OPTION_IGNORE, data...) } // Replace does "REPLACE INTO ..." statement for the model. // The optional parameter is the same as the parameter of Model.Data function, // see Model.Data. func (m *Model) Replace(data ...interface{}) (result sql.Result, err error) { if len(data) > 0 { return m.Data(data...).Replace() } return m.doInsertWithOption(gINSERT_OPTION_REPLACE, data...) } // Save does "INSERT INTO ... ON DUPLICATE KEY UPDATE..." statement for the model. // The optional parameter is the same as the parameter of Model.Data function, // see Model.Data. // // It updates the record if there's primary or unique index in the saving data, // or else it inserts a new record into the table. func (m *Model) Save(data ...interface{}) (result sql.Result, err error) { if len(data) > 0 { return m.Data(data...).Save() } return m.doInsertWithOption(gINSERT_OPTION_SAVE, data...) } // doInsertWithOption inserts data with option parameter. func (m *Model) doInsertWithOption(option int, data ...interface{}) (result sql.Result, err error) { defer func() { if err == nil { m.checkAndRemoveCache() } }() if m.data == nil { return nil, errors.New("inserting into table with empty data") } var ( nowString = gtime.Now().String() fieldNameCreate = m.getSoftFieldNameCreate() fieldNameUpdate = m.getSoftFieldNameUpdate() ) // Batch operation. if list, ok := m.data.(List); ok { batch := gDEFAULT_BATCH_NUM if m.batch > 0 { batch = m.batch } // Automatic handling for creating/updating time. if !m.unscoped && (fieldNameCreate != "" || fieldNameUpdate != "") { for k, v := range list { if fieldNameCreate != "" && !gutil.MapContainsPossibleKey(v, fieldNameCreate) { v[fieldNameCreate] = nowString } if fieldNameUpdate != "" && !gutil.MapContainsPossibleKey(v, fieldNameUpdate) { v[fieldNameUpdate] = nowString } list[k] = v } } return m.db.DoBatchInsert( m.getLink(true), m.tables, m.filterDataForInsertOrUpdate(list), option, batch, ) } // Single operation. if data, ok := m.data.(Map); ok { // Automatic handling for creating/updating time. if !m.unscoped && (fieldNameCreate != "" || fieldNameUpdate != "") { if fieldNameCreate != "" && !gutil.MapContainsPossibleKey(data, fieldNameCreate) { data[fieldNameCreate] = nowString } if fieldNameUpdate != "" && !gutil.MapContainsPossibleKey(data, fieldNameUpdate) { data[fieldNameUpdate] = nowString } } return m.db.DoInsert( m.getLink(true), m.tables, m.filterDataForInsertOrUpdate(data), option, ) } return nil, errors.New("inserting into table with invalid data type") }