{{- $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 //