在Goframe使用pgsql的时候使用Save的方法

Goframe的Orm本身不支持 Save方法的
官方文档里写着

It does not support Save/Replace features.
It does not support LastInsertId.

看了半天文档不会用Hook方法,所以动了core代码
临时这么用用,希望后期官方正式支持

1. 添加 onDuplicateKey 属性

修改文件路径: /golang/pkg/mod/github.com/gogf/gf/v2@v2.1.3/database/gdb/gdb_model.go

type Model struct {
  // ... 省略
	onDuplicateKey interface{}   // custom onDuplicateKey
}

2. 添加OnDuplicateKey方法

修改文件路径: /golang/pkg/mod/github.com/gogf/gf/v2@v2.1.3/database/gdb/gdb_model_insert.go

// 添加OnDuplicateKey方法
func (m *Model) OnDuplicateKey(onDuplicateKey ...interface{}) *Model {
	model := m.getModel()
	if len(onDuplicateKey) > 1 {
		model.onDuplicateKey = onDuplicateKey
	} else {
		model.onDuplicateKey = onDuplicateKey[0]
	}
	return model
}

3. 添加option属性

修改文件路径: /golang/pkg/mod/github.com/gogf/gf/v2@v2.1.3/database/gdb/gdb.go

type DoInsertOption struct {
	OnDuplicateRawStr string                 
	OnDuplicateKeyStr string                 // Custom string for `on duplicated` statement.
  // ...省略
}

3. 修改formatDoInsertOption方法

修改文件路径: /golang/pkg/mod/github.com/gogf/gf/v2@v2.1.3/database/gdb/gdb_model_insert.go

func (m *Model) formatDoInsertOption(insertOption int, columnNames []string) (option DoInsertOption, err error) {
	// ... 省略
	
		if m.onDuplicateKey != nil {
			switch m.onDuplicateKey.(type) {
			case Raw, *Raw:
				option.OnDuplicateKeyStr = gconv.String(m.onDuplicateKey)

			default:
				reflectInfo := reflection.OriginValueAndKind(m.onDuplicateKey)
				switch reflectInfo.OriginKind {
				case reflect.String:
					option.OnDuplicateKeyStr = gconv.String(m.onDuplicateKey)

				default:
					return option, gerror.NewCodef(
						gcode.CodeInvalidParameter,
						`unsupported OnDuplicateKey parameter type "%s"`,
						reflect.TypeOf(m.onDuplicateKey),
					)
				}
			}
		}
    // 添加到此为止
  
    // ...其他代码不动
	}
	return
}

5. 修改 pgsql DoInsert 驱动

修改文件路径: /golang/pkg/mod/github.com/gogf/gf/contrib/drivers/pgsql/v2@v2.1.3/pgsql.go

  // 修改 DoInsert方法
func (d *Driver) DoInsert(ctx context.Context, link gdb.Link, table string, list gdb.List, option gdb.DoInsertOption) (result sql.Result, err error) {
switch option.InsertOption {
case gdb.InsertOptionSave:
  if option.OnDuplicateKeyStr == "" {
    return nil, gerror.NewCode(
      gcode.CodeNotSupported,
      `使用Save方法前请先调用 OnDuplicateKey()设置key 例: g.table("user").OnDuplicateKey("id,code").Save()`,
    )
  } else {
    option.OnDuplicateRawStr = d.formatOnDuplicate(list, option)
  }
  // ...下面省略

// 添加 formatOnDuplicate 方法
func (d *Driver) formatOnDuplicate(list gdb.List, option gdb.DoInsertOption) string {
	var (
		onDuplicateStr    string
		onDuplicateKeyStr string
	)

	if option.OnDuplicateKeyStr != "" {
		onDuplicateKeyStr = option.OnDuplicateKeyStr
	}

	if option.OnDuplicateStr != "" {
		onDuplicateStr = option.OnDuplicateStr
	} else if len(option.OnDuplicateMap) > 0 {
		for k, v := range option.OnDuplicateMap {
			if len(onDuplicateStr) > 0 {
				onDuplicateStr += ","
			}
			switch v.(type) {
			case gdb.Raw, *gdb.Raw:
				onDuplicateStr += fmt.Sprintf(
					"%s=%s",
					d.QuoteWord(k),
					v,
				)
			default:
				onDuplicateStr += fmt.Sprintf(
					"%s=EXCLUDED.%s",
					d.QuoteWord(k),
					d.QuoteWord(gconv.String(v)),
				)
			}
		}
	} else {

		var (
			keys []string // Field names.
		)

		// Handle the field names and placeholders.
		for k := range list[0] {
			keys = append(keys, k)
		}
		for _, column := range keys {
			// If it's SAVE operation, do not automatically update the creating time.
			if len(onDuplicateStr) > 0 {
				onDuplicateStr += ","
			}
			onDuplicateStr += fmt.Sprintf(
				"%s=EXCLUDED.%s",
				d.QuoteWord(column),
				d.QuoteWord(column),
			)
		}
	}
	return fmt.Sprintf("ON CONFLICT (%s) DO UPDATE SET %s", onDuplicateKeyStr, onDuplicateStr)
}

5. 修改 gdb_core文件

修改文件路径: /golang/pkg/mod/github.com/gogf/gf/v2@v2.1.3/database/gdb/gdb_core.go

  // 修改 option.InsertOption == InsertOptionSave 部分
	if option.InsertOption == InsertOptionSave {
		if option.OnDuplicateRawStr != "" {
			onDuplicateStr = option.OnDuplicateRawStr
		} else {
			onDuplicateStr = c.formatOnDuplicate(keys, option)
		}
	}

然后使用方法是这样的

testModel := dao.Test.Ctx(ctx)
result, err := testModel.Data(testEntity).OnDuplicateKey("test_id").Save()
// 生成如下: INSERT INTO test (test_id,text) VALUES(2,'john') ON CONFLICT (test_id) DO UPDATE SET "test_id"=EXCLUDED.test_id "text1"=EXCLUDED.text1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值