Normally, when we do a service for a certain entity, we will find that many tables have similar query commands. For example, doing CRUD service will be in the form of Create, Find, Update, and Delete. This is done in the level of the repository in our project. If there are many tables, we may have to make a repository multiple times, but overall the commands inside will be similar.
Today, we will try to make a single repository file that can be used for multiple models or tables by using gorm and go generic.
Let's take a look at the code for the repository.
The code explains a little bit about the NewRepository
function, which is used to call this repository by passing in any models (go generic). After that, I will create other functions such as Create
, FindAll
. These are examples of overriding functions from gorm. You don't have to name them like gorm, but I prefer to do it this way because it's easier to read the gorm document and apply it.
The next part is the various conditions such as Where
, Order
and others. They are similar, just the return is different. Because we can do multiple conditions and it will stack up more and more.
By creating these functions, you can customize the parameters that are received and sent out. You can do many things. I may not have given examples that are too strange because I want to show how to use go generic in receiving and returning any type.
Great, now take a look at the code when implementing it, it will look like this
I will not explain about injecting the db or structuring the project, because I think each person has a different format. This will be a general example. The db value I sent will be of type gorm.DB, as required by our repository. Another value is the context that we may need to use if we use it with a framework or third-party that we want to send the context to.
All of this will just be a concept in doing go generic when using gorm repository, you can customize it all as you want.
GITHUB PROJECT ✨ nanpipat-dev/gorm-generic-repository
This is the git link that I have as an example for this article. If you have any questions or comments, please let me know.
Top comments (2)
I perfer to still use unique respository struct for every table, and use anonymous inheritance to reduce duplicate code. For example
Where(query, args...)
in not repository too mucu, will reduces maintainability. I like repository provider method likeGetXXXById(id uint64)
It makes the amount of code bigger, but reduced code dynamics.
That's my personal project practice experience and preference
Half modern piece ;-)
Instead of
value interface{}
you can usevalue any
shorter to type ;-)