Skip to content

Commit

Permalink
add belongs_to primary_id (aka. primary_key in rails) support (#185)
Browse files Browse the repository at this point in the history
* pass environments to exec

* revert environment passthru (+1 squashed commit)
Squashed commits:
[6d86b63] allow skip of missing migration due to changing branch

* belongs to support with fk_id

* remove autosave

* added query check (+1 squashed commit)
Squashed commits:
[6c0c3c9] touch up comment (+2 squashed commits)
Squashed commits:
[cfb8124] ensure paginator total entries size works on rawquery
[cce54f7] ensure raw query works with eager

* pagination works with raw query

* case insensitive check limit / offset

* case insensitive check limit / offset

* detect limit or offset by "limit xx,yy"

* support for postgresql FETCH FIRST X rows only

* allow space / tab / new line between limit and offset statements

* Update test.sh

removed sample debug line

* warning message if query contains pagination

* speed up regex matching

* refactor matched sql
reject columns if orderclauses contains ; (multiple query)

* warning indication for invalid order clauses

* made regex private

* add belongs_to primary_id (aka. primary_key in rails)  support

* remove debug

* changed to use indirect to get reflect value without pointer

* Flatten an else after if return

* Fix previous commit
  • Loading branch information
u007 authored and stanislas-m committed Aug 16, 2018
1 parent acc80d4 commit ebc8f64
Show file tree
Hide file tree
Showing 8 changed files with 59 additions and 7 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ type Writer struct {
ID uuid.UUID `db:"id"`
Name string `db:"name"`
BookID uuid.UUID `db:"book_id"`
Book Book `belongs_to:"book"`
Book Book `belongs_to:"book" fk_id:"BookID" primary_id:"ID"`
}

type Writers []Writer
Expand Down
29 changes: 28 additions & 1 deletion associations/belongs_to_association.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import (
"fmt"
"reflect"

"github.com/gobuffalo/pop/columns"
"github.com/gobuffalo/pop/nulls"
"github.com/markbates/inflect"
)

// belongsToAssociation is the implementation for the belongs_to
Expand All @@ -14,9 +16,12 @@ type belongsToAssociation struct {
ownerType reflect.Type
ownerID reflect.Value
fkID string
primaryID string
ownedModel interface{}
*associationSkipable
*associationComposite

primaryTableID string
}

func init() {
Expand All @@ -25,6 +30,11 @@ func init() {

func belongsToAssociationBuilder(p associationParams) (Association, error) {
fval := p.modelValue.FieldByName(p.field.Name)
primaryIDField := "ID"
if p.popTags.Find("primary_id").Value != "" {
primaryIDField = p.popTags.Find("primary_id").Value
}

ownerIDField := fmt.Sprintf("%s%s", p.field.Name, "ID")
if p.popTags.Find("fk_id").Value != "" {
ownerIDField = p.popTags.Find("fk_id").Value
Expand All @@ -40,17 +50,34 @@ func belongsToAssociationBuilder(p associationParams) (Association, error) {
if fieldIsNil(f) || isZero(f.Interface()) {
skipped = true
}
//associated model
ownerPrimaryTableField := "id"
if primaryIDField != "ID" {
ownerModel := reflect.Indirect(fval)
ownerPrimaryField, found := ownerModel.Type().FieldByName(primaryIDField)
if !found {
return nil, fmt.Errorf("there is no primary field '%s' defined in model '%s'", primaryIDField, ownerModel.Type())
}
ownerPrimaryTags := columns.TagsFor(ownerPrimaryField)
if dbField := ownerPrimaryTags.Find("db").Value; dbField == "" {
ownerPrimaryTableField = inflect.Underscore(ownerPrimaryField.Name) //autodetect without db tag
} else {
ownerPrimaryTableField = dbField
}
}

return &belongsToAssociation{
ownerModel: fval,
ownerType: fval.Type(),
ownerID: f,
fkID: ownerIDField,
primaryID: primaryIDField,
ownedModel: p.model,
associationSkipable: &associationSkipable{
skipped: skipped,
},
associationComposite: &associationComposite{innerAssociations: p.innerAssociations},
primaryTableID: ownerPrimaryTableField,
}, nil
}

Expand All @@ -73,7 +100,7 @@ func (b *belongsToAssociation) Interface() interface{} {
// Constraint returns the content for a where clause, and the args
// needed to execute it.
func (b *belongsToAssociation) Constraint() (string, []interface{}) {
return "id = ?", []interface{}{b.ownerID.Interface()}
return fmt.Sprintf("%s = ?", b.primaryTableID), []interface{}{b.ownerID.Interface()}
}

func (b *belongsToAssociation) BeforeInterface() interface{} {
Expand Down
2 changes: 1 addition & 1 deletion columns/tags.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"strings"
)

var tags = "db rw select belongs_to has_many has_one fk_id order_by many_to_many"
var tags = "db rw select belongs_to has_many has_one fk_id primary_id order_by many_to_many"

// Tag represents a field tag defined exclusively for pop package.
type Tag struct {
Expand Down
11 changes: 10 additions & 1 deletion finders_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ func Test_Find_Eager_Belongs_To(t *testing.T) {
transaction(func(tx *pop.Connection) {
r := require.New(t)

user := User{Name: nulls.NewString("Mark")}
user := User{Name: nulls.NewString("Mark"), UserName: "mark"}
err := tx.Create(&user)
r.NoError(err)

Expand All @@ -135,6 +135,15 @@ func Test_Find_Eager_Belongs_To(t *testing.T) {
r.NotEqual(b.ID, 0)
r.NotEqual(b.User.ID, 0)
r.Equal(b.User.ID, user.ID)

userAttr := UserAttribute{UserName: "mark", NickName: "Mark Z."}
err = tx.Create(&userAttr)
r.NoError(err)

uA := UserAttribute{}
err = tx.Eager().Find(&uA, userAttr.ID)
r.NoError(err)
r.Equal(uA.User.ID, user.ID)
})
}

Expand Down
3 changes: 2 additions & 1 deletion migrations/20160808213308_setup_tests.down.fizz
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ drop_table("validatable_cars")
drop_table("not_validatable_cars")
drop_table("callbacks_users")
drop_table("books")
drop_table("cars")
drop_table("cars")
drop_table("user_attributes")
6 changes: 6 additions & 0 deletions migrations/20160808213308_setup_tests.up.fizz
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
create_table("users") {
t.Column("name", "string", {})
t.Column("user_name", "string", {"size": 100})
t.Column("alive", "boolean", {"null": true})
t.Column("birth_date", "timestamp", {"null": true})
t.Column("bio", "text", {"null": true})
Expand Down Expand Up @@ -36,3 +37,8 @@ create_table("taxis") {
t.Column("model", "string", {})
t.Column("user_id", "int", {"null": true})
}
create_table("user_attributes") {
t.Column("user_name", "string", {"size": 100})
t.Column("nick_name", "string", {})
t.DisableTimestamps()
}
9 changes: 9 additions & 0 deletions pop_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ func ts(s string) string {

type User struct {
ID int `db:"id"`
UserName string `db:"user_name"`
Email string `db:"email"`
Name nulls.String `db:"name"`
Alive nulls.Bool `db:"alive"`
Expand All @@ -91,6 +92,14 @@ func (u *User) Validate(tx *pop.Connection) (*validate.Errors, error) {

type Users []User

type UserAttribute struct {
ID int `db:"id"`
UserName string `db:"user_name"`
NickName string `db:"nick_name"`

User User `json:"user" belongs_to:"user" fk_id:"UserName" primary_id:"UserName"`
}

type Book struct {
ID int `db:"id"`
Title string `db:"title"`
Expand Down
4 changes: 2 additions & 2 deletions query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ func Test_ToSQL(t *testing.T) {
transaction(func(tx *pop.Connection) {
user := &pop.Model{Value: &User{}}

s := "SELECT name as full_name, users.alive, users.bio, users.birth_date, users.created_at, users.email, users.id, users.name, users.price, users.updated_at FROM users AS users"
s := "SELECT name as full_name, users.alive, users.bio, users.birth_date, users.created_at, users.email, users.id, users.name, users.price, users.updated_at, users.user_name FROM users AS users"

query := pop.Q(tx)
q, _ := query.ToSQL(user)
Expand All @@ -131,7 +131,7 @@ func Test_ToSQL(t *testing.T) {
a.Equal(fmt.Sprintf("%s ORDER BY id desc", s), q)

q, _ = query.ToSQL(&pop.Model{Value: &User{}, As: "u"})
a.Equal("SELECT name as full_name, u.alive, u.bio, u.birth_date, u.created_at, u.email, u.id, u.name, u.price, u.updated_at FROM users AS u ORDER BY id desc", q)
a.Equal("SELECT name as full_name, u.alive, u.bio, u.birth_date, u.created_at, u.email, u.id, u.name, u.price, u.updated_at, u.user_name FROM users AS u ORDER BY id desc", q)

q, _ = query.ToSQL(&pop.Model{Value: &Family{}})
a.Equal("SELECT family_members.created_at, family_members.first_name, family_members.id, family_members.last_name, family_members.updated_at FROM family.members AS family_members ORDER BY id desc", q)
Expand Down

0 comments on commit ebc8f64

Please sign in to comment.