github.com/Ali-iotechsys/sqlboiler/v4@v4.0.0-20221208124957-6aec9a5f1f71/drivers/sqlboiler-mysql/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 -}} updateColumns, insertColumns boil.Columns) error { 7 return o.Upsert({{if .NoContext}}boil.GetDB(){{else}}ctx, boil.GetContextDB(){{end}}, 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 -}} updateColumns, insertColumns boil.Columns) { 15 if err := o.Upsert({{if .NoContext}}boil.GetDB(){{else}}ctx, boil.GetContextDB(){{end}}, 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}}, updateColumns, insertColumns boil.Columns) { 26 if err := o.Upsert({{if not .NoContext}}ctx, {{end -}} exec, updateColumns, insertColumns); err != nil { 27 panic(boil.WrapErr(err)) 28 } 29 } 30 31 {{end -}} 32 33 var mySQL{{$alias.UpSingular}}UniqueColumns = []string{ 34 {{- range $i, $col := .Table.Columns -}} 35 {{- if $col.Unique}} 36 "{{$col.Name}}", 37 {{- end -}} 38 {{- end}} 39 } 40 41 // Upsert attempts an insert using an executor, and does an update or ignore on conflict. 42 // See boil.Columns documentation for how to properly use updateColumns and insertColumns. 43 func (o *{{$alias.UpSingular}}) Upsert({{if .NoContext}}exec boil.Executor{{else}}ctx context.Context, exec boil.ContextExecutor{{end}}, updateColumns, insertColumns boil.Columns) error { 44 if o == nil { 45 return errors.New("{{.PkgName}}: no {{.Table.Name}} provided for upsert") 46 } 47 48 {{- template "timestamp_upsert_helper" . }} 49 50 {{if not .NoHooks -}} 51 if err := o.doBeforeUpsertHooks({{if not .NoContext}}ctx, {{end -}} exec); err != nil { 52 return err 53 } 54 {{- end}} 55 56 nzDefaults := queries.NonZeroDefaultSet({{$alias.DownSingular}}ColumnsWithDefault, o) 57 nzUniques := queries.NonZeroDefaultSet(mySQL{{$alias.UpSingular}}UniqueColumns, o) 58 59 if len(nzUniques) == 0 { 60 return errors.New("cannot upsert with a table that cannot conflict on a unique column") 61 } 62 63 // Build cache key in-line uglily - mysql vs psql problems 64 buf := strmangle.GetBuffer() 65 buf.WriteString(strconv.Itoa(updateColumns.Kind)) 66 for _, c := range updateColumns.Cols { 67 buf.WriteString(c) 68 } 69 buf.WriteByte('.') 70 buf.WriteString(strconv.Itoa(insertColumns.Kind)) 71 for _, c := range insertColumns.Cols { 72 buf.WriteString(c) 73 } 74 buf.WriteByte('.') 75 for _, c := range nzDefaults { 76 buf.WriteString(c) 77 } 78 buf.WriteByte('.') 79 for _, c := range nzUniques { 80 buf.WriteString(c) 81 } 82 key := buf.String() 83 strmangle.PutBuffer(buf) 84 85 {{$alias.DownSingular}}UpsertCacheMut.RLock() 86 cache, cached := {{$alias.DownSingular}}UpsertCache[key] 87 {{$alias.DownSingular}}UpsertCacheMut.RUnlock() 88 89 var err error 90 91 if !cached { 92 insert, ret := insertColumns.InsertColumnSet( 93 {{$alias.DownSingular}}AllColumns, 94 {{$alias.DownSingular}}ColumnsWithDefault, 95 {{$alias.DownSingular}}ColumnsWithoutDefault, 96 nzDefaults, 97 ) 98 99 update := updateColumns.UpdateColumnSet( 100 {{$alias.DownSingular}}AllColumns, 101 {{$alias.DownSingular}}PrimaryKeyColumns, 102 ) 103 {{if filterColumnsByAuto true .Table.Columns }} 104 insert = strmangle.SetComplement(insert, {{$alias.DownSingular}}GeneratedColumns) 105 update = strmangle.SetComplement(update, {{$alias.DownSingular}}GeneratedColumns) 106 {{- end }} 107 108 if !updateColumns.IsNone() && len(update) == 0 { 109 return errors.New("{{.PkgName}}: unable to upsert {{.Table.Name}}, could not build update column list") 110 } 111 112 ret = strmangle.SetComplement(ret, nzUniques) 113 cache.query = buildUpsertQueryMySQL(dialect, "{{$schemaTable}}", update, insert) 114 cache.retQuery = fmt.Sprintf( 115 "SELECT %s FROM {{.LQ}}{{.Table.Name}}{{.RQ}} WHERE %s", 116 strings.Join(strmangle.IdentQuoteSlice(dialect.LQ, dialect.RQ, ret), ","), 117 strmangle.WhereClause("{{.LQ}}", "{{.RQ}}", 0, nzUniques), 118 ) 119 120 cache.valueMapping, err = queries.BindMapping({{$alias.DownSingular}}Type, {{$alias.DownSingular}}Mapping, insert) 121 if err != nil { 122 return err 123 } 124 if len(ret) != 0 { 125 cache.retMapping, err = queries.BindMapping({{$alias.DownSingular}}Type, {{$alias.DownSingular}}Mapping, ret) 126 if err != nil { 127 return err 128 } 129 } 130 } 131 132 value := reflect.Indirect(reflect.ValueOf(o)) 133 vals := queries.ValuesFromMapping(value, cache.valueMapping) 134 var returns []interface{} 135 if len(cache.retMapping) != 0 { 136 returns = queries.PtrsFromMapping(value, cache.retMapping) 137 } 138 139 {{if .NoContext -}} 140 if boil.DebugMode { 141 fmt.Fprintln(boil.DebugWriter, cache.query) 142 fmt.Fprintln(boil.DebugWriter, vals) 143 } 144 {{else -}} 145 if boil.IsDebug(ctx) { 146 writer := boil.DebugWriterFrom(ctx) 147 fmt.Fprintln(writer, cache.query) 148 fmt.Fprintln(writer, vals) 149 } 150 {{end -}} 151 152 {{$canLastInsertID := .Table.CanLastInsertID -}} 153 {{if $canLastInsertID -}} 154 {{if .NoContext -}} 155 result, err := exec.Exec(cache.query, vals...) 156 {{else -}} 157 result, err := exec.ExecContext(ctx, cache.query, vals...) 158 {{end -}} 159 {{else -}} 160 {{if .NoContext -}} 161 _, err = exec.Exec(cache.query, vals...) 162 {{else -}} 163 _, err = exec.ExecContext(ctx, cache.query, vals...) 164 {{end -}} 165 {{- end}} 166 if err != nil { 167 return errors.Wrap(err, "{{.PkgName}}: unable to upsert for {{.Table.Name}}") 168 } 169 170 {{if $canLastInsertID -}} 171 var lastID int64 172 {{- end}} 173 var uniqueMap []uint64 174 var nzUniqueCols []interface{} 175 176 if len(cache.retMapping) == 0 { 177 goto CacheNoHooks 178 } 179 180 {{if $canLastInsertID -}} 181 lastID, err = result.LastInsertId() 182 if err != nil { 183 return ErrSyncFail 184 } 185 186 {{$colName := index .Table.PKey.Columns 0 -}} 187 {{- $col := .Table.GetColumn $colName -}} 188 {{- $colTitled := $alias.Column $colName}} 189 o.{{$colTitled}} = {{$col.Type}}(lastID) 190 if lastID != 0 && len(cache.retMapping) == 1 && cache.retMapping[0] == {{$alias.DownSingular}}Mapping["{{$colName}}"] { 191 goto CacheNoHooks 192 } 193 {{- end}} 194 195 uniqueMap, err = queries.BindMapping({{$alias.DownSingular}}Type, {{$alias.DownSingular}}Mapping, nzUniques) 196 if err != nil { 197 return errors.Wrap(err, "{{.PkgName}}: unable to retrieve unique values for {{.Table.Name}}") 198 } 199 nzUniqueCols = queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), uniqueMap) 200 201 {{if .NoContext -}} 202 if boil.DebugMode { 203 fmt.Fprintln(boil.DebugWriter, cache.retQuery) 204 fmt.Fprintln(boil.DebugWriter, nzUniqueCols...) 205 } 206 {{else -}} 207 if boil.IsDebug(ctx) { 208 writer := boil.DebugWriterFrom(ctx) 209 fmt.Fprintln(writer, cache.retQuery) 210 fmt.Fprintln(writer, nzUniqueCols...) 211 } 212 {{end -}} 213 214 {{if .NoContext -}} 215 err = exec.QueryRow(cache.retQuery, nzUniqueCols...).Scan(returns...) 216 {{else -}} 217 err = exec.QueryRowContext(ctx, cache.retQuery, nzUniqueCols...).Scan(returns...) 218 {{end -}} 219 if err != nil { 220 return errors.Wrap(err, "{{.PkgName}}: unable to populate default values for {{.Table.Name}}") 221 } 222 223 CacheNoHooks: 224 if !cached { 225 {{$alias.DownSingular}}UpsertCacheMut.Lock() 226 {{$alias.DownSingular}}UpsertCache[key] = cache 227 {{$alias.DownSingular}}UpsertCacheMut.Unlock() 228 } 229 230 {{if not .NoHooks -}} 231 return o.doAfterUpsertHooks({{if not .NoContext}}ctx, {{end -}} exec) 232 {{- else -}} 233 return nil 234 {{- end}} 235 } 236 {{end}}