package db import ( "strings" "gorm.io/gorm" ) const ( maxPlaceholderCount = 65535 ) func BatchNamedExec[T any](ctx SQLContext, sql string, argCnt int, arr []T, callback func(result *gorm.DB) bool) error { if argCnt == 0 { result := ctx.Exec(sql, toInterfaceSlice(arr)...) if result.Error != nil { return result.Error } if callback != nil { callback(result) } return nil } batchSize := maxPlaceholderCount / argCnt for len(arr) > 0 { curBatchSize := min(batchSize, len(arr)) result := ctx.Exec(sql, toInterfaceSlice(arr[:curBatchSize])...) if result.Error != nil { return result.Error } if callback != nil && !callback(result) { return nil } arr = arr[curBatchSize:] } return nil } // 将 []T 转换为 []interface{} func toInterfaceSlice[T any](arr []T) []interface{} { interfaceSlice := make([]interface{}, len(arr)) for i, v := range arr { interfaceSlice[i] = v } return interfaceSlice } func min(a, b int) int { if a < b { return a } return b } func escapeLike(left, right, word string) string { var n int for i := range word { if c := word[i]; c == '%' || c == '_' || c == '\\' { n++ } } // No characters to escape. if n == 0 { return left + word + right } var b strings.Builder b.Grow(len(word) + n) for _, c := range word { if c == '%' || c == '_' || c == '\\' { b.WriteByte('\\') } b.WriteRune(c) } return left + b.String() + right }