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}}