Skip to content

Commit de5a561

Browse files
committed
feat : migrator implementation
Signed-off-by: DavidDexter <dmwangi@kineticengines.co.ke>
1 parent 42ecefd commit de5a561

File tree

15 files changed

+285
-81
lines changed

15 files changed

+285
-81
lines changed

.gitignore

-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
gormgx*
21
cover*

README.md

+6
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,9 @@ gormgx.go -v make-migrations
4747
- Models specifications should be in one (1) go file. Preferably `models.go`
4848
- Override Foreign Key must be of the form `ModelNameRefer`.
4949
- Foreign key must be `Interface{}`. Gormgx will extract the extact model from the tags
50+
51+
## Environment
52+
53+
```sh
54+
export DATABASE_DSN="host=localhost user=gorm password=gorm dbname=gorm port=9920 sslmode=disable TimeZone=Africa/Nairobi"
55+
```

env.sh

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export DATABASE_DSN="host=localhost user=gorm password=gorm dbname=gorm port=9920 sslmode=disable TimeZone=Africa/Nairobi"

example/app/main.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,13 @@ import (
1010

1111
func main() {
1212

13-
dsn := "host=localhost user=gorm password=gorm dbname=gorm port=5432 sslmode=disable TimeZone=Africa/Nairobi"
14-
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
13+
// dsn := "host=localhost user=gorm password=gorm dbname=gorm port=5432 sslmode=disable TimeZone=Africa/Nairobi"
14+
// db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
15+
16+
db, err := gorm.Open(postgres.New(postgres.Config{
17+
DSN: "host=localhost user=gorm password=gorm dbname=gorm port=5432 sslmode=disable TimeZone=Africa/Nairobi",
18+
PreferSimpleProtocol: true, // disables implicit prepared statement usage
19+
}), &gorm.Config{})
1520

1621
if err != nil {
1722
panic("failed to connect database")

example/models/models.go

+16-14
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,6 @@ import (
77
"gorm.io/gorm"
88
)
99

10-
// Product ...
11-
type Product struct {
12-
Code string
13-
Price uint
14-
}
15-
16-
// // IsModel ..
17-
// func (m *Product) IsModel() bool {
18-
// return true
19-
// }
20-
2110
// User ...
2211
type User struct {
2312
gorm.Model
@@ -65,9 +54,9 @@ type Accounts struct {
6554
}
6655

6756
// IsModel ..
68-
func (m *Accounts) IsModel() bool {
69-
return true
70-
}
57+
// func (m *Accounts) IsModel() bool {
58+
// return true
59+
// }
7160

7261
// Credentials holds auth credentials when user logs in via afya notes console
7362
// This table is populated on first sign up
@@ -82,9 +71,22 @@ type Credentials struct {
8271
// return true
8372
// }
8473

74+
// Product ...
75+
type Product struct {
76+
Code string
77+
Price uint
78+
Company interface{} `gorm:"foreignKey:CompanyRefer;foreignKeyRefField:guid"`
79+
}
80+
81+
// IsModel ..
82+
func (m *Product) IsModel() bool {
83+
return true
84+
}
85+
8586
// Company ....
8687
type Company struct {
8788
ID int
89+
GUID string `gorm:"not null;unique;column:guid"`
8890
Name string
8991
}
9092

gormgx.yaml

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Where all migrations files will be located
2+
migrations: migrations/*.gormgx
3+
4+
# Where your gorm models are located
5+
models:
6+
- example/models/models.go
7+
8+
# Which database type to use. Defaults to "postgres". Choices : [postgres,mysql,sqlite]
9+
dialect: postgres
10+
11+
# Which driver to use. Defaults to "default". Choices : [default,cloudsqlpostgres]
12+
driver_name: default
13+
14+
# Optional : set the time zone for time.Time fields. Defaults to "Africa/Nairobi"
15+
time_zone: Africa/Nairobi
16+

pkg/commands/intialize.go pkg/commands/initialize.go

+15-12
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ import (
1212
"github.com/urfave/cli/v2"
1313
)
1414

15-
// IntializeCmd ...
16-
var IntializeCmd = &cli.Command{
17-
Name: definitions.IntializeCmd,
18-
Usage: definitions.IntializeCmdUsage,
15+
// InitializeCmd ...
16+
var InitializeCmd = &cli.Command{
17+
Name: definitions.InitializeCmd,
18+
Usage: definitions.InitializeCmdUsage,
1919
Action: func(c *cli.Context) error {
20-
i := initializor{runner: engine.NewRunner()}
20+
i := initializer{runner: engine.NewRunner()}
2121
return i.initialize()
2222
},
2323
}
@@ -30,19 +30,22 @@ migrations: migrations/*.gormgx
3030
models:
3131
- models/models.go
3232
33-
# Optional: set to add "gorm.Model" to your models
34-
add_gorm_model: true
33+
# Which database type to use. Defaults to "postgres". Choices : [postgres,mysql,sqlite]
34+
dialect: postgres
35+
36+
# Which driver to use. Defaults to "default". Choices : [default,cloudsqlpostgres]
37+
driver_name: default
3538
3639
# Optional : set the time zone for time.Time fields. Defaults to "Africa/Nairobi"
3740
time_zone: Africa/Nairobi
3841
3942
`))
4043

41-
type initializor struct {
44+
type initializer struct {
4245
runner definitions.Worker
4346
}
4447

45-
func (i *initializor) initialize() error {
48+
func (i *initializer) initialize() error {
4649
exists, err := i.checkIfInitialized()
4750
if err != nil {
4851
return err
@@ -55,7 +58,7 @@ func (i *initializor) initialize() error {
5558

5659
// checkIfInitialized checks for the presence of gormgx.yaml file
5760
// returns an error if it absent
58-
func (i *initializor) checkIfInitialized() (bool, error) {
61+
func (i *initializer) checkIfInitialized() (bool, error) {
5962
file, err := i.runner.GormgxFilePath()
6063
if err != nil {
6164
return false, err
@@ -66,7 +69,7 @@ func (i *initializor) checkIfInitialized() (bool, error) {
6669
return true, nil
6770
}
6871

69-
func (i *initializor) createGormgxYamlFile() error {
72+
func (i *initializer) createGormgxYamlFile() error {
7073
path, err := i.runner.GormgxFilePath()
7174
if err != nil {
7275
return err
@@ -85,6 +88,6 @@ func (i *initializor) createGormgxYamlFile() error {
8588
return fmt.Errorf("unable to write gormgx file: " + err.Error())
8689
}
8790

88-
fmt.Println(definitions.AfterIntializeMessage)
91+
fmt.Println(definitions.AfterInitializeMessage)
8992
return nil
9093
}

pkg/commands/make_migrations.go

+16-13
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ type MakeMigration interface {
3636
hasError() error
3737
loadYaml() MakeMigration
3838
setIntent() (MakeMigration, error)
39-
buildIntialIntent() (MakeMigration, error)
40-
buildAfterIntialIntent() (MakeMigration, error)
39+
buildInitialIntent() (MakeMigration, error)
40+
buildAfterInitialIntent() (MakeMigration, error)
4141
}
4242

4343
// MgxMaker ...
@@ -65,17 +65,20 @@ func NewMgxMaker(path string, verbose bool) MakeMigration {
6565

6666
// Migrate ...
6767
func (m *MgxMaker) Migrate() error {
68+
// check if required envs are set. Otherwise, kill the app early
69+
m.runner.FetchConnectionDNSFromEnv()
70+
6871
// read gormgx.yaml file
6972
if err := m.hasError(); err != nil {
7073
return err
7174
}
7275
if _, err := m.loadYaml().setIntent(); err != nil {
7376
return err
7477
}
75-
if _, err := m.buildIntialIntent(); err != nil {
78+
if _, err := m.buildInitialIntent(); err != nil {
7679
return err
7780
}
78-
if _, err := m.buildAfterIntialIntent(); err != nil {
81+
if _, err := m.buildAfterInitialIntent(); err != nil {
7982
return err
8083
}
8184
// called to catch any errors in the final steps
@@ -110,20 +113,20 @@ func (m *MgxMaker) setIntent() (MakeMigration, error) {
110113
}
111114

112115
m.runner.PrintVerbose(m.verbose, log.InfoLevel, "Setting intent")
113-
if !m.runner.CheckIntialMigrationExists() {
114-
m.intent = definitions.IntialIntent
116+
if !m.runner.CheckInitialMigrationExists() {
117+
m.intent = definitions.InitialIntent
115118
return m, nil
116119
}
117120

118-
m.intent = definitions.AfterIntialIntent
121+
m.intent = definitions.AfterInitialIntent
119122
return m, nil
120123
}
121124

122-
func (m *MgxMaker) buildIntialIntent() (MakeMigration, error) {
125+
func (m *MgxMaker) buildInitialIntent() (MakeMigration, error) {
123126
if err := m.hasError(); err != nil {
124127
return nil, err
125128
}
126-
if m.intent == definitions.IntialIntent {
129+
if m.intent == definitions.InitialIntent {
127130
if err := m.runner.ReadIntentModels(m.modelsPkgs, m.config.Models, m.verbose); err != nil {
128131
m.errorsCache.Store(errorKey, err)
129132
return nil, err
@@ -151,24 +154,24 @@ func (m *MgxMaker) buildIntialIntent() (MakeMigration, error) {
151154
return m.createMigrationFiles()
152155
}
153156

154-
func (m *MgxMaker) buildAfterIntialIntent() (MakeMigration, error) {
157+
func (m *MgxMaker) buildAfterInitialIntent() (MakeMigration, error) {
155158
if err := m.hasError(); err != nil {
156159
return nil, err
157160
}
158-
if m.intent == definitions.AfterIntialIntent {
161+
if m.intent == definitions.AfterInitialIntent {
159162
return m, nil
160163
}
161164
return m, nil
162165
}
163166

164167
func (m *MgxMaker) createMigrationFiles() (MakeMigration, error) {
165-
if m.intent == definitions.IntialIntent {
168+
if m.intent == definitions.InitialIntent {
166169
var wg sync.WaitGroup
167170
for tableName, tableTree := range m.tables {
168171
wg.Add(1)
169172
go func(w *sync.WaitGroup, tn string, tt *definitions.TableTree, mgx *MgxMaker) {
170173
defer wg.Done()
171-
if err := migrator.NewMigratorWorker(tn, tt, mgx.verbose, mgx.runner).RunIntialIntent(); err != nil {
174+
if err := migrator.NewMigratorWorker(tn, tt, mgx.verbose, mgx.runner).RunInitialIntent(); err != nil {
172175
m.errorsCache.Store(errorKey, err)
173176
}
174177

pkg/definitions/consts.go

+14-13
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,19 @@ import (
66

77
// context constants
88
const (
9-
AppName = "Gorm Migrations [gormgx]"
10-
AppDescription = `Gorm Migrations CLI utility manages SQL migrations for gorm. It implements the same API as Django migrations, so you should be at home if coming from Django.`
11-
AppUsage = "Making database changes ease, manageable and maintainable"
12-
GormgxYamlFileName = "gormgx.yaml"
13-
IntialMigrationFileName = "00001_init.gormgx"
14-
DefaultMIgrationsPath = "migrations"
15-
GormModelInterfaceFile = "pkg/definitions/gorm_model.go"
9+
AppName = "Gorm Migrations [gormgx]"
10+
AppDescription = `Gorm Migrations CLI utility manages SQL migrations for gorm. It implements the same API as Django migrations, so you should be at home if coming from Django.`
11+
AppUsage = "Making database changes ease, manageable and maintainable"
12+
GormgxYamlFileName = "gormgx.yaml"
13+
InitialMigrationFileName = "00001_init.gormgx"
14+
DefaultMIgrationsPath = "migrations"
15+
GormModelInterfaceFile = "pkg/definitions/gorm_model.go"
16+
GormDatabaseDSNEnv = "DATABASE_DSN"
1617
)
1718

1819
// commands
1920
const (
20-
IntializeCmd = "init"
21+
InitializeCmd = "init"
2122
MakemigrationsCmd = "make-migrations"
2223
ApplyCmd = "apply"
2324
RevertCmd = "revert"
@@ -28,7 +29,7 @@ const (
2829

2930
// commands usage descriptions
3031
const (
31-
IntializeCmdUsage = "intializes the default gormgx configuration. It create gormgx.yaml in the current working directory"
32+
InitializeCmdUsage = "initializes the default gormgx configuration. It create gormgx.yaml in the current working directory"
3233
MakemigrationsCmdUsage = "analyzes models and create migrations"
3334
ApplyCmdUsage = "commits migrations to the database"
3435
RevertCmdUsage = "undoes the previously performed migration"
@@ -51,14 +52,14 @@ const (
5152
type Intent int
5253

5354
const (
54-
// IntialIntent ...
55-
IntialIntent Intent = iota
55+
// InitialIntent ...
56+
InitialIntent Intent = iota
5657

5758
// AfterIntialIntent ...
58-
AfterIntialIntent
59+
AfterInitialIntent
5960
)
6061

6162
// response message
6263
var (
63-
AfterIntializeMessage = emoji.Sprint(`:beer: Hurray!!! Gormgx has been intialized. Check "gormgx.yaml" file and amend it to your needs. Remember not to remove it`)
64+
AfterInitializeMessage = emoji.Sprint(`:beer: Hurray!!! Gormgx has been intialized. Check "gormgx.yaml" file and amend it to your needs. Remember not to remove it`)
6465
)

pkg/definitions/models.go

+6-4
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ import (
66

77
// Config ...
88
type Config struct {
9-
Migrations string `yaml:"migrations"`
10-
Models []string `yaml:"models"`
11-
AddGormModel bool `yaml:"add_gorm_model"`
12-
TimeZone string `yaml:"time_zone"`
9+
Migrations string `yaml:"migrations"`
10+
Models []string `yaml:"models"`
11+
Dialect string `yaml:"dialect"`
12+
DriverName string `yaml:"driver_name"`
13+
DSN string `yaml:"dsn"`
14+
TimeZone string `yaml:"time_zone"`
1315
}
1416

1517
// Model is a same model as defines in `gorm.Model`

pkg/definitions/ops.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ type OpColumn struct {
7979
Size int
8080

8181
// the default of the the column, It's an interface since we don't know the `DatabaseType` for hand
82-
Default interface{}
82+
Default string
8383

8484
// the timezone to use for date fields. All date/time fields in gormgx are timezone by default
8585
TimeZone string

pkg/definitions/worker.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ type Worker interface {
1414

1515
ReadYamlToconfig() (*Config, error)
1616

17-
CheckIntialMigrationExists() bool
17+
CheckInitialMigrationExists() bool
1818

1919
ReadIntentModels(modelsPkgs *[]*types.Package, paths []string, verbose bool) error
2020

@@ -29,4 +29,6 @@ type Worker interface {
2929
NameTypeFieldsMeta(v *types.Named) *TableTree
3030

3131
SplitTypedNameToObjectName(t *types.Named) string
32+
33+
FetchConnectionDNSFromEnv() *string
3234
}

0 commit comments

Comments
 (0)