storj/satellite/satellitedb/dbx/templates/golang.header.tmpl
JT Olio 71e11b27f3 satellite/dbx: only retry with cockroach
Change-Id: Id3630c26dbfda36dcbece2849e2353d5ab2882af
2020-11-29 18:10:07 -07:00

486 lines
9.1 KiB
Cheetah

{{- $options := .Options -}}
// AUTOGENERATED BY storj.io/dbx
// DO NOT EDIT.
package {{ .Package }}
import (
"bytes"
"context"
"database/sql"
"errors"
"fmt"
"reflect"
"strconv"
"strings"
"time"
"unicode"
"sync"
{{- range .ExtraImports }}
{{ . }}
{{- end }}
)
// Prevent conditional imports from causing build failures.
var _ = strconv.Itoa
var _ = strings.LastIndex
var _ = fmt.Sprint
var _ sync.Mutex
var (
WrapErr = func(err *Error) error {return err}
Logger func(format string, args ...interface{})
ShouldRetry func(driver string, err error) bool
errTooManyRows = errors.New("too many rows")
errUnsupportedDriver = errors.New("unsupported driver")
errEmptyUpdate = errors.New("empty update")
)
func logError(format string, args ...interface{}) {
if Logger != nil {
Logger(format, args...)
}
}
type ErrorCode int
const (
ErrorCode_Unknown ErrorCode = iota
ErrorCode_UnsupportedDriver
ErrorCode_NoRows
ErrorCode_TxDone
ErrorCode_TooManyRows
ErrorCode_ConstraintViolation
ErrorCode_EmptyUpdate
)
type Error struct {
Err error
Code ErrorCode
Driver string
Constraint string
QuerySuffix string
}
func (e *Error) Error() string {
return e.Err.Error()
}
func wrapErr(e *Error) error {
if WrapErr == nil {
return e
}
return WrapErr(e)
}
func makeErr(err error) error {
if err == nil {
return nil
}
e := &Error{Err: err}
switch err {
case sql.ErrNoRows:
e.Code = ErrorCode_NoRows
case sql.ErrTxDone:
e.Code = ErrorCode_TxDone
}
return wrapErr(e)
}
func shouldRetry(driver string, err error) bool {
if ShouldRetry == nil {
return false
}
return ShouldRetry(driver, err)
}
func unsupportedDriver(driver string) error {
return wrapErr(&Error{
Err: errUnsupportedDriver,
Code: ErrorCode_UnsupportedDriver,
Driver: driver,
})
}
func emptyUpdate() error {
return wrapErr(&Error{
Err: errEmptyUpdate,
Code: ErrorCode_EmptyUpdate,
})
}
func tooManyRows(query_suffix string) error {
return wrapErr(&Error{
Err: errTooManyRows,
Code: ErrorCode_TooManyRows,
QuerySuffix: query_suffix,
})
}
func constraintViolation(err error, constraint string) error {
return wrapErr(&Error{
Err: err,
Code: ErrorCode_ConstraintViolation,
Constraint: constraint,
})
}
type driver interface {
ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row
}
var (
notAPointer = errors.New("destination not a pointer")
lossyConversion = errors.New("lossy conversion")
)
type DB struct {
*sql.DB
dbMethods
Hooks struct {
Now func() time.Time
}
driver string
}
func Open(driver, source string) (db *DB, err error) {
var sql_db *sql.DB
switch driver {
{{- range .Dialects }}
case {{ .Name | printf "%q" }}:
sql_db, err = open{{ .Name }}(source)
{{- end }}
default:
return nil, unsupportedDriver(driver)
}
if err != nil {
return nil, makeErr(err)
}
defer func(sql_db *sql.DB) {
if err != nil {
sql_db.Close()
}
}(sql_db)
if err := sql_db.Ping(); err != nil {
return nil, makeErr(err)
}
db = &DB{
DB: sql_db,
driver: driver,
}
db.Hooks.Now = time.Now
switch driver {
{{- range .Dialects }}
case {{ .Name | printf "%q" }}:
db.dbMethods = new{{ .Name }}(db)
{{- end }}
default:
return nil, unsupportedDriver(driver)
}
return db, nil
}
func (obj *DB) Close() (err error) {
return obj.makeErr(obj.DB.Close())
}
func (obj *DB) Open(ctx context.Context) (*Tx, error) {
tx, err := obj.DB.BeginTx(ctx, nil)
if err != nil {
return nil, obj.makeErr(err)
}
return &Tx{
Tx: tx,
txMethods: obj.wrapTx(tx),
}, nil
}
{{ if $options.SupportRx }}
func (obj *DB) NewRx() *Rx {
return &Rx{db: obj}
}
{{ end }}
func DeleteAll(ctx context.Context, db *DB) (int64, error) {
tx, err := db.Open(ctx)
if err != nil {
return 0, err
}
defer func() {
if err == nil {
err = db.makeErr(tx.Commit())
return
}
if err_rollback := tx.Rollback(); err_rollback != nil {
logError("delete-all: rollback failed: %v", db.makeErr(err_rollback))
}
}()
return tx.deleteAll(ctx)
}
type Tx struct {
Tx *sql.Tx
txMethods
}
type dialectTx struct {
tx *sql.Tx
}
func (tx *dialectTx) Commit() (err error) {
return makeErr(tx.tx.Commit())
}
func (tx *dialectTx) Rollback() (err error) {
return makeErr(tx.tx.Rollback())
}
{{- range .Dialects }}
{{- $dbtype := .Name | printf "%sDB" -}}
{{- $txtype := .Name | printf "%sTx" -}}
{{- $impltype := .Name | printf "%sImpl" }}
type {{ $impltype }} struct {
db *DB
dialect __sqlbundle_{{ .Name }}
driver driver
txn bool
}
func (obj *{{ $impltype }}) Rebind(s string) string {
return obj.dialect.Rebind(s)
}
func (obj *{{ $impltype }}) logStmt(stmt string, args... interface{}) {
{{ .Name }}LogStmt(stmt, args...)
}
func (obj *{{ $impltype }}) makeErr(err error) error {
constraint, ok := obj.isConstraintError(err)
if ok {
return constraintViolation(err, constraint)
}
return makeErr(err)
}
func (obj *{{ $impltype }}) shouldRetry(err error) bool {
return !obj.txn && shouldRetry(obj.db.driver, err)
}
type {{ $impltype }}_retryingRow struct {
obj *{{ $impltype }}
ctx context.Context
query string
args []interface{}
}
func (obj *{{ $impltype }}) queryRowContext(ctx context.Context, query string, args ...interface{}) *{{ $impltype }}_retryingRow {
return &{{ $impltype }}_retryingRow{
obj: obj,
ctx: ctx,
query: query,
args: args,
}
}
func (rows *{{ $impltype }}_retryingRow) Scan(dest ...interface{}) error {
for {
err := rows.obj.driver.QueryRowContext(rows.ctx, rows.query, rows.args...).Scan(dest...)
if err != nil {
if rows.obj.shouldRetry(err) {
continue
}
// caller will wrap this error
return err
}
return nil
}
}
type {{ $dbtype }} struct {
db *DB
*{{ $impltype }}
}
func new{{ .Name }}(db *DB) *{{ $dbtype }} {
return &{{ $dbtype }}{
db: db,
{{ $impltype }}: &{{ $impltype }}{
db: db,
driver: db.DB,
},
}
}
func (obj *{{ $dbtype }}) Schema() string {
return `{{ .SchemaSQL }}`
}
func (obj *{{ $dbtype }}) wrapTx(tx *sql.Tx) txMethods {
return &{{ $txtype }}{
dialectTx: dialectTx{tx: tx},
{{ $impltype }}: &{{ $impltype }}{
db: obj.db,
driver: tx,
txn: true,
},
}
}
type {{ $txtype }} struct {
dialectTx
*{{ $impltype }}
}
func {{ .Name }}LogStmt(stmt string, args ...interface{}) {
// TODO: render placeholders
if Logger != nil {
out := fmt.Sprintf("stmt: %s\nargs: %v\n", stmt, pretty(args))
Logger(out)
}
}
{{- end }}
type pretty []interface{}
func (p pretty) Format(f fmt.State, c rune) {
fmt.Fprint(f, "[")
nextval:
for i, val := range p {
if i > 0 {
fmt.Fprint(f, ", ")
}
rv := reflect.ValueOf(val)
if rv.Kind() == reflect.Ptr {
if rv.IsNil() {
fmt.Fprint(f, "NULL")
continue
}
val = rv.Elem().Interface()
}
switch v := val.(type) {
case string:
fmt.Fprintf(f, "%q", v)
case time.Time:
fmt.Fprintf(f, "%s", v.Format(time.RFC3339Nano))
case []byte:
for _, b := range v {
if !unicode.IsPrint(rune(b)) {
fmt.Fprintf(f, "%#x", v)
continue nextval
}
}
fmt.Fprintf(f, "%q", v)
default:
fmt.Fprintf(f, "%v", v)
}
}
fmt.Fprint(f, "]")
}
{{ range .Structs }}
{{- $struct := .Name -}}
{{- $createstruct := .CreateStructName -}}
{{- $updatestruct := .UpdateStructName }}
type {{ $struct }} struct {
{{- range .Fields }}
{{ .Name }} {{ .Type }}
{{- end }}
{{- if $options.SupportUserdata }}
userdata_mu sync.Mutex
userdata interface{}
{{- end}}
}
func ({{ $struct }}) _Table() string { return "{{ .Table }}" }
{{- if .InsertableOptionalFields }}
type {{ $createstruct }} struct {
{{- range .InsertableOptionalFields }}
{{ .Name }} {{ .StructName }}
{{- end }}
}
{{- end }}
type {{ $updatestruct }} struct {
{{- range .UpdatableFields }}
{{ .Name }} {{ .StructName }}
{{- end }}
}
{{- range .Fields }}
{{- $fstruct := .StructName }}
{{- $ctor := printf "%s_%s" .ModelName .Name }}
type {{ $fstruct }} struct {
_set bool
_null bool
_value {{ .Type }}
}
func {{ $ctor }}(v {{ .CtorValue }}) {{ $fstruct }} {
{{- if .MutateFn }}
v = {{ .MutateFn }}(v)
{{- end }}
return {{ $fstruct }}{ _set: true, _value: {{ if .TakeAddr }}&{{ end }}v }
}
{{ if .Nullable }}
func {{ $ctor }}_Raw(v {{ .Type }}) {{ $fstruct }} {
if v == nil {
return {{ $ctor }}_Null()
}
return {{ $ctor }}({{ if .TakeAddr }}*{{ end }}v)
}
func {{ $ctor }}_Null() {{ $fstruct }} {
return {{ $fstruct }}{ _set: true, _null: true }
}
func (f {{ $fstruct }}) isnull() bool { return !f._set || f._null || f._value == nil }
{{ end }}
func (f {{ $fstruct }}) value() interface{} { if !f._set || f._null { return nil }; return f._value }
func ({{ $fstruct }}) _Column() string { return "{{ .Column }}" }
{{- end -}}
{{- end }}
func toUTC(t time.Time) time.Time {
return t.UTC()
}
func toDate(t time.Time) time.Time {
// keep up the minute portion so that translations between timezones will
// continue to reflect properly.
return t.Truncate(time.Minute)
}
//
// runtime support for building sql statements
//
{{ .SQLSupport }}
//
// end runtime support for building sql statements
//