go vendor

This commit is contained in:
lealife
2017-11-30 19:55:33 +08:00
parent 2856da6888
commit 0fb92efbf3
670 changed files with 199010 additions and 0 deletions

80
vendor/github.com/revel/modules/orm/gorm/README.md generated vendored Normal file
View File

@@ -0,0 +1,80 @@
modules/gorm
===============
[Gorm](http://jinzhu.me/gorm) module
## Activation
```ini
module.gorm = github.com/revel/modules/orm/gorm
```
## Drivers
* sqlite3
* postgres
* mysql
## Configuration file
```ini
# Database config
db.autoinit=true # default=true
db.driver=sqlite # mysql, postgres, sqlite3
db.host=localhost # Use db.host /tmp/app.db is your driver is sqlite
db.user=dbuser
db.name=dbname
db.password=dbpassword
```
## Example usage with transactions
```go
package controllers
import (
"github.com/revel/revel"
gormc "github.com/revel/modules/gorm/orm/app/controllers"
)
type App struct {
gormc.TxnController
}
type Toy struct {
Name string
}
func (c App) Index() revel.Result {
c.Txn.LogMode(true)
c.Txn.AutoMigrate(&Toy{})
c.Txn.Save(&Toy{Name: "Fidget spinner"})
return c.Render()
}
```
## Example usage without transactions
```go
package controllers
import (
"github.com/revel/revel"
gormc "github.com/revel/modules/gorm/orm/app/controllers"
)
type App struct {
gormc.Controller
}
type Toy struct {
Name string
}
func (c App) Index() revel.Result {
c.DB.LogMode(true)
c.DB.AutoMigrate(&Toy{})
c.DB.Save(&Toy{Name: "Fidget spinner"})
return c.Render()
}
```

View File

@@ -0,0 +1,84 @@
package gormcontroller
import (
"database/sql"
"fmt"
"github.com/jinzhu/gorm"
gormdb "github.com/revel/modules/orm/gorm/app"
"github.com/revel/revel"
)
// Controller is a Revel controller with a pointer to the opened database
type Controller struct {
*revel.Controller
DB *gorm.DB
}
func (c *Controller) setDB() revel.Result {
c.DB = gormdb.DB
return nil
}
// TxnController is a Revel controller with database transaction support (begin, commit and rollback)
type TxnController struct {
*revel.Controller
Txn *gorm.DB
}
// Begin begins a DB transaction
func (c *TxnController) Begin() revel.Result {
txn := gormdb.DB.Begin()
if txn.Error != nil {
c.Log.Panic("Transaction begine error","error",txn.Error)
}
c.Txn = txn
return nil
}
// Commit commits the database transation
func (c *TxnController) Commit() revel.Result {
if c.Txn == nil {
return nil
}
c.Txn.Commit()
if c.Txn.Error != nil && c.Txn.Error != sql.ErrTxDone {
fmt.Println(c.Txn.Error)
panic(c.Txn.Error)
}
c.Txn = nil
return nil
}
// Rollback rolls back the transaction (eg. after a panic)
func (c *TxnController) Rollback() revel.Result {
if c.Txn == nil {
return nil
}
c.Txn.Rollback()
if c.Txn.Error != nil && c.Txn.Error != sql.ErrTxDone {
fmt.Println(c.Txn.Error)
panic(c.Txn.Error)
}
c.Txn = nil
return nil
}
func init() {
revel.OnAppStart(func() {
if revel.Config.BoolDefault("db.autoinit", true) {
gormdb.InitDB()
revel.InterceptMethod((*TxnController).Begin, revel.BEFORE)
revel.InterceptMethod((*TxnController).Commit, revel.AFTER)
revel.InterceptMethod((*TxnController).Rollback, revel.FINALLY)
revel.InterceptMethod((*Controller).setDB, revel.BEFORE)
}
})
}

72
vendor/github.com/revel/modules/orm/gorm/app/gorm.go generated vendored Normal file
View File

@@ -0,0 +1,72 @@
package gormdb
// # Database config
// db.driver=sqlite3 # mysql, postgres, sqlite3
// db.host=localhost # Use dbhost /tmp/app.db is your driver is sqlite
// db.user=dbuser
// db.name=dbname
// db.password=dbpassword
import (
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql" // mysql package
_ "github.com/jinzhu/gorm/dialects/postgres" // postgres package
_ "github.com/jinzhu/gorm/dialects/sqlite" // mysql package
"github.com/revel/revel"
)
// DB Gorm
var (
DB *gorm.DB
gormLog = revel.AppLog
)
func init() {
revel.RegisterModuleInit(func(m *revel.Module){
gormLog = m.Log
})
}
// InitDB database
func OpenDB(dbDriver string, dbInfo string) {
db, err := gorm.Open(dbDriver, dbInfo)
if err != nil {
gormLog.Fatal("sql.Open failed", "error", err)
}
DB = db
}
type DbInfo struct {
DbDriver string
DbHost string
DbUser string
DbPassword string
DbName string
}
func InitDBWithParameters(params DbInfo) {
dbInfo := ""
switch params.DbDriver {
default:
dbInfo = fmt.Sprintf(params.DbHost)
case "postgres":
dbInfo = fmt.Sprintf("host=%s user=%s dbname=%s sslmode=disable password=%s", params.DbHost, params.DbUser, params.DbName, params.DbPassword)
case "mysql":
dbInfo = fmt.Sprintf("%s:%s@%s/%s?charset=utf8&parseTime=True&loc=Local", params.DbUser, params.DbPassword, params.DbHost, params.DbName)
}
OpenDB(params.DbDriver, dbInfo)
}
func InitDB() {
params := DbInfo{}
params.DbDriver = revel.Config.StringDefault("db.driver", "sqlite3")
params.DbHost = revel.Config.StringDefault("db.host", "localhost")
if params.DbDriver == "sqlite3" && params.DbHost == "localhost" {
params.DbHost = "/tmp/app.db"
}
params.DbUser = revel.Config.StringDefault("db.user", "default")
params.DbPassword = revel.Config.StringDefault("db.password", "")
params.DbName = revel.Config.StringDefault("db.name", "default")
InitDBWithParameters(params)
}

3
vendor/github.com/revel/modules/orm/gorm/gorm.go generated vendored Normal file
View File

@@ -0,0 +1,3 @@
package gorm
// Required for vendoring see golang.org/issue/13832

264
vendor/github.com/revel/modules/orm/gorp/app/README.md generated vendored Normal file
View File

@@ -0,0 +1,264 @@
modules/gorp
===============
This composite orm module combines Gorp with Squirrel to give you a complete solution
* [Gorp](https://github.com/go-gorp/gorp) *saves you time, minimizes the drudgery of
getting data in and out of your database, and helps your code focus on algorithms,
not infrastructure*.
* [Squirrel](https://github.com/Masterminds/squirrel) *helps you build SQL queries from
composable parts*
## Activation
```ini
module.gorp = github.com/revel/modules/orm/gorp
```
## Drivers
* sqlite3
* postgres
* mysql
## Configuration file
```ini
# Database config
db.autoinit=true # default=true
db.driver=postgres # mysql, postgres, sqlite3
# The database connection properties individually or use the db.connection
db.host=localhost # Use db.host /tmp/app.db is your driver is sqlite
db.user=dbuser
db.name=dbname
db.password=dbpassword
# Database connection string (host, user, dbname and other params)
db.connection=localhost port=8500 user=user dbname=mydb sslmode=disable password=ack
# If true then the database will be initialized on startup.
db.autoinit=true
```
## Decelerations
A global `Db *DbGorp` object is created in `github.com/revel/modules/gorp/app`.
The `Db` is initialized from the app.conf if `db.autoinit=true`.
```go
// DB Gorp
type DbGorp struct {
Gorp *gorp.DbMap
// The Sql statement builder to use to build select statements
SqlStatementBuilder sq.StatementBuilderType
}
var (
// The database map to use to populate data
Db = &DbGorp{}
)
```
## Usage
If `db.autoinit=true` in app.conf then you can add your tables to Gorp on app start.
Note that the tables are added as a function using `gorp.Db.SetDbInit` - this is for database thread pooling
```go
import (
"github.com/revel/revel"
"github.com/revel/modules/gorp/app"
)
func init() {
revel.OnAppStart(func(){
// Register tables
gorp.Db.SetDbInit(func(dbGorp *gorp.DbGorp) error {
// Register tables
gorp.Db.Map.AddTableWithName(model.MyTable{}, "my_table")
return nil
})
},5)
}
```
### Controller
Controllers, with the `gorpController.Controller` embedded,
have a gorp.DbGorp populated in the `Controller.Db`. This database is
the global one that is created on startup
```go
package controllers
import (
"github.com/revel/revel"
"github.com/revel/modules/orm/gorp/app/controllers"
)
type App struct {
gorpController.Controller
}
type TableRow struct {
Id int `db:"id,int64"`
}
func (c App) Index() revel.Result {
sql,args,_ := c.Db.SqlStatementBuilder.Select("*").From("table").Limit(1).ToSql()
row := &TableRow{}
if err:= c.Db.Map.SelectOne(row,sql,args...); err!=nil {
c.RenderError(err)
}
return c.Render(row)
}
```
### Multiple databases
The gorp module can populate a `DbGorp` object for you from a `gorp.DbInfo` object. So if you don't want
to use the global database (in the gorp module) you can initialize another anywhere in your project.
```go
import (
"github.com/revel/revel"
"github.com/revel/modules/orm/gorp/app"
)
var (
SecondDb = &gorp.DbGorp{}
)
func init() {
revel.OnAppStart(func(){
// Create a DbInfo object with a minimum of a driver and other details
params := gorp.DbInfo{Driver:"postgres",DbUser:revel.Config.StringDefault("seconddb.user", "default")}
secondDb.Info = params
if err:=secondDb.InitDb(true); err!=nil {
revel.Panicf("Second database failed to open %s", err.Error())
}
},0)
}
```
### Multi Channel Connections
This is not connection pooling - this is for distributing work across multiple channels to get a
lot of stuff done fast. It creates a bunch workers and each worker has
its own connection (On the start of the worker a status is sent in case you want to do some prework).
Tasks are sent through the `DbWorkContainer.InputChannel` which distributes the
task to whatever worker is available.
If you are using any tables that requires GORP to have initialized tables you
must register the tables using `gorp.Db.SetDbInit`. This is the only way that this service
can properly initialize the newly thread created GORP instances. Here is an example.
```go
import (
"github.com/revel/revel"
"github.com/revel/modules/gorp/app"
)
func init() {
revel.OnAppStart(func(){
// Register tables
gorp.Db.SetDbInit(func(dbGorp *gorp.DbGorp) error {
// Register tables
gorp.Db.Map.AddTableWithName(model.MyTable{}, "my_table")
return nil
})
},5)
}
```
In order to achieve this there is a `gorp.DbWorkerContainer` which is initialized by
`NewDbWorker(db *DbGorp, callBack DbCallback, numWorkers int) (container *DbWorkerContainer, err error)`
The `DbCallback` can be initialized by
`gorp.MakeCallback(status func(phase WorkerPhase, worker *DbWorker), work func(value interface{}, worker *DbWorker)) DbCallback`
()the status function is optional) or implemented by your structure
Once the `gorp.DbWorkerContainer` is created tasks can be submitted to it by using the
`gorp.DbWorkerContainer.InputChannel<-task` this will call the `gorp.DbCallback.Work` function
passing in an instance of *DbWorker
```go
// Assume sourceDb is a *gorp.DbGorp instance
workerPool := gorp.NewDbWorker(d.Db, gorp.MakeCallback(func(phase gorp.WorkerPhase, worker *gorp.DbWorker) {
// On start initialize some data to be used later
if phase == gorp.Start {
dataList, err := model.FetchData(worker.Db)
worker.SharedData["dataList"] = dataList
} else if phase == gorp.JobLongrunning {
revel.AppLog.Error("Long running process detected", "worker", worker.Id)
}
}, func(work interface{}, worker *gorp.DbWorker) {
dataList := worker.SharedData["dataList"].(model.DataList)
// Whatever is sent into the workerPool.InputChannel<- will be the value
value := work.(*SomeObject)
}), 100)
// Set the timeout for watchdog notifications
workerPool.LongWorkTimeout=300
err := workerPool.Start() // Start a 100 worker threads
if err!=nil {
return err
}
defer workerPool.Close(0) // Close, wait for channels to exit (non zero would exit after timeout)
// var tasks[] a large list of work to be done
tasksBlock := make([]*SomeObject,100)
for i,task := range tasks {
if i>0 && i%100==0 {
workerPool.InputChannel<-taskBlock
tasksBlock = make([]*SomeObject)
}
taskBlock = append(taskBlock, task)
}
workerPool.InputChannel<-taskBlock
// Pool is closed on defer function, it will not return till pool closes
return nil
```
#### Implementation notes
If your "work" is short but there is a lot of it then it is highly recommended you pass in lists of
items to work on. Channels are great at providing an easy way
to move data to and from threads but it is a process of synchronizing between two threads. If you pass
in a single object at a time you pay that cost on every row you pass. If you do it once every 10,000
rows then the cost is minimal.
#### WorkParallel function
There is a handy function called
`WorkParallel(db *DbGorp, tasks []func(worker *DbWorker), returnResults bool, maxNumWorkers int, timeouts int) (err error)`
which makes it simple to do create a group of calls
```go
// Assume sourceDb is a *gorp.DbGorp instance
task := func(query string) func(db *gorp.DbWorker) {
return func(worker *gorp.DbWorker) {
_, e := worker.Db.Map.Exec("ANALYZE " + query)
}
}
gorp.WorkParallel(sourceDb, []func(worker *gorp.DbWorker){
task("history"),
task("summary"),
task("daily"),
task("monthly"),
}, false, 0, 0)
```
#### Returning data from workers
`gorp.DbWorker` contains an OutputChannel which you can send the results back to, you must read
from the output the same number of times that you wrote. The output size is the same size as the
```go
// Assume sourceDb is a *gorp.DbGorp instance
task := func(query string) func(db *gorp.DbWorker) {
return func(worker *gorp.DbWorker) {
result, err := worker.Db.Map.Exec("ANALYZE " + query)
worker.OutputChannel <- []interface{}{result,err}
}
}
r,e:=gorp.WorkParallel(sourceDb, []func(worker *gorp.DbWorker){
task("history"),
task("daily"),
task("monthly"),
},true, 0, 0)
println(r, e)
for _,result := range r {
key,err:= result.([]interface{})[0],result.([]interface{})[1]
fmt.Println("Returned result",key,"error",err)
}
```
#### Watchdog Timeouts
`gorp.DbWorkerContainer` contains a couple of timeout settings (in seconds) used to monitor
the startup and running of the workers for the duration of the container
(this is typically called a watchdog timeout).
- `StartWorkTimeout` If greater then 0 this is the timeout in seconds that it takes to start a worker.
- `LongWorkTimeout` If greater then 0 this is the timeout in seconds that it takes before a
notification is sent to the `DbCallbackImplied.StatusFn func(phase WorkerPhase, worker *DbWorker)`
if a worker runs past X seconds on a single task.
Each worker will have their own watchdog channel and it will send a `gorp.JobLongrunning` and
the `gorp.DBWorker` to the status function so you can log or investigate long running processes

View File

@@ -0,0 +1,69 @@
package gorpController
import (
"database/sql"
"github.com/revel/modules/orm/gorp/app"
"github.com/revel/revel"
)
// Controller definition for database transaction
// This controller is only useful if you intend to use the database instance
// defined in github.com/revel/modules/orm/gorp/app.Db
type Controller struct {
*revel.Controller
Txn *gorp.Transaction
Db *gorp.DbGorp
}
// Begin a transaction
func (c *Controller) Begin() revel.Result {
c.Db = gorp.Db
txn, err := gorp.Db.Begin()
if err != nil {
panic(err)
}
c.Txn = txn
return nil
}
// Rollback if it's still going (must have panicked).
func (c *Controller) Rollback() revel.Result {
if c.Txn != nil {
if err := c.Txn.Rollback(); err != nil {
if err != sql.ErrTxDone {
panic(err)
}
}
c.Txn = nil
}
return nil
}
// Commit the transaction.
func (c *Controller) Commit() revel.Result {
if c.Txn != nil {
if err := c.Txn.Commit(); err != nil {
if err != sql.ErrTxDone {
panic(err)
}
}
c.Txn = nil
}
return nil
}
func init() {
// Run this as soon as possible
revel.OnAppStart(func() {
if revel.Config.BoolDefault("db.autoinit", false) {
if err := gorp.InitDb(gorp.Db); err != nil {
// Force a failure
revel.RevelLog.Panicf("gorp:Unable to initialize database")
}
revel.InterceptMethod((*Controller).Begin, revel.BEFORE)
revel.InterceptMethod((*Controller).Commit, revel.AFTER)
revel.InterceptMethod((*Controller).Rollback, revel.FINALLY)
}
}, 0,
)
}

168
vendor/github.com/revel/modules/orm/gorp/app/dbgorp.go generated vendored Normal file
View File

@@ -0,0 +1,168 @@
package gorp
import (
"database/sql"
sq "gopkg.in/Masterminds/squirrel.v1"
"gopkg.in/gorp.v2"
"github.com/revel/revel/logger"
)
// DB Gorp
type DbGorp struct {
Map *gorp.DbMap
// The Sql statement builder to use to build select statements
SqlStatementBuilder sq.StatementBuilderType
// Database connection information
Info *DbInfo
// The database initialization function
dbInitFn func(dbMap *DbGorp) error
}
type DbInfo struct {
DbDriver string
DbHost string
DbUser string
DbPassword string
DbName string
DbConnection string
Dialect gorp.Dialect
}
// OpenDb database
func (dbGorp *DbGorp) OpenDb() (err error) {
db, err := sql.Open(dbGorp.Info.DbDriver, dbGorp.Info.DbConnection)
if err != nil {
moduleLogger.Fatal("Open Database Error", "error", err)
}
// Create the database map
dbGorp.Map = &gorp.DbMap{Db: db, Dialect: dbGorp.Info.Dialect}
return dbGorp.dbInit()
}
// Create a new database connection and open it from this one
func (dbGorp *DbGorp) CloneDb(open bool) (newDb *DbGorp, err error) {
dbInfo := *dbGorp.Info
newDb = &DbGorp{Info: &dbInfo}
newDb.dbInitFn = dbGorp.dbInitFn
err = newDb.InitDb(open)
return
}
// Close the database connection
func (dbGorp *DbGorp) Begin() (txn *Transaction, err error) {
tx,err := dbGorp.Map.Begin()
if err!=nil {
return
}
txn = &Transaction{tx}
return
}
// Close the database connection
func (dbGorp *DbGorp) Close() (err error) {
if dbGorp.Map.Db != nil {
err = dbGorp.Map.Db.Close()
}
return
}
// Called to perform table registration and anything else that needs to be done on a new connection
func (dbGorp *DbGorp) dbInit() (err error) {
if dbGorp.dbInitFn != nil {
err = dbGorp.dbInitFn(dbGorp)
}
return
}
// Used to specifiy the init function to call when database is initialized
// Calls the init function immediately
func (dbGorp *DbGorp) SetDbInit(dbInitFn func(dbMap *DbGorp) error) (err error) {
dbGorp.dbInitFn = dbInitFn
return dbGorp.dbInit()
}
func (dbGorp *DbGorp) Select(i interface{}, builder sq.SelectBuilder) (l []interface{}, err error) {
query, args, err := builder.ToSql()
if err == nil {
list, err := dbGorp.Map.Select(i, query, args...)
if err != nil && gorp.NonFatalError(err) {
return list, nil
}
if err==sql.ErrNoRows {
err = nil
}
return list, err
}
return
}
func (dbGorp *DbGorp) SelectOne(i interface{}, builder sq.SelectBuilder) (err error) {
query, args, err := builder.ToSql()
if err == nil {
err = dbGorp.Map.SelectOne(i, query, args...)
if err != nil && gorp.NonFatalError(err) {
return nil
}
}
return
}
func (dbGorp *DbGorp) SelectInt(builder sq.SelectBuilder) (i int64, err error) {
query, args, err := builder.ToSql()
if err == nil {
i, err = dbGorp.Map.SelectInt(query, args...)
}
return
}
func (dbGorp *DbGorp) ExecUpdate(builder sq.UpdateBuilder) (r sql.Result, err error) {
query, args, err := builder.ToSql()
if err == nil {
r, err = dbGorp.Map.Exec(query, args...)
}
return
}
func (dbGorp *DbGorp) ExecInsert(builder sq.InsertBuilder) (r sql.Result, err error) {
query, args, err := builder.ToSql()
if err == nil {
r, err = dbGorp.Map.Exec(query, args...)
}
return
}
//
// Shifted some common functions up a level
////
func (dbGorp *DbGorp) Insert(list ...interface{}) error {
return dbGorp.Map.Insert(list...)
}
func (dbGorp *DbGorp) Update(list ...interface{}) (int64, error) {
return dbGorp.Map.Update(list...)
}
func (dbGorp *DbGorp) Get(i interface{}, keys ...interface{}) (interface{}, error) {
return dbGorp.Map.Get(i,keys...)
}
func (dbGorp *DbGorp) Delete(i ...interface{}) (int64, error) {
return dbGorp.Map.Delete(i...)
}
func (dbGorp *DbGorp) TraceOn(log logger.MultiLogger) {
dbGorp.Map.TraceOn("",&simpleTrace{log.New("section","gorp")})
}
func (dbGorp *DbGorp) TraceOff() {
}
type simpleTrace struct {
log logger.MultiLogger
}
func (s *simpleTrace) Printf(format string, v ...interface{}) {
s.log.Infof(format,v...)
}

View File

@@ -0,0 +1,70 @@
package gorp
import (
"fmt"
_ "github.com/jinzhu/gorm/dialects/mysql" // mysql package
_ "github.com/jinzhu/gorm/dialects/postgres" // postgres package
_ "github.com/jinzhu/gorm/dialects/sqlite" // mysql package
"github.com/revel/revel"
sq "gopkg.in/Masterminds/squirrel.v1"
"gopkg.in/gorp.v2"
"github.com/revel/revel/logger"
)
var (
// The database map to use to populate data
Db = &DbGorp{}
moduleLogger logger.MultiLogger
)
func init() {
revel.RegisterModuleInit(func(module *revel.Module){
moduleLogger = module.Log
moduleLogger.Debug("Assigned Logger")
})
}
func (dbResult *DbGorp)InitDb(open bool) (err error) {
dbInfo := dbResult.Info
switch dbInfo.DbDriver {
default:
dbResult.SqlStatementBuilder = sq.StatementBuilder.PlaceholderFormat(sq.Question)
dbInfo.Dialect = gorp.SqliteDialect{}
if len(dbInfo.DbConnection) == 0 {
dbInfo.DbConnection = fmt.Sprintf(dbInfo.DbHost)
}
case "postgres":
dbResult.SqlStatementBuilder = sq.StatementBuilder.PlaceholderFormat(sq.Dollar)
dbInfo.Dialect = gorp.PostgresDialect{}
if len(dbInfo.DbConnection) == 0 {
dbInfo.DbConnection = fmt.Sprintf("host=%s port=8500 user=%s dbname=%s sslmode=disable password=%s", dbInfo.DbHost, dbInfo.DbUser, dbInfo.DbName, dbInfo.DbPassword)
}
case "mysql":
dbResult.SqlStatementBuilder = sq.StatementBuilder.PlaceholderFormat(sq.Question)
dbInfo.Dialect = gorp.MySQLDialect{}
if len(dbInfo.DbConnection) == 0 {
dbInfo.DbConnection = fmt.Sprintf("%s:%s@%s/%s?charset=utf8&parseTime=True&loc=Local", dbInfo.DbUser, dbInfo.DbPassword, dbInfo.DbHost, dbInfo.DbName)
}
}
if open {
err = dbResult.OpenDb()
}
return
}
// Initialize the database from revel.Config
func InitDb(dbResult *DbGorp) (error) {
params := DbInfo{}
params.DbDriver = revel.Config.StringDefault("db.driver", "sqlite3")
params.DbHost = revel.Config.StringDefault("db.host", "localhost")
if params.DbDriver == "sqlite3" && params.DbHost == "localhost" {
params.DbHost = "/tmp/app.db"
}
params.DbUser = revel.Config.StringDefault("db.user", "default")
params.DbPassword = revel.Config.StringDefault("db.password", "")
params.DbName = revel.Config.StringDefault("db.name", "default")
params.DbConnection = revel.Config.StringDefault("db.connection", "")
dbResult.Info = &params
return dbResult.InitDb(true)
}

View File

@@ -0,0 +1,82 @@
package gorp
import (
gorpa "gopkg.in/gorp.v2"
"database/sql"
sq "gopkg.in/Masterminds/squirrel.v1"
)
type (
// This is a small wrapped around gorp.Transaction so you can make use of the builder statements as well
Transaction struct {
Map *gorpa.Transaction
}
)
func (txn *Transaction) Rollback() (err error) {
return txn.Map.Rollback()
}
func (txn *Transaction) Commit() (err error) {
return txn.Map.Commit()
}
func (txn *Transaction) Select(i interface{}, builder sq.SelectBuilder) (l []interface{}, err error) {
query, args, err := builder.ToSql()
if err == nil {
list, err := txn.Map.Select(i, query, args...)
if err != nil && gorpa.NonFatalError(err) {
return list, nil
}
if err==sql.ErrNoRows {
err = nil
}
return list, err
}
return
}
func (txn *Transaction) SelectOne(i interface{}, builder sq.SelectBuilder) (err error) {
query, args, err := builder.ToSql()
if err == nil {
err = txn.Map.SelectOne(i, query, args...)
if err != nil && gorpa.NonFatalError(err) {
return nil
}
}
return
}
func (txn *Transaction) SelectInt(builder sq.SelectBuilder) (i int64, err error) {
query, args, err := builder.ToSql()
if err == nil {
i, err = txn.Map.SelectInt(query, args...)
}
return
}
func (txn *Transaction) ExecUpdate(builder sq.UpdateBuilder) (r sql.Result, err error) {
query, args, err := builder.ToSql()
if err == nil {
r, err = txn.Map.Exec(query, args...)
}
return
}
func (txn *Transaction) ExecInsert(builder sq.InsertBuilder) (r sql.Result, err error) {
query, args, err := builder.ToSql()
if err == nil {
r, err = txn.Map.Exec(query, args...)
}
return
}
// Shifted some common functions up a level
func (txn *Transaction) Insert(list ...interface{}) error {
return txn.Map.Insert(list...)
}
func (txn *Transaction) Update(list ...interface{}) (int64, error) {
return txn.Map.Update(list...)
}
func (txn *Transaction) Get(i interface{}, keys ...interface{}) (interface{}, error) {
return txn.Map.Get(i,keys...)
}
func (txn *Transaction) Delete(i ...interface{}) (int64, error) {
return txn.Map.Delete(i...)
}

268
vendor/github.com/revel/modules/orm/gorp/app/workers.go generated vendored Normal file
View File

@@ -0,0 +1,268 @@
package gorp
import (
"fmt"
"runtime"
"sync"
"time"
)
// The worker container
type DbWorkerContainer struct {
SharedWorker
mutex sync.Mutex
Workers []*DbWorker
NumWorkers int
LongWorkTimeout int64
StartWorkTimeout int64
Db *DbGorp
}
// The timeoutInfo for monitoring long running processes
type timeoutInfo struct {
worker *DbWorker
started time.Time
ended time.Time
state WorkerPhase
}
type DbWorker struct {
Id int
Db *DbGorp
SharedWorker
WorkUnit int
SharedData map[string]interface{}
TimeInfo *timeoutInfo
TimeoutChannel chan *timeoutInfo
}
type SharedWorker struct {
workInfo DbWorkInfo
InputChannel chan interface{}
OutputChannel chan interface{}
ControlChannel chan func() (WorkerPhase, *DbWorker)
}
type DbWorkInfo interface {
Status(phase WorkerPhase, worker *DbWorker)
Work(value interface{}, worker *DbWorker)
}
type DbCallbackImplied struct {
StatusFn func(phase WorkerPhase, worker *DbWorker)
WorkFn func(value interface{}, worker *DbWorker)
}
type WorkerPhase int
const (
Start WorkerPhase = iota
Stop
StartJob
EndJob
JobLongrunning
)
// Creates a container to run the group of workers (up to a max of maxNumWorkers), does not return to all workers are completed)
// If returnResults is true then the task MUST write to the DbWorker.OutputChannel once for every task
func WorkParallel(db *DbGorp, tasks []func(worker *DbWorker), returnResults bool, maxNumWorkers int, timeouts int) (results []interface{}, err error) {
if maxNumWorkers == 0 {
maxNumWorkers = len(tasks)
}
// Create a container with no status callback
container := NewDbWorker(db,
MakeCallback(nil,
func(value interface{}, worker *DbWorker) {
task := value.(func(worker *DbWorker))
task(worker)
}), maxNumWorkers)
err = container.Start()
if err != nil {
return
}
for _, task := range tasks {
container.InputChannel <- task
}
if returnResults {
for range tasks {
result := <-container.OutputChannel
results = append(results, result)
}
}
container.Close(timeouts)
return
}
// This creates a DbWorkerContainer with the number of working threads already started.
// Each working thread has their own database instance running.
func NewDbWorker(db *DbGorp, workInfo DbWorkInfo, numWorkers int) (container *DbWorkerContainer) {
container = &DbWorkerContainer{
SharedWorker: SharedWorker{
InputChannel: make(chan interface{}, numWorkers),
OutputChannel: make(chan interface{}, numWorkers),
ControlChannel: make(chan func() (WorkerPhase, *DbWorker), numWorkers),
workInfo: workInfo,
},
NumWorkers: numWorkers,
Db: db,
StartWorkTimeout: 0,
LongWorkTimeout: 0,
}
return
}
func (container *DbWorkerContainer) Start() (err error) {
for x := 0; x < container.NumWorkers; x++ {
go startWorker(container, container.Db, x)
}
// Make sure all containers are running before returning
for x := 0; x < container.NumWorkers; x++ {
if container.StartWorkTimeout > 0 {
select {
case result := <-container.ControlChannel:
state, source := result()
if state != Start {
container.Close(5)
err = fmt.Errorf("Failed to start workers %d", source)
return
}
case <-time.After(time.Second * time.Duration(container.StartWorkTimeout)):
container.Close(5)
err = fmt.Errorf("Failed to start worker timeout")
return
}
} else {
result := <-container.ControlChannel
state, source := result()
if state != Start {
container.Close(5)
err = fmt.Errorf("Failed to start workers %d", source)
return
}
}
}
return
}
func (container *DbWorkerContainer) Close(timeouts int) (totalWork int, err error) {
close(container.InputChannel)
for x := 0; x < len(container.Workers); x++ {
// Allow close to continue even if a worker does not respond
if timeouts > 0 {
select {
case result := <-container.ControlChannel:
_, worker := result()
totalWork += worker.WorkUnit
case <-time.After(time.Second * time.Duration(timeouts)):
}
} else {
_, worker := (<-container.ControlChannel)()
totalWork += worker.WorkUnit
}
}
close(container.OutputChannel)
return
}
// Called by using "go" to invoke, creates a DBWorker, and starts a watchdog channel
func startWorker(container *DbWorkerContainer, db *DbGorp, id int) {
newDb, _ := db.CloneDb(true)
worker := &DbWorker{
Db: newDb,
Id: id,
SharedData: map[string]interface{}{},
SharedWorker: SharedWorker{
workInfo: container.workInfo,
InputChannel: container.InputChannel,
OutputChannel: container.OutputChannel,
ControlChannel: container.ControlChannel,
},
}
// Close the database after worker has ended (Start returned
defer worker.Db.Close()
container.mutex.Lock()
container.Workers = append(container.Workers, worker)
container.mutex.Unlock()
// Only monitor jobs if Status function defined and a timeout is also defined
if worker.workInfo.Status != nil && container.LongWorkTimeout > 0 {
worker.TimeoutChannel = make(chan *timeoutInfo)
go worker.TimeInfo.start(worker.TimeoutChannel, container.LongWorkTimeout)
}
worker.start()
}
// Starts the worker, continues running until inputchannel is closed
func (worker *DbWorker) start() {
if worker.workInfo.Status != nil {
worker.workInfo.Status(Start, worker)
}
worker.ControlChannel <- func() (WorkerPhase, *DbWorker) { return Start, worker }
for job := range worker.InputChannel {
worker.invoke(job)
}
if worker.workInfo.Status != nil {
worker.workInfo.Status(Stop, worker)
}
worker.ControlChannel <- func() (WorkerPhase, *DbWorker) { return Stop, worker }
if worker.TimeoutChannel != nil {
close(worker.TimeoutChannel)
}
}
// Wrapper to prevent panics from disturbing the channel
func (worker *DbWorker) invoke(job interface{}) {
defer func() {
if err := recover(); err != nil {
trace := make([]byte, 1024)
count := runtime.Stack(trace, true)
moduleLogger.Error("Recover from panic: ", "error", err)
moduleLogger.Error("Stack", "size", count, "trace", string(trace))
}
}()
// Setup the timeout information
if worker.TimeoutChannel != nil {
worker.TimeInfo = &timeoutInfo{worker: worker, started: time.Now(), state: StartJob}
worker.TimeoutChannel <- worker.TimeInfo
}
worker.workInfo.Work(job, worker)
if worker.TimeoutChannel != nil {
worker.TimeInfo.state = EndJob
worker.TimeoutChannel <- worker.TimeInfo
}
}
// A function to return an object that is a valid DbCallback
func MakeCallback(status func(phase WorkerPhase, worker *DbWorker), work func(value interface{}, worker *DbWorker)) DbWorkInfo {
return &DbCallbackImplied{StatusFn: status, WorkFn: work}
}
// Call the status function if available
func (dbCallback *DbCallbackImplied) Status(phase WorkerPhase, worker *DbWorker) {
if dbCallback.StatusFn != nil {
dbCallback.StatusFn(phase, worker)
}
}
// Calls the work function
func (dbCallback *DbCallbackImplied) Work(value interface{}, worker *DbWorker) {
dbCallback.WorkFn(value, worker)
}
//Starts the timeout worker
func (_ *timeoutInfo) start(TimeoutChannel chan *timeoutInfo, timeout int64) {
for j := range TimeoutChannel {
j.started = time.Now()
j.state = StartJob
j.worker.workInfo.Status(j.state, j.worker)
for {
select {
case complete, ok := <-TimeoutChannel:
if !ok {
// Channel closed returning...
return
}
// Received new State, record and loop
complete.worker.workInfo.Status(complete.state, complete.worker)
break
case <-time.After(time.Second * time.Duration(timeout)):
j.worker.workInfo.Status(JobLongrunning, j.worker)
}
}
}
}

3
vendor/github.com/revel/modules/orm/gorp/gorp.go generated vendored Normal file
View File

@@ -0,0 +1,3 @@
package gorp
// Required for vendoring see golang.org/issue/13832