diff --git a/contracts/migration.go b/contracts/migration.go index ec4988c..d72a8b6 100644 --- a/contracts/migration.go +++ b/contracts/migration.go @@ -8,3 +8,5 @@ type Migration interface { Up(tx *gorm.DB) error Down(tx *gorm.DB) error } + +type MigrationProvider func() Migration diff --git a/contracts/seeder.go b/contracts/seeder.go index 97f0bcc..c3e7b71 100644 --- a/contracts/seeder.go +++ b/contracts/seeder.go @@ -9,3 +9,5 @@ import ( type Seeder interface { Run(*gofakeit.Faker, *gorm.DB) } + +type SeederProvider func() Seeder diff --git a/go.mod b/go.mod index f520cee..544f7a9 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/gofrs/uuid v4.0.0+incompatible github.com/golang-jwt/jwt/v4 v4.4.3 github.com/mojocn/base64Captcha v1.3.5 + github.com/pkg/errors v0.9.1 github.com/rogeecn/gen v1.0.11 github.com/spf13/cobra v1.5.0 github.com/spf13/viper v1.15.0 @@ -50,11 +51,11 @@ require ( github.com/leodido/go-urn v1.2.1 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-isatty v0.0.17 // indirect + github.com/microsoft/go-mssqldb v0.21.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.0.6 // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect github.com/spf13/afero v1.9.3 // indirect github.com/spf13/cast v1.5.0 // indirect diff --git a/go.sum b/go.sum index 038ecc0..56447a1 100644 --- a/go.sum +++ b/go.sum @@ -290,8 +290,8 @@ github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI= github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= -github.com/microsoft/go-mssqldb v0.17.0 h1:Fto83dMZPnYv1Zwx5vHHxpNraeEaUlQ/hhHLgZiaenE= github.com/microsoft/go-mssqldb v0.17.0/go.mod h1:OkoNGhGEs8EZqchVTtochlXruEhEOaO4S0d2sB5aeGQ= +github.com/microsoft/go-mssqldb v0.21.0 h1:p2rpHIL7TlSv1QrbXJUAcbyRKnIT0C9rRkH2E4OjLn8= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= diff --git a/migrate.go b/migrate.go index ce4e1bd..129b0cc 100644 --- a/migrate.go +++ b/migrate.go @@ -13,7 +13,54 @@ import ( "gorm.io/gorm" ) -func WithMigration(rootCmd *cobra.Command) *cobra.Command { +func withMigrationCommand(rootCmd *cobra.Command) *cobra.Command { + // migrateUpCmd represents the migrateUp command + var migrateUpCmd = &cobra.Command{ + Use: "up", + Short: "migrate up database tables", + Long: `migrate up database tables`, + RunE: func(cmd *cobra.Command, args []string) error { + return container.Container.Invoke(func(mi MigrationInfo) error { + m := gormigrate.New(mi.DB, gormigrate.DefaultOptions, sortedMigrations(mi.Migrations)) + if len(migrateToId) > 0 { + log.Printf("migrate up to [%s]\n", migrateToId) + return m.MigrateTo(migrateToId) + } + return m.Migrate() + }) + }, + PostRun: func(cmd *cobra.Command, args []string) { + log.Println("BINGO! migrate up done") + }, + } + + // migrateDownCmd represents the migrateDown command + var migrateDownCmd = &cobra.Command{ + Use: "down", + Short: "migrate down database tables", + Long: `migrate down database tables`, + RunE: func(cmd *cobra.Command, args []string) error { + return container.Container.Invoke(func(mi MigrationInfo) error { + m := gormigrate.New(mi.DB, gormigrate.DefaultOptions, sortedMigrations(mi.Migrations)) + + if len(migrateToId) > 0 { + log.Printf("migrate down to [%s]\n", migrateToId) + return m.RollbackTo(migrateToId) + } + return m.RollbackLast() + }) + }, + PostRun: func(cmd *cobra.Command, args []string) { + log.Println("BINGO! migrate down done") + }, + } + // migrateCmd represents the migrate command + var migrateCmd = &cobra.Command{ + Use: "migrate", + Short: "migrate database tables", + Long: `migrate database tables`, + } + rootCmd.AddCommand(migrateCmd) migrateCmd.AddCommand(migrateUpCmd) migrateCmd.AddCommand(migrateDownCmd) @@ -23,13 +70,6 @@ func WithMigration(rootCmd *cobra.Command) *cobra.Command { return rootCmd } -// migrateCmd represents the migrate command -var migrateCmd = &cobra.Command{ - Use: "migrate", - Short: "migrate database tables", - Long: `migrate database tables`, -} - var migrateToId string // MigrationInfo http service container @@ -40,47 +80,6 @@ type MigrationInfo struct { Migrations []contracts.Migration `group:"migrations"` } -// migrateUpCmd represents the migrateUp command -var migrateUpCmd = &cobra.Command{ - Use: "up", - Short: "migrate up database tables", - Long: `migrate up database tables`, - RunE: func(cmd *cobra.Command, args []string) error { - return container.Container.Invoke(func(mi MigrationInfo) error { - m := gormigrate.New(mi.DB, gormigrate.DefaultOptions, sortedMigrations(mi.Migrations)) - if len(migrateToId) > 0 { - log.Printf("migrate up to [%s]\n", migrateToId) - return m.MigrateTo(migrateToId) - } - return m.Migrate() - }) - }, - PostRun: func(cmd *cobra.Command, args []string) { - log.Println("BINGO! migrate up done") - }, -} - -// migrateDownCmd represents the migrateDown command -var migrateDownCmd = &cobra.Command{ - Use: "down", - Short: "migrate down database tables", - Long: `migrate down database tables`, - RunE: func(cmd *cobra.Command, args []string) error { - return container.Container.Invoke(func(mi MigrationInfo) error { - m := gormigrate.New(mi.DB, gormigrate.DefaultOptions, sortedMigrations(mi.Migrations)) - - if len(migrateToId) > 0 { - log.Printf("migrate down to [%s]\n", migrateToId) - return m.RollbackTo(migrateToId) - } - return m.RollbackLast() - }) - }, - PostRun: func(cmd *cobra.Command, args []string) { - log.Println("BINGO! migrate down done") - }, -} - func sortedMigrations(ms []contracts.Migration) []*gormigrate.Migration { migrationKeys := []string{} migrationMaps := make(map[string]*gormigrate.Migration) diff --git a/model.go b/model.go index 8bdeeae..0f3b094 100644 --- a/model.go +++ b/model.go @@ -14,11 +14,6 @@ import ( "gorm.io/gorm" ) -func WithModel(rootCmd *cobra.Command) *cobra.Command { - rootCmd.AddCommand(modelCmd) - return rootCmd -} - // MigrationInfo http service container type GenQueryGenerator struct { dig.In @@ -32,62 +27,67 @@ type GenQueryGenerator struct { // FilterWithNameAndRole(name, role string) ([]gen.T, error) // } -// modelCmd represents the gen command -var modelCmd = &cobra.Command{ - Use: "model", - Short: "gorm model&query generator", - Long: `gorm model&query generator. more info, see https://gorm.io/gen`, - RunE: func(cmd *cobra.Command, args []string) error { - return container.Container.Invoke(func(gq GenQueryGenerator) error { - var tables []string +func withModelCommand(rootCmd *cobra.Command) *cobra.Command { + // modelCmd represents the gen command + var modelCmd = &cobra.Command{ + Use: "model", + Short: "gorm model&query generator", + Long: `gorm model&query generator. more info, see https://gorm.io/gen`, + RunE: func(cmd *cobra.Command, args []string) error { + return container.Container.Invoke(func(gq GenQueryGenerator) error { + var tables []string - switch gq.DB.Dialector.Name() { - case mysql.Dialector{}.Name(): - err := gq.DB.Raw("show tables").Scan(&tables).Error - if err != nil { - log.Fatal(err) + switch gq.DB.Dialector.Name() { + case mysql.Dialector{}.Name(): + err := gq.DB.Raw("show tables").Scan(&tables).Error + if err != nil { + log.Fatal(err) + } + case postgres.Dialector{}.Name(): + err := gq.DB.Raw("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'").Scan(&tables).Error + if err != nil { + log.Fatal(err) + } + case sqlite.DriverName: + err := gq.DB.Raw("SELECT name FROM sqlite_master WHERE type='table'").Scan(&tables).Error + if err != nil { + log.Fatal(err) + } } - case postgres.Dialector{}.Name(): - err := gq.DB.Raw("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'").Scan(&tables).Error - if err != nil { - log.Fatal(err) - } - case sqlite.DriverName: - err := gq.DB.Raw("SELECT name FROM sqlite_master WHERE type='table'").Scan(&tables).Error - if err != nil { - log.Fatal(err) - } - } - if len(tables) == 0 { - return errors.New("no tables in database, run migrate first") - } + if len(tables) == 0 { + return errors.New("no tables in database, run migrate first") + } - g := gen.NewGenerator(gen.Config{ - OutPath: "database/query", - OutFile: "query.gen.go", - ModelPkgPath: "database/models", - FieldSignable: true, - FieldWithTypeTag: true, - Mode: gen.WithDefaultQuery | gen.WithQueryInterface, + g := gen.NewGenerator(gen.Config{ + OutPath: "database/query", + OutFile: "query.gen.go", + ModelPkgPath: "database/models", + FieldSignable: true, + FieldWithTypeTag: true, + Mode: gen.WithDefaultQuery | gen.WithQueryInterface, + }) + + g.UseDB(gq.DB) // reuse your gorm db + + models := []interface{}{} + for _, table := range tables { + models = append(models, g.GenerateModel(table)) + } + + // Generate basic type-safe DAO API for struct `model.User` following conventions + g.ApplyBasic(models...) + + // Generate Type Safe API with Dynamic SQL defined on Querier interface for `model.User` and `model.Company` + // g.ApplyInterface(func(Querier) {}, model.User{}, model.Company{}) + + // Generate the code + g.Execute() + return nil }) + }, + } - g.UseDB(gq.DB) // reuse your gorm db - - models := []interface{}{} - for _, table := range tables { - models = append(models, g.GenerateModel(table)) - } - - // Generate basic type-safe DAO API for struct `model.User` following conventions - g.ApplyBasic(models...) - - // Generate Type Safe API with Dynamic SQL defined on Querier interface for `model.User` and `model.Company` - // g.ApplyInterface(func(Querier) {}, model.User{}, model.Company{}) - - // Generate the code - g.Execute() - return nil - }) - }, + rootCmd.AddCommand(modelCmd) + return rootCmd } diff --git a/root.go b/root.go index 9fd3aca..98c381e 100644 --- a/root.go +++ b/root.go @@ -1,14 +1,22 @@ package atom import ( + "log" + "github.com/pkg/errors" "github.com/rogeecn/atom/container" + "github.com/rogeecn/atom/contracts" "github.com/rogeecn/atom/providers/config" "github.com/spf13/cobra" + "go.uber.org/dig" ) var cfgFile string +var ( + GroupRoutes = dig.Group("routes") +) + func Serve(providers container.Providers, opts ...Option) error { var rootCmd = &cobra.Command{} rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "config.toml", "config file path") @@ -17,9 +25,9 @@ func Serve(providers container.Providers, opts ...Option) error { opt(rootCmd) } - WithMigration(rootCmd) - WithModel(rootCmd) - WithSeeder(rootCmd) + withMigrationCommand(rootCmd) + withModelCommand(rootCmd) + withSeederCommand(rootCmd) // parse config files configure, err := config.Load(cfgFile) @@ -94,3 +102,23 @@ func Config(file string) Option { _ = cmd.PersistentFlags().Set("config", file) } } + +func Seeders(seeders ...contracts.SeederProvider) Option { + return func(cmd *cobra.Command) { + for _, seeder := range seeders { + if err := container.Container.Provide(seeder, dig.Group("seeder")); err != nil { + log.Fatal(err) + } + } + } +} + +func Migrations(migrations ...contracts.MigrationProvider) Option { + return func(cmd *cobra.Command) { + for _, migration := range migrations { + if err := container.Container.Provide(migration, dig.Group("migrations")); err != nil { + log.Fatal(err) + } + } + } +} diff --git a/seed.go b/seed.go deleted file mode 100644 index 31de3a6..0000000 --- a/seed.go +++ /dev/null @@ -1,49 +0,0 @@ -package atom - -import ( - "log" - - "github.com/rogeecn/atom/container" - "github.com/rogeecn/atom/contracts" - - "github.com/brianvoe/gofakeit/v6" - "github.com/spf13/cobra" - "go.uber.org/dig" - "gorm.io/gorm" -) - -func WithSeeder(rootCmd *cobra.Command) *cobra.Command { - rootCmd.AddCommand(seedCmd) - return rootCmd -} - -// seedCmd represents the seed command -var seedCmd = &cobra.Command{ - Use: "seed", - Short: "seed databases", - Long: `seed your database with data using seeders.`, - RunE: func(cmd *cobra.Command, args []string) error { - return container.Container.Invoke(func(c SeedersContainer) error { - if len(c.Seeders) == 0 { - log.Print("no seeder exists") - return nil - } - - for _, seeder := range c.Seeders { - seeder.Run(c.Faker, c.DB) - } - return nil - }) - }, - PostRun: func(cmd *cobra.Command, args []string) { - log.Println("BINGO! seeding done") - }, -} - -type SeedersContainer struct { - dig.In - - DB *gorm.DB - Faker *gofakeit.Faker - Seeders []contracts.Seeder `group:"seeders"` -} diff --git a/seeder.go b/seeder.go new file mode 100644 index 0000000..432c20a --- /dev/null +++ b/seeder.go @@ -0,0 +1,48 @@ +package atom + +import ( + "log" + + "github.com/rogeecn/atom/container" + "github.com/rogeecn/atom/contracts" + + "github.com/brianvoe/gofakeit/v6" + "github.com/spf13/cobra" + "go.uber.org/dig" + "gorm.io/gorm" +) + +type SeedersContainer struct { + dig.In + + DB *gorm.DB + Faker *gofakeit.Faker + Seeders []contracts.Seeder `group:"seeders"` +} + +func withSeederCommand(rootCmd *cobra.Command) *cobra.Command { + // seedCmd represents the seed command + var seedCmd = &cobra.Command{ + Use: "seed", + Short: "seed databases", + Long: `seed your database with data using seeders.`, + RunE: func(cmd *cobra.Command, args []string) error { + return container.Container.Invoke(func(c SeedersContainer) error { + if len(c.Seeders) == 0 { + log.Print("no seeder exists") + return nil + } + + for _, seeder := range c.Seeders { + seeder.Run(c.Faker, c.DB) + } + return nil + }) + }, + PostRun: func(cmd *cobra.Command, args []string) { + log.Println("BINGO! seeding done") + }, + } + rootCmd.AddCommand(seedCmd) + return rootCmd +} diff --git a/services/http.go b/services/http.go index 095e390..dac2c60 100644 --- a/services/http.go +++ b/services/http.go @@ -10,7 +10,7 @@ type Http struct { dig.In Service http.Service - Routes []http.Route `group:"route"` + Routes []http.Route `group:"routes"` } func ServeHttp() error {