Codegen - return interfaces instead of private structs
Is there a reason codegen returns private structs over exported or interfaces? If these methods could return an interface and or in some instances a generic interface, like the one below, it could open up some cool opportunities.
// prisma-client-go
// GENERATED FILE
// generic transaction interface
type Tx[T any] interface {
ExtractQuery() builder.Query
IsTx()
Result() T
}
// example of a model returning the Tx interface
func (r activityCreateOne) Tx() Tx[*ActivityModel] {
v := NewactivityUniqueTxResult()
v.query = r.query
v.query.TxResult = make(chan []byte, 1)
return v
}
By returning an interface specifically on Tx() we can create our own wrapping interface that enables "query builder" methods.
// developers own wrapper interface
type Executor[T any] interface {
ExtractQuery() builder.Query
Exec(ctx context.Context) (T, error)
Tx() prisma.Tx[T]
}
// query builders functions
func buildActivityQuery(db *db.DB, input Input) Executor[*prisma.ActivityModel] {
return db.Activity.CreateOne(
prisma.Activity.Title.Set(input.title),
prisma.Activity.Description.Set(input.description),
prisma.Activity.StartDate.Set(input.startDate),
prisma.Activity.Location.Set(input.location),
)
}
func buildGroupQuery(db *db.DB, input string) Executor[*prisma.GroupModel] {
return db.Group.CreateOne(
prisma.Group.Name.Set(input),
)
}
// example helper functions that either executes the query
func CreateActivity(ctx context.Context, db *db.DB, input Input) (*prisma.ActivityModel, error) {
act := buildActivityQuery(db, input)
return act.Exec(ctx)
}
// or create a transaction
func CreateActivityTx(ctx context.Context, db *db.DB, input Input) (prisma.Tx[*prisma.ActivityModel], error) {
act := buildActivityQuery(db, input)
return act.Tx(), nil
}
func DoSomethingTheNeedsTransactions(ctx context.Context, db *db.DB, input Input) (*prisma.ActivityModel, error) {
act, _ := CreateActivityTx(ctx, db, input)
group := buildGroupQuery(db, "some name").Tx()
if err := db.Prisma.Transaction(act, group).Exec(ctx); err != nil {
return nil, err
}
return act.Result(), nil
}
// these same query builders can then be used in a mocks expectation
mock.Activity.Expect(
BuildActivityQuery(client, Input{}),
).Returns(expected)
That's an interesting suggestion. Do you actually have the need in your app to use this?
The reason most of the methods are private is that most users don't need it, and I wanted to really think about the naming and so forth before making these public.
I prepared one small PR to make the transaction results public and it also renames the transaction interface to a better name: https://github.com/steebchen/prisma-client-go/pull/1180.
When I have some more spare time, I might take another look and work on a bigger PR to make this more unified, maybe with generics where it works or makes sense. Thanks for the suggestion and the example code, that's really helpful!