go-gorm / gorm

The fantastic ORM library for Golang, aims to be developer friendly
https://gorm.io
MIT License
37.02k stars 3.94k forks source link

Allow for the creation of custom "finishers" #7248

Open boichee opened 1 month ago

boichee commented 1 month ago

Describe the feature

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.