Add support for two step DB upsert
This commit is contained in:
committed by
Jože Fortun
parent
5d73098854
commit
878e5edddb
@@ -80,8 +80,29 @@ func (s *Store) Upsert{{ .expIdent }}(ctx context.Context, {{ template "extraArg
|
||||
return
|
||||
}
|
||||
|
||||
if err = s.Exec(ctx, {{ .ident }}UpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil {
|
||||
return
|
||||
// @todo this solution is ok for now but could be problematic when we start
|
||||
// batching together DB operations.
|
||||
if s.Dialect.Nuances().TwoStepUpsert {
|
||||
var rsp sql.Result
|
||||
rsp, err = s.ExecR(ctx, {{ .ident }}UpdateQuery(s.Dialect.GOQU(), rr[i]))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if c, err := rsp.RowsAffected(); err != nil {
|
||||
return err
|
||||
} else if c > 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
err = s.Exec(ctx, {{ .ident }}InsertQuery(s.Dialect.GOQU(), rr[i]))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
err = s.Exec(ctx, {{ .ident }}UpsertQuery(s.Dialect.GOQU(), rr[i]))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package drivers
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/pkg/dal"
|
||||
"github.com/cortezaproject/corteza/server/pkg/ql"
|
||||
"github.com/cortezaproject/corteza/server/store/adapters/rdbms/ddl"
|
||||
@@ -17,6 +18,13 @@ type (
|
||||
// use of aliases inside HAVING clause and
|
||||
// MySQL does not.
|
||||
HavingClauseMustUseAlias bool
|
||||
|
||||
// TwoStepUpsert allows support for databases which don't have an upsert
|
||||
// or we simply couldn't figure out how to make work.
|
||||
//
|
||||
// TwoStepUpsert uses the context from the update statement to figure out
|
||||
// if it needs to do an insert.
|
||||
TwoStepUpsert bool
|
||||
}
|
||||
|
||||
Dialect interface {
|
||||
|
||||
Generated
+966
-84
File diff suppressed because it is too large
Load Diff
@@ -114,17 +114,28 @@ func (s Store) Healthcheck(ctx context.Context) error {
|
||||
return s.Ping(ctx)
|
||||
}
|
||||
|
||||
// Exec executes the SQL and drops the result
|
||||
func (s Store) Exec(ctx context.Context, q sqlizer) error {
|
||||
_, err := s.exec(ctx, q)
|
||||
return err
|
||||
}
|
||||
|
||||
// ExecR executes the SQL and returns the result
|
||||
func (s Store) ExecR(ctx context.Context, q sqlizer) (rs sql.Result, _ error) {
|
||||
return s.exec(ctx, q)
|
||||
}
|
||||
|
||||
func (s Store) exec(ctx context.Context, q sqlizer) (rs sql.Result, _ error) {
|
||||
var (
|
||||
query, args, err = q.ToSQL()
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not build query: %w", err)
|
||||
return rs, fmt.Errorf("could not build query: %w", err)
|
||||
}
|
||||
|
||||
_, err = s.DB.ExecContext(ctx, query, args...)
|
||||
return store.HandleError(err, s.ErrorHandler)
|
||||
rs, err = s.DB.ExecContext(ctx, query, args...)
|
||||
return rs, store.HandleError(err, s.ErrorHandler)
|
||||
}
|
||||
|
||||
func (s Store) Query(ctx context.Context, q sqlizer) (*sql.Rows, error) {
|
||||
|
||||
Reference in New Issue
Block a user