Describe the feature
- As a user of
gorm, I can extend its capabilities with custom "finishers" (in thegormparlance).
I think something like the following would work:
First, you'd need to define an interface for "Finisher" plugins:
// Excuse me if I'm not exactly right on the gorm type that would be passsed to `Build` below
type Finisher interface {
Name() string
Build(stmt *gorm.Statement)
}
db.RegisterFinisher(finisher Finisher)
Then, I could perhaps call my finisher extension like:
db.Plugins().Execute(name, args....)
where Execute would have a signature like:
func Execute(name string, args any) *gorm.DB
Alternatively, you could just add Finish method to the main gorm.DB object and not require registration
In this case, the "finisher" extension would just be passed directly to Finish like:
type myFinisher struct {
foo someOtherType
}
// Assume I've implemented the finisher interface here
db.
Model(&someModel{}).
Where(&someModel{ID: 1}).
Finish(myFinisher{"someOtherTypeValue"})
This avoid the need to reference the finisher by name inline.
Motivation
Today, I was trying to implement an extension to gorm that would allow me to do EXISTS queries. What I quickly realized is that while the usual clause.Expression would allow me to implement a custom expression, EXISTS is, itself, actually a "Finisher" in terms of the way gorm thinks about things. So despite getting the Expression how I think it would work, I had no way to actually execute the query (aside from maybe doing ToSQL() and then Raw() which kind of defeats the purpose of having an ergonomic method that I can call.
Related Issues
Generally speaking, having an Exists() method in gorm feels like it would be useful. For now, my team tends to use Count() to verify existence, but this sometimes feels like a workaround.