85 lines
2.6 KiB
Go
85 lines
2.6 KiB
Go
// Copyright GoFrame Author(https://goframe.org). 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 pgsql
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"strings"
|
|
|
|
"git.magicany.cc/black1552/gin-base/database"
|
|
"github.com/gogf/gf/v2/errors/gcode"
|
|
"github.com/gogf/gf/v2/errors/gerror"
|
|
)
|
|
|
|
// DoInsert inserts or updates data for given table.
|
|
// The list parameter must contain at least one record, which was previously validated.
|
|
func (d *Driver) DoInsert(
|
|
ctx context.Context,
|
|
link database.Link, table string, list database.List, option database.DoInsertOption,
|
|
) (result sql.Result, err error) {
|
|
switch option.InsertOption {
|
|
case
|
|
database.InsertOptionSave,
|
|
database.InsertOptionReplace:
|
|
// PostgreSQL does not support REPLACE INTO syntax, use Save (ON CONFLICT ... DO UPDATE) instead.
|
|
// Automatically detect primary keys if OnConflict is not specified.
|
|
if len(option.OnConflict) == 0 {
|
|
primaryKeys, err := d.Core.GetPrimaryKeys(ctx, table)
|
|
if err != nil {
|
|
return nil, gerror.WrapCode(
|
|
gcode.CodeInternalError,
|
|
err,
|
|
`failed to get primary keys for Save/Replace operation`,
|
|
)
|
|
}
|
|
foundPrimaryKey := false
|
|
for _, primaryKey := range primaryKeys {
|
|
for dataKey := range list[0] {
|
|
if strings.EqualFold(dataKey, primaryKey) {
|
|
foundPrimaryKey = true
|
|
break
|
|
}
|
|
}
|
|
if foundPrimaryKey {
|
|
break
|
|
}
|
|
}
|
|
if !foundPrimaryKey {
|
|
return nil, gerror.NewCodef(
|
|
gcode.CodeMissingParameter,
|
|
`Replace/Save operation requires conflict detection: `+
|
|
`either specify OnConflict() columns or ensure table '%s' has a primary key in the data`,
|
|
table,
|
|
)
|
|
}
|
|
// TODO consider composite primary keys.
|
|
option.OnConflict = primaryKeys
|
|
}
|
|
// Treat Replace as Save operation
|
|
option.InsertOption = database.InsertOptionSave
|
|
|
|
// pgsql support InsertIgnore natively, so no need to set primary key in context.
|
|
case database.InsertOptionIgnore, database.InsertOptionDefault:
|
|
// Get table fields to retrieve the primary key TableField object (not just the name)
|
|
// because DoExec needs the `TableField.Type` to determine if LastInsertId is supported.
|
|
tableFields, err := d.GetCore().GetDB().TableFields(ctx, table)
|
|
if err == nil {
|
|
for _, field := range tableFields {
|
|
if strings.EqualFold(field.Key, "pri") {
|
|
pkField := *field
|
|
ctx = context.WithValue(ctx, internalPrimaryKeyInCtx, pkField)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
default:
|
|
}
|
|
return d.Core.DoInsert(ctx, link, table, list, option)
|
|
}
|