├── .gitignore ├── LICENSE ├── README.md ├── main.go ├── post ├── create.go ├── model.go ├── publish │ └── handler.go └── tag.go ├── postgres └── pq.go ├── schema.sql ├── tag ├── create.go └── model.go ├── user ├── create.go ├── find.go ├── login │ └── handler.go ├── model.go └── signup │ └── handler.go └── vendor ├── github.com ├── jinzhu │ ├── gorm │ │ ├── License │ │ ├── README.md │ │ ├── association.go │ │ ├── callback.go │ │ ├── callback_create.go │ │ ├── callback_delete.go │ │ ├── callback_query.go │ │ ├── callback_query_preload.go │ │ ├── callback_row_query.go │ │ ├── callback_save.go │ │ ├── callback_update.go │ │ ├── dialect.go │ │ ├── dialect_common.go │ │ ├── dialect_mysql.go │ │ ├── dialect_postgres.go │ │ ├── dialect_sqlite3.go │ │ ├── dialects │ │ │ └── postgres │ │ │ │ └── postgres.go │ │ ├── errors.go │ │ ├── field.go │ │ ├── interface.go │ │ ├── join_table_handler.go │ │ ├── logger.go │ │ ├── main.go │ │ ├── model.go │ │ ├── model_struct.go │ │ ├── scope.go │ │ ├── search.go │ │ ├── test_all.sh │ │ ├── utils.go │ │ └── wercker.yml │ └── inflection │ │ ├── LICENSE │ │ ├── README.md │ │ └── inflections.go └── lib │ └── pq │ ├── CONTRIBUTING.md │ ├── LICENSE.md │ ├── README.md │ ├── array.go │ ├── buf.go │ ├── conn.go │ ├── conn_go18.go │ ├── copy.go │ ├── doc.go │ ├── encode.go │ ├── error.go │ ├── hstore │ └── hstore.go │ ├── notify.go │ ├── oid │ ├── doc.go │ └── types.go │ ├── ssl.go │ ├── ssl_go1.7.go │ ├── ssl_permissions.go │ ├── ssl_renegotiation.go │ ├── ssl_windows.go │ ├── url.go │ ├── user_posix.go │ ├── user_windows.go │ └── uuid.go ├── golang.org └── x │ └── crypto │ ├── LICENSE │ ├── PATENTS │ ├── bcrypt │ ├── base64.go │ └── bcrypt.go │ └── blowfish │ ├── block.go │ ├── cipher.go │ └── const.go └── vendor.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.dll 4 | *.so 5 | *.dylib 6 | 7 | # Test binary, build with `go test -c` 8 | *.test 9 | 10 | # Output of the go coverage tool, specifically when used with LiteIDE 11 | *.out 12 | 13 | # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 14 | .glide/ 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Tamizhvendan S 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gomidway 2 | A sample blogging platform in golang 3 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/jinzhu/gorm" 7 | _ "github.com/jinzhu/gorm/dialects/postgres" 8 | "github.com/tamizhvendan/gomidway/post" 9 | "github.com/tamizhvendan/gomidway/post/publish" 10 | "github.com/tamizhvendan/gomidway/user" 11 | "github.com/tamizhvendan/gomidway/user/login" 12 | "github.com/tamizhvendan/gomidway/user/signup" 13 | ) 14 | 15 | func panicOnError(err error) { 16 | if err != nil { 17 | panic(err) 18 | } 19 | } 20 | 21 | func main() { 22 | db, err := gorm.Open("postgres", 23 | `host=localhost 24 | user=postgres password=test 25 | dbname=gomidway 26 | sslmode=disable`) 27 | panicOnError(err) 28 | defer db.Close() 29 | 30 | signupUser(db) 31 | loginUser(db) 32 | publishPost(db) 33 | } 34 | 35 | func signupUser(db *gorm.DB) { 36 | res, err := signup.Signup(db, &signup.Request{ 37 | Email: "foo@bar.com", 38 | Username: "foo", 39 | Password: "foobar", 40 | }) 41 | if err != nil { 42 | switch err.(type) { 43 | case *user.UsernameDuplicateError: 44 | fmt.Println("Bad Request: ", err.Error()) 45 | return 46 | case *user.EmailDuplicateError: 47 | fmt.Println("Bad Request: ", err.Error()) 48 | return 49 | default: 50 | fmt.Println("Internal Server Error: ", err.Error()) 51 | return 52 | } 53 | } 54 | fmt.Println("Created: ", res.Id) 55 | } 56 | 57 | func loginUser(db *gorm.DB) { 58 | res, err := login.Login(db, &login.Request{Email: "foo@bar.com", Password: "foobar"}) 59 | if err != nil { 60 | switch err.(type) { 61 | case *user.EmailNotExistsError: 62 | fmt.Println("Bad Request: ", err.Error()) 63 | return 64 | case *login.PasswordMismatchError: 65 | fmt.Println("Bad Request: ", err.Error()) 66 | return 67 | default: 68 | fmt.Println("Internal Server Error: ", err.Error()) 69 | return 70 | } 71 | } 72 | fmt.Printf("Ok: User '%s' logged in\n", res.User.Username) 73 | } 74 | 75 | func publishPost(db *gorm.DB) { 76 | res, err := publish.NewPost(db, &publish.Request{ 77 | AuthorID: 1, 78 | Body: "Golang rocks!", 79 | Title: "My first gomidway post", 80 | Tags: []string{"intro", "golang"}, 81 | }) 82 | if err != nil { 83 | if _, ok := err.(*post.TitleDuplicateError); ok { 84 | fmt.Println("Bad Request: ", err.Error()) 85 | return 86 | } 87 | fmt.Println("Internal Server Error: ", err.Error()) 88 | return 89 | } 90 | fmt.Println("Created: ", res.PostId) 91 | } 92 | -------------------------------------------------------------------------------- /post/create.go: -------------------------------------------------------------------------------- 1 | package post 2 | 3 | import ( 4 | "github.com/jinzhu/gorm" 5 | "github.com/tamizhvendan/gomidway/postgres" 6 | ) 7 | 8 | func Create(db *gorm.DB, post *Post) (uint, error) { 9 | res := db.Create(post) 10 | if res.Error != nil { 11 | if postgres.IsUniqueConstraintError(res.Error, UniqueConstraintTitle) { 12 | return 0, &TitleDuplicateError{} 13 | } 14 | return 0, res.Error 15 | } 16 | return post.ID, nil 17 | } 18 | -------------------------------------------------------------------------------- /post/model.go: -------------------------------------------------------------------------------- 1 | package post 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/tamizhvendan/gomidway/tag" 7 | ) 8 | 9 | const ( 10 | UniqueConstraintTitle = "posts_title_key" 11 | AssociationTags = "Tags" 12 | ) 13 | 14 | type Post struct { 15 | ID uint 16 | Title string 17 | Body string 18 | AuthorID uint 19 | Tags []tag.Tag `gorm:"many2many:posts_tags;"` 20 | PublishedAt time.Time 21 | } 22 | 23 | type TitleDuplicateError struct{} 24 | 25 | func (e *TitleDuplicateError) Error() string { 26 | return "title already exists" 27 | } 28 | -------------------------------------------------------------------------------- /post/publish/handler.go: -------------------------------------------------------------------------------- 1 | package publish 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/jinzhu/gorm" 7 | "github.com/tamizhvendan/gomidway/post" 8 | "github.com/tamizhvendan/gomidway/tag" 9 | ) 10 | 11 | type Request struct { 12 | Title string 13 | Body string 14 | AuthorID uint 15 | Tags []string 16 | } 17 | 18 | type Response struct { 19 | PostId uint 20 | } 21 | 22 | func NewPost(db *gorm.DB, req *Request) (*Response, error) { 23 | tx := db.Begin() 24 | if tx.Error != nil { 25 | return nil, tx.Error 26 | } 27 | newPost := &post.Post{ 28 | AuthorID: req.AuthorID, 29 | Title: req.Title, 30 | Body: req.Body, 31 | PublishedAt: time.Now().UTC(), 32 | } 33 | _, err := post.Create(tx, newPost) 34 | if err != nil { 35 | return nil, err 36 | } 37 | for _, tagName := range req.Tags { 38 | t, err := tag.CreateIfNotExists(tx, tagName) 39 | if err != nil { 40 | tx.Rollback() 41 | return nil, err 42 | } 43 | err = post.AddTag(tx, newPost, t) 44 | if err != nil { 45 | tx.Rollback() 46 | return nil, err 47 | } 48 | } 49 | res := tx.Commit() 50 | if res.Error != nil { 51 | return nil, res.Error 52 | } 53 | return &Response{PostId: newPost.ID}, nil 54 | } 55 | -------------------------------------------------------------------------------- /post/tag.go: -------------------------------------------------------------------------------- 1 | package post 2 | 3 | import ( 4 | "github.com/jinzhu/gorm" 5 | "github.com/tamizhvendan/gomidway/tag" 6 | ) 7 | 8 | func AddTag(db *gorm.DB, post *Post, tag *tag.Tag) error { 9 | res := db.Model(post).Association(AssociationTags).Append(tag) 10 | return res.Error 11 | } 12 | -------------------------------------------------------------------------------- /postgres/pq.go: -------------------------------------------------------------------------------- 1 | package postgres 2 | 3 | import "github.com/lib/pq" 4 | 5 | func IsUniqueConstraintError(err error, constraintName string) bool { 6 | if pqErr, ok := err.(*pq.Error); ok { 7 | return pqErr.Code == "23505" && pqErr.Constraint == constraintName 8 | } 9 | return false 10 | } 11 | -------------------------------------------------------------------------------- /schema.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE users( 2 | id SERIAL PRIMARY KEY, 3 | username VARCHAR(50) UNIQUE NOT NULL, 4 | email VARCHAR(255) UNIQUE NOT NULL, 5 | password_hash TEXT NOT NULL 6 | ); 7 | 8 | CREATE TABLE posts( 9 | id SERIAL PRIMARY KEY, 10 | title VARCHAR(50) UNIQUE NOT NULL, 11 | body TEXT NOT NULL, 12 | published_at TIMESTAMP NOT NULL, 13 | author_id INTEGER NOT NULL REFERENCES users(id) 14 | ); 15 | 16 | CREATE TABLE tags( 17 | id SERIAL PRIMARY KEY, 18 | name VARCHAR(50) NOT NULL 19 | ); 20 | 21 | CREATE TABLE posts_tags( 22 | tag_id INTEGER REFERENCES tags(id), 23 | post_id INTEGER REFERENCES posts(id) 24 | ); -------------------------------------------------------------------------------- /tag/create.go: -------------------------------------------------------------------------------- 1 | package tag 2 | 3 | import "github.com/jinzhu/gorm" 4 | 5 | func CreateIfNotExists(db *gorm.DB, tagName string) (*Tag, error) { 6 | var tag Tag 7 | res := db.FirstOrCreate(&tag, Tag{Name: tagName}) 8 | if res.Error != nil { 9 | return nil, res.Error 10 | } 11 | return &tag, nil 12 | } 13 | -------------------------------------------------------------------------------- /tag/model.go: -------------------------------------------------------------------------------- 1 | package tag 2 | 3 | type Tag struct { 4 | ID uint 5 | Name string 6 | } 7 | -------------------------------------------------------------------------------- /user/create.go: -------------------------------------------------------------------------------- 1 | package user 2 | 3 | import ( 4 | "github.com/jinzhu/gorm" 5 | "github.com/tamizhvendan/gomidway/postgres" 6 | ) 7 | 8 | func Create(db *gorm.DB, user *User) (uint, error) { 9 | err := db.Create(user).Error 10 | if err != nil { 11 | if postgres.IsUniqueConstraintError(err, UniqueConstraintUsername) { 12 | return 0, &UsernameDuplicateError{Username: user.Username} 13 | } 14 | if postgres.IsUniqueConstraintError(err, UniqueConstraintEmail) { 15 | return 0, &EmailDuplicateError{Email: user.Email} 16 | } 17 | return 0, err 18 | } 19 | return user.ID, nil 20 | } 21 | -------------------------------------------------------------------------------- /user/find.go: -------------------------------------------------------------------------------- 1 | package user 2 | 3 | import "github.com/jinzhu/gorm" 4 | 5 | type EmailNotExistsError struct{} 6 | 7 | func (*EmailNotExistsError) Error() string { 8 | return "email not exists" 9 | } 10 | 11 | func FindByEmail(db *gorm.DB, email string) (*User, error) { 12 | var user User 13 | res := db.Find(&user, &User{Email: email}) 14 | if res.RecordNotFound() { 15 | return nil, &EmailNotExistsError{} 16 | } 17 | return &user, nil 18 | } 19 | -------------------------------------------------------------------------------- /user/login/handler.go: -------------------------------------------------------------------------------- 1 | package login 2 | 3 | import ( 4 | "github.com/jinzhu/gorm" 5 | "github.com/tamizhvendan/gomidway/user" 6 | "golang.org/x/crypto/bcrypt" 7 | ) 8 | 9 | type Request struct { 10 | Email string 11 | Password string 12 | } 13 | 14 | type Response struct { 15 | User *user.User 16 | } 17 | 18 | type PasswordMismatchError struct{} 19 | 20 | func (e *PasswordMismatchError) Error() string { 21 | return "password didn't match" 22 | } 23 | 24 | func Login(db *gorm.DB, req *Request) (*Response, error) { 25 | user, err := user.FindByEmail(db, req.Email) 26 | if err != nil { 27 | return nil, err 28 | } 29 | err = bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(req.Password)) 30 | if err != nil { 31 | return nil, &PasswordMismatchError{} 32 | } 33 | return &Response{User: user}, nil 34 | } 35 | -------------------------------------------------------------------------------- /user/model.go: -------------------------------------------------------------------------------- 1 | package user 2 | 3 | import "fmt" 4 | 5 | const ( 6 | UniqueConstraintUsername = "users_username_key" 7 | UniqueConstraintEmail = "users_email_key" 8 | ) 9 | 10 | type User struct { 11 | ID uint `gorm:"primary_key"` 12 | Username string 13 | Email string 14 | PasswordHash string 15 | } 16 | 17 | type UsernameDuplicateError struct { 18 | Username string 19 | } 20 | 21 | func (e *UsernameDuplicateError) Error() string { 22 | return fmt.Sprintf("Username '%s' already exists", e.Username) 23 | } 24 | 25 | type EmailDuplicateError struct { 26 | Email string 27 | } 28 | 29 | func (e *EmailDuplicateError) Error() string { 30 | return fmt.Sprintf("Email '%s' already exists", e.Email) 31 | } 32 | 33 | /* 34 | gomidway=# \d users 35 | Table "public.users" 36 | Column | Type | Modifiers 37 | ---------------+------------------------+---------------------------------------------------- 38 | id | integer | not null default nextval('users_id_seq'::regclass) 39 | username | character varying(50) | not null 40 | email | character varying(255) | not null 41 | password_hash | text | not null 42 | Indexes: 43 | "users_pkey" PRIMARY KEY, btree (id) 44 | "users_email_key" UNIQUE CONSTRAINT, btree (email) 45 | "users_username_key" UNIQUE CONSTRAINT, btree (username) 46 | */ 47 | -------------------------------------------------------------------------------- /user/signup/handler.go: -------------------------------------------------------------------------------- 1 | package signup 2 | 3 | import ( 4 | "github.com/jinzhu/gorm" 5 | "github.com/tamizhvendan/gomidway/user" 6 | "golang.org/x/crypto/bcrypt" 7 | ) 8 | 9 | type Request struct { 10 | Username string 11 | Email string 12 | Password string 13 | } 14 | 15 | type Response struct { 16 | Id uint 17 | } 18 | 19 | func Signup(db *gorm.DB, req *Request) (*Response, error) { 20 | passwordHash, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost) 21 | if err != nil { 22 | return nil, err 23 | } 24 | newUser := &user.User{ 25 | Username: req.Username, 26 | Email: req.Email, 27 | PasswordHash: string(passwordHash), 28 | } 29 | 30 | id, err := user.Create(db, newUser) 31 | if err != nil { 32 | return nil, err 33 | } 34 | return &Response{Id: id}, err 35 | } 36 | -------------------------------------------------------------------------------- /vendor/github.com/jinzhu/gorm/License: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013-NOW Jinzhu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /vendor/github.com/jinzhu/gorm/README.md: -------------------------------------------------------------------------------- 1 | # GORM 2 | 3 | The fantastic ORM library for Golang, aims to be developer friendly. 4 | 5 | [![Join the chat at https://gitter.im/jinzhu/gorm](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/jinzhu/gorm?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 6 | [![wercker status](https://app.wercker.com/status/0cb7bb1039e21b74f8274941428e0921/s/master "wercker status")](https://app.wercker.com/project/bykey/0cb7bb1039e21b74f8274941428e0921) 7 | [![GoDoc](https://godoc.org/github.com/jinzhu/gorm?status.svg)](https://godoc.org/github.com/jinzhu/gorm) 8 | 9 | ## Overview 10 | 11 | * Full-Featured ORM (almost) 12 | * Associations (Has One, Has Many, Belongs To, Many To Many, Polymorphism) 13 | * Callbacks (Before/After Create/Save/Update/Delete/Find) 14 | * Preloading (eager loading) 15 | * Transactions 16 | * Composite Primary Key 17 | * SQL Builder 18 | * Auto Migrations 19 | * Logger 20 | * Extendable, write Plugins based on GORM callbacks 21 | * Every feature comes with tests 22 | * Developer Friendly 23 | 24 | ## Getting Started 25 | 26 | * GORM Guides [jinzhu.github.com/gorm](http://jinzhu.github.io/gorm) 27 | 28 | ## Upgrading To V1.0 29 | 30 | * [CHANGELOG](http://jinzhu.github.io/gorm/changelog.html) 31 | 32 | ## Supporting the project 33 | 34 | [![http://patreon.com/jinzhu](http://patreon_public_assets.s3.amazonaws.com/sized/becomeAPatronBanner.png)](http://patreon.com/jinzhu) 35 | 36 | ## Author 37 | 38 | **jinzhu** 39 | 40 | * 41 | * 42 | * 43 | 44 | ## Contributors 45 | 46 | https://github.com/jinzhu/gorm/graphs/contributors 47 | 48 | ## License 49 | 50 | Released under the [MIT License](https://github.com/jinzhu/gorm/blob/master/License). 51 | -------------------------------------------------------------------------------- /vendor/github.com/jinzhu/gorm/callback.go: -------------------------------------------------------------------------------- 1 | package gorm 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // DefaultCallback default callbacks defined by gorm 8 | var DefaultCallback = &Callback{} 9 | 10 | // Callback is a struct that contains all CRUD callbacks 11 | // Field `creates` contains callbacks will be call when creating object 12 | // Field `updates` contains callbacks will be call when updating object 13 | // Field `deletes` contains callbacks will be call when deleting object 14 | // Field `queries` contains callbacks will be call when querying object with query methods like Find, First, Related, Association... 15 | // Field `rowQueries` contains callbacks will be call when querying object with Row, Rows... 16 | // Field `processors` contains all callback processors, will be used to generate above callbacks in order 17 | type Callback struct { 18 | creates []*func(scope *Scope) 19 | updates []*func(scope *Scope) 20 | deletes []*func(scope *Scope) 21 | queries []*func(scope *Scope) 22 | rowQueries []*func(scope *Scope) 23 | processors []*CallbackProcessor 24 | } 25 | 26 | // CallbackProcessor contains callback informations 27 | type CallbackProcessor struct { 28 | name string // current callback's name 29 | before string // register current callback before a callback 30 | after string // register current callback after a callback 31 | replace bool // replace callbacks with same name 32 | remove bool // delete callbacks with same name 33 | kind string // callback type: create, update, delete, query, row_query 34 | processor *func(scope *Scope) // callback handler 35 | parent *Callback 36 | } 37 | 38 | func (c *Callback) clone() *Callback { 39 | return &Callback{ 40 | creates: c.creates, 41 | updates: c.updates, 42 | deletes: c.deletes, 43 | queries: c.queries, 44 | rowQueries: c.rowQueries, 45 | processors: c.processors, 46 | } 47 | } 48 | 49 | // Create could be used to register callbacks for creating object 50 | // db.Callback().Create().After("gorm:create").Register("plugin:run_after_create", func(*Scope) { 51 | // // business logic 52 | // ... 53 | // 54 | // // set error if some thing wrong happened, will rollback the creating 55 | // scope.Err(errors.New("error")) 56 | // }) 57 | func (c *Callback) Create() *CallbackProcessor { 58 | return &CallbackProcessor{kind: "create", parent: c} 59 | } 60 | 61 | // Update could be used to register callbacks for updating object, refer `Create` for usage 62 | func (c *Callback) Update() *CallbackProcessor { 63 | return &CallbackProcessor{kind: "update", parent: c} 64 | } 65 | 66 | // Delete could be used to register callbacks for deleting object, refer `Create` for usage 67 | func (c *Callback) Delete() *CallbackProcessor { 68 | return &CallbackProcessor{kind: "delete", parent: c} 69 | } 70 | 71 | // Query could be used to register callbacks for querying objects with query methods like `Find`, `First`, `Related`, `Association`... 72 | // Refer `Create` for usage 73 | func (c *Callback) Query() *CallbackProcessor { 74 | return &CallbackProcessor{kind: "query", parent: c} 75 | } 76 | 77 | // RowQuery could be used to register callbacks for querying objects with `Row`, `Rows`, refer `Create` for usage 78 | func (c *Callback) RowQuery() *CallbackProcessor { 79 | return &CallbackProcessor{kind: "row_query", parent: c} 80 | } 81 | 82 | // After insert a new callback after callback `callbackName`, refer `Callbacks.Create` 83 | func (cp *CallbackProcessor) After(callbackName string) *CallbackProcessor { 84 | cp.after = callbackName 85 | return cp 86 | } 87 | 88 | // Before insert a new callback before callback `callbackName`, refer `Callbacks.Create` 89 | func (cp *CallbackProcessor) Before(callbackName string) *CallbackProcessor { 90 | cp.before = callbackName 91 | return cp 92 | } 93 | 94 | // Register a new callback, refer `Callbacks.Create` 95 | func (cp *CallbackProcessor) Register(callbackName string, callback func(scope *Scope)) { 96 | if cp.kind == "row_query" { 97 | if cp.before == "" && cp.after == "" && callbackName != "gorm:row_query" { 98 | fmt.Printf("Registing RowQuery callback %v without specify order with Before(), After(), applying Before('gorm:row_query') by default for compatibility...\n", callbackName) 99 | cp.before = "gorm:row_query" 100 | } 101 | } 102 | 103 | cp.name = callbackName 104 | cp.processor = &callback 105 | cp.parent.processors = append(cp.parent.processors, cp) 106 | cp.parent.reorder() 107 | } 108 | 109 | // Remove a registered callback 110 | // db.Callback().Create().Remove("gorm:update_time_stamp_when_create") 111 | func (cp *CallbackProcessor) Remove(callbackName string) { 112 | fmt.Printf("[info] removing callback `%v` from %v\n", callbackName, fileWithLineNum()) 113 | cp.name = callbackName 114 | cp.remove = true 115 | cp.parent.processors = append(cp.parent.processors, cp) 116 | cp.parent.reorder() 117 | } 118 | 119 | // Replace a registered callback with new callback 120 | // db.Callback().Create().Replace("gorm:update_time_stamp_when_create", func(*Scope) { 121 | // scope.SetColumn("Created", now) 122 | // scope.SetColumn("Updated", now) 123 | // }) 124 | func (cp *CallbackProcessor) Replace(callbackName string, callback func(scope *Scope)) { 125 | fmt.Printf("[info] replacing callback `%v` from %v\n", callbackName, fileWithLineNum()) 126 | cp.name = callbackName 127 | cp.processor = &callback 128 | cp.replace = true 129 | cp.parent.processors = append(cp.parent.processors, cp) 130 | cp.parent.reorder() 131 | } 132 | 133 | // Get registered callback 134 | // db.Callback().Create().Get("gorm:create") 135 | func (cp *CallbackProcessor) Get(callbackName string) (callback func(scope *Scope)) { 136 | for _, p := range cp.parent.processors { 137 | if p.name == callbackName && p.kind == cp.kind && !cp.remove { 138 | return *p.processor 139 | } 140 | } 141 | return nil 142 | } 143 | 144 | // getRIndex get right index from string slice 145 | func getRIndex(strs []string, str string) int { 146 | for i := len(strs) - 1; i >= 0; i-- { 147 | if strs[i] == str { 148 | return i 149 | } 150 | } 151 | return -1 152 | } 153 | 154 | // sortProcessors sort callback processors based on its before, after, remove, replace 155 | func sortProcessors(cps []*CallbackProcessor) []*func(scope *Scope) { 156 | var ( 157 | allNames, sortedNames []string 158 | sortCallbackProcessor func(c *CallbackProcessor) 159 | ) 160 | 161 | for _, cp := range cps { 162 | // show warning message the callback name already exists 163 | if index := getRIndex(allNames, cp.name); index > -1 && !cp.replace && !cp.remove { 164 | fmt.Printf("[warning] duplicated callback `%v` from %v\n", cp.name, fileWithLineNum()) 165 | } 166 | allNames = append(allNames, cp.name) 167 | } 168 | 169 | sortCallbackProcessor = func(c *CallbackProcessor) { 170 | if getRIndex(sortedNames, c.name) == -1 { // if not sorted 171 | if c.before != "" { // if defined before callback 172 | if index := getRIndex(sortedNames, c.before); index != -1 { 173 | // if before callback already sorted, append current callback just after it 174 | sortedNames = append(sortedNames[:index], append([]string{c.name}, sortedNames[index:]...)...) 175 | } else if index := getRIndex(allNames, c.before); index != -1 { 176 | // if before callback exists but haven't sorted, append current callback to last 177 | sortedNames = append(sortedNames, c.name) 178 | sortCallbackProcessor(cps[index]) 179 | } 180 | } 181 | 182 | if c.after != "" { // if defined after callback 183 | if index := getRIndex(sortedNames, c.after); index != -1 { 184 | // if after callback already sorted, append current callback just before it 185 | sortedNames = append(sortedNames[:index+1], append([]string{c.name}, sortedNames[index+1:]...)...) 186 | } else if index := getRIndex(allNames, c.after); index != -1 { 187 | // if after callback exists but haven't sorted 188 | cp := cps[index] 189 | // set after callback's before callback to current callback 190 | if cp.before == "" { 191 | cp.before = c.name 192 | } 193 | sortCallbackProcessor(cp) 194 | } 195 | } 196 | 197 | // if current callback haven't been sorted, append it to last 198 | if getRIndex(sortedNames, c.name) == -1 { 199 | sortedNames = append(sortedNames, c.name) 200 | } 201 | } 202 | } 203 | 204 | for _, cp := range cps { 205 | sortCallbackProcessor(cp) 206 | } 207 | 208 | var sortedFuncs []*func(scope *Scope) 209 | for _, name := range sortedNames { 210 | if index := getRIndex(allNames, name); !cps[index].remove { 211 | sortedFuncs = append(sortedFuncs, cps[index].processor) 212 | } 213 | } 214 | 215 | return sortedFuncs 216 | } 217 | 218 | // reorder all registered processors, and reset CRUD callbacks 219 | func (c *Callback) reorder() { 220 | var creates, updates, deletes, queries, rowQueries []*CallbackProcessor 221 | 222 | for _, processor := range c.processors { 223 | if processor.name != "" { 224 | switch processor.kind { 225 | case "create": 226 | creates = append(creates, processor) 227 | case "update": 228 | updates = append(updates, processor) 229 | case "delete": 230 | deletes = append(deletes, processor) 231 | case "query": 232 | queries = append(queries, processor) 233 | case "row_query": 234 | rowQueries = append(rowQueries, processor) 235 | } 236 | } 237 | } 238 | 239 | c.creates = sortProcessors(creates) 240 | c.updates = sortProcessors(updates) 241 | c.deletes = sortProcessors(deletes) 242 | c.queries = sortProcessors(queries) 243 | c.rowQueries = sortProcessors(rowQueries) 244 | } 245 | -------------------------------------------------------------------------------- /vendor/github.com/jinzhu/gorm/callback_create.go: -------------------------------------------------------------------------------- 1 | package gorm 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | // Define callbacks for creating 9 | func init() { 10 | DefaultCallback.Create().Register("gorm:begin_transaction", beginTransactionCallback) 11 | DefaultCallback.Create().Register("gorm:before_create", beforeCreateCallback) 12 | DefaultCallback.Create().Register("gorm:save_before_associations", saveBeforeAssociationsCallback) 13 | DefaultCallback.Create().Register("gorm:update_time_stamp", updateTimeStampForCreateCallback) 14 | DefaultCallback.Create().Register("gorm:create", createCallback) 15 | DefaultCallback.Create().Register("gorm:force_reload_after_create", forceReloadAfterCreateCallback) 16 | DefaultCallback.Create().Register("gorm:save_after_associations", saveAfterAssociationsCallback) 17 | DefaultCallback.Create().Register("gorm:after_create", afterCreateCallback) 18 | DefaultCallback.Create().Register("gorm:commit_or_rollback_transaction", commitOrRollbackTransactionCallback) 19 | } 20 | 21 | // beforeCreateCallback will invoke `BeforeSave`, `BeforeCreate` method before creating 22 | func beforeCreateCallback(scope *Scope) { 23 | if !scope.HasError() { 24 | scope.CallMethod("BeforeSave") 25 | } 26 | if !scope.HasError() { 27 | scope.CallMethod("BeforeCreate") 28 | } 29 | } 30 | 31 | // updateTimeStampForCreateCallback will set `CreatedAt`, `UpdatedAt` when creating 32 | func updateTimeStampForCreateCallback(scope *Scope) { 33 | if !scope.HasError() { 34 | now := NowFunc() 35 | scope.SetColumn("CreatedAt", now) 36 | scope.SetColumn("UpdatedAt", now) 37 | } 38 | } 39 | 40 | // createCallback the callback used to insert data into database 41 | func createCallback(scope *Scope) { 42 | if !scope.HasError() { 43 | defer scope.trace(NowFunc()) 44 | 45 | var ( 46 | columns, placeholders []string 47 | blankColumnsWithDefaultValue []string 48 | ) 49 | 50 | for _, field := range scope.Fields() { 51 | if scope.changeableField(field) { 52 | if field.IsNormal { 53 | if field.IsBlank && field.HasDefaultValue { 54 | blankColumnsWithDefaultValue = append(blankColumnsWithDefaultValue, scope.Quote(field.DBName)) 55 | scope.InstanceSet("gorm:blank_columns_with_default_value", blankColumnsWithDefaultValue) 56 | } else if !field.IsPrimaryKey || !field.IsBlank { 57 | columns = append(columns, scope.Quote(field.DBName)) 58 | placeholders = append(placeholders, scope.AddToVars(field.Field.Interface())) 59 | } 60 | } else if field.Relationship != nil && field.Relationship.Kind == "belongs_to" { 61 | for _, foreignKey := range field.Relationship.ForeignDBNames { 62 | if foreignField, ok := scope.FieldByName(foreignKey); ok && !scope.changeableField(foreignField) { 63 | columns = append(columns, scope.Quote(foreignField.DBName)) 64 | placeholders = append(placeholders, scope.AddToVars(foreignField.Field.Interface())) 65 | } 66 | } 67 | } 68 | } 69 | } 70 | 71 | var ( 72 | returningColumn = "*" 73 | quotedTableName = scope.QuotedTableName() 74 | primaryField = scope.PrimaryField() 75 | extraOption string 76 | ) 77 | 78 | if str, ok := scope.Get("gorm:insert_option"); ok { 79 | extraOption = fmt.Sprint(str) 80 | } 81 | 82 | if primaryField != nil { 83 | returningColumn = scope.Quote(primaryField.DBName) 84 | } 85 | 86 | lastInsertIDReturningSuffix := scope.Dialect().LastInsertIDReturningSuffix(quotedTableName, returningColumn) 87 | 88 | if len(columns) == 0 { 89 | scope.Raw(fmt.Sprintf( 90 | "INSERT INTO %v DEFAULT VALUES%v%v", 91 | quotedTableName, 92 | addExtraSpaceIfExist(extraOption), 93 | addExtraSpaceIfExist(lastInsertIDReturningSuffix), 94 | )) 95 | } else { 96 | scope.Raw(fmt.Sprintf( 97 | "INSERT INTO %v (%v) VALUES (%v)%v%v", 98 | scope.QuotedTableName(), 99 | strings.Join(columns, ","), 100 | strings.Join(placeholders, ","), 101 | addExtraSpaceIfExist(extraOption), 102 | addExtraSpaceIfExist(lastInsertIDReturningSuffix), 103 | )) 104 | } 105 | 106 | // execute create sql 107 | if lastInsertIDReturningSuffix == "" || primaryField == nil { 108 | if result, err := scope.SQLDB().Exec(scope.SQL, scope.SQLVars...); scope.Err(err) == nil { 109 | // set rows affected count 110 | scope.db.RowsAffected, _ = result.RowsAffected() 111 | 112 | // set primary value to primary field 113 | if primaryField != nil && primaryField.IsBlank { 114 | if primaryValue, err := result.LastInsertId(); scope.Err(err) == nil { 115 | scope.Err(primaryField.Set(primaryValue)) 116 | } 117 | } 118 | } 119 | } else { 120 | if primaryField.Field.CanAddr() { 121 | if err := scope.SQLDB().QueryRow(scope.SQL, scope.SQLVars...).Scan(primaryField.Field.Addr().Interface()); scope.Err(err) == nil { 122 | primaryField.IsBlank = false 123 | scope.db.RowsAffected = 1 124 | } 125 | } else { 126 | scope.Err(ErrUnaddressable) 127 | } 128 | } 129 | } 130 | } 131 | 132 | // forceReloadAfterCreateCallback will reload columns that having default value, and set it back to current object 133 | func forceReloadAfterCreateCallback(scope *Scope) { 134 | if blankColumnsWithDefaultValue, ok := scope.InstanceGet("gorm:blank_columns_with_default_value"); ok { 135 | db := scope.DB().New().Table(scope.TableName()).Select(blankColumnsWithDefaultValue.([]string)) 136 | for _, field := range scope.Fields() { 137 | if field.IsPrimaryKey && !field.IsBlank { 138 | db = db.Where(fmt.Sprintf("%v = ?", field.DBName), field.Field.Interface()) 139 | } 140 | } 141 | db.Scan(scope.Value) 142 | } 143 | } 144 | 145 | // afterCreateCallback will invoke `AfterCreate`, `AfterSave` method after creating 146 | func afterCreateCallback(scope *Scope) { 147 | if !scope.HasError() { 148 | scope.CallMethod("AfterCreate") 149 | } 150 | if !scope.HasError() { 151 | scope.CallMethod("AfterSave") 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /vendor/github.com/jinzhu/gorm/callback_delete.go: -------------------------------------------------------------------------------- 1 | package gorm 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | // Define callbacks for deleting 9 | func init() { 10 | DefaultCallback.Delete().Register("gorm:begin_transaction", beginTransactionCallback) 11 | DefaultCallback.Delete().Register("gorm:before_delete", beforeDeleteCallback) 12 | DefaultCallback.Delete().Register("gorm:delete", deleteCallback) 13 | DefaultCallback.Delete().Register("gorm:after_delete", afterDeleteCallback) 14 | DefaultCallback.Delete().Register("gorm:commit_or_rollback_transaction", commitOrRollbackTransactionCallback) 15 | } 16 | 17 | // beforeDeleteCallback will invoke `BeforeDelete` method before deleting 18 | func beforeDeleteCallback(scope *Scope) { 19 | if scope.DB().HasBlockGlobalUpdate() && !scope.hasConditions() { 20 | scope.Err(errors.New("Missing WHERE clause while deleting")) 21 | return 22 | } 23 | if !scope.HasError() { 24 | scope.CallMethod("BeforeDelete") 25 | } 26 | } 27 | 28 | // deleteCallback used to delete data from database or set deleted_at to current time (when using with soft delete) 29 | func deleteCallback(scope *Scope) { 30 | if !scope.HasError() { 31 | var extraOption string 32 | if str, ok := scope.Get("gorm:delete_option"); ok { 33 | extraOption = fmt.Sprint(str) 34 | } 35 | 36 | deletedAtField, hasDeletedAtField := scope.FieldByName("DeletedAt") 37 | 38 | if !scope.Search.Unscoped && hasDeletedAtField { 39 | scope.Raw(fmt.Sprintf( 40 | "UPDATE %v SET %v=%v%v%v", 41 | scope.QuotedTableName(), 42 | scope.Quote(deletedAtField.DBName), 43 | scope.AddToVars(NowFunc()), 44 | addExtraSpaceIfExist(scope.CombinedConditionSql()), 45 | addExtraSpaceIfExist(extraOption), 46 | )).Exec() 47 | } else { 48 | scope.Raw(fmt.Sprintf( 49 | "DELETE FROM %v%v%v", 50 | scope.QuotedTableName(), 51 | addExtraSpaceIfExist(scope.CombinedConditionSql()), 52 | addExtraSpaceIfExist(extraOption), 53 | )).Exec() 54 | } 55 | } 56 | } 57 | 58 | // afterDeleteCallback will invoke `AfterDelete` method after deleting 59 | func afterDeleteCallback(scope *Scope) { 60 | if !scope.HasError() { 61 | scope.CallMethod("AfterDelete") 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /vendor/github.com/jinzhu/gorm/callback_query.go: -------------------------------------------------------------------------------- 1 | package gorm 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | ) 8 | 9 | // Define callbacks for querying 10 | func init() { 11 | DefaultCallback.Query().Register("gorm:query", queryCallback) 12 | DefaultCallback.Query().Register("gorm:preload", preloadCallback) 13 | DefaultCallback.Query().Register("gorm:after_query", afterQueryCallback) 14 | } 15 | 16 | // queryCallback used to query data from database 17 | func queryCallback(scope *Scope) { 18 | defer scope.trace(NowFunc()) 19 | 20 | var ( 21 | isSlice, isPtr bool 22 | resultType reflect.Type 23 | results = scope.IndirectValue() 24 | ) 25 | 26 | if orderBy, ok := scope.Get("gorm:order_by_primary_key"); ok { 27 | if primaryField := scope.PrimaryField(); primaryField != nil { 28 | scope.Search.Order(fmt.Sprintf("%v.%v %v", scope.QuotedTableName(), scope.Quote(primaryField.DBName), orderBy)) 29 | } 30 | } 31 | 32 | if value, ok := scope.Get("gorm:query_destination"); ok { 33 | results = indirect(reflect.ValueOf(value)) 34 | } 35 | 36 | if kind := results.Kind(); kind == reflect.Slice { 37 | isSlice = true 38 | resultType = results.Type().Elem() 39 | results.Set(reflect.MakeSlice(results.Type(), 0, 0)) 40 | 41 | if resultType.Kind() == reflect.Ptr { 42 | isPtr = true 43 | resultType = resultType.Elem() 44 | } 45 | } else if kind != reflect.Struct { 46 | scope.Err(errors.New("unsupported destination, should be slice or struct")) 47 | return 48 | } 49 | 50 | scope.prepareQuerySQL() 51 | 52 | if !scope.HasError() { 53 | scope.db.RowsAffected = 0 54 | if str, ok := scope.Get("gorm:query_option"); ok { 55 | scope.SQL += addExtraSpaceIfExist(fmt.Sprint(str)) 56 | } 57 | 58 | if rows, err := scope.SQLDB().Query(scope.SQL, scope.SQLVars...); scope.Err(err) == nil { 59 | defer rows.Close() 60 | 61 | columns, _ := rows.Columns() 62 | for rows.Next() { 63 | scope.db.RowsAffected++ 64 | 65 | elem := results 66 | if isSlice { 67 | elem = reflect.New(resultType).Elem() 68 | } 69 | 70 | scope.scan(rows, columns, scope.New(elem.Addr().Interface()).Fields()) 71 | 72 | if isSlice { 73 | if isPtr { 74 | results.Set(reflect.Append(results, elem.Addr())) 75 | } else { 76 | results.Set(reflect.Append(results, elem)) 77 | } 78 | } 79 | } 80 | 81 | if err := rows.Err(); err != nil { 82 | scope.Err(err) 83 | } else if scope.db.RowsAffected == 0 && !isSlice { 84 | scope.Err(ErrRecordNotFound) 85 | } 86 | } 87 | } 88 | } 89 | 90 | // afterQueryCallback will invoke `AfterFind` method after querying 91 | func afterQueryCallback(scope *Scope) { 92 | if !scope.HasError() { 93 | scope.CallMethod("AfterFind") 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /vendor/github.com/jinzhu/gorm/callback_query_preload.go: -------------------------------------------------------------------------------- 1 | package gorm 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | // preloadCallback used to preload associations 12 | func preloadCallback(scope *Scope) { 13 | 14 | if _, ok := scope.Get("gorm:auto_preload"); ok { 15 | autoPreload(scope) 16 | } 17 | 18 | if scope.Search.preload == nil || scope.HasError() { 19 | return 20 | } 21 | 22 | var ( 23 | preloadedMap = map[string]bool{} 24 | fields = scope.Fields() 25 | ) 26 | 27 | for _, preload := range scope.Search.preload { 28 | var ( 29 | preloadFields = strings.Split(preload.schema, ".") 30 | currentScope = scope 31 | currentFields = fields 32 | ) 33 | 34 | for idx, preloadField := range preloadFields { 35 | var currentPreloadConditions []interface{} 36 | 37 | if currentScope == nil { 38 | continue 39 | } 40 | 41 | // if not preloaded 42 | if preloadKey := strings.Join(preloadFields[:idx+1], "."); !preloadedMap[preloadKey] { 43 | 44 | // assign search conditions to last preload 45 | if idx == len(preloadFields)-1 { 46 | currentPreloadConditions = preload.conditions 47 | } 48 | 49 | for _, field := range currentFields { 50 | if field.Name != preloadField || field.Relationship == nil { 51 | continue 52 | } 53 | 54 | switch field.Relationship.Kind { 55 | case "has_one": 56 | currentScope.handleHasOnePreload(field, currentPreloadConditions) 57 | case "has_many": 58 | currentScope.handleHasManyPreload(field, currentPreloadConditions) 59 | case "belongs_to": 60 | currentScope.handleBelongsToPreload(field, currentPreloadConditions) 61 | case "many_to_many": 62 | currentScope.handleManyToManyPreload(field, currentPreloadConditions) 63 | default: 64 | scope.Err(errors.New("unsupported relation")) 65 | } 66 | 67 | preloadedMap[preloadKey] = true 68 | break 69 | } 70 | 71 | if !preloadedMap[preloadKey] { 72 | scope.Err(fmt.Errorf("can't preload field %s for %s", preloadField, currentScope.GetModelStruct().ModelType)) 73 | return 74 | } 75 | } 76 | 77 | // preload next level 78 | if idx < len(preloadFields)-1 { 79 | currentScope = currentScope.getColumnAsScope(preloadField) 80 | if currentScope != nil { 81 | currentFields = currentScope.Fields() 82 | } 83 | } 84 | } 85 | } 86 | } 87 | 88 | func autoPreload(scope *Scope) { 89 | for _, field := range scope.Fields() { 90 | if field.Relationship == nil { 91 | continue 92 | } 93 | 94 | if val, ok := field.TagSettings["PRELOAD"]; ok { 95 | if preload, err := strconv.ParseBool(val); err != nil { 96 | scope.Err(errors.New("invalid preload option")) 97 | return 98 | } else if !preload { 99 | continue 100 | } 101 | } 102 | 103 | scope.Search.Preload(field.Name) 104 | } 105 | } 106 | 107 | func (scope *Scope) generatePreloadDBWithConditions(conditions []interface{}) (*DB, []interface{}) { 108 | var ( 109 | preloadDB = scope.NewDB() 110 | preloadConditions []interface{} 111 | ) 112 | 113 | for _, condition := range conditions { 114 | if scopes, ok := condition.(func(*DB) *DB); ok { 115 | preloadDB = scopes(preloadDB) 116 | } else { 117 | preloadConditions = append(preloadConditions, condition) 118 | } 119 | } 120 | 121 | return preloadDB, preloadConditions 122 | } 123 | 124 | // handleHasOnePreload used to preload has one associations 125 | func (scope *Scope) handleHasOnePreload(field *Field, conditions []interface{}) { 126 | relation := field.Relationship 127 | 128 | // get relations's primary keys 129 | primaryKeys := scope.getColumnAsArray(relation.AssociationForeignFieldNames, scope.Value) 130 | if len(primaryKeys) == 0 { 131 | return 132 | } 133 | 134 | // preload conditions 135 | preloadDB, preloadConditions := scope.generatePreloadDBWithConditions(conditions) 136 | 137 | // find relations 138 | query := fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, relation.ForeignDBNames), toQueryMarks(primaryKeys)) 139 | values := toQueryValues(primaryKeys) 140 | if relation.PolymorphicType != "" { 141 | query += fmt.Sprintf(" AND %v = ?", scope.Quote(relation.PolymorphicDBName)) 142 | values = append(values, relation.PolymorphicValue) 143 | } 144 | 145 | results := makeSlice(field.Struct.Type) 146 | scope.Err(preloadDB.Where(query, values...).Find(results, preloadConditions...).Error) 147 | 148 | // assign find results 149 | var ( 150 | resultsValue = indirect(reflect.ValueOf(results)) 151 | indirectScopeValue = scope.IndirectValue() 152 | ) 153 | 154 | if indirectScopeValue.Kind() == reflect.Slice { 155 | for j := 0; j < indirectScopeValue.Len(); j++ { 156 | for i := 0; i < resultsValue.Len(); i++ { 157 | result := resultsValue.Index(i) 158 | foreignValues := getValueFromFields(result, relation.ForeignFieldNames) 159 | if indirectValue := indirect(indirectScopeValue.Index(j)); equalAsString(getValueFromFields(indirectValue, relation.AssociationForeignFieldNames), foreignValues) { 160 | indirectValue.FieldByName(field.Name).Set(result) 161 | break 162 | } 163 | } 164 | } 165 | } else { 166 | for i := 0; i < resultsValue.Len(); i++ { 167 | result := resultsValue.Index(i) 168 | scope.Err(field.Set(result)) 169 | } 170 | } 171 | } 172 | 173 | // handleHasManyPreload used to preload has many associations 174 | func (scope *Scope) handleHasManyPreload(field *Field, conditions []interface{}) { 175 | relation := field.Relationship 176 | 177 | // get relations's primary keys 178 | primaryKeys := scope.getColumnAsArray(relation.AssociationForeignFieldNames, scope.Value) 179 | if len(primaryKeys) == 0 { 180 | return 181 | } 182 | 183 | // preload conditions 184 | preloadDB, preloadConditions := scope.generatePreloadDBWithConditions(conditions) 185 | 186 | // find relations 187 | query := fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, relation.ForeignDBNames), toQueryMarks(primaryKeys)) 188 | values := toQueryValues(primaryKeys) 189 | if relation.PolymorphicType != "" { 190 | query += fmt.Sprintf(" AND %v = ?", scope.Quote(relation.PolymorphicDBName)) 191 | values = append(values, relation.PolymorphicValue) 192 | } 193 | 194 | results := makeSlice(field.Struct.Type) 195 | scope.Err(preloadDB.Where(query, values...).Find(results, preloadConditions...).Error) 196 | 197 | // assign find results 198 | var ( 199 | resultsValue = indirect(reflect.ValueOf(results)) 200 | indirectScopeValue = scope.IndirectValue() 201 | ) 202 | 203 | if indirectScopeValue.Kind() == reflect.Slice { 204 | preloadMap := make(map[string][]reflect.Value) 205 | for i := 0; i < resultsValue.Len(); i++ { 206 | result := resultsValue.Index(i) 207 | foreignValues := getValueFromFields(result, relation.ForeignFieldNames) 208 | preloadMap[toString(foreignValues)] = append(preloadMap[toString(foreignValues)], result) 209 | } 210 | 211 | for j := 0; j < indirectScopeValue.Len(); j++ { 212 | object := indirect(indirectScopeValue.Index(j)) 213 | objectRealValue := getValueFromFields(object, relation.AssociationForeignFieldNames) 214 | f := object.FieldByName(field.Name) 215 | if results, ok := preloadMap[toString(objectRealValue)]; ok { 216 | f.Set(reflect.Append(f, results...)) 217 | } else { 218 | f.Set(reflect.MakeSlice(f.Type(), 0, 0)) 219 | } 220 | } 221 | } else { 222 | scope.Err(field.Set(resultsValue)) 223 | } 224 | } 225 | 226 | // handleBelongsToPreload used to preload belongs to associations 227 | func (scope *Scope) handleBelongsToPreload(field *Field, conditions []interface{}) { 228 | relation := field.Relationship 229 | 230 | // preload conditions 231 | preloadDB, preloadConditions := scope.generatePreloadDBWithConditions(conditions) 232 | 233 | // get relations's primary keys 234 | primaryKeys := scope.getColumnAsArray(relation.ForeignFieldNames, scope.Value) 235 | if len(primaryKeys) == 0 { 236 | return 237 | } 238 | 239 | // find relations 240 | results := makeSlice(field.Struct.Type) 241 | scope.Err(preloadDB.Where(fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, relation.AssociationForeignDBNames), toQueryMarks(primaryKeys)), toQueryValues(primaryKeys)...).Find(results, preloadConditions...).Error) 242 | 243 | // assign find results 244 | var ( 245 | resultsValue = indirect(reflect.ValueOf(results)) 246 | indirectScopeValue = scope.IndirectValue() 247 | ) 248 | 249 | for i := 0; i < resultsValue.Len(); i++ { 250 | result := resultsValue.Index(i) 251 | if indirectScopeValue.Kind() == reflect.Slice { 252 | value := getValueFromFields(result, relation.AssociationForeignFieldNames) 253 | for j := 0; j < indirectScopeValue.Len(); j++ { 254 | object := indirect(indirectScopeValue.Index(j)) 255 | if equalAsString(getValueFromFields(object, relation.ForeignFieldNames), value) { 256 | object.FieldByName(field.Name).Set(result) 257 | } 258 | } 259 | } else { 260 | scope.Err(field.Set(result)) 261 | } 262 | } 263 | } 264 | 265 | // handleManyToManyPreload used to preload many to many associations 266 | func (scope *Scope) handleManyToManyPreload(field *Field, conditions []interface{}) { 267 | var ( 268 | relation = field.Relationship 269 | joinTableHandler = relation.JoinTableHandler 270 | fieldType = field.Struct.Type.Elem() 271 | foreignKeyValue interface{} 272 | foreignKeyType = reflect.ValueOf(&foreignKeyValue).Type() 273 | linkHash = map[string][]reflect.Value{} 274 | isPtr bool 275 | ) 276 | 277 | if fieldType.Kind() == reflect.Ptr { 278 | isPtr = true 279 | fieldType = fieldType.Elem() 280 | } 281 | 282 | var sourceKeys = []string{} 283 | for _, key := range joinTableHandler.SourceForeignKeys() { 284 | sourceKeys = append(sourceKeys, key.DBName) 285 | } 286 | 287 | // preload conditions 288 | preloadDB, preloadConditions := scope.generatePreloadDBWithConditions(conditions) 289 | 290 | // generate query with join table 291 | newScope := scope.New(reflect.New(fieldType).Interface()) 292 | preloadDB = preloadDB.Table(newScope.TableName()).Model(newScope.Value).Select("*") 293 | preloadDB = joinTableHandler.JoinWith(joinTableHandler, preloadDB, scope.Value) 294 | 295 | // preload inline conditions 296 | if len(preloadConditions) > 0 { 297 | preloadDB = preloadDB.Where(preloadConditions[0], preloadConditions[1:]...) 298 | } 299 | 300 | rows, err := preloadDB.Rows() 301 | 302 | if scope.Err(err) != nil { 303 | return 304 | } 305 | defer rows.Close() 306 | 307 | columns, _ := rows.Columns() 308 | for rows.Next() { 309 | var ( 310 | elem = reflect.New(fieldType).Elem() 311 | fields = scope.New(elem.Addr().Interface()).Fields() 312 | ) 313 | 314 | // register foreign keys in join tables 315 | var joinTableFields []*Field 316 | for _, sourceKey := range sourceKeys { 317 | joinTableFields = append(joinTableFields, &Field{StructField: &StructField{DBName: sourceKey, IsNormal: true}, Field: reflect.New(foreignKeyType).Elem()}) 318 | } 319 | 320 | scope.scan(rows, columns, append(fields, joinTableFields...)) 321 | 322 | var foreignKeys = make([]interface{}, len(sourceKeys)) 323 | // generate hashed forkey keys in join table 324 | for idx, joinTableField := range joinTableFields { 325 | if !joinTableField.Field.IsNil() { 326 | foreignKeys[idx] = joinTableField.Field.Elem().Interface() 327 | } 328 | } 329 | hashedSourceKeys := toString(foreignKeys) 330 | 331 | if isPtr { 332 | linkHash[hashedSourceKeys] = append(linkHash[hashedSourceKeys], elem.Addr()) 333 | } else { 334 | linkHash[hashedSourceKeys] = append(linkHash[hashedSourceKeys], elem) 335 | } 336 | } 337 | 338 | if err := rows.Err(); err != nil { 339 | scope.Err(err) 340 | } 341 | 342 | // assign find results 343 | var ( 344 | indirectScopeValue = scope.IndirectValue() 345 | fieldsSourceMap = map[string][]reflect.Value{} 346 | foreignFieldNames = []string{} 347 | ) 348 | 349 | for _, dbName := range relation.ForeignFieldNames { 350 | if field, ok := scope.FieldByName(dbName); ok { 351 | foreignFieldNames = append(foreignFieldNames, field.Name) 352 | } 353 | } 354 | 355 | if indirectScopeValue.Kind() == reflect.Slice { 356 | for j := 0; j < indirectScopeValue.Len(); j++ { 357 | object := indirect(indirectScopeValue.Index(j)) 358 | key := toString(getValueFromFields(object, foreignFieldNames)) 359 | fieldsSourceMap[key] = append(fieldsSourceMap[key], object.FieldByName(field.Name)) 360 | } 361 | } else if indirectScopeValue.IsValid() { 362 | key := toString(getValueFromFields(indirectScopeValue, foreignFieldNames)) 363 | fieldsSourceMap[key] = append(fieldsSourceMap[key], indirectScopeValue.FieldByName(field.Name)) 364 | } 365 | for source, link := range linkHash { 366 | for i, field := range fieldsSourceMap[source] { 367 | //If not 0 this means Value is a pointer and we already added preloaded models to it 368 | if fieldsSourceMap[source][i].Len() != 0 { 369 | continue 370 | } 371 | field.Set(reflect.Append(fieldsSourceMap[source][i], link...)) 372 | } 373 | 374 | } 375 | } 376 | -------------------------------------------------------------------------------- /vendor/github.com/jinzhu/gorm/callback_row_query.go: -------------------------------------------------------------------------------- 1 | package gorm 2 | 3 | import "database/sql" 4 | 5 | // Define callbacks for row query 6 | func init() { 7 | DefaultCallback.RowQuery().Register("gorm:row_query", rowQueryCallback) 8 | } 9 | 10 | type RowQueryResult struct { 11 | Row *sql.Row 12 | } 13 | 14 | type RowsQueryResult struct { 15 | Rows *sql.Rows 16 | Error error 17 | } 18 | 19 | // queryCallback used to query data from database 20 | func rowQueryCallback(scope *Scope) { 21 | if result, ok := scope.InstanceGet("row_query_result"); ok { 22 | scope.prepareQuerySQL() 23 | 24 | if rowResult, ok := result.(*RowQueryResult); ok { 25 | rowResult.Row = scope.SQLDB().QueryRow(scope.SQL, scope.SQLVars...) 26 | } else if rowsResult, ok := result.(*RowsQueryResult); ok { 27 | rowsResult.Rows, rowsResult.Error = scope.SQLDB().Query(scope.SQL, scope.SQLVars...) 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /vendor/github.com/jinzhu/gorm/callback_save.go: -------------------------------------------------------------------------------- 1 | package gorm 2 | 3 | import "reflect" 4 | 5 | func beginTransactionCallback(scope *Scope) { 6 | scope.Begin() 7 | } 8 | 9 | func commitOrRollbackTransactionCallback(scope *Scope) { 10 | scope.CommitOrRollback() 11 | } 12 | 13 | func saveFieldAsAssociation(scope *Scope, field *Field) (bool, *Relationship) { 14 | if scope.changeableField(field) && !field.IsBlank && !field.IsIgnored { 15 | if value, ok := field.TagSettings["SAVE_ASSOCIATIONS"]; !ok || (value != "false" && value != "skip") { 16 | if relationship := field.Relationship; relationship != nil { 17 | return true, relationship 18 | } 19 | } 20 | } 21 | return false, nil 22 | } 23 | 24 | func saveBeforeAssociationsCallback(scope *Scope) { 25 | if !scope.shouldSaveAssociations() { 26 | return 27 | } 28 | for _, field := range scope.Fields() { 29 | if ok, relationship := saveFieldAsAssociation(scope, field); ok && relationship.Kind == "belongs_to" { 30 | fieldValue := field.Field.Addr().Interface() 31 | scope.Err(scope.NewDB().Save(fieldValue).Error) 32 | if len(relationship.ForeignFieldNames) != 0 { 33 | // set value's foreign key 34 | for idx, fieldName := range relationship.ForeignFieldNames { 35 | associationForeignName := relationship.AssociationForeignDBNames[idx] 36 | if foreignField, ok := scope.New(fieldValue).FieldByName(associationForeignName); ok { 37 | scope.Err(scope.SetColumn(fieldName, foreignField.Field.Interface())) 38 | } 39 | } 40 | } 41 | } 42 | } 43 | } 44 | 45 | func saveAfterAssociationsCallback(scope *Scope) { 46 | if !scope.shouldSaveAssociations() { 47 | return 48 | } 49 | for _, field := range scope.Fields() { 50 | if ok, relationship := saveFieldAsAssociation(scope, field); ok && 51 | (relationship.Kind == "has_one" || relationship.Kind == "has_many" || relationship.Kind == "many_to_many") { 52 | value := field.Field 53 | 54 | switch value.Kind() { 55 | case reflect.Slice: 56 | for i := 0; i < value.Len(); i++ { 57 | newDB := scope.NewDB() 58 | elem := value.Index(i).Addr().Interface() 59 | newScope := newDB.NewScope(elem) 60 | 61 | if relationship.JoinTableHandler == nil && len(relationship.ForeignFieldNames) != 0 { 62 | for idx, fieldName := range relationship.ForeignFieldNames { 63 | associationForeignName := relationship.AssociationForeignDBNames[idx] 64 | if f, ok := scope.FieldByName(associationForeignName); ok { 65 | scope.Err(newScope.SetColumn(fieldName, f.Field.Interface())) 66 | } 67 | } 68 | } 69 | 70 | if relationship.PolymorphicType != "" { 71 | scope.Err(newScope.SetColumn(relationship.PolymorphicType, relationship.PolymorphicValue)) 72 | } 73 | 74 | scope.Err(newDB.Save(elem).Error) 75 | 76 | if joinTableHandler := relationship.JoinTableHandler; joinTableHandler != nil { 77 | scope.Err(joinTableHandler.Add(joinTableHandler, newDB, scope.Value, newScope.Value)) 78 | } 79 | } 80 | default: 81 | elem := value.Addr().Interface() 82 | newScope := scope.New(elem) 83 | if len(relationship.ForeignFieldNames) != 0 { 84 | for idx, fieldName := range relationship.ForeignFieldNames { 85 | associationForeignName := relationship.AssociationForeignDBNames[idx] 86 | if f, ok := scope.FieldByName(associationForeignName); ok { 87 | scope.Err(newScope.SetColumn(fieldName, f.Field.Interface())) 88 | } 89 | } 90 | } 91 | 92 | if relationship.PolymorphicType != "" { 93 | scope.Err(newScope.SetColumn(relationship.PolymorphicType, relationship.PolymorphicValue)) 94 | } 95 | scope.Err(scope.NewDB().Save(elem).Error) 96 | } 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /vendor/github.com/jinzhu/gorm/callback_update.go: -------------------------------------------------------------------------------- 1 | package gorm 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "strings" 7 | ) 8 | 9 | // Define callbacks for updating 10 | func init() { 11 | DefaultCallback.Update().Register("gorm:assign_updating_attributes", assignUpdatingAttributesCallback) 12 | DefaultCallback.Update().Register("gorm:begin_transaction", beginTransactionCallback) 13 | DefaultCallback.Update().Register("gorm:before_update", beforeUpdateCallback) 14 | DefaultCallback.Update().Register("gorm:save_before_associations", saveBeforeAssociationsCallback) 15 | DefaultCallback.Update().Register("gorm:update_time_stamp", updateTimeStampForUpdateCallback) 16 | DefaultCallback.Update().Register("gorm:update", updateCallback) 17 | DefaultCallback.Update().Register("gorm:save_after_associations", saveAfterAssociationsCallback) 18 | DefaultCallback.Update().Register("gorm:after_update", afterUpdateCallback) 19 | DefaultCallback.Update().Register("gorm:commit_or_rollback_transaction", commitOrRollbackTransactionCallback) 20 | } 21 | 22 | // assignUpdatingAttributesCallback assign updating attributes to model 23 | func assignUpdatingAttributesCallback(scope *Scope) { 24 | if attrs, ok := scope.InstanceGet("gorm:update_interface"); ok { 25 | if updateMaps, hasUpdate := scope.updatedAttrsWithValues(attrs); hasUpdate { 26 | scope.InstanceSet("gorm:update_attrs", updateMaps) 27 | } else { 28 | scope.SkipLeft() 29 | } 30 | } 31 | } 32 | 33 | // beforeUpdateCallback will invoke `BeforeSave`, `BeforeUpdate` method before updating 34 | func beforeUpdateCallback(scope *Scope) { 35 | if scope.DB().HasBlockGlobalUpdate() && !scope.hasConditions() { 36 | scope.Err(errors.New("Missing WHERE clause while updating")) 37 | return 38 | } 39 | if _, ok := scope.Get("gorm:update_column"); !ok { 40 | if !scope.HasError() { 41 | scope.CallMethod("BeforeSave") 42 | } 43 | if !scope.HasError() { 44 | scope.CallMethod("BeforeUpdate") 45 | } 46 | } 47 | } 48 | 49 | // updateTimeStampForUpdateCallback will set `UpdatedAt` when updating 50 | func updateTimeStampForUpdateCallback(scope *Scope) { 51 | if _, ok := scope.Get("gorm:update_column"); !ok { 52 | scope.SetColumn("UpdatedAt", NowFunc()) 53 | } 54 | } 55 | 56 | // updateCallback the callback used to update data to database 57 | func updateCallback(scope *Scope) { 58 | if !scope.HasError() { 59 | var sqls []string 60 | 61 | if updateAttrs, ok := scope.InstanceGet("gorm:update_attrs"); ok { 62 | for column, value := range updateAttrs.(map[string]interface{}) { 63 | sqls = append(sqls, fmt.Sprintf("%v = %v", scope.Quote(column), scope.AddToVars(value))) 64 | } 65 | } else { 66 | for _, field := range scope.Fields() { 67 | if scope.changeableField(field) { 68 | if !field.IsPrimaryKey && field.IsNormal { 69 | sqls = append(sqls, fmt.Sprintf("%v = %v", scope.Quote(field.DBName), scope.AddToVars(field.Field.Interface()))) 70 | } else if relationship := field.Relationship; relationship != nil && relationship.Kind == "belongs_to" { 71 | for _, foreignKey := range relationship.ForeignDBNames { 72 | if foreignField, ok := scope.FieldByName(foreignKey); ok && !scope.changeableField(foreignField) { 73 | sqls = append(sqls, 74 | fmt.Sprintf("%v = %v", scope.Quote(foreignField.DBName), scope.AddToVars(foreignField.Field.Interface()))) 75 | } 76 | } 77 | } 78 | } 79 | } 80 | } 81 | 82 | var extraOption string 83 | if str, ok := scope.Get("gorm:update_option"); ok { 84 | extraOption = fmt.Sprint(str) 85 | } 86 | 87 | if len(sqls) > 0 { 88 | scope.Raw(fmt.Sprintf( 89 | "UPDATE %v SET %v%v%v", 90 | scope.QuotedTableName(), 91 | strings.Join(sqls, ", "), 92 | addExtraSpaceIfExist(scope.CombinedConditionSql()), 93 | addExtraSpaceIfExist(extraOption), 94 | )).Exec() 95 | } 96 | } 97 | } 98 | 99 | // afterUpdateCallback will invoke `AfterUpdate`, `AfterSave` method after updating 100 | func afterUpdateCallback(scope *Scope) { 101 | if _, ok := scope.Get("gorm:update_column"); !ok { 102 | if !scope.HasError() { 103 | scope.CallMethod("AfterUpdate") 104 | } 105 | if !scope.HasError() { 106 | scope.CallMethod("AfterSave") 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /vendor/github.com/jinzhu/gorm/dialect.go: -------------------------------------------------------------------------------- 1 | package gorm 2 | 3 | import ( 4 | "database/sql" 5 | "fmt" 6 | "reflect" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | // Dialect interface contains behaviors that differ across SQL database 12 | type Dialect interface { 13 | // GetName get dialect's name 14 | GetName() string 15 | 16 | // SetDB set db for dialect 17 | SetDB(db SQLCommon) 18 | 19 | // BindVar return the placeholder for actual values in SQL statements, in many dbs it is "?", Postgres using $1 20 | BindVar(i int) string 21 | // Quote quotes field name to avoid SQL parsing exceptions by using a reserved word as a field name 22 | Quote(key string) string 23 | // DataTypeOf return data's sql type 24 | DataTypeOf(field *StructField) string 25 | 26 | // HasIndex check has index or not 27 | HasIndex(tableName string, indexName string) bool 28 | // HasForeignKey check has foreign key or not 29 | HasForeignKey(tableName string, foreignKeyName string) bool 30 | // RemoveIndex remove index 31 | RemoveIndex(tableName string, indexName string) error 32 | // HasTable check has table or not 33 | HasTable(tableName string) bool 34 | // HasColumn check has column or not 35 | HasColumn(tableName string, columnName string) bool 36 | 37 | // LimitAndOffsetSQL return generated SQL with Limit and Offset, as mssql has special case 38 | LimitAndOffsetSQL(limit, offset interface{}) string 39 | // SelectFromDummyTable return select values, for most dbs, `SELECT values` just works, mysql needs `SELECT value FROM DUAL` 40 | SelectFromDummyTable() string 41 | // LastInsertIdReturningSuffix most dbs support LastInsertId, but postgres needs to use `RETURNING` 42 | LastInsertIDReturningSuffix(tableName, columnName string) string 43 | 44 | // BuildForeignKeyName returns a foreign key name for the given table, field and reference 45 | BuildForeignKeyName(tableName, field, dest string) string 46 | 47 | // CurrentDatabase return current database name 48 | CurrentDatabase() string 49 | } 50 | 51 | var dialectsMap = map[string]Dialect{} 52 | 53 | func newDialect(name string, db SQLCommon) Dialect { 54 | if value, ok := dialectsMap[name]; ok { 55 | dialect := reflect.New(reflect.TypeOf(value).Elem()).Interface().(Dialect) 56 | dialect.SetDB(db) 57 | return dialect 58 | } 59 | 60 | fmt.Printf("`%v` is not officially supported, running under compatibility mode.\n", name) 61 | commontDialect := &commonDialect{} 62 | commontDialect.SetDB(db) 63 | return commontDialect 64 | } 65 | 66 | // RegisterDialect register new dialect 67 | func RegisterDialect(name string, dialect Dialect) { 68 | dialectsMap[name] = dialect 69 | } 70 | 71 | // ParseFieldStructForDialect get field's sql data type 72 | var ParseFieldStructForDialect = func(field *StructField, dialect Dialect) (fieldValue reflect.Value, sqlType string, size int, additionalType string) { 73 | // Get redirected field type 74 | var ( 75 | reflectType = field.Struct.Type 76 | dataType = field.TagSettings["TYPE"] 77 | ) 78 | 79 | for reflectType.Kind() == reflect.Ptr { 80 | reflectType = reflectType.Elem() 81 | } 82 | 83 | // Get redirected field value 84 | fieldValue = reflect.Indirect(reflect.New(reflectType)) 85 | 86 | if gormDataType, ok := fieldValue.Interface().(interface { 87 | GormDataType(Dialect) string 88 | }); ok { 89 | dataType = gormDataType.GormDataType(dialect) 90 | } 91 | 92 | // Get scanner's real value 93 | var getScannerValue func(reflect.Value) 94 | getScannerValue = func(value reflect.Value) { 95 | fieldValue = value 96 | if _, isScanner := reflect.New(fieldValue.Type()).Interface().(sql.Scanner); isScanner && fieldValue.Kind() == reflect.Struct { 97 | getScannerValue(fieldValue.Field(0)) 98 | } 99 | } 100 | getScannerValue(fieldValue) 101 | 102 | // Default Size 103 | if num, ok := field.TagSettings["SIZE"]; ok { 104 | size, _ = strconv.Atoi(num) 105 | } else { 106 | size = 255 107 | } 108 | 109 | // Default type from tag setting 110 | additionalType = field.TagSettings["NOT NULL"] + " " + field.TagSettings["UNIQUE"] 111 | if value, ok := field.TagSettings["DEFAULT"]; ok { 112 | additionalType = additionalType + " DEFAULT " + value 113 | } 114 | 115 | return fieldValue, dataType, size, strings.TrimSpace(additionalType) 116 | } 117 | -------------------------------------------------------------------------------- /vendor/github.com/jinzhu/gorm/dialect_common.go: -------------------------------------------------------------------------------- 1 | package gorm 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "regexp" 7 | "strconv" 8 | "strings" 9 | "time" 10 | ) 11 | 12 | // DefaultForeignKeyNamer contains the default foreign key name generator method 13 | type DefaultForeignKeyNamer struct { 14 | } 15 | 16 | type commonDialect struct { 17 | db SQLCommon 18 | DefaultForeignKeyNamer 19 | } 20 | 21 | func init() { 22 | RegisterDialect("common", &commonDialect{}) 23 | } 24 | 25 | func (commonDialect) GetName() string { 26 | return "common" 27 | } 28 | 29 | func (s *commonDialect) SetDB(db SQLCommon) { 30 | s.db = db 31 | } 32 | 33 | func (commonDialect) BindVar(i int) string { 34 | return "$$$" // ? 35 | } 36 | 37 | func (commonDialect) Quote(key string) string { 38 | return fmt.Sprintf(`"%s"`, key) 39 | } 40 | 41 | func (s *commonDialect) DataTypeOf(field *StructField) string { 42 | var dataValue, sqlType, size, additionalType = ParseFieldStructForDialect(field, s) 43 | 44 | if sqlType == "" { 45 | switch dataValue.Kind() { 46 | case reflect.Bool: 47 | sqlType = "BOOLEAN" 48 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr: 49 | if _, ok := field.TagSettings["AUTO_INCREMENT"]; ok { 50 | sqlType = "INTEGER AUTO_INCREMENT" 51 | } else { 52 | sqlType = "INTEGER" 53 | } 54 | case reflect.Int64, reflect.Uint64: 55 | if _, ok := field.TagSettings["AUTO_INCREMENT"]; ok { 56 | sqlType = "BIGINT AUTO_INCREMENT" 57 | } else { 58 | sqlType = "BIGINT" 59 | } 60 | case reflect.Float32, reflect.Float64: 61 | sqlType = "FLOAT" 62 | case reflect.String: 63 | if size > 0 && size < 65532 { 64 | sqlType = fmt.Sprintf("VARCHAR(%d)", size) 65 | } else { 66 | sqlType = "VARCHAR(65532)" 67 | } 68 | case reflect.Struct: 69 | if _, ok := dataValue.Interface().(time.Time); ok { 70 | sqlType = "TIMESTAMP" 71 | } 72 | default: 73 | if _, ok := dataValue.Interface().([]byte); ok { 74 | if size > 0 && size < 65532 { 75 | sqlType = fmt.Sprintf("BINARY(%d)", size) 76 | } else { 77 | sqlType = "BINARY(65532)" 78 | } 79 | } 80 | } 81 | } 82 | 83 | if sqlType == "" { 84 | panic(fmt.Sprintf("invalid sql type %s (%s) for commonDialect", dataValue.Type().Name(), dataValue.Kind().String())) 85 | } 86 | 87 | if strings.TrimSpace(additionalType) == "" { 88 | return sqlType 89 | } 90 | return fmt.Sprintf("%v %v", sqlType, additionalType) 91 | } 92 | 93 | func (s commonDialect) HasIndex(tableName string, indexName string) bool { 94 | var count int 95 | s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.STATISTICS WHERE table_schema = ? AND table_name = ? AND index_name = ?", s.CurrentDatabase(), tableName, indexName).Scan(&count) 96 | return count > 0 97 | } 98 | 99 | func (s commonDialect) RemoveIndex(tableName string, indexName string) error { 100 | _, err := s.db.Exec(fmt.Sprintf("DROP INDEX %v", indexName)) 101 | return err 102 | } 103 | 104 | func (s commonDialect) HasForeignKey(tableName string, foreignKeyName string) bool { 105 | return false 106 | } 107 | 108 | func (s commonDialect) HasTable(tableName string) bool { 109 | var count int 110 | s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = ? AND table_name = ?", s.CurrentDatabase(), tableName).Scan(&count) 111 | return count > 0 112 | } 113 | 114 | func (s commonDialect) HasColumn(tableName string, columnName string) bool { 115 | var count int 116 | s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = ? AND table_name = ? AND column_name = ?", s.CurrentDatabase(), tableName, columnName).Scan(&count) 117 | return count > 0 118 | } 119 | 120 | func (s commonDialect) CurrentDatabase() (name string) { 121 | s.db.QueryRow("SELECT DATABASE()").Scan(&name) 122 | return 123 | } 124 | 125 | func (commonDialect) LimitAndOffsetSQL(limit, offset interface{}) (sql string) { 126 | if limit != nil { 127 | if parsedLimit, err := strconv.ParseInt(fmt.Sprint(limit), 0, 0); err == nil && parsedLimit >= 0 { 128 | sql += fmt.Sprintf(" LIMIT %d", parsedLimit) 129 | } 130 | } 131 | if offset != nil { 132 | if parsedOffset, err := strconv.ParseInt(fmt.Sprint(offset), 0, 0); err == nil && parsedOffset >= 0 { 133 | sql += fmt.Sprintf(" OFFSET %d", parsedOffset) 134 | } 135 | } 136 | return 137 | } 138 | 139 | func (commonDialect) SelectFromDummyTable() string { 140 | return "" 141 | } 142 | 143 | func (commonDialect) LastInsertIDReturningSuffix(tableName, columnName string) string { 144 | return "" 145 | } 146 | 147 | func (DefaultForeignKeyNamer) BuildForeignKeyName(tableName, field, dest string) string { 148 | keyName := fmt.Sprintf("%s_%s_%s_foreign", tableName, field, dest) 149 | keyName = regexp.MustCompile("(_*[^a-zA-Z]+_*|_+)").ReplaceAllString(keyName, "_") 150 | return keyName 151 | } 152 | 153 | // IsByteArrayOrSlice returns true of the reflected value is an array or slice 154 | func IsByteArrayOrSlice(value reflect.Value) bool { 155 | return (value.Kind() == reflect.Array || value.Kind() == reflect.Slice) && value.Type().Elem() == reflect.TypeOf(uint8(0)) 156 | } 157 | -------------------------------------------------------------------------------- /vendor/github.com/jinzhu/gorm/dialect_mysql.go: -------------------------------------------------------------------------------- 1 | package gorm 2 | 3 | import ( 4 | "crypto/sha1" 5 | "fmt" 6 | "reflect" 7 | "regexp" 8 | "strconv" 9 | "strings" 10 | "time" 11 | "unicode/utf8" 12 | ) 13 | 14 | type mysql struct { 15 | commonDialect 16 | } 17 | 18 | func init() { 19 | RegisterDialect("mysql", &mysql{}) 20 | } 21 | 22 | func (mysql) GetName() string { 23 | return "mysql" 24 | } 25 | 26 | func (mysql) Quote(key string) string { 27 | return fmt.Sprintf("`%s`", key) 28 | } 29 | 30 | // Get Data Type for MySQL Dialect 31 | func (s *mysql) DataTypeOf(field *StructField) string { 32 | var dataValue, sqlType, size, additionalType = ParseFieldStructForDialect(field, s) 33 | 34 | // MySQL allows only one auto increment column per table, and it must 35 | // be a KEY column. 36 | if _, ok := field.TagSettings["AUTO_INCREMENT"]; ok { 37 | if _, ok = field.TagSettings["INDEX"]; !ok && !field.IsPrimaryKey { 38 | delete(field.TagSettings, "AUTO_INCREMENT") 39 | } 40 | } 41 | 42 | if sqlType == "" { 43 | switch dataValue.Kind() { 44 | case reflect.Bool: 45 | sqlType = "boolean" 46 | case reflect.Int8: 47 | if _, ok := field.TagSettings["AUTO_INCREMENT"]; ok || field.IsPrimaryKey { 48 | field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT" 49 | sqlType = "tinyint AUTO_INCREMENT" 50 | } else { 51 | sqlType = "tinyint" 52 | } 53 | case reflect.Int, reflect.Int16, reflect.Int32: 54 | if _, ok := field.TagSettings["AUTO_INCREMENT"]; ok || field.IsPrimaryKey { 55 | field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT" 56 | sqlType = "int AUTO_INCREMENT" 57 | } else { 58 | sqlType = "int" 59 | } 60 | case reflect.Uint8: 61 | if _, ok := field.TagSettings["AUTO_INCREMENT"]; ok || field.IsPrimaryKey { 62 | field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT" 63 | sqlType = "tinyint unsigned AUTO_INCREMENT" 64 | } else { 65 | sqlType = "tinyint unsigned" 66 | } 67 | case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uintptr: 68 | if _, ok := field.TagSettings["AUTO_INCREMENT"]; ok || field.IsPrimaryKey { 69 | field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT" 70 | sqlType = "int unsigned AUTO_INCREMENT" 71 | } else { 72 | sqlType = "int unsigned" 73 | } 74 | case reflect.Int64: 75 | if _, ok := field.TagSettings["AUTO_INCREMENT"]; ok || field.IsPrimaryKey { 76 | field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT" 77 | sqlType = "bigint AUTO_INCREMENT" 78 | } else { 79 | sqlType = "bigint" 80 | } 81 | case reflect.Uint64: 82 | if _, ok := field.TagSettings["AUTO_INCREMENT"]; ok || field.IsPrimaryKey { 83 | field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT" 84 | sqlType = "bigint unsigned AUTO_INCREMENT" 85 | } else { 86 | sqlType = "bigint unsigned" 87 | } 88 | case reflect.Float32, reflect.Float64: 89 | sqlType = "double" 90 | case reflect.String: 91 | if size > 0 && size < 65532 { 92 | sqlType = fmt.Sprintf("varchar(%d)", size) 93 | } else { 94 | sqlType = "longtext" 95 | } 96 | case reflect.Struct: 97 | if _, ok := dataValue.Interface().(time.Time); ok { 98 | if _, ok := field.TagSettings["NOT NULL"]; ok { 99 | sqlType = "timestamp" 100 | } else { 101 | sqlType = "timestamp NULL" 102 | } 103 | } 104 | default: 105 | if IsByteArrayOrSlice(dataValue) { 106 | if size > 0 && size < 65532 { 107 | sqlType = fmt.Sprintf("varbinary(%d)", size) 108 | } else { 109 | sqlType = "longblob" 110 | } 111 | } 112 | } 113 | } 114 | 115 | if sqlType == "" { 116 | panic(fmt.Sprintf("invalid sql type %s (%s) for mysql", dataValue.Type().Name(), dataValue.Kind().String())) 117 | } 118 | 119 | if strings.TrimSpace(additionalType) == "" { 120 | return sqlType 121 | } 122 | return fmt.Sprintf("%v %v", sqlType, additionalType) 123 | } 124 | 125 | func (s mysql) RemoveIndex(tableName string, indexName string) error { 126 | _, err := s.db.Exec(fmt.Sprintf("DROP INDEX %v ON %v", indexName, s.Quote(tableName))) 127 | return err 128 | } 129 | 130 | func (s mysql) LimitAndOffsetSQL(limit, offset interface{}) (sql string) { 131 | if limit != nil { 132 | if parsedLimit, err := strconv.ParseInt(fmt.Sprint(limit), 0, 0); err == nil && parsedLimit >= 0 { 133 | sql += fmt.Sprintf(" LIMIT %d", parsedLimit) 134 | 135 | if offset != nil { 136 | if parsedOffset, err := strconv.ParseInt(fmt.Sprint(offset), 0, 0); err == nil && parsedOffset >= 0 { 137 | sql += fmt.Sprintf(" OFFSET %d", parsedOffset) 138 | } 139 | } 140 | } 141 | } 142 | return 143 | } 144 | 145 | func (s mysql) HasForeignKey(tableName string, foreignKeyName string) bool { 146 | var count int 147 | s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_SCHEMA=? AND TABLE_NAME=? AND CONSTRAINT_NAME=? AND CONSTRAINT_TYPE='FOREIGN KEY'", s.CurrentDatabase(), tableName, foreignKeyName).Scan(&count) 148 | return count > 0 149 | } 150 | 151 | func (s mysql) CurrentDatabase() (name string) { 152 | s.db.QueryRow("SELECT DATABASE()").Scan(&name) 153 | return 154 | } 155 | 156 | func (mysql) SelectFromDummyTable() string { 157 | return "FROM DUAL" 158 | } 159 | 160 | func (s mysql) BuildForeignKeyName(tableName, field, dest string) string { 161 | keyName := s.commonDialect.BuildForeignKeyName(tableName, field, dest) 162 | if utf8.RuneCountInString(keyName) <= 64 { 163 | return keyName 164 | } 165 | h := sha1.New() 166 | h.Write([]byte(keyName)) 167 | bs := h.Sum(nil) 168 | 169 | // sha1 is 40 digits, keep first 24 characters of destination 170 | destRunes := []rune(regexp.MustCompile("(_*[^a-zA-Z]+_*|_+)").ReplaceAllString(dest, "_")) 171 | if len(destRunes) > 24 { 172 | destRunes = destRunes[:24] 173 | } 174 | 175 | return fmt.Sprintf("%s%x", string(destRunes), bs) 176 | } 177 | -------------------------------------------------------------------------------- /vendor/github.com/jinzhu/gorm/dialect_postgres.go: -------------------------------------------------------------------------------- 1 | package gorm 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "strings" 7 | "time" 8 | ) 9 | 10 | type postgres struct { 11 | commonDialect 12 | } 13 | 14 | func init() { 15 | RegisterDialect("postgres", &postgres{}) 16 | } 17 | 18 | func (postgres) GetName() string { 19 | return "postgres" 20 | } 21 | 22 | func (postgres) BindVar(i int) string { 23 | return fmt.Sprintf("$%v", i) 24 | } 25 | 26 | func (s *postgres) DataTypeOf(field *StructField) string { 27 | var dataValue, sqlType, size, additionalType = ParseFieldStructForDialect(field, s) 28 | 29 | if sqlType == "" { 30 | switch dataValue.Kind() { 31 | case reflect.Bool: 32 | sqlType = "boolean" 33 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr: 34 | if _, ok := field.TagSettings["AUTO_INCREMENT"]; ok || field.IsPrimaryKey { 35 | field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT" 36 | sqlType = "serial" 37 | } else { 38 | sqlType = "integer" 39 | } 40 | case reflect.Int64, reflect.Uint64: 41 | if _, ok := field.TagSettings["AUTO_INCREMENT"]; ok || field.IsPrimaryKey { 42 | field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT" 43 | sqlType = "bigserial" 44 | } else { 45 | sqlType = "bigint" 46 | } 47 | case reflect.Float32, reflect.Float64: 48 | sqlType = "numeric" 49 | case reflect.String: 50 | if _, ok := field.TagSettings["SIZE"]; !ok { 51 | size = 0 // if SIZE haven't been set, use `text` as the default type, as there are no performance different 52 | } 53 | 54 | if size > 0 && size < 65532 { 55 | sqlType = fmt.Sprintf("varchar(%d)", size) 56 | } else { 57 | sqlType = "text" 58 | } 59 | case reflect.Struct: 60 | if _, ok := dataValue.Interface().(time.Time); ok { 61 | sqlType = "timestamp with time zone" 62 | } 63 | case reflect.Map: 64 | if dataValue.Type().Name() == "Hstore" { 65 | sqlType = "hstore" 66 | } 67 | default: 68 | if IsByteArrayOrSlice(dataValue) { 69 | sqlType = "bytea" 70 | } else if isUUID(dataValue) { 71 | sqlType = "uuid" 72 | } 73 | } 74 | } 75 | 76 | if sqlType == "" { 77 | panic(fmt.Sprintf("invalid sql type %s (%s) for postgres", dataValue.Type().Name(), dataValue.Kind().String())) 78 | } 79 | 80 | if strings.TrimSpace(additionalType) == "" { 81 | return sqlType 82 | } 83 | return fmt.Sprintf("%v %v", sqlType, additionalType) 84 | } 85 | 86 | func (s postgres) HasIndex(tableName string, indexName string) bool { 87 | var count int 88 | s.db.QueryRow("SELECT count(*) FROM pg_indexes WHERE tablename = $1 AND indexname = $2", tableName, indexName).Scan(&count) 89 | return count > 0 90 | } 91 | 92 | func (s postgres) HasForeignKey(tableName string, foreignKeyName string) bool { 93 | var count int 94 | s.db.QueryRow("SELECT count(con.conname) FROM pg_constraint con WHERE $1::regclass::oid = con.conrelid AND con.conname = $2 AND con.contype='f'", tableName, foreignKeyName).Scan(&count) 95 | return count > 0 96 | } 97 | 98 | func (s postgres) HasTable(tableName string) bool { 99 | var count int 100 | s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.tables WHERE table_name = $1 AND table_type = 'BASE TABLE'", tableName).Scan(&count) 101 | return count > 0 102 | } 103 | 104 | func (s postgres) HasColumn(tableName string, columnName string) bool { 105 | var count int 106 | s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.columns WHERE table_name = $1 AND column_name = $2", tableName, columnName).Scan(&count) 107 | return count > 0 108 | } 109 | 110 | func (s postgres) CurrentDatabase() (name string) { 111 | s.db.QueryRow("SELECT CURRENT_DATABASE()").Scan(&name) 112 | return 113 | } 114 | 115 | func (s postgres) LastInsertIDReturningSuffix(tableName, key string) string { 116 | return fmt.Sprintf("RETURNING %v.%v", tableName, key) 117 | } 118 | 119 | func (postgres) SupportLastInsertID() bool { 120 | return false 121 | } 122 | 123 | func isUUID(value reflect.Value) bool { 124 | if value.Kind() != reflect.Array || value.Type().Len() != 16 { 125 | return false 126 | } 127 | typename := value.Type().Name() 128 | lower := strings.ToLower(typename) 129 | return "uuid" == lower || "guid" == lower 130 | } 131 | -------------------------------------------------------------------------------- /vendor/github.com/jinzhu/gorm/dialect_sqlite3.go: -------------------------------------------------------------------------------- 1 | package gorm 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "strings" 7 | "time" 8 | ) 9 | 10 | type sqlite3 struct { 11 | commonDialect 12 | } 13 | 14 | func init() { 15 | RegisterDialect("sqlite3", &sqlite3{}) 16 | } 17 | 18 | func (sqlite3) GetName() string { 19 | return "sqlite3" 20 | } 21 | 22 | // Get Data Type for Sqlite Dialect 23 | func (s *sqlite3) DataTypeOf(field *StructField) string { 24 | var dataValue, sqlType, size, additionalType = ParseFieldStructForDialect(field, s) 25 | 26 | if sqlType == "" { 27 | switch dataValue.Kind() { 28 | case reflect.Bool: 29 | sqlType = "bool" 30 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr: 31 | if field.IsPrimaryKey { 32 | field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT" 33 | sqlType = "integer primary key autoincrement" 34 | } else { 35 | sqlType = "integer" 36 | } 37 | case reflect.Int64, reflect.Uint64: 38 | if field.IsPrimaryKey { 39 | field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT" 40 | sqlType = "integer primary key autoincrement" 41 | } else { 42 | sqlType = "bigint" 43 | } 44 | case reflect.Float32, reflect.Float64: 45 | sqlType = "real" 46 | case reflect.String: 47 | if size > 0 && size < 65532 { 48 | sqlType = fmt.Sprintf("varchar(%d)", size) 49 | } else { 50 | sqlType = "text" 51 | } 52 | case reflect.Struct: 53 | if _, ok := dataValue.Interface().(time.Time); ok { 54 | sqlType = "datetime" 55 | } 56 | default: 57 | if IsByteArrayOrSlice(dataValue) { 58 | sqlType = "blob" 59 | } 60 | } 61 | } 62 | 63 | if sqlType == "" { 64 | panic(fmt.Sprintf("invalid sql type %s (%s) for sqlite3", dataValue.Type().Name(), dataValue.Kind().String())) 65 | } 66 | 67 | if strings.TrimSpace(additionalType) == "" { 68 | return sqlType 69 | } 70 | return fmt.Sprintf("%v %v", sqlType, additionalType) 71 | } 72 | 73 | func (s sqlite3) HasIndex(tableName string, indexName string) bool { 74 | var count int 75 | s.db.QueryRow(fmt.Sprintf("SELECT count(*) FROM sqlite_master WHERE tbl_name = ? AND sql LIKE '%%INDEX %v ON%%'", indexName), tableName).Scan(&count) 76 | return count > 0 77 | } 78 | 79 | func (s sqlite3) HasTable(tableName string) bool { 80 | var count int 81 | s.db.QueryRow("SELECT count(*) FROM sqlite_master WHERE type='table' AND name=?", tableName).Scan(&count) 82 | return count > 0 83 | } 84 | 85 | func (s sqlite3) HasColumn(tableName string, columnName string) bool { 86 | var count int 87 | s.db.QueryRow(fmt.Sprintf("SELECT count(*) FROM sqlite_master WHERE tbl_name = ? AND (sql LIKE '%%\"%v\" %%' OR sql LIKE '%%%v %%');\n", columnName, columnName), tableName).Scan(&count) 88 | return count > 0 89 | } 90 | 91 | func (s sqlite3) CurrentDatabase() (name string) { 92 | var ( 93 | ifaces = make([]interface{}, 3) 94 | pointers = make([]*string, 3) 95 | i int 96 | ) 97 | for i = 0; i < 3; i++ { 98 | ifaces[i] = &pointers[i] 99 | } 100 | if err := s.db.QueryRow("PRAGMA database_list").Scan(ifaces...); err != nil { 101 | return 102 | } 103 | if pointers[1] != nil { 104 | name = *pointers[1] 105 | } 106 | return 107 | } 108 | -------------------------------------------------------------------------------- /vendor/github.com/jinzhu/gorm/dialects/postgres/postgres.go: -------------------------------------------------------------------------------- 1 | package postgres 2 | 3 | import ( 4 | "database/sql" 5 | "database/sql/driver" 6 | 7 | _ "github.com/lib/pq" 8 | "github.com/lib/pq/hstore" 9 | ) 10 | 11 | type Hstore map[string]*string 12 | 13 | // Value get value of Hstore 14 | func (h Hstore) Value() (driver.Value, error) { 15 | hstore := hstore.Hstore{Map: map[string]sql.NullString{}} 16 | if len(h) == 0 { 17 | return nil, nil 18 | } 19 | 20 | for key, value := range h { 21 | var s sql.NullString 22 | if value != nil { 23 | s.String = *value 24 | s.Valid = true 25 | } 26 | hstore.Map[key] = s 27 | } 28 | return hstore.Value() 29 | } 30 | 31 | // Scan scan value into Hstore 32 | func (h *Hstore) Scan(value interface{}) error { 33 | hstore := hstore.Hstore{} 34 | 35 | if err := hstore.Scan(value); err != nil { 36 | return err 37 | } 38 | 39 | if len(hstore.Map) == 0 { 40 | return nil 41 | } 42 | 43 | *h = Hstore{} 44 | for k := range hstore.Map { 45 | if hstore.Map[k].Valid { 46 | s := hstore.Map[k].String 47 | (*h)[k] = &s 48 | } else { 49 | (*h)[k] = nil 50 | } 51 | } 52 | 53 | return nil 54 | } 55 | -------------------------------------------------------------------------------- /vendor/github.com/jinzhu/gorm/errors.go: -------------------------------------------------------------------------------- 1 | package gorm 2 | 3 | import ( 4 | "errors" 5 | "strings" 6 | ) 7 | 8 | var ( 9 | // ErrRecordNotFound record not found error, happens when haven't find any matched data when looking up with a struct 10 | ErrRecordNotFound = errors.New("record not found") 11 | // ErrInvalidSQL invalid SQL error, happens when you passed invalid SQL 12 | ErrInvalidSQL = errors.New("invalid SQL") 13 | // ErrInvalidTransaction invalid transaction when you are trying to `Commit` or `Rollback` 14 | ErrInvalidTransaction = errors.New("no valid transaction") 15 | // ErrCantStartTransaction can't start transaction when you are trying to start one with `Begin` 16 | ErrCantStartTransaction = errors.New("can't start transaction") 17 | // ErrUnaddressable unaddressable value 18 | ErrUnaddressable = errors.New("using unaddressable value") 19 | ) 20 | 21 | // Errors contains all happened errors 22 | type Errors []error 23 | 24 | // GetErrors gets all happened errors 25 | func (errs Errors) GetErrors() []error { 26 | return errs 27 | } 28 | 29 | // Add adds an error 30 | func (errs Errors) Add(newErrors ...error) Errors { 31 | for _, err := range newErrors { 32 | if errors, ok := err.(Errors); ok { 33 | errs = errs.Add(errors...) 34 | } else { 35 | ok = true 36 | for _, e := range errs { 37 | if err == e { 38 | ok = false 39 | } 40 | } 41 | if ok { 42 | errs = append(errs, err) 43 | } 44 | } 45 | } 46 | return errs 47 | } 48 | 49 | // Error format happened errors 50 | func (errs Errors) Error() string { 51 | var errors = []string{} 52 | for _, e := range errs { 53 | errors = append(errors, e.Error()) 54 | } 55 | return strings.Join(errors, "; ") 56 | } 57 | -------------------------------------------------------------------------------- /vendor/github.com/jinzhu/gorm/field.go: -------------------------------------------------------------------------------- 1 | package gorm 2 | 3 | import ( 4 | "database/sql" 5 | "errors" 6 | "fmt" 7 | "reflect" 8 | ) 9 | 10 | // Field model field definition 11 | type Field struct { 12 | *StructField 13 | IsBlank bool 14 | Field reflect.Value 15 | } 16 | 17 | // Set set a value to the field 18 | func (field *Field) Set(value interface{}) (err error) { 19 | if !field.Field.IsValid() { 20 | return errors.New("field value not valid") 21 | } 22 | 23 | if !field.Field.CanAddr() { 24 | return ErrUnaddressable 25 | } 26 | 27 | reflectValue, ok := value.(reflect.Value) 28 | if !ok { 29 | reflectValue = reflect.ValueOf(value) 30 | } 31 | 32 | fieldValue := field.Field 33 | if reflectValue.IsValid() { 34 | if reflectValue.Type().ConvertibleTo(fieldValue.Type()) { 35 | fieldValue.Set(reflectValue.Convert(fieldValue.Type())) 36 | } else { 37 | if fieldValue.Kind() == reflect.Ptr { 38 | if fieldValue.IsNil() { 39 | fieldValue.Set(reflect.New(field.Struct.Type.Elem())) 40 | } 41 | fieldValue = fieldValue.Elem() 42 | } 43 | 44 | if reflectValue.Type().ConvertibleTo(fieldValue.Type()) { 45 | fieldValue.Set(reflectValue.Convert(fieldValue.Type())) 46 | } else if scanner, ok := fieldValue.Addr().Interface().(sql.Scanner); ok { 47 | err = scanner.Scan(reflectValue.Interface()) 48 | } else { 49 | err = fmt.Errorf("could not convert argument of field %s from %s to %s", field.Name, reflectValue.Type(), fieldValue.Type()) 50 | } 51 | } 52 | } else { 53 | field.Field.Set(reflect.Zero(field.Field.Type())) 54 | } 55 | 56 | field.IsBlank = isBlank(field.Field) 57 | return err 58 | } 59 | -------------------------------------------------------------------------------- /vendor/github.com/jinzhu/gorm/interface.go: -------------------------------------------------------------------------------- 1 | package gorm 2 | 3 | import "database/sql" 4 | 5 | // SQLCommon is the minimal database connection functionality gorm requires. Implemented by *sql.DB. 6 | type SQLCommon interface { 7 | Exec(query string, args ...interface{}) (sql.Result, error) 8 | Prepare(query string) (*sql.Stmt, error) 9 | Query(query string, args ...interface{}) (*sql.Rows, error) 10 | QueryRow(query string, args ...interface{}) *sql.Row 11 | } 12 | 13 | type sqlDb interface { 14 | Begin() (*sql.Tx, error) 15 | } 16 | 17 | type sqlTx interface { 18 | Commit() error 19 | Rollback() error 20 | } 21 | -------------------------------------------------------------------------------- /vendor/github.com/jinzhu/gorm/join_table_handler.go: -------------------------------------------------------------------------------- 1 | package gorm 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | "strings" 8 | ) 9 | 10 | // JoinTableHandlerInterface is an interface for how to handle many2many relations 11 | type JoinTableHandlerInterface interface { 12 | // initialize join table handler 13 | Setup(relationship *Relationship, tableName string, source reflect.Type, destination reflect.Type) 14 | // Table return join table's table name 15 | Table(db *DB) string 16 | // Add create relationship in join table for source and destination 17 | Add(handler JoinTableHandlerInterface, db *DB, source interface{}, destination interface{}) error 18 | // Delete delete relationship in join table for sources 19 | Delete(handler JoinTableHandlerInterface, db *DB, sources ...interface{}) error 20 | // JoinWith query with `Join` conditions 21 | JoinWith(handler JoinTableHandlerInterface, db *DB, source interface{}) *DB 22 | // SourceForeignKeys return source foreign keys 23 | SourceForeignKeys() []JoinTableForeignKey 24 | // DestinationForeignKeys return destination foreign keys 25 | DestinationForeignKeys() []JoinTableForeignKey 26 | } 27 | 28 | // JoinTableForeignKey join table foreign key struct 29 | type JoinTableForeignKey struct { 30 | DBName string 31 | AssociationDBName string 32 | } 33 | 34 | // JoinTableSource is a struct that contains model type and foreign keys 35 | type JoinTableSource struct { 36 | ModelType reflect.Type 37 | ForeignKeys []JoinTableForeignKey 38 | } 39 | 40 | // JoinTableHandler default join table handler 41 | type JoinTableHandler struct { 42 | TableName string `sql:"-"` 43 | Source JoinTableSource `sql:"-"` 44 | Destination JoinTableSource `sql:"-"` 45 | } 46 | 47 | // SourceForeignKeys return source foreign keys 48 | func (s *JoinTableHandler) SourceForeignKeys() []JoinTableForeignKey { 49 | return s.Source.ForeignKeys 50 | } 51 | 52 | // DestinationForeignKeys return destination foreign keys 53 | func (s *JoinTableHandler) DestinationForeignKeys() []JoinTableForeignKey { 54 | return s.Destination.ForeignKeys 55 | } 56 | 57 | // Setup initialize a default join table handler 58 | func (s *JoinTableHandler) Setup(relationship *Relationship, tableName string, source reflect.Type, destination reflect.Type) { 59 | s.TableName = tableName 60 | 61 | s.Source = JoinTableSource{ModelType: source} 62 | s.Source.ForeignKeys = []JoinTableForeignKey{} 63 | for idx, dbName := range relationship.ForeignFieldNames { 64 | s.Source.ForeignKeys = append(s.Source.ForeignKeys, JoinTableForeignKey{ 65 | DBName: relationship.ForeignDBNames[idx], 66 | AssociationDBName: dbName, 67 | }) 68 | } 69 | 70 | s.Destination = JoinTableSource{ModelType: destination} 71 | s.Destination.ForeignKeys = []JoinTableForeignKey{} 72 | for idx, dbName := range relationship.AssociationForeignFieldNames { 73 | s.Destination.ForeignKeys = append(s.Destination.ForeignKeys, JoinTableForeignKey{ 74 | DBName: relationship.AssociationForeignDBNames[idx], 75 | AssociationDBName: dbName, 76 | }) 77 | } 78 | } 79 | 80 | // Table return join table's table name 81 | func (s JoinTableHandler) Table(db *DB) string { 82 | return s.TableName 83 | } 84 | 85 | func (s JoinTableHandler) getSearchMap(db *DB, sources ...interface{}) map[string]interface{} { 86 | values := map[string]interface{}{} 87 | 88 | for _, source := range sources { 89 | scope := db.NewScope(source) 90 | modelType := scope.GetModelStruct().ModelType 91 | 92 | if s.Source.ModelType == modelType { 93 | for _, foreignKey := range s.Source.ForeignKeys { 94 | if field, ok := scope.FieldByName(foreignKey.AssociationDBName); ok { 95 | values[foreignKey.DBName] = field.Field.Interface() 96 | } 97 | } 98 | } else if s.Destination.ModelType == modelType { 99 | for _, foreignKey := range s.Destination.ForeignKeys { 100 | if field, ok := scope.FieldByName(foreignKey.AssociationDBName); ok { 101 | values[foreignKey.DBName] = field.Field.Interface() 102 | } 103 | } 104 | } 105 | } 106 | return values 107 | } 108 | 109 | // Add create relationship in join table for source and destination 110 | func (s JoinTableHandler) Add(handler JoinTableHandlerInterface, db *DB, source interface{}, destination interface{}) error { 111 | scope := db.NewScope("") 112 | searchMap := s.getSearchMap(db, source, destination) 113 | 114 | var assignColumns, binVars, conditions []string 115 | var values []interface{} 116 | for key, value := range searchMap { 117 | assignColumns = append(assignColumns, scope.Quote(key)) 118 | binVars = append(binVars, `?`) 119 | conditions = append(conditions, fmt.Sprintf("%v = ?", scope.Quote(key))) 120 | values = append(values, value) 121 | } 122 | 123 | for _, value := range values { 124 | values = append(values, value) 125 | } 126 | 127 | quotedTable := scope.Quote(handler.Table(db)) 128 | sql := fmt.Sprintf( 129 | "INSERT INTO %v (%v) SELECT %v %v WHERE NOT EXISTS (SELECT * FROM %v WHERE %v)", 130 | quotedTable, 131 | strings.Join(assignColumns, ","), 132 | strings.Join(binVars, ","), 133 | scope.Dialect().SelectFromDummyTable(), 134 | quotedTable, 135 | strings.Join(conditions, " AND "), 136 | ) 137 | 138 | return db.Exec(sql, values...).Error 139 | } 140 | 141 | // Delete delete relationship in join table for sources 142 | func (s JoinTableHandler) Delete(handler JoinTableHandlerInterface, db *DB, sources ...interface{}) error { 143 | var ( 144 | scope = db.NewScope(nil) 145 | conditions []string 146 | values []interface{} 147 | ) 148 | 149 | for key, value := range s.getSearchMap(db, sources...) { 150 | conditions = append(conditions, fmt.Sprintf("%v = ?", scope.Quote(key))) 151 | values = append(values, value) 152 | } 153 | 154 | return db.Table(handler.Table(db)).Where(strings.Join(conditions, " AND "), values...).Delete("").Error 155 | } 156 | 157 | // JoinWith query with `Join` conditions 158 | func (s JoinTableHandler) JoinWith(handler JoinTableHandlerInterface, db *DB, source interface{}) *DB { 159 | var ( 160 | scope = db.NewScope(source) 161 | tableName = handler.Table(db) 162 | quotedTableName = scope.Quote(tableName) 163 | joinConditions []string 164 | values []interface{} 165 | ) 166 | 167 | if s.Source.ModelType == scope.GetModelStruct().ModelType { 168 | destinationTableName := db.NewScope(reflect.New(s.Destination.ModelType).Interface()).QuotedTableName() 169 | for _, foreignKey := range s.Destination.ForeignKeys { 170 | joinConditions = append(joinConditions, fmt.Sprintf("%v.%v = %v.%v", quotedTableName, scope.Quote(foreignKey.DBName), destinationTableName, scope.Quote(foreignKey.AssociationDBName))) 171 | } 172 | 173 | var foreignDBNames []string 174 | var foreignFieldNames []string 175 | 176 | for _, foreignKey := range s.Source.ForeignKeys { 177 | foreignDBNames = append(foreignDBNames, foreignKey.DBName) 178 | if field, ok := scope.FieldByName(foreignKey.AssociationDBName); ok { 179 | foreignFieldNames = append(foreignFieldNames, field.Name) 180 | } 181 | } 182 | 183 | foreignFieldValues := scope.getColumnAsArray(foreignFieldNames, scope.Value) 184 | 185 | var condString string 186 | if len(foreignFieldValues) > 0 { 187 | var quotedForeignDBNames []string 188 | for _, dbName := range foreignDBNames { 189 | quotedForeignDBNames = append(quotedForeignDBNames, tableName+"."+dbName) 190 | } 191 | 192 | condString = fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, quotedForeignDBNames), toQueryMarks(foreignFieldValues)) 193 | 194 | keys := scope.getColumnAsArray(foreignFieldNames, scope.Value) 195 | values = append(values, toQueryValues(keys)) 196 | } else { 197 | condString = fmt.Sprintf("1 <> 1") 198 | } 199 | 200 | return db.Joins(fmt.Sprintf("INNER JOIN %v ON %v", quotedTableName, strings.Join(joinConditions, " AND "))). 201 | Where(condString, toQueryValues(foreignFieldValues)...) 202 | } 203 | 204 | db.Error = errors.New("wrong source type for join table handler") 205 | return db 206 | } 207 | -------------------------------------------------------------------------------- /vendor/github.com/jinzhu/gorm/logger.go: -------------------------------------------------------------------------------- 1 | package gorm 2 | 3 | import ( 4 | "database/sql/driver" 5 | "fmt" 6 | "log" 7 | "os" 8 | "reflect" 9 | "regexp" 10 | "time" 11 | "unicode" 12 | ) 13 | 14 | var ( 15 | defaultLogger = Logger{log.New(os.Stdout, "\r\n", 0)} 16 | sqlRegexp = regexp.MustCompile(`\?`) 17 | numericPlaceHolderRegexp = regexp.MustCompile(`\$\d+`) 18 | ) 19 | 20 | func isPrintable(s string) bool { 21 | for _, r := range s { 22 | if !unicode.IsPrint(r) { 23 | return false 24 | } 25 | } 26 | return true 27 | } 28 | 29 | var LogFormatter = func(values ...interface{}) (messages []interface{}) { 30 | if len(values) > 1 { 31 | var ( 32 | sql string 33 | formattedValues []string 34 | level = values[0] 35 | currentTime = "\n\033[33m[" + NowFunc().Format("2006-01-02 15:04:05") + "]\033[0m" 36 | source = fmt.Sprintf("\033[35m(%v)\033[0m", values[1]) 37 | ) 38 | 39 | messages = []interface{}{source, currentTime} 40 | 41 | if level == "sql" { 42 | // duration 43 | messages = append(messages, fmt.Sprintf(" \033[36;1m[%.2fms]\033[0m ", float64(values[2].(time.Duration).Nanoseconds()/1e4)/100.0)) 44 | // sql 45 | 46 | for _, value := range values[4].([]interface{}) { 47 | indirectValue := reflect.Indirect(reflect.ValueOf(value)) 48 | if indirectValue.IsValid() { 49 | value = indirectValue.Interface() 50 | if t, ok := value.(time.Time); ok { 51 | formattedValues = append(formattedValues, fmt.Sprintf("'%v'", t.Format("2006-01-02 15:04:05"))) 52 | } else if b, ok := value.([]byte); ok { 53 | if str := string(b); isPrintable(str) { 54 | formattedValues = append(formattedValues, fmt.Sprintf("'%v'", str)) 55 | } else { 56 | formattedValues = append(formattedValues, "''") 57 | } 58 | } else if r, ok := value.(driver.Valuer); ok { 59 | if value, err := r.Value(); err == nil && value != nil { 60 | formattedValues = append(formattedValues, fmt.Sprintf("'%v'", value)) 61 | } else { 62 | formattedValues = append(formattedValues, "NULL") 63 | } 64 | } else { 65 | formattedValues = append(formattedValues, fmt.Sprintf("'%v'", value)) 66 | } 67 | } else { 68 | formattedValues = append(formattedValues, "NULL") 69 | } 70 | } 71 | 72 | // differentiate between $n placeholders or else treat like ? 73 | if numericPlaceHolderRegexp.MatchString(values[3].(string)) { 74 | sql = values[3].(string) 75 | for index, value := range formattedValues { 76 | placeholder := fmt.Sprintf(`\$%d([^\d]|$)`, index+1) 77 | sql = regexp.MustCompile(placeholder).ReplaceAllString(sql, value+"$1") 78 | } 79 | } else { 80 | formattedValuesLength := len(formattedValues) 81 | for index, value := range sqlRegexp.Split(values[3].(string), -1) { 82 | sql += value 83 | if index < formattedValuesLength { 84 | sql += formattedValues[index] 85 | } 86 | } 87 | } 88 | 89 | messages = append(messages, sql) 90 | } else { 91 | messages = append(messages, "\033[31;1m") 92 | messages = append(messages, values[2:]...) 93 | messages = append(messages, "\033[0m") 94 | } 95 | } 96 | 97 | return 98 | } 99 | 100 | type logger interface { 101 | Print(v ...interface{}) 102 | } 103 | 104 | // LogWriter log writer interface 105 | type LogWriter interface { 106 | Println(v ...interface{}) 107 | } 108 | 109 | // Logger default logger 110 | type Logger struct { 111 | LogWriter 112 | } 113 | 114 | // Print format & print log 115 | func (logger Logger) Print(values ...interface{}) { 116 | logger.Println(LogFormatter(values...)...) 117 | } 118 | -------------------------------------------------------------------------------- /vendor/github.com/jinzhu/gorm/model.go: -------------------------------------------------------------------------------- 1 | package gorm 2 | 3 | import "time" 4 | 5 | // Model base model definition, including fields `ID`, `CreatedAt`, `UpdatedAt`, `DeletedAt`, which could be embedded in your models 6 | // type User struct { 7 | // gorm.Model 8 | // } 9 | type Model struct { 10 | ID uint `gorm:"primary_key"` 11 | CreatedAt time.Time 12 | UpdatedAt time.Time 13 | DeletedAt *time.Time `sql:"index"` 14 | } 15 | -------------------------------------------------------------------------------- /vendor/github.com/jinzhu/gorm/search.go: -------------------------------------------------------------------------------- 1 | package gorm 2 | 3 | import ( 4 | "fmt" 5 | "regexp" 6 | ) 7 | 8 | type search struct { 9 | db *DB 10 | whereConditions []map[string]interface{} 11 | orConditions []map[string]interface{} 12 | notConditions []map[string]interface{} 13 | havingConditions []map[string]interface{} 14 | joinConditions []map[string]interface{} 15 | initAttrs []interface{} 16 | assignAttrs []interface{} 17 | selects map[string]interface{} 18 | omits []string 19 | orders []interface{} 20 | preload []searchPreload 21 | offset interface{} 22 | limit interface{} 23 | group string 24 | tableName string 25 | raw bool 26 | Unscoped bool 27 | ignoreOrderQuery bool 28 | } 29 | 30 | type searchPreload struct { 31 | schema string 32 | conditions []interface{} 33 | } 34 | 35 | func (s *search) clone() *search { 36 | clone := *s 37 | return &clone 38 | } 39 | 40 | func (s *search) Where(query interface{}, values ...interface{}) *search { 41 | s.whereConditions = append(s.whereConditions, map[string]interface{}{"query": query, "args": values}) 42 | return s 43 | } 44 | 45 | func (s *search) Not(query interface{}, values ...interface{}) *search { 46 | s.notConditions = append(s.notConditions, map[string]interface{}{"query": query, "args": values}) 47 | return s 48 | } 49 | 50 | func (s *search) Or(query interface{}, values ...interface{}) *search { 51 | s.orConditions = append(s.orConditions, map[string]interface{}{"query": query, "args": values}) 52 | return s 53 | } 54 | 55 | func (s *search) Attrs(attrs ...interface{}) *search { 56 | s.initAttrs = append(s.initAttrs, toSearchableMap(attrs...)) 57 | return s 58 | } 59 | 60 | func (s *search) Assign(attrs ...interface{}) *search { 61 | s.assignAttrs = append(s.assignAttrs, toSearchableMap(attrs...)) 62 | return s 63 | } 64 | 65 | func (s *search) Order(value interface{}, reorder ...bool) *search { 66 | if len(reorder) > 0 && reorder[0] { 67 | s.orders = []interface{}{} 68 | } 69 | 70 | if value != nil && value != "" { 71 | s.orders = append(s.orders, value) 72 | } 73 | return s 74 | } 75 | 76 | var distinctSQLRegexp = regexp.MustCompile(`(?i)distinct[^a-z]+[a-z]+`) 77 | 78 | func (s *search) Select(query interface{}, args ...interface{}) *search { 79 | if distinctSQLRegexp.MatchString(fmt.Sprint(query)) { 80 | s.ignoreOrderQuery = true 81 | } 82 | 83 | s.selects = map[string]interface{}{"query": query, "args": args} 84 | return s 85 | } 86 | 87 | func (s *search) Omit(columns ...string) *search { 88 | s.omits = columns 89 | return s 90 | } 91 | 92 | func (s *search) Limit(limit interface{}) *search { 93 | s.limit = limit 94 | return s 95 | } 96 | 97 | func (s *search) Offset(offset interface{}) *search { 98 | s.offset = offset 99 | return s 100 | } 101 | 102 | func (s *search) Group(query string) *search { 103 | s.group = s.getInterfaceAsSQL(query) 104 | return s 105 | } 106 | 107 | func (s *search) Having(query string, values ...interface{}) *search { 108 | s.havingConditions = append(s.havingConditions, map[string]interface{}{"query": query, "args": values}) 109 | return s 110 | } 111 | 112 | func (s *search) Joins(query string, values ...interface{}) *search { 113 | s.joinConditions = append(s.joinConditions, map[string]interface{}{"query": query, "args": values}) 114 | return s 115 | } 116 | 117 | func (s *search) Preload(schema string, values ...interface{}) *search { 118 | var preloads []searchPreload 119 | for _, preload := range s.preload { 120 | if preload.schema != schema { 121 | preloads = append(preloads, preload) 122 | } 123 | } 124 | preloads = append(preloads, searchPreload{schema, values}) 125 | s.preload = preloads 126 | return s 127 | } 128 | 129 | func (s *search) Raw(b bool) *search { 130 | s.raw = b 131 | return s 132 | } 133 | 134 | func (s *search) unscoped() *search { 135 | s.Unscoped = true 136 | return s 137 | } 138 | 139 | func (s *search) Table(name string) *search { 140 | s.tableName = name 141 | return s 142 | } 143 | 144 | func (s *search) getInterfaceAsSQL(value interface{}) (str string) { 145 | switch value.(type) { 146 | case string, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64: 147 | str = fmt.Sprintf("%v", value) 148 | default: 149 | s.db.AddError(ErrInvalidSQL) 150 | } 151 | 152 | if str == "-1" { 153 | return "" 154 | } 155 | return 156 | } 157 | -------------------------------------------------------------------------------- /vendor/github.com/jinzhu/gorm/test_all.sh: -------------------------------------------------------------------------------- 1 | dialects=("postgres" "mysql" "mssql" "sqlite") 2 | 3 | for dialect in "${dialects[@]}" ; do 4 | GORM_DIALECT=${dialect} go test 5 | done 6 | -------------------------------------------------------------------------------- /vendor/github.com/jinzhu/gorm/utils.go: -------------------------------------------------------------------------------- 1 | package gorm 2 | 3 | import ( 4 | "bytes" 5 | "database/sql/driver" 6 | "fmt" 7 | "reflect" 8 | "regexp" 9 | "runtime" 10 | "strings" 11 | "sync" 12 | "time" 13 | ) 14 | 15 | // NowFunc returns current time, this function is exported in order to be able 16 | // to give the flexibility to the developer to customize it according to their 17 | // needs, e.g: 18 | // gorm.NowFunc = func() time.Time { 19 | // return time.Now().UTC() 20 | // } 21 | var NowFunc = func() time.Time { 22 | return time.Now() 23 | } 24 | 25 | // Copied from golint 26 | var commonInitialisms = []string{"API", "ASCII", "CPU", "CSS", "DNS", "EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", "LHS", "QPS", "RAM", "RHS", "RPC", "SLA", "SMTP", "SSH", "TLS", "TTL", "UI", "UID", "UUID", "URI", "URL", "UTF8", "VM", "XML", "XSRF", "XSS"} 27 | var commonInitialismsReplacer *strings.Replacer 28 | 29 | var goSrcRegexp = regexp.MustCompile(`jinzhu/gorm/.*.go`) 30 | var goTestRegexp = regexp.MustCompile(`jinzhu/gorm/.*test.go`) 31 | 32 | func init() { 33 | var commonInitialismsForReplacer []string 34 | for _, initialism := range commonInitialisms { 35 | commonInitialismsForReplacer = append(commonInitialismsForReplacer, initialism, strings.Title(strings.ToLower(initialism))) 36 | } 37 | commonInitialismsReplacer = strings.NewReplacer(commonInitialismsForReplacer...) 38 | } 39 | 40 | type safeMap struct { 41 | m map[string]string 42 | l *sync.RWMutex 43 | } 44 | 45 | func (s *safeMap) Set(key string, value string) { 46 | s.l.Lock() 47 | defer s.l.Unlock() 48 | s.m[key] = value 49 | } 50 | 51 | func (s *safeMap) Get(key string) string { 52 | s.l.RLock() 53 | defer s.l.RUnlock() 54 | return s.m[key] 55 | } 56 | 57 | func newSafeMap() *safeMap { 58 | return &safeMap{l: new(sync.RWMutex), m: make(map[string]string)} 59 | } 60 | 61 | var smap = newSafeMap() 62 | 63 | type strCase bool 64 | 65 | const ( 66 | lower strCase = false 67 | upper strCase = true 68 | ) 69 | 70 | // ToDBName convert string to db name 71 | func ToDBName(name string) string { 72 | if v := smap.Get(name); v != "" { 73 | return v 74 | } 75 | 76 | if name == "" { 77 | return "" 78 | } 79 | 80 | var ( 81 | value = commonInitialismsReplacer.Replace(name) 82 | buf = bytes.NewBufferString("") 83 | lastCase, currCase, nextCase strCase 84 | ) 85 | 86 | for i, v := range value[:len(value)-1] { 87 | nextCase = strCase(value[i+1] >= 'A' && value[i+1] <= 'Z') 88 | if i > 0 { 89 | if currCase == upper { 90 | if lastCase == upper && nextCase == upper { 91 | buf.WriteRune(v) 92 | } else { 93 | if value[i-1] != '_' && value[i+1] != '_' { 94 | buf.WriteRune('_') 95 | } 96 | buf.WriteRune(v) 97 | } 98 | } else { 99 | buf.WriteRune(v) 100 | if i == len(value)-2 && nextCase == upper { 101 | buf.WriteRune('_') 102 | } 103 | } 104 | } else { 105 | currCase = upper 106 | buf.WriteRune(v) 107 | } 108 | lastCase = currCase 109 | currCase = nextCase 110 | } 111 | 112 | buf.WriteByte(value[len(value)-1]) 113 | 114 | s := strings.ToLower(buf.String()) 115 | smap.Set(name, s) 116 | return s 117 | } 118 | 119 | // SQL expression 120 | type expr struct { 121 | expr string 122 | args []interface{} 123 | } 124 | 125 | // Expr generate raw SQL expression, for example: 126 | // DB.Model(&product).Update("price", gorm.Expr("price * ? + ?", 2, 100)) 127 | func Expr(expression string, args ...interface{}) *expr { 128 | return &expr{expr: expression, args: args} 129 | } 130 | 131 | func indirect(reflectValue reflect.Value) reflect.Value { 132 | for reflectValue.Kind() == reflect.Ptr { 133 | reflectValue = reflectValue.Elem() 134 | } 135 | return reflectValue 136 | } 137 | 138 | func toQueryMarks(primaryValues [][]interface{}) string { 139 | var results []string 140 | 141 | for _, primaryValue := range primaryValues { 142 | var marks []string 143 | for range primaryValue { 144 | marks = append(marks, "?") 145 | } 146 | 147 | if len(marks) > 1 { 148 | results = append(results, fmt.Sprintf("(%v)", strings.Join(marks, ","))) 149 | } else { 150 | results = append(results, strings.Join(marks, "")) 151 | } 152 | } 153 | return strings.Join(results, ",") 154 | } 155 | 156 | func toQueryCondition(scope *Scope, columns []string) string { 157 | var newColumns []string 158 | for _, column := range columns { 159 | newColumns = append(newColumns, scope.Quote(column)) 160 | } 161 | 162 | if len(columns) > 1 { 163 | return fmt.Sprintf("(%v)", strings.Join(newColumns, ",")) 164 | } 165 | return strings.Join(newColumns, ",") 166 | } 167 | 168 | func toQueryValues(values [][]interface{}) (results []interface{}) { 169 | for _, value := range values { 170 | for _, v := range value { 171 | results = append(results, v) 172 | } 173 | } 174 | return 175 | } 176 | 177 | func fileWithLineNum() string { 178 | for i := 2; i < 15; i++ { 179 | _, file, line, ok := runtime.Caller(i) 180 | if ok && (!goSrcRegexp.MatchString(file) || goTestRegexp.MatchString(file)) { 181 | return fmt.Sprintf("%v:%v", file, line) 182 | } 183 | } 184 | return "" 185 | } 186 | 187 | func isBlank(value reflect.Value) bool { 188 | switch value.Kind() { 189 | case reflect.String: 190 | return value.Len() == 0 191 | case reflect.Bool: 192 | return !value.Bool() 193 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 194 | return value.Int() == 0 195 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 196 | return value.Uint() == 0 197 | case reflect.Float32, reflect.Float64: 198 | return value.Float() == 0 199 | case reflect.Interface, reflect.Ptr: 200 | return value.IsNil() 201 | } 202 | 203 | return reflect.DeepEqual(value.Interface(), reflect.Zero(value.Type()).Interface()) 204 | } 205 | 206 | func toSearchableMap(attrs ...interface{}) (result interface{}) { 207 | if len(attrs) > 1 { 208 | if str, ok := attrs[0].(string); ok { 209 | result = map[string]interface{}{str: attrs[1]} 210 | } 211 | } else if len(attrs) == 1 { 212 | if attr, ok := attrs[0].(map[string]interface{}); ok { 213 | result = attr 214 | } 215 | 216 | if attr, ok := attrs[0].(interface{}); ok { 217 | result = attr 218 | } 219 | } 220 | return 221 | } 222 | 223 | func equalAsString(a interface{}, b interface{}) bool { 224 | return toString(a) == toString(b) 225 | } 226 | 227 | func toString(str interface{}) string { 228 | if values, ok := str.([]interface{}); ok { 229 | var results []string 230 | for _, value := range values { 231 | results = append(results, toString(value)) 232 | } 233 | return strings.Join(results, "_") 234 | } else if bytes, ok := str.([]byte); ok { 235 | return string(bytes) 236 | } else if reflectValue := reflect.Indirect(reflect.ValueOf(str)); reflectValue.IsValid() { 237 | return fmt.Sprintf("%v", reflectValue.Interface()) 238 | } 239 | return "" 240 | } 241 | 242 | func makeSlice(elemType reflect.Type) interface{} { 243 | if elemType.Kind() == reflect.Slice { 244 | elemType = elemType.Elem() 245 | } 246 | sliceType := reflect.SliceOf(elemType) 247 | slice := reflect.New(sliceType) 248 | slice.Elem().Set(reflect.MakeSlice(sliceType, 0, 0)) 249 | return slice.Interface() 250 | } 251 | 252 | func strInSlice(a string, list []string) bool { 253 | for _, b := range list { 254 | if b == a { 255 | return true 256 | } 257 | } 258 | return false 259 | } 260 | 261 | // getValueFromFields return given fields's value 262 | func getValueFromFields(value reflect.Value, fieldNames []string) (results []interface{}) { 263 | // If value is a nil pointer, Indirect returns a zero Value! 264 | // Therefor we need to check for a zero value, 265 | // as FieldByName could panic 266 | if indirectValue := reflect.Indirect(value); indirectValue.IsValid() { 267 | for _, fieldName := range fieldNames { 268 | if fieldValue := indirectValue.FieldByName(fieldName); fieldValue.IsValid() { 269 | result := fieldValue.Interface() 270 | if r, ok := result.(driver.Valuer); ok { 271 | result, _ = r.Value() 272 | } 273 | results = append(results, result) 274 | } 275 | } 276 | } 277 | return 278 | } 279 | 280 | func addExtraSpaceIfExist(str string) string { 281 | if str != "" { 282 | return " " + str 283 | } 284 | return "" 285 | } 286 | -------------------------------------------------------------------------------- /vendor/github.com/jinzhu/gorm/wercker.yml: -------------------------------------------------------------------------------- 1 | # use the default golang container from Docker Hub 2 | box: golang 3 | 4 | services: 5 | - id: mariadb:10.0 6 | env: 7 | MYSQL_DATABASE: gorm 8 | MYSQL_USER: gorm 9 | MYSQL_PASSWORD: gorm 10 | MYSQL_RANDOM_ROOT_PASSWORD: "yes" 11 | - id: postgres 12 | env: 13 | POSTGRES_USER: gorm 14 | POSTGRES_PASSWORD: gorm 15 | POSTGRES_DB: gorm 16 | 17 | # The steps that will be executed in the build pipeline 18 | build: 19 | # The steps that will be executed on build 20 | steps: 21 | # Sets the go workspace and places you package 22 | # at the right place in the workspace tree 23 | - setup-go-workspace 24 | 25 | # Gets the dependencies 26 | - script: 27 | name: go get 28 | code: | 29 | cd $WERCKER_SOURCE_DIR 30 | go version 31 | go get -t ./... 32 | 33 | # Build the project 34 | - script: 35 | name: go build 36 | code: | 37 | go build ./... 38 | 39 | # Test the project 40 | - script: 41 | name: test sqlite 42 | code: | 43 | go test ./... 44 | 45 | - script: 46 | name: test mysql 47 | code: | 48 | GORM_DIALECT=mysql GORM_DBADDRESS=mariadb:3306 go test ./... 49 | 50 | - script: 51 | name: test postgres 52 | code: | 53 | GORM_DIALECT=postgres GORM_DBHOST=postgres go test ./... 54 | -------------------------------------------------------------------------------- /vendor/github.com/jinzhu/inflection/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 - Jinzhu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /vendor/github.com/jinzhu/inflection/README.md: -------------------------------------------------------------------------------- 1 | Inflection 2 | ========= 3 | 4 | Inflection pluralizes and singularizes English nouns 5 | 6 | ## Basic Usage 7 | 8 | ```go 9 | inflection.Plural("person") => "people" 10 | inflection.Plural("Person") => "People" 11 | inflection.Plural("PERSON") => "PEOPLE" 12 | inflection.Plural("bus") => "buses" 13 | inflection.Plural("BUS") => "BUSES" 14 | inflection.Plural("Bus") => "Buses" 15 | 16 | inflection.Singular("people") => "person" 17 | inflection.Singular("People") => "Person" 18 | inflection.Singular("PEOPLE") => "PERSON" 19 | inflection.Singular("buses") => "bus" 20 | inflection.Singular("BUSES") => "BUS" 21 | inflection.Singular("Buses") => "Bus" 22 | 23 | inflection.Plural("FancyPerson") => "FancyPeople" 24 | inflection.Singular("FancyPeople") => "FancyPerson" 25 | ``` 26 | 27 | ## Register Rules 28 | 29 | Standard rules are from Rails's ActiveSupport (https://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflections.rb) 30 | 31 | If you want to register more rules, follow: 32 | 33 | ``` 34 | inflection.AddUncountable("fish") 35 | inflection.AddIrregular("person", "people") 36 | inflection.AddPlural("(bu)s$", "${1}ses") # "bus" => "buses" / "BUS" => "BUSES" / "Bus" => "Buses" 37 | inflection.AddSingular("(bus)(es)?$", "${1}") # "buses" => "bus" / "Buses" => "Bus" / "BUSES" => "BUS" 38 | ``` 39 | 40 | ## Supporting the project 41 | 42 | [![http://patreon.com/jinzhu](http://patreon_public_assets.s3.amazonaws.com/sized/becomeAPatronBanner.png)](http://patreon.com/jinzhu) 43 | 44 | 45 | ## Author 46 | 47 | **jinzhu** 48 | 49 | * 50 | * 51 | * 52 | 53 | ## License 54 | 55 | Released under the [MIT License](http://www.opensource.org/licenses/MIT). 56 | -------------------------------------------------------------------------------- /vendor/github.com/jinzhu/inflection/inflections.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package inflection pluralizes and singularizes English nouns. 3 | 4 | inflection.Plural("person") => "people" 5 | inflection.Plural("Person") => "People" 6 | inflection.Plural("PERSON") => "PEOPLE" 7 | 8 | inflection.Singular("people") => "person" 9 | inflection.Singular("People") => "Person" 10 | inflection.Singular("PEOPLE") => "PERSON" 11 | 12 | inflection.Plural("FancyPerson") => "FancydPeople" 13 | inflection.Singular("FancyPeople") => "FancydPerson" 14 | 15 | Standard rules are from Rails's ActiveSupport (https://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflections.rb) 16 | 17 | If you want to register more rules, follow: 18 | 19 | inflection.AddUncountable("fish") 20 | inflection.AddIrregular("person", "people") 21 | inflection.AddPlural("(bu)s$", "${1}ses") # "bus" => "buses" / "BUS" => "BUSES" / "Bus" => "Buses" 22 | inflection.AddSingular("(bus)(es)?$", "${1}") # "buses" => "bus" / "Buses" => "Bus" / "BUSES" => "BUS" 23 | */ 24 | package inflection 25 | 26 | import ( 27 | "regexp" 28 | "strings" 29 | ) 30 | 31 | type inflection struct { 32 | regexp *regexp.Regexp 33 | replace string 34 | } 35 | 36 | // Regular is a regexp find replace inflection 37 | type Regular struct { 38 | find string 39 | replace string 40 | } 41 | 42 | // Irregular is a hard replace inflection, 43 | // containing both singular and plural forms 44 | type Irregular struct { 45 | singular string 46 | plural string 47 | } 48 | 49 | // RegularSlice is a slice of Regular inflections 50 | type RegularSlice []Regular 51 | 52 | // IrregularSlice is a slice of Irregular inflections 53 | type IrregularSlice []Irregular 54 | 55 | var pluralInflections = RegularSlice{ 56 | {"([a-z])$", "${1}s"}, 57 | {"s$", "s"}, 58 | {"^(ax|test)is$", "${1}es"}, 59 | {"(octop|vir)us$", "${1}i"}, 60 | {"(octop|vir)i$", "${1}i"}, 61 | {"(alias|status)$", "${1}es"}, 62 | {"(bu)s$", "${1}ses"}, 63 | {"(buffal|tomat)o$", "${1}oes"}, 64 | {"([ti])um$", "${1}a"}, 65 | {"([ti])a$", "${1}a"}, 66 | {"sis$", "ses"}, 67 | {"(?:([^f])fe|([lr])f)$", "${1}${2}ves"}, 68 | {"(hive)$", "${1}s"}, 69 | {"([^aeiouy]|qu)y$", "${1}ies"}, 70 | {"(x|ch|ss|sh)$", "${1}es"}, 71 | {"(matr|vert|ind)(?:ix|ex)$", "${1}ices"}, 72 | {"^(m|l)ouse$", "${1}ice"}, 73 | {"^(m|l)ice$", "${1}ice"}, 74 | {"^(ox)$", "${1}en"}, 75 | {"^(oxen)$", "${1}"}, 76 | {"(quiz)$", "${1}zes"}, 77 | } 78 | 79 | var singularInflections = RegularSlice{ 80 | {"s$", ""}, 81 | {"(ss)$", "${1}"}, 82 | {"(n)ews$", "${1}ews"}, 83 | {"([ti])a$", "${1}um"}, 84 | {"((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$", "${1}sis"}, 85 | {"(^analy)(sis|ses)$", "${1}sis"}, 86 | {"([^f])ves$", "${1}fe"}, 87 | {"(hive)s$", "${1}"}, 88 | {"(tive)s$", "${1}"}, 89 | {"([lr])ves$", "${1}f"}, 90 | {"([^aeiouy]|qu)ies$", "${1}y"}, 91 | {"(s)eries$", "${1}eries"}, 92 | {"(m)ovies$", "${1}ovie"}, 93 | {"(c)ookies$", "${1}ookie"}, 94 | {"(x|ch|ss|sh)es$", "${1}"}, 95 | {"^(m|l)ice$", "${1}ouse"}, 96 | {"(bus)(es)?$", "${1}"}, 97 | {"(o)es$", "${1}"}, 98 | {"(shoe)s$", "${1}"}, 99 | {"(cris|test)(is|es)$", "${1}is"}, 100 | {"^(a)x[ie]s$", "${1}xis"}, 101 | {"(octop|vir)(us|i)$", "${1}us"}, 102 | {"(alias|status)(es)?$", "${1}"}, 103 | {"^(ox)en", "${1}"}, 104 | {"(vert|ind)ices$", "${1}ex"}, 105 | {"(matr)ices$", "${1}ix"}, 106 | {"(quiz)zes$", "${1}"}, 107 | {"(database)s$", "${1}"}, 108 | } 109 | 110 | var irregularInflections = IrregularSlice{ 111 | {"person", "people"}, 112 | {"man", "men"}, 113 | {"child", "children"}, 114 | {"sex", "sexes"}, 115 | {"move", "moves"}, 116 | {"mombie", "mombies"}, 117 | } 118 | 119 | var uncountableInflections = []string{"equipment", "information", "rice", "money", "species", "series", "fish", "sheep", "jeans", "police"} 120 | 121 | var compiledPluralMaps []inflection 122 | var compiledSingularMaps []inflection 123 | 124 | func compile() { 125 | compiledPluralMaps = []inflection{} 126 | compiledSingularMaps = []inflection{} 127 | for _, uncountable := range uncountableInflections { 128 | inf := inflection{ 129 | regexp: regexp.MustCompile("^(?i)(" + uncountable + ")$"), 130 | replace: "${1}", 131 | } 132 | compiledPluralMaps = append(compiledPluralMaps, inf) 133 | compiledSingularMaps = append(compiledSingularMaps, inf) 134 | } 135 | 136 | for _, value := range irregularInflections { 137 | infs := []inflection{ 138 | inflection{regexp: regexp.MustCompile(strings.ToUpper(value.singular) + "$"), replace: strings.ToUpper(value.plural)}, 139 | inflection{regexp: regexp.MustCompile(strings.Title(value.singular) + "$"), replace: strings.Title(value.plural)}, 140 | inflection{regexp: regexp.MustCompile(value.singular + "$"), replace: value.plural}, 141 | } 142 | compiledPluralMaps = append(compiledPluralMaps, infs...) 143 | } 144 | 145 | for _, value := range irregularInflections { 146 | infs := []inflection{ 147 | inflection{regexp: regexp.MustCompile(strings.ToUpper(value.plural) + "$"), replace: strings.ToUpper(value.singular)}, 148 | inflection{regexp: regexp.MustCompile(strings.Title(value.plural) + "$"), replace: strings.Title(value.singular)}, 149 | inflection{regexp: regexp.MustCompile(value.plural + "$"), replace: value.singular}, 150 | } 151 | compiledSingularMaps = append(compiledSingularMaps, infs...) 152 | } 153 | 154 | for i := len(pluralInflections) - 1; i >= 0; i-- { 155 | value := pluralInflections[i] 156 | infs := []inflection{ 157 | inflection{regexp: regexp.MustCompile(strings.ToUpper(value.find)), replace: strings.ToUpper(value.replace)}, 158 | inflection{regexp: regexp.MustCompile(value.find), replace: value.replace}, 159 | inflection{regexp: regexp.MustCompile("(?i)" + value.find), replace: value.replace}, 160 | } 161 | compiledPluralMaps = append(compiledPluralMaps, infs...) 162 | } 163 | 164 | for i := len(singularInflections) - 1; i >= 0; i-- { 165 | value := singularInflections[i] 166 | infs := []inflection{ 167 | inflection{regexp: regexp.MustCompile(strings.ToUpper(value.find)), replace: strings.ToUpper(value.replace)}, 168 | inflection{regexp: regexp.MustCompile(value.find), replace: value.replace}, 169 | inflection{regexp: regexp.MustCompile("(?i)" + value.find), replace: value.replace}, 170 | } 171 | compiledSingularMaps = append(compiledSingularMaps, infs...) 172 | } 173 | } 174 | 175 | func init() { 176 | compile() 177 | } 178 | 179 | // AddPlural adds a plural inflection 180 | func AddPlural(find, replace string) { 181 | pluralInflections = append(pluralInflections, Regular{find, replace}) 182 | compile() 183 | } 184 | 185 | // AddSingular adds a singular inflection 186 | func AddSingular(find, replace string) { 187 | singularInflections = append(singularInflections, Regular{find, replace}) 188 | compile() 189 | } 190 | 191 | // AddIrregular adds an irregular inflection 192 | func AddIrregular(singular, plural string) { 193 | irregularInflections = append(irregularInflections, Irregular{singular, plural}) 194 | compile() 195 | } 196 | 197 | // AddUncountable adds an uncountable inflection 198 | func AddUncountable(values ...string) { 199 | uncountableInflections = append(uncountableInflections, values...) 200 | compile() 201 | } 202 | 203 | // GetPlural retrieves the plural inflection values 204 | func GetPlural() RegularSlice { 205 | plurals := make(RegularSlice, len(pluralInflections)) 206 | copy(plurals, pluralInflections) 207 | return plurals 208 | } 209 | 210 | // GetSingular retrieves the singular inflection values 211 | func GetSingular() RegularSlice { 212 | singulars := make(RegularSlice, len(singularInflections)) 213 | copy(singulars, singularInflections) 214 | return singulars 215 | } 216 | 217 | // GetIrregular retrieves the irregular inflection values 218 | func GetIrregular() IrregularSlice { 219 | irregular := make(IrregularSlice, len(irregularInflections)) 220 | copy(irregular, irregularInflections) 221 | return irregular 222 | } 223 | 224 | // GetUncountable retrieves the uncountable inflection values 225 | func GetUncountable() []string { 226 | uncountables := make([]string, len(uncountableInflections)) 227 | copy(uncountables, uncountableInflections) 228 | return uncountables 229 | } 230 | 231 | // SetPlural sets the plural inflections slice 232 | func SetPlural(inflections RegularSlice) { 233 | pluralInflections = inflections 234 | compile() 235 | } 236 | 237 | // SetSingular sets the singular inflections slice 238 | func SetSingular(inflections RegularSlice) { 239 | singularInflections = inflections 240 | compile() 241 | } 242 | 243 | // SetIrregular sets the irregular inflections slice 244 | func SetIrregular(inflections IrregularSlice) { 245 | irregularInflections = inflections 246 | compile() 247 | } 248 | 249 | // SetUncountable sets the uncountable inflections slice 250 | func SetUncountable(inflections []string) { 251 | uncountableInflections = inflections 252 | compile() 253 | } 254 | 255 | // Plural converts a word to its plural form 256 | func Plural(str string) string { 257 | for _, inflection := range compiledPluralMaps { 258 | if inflection.regexp.MatchString(str) { 259 | return inflection.regexp.ReplaceAllString(str, inflection.replace) 260 | } 261 | } 262 | return str 263 | } 264 | 265 | // Singular converts a word to its singular form 266 | func Singular(str string) string { 267 | for _, inflection := range compiledSingularMaps { 268 | if inflection.regexp.MatchString(str) { 269 | return inflection.regexp.ReplaceAllString(str, inflection.replace) 270 | } 271 | } 272 | return str 273 | } 274 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing to pq 2 | 3 | `pq` has a backlog of pull requests, but contributions are still very 4 | much welcome. You can help with patch review, submitting bug reports, 5 | or adding new functionality. There is no formal style guide, but 6 | please conform to the style of existing code and general Go formatting 7 | conventions when submitting patches. 8 | 9 | ### Patch review 10 | 11 | Help review existing open pull requests by commenting on the code or 12 | proposed functionality. 13 | 14 | ### Bug reports 15 | 16 | We appreciate any bug reports, but especially ones with self-contained 17 | (doesn't depend on code outside of pq), minimal (can't be simplified 18 | further) test cases. It's especially helpful if you can submit a pull 19 | request with just the failing test case (you'll probably want to 20 | pattern it after the tests in 21 | [conn_test.go](https://github.com/lib/pq/blob/master/conn_test.go). 22 | 23 | ### New functionality 24 | 25 | There are a number of pending patches for new functionality, so 26 | additional feature patches will take a while to merge. Still, patches 27 | are generally reviewed based on usefulness and complexity in addition 28 | to time-in-queue, so if you have a knockout idea, take a shot. Feel 29 | free to open an issue discussion your proposed patch beforehand. 30 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011-2013, 'pq' Contributors 2 | Portions Copyright (C) 2011 Blake Mizerany 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/README.md: -------------------------------------------------------------------------------- 1 | # pq - A pure Go postgres driver for Go's database/sql package 2 | 3 | [![Build Status](https://travis-ci.org/lib/pq.svg?branch=master)](https://travis-ci.org/lib/pq) 4 | 5 | ## Install 6 | 7 | go get github.com/lib/pq 8 | 9 | ## Docs 10 | 11 | For detailed documentation and basic usage examples, please see the package 12 | documentation at . 13 | 14 | ## Tests 15 | 16 | `go test` is used for testing. A running PostgreSQL server is 17 | required, with the ability to log in. The default database to connect 18 | to test with is "pqgotest," but it can be overridden using environment 19 | variables. 20 | 21 | Example: 22 | 23 | PGHOST=/run/postgresql go test github.com/lib/pq 24 | 25 | Optionally, a benchmark suite can be run as part of the tests: 26 | 27 | PGHOST=/run/postgresql go test -bench . 28 | 29 | ## Features 30 | 31 | * SSL 32 | * Handles bad connections for `database/sql` 33 | * Scan `time.Time` correctly (i.e. `timestamp[tz]`, `time[tz]`, `date`) 34 | * Scan binary blobs correctly (i.e. `bytea`) 35 | * Package for `hstore` support 36 | * COPY FROM support 37 | * pq.ParseURL for converting urls to connection strings for sql.Open. 38 | * Many libpq compatible environment variables 39 | * Unix socket support 40 | * Notifications: `LISTEN`/`NOTIFY` 41 | * pgpass support 42 | 43 | ## Future / Things you can help with 44 | 45 | * Better COPY FROM / COPY TO (see discussion in #181) 46 | 47 | ## Thank you (alphabetical) 48 | 49 | Some of these contributors are from the original library `bmizerany/pq.go` whose 50 | code still exists in here. 51 | 52 | * Andy Balholm (andybalholm) 53 | * Ben Berkert (benburkert) 54 | * Benjamin Heatwole (bheatwole) 55 | * Bill Mill (llimllib) 56 | * Bjørn Madsen (aeons) 57 | * Blake Gentry (bgentry) 58 | * Brad Fitzpatrick (bradfitz) 59 | * Charlie Melbye (cmelbye) 60 | * Chris Bandy (cbandy) 61 | * Chris Gilling (cgilling) 62 | * Chris Walsh (cwds) 63 | * Dan Sosedoff (sosedoff) 64 | * Daniel Farina (fdr) 65 | * Eric Chlebek (echlebek) 66 | * Eric Garrido (minusnine) 67 | * Eric Urban (hydrogen18) 68 | * Everyone at The Go Team 69 | * Evan Shaw (edsrzf) 70 | * Ewan Chou (coocood) 71 | * Fazal Majid (fazalmajid) 72 | * Federico Romero (federomero) 73 | * Fumin (fumin) 74 | * Gary Burd (garyburd) 75 | * Heroku (heroku) 76 | * James Pozdena (jpoz) 77 | * Jason McVetta (jmcvetta) 78 | * Jeremy Jay (pbnjay) 79 | * Joakim Sernbrant (serbaut) 80 | * John Gallagher (jgallagher) 81 | * Jonathan Rudenberg (titanous) 82 | * Joël Stemmer (jstemmer) 83 | * Kamil Kisiel (kisielk) 84 | * Kelly Dunn (kellydunn) 85 | * Keith Rarick (kr) 86 | * Kir Shatrov (kirs) 87 | * Lann Martin (lann) 88 | * Maciek Sakrejda (uhoh-itsmaciek) 89 | * Marc Brinkmann (mbr) 90 | * Marko Tiikkaja (johto) 91 | * Matt Newberry (MattNewberry) 92 | * Matt Robenolt (mattrobenolt) 93 | * Martin Olsen (martinolsen) 94 | * Mike Lewis (mikelikespie) 95 | * Nicolas Patry (Narsil) 96 | * Oliver Tonnhofer (olt) 97 | * Patrick Hayes (phayes) 98 | * Paul Hammond (paulhammond) 99 | * Ryan Smith (ryandotsmith) 100 | * Samuel Stauffer (samuel) 101 | * Timothée Peignier (cyberdelia) 102 | * Travis Cline (tmc) 103 | * TruongSinh Tran-Nguyen (truongsinh) 104 | * Yaismel Miranda (ympons) 105 | * notedit (notedit) 106 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/buf.go: -------------------------------------------------------------------------------- 1 | package pq 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | 7 | "github.com/lib/pq/oid" 8 | ) 9 | 10 | type readBuf []byte 11 | 12 | func (b *readBuf) int32() (n int) { 13 | n = int(int32(binary.BigEndian.Uint32(*b))) 14 | *b = (*b)[4:] 15 | return 16 | } 17 | 18 | func (b *readBuf) oid() (n oid.Oid) { 19 | n = oid.Oid(binary.BigEndian.Uint32(*b)) 20 | *b = (*b)[4:] 21 | return 22 | } 23 | 24 | // N.B: this is actually an unsigned 16-bit integer, unlike int32 25 | func (b *readBuf) int16() (n int) { 26 | n = int(binary.BigEndian.Uint16(*b)) 27 | *b = (*b)[2:] 28 | return 29 | } 30 | 31 | func (b *readBuf) string() string { 32 | i := bytes.IndexByte(*b, 0) 33 | if i < 0 { 34 | errorf("invalid message format; expected string terminator") 35 | } 36 | s := (*b)[:i] 37 | *b = (*b)[i+1:] 38 | return string(s) 39 | } 40 | 41 | func (b *readBuf) next(n int) (v []byte) { 42 | v = (*b)[:n] 43 | *b = (*b)[n:] 44 | return 45 | } 46 | 47 | func (b *readBuf) byte() byte { 48 | return b.next(1)[0] 49 | } 50 | 51 | type writeBuf struct { 52 | buf []byte 53 | pos int 54 | } 55 | 56 | func (b *writeBuf) int32(n int) { 57 | x := make([]byte, 4) 58 | binary.BigEndian.PutUint32(x, uint32(n)) 59 | b.buf = append(b.buf, x...) 60 | } 61 | 62 | func (b *writeBuf) int16(n int) { 63 | x := make([]byte, 2) 64 | binary.BigEndian.PutUint16(x, uint16(n)) 65 | b.buf = append(b.buf, x...) 66 | } 67 | 68 | func (b *writeBuf) string(s string) { 69 | b.buf = append(b.buf, (s + "\000")...) 70 | } 71 | 72 | func (b *writeBuf) byte(c byte) { 73 | b.buf = append(b.buf, c) 74 | } 75 | 76 | func (b *writeBuf) bytes(v []byte) { 77 | b.buf = append(b.buf, v...) 78 | } 79 | 80 | func (b *writeBuf) wrap() []byte { 81 | p := b.buf[b.pos:] 82 | binary.BigEndian.PutUint32(p, uint32(len(p))) 83 | return b.buf 84 | } 85 | 86 | func (b *writeBuf) next(c byte) { 87 | p := b.buf[b.pos:] 88 | binary.BigEndian.PutUint32(p, uint32(len(p))) 89 | b.pos = len(b.buf) + 1 90 | b.buf = append(b.buf, c, 0, 0, 0, 0) 91 | } 92 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/conn_go18.go: -------------------------------------------------------------------------------- 1 | // +build go1.8 2 | 3 | package pq 4 | 5 | import ( 6 | "context" 7 | "database/sql" 8 | "database/sql/driver" 9 | "fmt" 10 | "io" 11 | "io/ioutil" 12 | ) 13 | 14 | // Implement the "QueryerContext" interface 15 | func (cn *conn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) { 16 | list := make([]driver.Value, len(args)) 17 | for i, nv := range args { 18 | list[i] = nv.Value 19 | } 20 | finish := cn.watchCancel(ctx) 21 | r, err := cn.query(query, list) 22 | if err != nil { 23 | if finish != nil { 24 | finish() 25 | } 26 | return nil, err 27 | } 28 | r.finish = finish 29 | return r, nil 30 | } 31 | 32 | // Implement the "ExecerContext" interface 33 | func (cn *conn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) { 34 | list := make([]driver.Value, len(args)) 35 | for i, nv := range args { 36 | list[i] = nv.Value 37 | } 38 | 39 | if finish := cn.watchCancel(ctx); finish != nil { 40 | defer finish() 41 | } 42 | 43 | return cn.Exec(query, list) 44 | } 45 | 46 | // Implement the "ConnBeginTx" interface 47 | func (cn *conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) { 48 | var mode string 49 | 50 | switch sql.IsolationLevel(opts.Isolation) { 51 | case sql.LevelDefault: 52 | // Don't touch mode: use the server's default 53 | case sql.LevelReadUncommitted: 54 | mode = " ISOLATION LEVEL READ UNCOMMITTED" 55 | case sql.LevelReadCommitted: 56 | mode = " ISOLATION LEVEL READ COMMITTED" 57 | case sql.LevelRepeatableRead: 58 | mode = " ISOLATION LEVEL REPEATABLE READ" 59 | case sql.LevelSerializable: 60 | mode = " ISOLATION LEVEL SERIALIZABLE" 61 | default: 62 | return nil, fmt.Errorf("pq: isolation level not supported: %d", opts.Isolation) 63 | } 64 | 65 | if opts.ReadOnly { 66 | mode += " READ ONLY" 67 | } else { 68 | mode += " READ WRITE" 69 | } 70 | 71 | tx, err := cn.begin(mode) 72 | if err != nil { 73 | return nil, err 74 | } 75 | cn.txnFinish = cn.watchCancel(ctx) 76 | return tx, nil 77 | } 78 | 79 | func (cn *conn) watchCancel(ctx context.Context) func() { 80 | if done := ctx.Done(); done != nil { 81 | finished := make(chan struct{}) 82 | go func() { 83 | select { 84 | case <-done: 85 | _ = cn.cancel() 86 | finished <- struct{}{} 87 | case <-finished: 88 | } 89 | }() 90 | return func() { 91 | select { 92 | case <-finished: 93 | case finished <- struct{}{}: 94 | } 95 | } 96 | } 97 | return nil 98 | } 99 | 100 | func (cn *conn) cancel() error { 101 | c, err := dial(cn.dialer, cn.opts) 102 | if err != nil { 103 | return err 104 | } 105 | defer c.Close() 106 | 107 | { 108 | can := conn{ 109 | c: c, 110 | } 111 | can.ssl(cn.opts) 112 | 113 | w := can.writeBuf(0) 114 | w.int32(80877102) // cancel request code 115 | w.int32(cn.processID) 116 | w.int32(cn.secretKey) 117 | 118 | if err := can.sendStartupPacket(w); err != nil { 119 | return err 120 | } 121 | } 122 | 123 | // Read until EOF to ensure that the server received the cancel. 124 | { 125 | _, err := io.Copy(ioutil.Discard, c) 126 | return err 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/copy.go: -------------------------------------------------------------------------------- 1 | package pq 2 | 3 | import ( 4 | "database/sql/driver" 5 | "encoding/binary" 6 | "errors" 7 | "fmt" 8 | "sync" 9 | ) 10 | 11 | var ( 12 | errCopyInClosed = errors.New("pq: copyin statement has already been closed") 13 | errBinaryCopyNotSupported = errors.New("pq: only text format supported for COPY") 14 | errCopyToNotSupported = errors.New("pq: COPY TO is not supported") 15 | errCopyNotSupportedOutsideTxn = errors.New("pq: COPY is only allowed inside a transaction") 16 | errCopyInProgress = errors.New("pq: COPY in progress") 17 | ) 18 | 19 | // CopyIn creates a COPY FROM statement which can be prepared with 20 | // Tx.Prepare(). The target table should be visible in search_path. 21 | func CopyIn(table string, columns ...string) string { 22 | stmt := "COPY " + QuoteIdentifier(table) + " (" 23 | for i, col := range columns { 24 | if i != 0 { 25 | stmt += ", " 26 | } 27 | stmt += QuoteIdentifier(col) 28 | } 29 | stmt += ") FROM STDIN" 30 | return stmt 31 | } 32 | 33 | // CopyInSchema creates a COPY FROM statement which can be prepared with 34 | // Tx.Prepare(). 35 | func CopyInSchema(schema, table string, columns ...string) string { 36 | stmt := "COPY " + QuoteIdentifier(schema) + "." + QuoteIdentifier(table) + " (" 37 | for i, col := range columns { 38 | if i != 0 { 39 | stmt += ", " 40 | } 41 | stmt += QuoteIdentifier(col) 42 | } 43 | stmt += ") FROM STDIN" 44 | return stmt 45 | } 46 | 47 | type copyin struct { 48 | cn *conn 49 | buffer []byte 50 | rowData chan []byte 51 | done chan bool 52 | 53 | closed bool 54 | 55 | sync.Mutex // guards err 56 | err error 57 | } 58 | 59 | const ciBufferSize = 64 * 1024 60 | 61 | // flush buffer before the buffer is filled up and needs reallocation 62 | const ciBufferFlushSize = 63 * 1024 63 | 64 | func (cn *conn) prepareCopyIn(q string) (_ driver.Stmt, err error) { 65 | if !cn.isInTransaction() { 66 | return nil, errCopyNotSupportedOutsideTxn 67 | } 68 | 69 | ci := ©in{ 70 | cn: cn, 71 | buffer: make([]byte, 0, ciBufferSize), 72 | rowData: make(chan []byte), 73 | done: make(chan bool, 1), 74 | } 75 | // add CopyData identifier + 4 bytes for message length 76 | ci.buffer = append(ci.buffer, 'd', 0, 0, 0, 0) 77 | 78 | b := cn.writeBuf('Q') 79 | b.string(q) 80 | cn.send(b) 81 | 82 | awaitCopyInResponse: 83 | for { 84 | t, r := cn.recv1() 85 | switch t { 86 | case 'G': 87 | if r.byte() != 0 { 88 | err = errBinaryCopyNotSupported 89 | break awaitCopyInResponse 90 | } 91 | go ci.resploop() 92 | return ci, nil 93 | case 'H': 94 | err = errCopyToNotSupported 95 | break awaitCopyInResponse 96 | case 'E': 97 | err = parseError(r) 98 | case 'Z': 99 | if err == nil { 100 | ci.setBad() 101 | errorf("unexpected ReadyForQuery in response to COPY") 102 | } 103 | cn.processReadyForQuery(r) 104 | return nil, err 105 | default: 106 | ci.setBad() 107 | errorf("unknown response for copy query: %q", t) 108 | } 109 | } 110 | 111 | // something went wrong, abort COPY before we return 112 | b = cn.writeBuf('f') 113 | b.string(err.Error()) 114 | cn.send(b) 115 | 116 | for { 117 | t, r := cn.recv1() 118 | switch t { 119 | case 'c', 'C', 'E': 120 | case 'Z': 121 | // correctly aborted, we're done 122 | cn.processReadyForQuery(r) 123 | return nil, err 124 | default: 125 | ci.setBad() 126 | errorf("unknown response for CopyFail: %q", t) 127 | } 128 | } 129 | } 130 | 131 | func (ci *copyin) flush(buf []byte) { 132 | // set message length (without message identifier) 133 | binary.BigEndian.PutUint32(buf[1:], uint32(len(buf)-1)) 134 | 135 | _, err := ci.cn.c.Write(buf) 136 | if err != nil { 137 | panic(err) 138 | } 139 | } 140 | 141 | func (ci *copyin) resploop() { 142 | for { 143 | var r readBuf 144 | t, err := ci.cn.recvMessage(&r) 145 | if err != nil { 146 | ci.setBad() 147 | ci.setError(err) 148 | ci.done <- true 149 | return 150 | } 151 | switch t { 152 | case 'C': 153 | // complete 154 | case 'N': 155 | // NoticeResponse 156 | case 'Z': 157 | ci.cn.processReadyForQuery(&r) 158 | ci.done <- true 159 | return 160 | case 'E': 161 | err := parseError(&r) 162 | ci.setError(err) 163 | default: 164 | ci.setBad() 165 | ci.setError(fmt.Errorf("unknown response during CopyIn: %q", t)) 166 | ci.done <- true 167 | return 168 | } 169 | } 170 | } 171 | 172 | func (ci *copyin) setBad() { 173 | ci.Lock() 174 | ci.cn.bad = true 175 | ci.Unlock() 176 | } 177 | 178 | func (ci *copyin) isBad() bool { 179 | ci.Lock() 180 | b := ci.cn.bad 181 | ci.Unlock() 182 | return b 183 | } 184 | 185 | func (ci *copyin) isErrorSet() bool { 186 | ci.Lock() 187 | isSet := (ci.err != nil) 188 | ci.Unlock() 189 | return isSet 190 | } 191 | 192 | // setError() sets ci.err if one has not been set already. Caller must not be 193 | // holding ci.Mutex. 194 | func (ci *copyin) setError(err error) { 195 | ci.Lock() 196 | if ci.err == nil { 197 | ci.err = err 198 | } 199 | ci.Unlock() 200 | } 201 | 202 | func (ci *copyin) NumInput() int { 203 | return -1 204 | } 205 | 206 | func (ci *copyin) Query(v []driver.Value) (r driver.Rows, err error) { 207 | return nil, ErrNotSupported 208 | } 209 | 210 | // Exec inserts values into the COPY stream. The insert is asynchronous 211 | // and Exec can return errors from previous Exec calls to the same 212 | // COPY stmt. 213 | // 214 | // You need to call Exec(nil) to sync the COPY stream and to get any 215 | // errors from pending data, since Stmt.Close() doesn't return errors 216 | // to the user. 217 | func (ci *copyin) Exec(v []driver.Value) (r driver.Result, err error) { 218 | if ci.closed { 219 | return nil, errCopyInClosed 220 | } 221 | 222 | if ci.isBad() { 223 | return nil, driver.ErrBadConn 224 | } 225 | defer ci.cn.errRecover(&err) 226 | 227 | if ci.isErrorSet() { 228 | return nil, ci.err 229 | } 230 | 231 | if len(v) == 0 { 232 | return nil, ci.Close() 233 | } 234 | 235 | numValues := len(v) 236 | for i, value := range v { 237 | ci.buffer = appendEncodedText(&ci.cn.parameterStatus, ci.buffer, value) 238 | if i < numValues-1 { 239 | ci.buffer = append(ci.buffer, '\t') 240 | } 241 | } 242 | 243 | ci.buffer = append(ci.buffer, '\n') 244 | 245 | if len(ci.buffer) > ciBufferFlushSize { 246 | ci.flush(ci.buffer) 247 | // reset buffer, keep bytes for message identifier and length 248 | ci.buffer = ci.buffer[:5] 249 | } 250 | 251 | return driver.RowsAffected(0), nil 252 | } 253 | 254 | func (ci *copyin) Close() (err error) { 255 | if ci.closed { // Don't do anything, we're already closed 256 | return nil 257 | } 258 | ci.closed = true 259 | 260 | if ci.isBad() { 261 | return driver.ErrBadConn 262 | } 263 | defer ci.cn.errRecover(&err) 264 | 265 | if len(ci.buffer) > 0 { 266 | ci.flush(ci.buffer) 267 | } 268 | // Avoid touching the scratch buffer as resploop could be using it. 269 | err = ci.cn.sendSimpleMessage('c') 270 | if err != nil { 271 | return err 272 | } 273 | 274 | <-ci.done 275 | ci.cn.inCopy = false 276 | 277 | if ci.isErrorSet() { 278 | err = ci.err 279 | return err 280 | } 281 | return nil 282 | } 283 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package pq is a pure Go Postgres driver for the database/sql package. 3 | 4 | In most cases clients will use the database/sql package instead of 5 | using this package directly. For example: 6 | 7 | import ( 8 | "database/sql" 9 | 10 | _ "github.com/lib/pq" 11 | ) 12 | 13 | func main() { 14 | db, err := sql.Open("postgres", "user=pqgotest dbname=pqgotest sslmode=verify-full") 15 | if err != nil { 16 | log.Fatal(err) 17 | } 18 | 19 | age := 21 20 | rows, err := db.Query("SELECT name FROM users WHERE age = $1", age) 21 | … 22 | } 23 | 24 | You can also connect to a database using a URL. For example: 25 | 26 | db, err := sql.Open("postgres", "postgres://pqgotest:password@localhost/pqgotest?sslmode=verify-full") 27 | 28 | 29 | Connection String Parameters 30 | 31 | 32 | Similarly to libpq, when establishing a connection using pq you are expected to 33 | supply a connection string containing zero or more parameters. 34 | A subset of the connection parameters supported by libpq are also supported by pq. 35 | Additionally, pq also lets you specify run-time parameters (such as search_path or work_mem) 36 | directly in the connection string. This is different from libpq, which does not allow 37 | run-time parameters in the connection string, instead requiring you to supply 38 | them in the options parameter. 39 | 40 | For compatibility with libpq, the following special connection parameters are 41 | supported: 42 | 43 | * dbname - The name of the database to connect to 44 | * user - The user to sign in as 45 | * password - The user's password 46 | * host - The host to connect to. Values that start with / are for unix domain sockets. (default is localhost) 47 | * port - The port to bind to. (default is 5432) 48 | * sslmode - Whether or not to use SSL (default is require, this is not the default for libpq) 49 | * fallback_application_name - An application_name to fall back to if one isn't provided. 50 | * connect_timeout - Maximum wait for connection, in seconds. Zero or not specified means wait indefinitely. 51 | * sslcert - Cert file location. The file must contain PEM encoded data. 52 | * sslkey - Key file location. The file must contain PEM encoded data. 53 | * sslrootcert - The location of the root certificate file. The file must contain PEM encoded data. 54 | 55 | Valid values for sslmode are: 56 | 57 | * disable - No SSL 58 | * require - Always SSL (skip verification) 59 | * verify-ca - Always SSL (verify that the certificate presented by the server was signed by a trusted CA) 60 | * verify-full - Always SSL (verify that the certification presented by the server was signed by a trusted CA and the server host name matches the one in the certificate) 61 | 62 | See http://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING 63 | for more information about connection string parameters. 64 | 65 | Use single quotes for values that contain whitespace: 66 | 67 | "user=pqgotest password='with spaces'" 68 | 69 | A backslash will escape the next character in values: 70 | 71 | "user=space\ man password='it\'s valid' 72 | 73 | Note that the connection parameter client_encoding (which sets the 74 | text encoding for the connection) may be set but must be "UTF8", 75 | matching with the same rules as Postgres. It is an error to provide 76 | any other value. 77 | 78 | In addition to the parameters listed above, any run-time parameter that can be 79 | set at backend start time can be set in the connection string. For more 80 | information, see 81 | http://www.postgresql.org/docs/current/static/runtime-config.html. 82 | 83 | Most environment variables as specified at http://www.postgresql.org/docs/current/static/libpq-envars.html 84 | supported by libpq are also supported by pq. If any of the environment 85 | variables not supported by pq are set, pq will panic during connection 86 | establishment. Environment variables have a lower precedence than explicitly 87 | provided connection parameters. 88 | 89 | The pgpass mechanism as described in http://www.postgresql.org/docs/current/static/libpq-pgpass.html 90 | is supported, but on Windows PGPASSFILE must be specified explicitly. 91 | 92 | 93 | Queries 94 | 95 | 96 | database/sql does not dictate any specific format for parameter 97 | markers in query strings, and pq uses the Postgres-native ordinal markers, 98 | as shown above. The same marker can be reused for the same parameter: 99 | 100 | rows, err := db.Query(`SELECT name FROM users WHERE favorite_fruit = $1 101 | OR age BETWEEN $2 AND $2 + 3`, "orange", 64) 102 | 103 | pq does not support the LastInsertId() method of the Result type in database/sql. 104 | To return the identifier of an INSERT (or UPDATE or DELETE), use the Postgres 105 | RETURNING clause with a standard Query or QueryRow call: 106 | 107 | var userid int 108 | err := db.QueryRow(`INSERT INTO users(name, favorite_fruit, age) 109 | VALUES('beatrice', 'starfruit', 93) RETURNING id`).Scan(&userid) 110 | 111 | For more details on RETURNING, see the Postgres documentation: 112 | 113 | http://www.postgresql.org/docs/current/static/sql-insert.html 114 | http://www.postgresql.org/docs/current/static/sql-update.html 115 | http://www.postgresql.org/docs/current/static/sql-delete.html 116 | 117 | For additional instructions on querying see the documentation for the database/sql package. 118 | 119 | 120 | Data Types 121 | 122 | 123 | Parameters pass through driver.DefaultParameterConverter before they are handled 124 | by this package. When the binary_parameters connection option is enabled, 125 | []byte values are sent directly to the backend as data in binary format. 126 | 127 | This package returns the following types for values from the PostgreSQL backend: 128 | 129 | - integer types smallint, integer, and bigint are returned as int64 130 | - floating-point types real and double precision are returned as float64 131 | - character types char, varchar, and text are returned as string 132 | - temporal types date, time, timetz, timestamp, and timestamptz are returned as time.Time 133 | - the boolean type is returned as bool 134 | - the bytea type is returned as []byte 135 | 136 | All other types are returned directly from the backend as []byte values in text format. 137 | 138 | 139 | Errors 140 | 141 | 142 | pq may return errors of type *pq.Error which can be interrogated for error details: 143 | 144 | if err, ok := err.(*pq.Error); ok { 145 | fmt.Println("pq error:", err.Code.Name()) 146 | } 147 | 148 | See the pq.Error type for details. 149 | 150 | 151 | Bulk imports 152 | 153 | You can perform bulk imports by preparing a statement returned by pq.CopyIn (or 154 | pq.CopyInSchema) in an explicit transaction (sql.Tx). The returned statement 155 | handle can then be repeatedly "executed" to copy data into the target table. 156 | After all data has been processed you should call Exec() once with no arguments 157 | to flush all buffered data. Any call to Exec() might return an error which 158 | should be handled appropriately, but because of the internal buffering an error 159 | returned by Exec() might not be related to the data passed in the call that 160 | failed. 161 | 162 | CopyIn uses COPY FROM internally. It is not possible to COPY outside of an 163 | explicit transaction in pq. 164 | 165 | Usage example: 166 | 167 | txn, err := db.Begin() 168 | if err != nil { 169 | log.Fatal(err) 170 | } 171 | 172 | stmt, err := txn.Prepare(pq.CopyIn("users", "name", "age")) 173 | if err != nil { 174 | log.Fatal(err) 175 | } 176 | 177 | for _, user := range users { 178 | _, err = stmt.Exec(user.Name, int64(user.Age)) 179 | if err != nil { 180 | log.Fatal(err) 181 | } 182 | } 183 | 184 | _, err = stmt.Exec() 185 | if err != nil { 186 | log.Fatal(err) 187 | } 188 | 189 | err = stmt.Close() 190 | if err != nil { 191 | log.Fatal(err) 192 | } 193 | 194 | err = txn.Commit() 195 | if err != nil { 196 | log.Fatal(err) 197 | } 198 | 199 | 200 | Notifications 201 | 202 | 203 | PostgreSQL supports a simple publish/subscribe model over database 204 | connections. See http://www.postgresql.org/docs/current/static/sql-notify.html 205 | for more information about the general mechanism. 206 | 207 | To start listening for notifications, you first have to open a new connection 208 | to the database by calling NewListener. This connection can not be used for 209 | anything other than LISTEN / NOTIFY. Calling Listen will open a "notification 210 | channel"; once a notification channel is open, a notification generated on that 211 | channel will effect a send on the Listener.Notify channel. A notification 212 | channel will remain open until Unlisten is called, though connection loss might 213 | result in some notifications being lost. To solve this problem, Listener sends 214 | a nil pointer over the Notify channel any time the connection is re-established 215 | following a connection loss. The application can get information about the 216 | state of the underlying connection by setting an event callback in the call to 217 | NewListener. 218 | 219 | A single Listener can safely be used from concurrent goroutines, which means 220 | that there is often no need to create more than one Listener in your 221 | application. However, a Listener is always connected to a single database, so 222 | you will need to create a new Listener instance for every database you want to 223 | receive notifications in. 224 | 225 | The channel name in both Listen and Unlisten is case sensitive, and can contain 226 | any characters legal in an identifier (see 227 | http://www.postgresql.org/docs/current/static/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS 228 | for more information). Note that the channel name will be truncated to 63 229 | bytes by the PostgreSQL server. 230 | 231 | You can find a complete, working example of Listener usage at 232 | http://godoc.org/github.com/lib/pq/listen_example. 233 | 234 | */ 235 | package pq 236 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/hstore/hstore.go: -------------------------------------------------------------------------------- 1 | package hstore 2 | 3 | import ( 4 | "database/sql" 5 | "database/sql/driver" 6 | "strings" 7 | ) 8 | 9 | // A wrapper for transferring Hstore values back and forth easily. 10 | type Hstore struct { 11 | Map map[string]sql.NullString 12 | } 13 | 14 | // escapes and quotes hstore keys/values 15 | // s should be a sql.NullString or string 16 | func hQuote(s interface{}) string { 17 | var str string 18 | switch v := s.(type) { 19 | case sql.NullString: 20 | if !v.Valid { 21 | return "NULL" 22 | } 23 | str = v.String 24 | case string: 25 | str = v 26 | default: 27 | panic("not a string or sql.NullString") 28 | } 29 | 30 | str = strings.Replace(str, "\\", "\\\\", -1) 31 | return `"` + strings.Replace(str, "\"", "\\\"", -1) + `"` 32 | } 33 | 34 | // Scan implements the Scanner interface. 35 | // 36 | // Note h.Map is reallocated before the scan to clear existing values. If the 37 | // hstore column's database value is NULL, then h.Map is set to nil instead. 38 | func (h *Hstore) Scan(value interface{}) error { 39 | if value == nil { 40 | h.Map = nil 41 | return nil 42 | } 43 | h.Map = make(map[string]sql.NullString) 44 | var b byte 45 | pair := [][]byte{{}, {}} 46 | pi := 0 47 | inQuote := false 48 | didQuote := false 49 | sawSlash := false 50 | bindex := 0 51 | for bindex, b = range value.([]byte) { 52 | if sawSlash { 53 | pair[pi] = append(pair[pi], b) 54 | sawSlash = false 55 | continue 56 | } 57 | 58 | switch b { 59 | case '\\': 60 | sawSlash = true 61 | continue 62 | case '"': 63 | inQuote = !inQuote 64 | if !didQuote { 65 | didQuote = true 66 | } 67 | continue 68 | default: 69 | if !inQuote { 70 | switch b { 71 | case ' ', '\t', '\n', '\r': 72 | continue 73 | case '=': 74 | continue 75 | case '>': 76 | pi = 1 77 | didQuote = false 78 | continue 79 | case ',': 80 | s := string(pair[1]) 81 | if !didQuote && len(s) == 4 && strings.ToLower(s) == "null" { 82 | h.Map[string(pair[0])] = sql.NullString{String: "", Valid: false} 83 | } else { 84 | h.Map[string(pair[0])] = sql.NullString{String: string(pair[1]), Valid: true} 85 | } 86 | pair[0] = []byte{} 87 | pair[1] = []byte{} 88 | pi = 0 89 | continue 90 | } 91 | } 92 | } 93 | pair[pi] = append(pair[pi], b) 94 | } 95 | if bindex > 0 { 96 | s := string(pair[1]) 97 | if !didQuote && len(s) == 4 && strings.ToLower(s) == "null" { 98 | h.Map[string(pair[0])] = sql.NullString{String: "", Valid: false} 99 | } else { 100 | h.Map[string(pair[0])] = sql.NullString{String: string(pair[1]), Valid: true} 101 | } 102 | } 103 | return nil 104 | } 105 | 106 | // Value implements the driver Valuer interface. Note if h.Map is nil, the 107 | // database column value will be set to NULL. 108 | func (h Hstore) Value() (driver.Value, error) { 109 | if h.Map == nil { 110 | return nil, nil 111 | } 112 | parts := []string{} 113 | for key, val := range h.Map { 114 | thispart := hQuote(key) + "=>" + hQuote(val) 115 | parts = append(parts, thispart) 116 | } 117 | return []byte(strings.Join(parts, ",")), nil 118 | } 119 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/oid/doc.go: -------------------------------------------------------------------------------- 1 | // Package oid contains OID constants 2 | // as defined by the Postgres server. 3 | package oid 4 | 5 | // Oid is a Postgres Object ID. 6 | type Oid uint32 7 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/oid/types.go: -------------------------------------------------------------------------------- 1 | // generated by 'go run gen.go'; do not edit 2 | 3 | package oid 4 | 5 | const ( 6 | T_bool Oid = 16 7 | T_bytea Oid = 17 8 | T_char Oid = 18 9 | T_name Oid = 19 10 | T_int8 Oid = 20 11 | T_int2 Oid = 21 12 | T_int2vector Oid = 22 13 | T_int4 Oid = 23 14 | T_regproc Oid = 24 15 | T_text Oid = 25 16 | T_oid Oid = 26 17 | T_tid Oid = 27 18 | T_xid Oid = 28 19 | T_cid Oid = 29 20 | T_oidvector Oid = 30 21 | T_pg_ddl_command Oid = 32 22 | T_pg_type Oid = 71 23 | T_pg_attribute Oid = 75 24 | T_pg_proc Oid = 81 25 | T_pg_class Oid = 83 26 | T_json Oid = 114 27 | T_xml Oid = 142 28 | T__xml Oid = 143 29 | T_pg_node_tree Oid = 194 30 | T__json Oid = 199 31 | T_smgr Oid = 210 32 | T_index_am_handler Oid = 325 33 | T_point Oid = 600 34 | T_lseg Oid = 601 35 | T_path Oid = 602 36 | T_box Oid = 603 37 | T_polygon Oid = 604 38 | T_line Oid = 628 39 | T__line Oid = 629 40 | T_cidr Oid = 650 41 | T__cidr Oid = 651 42 | T_float4 Oid = 700 43 | T_float8 Oid = 701 44 | T_abstime Oid = 702 45 | T_reltime Oid = 703 46 | T_tinterval Oid = 704 47 | T_unknown Oid = 705 48 | T_circle Oid = 718 49 | T__circle Oid = 719 50 | T_money Oid = 790 51 | T__money Oid = 791 52 | T_macaddr Oid = 829 53 | T_inet Oid = 869 54 | T__bool Oid = 1000 55 | T__bytea Oid = 1001 56 | T__char Oid = 1002 57 | T__name Oid = 1003 58 | T__int2 Oid = 1005 59 | T__int2vector Oid = 1006 60 | T__int4 Oid = 1007 61 | T__regproc Oid = 1008 62 | T__text Oid = 1009 63 | T__tid Oid = 1010 64 | T__xid Oid = 1011 65 | T__cid Oid = 1012 66 | T__oidvector Oid = 1013 67 | T__bpchar Oid = 1014 68 | T__varchar Oid = 1015 69 | T__int8 Oid = 1016 70 | T__point Oid = 1017 71 | T__lseg Oid = 1018 72 | T__path Oid = 1019 73 | T__box Oid = 1020 74 | T__float4 Oid = 1021 75 | T__float8 Oid = 1022 76 | T__abstime Oid = 1023 77 | T__reltime Oid = 1024 78 | T__tinterval Oid = 1025 79 | T__polygon Oid = 1027 80 | T__oid Oid = 1028 81 | T_aclitem Oid = 1033 82 | T__aclitem Oid = 1034 83 | T__macaddr Oid = 1040 84 | T__inet Oid = 1041 85 | T_bpchar Oid = 1042 86 | T_varchar Oid = 1043 87 | T_date Oid = 1082 88 | T_time Oid = 1083 89 | T_timestamp Oid = 1114 90 | T__timestamp Oid = 1115 91 | T__date Oid = 1182 92 | T__time Oid = 1183 93 | T_timestamptz Oid = 1184 94 | T__timestamptz Oid = 1185 95 | T_interval Oid = 1186 96 | T__interval Oid = 1187 97 | T__numeric Oid = 1231 98 | T_pg_database Oid = 1248 99 | T__cstring Oid = 1263 100 | T_timetz Oid = 1266 101 | T__timetz Oid = 1270 102 | T_bit Oid = 1560 103 | T__bit Oid = 1561 104 | T_varbit Oid = 1562 105 | T__varbit Oid = 1563 106 | T_numeric Oid = 1700 107 | T_refcursor Oid = 1790 108 | T__refcursor Oid = 2201 109 | T_regprocedure Oid = 2202 110 | T_regoper Oid = 2203 111 | T_regoperator Oid = 2204 112 | T_regclass Oid = 2205 113 | T_regtype Oid = 2206 114 | T__regprocedure Oid = 2207 115 | T__regoper Oid = 2208 116 | T__regoperator Oid = 2209 117 | T__regclass Oid = 2210 118 | T__regtype Oid = 2211 119 | T_record Oid = 2249 120 | T_cstring Oid = 2275 121 | T_any Oid = 2276 122 | T_anyarray Oid = 2277 123 | T_void Oid = 2278 124 | T_trigger Oid = 2279 125 | T_language_handler Oid = 2280 126 | T_internal Oid = 2281 127 | T_opaque Oid = 2282 128 | T_anyelement Oid = 2283 129 | T__record Oid = 2287 130 | T_anynonarray Oid = 2776 131 | T_pg_authid Oid = 2842 132 | T_pg_auth_members Oid = 2843 133 | T__txid_snapshot Oid = 2949 134 | T_uuid Oid = 2950 135 | T__uuid Oid = 2951 136 | T_txid_snapshot Oid = 2970 137 | T_fdw_handler Oid = 3115 138 | T_pg_lsn Oid = 3220 139 | T__pg_lsn Oid = 3221 140 | T_tsm_handler Oid = 3310 141 | T_anyenum Oid = 3500 142 | T_tsvector Oid = 3614 143 | T_tsquery Oid = 3615 144 | T_gtsvector Oid = 3642 145 | T__tsvector Oid = 3643 146 | T__gtsvector Oid = 3644 147 | T__tsquery Oid = 3645 148 | T_regconfig Oid = 3734 149 | T__regconfig Oid = 3735 150 | T_regdictionary Oid = 3769 151 | T__regdictionary Oid = 3770 152 | T_jsonb Oid = 3802 153 | T__jsonb Oid = 3807 154 | T_anyrange Oid = 3831 155 | T_event_trigger Oid = 3838 156 | T_int4range Oid = 3904 157 | T__int4range Oid = 3905 158 | T_numrange Oid = 3906 159 | T__numrange Oid = 3907 160 | T_tsrange Oid = 3908 161 | T__tsrange Oid = 3909 162 | T_tstzrange Oid = 3910 163 | T__tstzrange Oid = 3911 164 | T_daterange Oid = 3912 165 | T__daterange Oid = 3913 166 | T_int8range Oid = 3926 167 | T__int8range Oid = 3927 168 | T_pg_shseclabel Oid = 4066 169 | T_regnamespace Oid = 4089 170 | T__regnamespace Oid = 4090 171 | T_regrole Oid = 4096 172 | T__regrole Oid = 4097 173 | ) 174 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/ssl.go: -------------------------------------------------------------------------------- 1 | package pq 2 | 3 | import ( 4 | "crypto/tls" 5 | "crypto/x509" 6 | "io/ioutil" 7 | "net" 8 | "os" 9 | "os/user" 10 | "path/filepath" 11 | ) 12 | 13 | // ssl generates a function to upgrade a net.Conn based on the "sslmode" and 14 | // related settings. The function is nil when no upgrade should take place. 15 | func ssl(o values) func(net.Conn) net.Conn { 16 | verifyCaOnly := false 17 | tlsConf := tls.Config{} 18 | switch mode := o["sslmode"]; mode { 19 | // "require" is the default. 20 | case "", "require": 21 | // We must skip TLS's own verification since it requires full 22 | // verification since Go 1.3. 23 | tlsConf.InsecureSkipVerify = true 24 | 25 | // From http://www.postgresql.org/docs/current/static/libpq-ssl.html: 26 | // 27 | // Note: For backwards compatibility with earlier versions of 28 | // PostgreSQL, if a root CA file exists, the behavior of 29 | // sslmode=require will be the same as that of verify-ca, meaning the 30 | // server certificate is validated against the CA. Relying on this 31 | // behavior is discouraged, and applications that need certificate 32 | // validation should always use verify-ca or verify-full. 33 | if sslrootcert, ok := o["sslrootcert"]; ok { 34 | if _, err := os.Stat(sslrootcert); err == nil { 35 | verifyCaOnly = true 36 | } else { 37 | delete(o, "sslrootcert") 38 | } 39 | } 40 | case "verify-ca": 41 | // We must skip TLS's own verification since it requires full 42 | // verification since Go 1.3. 43 | tlsConf.InsecureSkipVerify = true 44 | verifyCaOnly = true 45 | case "verify-full": 46 | tlsConf.ServerName = o["host"] 47 | case "disable": 48 | return nil 49 | default: 50 | errorf(`unsupported sslmode %q; only "require" (default), "verify-full", "verify-ca", and "disable" supported`, mode) 51 | } 52 | 53 | sslClientCertificates(&tlsConf, o) 54 | sslCertificateAuthority(&tlsConf, o) 55 | sslRenegotiation(&tlsConf) 56 | 57 | return func(conn net.Conn) net.Conn { 58 | client := tls.Client(conn, &tlsConf) 59 | if verifyCaOnly { 60 | sslVerifyCertificateAuthority(client, &tlsConf) 61 | } 62 | return client 63 | } 64 | } 65 | 66 | // sslClientCertificates adds the certificate specified in the "sslcert" and 67 | // "sslkey" settings, or if they aren't set, from the .postgresql directory 68 | // in the user's home directory. The configured files must exist and have 69 | // the correct permissions. 70 | func sslClientCertificates(tlsConf *tls.Config, o values) { 71 | // user.Current() might fail when cross-compiling. We have to ignore the 72 | // error and continue without home directory defaults, since we wouldn't 73 | // know from where to load them. 74 | user, _ := user.Current() 75 | 76 | // In libpq, the client certificate is only loaded if the setting is not blank. 77 | // 78 | // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1036-L1037 79 | sslcert := o["sslcert"] 80 | if len(sslcert) == 0 && user != nil { 81 | sslcert = filepath.Join(user.HomeDir, ".postgresql", "postgresql.crt") 82 | } 83 | // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1045 84 | if len(sslcert) == 0 { 85 | return 86 | } 87 | // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1050:L1054 88 | if _, err := os.Stat(sslcert); os.IsNotExist(err) { 89 | return 90 | } else if err != nil { 91 | panic(err) 92 | } 93 | 94 | // In libpq, the ssl key is only loaded if the setting is not blank. 95 | // 96 | // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1123-L1222 97 | sslkey := o["sslkey"] 98 | if len(sslkey) == 0 && user != nil { 99 | sslkey = filepath.Join(user.HomeDir, ".postgresql", "postgresql.key") 100 | } 101 | 102 | if len(sslkey) > 0 { 103 | if err := sslKeyPermissions(sslkey); err != nil { 104 | panic(err) 105 | } 106 | } 107 | 108 | cert, err := tls.LoadX509KeyPair(sslcert, sslkey) 109 | if err != nil { 110 | panic(err) 111 | } 112 | tlsConf.Certificates = []tls.Certificate{cert} 113 | } 114 | 115 | // sslCertificateAuthority adds the RootCA specified in the "sslrootcert" setting. 116 | func sslCertificateAuthority(tlsConf *tls.Config, o values) { 117 | // In libpq, the root certificate is only loaded if the setting is not blank. 118 | // 119 | // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L950-L951 120 | if sslrootcert := o["sslrootcert"]; len(sslrootcert) > 0 { 121 | tlsConf.RootCAs = x509.NewCertPool() 122 | 123 | cert, err := ioutil.ReadFile(sslrootcert) 124 | if err != nil { 125 | panic(err) 126 | } 127 | 128 | if !tlsConf.RootCAs.AppendCertsFromPEM(cert) { 129 | errorf("couldn't parse pem in sslrootcert") 130 | } 131 | } 132 | } 133 | 134 | // sslVerifyCertificateAuthority carries out a TLS handshake to the server and 135 | // verifies the presented certificate against the CA, i.e. the one specified in 136 | // sslrootcert or the system CA if sslrootcert was not specified. 137 | func sslVerifyCertificateAuthority(client *tls.Conn, tlsConf *tls.Config) { 138 | err := client.Handshake() 139 | if err != nil { 140 | panic(err) 141 | } 142 | certs := client.ConnectionState().PeerCertificates 143 | opts := x509.VerifyOptions{ 144 | DNSName: client.ConnectionState().ServerName, 145 | Intermediates: x509.NewCertPool(), 146 | Roots: tlsConf.RootCAs, 147 | } 148 | for i, cert := range certs { 149 | if i == 0 { 150 | continue 151 | } 152 | opts.Intermediates.AddCert(cert) 153 | } 154 | _, err = certs[0].Verify(opts) 155 | if err != nil { 156 | panic(err) 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/ssl_go1.7.go: -------------------------------------------------------------------------------- 1 | // +build go1.7 2 | 3 | package pq 4 | 5 | import "crypto/tls" 6 | 7 | // Accept renegotiation requests initiated by the backend. 8 | // 9 | // Renegotiation was deprecated then removed from PostgreSQL 9.5, but 10 | // the default configuration of older versions has it enabled. Redshift 11 | // also initiates renegotiations and cannot be reconfigured. 12 | func sslRenegotiation(conf *tls.Config) { 13 | conf.Renegotiation = tls.RenegotiateFreelyAsClient 14 | } 15 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/ssl_permissions.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package pq 4 | 5 | import "os" 6 | 7 | // sslKeyPermissions checks the permissions on user-supplied ssl key files. 8 | // The key file should have very little access. 9 | // 10 | // libpq does not check key file permissions on Windows. 11 | func sslKeyPermissions(sslkey string) error { 12 | info, err := os.Stat(sslkey) 13 | if err != nil { 14 | return err 15 | } 16 | if info.Mode().Perm()&0077 != 0 { 17 | return ErrSSLKeyHasWorldPermissions 18 | } 19 | return nil 20 | } 21 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/ssl_renegotiation.go: -------------------------------------------------------------------------------- 1 | // +build !go1.7 2 | 3 | package pq 4 | 5 | import "crypto/tls" 6 | 7 | // Renegotiation is not supported by crypto/tls until Go 1.7. 8 | func sslRenegotiation(*tls.Config) {} 9 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/ssl_windows.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package pq 4 | 5 | // sslKeyPermissions checks the permissions on user-supplied ssl key files. 6 | // The key file should have very little access. 7 | // 8 | // libpq does not check key file permissions on Windows. 9 | func sslKeyPermissions(string) error { return nil } 10 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/url.go: -------------------------------------------------------------------------------- 1 | package pq 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | nurl "net/url" 7 | "sort" 8 | "strings" 9 | ) 10 | 11 | // ParseURL no longer needs to be used by clients of this library since supplying a URL as a 12 | // connection string to sql.Open() is now supported: 13 | // 14 | // sql.Open("postgres", "postgres://bob:secret@1.2.3.4:5432/mydb?sslmode=verify-full") 15 | // 16 | // It remains exported here for backwards-compatibility. 17 | // 18 | // ParseURL converts a url to a connection string for driver.Open. 19 | // Example: 20 | // 21 | // "postgres://bob:secret@1.2.3.4:5432/mydb?sslmode=verify-full" 22 | // 23 | // converts to: 24 | // 25 | // "user=bob password=secret host=1.2.3.4 port=5432 dbname=mydb sslmode=verify-full" 26 | // 27 | // A minimal example: 28 | // 29 | // "postgres://" 30 | // 31 | // This will be blank, causing driver.Open to use all of the defaults 32 | func ParseURL(url string) (string, error) { 33 | u, err := nurl.Parse(url) 34 | if err != nil { 35 | return "", err 36 | } 37 | 38 | if u.Scheme != "postgres" && u.Scheme != "postgresql" { 39 | return "", fmt.Errorf("invalid connection protocol: %s", u.Scheme) 40 | } 41 | 42 | var kvs []string 43 | escaper := strings.NewReplacer(` `, `\ `, `'`, `\'`, `\`, `\\`) 44 | accrue := func(k, v string) { 45 | if v != "" { 46 | kvs = append(kvs, k+"="+escaper.Replace(v)) 47 | } 48 | } 49 | 50 | if u.User != nil { 51 | v := u.User.Username() 52 | accrue("user", v) 53 | 54 | v, _ = u.User.Password() 55 | accrue("password", v) 56 | } 57 | 58 | if host, port, err := net.SplitHostPort(u.Host); err != nil { 59 | accrue("host", u.Host) 60 | } else { 61 | accrue("host", host) 62 | accrue("port", port) 63 | } 64 | 65 | if u.Path != "" { 66 | accrue("dbname", u.Path[1:]) 67 | } 68 | 69 | q := u.Query() 70 | for k := range q { 71 | accrue(k, q.Get(k)) 72 | } 73 | 74 | sort.Strings(kvs) // Makes testing easier (not a performance concern) 75 | return strings.Join(kvs, " "), nil 76 | } 77 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/user_posix.go: -------------------------------------------------------------------------------- 1 | // Package pq is a pure Go Postgres driver for the database/sql package. 2 | 3 | // +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris rumprun 4 | 5 | package pq 6 | 7 | import ( 8 | "os" 9 | "os/user" 10 | ) 11 | 12 | func userCurrent() (string, error) { 13 | u, err := user.Current() 14 | if err == nil { 15 | return u.Username, nil 16 | } 17 | 18 | name := os.Getenv("USER") 19 | if name != "" { 20 | return name, nil 21 | } 22 | 23 | return "", ErrCouldNotDetectUsername 24 | } 25 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/user_windows.go: -------------------------------------------------------------------------------- 1 | // Package pq is a pure Go Postgres driver for the database/sql package. 2 | package pq 3 | 4 | import ( 5 | "path/filepath" 6 | "syscall" 7 | ) 8 | 9 | // Perform Windows user name lookup identically to libpq. 10 | // 11 | // The PostgreSQL code makes use of the legacy Win32 function 12 | // GetUserName, and that function has not been imported into stock Go. 13 | // GetUserNameEx is available though, the difference being that a 14 | // wider range of names are available. To get the output to be the 15 | // same as GetUserName, only the base (or last) component of the 16 | // result is returned. 17 | func userCurrent() (string, error) { 18 | pw_name := make([]uint16, 128) 19 | pwname_size := uint32(len(pw_name)) - 1 20 | err := syscall.GetUserNameEx(syscall.NameSamCompatible, &pw_name[0], &pwname_size) 21 | if err != nil { 22 | return "", ErrCouldNotDetectUsername 23 | } 24 | s := syscall.UTF16ToString(pw_name) 25 | u := filepath.Base(s) 26 | return u, nil 27 | } 28 | -------------------------------------------------------------------------------- /vendor/github.com/lib/pq/uuid.go: -------------------------------------------------------------------------------- 1 | package pq 2 | 3 | import ( 4 | "encoding/hex" 5 | "fmt" 6 | ) 7 | 8 | // decodeUUIDBinary interprets the binary format of a uuid, returning it in text format. 9 | func decodeUUIDBinary(src []byte) ([]byte, error) { 10 | if len(src) != 16 { 11 | return nil, fmt.Errorf("pq: unable to decode uuid; bad length: %d", len(src)) 12 | } 13 | 14 | dst := make([]byte, 36) 15 | dst[8], dst[13], dst[18], dst[23] = '-', '-', '-', '-' 16 | hex.Encode(dst[0:], src[0:4]) 17 | hex.Encode(dst[9:], src[4:6]) 18 | hex.Encode(dst[14:], src[6:8]) 19 | hex.Encode(dst[19:], src[8:10]) 20 | hex.Encode(dst[24:], src[10:16]) 21 | 22 | return dst, nil 23 | } 24 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/PATENTS: -------------------------------------------------------------------------------- 1 | Additional IP Rights Grant (Patents) 2 | 3 | "This implementation" means the copyrightable works distributed by 4 | Google as part of the Go project. 5 | 6 | Google hereby grants to You a perpetual, worldwide, non-exclusive, 7 | no-charge, royalty-free, irrevocable (except as stated in this section) 8 | patent license to make, have made, use, offer to sell, sell, import, 9 | transfer and otherwise run, modify and propagate the contents of this 10 | implementation of Go, where such license applies only to those patent 11 | claims, both currently owned or controlled by Google and acquired in 12 | the future, licensable by Google that are necessarily infringed by this 13 | implementation of Go. This grant does not include claims that would be 14 | infringed only as a consequence of further modification of this 15 | implementation. If you or your agent or exclusive licensee institute or 16 | order or agree to the institution of patent litigation against any 17 | entity (including a cross-claim or counterclaim in a lawsuit) alleging 18 | that this implementation of Go or any code incorporated within this 19 | implementation of Go constitutes direct or contributory patent 20 | infringement, or inducement of patent infringement, then any patent 21 | rights granted to you under this License for this implementation of Go 22 | shall terminate as of the date such litigation is filed. 23 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/bcrypt/base64.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package bcrypt 6 | 7 | import "encoding/base64" 8 | 9 | const alphabet = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" 10 | 11 | var bcEncoding = base64.NewEncoding(alphabet) 12 | 13 | func base64Encode(src []byte) []byte { 14 | n := bcEncoding.EncodedLen(len(src)) 15 | dst := make([]byte, n) 16 | bcEncoding.Encode(dst, src) 17 | for dst[n-1] == '=' { 18 | n-- 19 | } 20 | return dst[:n] 21 | } 22 | 23 | func base64Decode(src []byte) ([]byte, error) { 24 | numOfEquals := 4 - (len(src) % 4) 25 | for i := 0; i < numOfEquals; i++ { 26 | src = append(src, '=') 27 | } 28 | 29 | dst := make([]byte, bcEncoding.DecodedLen(len(src))) 30 | n, err := bcEncoding.Decode(dst, src) 31 | if err != nil { 32 | return nil, err 33 | } 34 | return dst[:n], nil 35 | } 36 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/bcrypt/bcrypt.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package bcrypt implements Provos and Mazières's bcrypt adaptive hashing 6 | // algorithm. See http://www.usenix.org/event/usenix99/provos/provos.pdf 7 | package bcrypt // import "golang.org/x/crypto/bcrypt" 8 | 9 | // The code is a port of Provos and Mazières's C implementation. 10 | import ( 11 | "crypto/rand" 12 | "crypto/subtle" 13 | "errors" 14 | "fmt" 15 | "io" 16 | "strconv" 17 | 18 | "golang.org/x/crypto/blowfish" 19 | ) 20 | 21 | const ( 22 | MinCost int = 4 // the minimum allowable cost as passed in to GenerateFromPassword 23 | MaxCost int = 31 // the maximum allowable cost as passed in to GenerateFromPassword 24 | DefaultCost int = 10 // the cost that will actually be set if a cost below MinCost is passed into GenerateFromPassword 25 | ) 26 | 27 | // The error returned from CompareHashAndPassword when a password and hash do 28 | // not match. 29 | var ErrMismatchedHashAndPassword = errors.New("crypto/bcrypt: hashedPassword is not the hash of the given password") 30 | 31 | // The error returned from CompareHashAndPassword when a hash is too short to 32 | // be a bcrypt hash. 33 | var ErrHashTooShort = errors.New("crypto/bcrypt: hashedSecret too short to be a bcrypted password") 34 | 35 | // The error returned from CompareHashAndPassword when a hash was created with 36 | // a bcrypt algorithm newer than this implementation. 37 | type HashVersionTooNewError byte 38 | 39 | func (hv HashVersionTooNewError) Error() string { 40 | return fmt.Sprintf("crypto/bcrypt: bcrypt algorithm version '%c' requested is newer than current version '%c'", byte(hv), majorVersion) 41 | } 42 | 43 | // The error returned from CompareHashAndPassword when a hash starts with something other than '$' 44 | type InvalidHashPrefixError byte 45 | 46 | func (ih InvalidHashPrefixError) Error() string { 47 | return fmt.Sprintf("crypto/bcrypt: bcrypt hashes must start with '$', but hashedSecret started with '%c'", byte(ih)) 48 | } 49 | 50 | type InvalidCostError int 51 | 52 | func (ic InvalidCostError) Error() string { 53 | return fmt.Sprintf("crypto/bcrypt: cost %d is outside allowed range (%d,%d)", int(ic), int(MinCost), int(MaxCost)) 54 | } 55 | 56 | const ( 57 | majorVersion = '2' 58 | minorVersion = 'a' 59 | maxSaltSize = 16 60 | maxCryptedHashSize = 23 61 | encodedSaltSize = 22 62 | encodedHashSize = 31 63 | minHashSize = 59 64 | ) 65 | 66 | // magicCipherData is an IV for the 64 Blowfish encryption calls in 67 | // bcrypt(). It's the string "OrpheanBeholderScryDoubt" in big-endian bytes. 68 | var magicCipherData = []byte{ 69 | 0x4f, 0x72, 0x70, 0x68, 70 | 0x65, 0x61, 0x6e, 0x42, 71 | 0x65, 0x68, 0x6f, 0x6c, 72 | 0x64, 0x65, 0x72, 0x53, 73 | 0x63, 0x72, 0x79, 0x44, 74 | 0x6f, 0x75, 0x62, 0x74, 75 | } 76 | 77 | type hashed struct { 78 | hash []byte 79 | salt []byte 80 | cost int // allowed range is MinCost to MaxCost 81 | major byte 82 | minor byte 83 | } 84 | 85 | // GenerateFromPassword returns the bcrypt hash of the password at the given 86 | // cost. If the cost given is less than MinCost, the cost will be set to 87 | // DefaultCost, instead. Use CompareHashAndPassword, as defined in this package, 88 | // to compare the returned hashed password with its cleartext version. 89 | func GenerateFromPassword(password []byte, cost int) ([]byte, error) { 90 | p, err := newFromPassword(password, cost) 91 | if err != nil { 92 | return nil, err 93 | } 94 | return p.Hash(), nil 95 | } 96 | 97 | // CompareHashAndPassword compares a bcrypt hashed password with its possible 98 | // plaintext equivalent. Returns nil on success, or an error on failure. 99 | func CompareHashAndPassword(hashedPassword, password []byte) error { 100 | p, err := newFromHash(hashedPassword) 101 | if err != nil { 102 | return err 103 | } 104 | 105 | otherHash, err := bcrypt(password, p.cost, p.salt) 106 | if err != nil { 107 | return err 108 | } 109 | 110 | otherP := &hashed{otherHash, p.salt, p.cost, p.major, p.minor} 111 | if subtle.ConstantTimeCompare(p.Hash(), otherP.Hash()) == 1 { 112 | return nil 113 | } 114 | 115 | return ErrMismatchedHashAndPassword 116 | } 117 | 118 | // Cost returns the hashing cost used to create the given hashed 119 | // password. When, in the future, the hashing cost of a password system needs 120 | // to be increased in order to adjust for greater computational power, this 121 | // function allows one to establish which passwords need to be updated. 122 | func Cost(hashedPassword []byte) (int, error) { 123 | p, err := newFromHash(hashedPassword) 124 | if err != nil { 125 | return 0, err 126 | } 127 | return p.cost, nil 128 | } 129 | 130 | func newFromPassword(password []byte, cost int) (*hashed, error) { 131 | if cost < MinCost { 132 | cost = DefaultCost 133 | } 134 | p := new(hashed) 135 | p.major = majorVersion 136 | p.minor = minorVersion 137 | 138 | err := checkCost(cost) 139 | if err != nil { 140 | return nil, err 141 | } 142 | p.cost = cost 143 | 144 | unencodedSalt := make([]byte, maxSaltSize) 145 | _, err = io.ReadFull(rand.Reader, unencodedSalt) 146 | if err != nil { 147 | return nil, err 148 | } 149 | 150 | p.salt = base64Encode(unencodedSalt) 151 | hash, err := bcrypt(password, p.cost, p.salt) 152 | if err != nil { 153 | return nil, err 154 | } 155 | p.hash = hash 156 | return p, err 157 | } 158 | 159 | func newFromHash(hashedSecret []byte) (*hashed, error) { 160 | if len(hashedSecret) < minHashSize { 161 | return nil, ErrHashTooShort 162 | } 163 | p := new(hashed) 164 | n, err := p.decodeVersion(hashedSecret) 165 | if err != nil { 166 | return nil, err 167 | } 168 | hashedSecret = hashedSecret[n:] 169 | n, err = p.decodeCost(hashedSecret) 170 | if err != nil { 171 | return nil, err 172 | } 173 | hashedSecret = hashedSecret[n:] 174 | 175 | // The "+2" is here because we'll have to append at most 2 '=' to the salt 176 | // when base64 decoding it in expensiveBlowfishSetup(). 177 | p.salt = make([]byte, encodedSaltSize, encodedSaltSize+2) 178 | copy(p.salt, hashedSecret[:encodedSaltSize]) 179 | 180 | hashedSecret = hashedSecret[encodedSaltSize:] 181 | p.hash = make([]byte, len(hashedSecret)) 182 | copy(p.hash, hashedSecret) 183 | 184 | return p, nil 185 | } 186 | 187 | func bcrypt(password []byte, cost int, salt []byte) ([]byte, error) { 188 | cipherData := make([]byte, len(magicCipherData)) 189 | copy(cipherData, magicCipherData) 190 | 191 | c, err := expensiveBlowfishSetup(password, uint32(cost), salt) 192 | if err != nil { 193 | return nil, err 194 | } 195 | 196 | for i := 0; i < 24; i += 8 { 197 | for j := 0; j < 64; j++ { 198 | c.Encrypt(cipherData[i:i+8], cipherData[i:i+8]) 199 | } 200 | } 201 | 202 | // Bug compatibility with C bcrypt implementations. We only encode 23 of 203 | // the 24 bytes encrypted. 204 | hsh := base64Encode(cipherData[:maxCryptedHashSize]) 205 | return hsh, nil 206 | } 207 | 208 | func expensiveBlowfishSetup(key []byte, cost uint32, salt []byte) (*blowfish.Cipher, error) { 209 | csalt, err := base64Decode(salt) 210 | if err != nil { 211 | return nil, err 212 | } 213 | 214 | // Bug compatibility with C bcrypt implementations. They use the trailing 215 | // NULL in the key string during expansion. 216 | // We copy the key to prevent changing the underlying array. 217 | ckey := append(key[:len(key):len(key)], 0) 218 | 219 | c, err := blowfish.NewSaltedCipher(ckey, csalt) 220 | if err != nil { 221 | return nil, err 222 | } 223 | 224 | var i, rounds uint64 225 | rounds = 1 << cost 226 | for i = 0; i < rounds; i++ { 227 | blowfish.ExpandKey(ckey, c) 228 | blowfish.ExpandKey(csalt, c) 229 | } 230 | 231 | return c, nil 232 | } 233 | 234 | func (p *hashed) Hash() []byte { 235 | arr := make([]byte, 60) 236 | arr[0] = '$' 237 | arr[1] = p.major 238 | n := 2 239 | if p.minor != 0 { 240 | arr[2] = p.minor 241 | n = 3 242 | } 243 | arr[n] = '$' 244 | n += 1 245 | copy(arr[n:], []byte(fmt.Sprintf("%02d", p.cost))) 246 | n += 2 247 | arr[n] = '$' 248 | n += 1 249 | copy(arr[n:], p.salt) 250 | n += encodedSaltSize 251 | copy(arr[n:], p.hash) 252 | n += encodedHashSize 253 | return arr[:n] 254 | } 255 | 256 | func (p *hashed) decodeVersion(sbytes []byte) (int, error) { 257 | if sbytes[0] != '$' { 258 | return -1, InvalidHashPrefixError(sbytes[0]) 259 | } 260 | if sbytes[1] > majorVersion { 261 | return -1, HashVersionTooNewError(sbytes[1]) 262 | } 263 | p.major = sbytes[1] 264 | n := 3 265 | if sbytes[2] != '$' { 266 | p.minor = sbytes[2] 267 | n++ 268 | } 269 | return n, nil 270 | } 271 | 272 | // sbytes should begin where decodeVersion left off. 273 | func (p *hashed) decodeCost(sbytes []byte) (int, error) { 274 | cost, err := strconv.Atoi(string(sbytes[0:2])) 275 | if err != nil { 276 | return -1, err 277 | } 278 | err = checkCost(cost) 279 | if err != nil { 280 | return -1, err 281 | } 282 | p.cost = cost 283 | return 3, nil 284 | } 285 | 286 | func (p *hashed) String() string { 287 | return fmt.Sprintf("&{hash: %#v, salt: %#v, cost: %d, major: %c, minor: %c}", string(p.hash), p.salt, p.cost, p.major, p.minor) 288 | } 289 | 290 | func checkCost(cost int) error { 291 | if cost < MinCost || cost > MaxCost { 292 | return InvalidCostError(cost) 293 | } 294 | return nil 295 | } 296 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/blowfish/block.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package blowfish 6 | 7 | // getNextWord returns the next big-endian uint32 value from the byte slice 8 | // at the given position in a circular manner, updating the position. 9 | func getNextWord(b []byte, pos *int) uint32 { 10 | var w uint32 11 | j := *pos 12 | for i := 0; i < 4; i++ { 13 | w = w<<8 | uint32(b[j]) 14 | j++ 15 | if j >= len(b) { 16 | j = 0 17 | } 18 | } 19 | *pos = j 20 | return w 21 | } 22 | 23 | // ExpandKey performs a key expansion on the given *Cipher. Specifically, it 24 | // performs the Blowfish algorithm's key schedule which sets up the *Cipher's 25 | // pi and substitution tables for calls to Encrypt. This is used, primarily, 26 | // by the bcrypt package to reuse the Blowfish key schedule during its 27 | // set up. It's unlikely that you need to use this directly. 28 | func ExpandKey(key []byte, c *Cipher) { 29 | j := 0 30 | for i := 0; i < 18; i++ { 31 | // Using inlined getNextWord for performance. 32 | var d uint32 33 | for k := 0; k < 4; k++ { 34 | d = d<<8 | uint32(key[j]) 35 | j++ 36 | if j >= len(key) { 37 | j = 0 38 | } 39 | } 40 | c.p[i] ^= d 41 | } 42 | 43 | var l, r uint32 44 | for i := 0; i < 18; i += 2 { 45 | l, r = encryptBlock(l, r, c) 46 | c.p[i], c.p[i+1] = l, r 47 | } 48 | 49 | for i := 0; i < 256; i += 2 { 50 | l, r = encryptBlock(l, r, c) 51 | c.s0[i], c.s0[i+1] = l, r 52 | } 53 | for i := 0; i < 256; i += 2 { 54 | l, r = encryptBlock(l, r, c) 55 | c.s1[i], c.s1[i+1] = l, r 56 | } 57 | for i := 0; i < 256; i += 2 { 58 | l, r = encryptBlock(l, r, c) 59 | c.s2[i], c.s2[i+1] = l, r 60 | } 61 | for i := 0; i < 256; i += 2 { 62 | l, r = encryptBlock(l, r, c) 63 | c.s3[i], c.s3[i+1] = l, r 64 | } 65 | } 66 | 67 | // This is similar to ExpandKey, but folds the salt during the key 68 | // schedule. While ExpandKey is essentially expandKeyWithSalt with an all-zero 69 | // salt passed in, reusing ExpandKey turns out to be a place of inefficiency 70 | // and specializing it here is useful. 71 | func expandKeyWithSalt(key []byte, salt []byte, c *Cipher) { 72 | j := 0 73 | for i := 0; i < 18; i++ { 74 | c.p[i] ^= getNextWord(key, &j) 75 | } 76 | 77 | j = 0 78 | var l, r uint32 79 | for i := 0; i < 18; i += 2 { 80 | l ^= getNextWord(salt, &j) 81 | r ^= getNextWord(salt, &j) 82 | l, r = encryptBlock(l, r, c) 83 | c.p[i], c.p[i+1] = l, r 84 | } 85 | 86 | for i := 0; i < 256; i += 2 { 87 | l ^= getNextWord(salt, &j) 88 | r ^= getNextWord(salt, &j) 89 | l, r = encryptBlock(l, r, c) 90 | c.s0[i], c.s0[i+1] = l, r 91 | } 92 | 93 | for i := 0; i < 256; i += 2 { 94 | l ^= getNextWord(salt, &j) 95 | r ^= getNextWord(salt, &j) 96 | l, r = encryptBlock(l, r, c) 97 | c.s1[i], c.s1[i+1] = l, r 98 | } 99 | 100 | for i := 0; i < 256; i += 2 { 101 | l ^= getNextWord(salt, &j) 102 | r ^= getNextWord(salt, &j) 103 | l, r = encryptBlock(l, r, c) 104 | c.s2[i], c.s2[i+1] = l, r 105 | } 106 | 107 | for i := 0; i < 256; i += 2 { 108 | l ^= getNextWord(salt, &j) 109 | r ^= getNextWord(salt, &j) 110 | l, r = encryptBlock(l, r, c) 111 | c.s3[i], c.s3[i+1] = l, r 112 | } 113 | } 114 | 115 | func encryptBlock(l, r uint32, c *Cipher) (uint32, uint32) { 116 | xl, xr := l, r 117 | xl ^= c.p[0] 118 | xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[1] 119 | xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[2] 120 | xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[3] 121 | xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[4] 122 | xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[5] 123 | xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[6] 124 | xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[7] 125 | xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[8] 126 | xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[9] 127 | xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[10] 128 | xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[11] 129 | xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[12] 130 | xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[13] 131 | xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[14] 132 | xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[15] 133 | xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[16] 134 | xr ^= c.p[17] 135 | return xr, xl 136 | } 137 | 138 | func decryptBlock(l, r uint32, c *Cipher) (uint32, uint32) { 139 | xl, xr := l, r 140 | xl ^= c.p[17] 141 | xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[16] 142 | xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[15] 143 | xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[14] 144 | xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[13] 145 | xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[12] 146 | xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[11] 147 | xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[10] 148 | xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[9] 149 | xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[8] 150 | xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[7] 151 | xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[6] 152 | xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[5] 153 | xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[4] 154 | xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[3] 155 | xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[2] 156 | xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[1] 157 | xr ^= c.p[0] 158 | return xr, xl 159 | } 160 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/blowfish/cipher.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package blowfish implements Bruce Schneier's Blowfish encryption algorithm. 6 | package blowfish // import "golang.org/x/crypto/blowfish" 7 | 8 | // The code is a port of Bruce Schneier's C implementation. 9 | // See https://www.schneier.com/blowfish.html. 10 | 11 | import "strconv" 12 | 13 | // The Blowfish block size in bytes. 14 | const BlockSize = 8 15 | 16 | // A Cipher is an instance of Blowfish encryption using a particular key. 17 | type Cipher struct { 18 | p [18]uint32 19 | s0, s1, s2, s3 [256]uint32 20 | } 21 | 22 | type KeySizeError int 23 | 24 | func (k KeySizeError) Error() string { 25 | return "crypto/blowfish: invalid key size " + strconv.Itoa(int(k)) 26 | } 27 | 28 | // NewCipher creates and returns a Cipher. 29 | // The key argument should be the Blowfish key, from 1 to 56 bytes. 30 | func NewCipher(key []byte) (*Cipher, error) { 31 | var result Cipher 32 | if k := len(key); k < 1 || k > 56 { 33 | return nil, KeySizeError(k) 34 | } 35 | initCipher(&result) 36 | ExpandKey(key, &result) 37 | return &result, nil 38 | } 39 | 40 | // NewSaltedCipher creates a returns a Cipher that folds a salt into its key 41 | // schedule. For most purposes, NewCipher, instead of NewSaltedCipher, is 42 | // sufficient and desirable. For bcrypt compatibility, the key can be over 56 43 | // bytes. 44 | func NewSaltedCipher(key, salt []byte) (*Cipher, error) { 45 | if len(salt) == 0 { 46 | return NewCipher(key) 47 | } 48 | var result Cipher 49 | if k := len(key); k < 1 { 50 | return nil, KeySizeError(k) 51 | } 52 | initCipher(&result) 53 | expandKeyWithSalt(key, salt, &result) 54 | return &result, nil 55 | } 56 | 57 | // BlockSize returns the Blowfish block size, 8 bytes. 58 | // It is necessary to satisfy the Block interface in the 59 | // package "crypto/cipher". 60 | func (c *Cipher) BlockSize() int { return BlockSize } 61 | 62 | // Encrypt encrypts the 8-byte buffer src using the key k 63 | // and stores the result in dst. 64 | // Note that for amounts of data larger than a block, 65 | // it is not safe to just call Encrypt on successive blocks; 66 | // instead, use an encryption mode like CBC (see crypto/cipher/cbc.go). 67 | func (c *Cipher) Encrypt(dst, src []byte) { 68 | l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3]) 69 | r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7]) 70 | l, r = encryptBlock(l, r, c) 71 | dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l) 72 | dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r) 73 | } 74 | 75 | // Decrypt decrypts the 8-byte buffer src using the key k 76 | // and stores the result in dst. 77 | func (c *Cipher) Decrypt(dst, src []byte) { 78 | l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3]) 79 | r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7]) 80 | l, r = decryptBlock(l, r, c) 81 | dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l) 82 | dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r) 83 | } 84 | 85 | func initCipher(c *Cipher) { 86 | copy(c.p[0:], p[0:]) 87 | copy(c.s0[0:], s0[0:]) 88 | copy(c.s1[0:], s1[0:]) 89 | copy(c.s2[0:], s2[0:]) 90 | copy(c.s3[0:], s3[0:]) 91 | } 92 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/blowfish/const.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // The startup permutation array and substitution boxes. 6 | // They are the hexadecimal digits of PI; see: 7 | // https://www.schneier.com/code/constants.txt. 8 | 9 | package blowfish 10 | 11 | var s0 = [256]uint32{ 12 | 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 13 | 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 14 | 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658, 15 | 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, 16 | 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 17 | 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 18 | 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6, 19 | 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, 20 | 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 21 | 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 22 | 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1, 23 | 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, 24 | 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 25 | 0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 26 | 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176, 27 | 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, 28 | 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 29 | 0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 30 | 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b, 31 | 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, 32 | 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 33 | 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 34 | 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a, 35 | 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, 36 | 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 37 | 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 38 | 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8, 39 | 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, 40 | 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 41 | 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 42 | 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0, 43 | 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, 44 | 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 45 | 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 46 | 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705, 47 | 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, 48 | 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 49 | 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 50 | 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9, 51 | 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, 52 | 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 53 | 0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 54 | 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a, 55 | } 56 | 57 | var s1 = [256]uint32{ 58 | 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 59 | 0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 60 | 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65, 61 | 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, 62 | 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 63 | 0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 64 | 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d, 65 | 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, 66 | 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 67 | 0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 68 | 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908, 69 | 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, 70 | 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 71 | 0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 72 | 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908, 73 | 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, 74 | 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 75 | 0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 76 | 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa, 77 | 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, 78 | 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 79 | 0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 80 | 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5, 81 | 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, 82 | 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 83 | 0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 84 | 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca, 85 | 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, 86 | 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 87 | 0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 88 | 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054, 89 | 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, 90 | 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 91 | 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 92 | 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646, 93 | 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, 94 | 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 95 | 0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 96 | 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e, 97 | 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, 98 | 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 99 | 0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 100 | 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7, 101 | } 102 | 103 | var s2 = [256]uint32{ 104 | 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 105 | 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 106 | 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af, 107 | 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, 108 | 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 109 | 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 110 | 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec, 111 | 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, 112 | 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 113 | 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 114 | 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58, 115 | 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, 116 | 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 117 | 0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 118 | 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60, 119 | 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, 120 | 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 121 | 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 122 | 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74, 123 | 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, 124 | 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 125 | 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 126 | 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979, 127 | 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, 128 | 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 129 | 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 130 | 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086, 131 | 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, 132 | 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 133 | 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 134 | 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84, 135 | 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, 136 | 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 137 | 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 138 | 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe, 139 | 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, 140 | 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 141 | 0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 142 | 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188, 143 | 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, 144 | 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 145 | 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 146 | 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0, 147 | } 148 | 149 | var s3 = [256]uint32{ 150 | 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 151 | 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 152 | 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79, 153 | 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, 154 | 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 155 | 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 156 | 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1, 157 | 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, 158 | 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 159 | 0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 160 | 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6, 161 | 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, 162 | 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 163 | 0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 164 | 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5, 165 | 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, 166 | 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 167 | 0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 168 | 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd, 169 | 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, 170 | 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 171 | 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 172 | 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc, 173 | 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, 174 | 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 175 | 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 176 | 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a, 177 | 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, 178 | 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 179 | 0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 180 | 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b, 181 | 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, 182 | 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 183 | 0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 184 | 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623, 185 | 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, 186 | 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 187 | 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 188 | 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3, 189 | 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, 190 | 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 191 | 0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 192 | 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6, 193 | } 194 | 195 | var p = [18]uint32{ 196 | 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0, 197 | 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, 198 | 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b, 199 | } 200 | -------------------------------------------------------------------------------- /vendor/vendor.json: -------------------------------------------------------------------------------- 1 | { 2 | "comment": "", 3 | "ignore": "test", 4 | "package": [ 5 | { 6 | "checksumSHA1": "IqQmIPZbwgzbZD4k7YX6Rj230pY=", 7 | "path": "github.com/jinzhu/gorm", 8 | "revision": "2a1463811ee1dc85d168fd639a2d4251d030e6e5", 9 | "revisionTime": "2017-07-03T13:49:54Z" 10 | }, 11 | { 12 | "checksumSHA1": "QmQW8snORAputB7/1jFXpsOZa8A=", 13 | "path": "github.com/jinzhu/gorm/dialects/postgres", 14 | "revision": "2a1463811ee1dc85d168fd639a2d4251d030e6e5", 15 | "revisionTime": "2017-07-03T13:49:54Z" 16 | }, 17 | { 18 | "checksumSHA1": "VIp1lZm6joWhlNdwhady8u//qRw=", 19 | "path": "github.com/jinzhu/inflection", 20 | "revision": "1c35d901db3da928c72a72d8458480cc9ade058f", 21 | "revisionTime": "2017-01-02T12:52:26Z" 22 | }, 23 | { 24 | "checksumSHA1": "ZAj/o03zG8Ui4mZ4XmzU4yyKC04=", 25 | "path": "github.com/lib/pq", 26 | "revision": "dd1fe2071026ce53f36a39112e645b4d4f5793a4", 27 | "revisionTime": "2017-07-07T05:36:02Z" 28 | }, 29 | { 30 | "checksumSHA1": "jaCQF1par6Jl8g+V2Cgp0n/0wSc=", 31 | "path": "github.com/lib/pq/hstore", 32 | "revision": "dd1fe2071026ce53f36a39112e645b4d4f5793a4", 33 | "revisionTime": "2017-07-07T05:36:02Z" 34 | }, 35 | { 36 | "checksumSHA1": "q5SZBWFVC3wOIzftf+l/h5WLG1k=", 37 | "path": "github.com/lib/pq/oid", 38 | "revision": "dd1fe2071026ce53f36a39112e645b4d4f5793a4", 39 | "revisionTime": "2017-07-07T05:36:02Z" 40 | }, 41 | { 42 | "checksumSHA1": "UWjVYmoHlIfHzVIskELHiJQtMOI=", 43 | "path": "golang.org/x/crypto/bcrypt", 44 | "revision": "6914964337150723782436d56b3f21610a74ce7b", 45 | "revisionTime": "2017-07-20T17:50:53Z" 46 | }, 47 | { 48 | "checksumSHA1": "oVPHWesOmZ02vLq2fglGvf+AMgk=", 49 | "path": "golang.org/x/crypto/blowfish", 50 | "revision": "6914964337150723782436d56b3f21610a74ce7b", 51 | "revisionTime": "2017-07-20T17:50:53Z" 52 | } 53 | ], 54 | "rootPath": "github.com/tamizhvendan/gomidway" 55 | } 56 | --------------------------------------------------------------------------------