SoFunction
Updated on 2025-03-05

Best practices for the usage of GORM uncertain parameters

introduction

This article introduces an experience I like very much: the use of uncertain parameters (i.e.... operators) in GORM.

Getting started √——Junior level—Intermediate level—Advanced; this article is suitable for introduction and above.

Usage of uncertain parameters for GORM best practice

Undetermined parameters in Go

In Golang's language feature document, uncertain parameters (… parameters) are specifically explained. When an indefinite parameter is declared in the function definition…T(for examplefunc Greeting(prefix string, who ...string)), inside the function, it is equivalent to having a variable of type []T (for example,GreetingIn the function, there is a type[]stringofwho)。

If there is the following Greeting function:

func Greeting(prefix string, who ...string){
 (prefix, len(who), who)
 if len(who) > 0 {
  Greeting(prefix, who[1:]...)
 }
}

Then it can be passedGreeting("nobody")andGreeting("hello:", "KiKi", "Joe", "Anna")Come to callGreetingmethod. For the usage of the former,whoThe value ofnil;For the latter usage,whoThe value of[]string{"KiKi", "Joe", "Anna"}

Two points to note here:

1) You cannot directly pass in string slice callsGreeting("hello:", []string{"KiKi", "Joe", "Anna"}), otherwise the compiler will report an error.

2) You can't call thisGreeting(prefix, who[1:]), must be transmittedwho[1:]...

These two points can basically reveal the essence of uncertain parameters.It's more like declaring a computation process than a data type

① When used in a function declaration, what is done is to assemble the parameters passed in during function call into slices

② When parameters are transferred inside the function body, it means that the data in the slice is divided into a single element.. Well, that's basically it.

Best practices for uncertain parameters in GROM

To be honest, when you first get into uncertain parameters, you don’t feel the necessity of it; you rarely use it to write code on weekdays, and it feels like a toy or a gimmick of language.

Until recently, when using GROM, facing complex business logic, when there are more and more methods of customizing model layers, I always feel overwhelmed. It was not until I reviewed the code once, after the guidance of Teacher Lai of our group, that a new door was opened to my code world.

Let's look at a piece of code first:

// Topic topictype Topic struct {
 
 Title         string    `gorm:"index"`
 Content       string    `gorm:"type:text"`
 ViewCount     int       `json:"view_count"`
 ReplyCount    int       `json:"reply_count"`
 UserID        int       `gorm:"index" json:"user_id"`
}
// QueryByUserID Get topics based on UserIDfunc (t *Topic) QueryByUserID(userID int) (topics []Topic, err error) {
 db := ("user_id = ?", userID).Find(&topics).Error
 return
}

In order to obtain the corresponding topic (Topic) based on the user ID (UserID), we have defined aQueryByUserIDThe method of   is deliberately passed a parameter here to express the meaning; it seems that this function can help us solve the separation between the model layer and the controller. However, if you really use it, you will find that this function actually has great limitations: it can only obtain all topics of a certain UserID, but it cannot realize further filtering of topics under this UserID (such as obtaining topics published in the past seven days).

So how should we define this Query function so that we are both elegant and powerful when using it?The answer is uncertain parameters

Just imagine, weQueryByUserIDFunctions are defined in the following way:

// QueryByUserID Get topics based on UserIDfunc (t *Topic) QueryByUserID(userID int, args ...interface{}) (topics []Topic, err error) {
 db := ("user_id = ?", userID)
 if len(args) >= 2 {
  db = (args[0], args[1:]...)
 } else if len(args) >= 1 {
  db = (args[0])
 }
 err = (&topics).Error
 return
}

We're hereQueryByUserIDFinally, an args indefinite parameter is added, thereby accepting the additional parameters passed in when the call is called. At the same time, in the function body, we apply it in different ways according to the length of the args, which is very elegantly extendedQueryByUserIDfunction. According to the characteristics of GORM, Go's reflection characteristics are used extensively. After checking the source code, you will know that this usage is completely feasible.

If an uncertain parameter is added, call it againQueryByUserIDWhen it comes to searching for topics more carefully, it is much more convenient. For example, if you want to obtain a topic with UserID of 1 and published in the last week, you can write it like this:

topics, err := (&Topic{}).QueryByUserID(1, "created_at > ?", ().Add(-7*24*)
// ... Other treatments of topics and err

Very flexible, I like it very much!

summary

This article briefly introduces the uncertain parameters and GORM in Go, and describes the elegant combination of the two. A search for topics published by a user (Topic) introduces the great flexibility brought by adding uncertain parameters when using GORM.

Through such a combination, we can have a deeper understanding of uncertain parameters and GORM, and if we have a deeper understanding, we can develop it more easily.

For more information on the usage of GORM indefinite parameters, please follow my other related articles!