repogen icon indicating copy to clipboard operation
repogen copied to clipboard

Repository Interface and destination in different packages from Model

Open hhow09 opened this issue 1 year ago • 4 comments

Nice generator package!

Is your feature request related to a problem? Please describe. With dependency injection pattern, it's common that controller package defines the repository interface and accept it as input. However current implementation requires that repository interface and model type located within the same package.

Describe the solution you'd like It would be nice if it could support the setup like this.

examples/ref_exp
├── ctrl
│   └── ctrl.go
├── repo
│   └── user_repo.go // generated
└── user.go
// ctrl.go
package ctrl

//go:generate repogen -pkg=.. -dest=../repo/user_repo.go -model=UserModel -repo=UserRepository

// UserRepository is an interface that describes the specification of querying
// user data in the database.
type UserRepository interface {
	// InsertOne stores userModel into the database and returns inserted ID
	// if insertion succeeds and returns error if insertion fails.
	InsertOne(ctx context.Context, userModel *ref_exp.UserModel) (interface{}, error)
	// FindByUsername queries user by username. If a user with specified
	// username exists, the user will be returned. Otherwise, error will be
	// returned.
	FindByUsername(ctx context.Context, username string) (*ref_exp.UserModel, error)

        ...
}

func NewController(userRepo UserRepository ... )...

Additional context Just play around the code base. For this feature these might be related:

  • Package ID of where Model located. (to be used in RepositoryGenerator.Imports() )
  • in interfaceMethodParser there are some operation mode checking. And about the type comparison. Not sure how to allow imported types like *ref_exp.UserModel in args and return. (Currently it will check with p.StructModel).

hhow09 avatar Feb 24 '24 16:02 hhow09

Great improvement proposal! I was trying to do that but for my use case, I don't need that at the moment. However, if you can work on this, here are the high-level specification that I want:

  • When the model struct and the repository interface are in the different package, -pkg flag should reference the package of the repository interface, not the model struct. The generator should be able to derive the location of the model struct automatically.
  • -model flag should be able to read the imported type, e.g. ref_exp.UserModel.

And for the detailed specification, I want to separate the responsibilities as follows:

  • internal/code package should be able to provide the imported packages (lazily is ok)
  • internal/spec package should be able to validate the referencing fields
  • internal/mongo package should be able to derive bson tags and construct the query

sunboyy avatar Feb 26 '24 05:02 sunboyy

Thanks for the specification!

What I am thinking is:

  1. package.Package
    • ~add field Imports and collect all imports from extracted File~
    • add field Path to locate itself
  2. in generateFromRequest, check structModelName if it's from the same package.
    • if not, then parse package for structModel's package to read structModel (roughly)
  3. mongo generator will need additional import provide by package.Path

However in step 2, I am not sure: given -mode=ref_exp.UserModel and package.Imports, how to locate the model go file ? go/parser need a file path, but what I got is package path. (Update) might need something like go list -f '{{.Dir}}' "modelPackagePath"

would it be more feasible if provide the option flag like modelDirPtr ? inspired by https://github.com/dobyte/mongo-dao-generator

hhow09 avatar Feb 26 '24 15:02 hhow09

For step 1, how does it need to be changed? Are there any concerns?

And for step 2, I've just noticed that concern. In my opinion, -model-dir flag should be a possible option. I have ever thought about -pkgs flag that read multiple packages and construct references by itself. It should be able to support the case that the model references a struct in a third package, but it may be too complicated.

sunboyy avatar Feb 26 '24 15:02 sunboyy

thanks for the prompt reply

Then I will add -model-dir as flag.

for step 1,

  • Path is required for model pkg import in generated code (step 3).
  • no need Imports anymore since -model-dir should be enough

I also found destPkgName := flag.String("dest-pkg", "", "destination package name") might also needed :P

hhow09 avatar Feb 27 '24 05:02 hhow09

Resolved in https://github.com/sunboyy/repogen/pull/49

sunboyy avatar May 23 '24 15:05 sunboyy