1// Copyright 2019 The Gitea Authors. All rights reserved. 2// Use of this source code is governed by a MIT-style 3// license that can be found in the LICENSE file. 4 5package db 6 7import ( 8 "context" 9 "database/sql" 10 11 "code.gitea.io/gitea/modules/setting" 12 13 "xorm.io/builder" 14) 15 16// DefaultContext is the default context to run xorm queries in 17// will be overwritten by Init with HammerContext 18var DefaultContext context.Context 19 20// contextKey is a value for use with context.WithValue. 21type contextKey struct { 22 name string 23} 24 25// EnginedContextKey is a context key. It is used with context.Value() to get the current Engined for the context 26var EnginedContextKey = &contextKey{"engined"} 27 28// Context represents a db context 29type Context struct { 30 context.Context 31 e Engine 32} 33 34// WithEngine returns a db.Context from a context.Context and db.Engine 35func WithEngine(ctx context.Context, e Engine) *Context { 36 return &Context{ 37 Context: ctx, 38 e: e, 39 } 40} 41 42// Engine returns db engine 43func (ctx *Context) Engine() Engine { 44 return ctx.e 45} 46 47// Value shadows Value for context.Context but allows us to get ourselves and an Engined object 48func (ctx *Context) Value(key interface{}) interface{} { 49 if key == EnginedContextKey { 50 return ctx 51 } 52 return ctx.Context.Value(key) 53} 54 55// Engined structs provide an Engine 56type Engined interface { 57 Engine() Engine 58} 59 60// GetEngine will get a db Engine from this context or return an Engine restricted to this context 61func GetEngine(ctx context.Context) Engine { 62 if engined, ok := ctx.(Engined); ok { 63 return engined.Engine() 64 } 65 enginedInterface := ctx.Value(EnginedContextKey) 66 if enginedInterface != nil { 67 return enginedInterface.(Engined).Engine() 68 } 69 return x.Context(ctx) 70} 71 72// Committer represents an interface to Commit or Close the Context 73type Committer interface { 74 Commit() error 75 Close() error 76} 77 78// TxContext represents a transaction Context 79func TxContext() (*Context, Committer, error) { 80 sess := x.NewSession() 81 if err := sess.Begin(); err != nil { 82 sess.Close() 83 return nil, nil, err 84 } 85 86 return &Context{ 87 Context: DefaultContext, 88 e: sess, 89 }, sess, nil 90} 91 92// WithContext represents executing database operations 93func WithContext(f func(ctx *Context) error) error { 94 return f(&Context{ 95 Context: DefaultContext, 96 e: x, 97 }) 98} 99 100// WithTx represents executing database operations on a transaction 101func WithTx(f func(ctx context.Context) error) error { 102 sess := x.NewSession() 103 defer sess.Close() 104 if err := sess.Begin(); err != nil { 105 return err 106 } 107 108 if err := f(&Context{ 109 Context: DefaultContext, 110 e: sess, 111 }); err != nil { 112 return err 113 } 114 115 return sess.Commit() 116} 117 118// Iterate iterates the databases and doing something 119func Iterate(ctx context.Context, tableBean interface{}, cond builder.Cond, fun func(idx int, bean interface{}) error) error { 120 return GetEngine(ctx).Where(cond). 121 BufferSize(setting.Database.IterateBufferSize). 122 Iterate(tableBean, fun) 123} 124 125// Insert inserts records into database 126func Insert(ctx context.Context, beans ...interface{}) error { 127 _, err := GetEngine(ctx).Insert(beans...) 128 return err 129} 130 131// Exec executes a sql with args 132func Exec(ctx context.Context, sqlAndArgs ...interface{}) (sql.Result, error) { 133 return GetEngine(ctx).Exec(sqlAndArgs...) 134} 135 136// GetByBean filled empty fields of the bean according non-empty fields to query in database. 137func GetByBean(ctx context.Context, bean interface{}) (bool, error) { 138 return GetEngine(ctx).Get(bean) 139} 140 141// DeleteByBean deletes all records according non-empty fields of the bean as conditions. 142func DeleteByBean(ctx context.Context, bean interface{}) (int64, error) { 143 return GetEngine(ctx).Delete(bean) 144} 145 146// CountByBean counts the number of database records according non-empty fields of the bean as conditions. 147func CountByBean(ctx context.Context, bean interface{}) (int64, error) { 148 return GetEngine(ctx).Count(bean) 149} 150 151// TableName returns the table name according a bean object 152func TableName(bean interface{}) string { 153 return x.TableName(bean) 154} 155