3
0

Add support for two step DB upsert

This commit is contained in:
Tomaž Jerman
2022-11-23 08:57:27 +01:00
committed by Jože Fortun
parent 5d73098854
commit 878e5edddb
4 changed files with 1011 additions and 89 deletions
@@ -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 {
+966 -84
View File
File diff suppressed because it is too large Load Diff
+14 -3
View File
@@ -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) {