Boilerplate for upsert
This commit is contained in:
parent
358dac851f
commit
70b2dcfbb2
7 changed files with 108 additions and 29 deletions
|
@ -7,6 +7,8 @@ type HookPoint int
|
|||
const (
|
||||
HookAfterCreate HookPoint = iota + 1
|
||||
HookAfterUpdate
|
||||
HookAfterUpsert
|
||||
HookBeforeCreate
|
||||
HookBeforeUpdate
|
||||
HookBeforeUpsert
|
||||
)
|
||||
|
|
|
@ -52,8 +52,6 @@ func buildQuery(q *Query) (string, []interface{}) {
|
|||
return q.plainSQL.sql, q.plainSQL.args
|
||||
case q.delete:
|
||||
buf, args = buildDeleteQuery(q)
|
||||
case len(q.update) > 0:
|
||||
buf, args = buildUpdateQuery(q)
|
||||
default:
|
||||
buf, args = buildSelectQuery(q)
|
||||
}
|
||||
|
@ -115,13 +113,6 @@ func buildDeleteQuery(q *Query) (*bytes.Buffer, []interface{}) {
|
|||
return buf, args
|
||||
}
|
||||
|
||||
func buildUpdateQuery(q *Query) (*bytes.Buffer, []interface{}) {
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
buf.WriteByte(';')
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
// ExecQuery executes a query that does not need a row returned
|
||||
func ExecQuery(q *Query) (sql.Result, error) {
|
||||
qs, args := buildQuery(q)
|
||||
|
@ -164,11 +155,6 @@ func SetDelete(q *Query) {
|
|||
q.delete = true
|
||||
}
|
||||
|
||||
// SetUpdate on the query.
|
||||
func SetUpdate(q *Query, cols map[string]interface{}) {
|
||||
q.update = cols
|
||||
}
|
||||
|
||||
// SetExecutor on the query.
|
||||
func SetExecutor(q *Query, exec Executor) {
|
||||
q.executor = exec
|
||||
|
|
|
@ -258,21 +258,6 @@ func TestSetDelete(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestSetUpdate(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
q := &Query{}
|
||||
SetUpdate(q, map[string]interface{}{"col1": 1, "col2": 2})
|
||||
|
||||
if len(q.update) != 2 {
|
||||
t.Errorf("Expected len 2, got %d", len(q.update))
|
||||
}
|
||||
|
||||
if q.update["col1"] != 1 && q.update["col2"] != 2 {
|
||||
t.Errorf("Value misatch: %#v", q.update)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetExecutor(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
|
|
@ -202,6 +202,7 @@ func RandomizeStruct(str interface{}, colTypes map[string]string, includeInvalid
|
|||
return nil
|
||||
}
|
||||
|
||||
// RandomizeValidatedStruct takes an object fills its validated columns with random data.
|
||||
func RandomizeValidatedStruct(obj interface{}, validatedCols []string, colTypes map[string]string) error {
|
||||
// Check if it's pointer
|
||||
value := reflect.ValueOf(obj)
|
||||
|
|
|
@ -27,6 +27,17 @@ func (o *{{$tableNameSingular}}) doBeforeUpdateHooks() (err error) {
|
|||
return nil
|
||||
}
|
||||
|
||||
// doBeforeUpsertHooks executes all "before Upsert" hooks.
|
||||
func (o *{{$tableNameSingular}}) doBeforeUpsertHooks() (err error) {
|
||||
for _, hook := range {{$varNameSingular}}BeforeUpsertHooks {
|
||||
if err := hook(o); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// doAfterCreateHooks executes all "after create" hooks.
|
||||
func (o *{{$tableNameSingular}}) doAfterCreateHooks() (err error) {
|
||||
for _, hook := range {{$varNameSingular}}AfterCreateHooks {
|
||||
|
@ -49,15 +60,30 @@ func (o *{{$tableNameSingular}}) doAfterUpdateHooks() (err error) {
|
|||
return nil
|
||||
}
|
||||
|
||||
// doAfterUpsertHooks executes all "after Upsert" hooks.
|
||||
func (o *{{$tableNameSingular}}) doAfterUpsertHooks() (err error) {
|
||||
for _, hook := range {{$varNameSingular}}AfterUpsertHooks {
|
||||
if err := hook(o); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func {{$tableNameSingular}}AddHook(hookPoint boil.HookPoint, {{$varNameSingular}}Hook {{$tableNameSingular}}Hook) {
|
||||
switch hookPoint {
|
||||
case boil.HookBeforeCreate:
|
||||
{{$varNameSingular}}BeforeCreateHooks = append({{$varNameSingular}}BeforeCreateHooks, {{$varNameSingular}}Hook)
|
||||
case boil.HookBeforeUpdate:
|
||||
{{$varNameSingular}}BeforeUpdateHooks = append({{$varNameSingular}}BeforeUpdateHooks, {{$varNameSingular}}Hook)
|
||||
case boil.HookBeforeUpsert:
|
||||
{{$varNameSingular}}BeforeUpsertHooks = append({{$varNameSingular}}BeforeUpsertHooks, {{$varNameSingular}}Hook)
|
||||
case boil.HookAfterCreate:
|
||||
{{$varNameSingular}}AfterCreateHooks = append({{$varNameSingular}}AfterCreateHooks, {{$varNameSingular}}Hook)
|
||||
case boil.HookAfterUpdate:
|
||||
{{$varNameSingular}}AfterUpdateHooks = append({{$varNameSingular}}AfterUpdateHooks, {{$varNameSingular}}Hook)
|
||||
case boil.HookAfterUpsert:
|
||||
{{$varNameSingular}}AfterUpsertHooks = append({{$varNameSingular}}AfterUpsertHooks, {{$varNameSingular}}Hook)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
{{- $tableNameSingular := .Table.Name | singular | titleCase -}}
|
||||
{{- $varNameSingular := .Table.Name | singular | camelCase -}}
|
||||
// UpsertG attempts an insert, and does an update or ignore on conflict.
|
||||
func (o *{{$tableNameSingular}}) UpsertG(update bool, conflictColumns []string, updateColumns []string, whitelist ...string) error {
|
||||
return o.Upsert(boil.GetDB(), update, conflictColumns, updateColumns, whitelist...)
|
||||
}
|
||||
|
||||
// UpsertGP attempts an insert, and does an update or ignore on conflict. Panics on error.
|
||||
func (o *{{$tableNameSingular}}) UpsertGP(update bool, conflictColumns []string, updateColumns []string, whitelist ...string) {
|
||||
if err := o.Upsert(boil.GetDB(), update, conflictColumns, updateColumns, whitelist...); err != nil {
|
||||
panic(boil.WrapErr(err))
|
||||
}
|
||||
}
|
||||
|
||||
// Upsert attempts an insert using an executor, and does an update or ignore on conflict.
|
||||
func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, update bool, conflictColumns []string, updateColumns []string, whitelist ...string) error {
|
||||
if o == nil {
|
||||
return errors.New("{{.PkgName}}: no {{.Table.Name}} provided for upsert")
|
||||
}
|
||||
|
||||
wl, returnColumns := o.generateInsertColumns(whitelist...)
|
||||
|
||||
conflict := make([]string, len(conflictColumns))
|
||||
update := make([]string, len(updateColumns))
|
||||
|
||||
copy(conflict, conflictColumns)
|
||||
copy(update, updateColumns)
|
||||
|
||||
for i, v := range conflict {
|
||||
conflict[i] = strmangle.IdentQuote(v)
|
||||
}
|
||||
|
||||
for i, v := range update {
|
||||
update[i] = strmangle.IdentQuote(v)
|
||||
}
|
||||
|
||||
var err error
|
||||
if err := o.doBeforeUpsertHooks(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ins := fmt.Sprintf(`INSERT INTO {{.Table.Name}} ("%s") VALUES (%s) ON CONFLICT `, strings.Join(wl, `","`), boil.GenerateParamFlags(len(wl), 1))
|
||||
if !update {
|
||||
ins := ins + "DO NOTHING"
|
||||
} else if len(conflict) != 0 {
|
||||
ins := ins + fmt.Sprintf(`("%s") DO UPDATE SET %s`, strings.Join(conflict, `","`))
|
||||
} else {
|
||||
ins := ins + fmt.Sprintf(`("%s") DO UPDATE SET %s`, strings.Join({{$varNameSingular}}PrimaryKeyColumns, `","`))
|
||||
}
|
||||
|
||||
if len(returnColumns) != 0 {
|
||||
ins = ins + fmt.Sprintf(` RETURNING %s`, strings.Join(returnColumns, ","))
|
||||
err = exec.QueryRow(ins, boil.GetStructValues(o, wl...)...).Scan(boil.GetStructPointers(o, returnColumns...)...)
|
||||
} else {
|
||||
_, err = exec.Exec(ins, {{.Table.Columns | columnNames | stringMap .StringFuncs.titleCase | prefixStringSlice "o." | join ", "}})
|
||||
}
|
||||
|
||||
if boil.DebugMode {
|
||||
fmt.Fprintln(boil.DebugWriter, ins, boil.GetStructValues(o, wl...))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("{{.PkgName}}: unable to upsert for {{.Table.Name}}: %s", err)
|
||||
}
|
||||
|
||||
if err := o.doAfterUpsertHooks(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpsertP attempts an insert using an executor, and does an update or ignore on conflict.
|
||||
// UpsertP panics on error.
|
||||
func (o *{{$tableNameSingular}}) UpsertP(exec boil.Executor, update bool, conflictColumns []string, updateColumns []string, whitelist ...string) {
|
||||
if err := o.Upsert(exec, update, conflictColumns, updateColumns, whitelist...); err != nil {
|
||||
panic(boil.WrapErr(err))
|
||||
}
|
||||
}
|
0
templates_test/upsert.tpl
Normal file
0
templates_test/upsert.tpl
Normal file
Loading…
Add table
Reference in a new issue