Skip to content

Instantly share code, notes, and snippets.

@yutakahashi114
Last active March 26, 2021 12:43
Show Gist options
  • Save yutakahashi114/1e2de3019e0fb2e28dabf786dedb386e to your computer and use it in GitHub Desktop.
Save yutakahashi114/1e2de3019e0fb2e28dabf786dedb386e to your computer and use it in GitHub Desktop.
type bulkInserter interface {
TableName() string
Args(int) []interface{}
Columns() string
Values() string
Len() int
}
const pqArgLimit = 65535
type config struct {
returningColumns []string
}
type Option func(*config)
func Returning(columns ...string) Option {
return func(c *config) {
c.returningColumns = columns
}
}
func BulkInsert(db xorm.Interface, inserter bulkInserter, options ...Option) ([]map[string]string, error) {
insertCount := inserter.Len()
if insertCount == 0 {
return nil, nil
}
c := &config{}
for _, opt := range options {
opt(c)
}
var results []map[string]string
returning := ""
// RETURNING を使用する場合はSQLと返却値を用意する
if len(c.returningColumns) > 0 {
returning = fmt.Sprintf(" RETURNING %s", strings.Join(c.returningColumns, ", "))
results = make([]map[string]string, 0, insertCount)
}
valuesString := inserter.Values() + ","
argCount := len(inserter.Args(0))
// "github.com/lib/pq" の引数の上限を超えないよう分割する
insertLimit := pqArgLimit/argCount - 1
for start := 0; start < insertCount; start += insertLimit {
end := start + insertLimit
if end > insertCount {
end = insertCount
}
var values strings.Builder
values.Grow(len([]byte(valuesString)) * (end - start))
args := make([]interface{}, 0, (end-start)*argCount)
for i := start; i < end; i++ {
args = append(args, inserter.Args(i)...)
values.WriteString(valuesString)
}
sql := fmt.Sprintf(
"INSERT INTO %s (%s) VALUES %s%s",
inserter.TableName(),
inserter.Columns(),
strings.TrimRight(values.String(), ","),
returning,
)
result, err := db.QueryString(append([]interface{}{sql}, args...)...)
if err != nil {
return nil, err
}
if len(c.returningColumns) > 0 {
results = append(results, result...)
}
}
return results, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment