Scoping
Scoping是一种构造数据库查询的方法,当在很多地方都需要这个查询的时候。假设我们想创建一个书店:书店为每个人提供书籍,但是有些特殊版本是为注册帐户的客户保留的。这意味着对于整个商店,我们需要过滤书籍,这样客户只能看到受限的书籍列表。
正常的做法
正常的做法就是每次写where语句。
type Book struct {
ID uuid.UUID `json:"id" db:"id"`
Label string `json:"label" db:"label"`
Restricted bool `json:"is_restricted" db:"is_restricted"`
}
type Books []Book
Copy// Get available books list
books := Books{}
tx := c.Value("tx").(*pop.Connection)
var err error
if !registeredAccount {
err = tx.Where("is_restricted = false").All(&books)
} else {
// Create an empty query
err = tx.All(&books)
}
if err != nil {
fmt.Printf("ERROR: %v\n", err)
} else {
fmt.Printf("%v\n", books)
}
// Get a specific book
book := Book{}
bookID := "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
tx := c.Value("tx").(*pop.Connection)
var err error
if !registeredAccount {
err = tx.Where("is_restricted = false AND id = ?", bookID).First(&book)
} else {
err = tx.Find(&book, bookID)
}
if err != nil {
fmt.Printf("ERROR: %v\n", err)
} else {
fmt.Printf("%v\n", book)
}
使用 scoped
type Book struct {
ID uuid.UUID `json:"id" db:"id"`
Label string `json:"label" db:"label"`
Restricted bool `json:"is_restricted" db:"is_restricted"`
}
type Books []Book
Copy// restrictedScope defines a base query which shares the common constraint.
func restrictedScope(registeredAccount bool) pop.ScopeFunc {
return func(q *pop.Query) *pop.Query {
if !registeredAccount {
return q
}
return q.Where("is_restricted = false")
}
}
Copy// Get available books list
books := Books{}
if err := tx.Scope(restrictedScope(registeredAccount)).All(&books); err != nil {
fmt.Printf("ERROR: %v\n", err)
} else {
fmt.Printf("%v\n", books)
}
// Get a specific book
book := Book{}
bookID := "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
tx := c.Value("tx").(*pop.Connection)
var err error
if err := tx.Scope(restrictedScope(registeredAccount)).Find(&book, bookID) != nil {
fmt.Printf("ERROR: %v\n", err)
} else {
fmt.Printf("%v\n", book)
}
这样就可以使用restrictedScope方法来直接查询,既代码可读性提高了。也省去了重复写where语句。