github.com/Ali-iotechsys/sqlboiler/v4@v4.0.0-20221208124957-6aec9a5f1f71/drivers/sqlboiler-psql/driver/override/main/17_upsert.go.tpl (about) 1 {{- if or (not .Table.IsView) .Table.ViewCapabilities.CanUpsert -}} 2 {{- $alias := .Aliases.Table .Table.Name}} 3 {{- $schemaTable := .Table.Name | .SchemaTable}} 4 {{if .AddGlobal -}} 5 // UpsertG attempts an insert, and does an update or ignore on conflict. 6 func (o *{{$alias.UpSingular}}) UpsertG({{if not .NoContext}}ctx context.Context, {{end -}} updateOnConflict bool, conflictColumns []string, updateColumns, insertColumns boil.Columns) error { 7 return o.Upsert({{if .NoContext}}boil.GetDB(){{else}}ctx, boil.GetContextDB(){{end}}, updateOnConflict, conflictColumns, updateColumns, insertColumns) 8 } 9 10 {{end -}} 11 12 {{if and .AddGlobal .AddPanic -}} 13 // UpsertGP attempts an insert, and does an update or ignore on conflict. Panics on error. 14 func (o *{{$alias.UpSingular}}) UpsertGP({{if not .NoContext}}ctx context.Context, {{end -}} updateOnConflict bool, conflictColumns []string, updateColumns, insertColumns boil.Columns) { 15 if err := o.Upsert({{if .NoContext}}boil.GetDB(){{else}}ctx, boil.GetContextDB(){{end}}, updateOnConflict, conflictColumns, updateColumns, insertColumns); err != nil { 16 panic(boil.WrapErr(err)) 17 } 18 } 19 20 {{end -}} 21 22 {{if .AddPanic -}} 23 // UpsertP attempts an insert using an executor, and does an update or ignore on conflict. 24 // UpsertP panics on error. 25 func (o *{{$alias.UpSingular}}) UpsertP({{if .NoContext}}exec boil.Executor{{else}}ctx context.Context, exec boil.ContextExecutor{{end}}, updateOnConflict bool, conflictColumns []string, updateColumns, insertColumns boil.Columns) { 26 if err := o.Upsert({{if not .NoContext}}ctx, {{end -}} exec, updateOnConflict, conflictColumns, updateColumns, insertColumns); err != nil { 27 panic(boil.WrapErr(err)) 28 } 29 } 30 31 {{end -}} 32 33 // Upsert attempts an insert using an executor, and does an update or ignore on conflict. 34 // See boil.Columns documentation for how to properly use updateColumns and insertColumns. 35 func (o *{{$alias.UpSingular}}) Upsert({{if .NoContext}}exec boil.Executor{{else}}ctx context.Context, exec boil.ContextExecutor{{end}}, updateOnConflict bool, conflictColumns []string, updateColumns, insertColumns boil.Columns) error { 36 if o == nil { 37 return errors.New("{{.PkgName}}: no {{.Table.Name}} provided for upsert") 38 } 39 40 {{- template "timestamp_upsert_helper" . }} 41 42 {{if not .NoHooks -}} 43 if err := o.doBeforeUpsertHooks({{if not .NoContext}}ctx, {{end -}} exec); err != nil { 44 return err 45 } 46 {{- end}} 47 48 nzDefaults := queries.NonZeroDefaultSet({{$alias.DownSingular}}ColumnsWithDefault, o) 49 50 // Build cache key in-line uglily - mysql vs psql problems 51 buf := strmangle.GetBuffer() 52 if updateOnConflict { 53 buf.WriteByte('t') 54 } else { 55 buf.WriteByte('f') 56 } 57 buf.WriteByte('.') 58 for _, c := range conflictColumns { 59 buf.WriteString(c) 60 } 61 buf.WriteByte('.') 62 buf.WriteString(strconv.Itoa(updateColumns.Kind)) 63 for _, c := range updateColumns.Cols { 64 buf.WriteString(c) 65 } 66 buf.WriteByte('.') 67 buf.WriteString(strconv.Itoa(insertColumns.Kind)) 68 for _, c := range insertColumns.Cols { 69 buf.WriteString(c) 70 } 71 buf.WriteByte('.') 72 for _, c := range nzDefaults { 73 buf.WriteString(c) 74 } 75 key := buf.String() 76 strmangle.PutBuffer(buf) 77 78 {{$alias.DownSingular}}UpsertCacheMut.RLock() 79 cache, cached := {{$alias.DownSingular}}UpsertCache[key] 80 {{$alias.DownSingular}}UpsertCacheMut.RUnlock() 81 82 var err error 83 84 if !cached { 85 insert, ret := insertColumns.InsertColumnSet( 86 {{$alias.DownSingular}}AllColumns, 87 {{$alias.DownSingular}}ColumnsWithDefault, 88 {{$alias.DownSingular}}ColumnsWithoutDefault, 89 nzDefaults, 90 ) 91 92 update := updateColumns.UpdateColumnSet( 93 {{$alias.DownSingular}}AllColumns, 94 {{$alias.DownSingular}}PrimaryKeyColumns, 95 ) 96 {{if filterColumnsByAuto true .Table.Columns }} 97 insert = strmangle.SetComplement(insert, {{$alias.DownSingular}}GeneratedColumns) 98 update = strmangle.SetComplement(update, {{$alias.DownSingular}}GeneratedColumns) 99 {{- end }} 100 101 if updateOnConflict && len(update) == 0 { 102 return errors.New("{{.PkgName}}: unable to upsert {{.Table.Name}}, could not build update column list") 103 } 104 105 conflict := conflictColumns 106 if len(conflict) == 0 { 107 conflict = make([]string, len({{$alias.DownSingular}}PrimaryKeyColumns)) 108 copy(conflict, {{$alias.DownSingular}}PrimaryKeyColumns) 109 } 110 cache.query = buildUpsertQueryPostgres(dialect, "{{$schemaTable}}", updateOnConflict, ret, update, conflict, insert) 111 112 cache.valueMapping, err = queries.BindMapping({{$alias.DownSingular}}Type, {{$alias.DownSingular}}Mapping, insert) 113 if err != nil { 114 return err 115 } 116 if len(ret) != 0 { 117 cache.retMapping, err = queries.BindMapping({{$alias.DownSingular}}Type, {{$alias.DownSingular}}Mapping, ret) 118 if err != nil { 119 return err 120 } 121 } 122 } 123 124 value := reflect.Indirect(reflect.ValueOf(o)) 125 vals := queries.ValuesFromMapping(value, cache.valueMapping) 126 var returns []interface{} 127 if len(cache.retMapping) != 0 { 128 returns = queries.PtrsFromMapping(value, cache.retMapping) 129 } 130 131 {{if .NoContext -}} 132 if boil.DebugMode { 133 fmt.Fprintln(boil.DebugWriter, cache.query) 134 fmt.Fprintln(boil.DebugWriter, vals) 135 } 136 {{else -}} 137 if boil.IsDebug(ctx) { 138 writer := boil.DebugWriterFrom(ctx) 139 fmt.Fprintln(writer, cache.query) 140 fmt.Fprintln(writer, vals) 141 } 142 {{end -}} 143 144 if len(cache.retMapping) != 0 { 145 {{if .NoContext -}} 146 err = exec.QueryRow(cache.query, vals...).Scan(returns...) 147 {{else -}} 148 err = exec.QueryRowContext(ctx, cache.query, vals...).Scan(returns...) 149 {{end -}} 150 if errors.Is(err, sql.ErrNoRows) { 151 err = nil // Postgres doesn't return anything when there's no update 152 } 153 } else { 154 {{if .NoContext -}} 155 _, err = exec.Exec(cache.query, vals...) 156 {{else -}} 157 _, err = exec.ExecContext(ctx, cache.query, vals...) 158 {{end -}} 159 } 160 if err != nil { 161 return errors.Wrap(err, "{{.PkgName}}: unable to upsert {{.Table.Name}}") 162 } 163 164 if !cached { 165 {{$alias.DownSingular}}UpsertCacheMut.Lock() 166 {{$alias.DownSingular}}UpsertCache[key] = cache 167 {{$alias.DownSingular}}UpsertCacheMut.Unlock() 168 } 169 170 {{if not .NoHooks -}} 171 return o.doAfterUpsertHooks({{if not .NoContext}}ctx, {{end -}} exec) 172 {{- else -}} 173 return nil 174 {{- end}} 175 } 176 {{end}}