Documentation
¶
Overview ¶
Package hydrate provides functionality to expand preloading functionality of gorm.
Specifically gorm hydrate will only support loading each relationship as a different query. This results in a query per level. Additionally each level loads the data by using a WHERE IN (...primary keys) which in certain situations with deep hierarchies with thousands of items can result in poor performing queries.
There are two ways provided to load data into a hierarchy using raw queries. Query will perform a single query to load one or more model structs. MultiQuery has a slice of Queries as its backing type and will allow multiple queries to be run and have results combined.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type MultiQuery ¶
type MultiQuery []Query
MultiQuery will allow you to run multiple Queries and combine all results. Queries are run as normal but all structs are shared across all queries. Meaning relationships can be populated from independent queries, or even a collection of results from the same table can be loaded from multiple queries.
Example ¶
package main import ( "context" "fmt" "github.com/jinzhu/gorm" "github.com/coursehero/hydrate" ) func main() { var db *gorm.DB //example tables type Author struct { AuthorID uint `gorm:"primary_key"` Name string } type Section struct { SectionID *uint `gorm:"primary_key"` TextbookID uint Title string } type Textbook struct { TextbookID uint `gorm:"primary_key"` AuthorID uint Name string Author Author `gorm:"foreignkey:AuthorID;association_foreignkey:AuthorID"` Sections []*Section `gorm:"foreignkey:TextbookID;association_foreignkey:TextbookID"` } var textbooks []Textbook err := hydrate.MultiQuery{ hydrate.NewQuery(db, `FROM textbooks t LEFT JOIN sections s on t.textbook_id = s.textbook_id WHERE t.textbook_id in (?) ORDER BY t.textbook_id, s.section_id`, 1). AddModel(Textbook{}, "t"). AddModel(Section{}, "s"), hydrate.NewQuery(db, `FROM textbooks t LEFT JOIN authors a ON a.author_id = t.author_id WHERE t.textbook_id in (?) ORDER BY t.textbook_id, s.section_id, a.author_id`, 1). AddModel(Author{}, "a"), }.Run(context.Background(), &textbooks) if err != nil { fmt.Printf("err = %v\n", err) } //all textbooks are fully loaded with all relationships fmt.Printf("%d textbooks loaded\n", len(textbooks)) for _, t := range textbooks { fmt.Printf("Textbook %d has %d sections\n", t.TextbookID, len(t.Sections)) } }
Output:
type Query ¶
type Query struct {
// contains filtered or unexported fields
}
Query is used to define a query to hydrate data using a single query. Any number of models can be added to be loaded, each model will be added to the select query using the alias provided (or the table name if empty). Each model added will store unique items based on primary key values returned from the query. All relationships for each model will be filled by connecting to other loaded models using the gorm defined relationship.
Example ¶
A single query can be provided using hydrate.NewQuery. Add model structs using AddModel providing a pointer to an instance of the model type and the alias used for the model in the query. The query provided should not include SELECT and should start with FROM.
package main import ( "context" "fmt" "github.com/jinzhu/gorm" "github.com/coursehero/hydrate" ) func main() { var db *gorm.DB //example structs type Author struct { AuthorID uint `gorm:"primary_key"` Name string } type Exercise struct { ExerciseID uint `gorm:"primary_key"` SectionID uint Name string } type Section struct { SectionID *uint `gorm:"primary_key"` TextbookID uint Title string Exercises []Exercise `gorm:"foreignkey:SectionID;association_foreignkey:SectionID"` } type Textbook struct { TextbookID uint `gorm:"primary_key"` AuthorID uint Name string Author Author `gorm:"foreignkey:AuthorID;association_foreignkey:AuthorID"` Sections []*Section `gorm:"foreignkey:TextbookID;association_foreignkey:TextbookID"` } var textbooks []Textbook err := hydrate.NewQuery(db, `FROM textbooks t LEFT JOIN sections s on t.textbook_id = s.textbook_id LEFT JOIN exercises e ON e.section_id = s.section_id LEFT JOIN authors a ON a.author_id = t.author_id WHERE t.textbook_id in (?) ORDER BY t.textbook_id, s.section_id, a.author_id`, 1). AddModel(Textbook{}, "t"). AddModel(Section{}, "s"). AddModel(Exercise{}, "e"). AddModel(Author{}, "a"). Run(context.Background(), &textbooks) if err != nil { fmt.Printf("err = %v\n", err) } //all textbooks are fully loaded with all relationships fmt.Printf("%d textbooks loaded\n", len(textbooks)) for _, t := range textbooks { fmt.Printf("Textbook %d has %d sections\n", t.TextbookID, len(t.Sections)) for _, s := range t.Sections { fmt.Printf("Section %d has %d exercises\n", s.SectionID, len(s.Exercises)) } } }
Output:
func (Query) AddModel ¶
AddModel will add a model to be loaded during execution. Its fields will be added to the select. If no alias is provided it will use the table name
func (Query) Run ¶
Run will run the query and put results in any outputs provided. Each output must be a pointer to a value that can be set. If a slice is provided it will fill with all results. If a single item is passed the first item will be returned. However no limiting will be done to the query.