one_to_one_morph

One To One

If you have a Post model,a Video model. Post model has a Cover Image,Video model has a Thumbnail Image.

In this case , you can create a post_images and video_images. Or you can use a image table with an additional column indicate which type of the image is.This is Morpy One.

Table Structure

posts
id - integer
title - string
videos
id - integer
title - string
image
id - integer
path - string
imageable_id - integer
imageable_type - string

Set Up

Before use morph, you need to register a morphmap so that we can convert a string to a model , you can call goeloquent.RegistMorphMap inside init func

//register morph model map
goeloquent.RegistMorphMap(map[string]interface{}{
"posts": &Post{},
"videos": &Video{},
"tag": &Tag{},
})

Model Structure

type Post struct {
*goeloquent.EloquentModel
ID int64 `goelo:"column:pid;primaryKey"`
Title string `goelo:"column:title"`
Author UserT `goelo:"BelongsTo:AuthorRelation"`
AuthorId int64 `goelo:"column:author_id"`
Comments []Comment `goelo:"HasMany:CommentsRelation"`
Viewers []UserT `goelo:"BelongsToMany:ViewersRelation"`
Image Image `goelo:"MorphOne:ImageRelation"`
Tags []Tag `goelo:"MorphToMany:TagsRelation"`
}

func (p *Post) ImageRelation() *goeloquent.RelationBuilder {
rb := p.MorphOne(p, &Image{}, "imageable_type", "imageable_id", "pid")
rb.EnableLogQuery()
return rb
}


type Video struct {
goeloquent.EloquentModel
Id int64 `goelo:"column:id;primaryKey"`
UserId int64 `goelo:"column:user_id"`
Title string `goelo:"column:title"`
Durition int `goelo:"column:durition"`
UploadAt time.Time `goelo:"column:upload_at"`
ViewCount int `goelo:"column:view_count"`
PublishedAt time.Time `goelo:"column:published_at"`
Cover Image `goelo:"MorphOne:ImageRelation"`
User *User `goelo:"BelongsTo:UserRelation"`

}


func (v *Video) ImageRelation() *goeloquent.RelationBuilder {
return v.MorphOne(v, &Image{}, "imageable_type", "imageable_id", "id")
}


type Image struct {
goeloquent.EloquentModel
Id int64 `goelo:"column:id;primaryKey"`
Path string `goelo:"column:path"`
ImageableId int64 `goelo:"column:imageable_id"`
ImageableType string `goelo:"column:imageable_type"`
Imageable interface{} `goelo:"MorphTo:ImageableRelation"`
}

func (i *Image) ImageableRelation() *goeloquent.RelationBuilder {
return i.MorphTo(i, "imageable_id", "id", "imageable_type")
}
func (i *Image) TableName() string {
return "images"
}

MorphOne takes 5 parameter,first one is a pointer of current model,second is a pointer of related model, third is
related model database column correspond to current(parent) model morph type , 4th is related model database column correspond to current(parent) model id, last one is current model column correspond to 4th parameter.

Usage Example

Use With when retrive

var p Post
var ps []Post

DB.Model(&p).With("Image").Find(&p, 4)
//{select * from `posts` where `id` in (?) limit 1 [4] {1} 64.390881ms}
//{select * from `image` where `imageable_id` = ? and `imageable_id` is not null and `imageable_type` = ? [4 posts] {1} 82.064625ms}

DB.Model(&p).With("Image").Get(&ps)
//{select * from `posts` [] {6} 60.657653ms}
//{select * from `images` where `imageable_id` is not null and `imageable_type` = ? and `imageable_id` in (?,?,?,?,?,?) [post 2 4 6 8 10 12] {2} 61.786686ms}


Directly Call Relation Method

var i Image
p.ImageRelation().Get(&i)
//{select * from `images` where `imageable_id` = ? and `imageable_id` is not null and `imageable_type` = ? [2 posts] {1} 60.931456ms}

MorphOne Reverse/MorphTo

MorphTo takes 4 parameter,first one is a pointer of current model,second is a pointer of related model, third is
current(parent) model database column correspond to related model key , 4th is related model type in MorphMap we registered.When we get imageable_type “post” in databse ,we will find which “post” paired model in MorphMap

Usage Example

var i Image
var is []Image
DB.Model(&i).With("Imageable").Find(&i,4)
//{select * from `image` where `id` in (?) limit 1 [4] {1} 60.239766ms}
//{select * from `post` where `id` in (?) [2] {1} 59.779593ms}
DB.Model(&i).With("Imageable").Get(&is)
//{select * from `image` [] {3} 59.796413ms}
//{select * from `video` where `id` in (?) [2] {1} 62.999856ms}
//{select * from `post` where `id` in (?,?) [2 4] {2} 59.979136ms}

Directly Call Relation Method

var t interface{}

if i.ImageableType == "post" {
var t models.Post
i.ImageableRelation().Get(&t)
} else if i.ImageableType == "video" {
var t models.Video
i.ImageableRelation().Get(&t)
}
//{select * from `posts` where `id` = ? [2] {1} 63.613889ms}