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

feat: add query interface #870

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

FLAGLORD
Copy link

@FLAGLORD FLAGLORD commented May 25, 2023

  • Do only one thing
  • Non breaking API changes
  • Tested

What did this pull request do?

Now gen.WithQueryInterface only generates interface for DO object. Considering that DO object uses context to initialize, most services would import Query instead of some DO object. In that case, it would be difficult to mock Query because Query is just a struct instead of interface. It would be easier to mock if we have a interface for Query.

User Case Description

@FLAGLORD
Copy link
Author

#342

@jinzhu
Copy link
Member

jinzhu commented Aug 2, 2023

Can you add more details about why to mock the query interface?

Thank you.

@FLAGLORD
Copy link
Author

I would add some explanations:
Assuming that I have a table Person, gen.WithQueryInterface will generate files following.
person.gen.go

// struct with do
type person struct{
	// personDo implements IPersonDO
	personDo personDo
	// ...
}

// interface for query
type IPersonDO interface {
	// ...
}

func(p *person) WithContext(ctx context.Context) IPersonDO{
	return p.personDo.WithContext(ctx)
}

// ...

gen.go

type Query struct {
	db *gorm.DB

	Person person
}

type queryCtx struct {
	Person IPersonDO
}

func (q *Query) WithContext(ctx context.Context) *queryCtx {
	// ...
}

If a ServiceA has a dependency on table Person, it's easy to write a constructor function like this:

func NewServiceA(personDO IPersonDO)*ServiceA{
	// ...
}

It's also easy to inject a mocked IPersonDO to write some test. (a mocked IPersonDO can be generated by mockery or something like that)

But if ServiceA is a more complicated service, it may use many tables. Thus it's easier to accept Query as a parameter for its constructor function.

But At this time, injecting a mocked interface is difficult. Query is a struct and its field Person doesn't implement IPersonDO. So we can't even set a mocked IPersonDO to the field Person of Query.

@stoffeastrom
Copy link

What about retrieving objects with primary key?

func PersonHandler(id uuid.UUID, q generatedpkg.IQuery) {
  p, err := q.PersonDo().Where(
    // How to retrive with primary key through interface?
    q.PersonDo().Fields().ID().Eq(id) // This will not work but would be nice to expose the fields as an interface as well
  ).First()
}

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

Successfully merging this pull request may close these issues.

None yet

3 participants