Skip to content

Commit

Permalink
Merge branch 'jinzhu/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
hb-chen committed Mar 2, 2018
2 parents 5f8eb3e + 6ed508e commit 3683d88
Show file tree
Hide file tree
Showing 33 changed files with 1,206 additions and 336 deletions.
21 changes: 6 additions & 15 deletions .github/ISSUE_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
Before posting a bug report about a problem, please try to verify that it is a bug and that it has not been reported already, please apply corresponding GitHub labels to the issue, for feature requests, please apply `type:feature`.

DON'T post usage related questions, ask in https://gitter.im/jinzhu/gorm or http://stackoverflow.com/questions/tagged/go-gorm,

Please answer these questions before submitting your issue. Thanks!


Your issue may already be reported! Please search on the [issue track](https://github.com/jinzhu/gorm/issues) before creating one.

### What version of Go are you using (`go version`)?


### Which database and its version are you using?


### What did you do?
### Please provide a complete runnable program to reproduce your issue. **IMPORTANT**

Please provide a complete runnable program to reproduce your issue.
Need to runnable with [GORM's docker compose config](https://github.com/jinzhu/gorm/blob/master/docker-compose.yml) or please provides your config.

```go
package main
Expand All @@ -32,19 +26,16 @@ var db *gorm.DB
func init() {
var err error
db, err = gorm.Open("sqlite3", "test.db")
// Please use below username, password as your database's account for the script.
// db, err = gorm.Open("postgres", "user=gorm dbname=gorm sslmode=disable")
// db, err = gorm.Open("mysql", "gorm:gorm@/dbname?charset=utf8&parseTime=True")
// db, err = gorm.Open("mssql", "sqlserver://gorm:LoremIpsum86@localhost:1433?database=gorm")
// db, err = gorm.Open("postgres", "user=gorm password=gorm DB.name=gorm port=9920 sslmode=disable")
// db, err = gorm.Open("mysql", "gorm:gorm@tcp(localhost:9910)/gorm?charset=utf8&parseTime=True")
// db, err = gorm.Open("mssql", "sqlserver://gorm:LoremIpsum86@localhost:9930?database=gorm")
if err != nil {
panic(err)
}
db.LogMode(true)
}

func main() {
// your code here

if /* failure condition */ {
fmt.Println("failed")
} else {
Expand Down
7 changes: 1 addition & 6 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,7 @@ Make sure these boxes checked before submitting your pull request.
- [] Do only one thing
- [] No API-breaking changes
- [] New code/logic commented & tested
- [] Write good commit message, try to squash your commits into a single one
- [] Run `./build.sh` in `gh-pages` branch for document changes

For significant changes like big bug fixes, new features, please open an issue to make a agreement on an implementation design/plan first before starting it.

Thank you.

For significant changes like big bug fixes, new features, please open an issue to make an agreement on an implementation design/plan first before starting it.

### What did this pull request do?
35 changes: 12 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@

The fantastic ORM library for Golang, aims to be developer friendly.

[![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)
[![go report card](https://goreportcard.com/badge/github.com/jinzhu/gorm "go report card")](https://goreportcard.com/report/github.com/jinzhu/gorm)
[![wercker status](https://app.wercker.com/status/0cb7bb1039e21b74f8274941428e0921/s/master "wercker status")](https://app.wercker.com/project/bykey/0cb7bb1039e21b74f8274941428e0921)
[![wercker status](https://app.wercker.com/status/8596cace912c9947dd9c8542ecc8cb8b/s/master "wercker status")](https://app.wercker.com/project/byKey/8596cace912c9947dd9c8542ecc8cb8b)
[![Join the chat at https://gitter.im/jinzhu/gorm](https://img.shields.io/gitter/room/jinzhu/gorm.svg)](https://gitter.im/jinzhu/gorm?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Open Collective Backer](https://opencollective.com/gorm/tiers/backer/badge.svg?label=backer&color=brightgreen "Open Collective Backer")](https://opencollective.com/gorm)
[![Open Collective Sponsor](https://opencollective.com/gorm/tiers/sponsor/badge.svg?label=sponsor&color=brightgreen "Open Collective Sponsor")](https://opencollective.com/gorm)
[![MIT license](http://img.shields.io/badge/license-MIT-brightgreen.svg)](http://opensource.org/licenses/MIT)
[![GoDoc](https://godoc.org/github.com/jinzhu/gorm?status.svg)](https://godoc.org/github.com/jinzhu/gorm)

## Overview

* Full-Featured ORM (almost)
* Associations (Has One, Has Many, Belongs To, Many To Many, Polymorphism)
* Callbacks (Before/After Create/Save/Update/Delete/Find)
* Hooks (Before/After Create/Save/Update/Delete/Find)
* Preloading (eager loading)
* Transactions
* Composite Primary Key
Expand All @@ -24,28 +27,14 @@ The fantastic ORM library for Golang, aims to be developer friendly.

## Getting Started

* GORM Guides [jinzhu.github.com/gorm](http://jinzhu.github.io/gorm)
* GORM Guides [http://gorm.io](http://gorm.io)

## Upgrading To V1.0
## Contributing

* [CHANGELOG](http://jinzhu.github.io/gorm/changelog.html)

## Supporting the project

[![http://patreon.com/jinzhu](https://c5.patreon.com/external/logo/become_a_patron_button.png)](http://patreon.com/jinzhu)

## Author

**jinzhu**

* <http://github.com/jinzhu>
* <[email protected]>
* <http://twitter.com/zhangjinzhu>

## Contributors

https://github.com/jinzhu/gorm/graphs/contributors
[You can help to deliver a better GORM, check out things you can do](http://gorm.io/contribute.html)

## License

Released under the [MIT License](https://github.com/jinzhu/gorm/blob/master/License).
© Jinzhu, 2013~time.Now

Released under the [MIT License](https://github.com/jinzhu/gorm/blob/master/License)
4 changes: 2 additions & 2 deletions association.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ func (association *Association) Replace(values ...interface{}) *Association {
if sourcePrimaryKeys := scope.getColumnAsArray(sourceForeignFieldNames, scope.Value); len(sourcePrimaryKeys) > 0 {
newDB = newDB.Where(fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, relationship.ForeignDBNames), toQueryMarks(sourcePrimaryKeys)), toQueryValues(sourcePrimaryKeys)...)

association.setErr(relationship.JoinTableHandler.Delete(relationship.JoinTableHandler, newDB, relationship))
association.setErr(relationship.JoinTableHandler.Delete(relationship.JoinTableHandler, newDB))
}
} else if relationship.Kind == "has_one" || relationship.Kind == "has_many" {
// has_one or has_many relations, set foreign key to be nil (TODO or delete them?)
Expand Down Expand Up @@ -173,7 +173,7 @@ func (association *Association) Delete(values ...interface{}) *Association {
sql := fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, relationship.AssociationForeignDBNames), toQueryMarks(deletingPrimaryKeys))
newDB = newDB.Where(sql, toQueryValues(deletingPrimaryKeys)...)

association.setErr(relationship.JoinTableHandler.Delete(relationship.JoinTableHandler, newDB, relationship))
association.setErr(relationship.JoinTableHandler.Delete(relationship.JoinTableHandler, newDB))
} else {
var foreignKeyMap = map[string]interface{}{}
for _, foreignKey := range relationship.ForeignDBNames {
Expand Down
153 changes: 148 additions & 5 deletions association_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -885,7 +885,7 @@ func TestHasManyChildrenWithOneStruct(t *testing.T) {
DB.Save(&category)
}

func TestSkipSaveAssociation(t *testing.T) {
func TestAutoSaveBelongsToAssociation(t *testing.T) {
type Company struct {
gorm.Model
Name string
Expand All @@ -895,13 +895,156 @@ func TestSkipSaveAssociation(t *testing.T) {
gorm.Model
Name string
CompanyID uint
Company Company `gorm:"save_associations:false"`
Company Company `gorm:"association_autoupdate:false;association_autocreate:false;"`
}

DB.Where("name = ?", "auto_save_association").Delete(&Company{})
DB.AutoMigrate(&Company{}, &User{})

DB.Save(&User{Name: "jinzhu", Company: Company{Name: "auto_save_association"}})

if !DB.Where("name = ?", "auto_save_association").First(&Company{}).RecordNotFound() {
t.Errorf("Company auto_save_association should not have been saved when autosave is false")
}

// if foreign key is set, this should be saved even if association isn't
company := Company{Name: "auto_save_association"}
DB.Save(&company)

company.Name = "auto_save_association_new_name"
user := User{Name: "jinzhu", Company: company}

DB.Save(&user)

if !DB.Where("name = ?", "auto_save_association_new_name").First(&Company{}).RecordNotFound() {
t.Errorf("Company should not have been updated")
}

if DB.Where("id = ? AND company_id = ?", user.ID, company.ID).First(&User{}).RecordNotFound() {
t.Errorf("User's foreign key should have been saved")
}

user2 := User{Name: "jinzhu_2", Company: Company{Name: "auto_save_association_2"}}
DB.Set("gorm:association_autocreate", true).Save(&user2)
if DB.Where("name = ?", "auto_save_association_2").First(&Company{}).RecordNotFound() {
t.Errorf("Company auto_save_association_2 should been created when autocreate is true")
}

user2.Company.Name = "auto_save_association_2_newname"
DB.Set("gorm:association_autoupdate", true).Save(&user2)

if DB.Where("name = ?", "auto_save_association_2_newname").First(&Company{}).RecordNotFound() {
t.Errorf("Company should been updated")
}
}

func TestAutoSaveHasOneAssociation(t *testing.T) {
type Company struct {
gorm.Model
UserID uint
Name string
}

type User struct {
gorm.Model
Name string
Company Company `gorm:"association_autoupdate:false;association_autocreate:false;"`
}

DB.Where("name = ?", "auto_save_has_one_association").Delete(&Company{})
DB.AutoMigrate(&Company{}, &User{})

DB.Save(&User{Name: "jinzhu", Company: Company{Name: "auto_save_has_one_association"}})

if !DB.Where("name = ?", "auto_save_has_one_association").First(&Company{}).RecordNotFound() {
t.Errorf("Company auto_save_has_one_association should not have been saved when autosave is false")
}

company := Company{Name: "auto_save_has_one_association"}
DB.Save(&company)

company.Name = "auto_save_has_one_association_new_name"
user := User{Name: "jinzhu", Company: company}

DB.Save(&user)

if !DB.Where("name = ?", "auto_save_has_one_association_new_name").First(&Company{}).RecordNotFound() {
t.Errorf("Company should not have been updated")
}

if !DB.Where("name = ? AND user_id = ?", "auto_save_has_one_association", user.ID).First(&Company{}).RecordNotFound() {
t.Errorf("Company should not have been updated")
}

if user.Company.UserID == 0 {
t.Errorf("UserID should be assigned")
}

company.Name = "auto_save_has_one_association_2_new_name"
DB.Set("gorm:association_autoupdate", true).Save(&user)

if DB.Where("name = ? AND user_id = ?", "auto_save_has_one_association_new_name", user.ID).First(&Company{}).RecordNotFound() {
t.Errorf("Company should been updated")
}

user2 := User{Name: "jinzhu_2", Company: Company{Name: "auto_save_has_one_association_2"}}
DB.Set("gorm:association_autocreate", true).Save(&user2)
if DB.Where("name = ?", "auto_save_has_one_association_2").First(&Company{}).RecordNotFound() {
t.Errorf("Company auto_save_has_one_association_2 should been created when autocreate is true")
}
}

func TestAutoSaveMany2ManyAssociation(t *testing.T) {
type Company struct {
gorm.Model
Name string
}

type User struct {
gorm.Model
Name string
Companies []Company `gorm:"many2many:user_companies;association_autoupdate:false;association_autocreate:false;"`
}

DB.AutoMigrate(&Company{}, &User{})

DB.Save(&User{Name: "jinzhu", Company: Company{Name: "skip_save_association"}})
DB.Save(&User{Name: "jinzhu", Companies: []Company{{Name: "auto_save_m2m_association"}}})

if !DB.Where("name = ?", "auto_save_m2m_association").First(&Company{}).RecordNotFound() {
t.Errorf("Company auto_save_m2m_association should not have been saved when autosave is false")
}

company := Company{Name: "auto_save_m2m_association"}
DB.Save(&company)

company.Name = "auto_save_m2m_association_new_name"
user := User{Name: "jinzhu", Companies: []Company{company, {Name: "auto_save_m2m_association_new_name_2"}}}

DB.Save(&user)

if !DB.Where("name = ?", "auto_save_m2m_association_new_name").First(&Company{}).RecordNotFound() {
t.Errorf("Company should not have been updated")
}

if !DB.Where("name = ?", "auto_save_m2m_association_new_name_2").First(&Company{}).RecordNotFound() {
t.Errorf("Company should not been created")
}

if DB.Model(&user).Association("Companies").Count() != 1 {
t.Errorf("Relationship should been saved")
}

DB.Set("gorm:association_autoupdate", true).Set("gorm:association_autocreate", true).Save(&user)

if DB.Where("name = ?", "auto_save_m2m_association_new_name").First(&Company{}).RecordNotFound() {
t.Errorf("Company should been updated")
}

if DB.Where("name = ?", "auto_save_m2m_association_new_name_2").First(&Company{}).RecordNotFound() {
t.Errorf("Company should been created")
}

if !DB.Where("name = ?", "skip_save_association").First(&Company{}).RecordNotFound() {
t.Errorf("Company skip_save_association should not been saved")
if DB.Model(&user).Association("Companies").Count() != 2 {
t.Errorf("Relationship should been updated")
}
}
3 changes: 2 additions & 1 deletion callback_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,9 @@ func createCallback(scope *Scope) {

if len(columns) == 0 {
scope.Raw(fmt.Sprintf(
"INSERT INTO %v DEFAULT VALUES%v%v",
"INSERT INTO %v %v%v%v",
quotedTableName,
scope.Dialect().DefaultValueStr(),
addExtraSpaceIfExist(extraOption),
addExtraSpaceIfExist(lastInsertIDReturningSuffix),
))
Expand Down
4 changes: 4 additions & 0 deletions callback_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ func init() {

// queryCallback used to query data from database
func queryCallback(scope *Scope) {
if _, skip := scope.InstanceGet("gorm:skip_query_callback"); skip {
return
}

defer scope.trace(NowFunc())

var (
Expand Down
7 changes: 7 additions & 0 deletions callback_query_preload.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import (

// preloadCallback used to preload associations
func preloadCallback(scope *Scope) {
if _, skip := scope.InstanceGet("gorm:skip_query_callback"); skip {
return
}

if _, ok := scope.Get("gorm:auto_preload"); ok {
autoPreload(scope)
Expand Down Expand Up @@ -324,6 +327,10 @@ func (scope *Scope) handleManyToManyPreload(field *Field, conditions []interface

scope.scan(rows, columns, append(fields, joinTableFields...))

scope.New(elem.Addr().Interface()).
InstanceSet("gorm:skip_query_callback", true).
callCallbacks(scope.db.parent.callbacks.queries)

var foreignKeys = make([]interface{}, len(sourceKeys))
// generate hashed forkey keys in join table
for idx, joinTableField := range joinTableFields {
Expand Down
Loading

0 comments on commit 3683d88

Please sign in to comment.