Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Codegen - return interfaces instead of private structs #1176

Open
randallmlough opened this issue Feb 8, 2024 · 1 comment
Open

Codegen - return interfaces instead of private structs #1176

randallmlough opened this issue Feb 8, 2024 · 1 comment

Comments

@randallmlough
Copy link

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)
@steebchen
Copy link
Owner

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: #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!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Development

No branches or pull requests

2 participants