Skip to content

Commit

Permalink
Feat/setup logger (#48)
Browse files Browse the repository at this point in the history
- Add zap logger
- Add zapFactory to build the logger
- Add LogService to manage logging
- Add verbose and silent flags
  • Loading branch information
alexandremr01 authored Jul 4, 2022
1 parent 409a599 commit 889e2e9
Show file tree
Hide file tree
Showing 19 changed files with 306 additions and 41 deletions.
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ release:
.PHONY: mock
mock:
@mockgen -source=domain/driver.go -destination=mock/domain/driver_mock.go -package=domain_mock
@mockgen -source=domain/diff_deque.go -destination=mock/domain/diff_deque_mock.go -package=domain_mock
@mockgen -source=infrastructure/clock.go -destination=mock/infrastructure/clock_mock.go -package=infrastructure_mock
@mockgen -source=infrastructure/file.go -destination=mock/infrastructure/file_mock.go -package=infrastructure_mock
@mockgen -source=applications/migrationscripts.go -destination=mock/applications/migrationscripts_mock.go -package=applications_mock
@mockgen -source=applications/log.go -destination=mock/applications/log_mock.go -package=applications_mock
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ Set through command flag `--driver`.

- **dir**: Migrations directory. <br/>
Set through command flag `--dir`.

#### Optional flags

- **verbose**: Prints info logs. Mutually exclusive with `silent`.

- **silent**: Only prints critical logs. Mutually exclusive with `verbose`.


### Execute migrations

Requires: **database**, **dir**, **driver** <br/>
Expand Down
File renamed without changes.
File renamed without changes.
8 changes: 4 additions & 4 deletions applications/migrationscripts.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ package applications

import (
"fmt"
"log"

"github.com/migratemgr8/mgr8/domain"
"github.com/migratemgr8/mgr8/infrastructure"
)
Expand All @@ -18,13 +16,15 @@ type migrationFileService struct {
fileService infrastructure.FileService
driver domain.Driver
fileNameFormatter FileNameFormatter
logService infrastructure.LogService
}

func NewMigrationFileService(fService infrastructure.FileService, fileNameFormatter FileNameFormatter, driver domain.Driver) *migrationFileService {
func NewMigrationFileService(fService infrastructure.FileService, fileNameFormatter FileNameFormatter, driver domain.Driver, logService infrastructure.LogService) *migrationFileService {
return &migrationFileService{
fileService: fService,
driver: driver,
fileNameFormatter: fileNameFormatter,
logService: logService,
}
}

Expand Down Expand Up @@ -54,7 +54,7 @@ func (g *migrationFileService) GetSchemaFromFile(filename string) (*domain.Schem

func (g *migrationFileService) WriteStatementsToFile(migrationDir string, statements []string, migrationNumber int, migrationType string) error {
filename := g.fileNameFormatter.FormatFilename(migrationNumber, migrationType)
log.Printf("Generating file %s migration %s", migrationType, filename)
g.logService.Info("Generating file %s migration %s", migrationType, filename)
content := g.driver.Deparser().WriteScript(statements)
return g.fileService.Write(migrationDir, filename, content)
}
Expand Down
17 changes: 14 additions & 3 deletions applications/migrationscripts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ var _ = Describe("Migration Scripts", func() {
driver.EXPECT().Deparser().Return(mockDeparser)
mockDeparser.EXPECT().WriteScript([]string{"statement"}).Return("sql")
fileService.EXPECT().Write("directory", "formatted_filename", "sql")
subject = NewMigrationFileService(fileService, formatter, driver)
mockLogService := anyLog(ctrl)

subject = NewMigrationFileService(fileService, formatter, driver, mockLogService)
})
When(fmt.Sprintf("Asked to generated"), func() {
It("Generates expected file", func() {
Expand All @@ -83,7 +85,8 @@ var _ = Describe("Migration Scripts", func() {
ctrl := gomock.NewController(_t)
clock := infrastructure_mock.NewMockClock(ctrl)
fileService = infrastructure_mock.NewMockFileService(ctrl)
subject = NewMigrationFileService(fileService, NewFileNameFormatter(clock), domain_mock.NewMockDriver(ctrl))
mockLogService := anyLog(ctrl)
subject = NewMigrationFileService(fileService, NewFileNameFormatter(clock), domain_mock.NewMockDriver(ctrl), mockLogService)
})
When("Has two migration files", func() {
It("Next migration number is 3", func() {
Expand Down Expand Up @@ -131,7 +134,7 @@ var _ = Describe("Migration Scripts", func() {
clock := infrastructure_mock.NewMockClock(ctrl)
fileService = infrastructure_mock.NewMockFileService(ctrl)
driver = domain_mock.NewMockDriver(ctrl)
subject = NewMigrationFileService(fileService, NewFileNameFormatter(clock), driver)
subject = NewMigrationFileService(fileService, NewFileNameFormatter(clock), driver, applications_mock.NewMockLogService(ctrl))
})
When("Reads file successfully", func() {
It("Generates expected filename", func() {
Expand All @@ -154,3 +157,11 @@ var _ = Describe("Migration Scripts", func() {
})

})

func anyLog(ctrl *gomock.Controller) *applications_mock.MockLogService{
mockLogService := applications_mock.NewMockLogService(ctrl)
mockLogService.EXPECT().Info(gomock.Any()).AnyTimes()
mockLogService.EXPECT().Critical(gomock.Any()).AnyTimes()
mockLogService.EXPECT().Debug(gomock.Any()).AnyTimes()
return mockLogService
}
2 changes: 1 addition & 1 deletion cmd/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ type Migrations struct {
isUpType bool
}

func (a *apply) execute(args []string, databaseURL string, migrationsDir string, driver domain.Driver) error {
func (a *apply) execute(args []string, databaseURL string, migrationsDir string, driver domain.Driver, verbosity infrastructure.LogLevel) error {
a.hashService = applications.NewHashService(infrastructure.NewFileService())
dir := migrationsDir
migrationFiles, err := getMigrationsFiles(dir)
Expand Down
40 changes: 37 additions & 3 deletions cmd/command.go
Original file line number Diff line number Diff line change
@@ -1,34 +1,68 @@
package cmd

import (
"errors"
"log"

"github.com/migratemgr8/mgr8/domain"
"github.com/migratemgr8/mgr8/drivers"
"github.com/migratemgr8/mgr8/infrastructure"

"github.com/spf13/cobra"
)

var defaultDriverName = string(drivers.Postgres)

type CommandExecutor interface {
execute(args []string, databaseURL string, migrationsDir string, driver domain.Driver) error
execute(args []string, databaseURL string, migrationsDir string, driver domain.Driver, verbosity infrastructure.LogLevel) error
}

type Command struct {
driverName string
databaseURL string
migrationsDir string
cmd CommandExecutor

cmd CommandExecutor
}

func (c *Command) Execute(cmd *cobra.Command, args []string) {
verbose, err := cmd.Flags().GetBool(verboseFlag)
if err != nil {
panic(err)
}
silent, err := cmd.Flags().GetBool(silentFlag)
if err != nil {
panic(err)
}

driver, err := drivers.GetDriver(c.driverName)
if err != nil {
log.Fatal(err)
}

err = c.cmd.execute(args, c.databaseURL, c.migrationsDir, driver)
logLevel, err := c.getLogLevel(verbose, silent)
if err != nil {
log.Fatal(err)
}

err = c.cmd.execute(args, c.databaseURL, c.migrationsDir, driver, logLevel)
if err != nil {
log.Fatal(err)
}
}

func (c *Command) getLogLevel(verbose, silent bool) (infrastructure.LogLevel, error) {
if silent && verbose {
return "", errors.New("flags silent and verbose are mutually exclusive")
}

if silent {
return infrastructure.CriticalLogLevel, nil
}

if verbose {
return infrastructure.DebugLogLevel, nil
}

return infrastructure.InfoLogLevel, nil
}
11 changes: 8 additions & 3 deletions cmd/diff.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cmd

import (
"fmt"
"log"

"github.com/migratemgr8/mgr8/applications"
Expand All @@ -10,19 +11,23 @@ import (

type diff struct{}

func (g *diff) execute(args []string, databaseURL string, migrationsDir string, driver domain.Driver) error {
func (g *diff) execute(args []string, databaseURL string, migrationsDir string, driver domain.Driver, verbosity infrastructure.LogLevel) error {
newSchemaPath := args[0]

fileService := infrastructure.NewFileService()
clock := infrastructure.NewClock()
logService, err := infrastructure.NewLogService(verbosity)
if err != nil {
return fmt.Errorf("could not start logger, error: %w", err)
}

generateCommand := applications.NewGenerateCommand(
driver,
applications.NewMigrationFileService(fileService, applications.NewFileNameFormatter(clock), driver),
applications.NewMigrationFileService(fileService, applications.NewFileNameFormatter(clock), driver, logService),
fileService,
)

err := generateCommand.Execute(&applications.GenerateParameters{
err = generateCommand.Execute(&applications.GenerateParameters{
OldSchemaPath: ".mgr8/reference.sql",
NewSchemaPath: newSchemaPath,
MigrationDir: migrationsDir,
Expand Down
9 changes: 7 additions & 2 deletions cmd/empty.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,16 @@ type empty struct {
emptyCommand applications.EmptyCommand
}

func (c *empty) execute(args []string, databaseURL string, migrationsDir string, driver domain.Driver) error {
func (c *empty) execute(args []string, databaseURL string, migrationsDir string, driver domain.Driver, verbosity infrastructure.LogLevel) error {
if c.emptyCommand == nil {
fileService := infrastructure.NewFileService()
clock := infrastructure.NewClock()
migrationFileService := applications.NewMigrationFileService(fileService, applications.NewFileNameFormatter(clock), driver)
logService, err := infrastructure.NewLogService(verbosity)
if err != nil {
log.Fatal(err)
}

migrationFileService := applications.NewMigrationFileService(fileService, applications.NewFileNameFormatter(clock), driver, logService)
c.emptyCommand = applications.NewEmptyCommand(migrationFileService)
}

Expand Down
18 changes: 13 additions & 5 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ import (
"github.com/spf13/cobra"
)

const defaultMigrationDir = "migrations"
const (
defaultMigrationDir = "migrations"
verboseFlag = "verbose"
silentFlag = "silent"
)

func Execute() {
rootCmd := &cobra.Command{
Expand All @@ -16,6 +20,9 @@ func Execute() {
Long: `Long version: mgr8 is an agnostic tool that abstracts database migration operations`,
}

rootCmd.PersistentFlags().Bool(verboseFlag, false, "Verbose")
rootCmd.PersistentFlags().Bool(silentFlag, false, "Silent")

generateCmd := &cobra.Command{
Use: "generate",
Short: "generate creates migration scripts",
Expand All @@ -37,21 +44,22 @@ func Execute() {
Use: "empty",
Short: "empty creates empty migration",
Run: emptyCommand.Execute,
Args: cobra.NoArgs,
}
emptyCmd.Flags().StringVar(&emptyCommand.migrationsDir, "dir", defaultMigrationDir, "Migrations Directory")
emptyCmd.Flags().StringVar(&emptyCommand.driverName, "driver", defaultDriverName, "Driver Name")

initCommand := &InitCommand{}
initCmd := &cobra.Command{
Use: "init",
Use: "init file",
Short: "init sets the schema as reference",
Run: initCommand.Execute,
Args: cobra.MinimumNArgs(1),
}

checkCommand := &CheckCommand{}
checkCmd := &cobra.Command{
Use: "check",
Use: "check file",
Short: "check returns 0 if files match",
Run: checkCommand.Execute,
Args: cobra.MinimumNArgs(1),
Expand All @@ -61,7 +69,7 @@ func Execute() {

applyCommand := Command{cmd: &apply{}}
applyCmd := &cobra.Command{
Use: "apply",
Use: "apply n",
Short: "apply runs migrations in the selected database",
Run: applyCommand.Execute,
Args: cobra.MinimumNArgs(1),
Expand All @@ -72,7 +80,7 @@ func Execute() {

validateCommand := Command{cmd: &validate{}}
validateCmd := &cobra.Command{
Use: "validate",
Use: "validate file",
Short: "validate compares migrations sql scripts against hashing ",
Run: validateCommand.Execute,
Args: cobra.MinimumNArgs(1),
Expand Down
2 changes: 1 addition & 1 deletion cmd/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (

type validate struct{}

func (v *validate) execute(args []string, databaseURL string, migrationsDir string, driver domain.Driver) error {
func (v *validate) execute(args []string, databaseURL string, migrationsDir string, driver domain.Driver, verbosity infrastructure.LogLevel) error {
dir := args[0]
return driver.ExecuteTransaction(databaseURL, func() error {
err := applications.CheckAndInstallTool(driver)
Expand Down
7 changes: 4 additions & 3 deletions domain/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ func NewTable(name string, columns map[string]*Column) *Table {
}

type Column struct {
Datatype string
Parameters map[string]interface{}
IsNotNull bool
Datatype string
Parameters map[string]interface{}
IsNotNull bool
DefaultValue interface{}
}

type View struct {
Expand Down
20 changes: 16 additions & 4 deletions drivers/postgres/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,15 +275,27 @@ func (d *postgresDriver) parseColumn(columnDefinition *pg_query.ColumnDef) *doma
}

isNotNull := false
defaultValue := interface{}(nil)

for _, constraint := range columnDefinition.Constraints {
if constraint.GetConstraint().GetContype().String() == "CONSTR_NOTNULL" {
if constraint.GetConstraint().GetContype() == pg_query.ConstrType_CONSTR_NOTNULL {
isNotNull = true
}
if constraint.GetConstraint().GetContype() == pg_query.ConstrType_CONSTR_DEFAULT {
constant := constraint.GetConstraint().RawExpr.GetAConst().Val
switch constant.Node.(type) {
case *pg_query.Node_String_:
defaultValue = constant.GetString_().Str
case *pg_query.Node_Integer:
defaultValue = constant.GetInteger().Ival
}
}
}

return &domain.Column{
Datatype: datatype,
Parameters: parameters,
IsNotNull: isNotNull,
Datatype: datatype,
Parameters: parameters,
IsNotNull: isNotNull,
DefaultValue: defaultValue,
}
}
9 changes: 4 additions & 5 deletions drivers/postgres/postgres_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,15 @@ var _ = Describe("Postgres Driver", func() {
BeforeEach(func() {
subject = NewPostgresDriver()
})

When("Table has all data types", func() {
It("Parses each of them", func() {
migration := `
CREATE TABLE users (
social_number VARCHAR(9) PRIMARY KEY,
phone VARCHAR(11),
name VARCHAR(15) NOT NULL,
name VARCHAR(15) NOT NULL DEFAULT 'oi',
age INTEGER,
size INT,
size INT DEFAULT 5,
height DECIMAL(2, 3),
ddi VARCHAR(3)
);
Expand All @@ -45,10 +44,10 @@ var _ = Describe("Postgres Driver", func() {
Columns: map[string]*domain.Column{
"social_number": {Datatype: "varchar", IsNotNull: false, Parameters: map[string]interface{}{"size": int32(9)}},
"phone": {Datatype: "varchar", IsNotNull: false, Parameters: map[string]interface{}{"size": int32(11)}},
"name": {Datatype: "varchar", IsNotNull: true, Parameters: map[string]interface{}{"size": int32(15)}},
"name": {Datatype: "varchar", IsNotNull: true, Parameters: map[string]interface{}{"size": int32(15)}, DefaultValue: "oi"},
"ddi": {Datatype: "varchar", IsNotNull: false, Parameters: map[string]interface{}{"size": int32(3)}},
"age": {Datatype: "int4", IsNotNull: false, Parameters: map[string]interface{}{}},
"size": {Datatype: "int4", IsNotNull: false, Parameters: map[string]interface{}{}},
"size": {Datatype: "int4", IsNotNull: false, Parameters: map[string]interface{}{}, DefaultValue: int32(5)},
"height": {Datatype: "numeric", IsNotNull: false, Parameters: map[string]interface{}{"precision": int32(2), "scale": int32(3)}},
},
},
Expand Down
Loading

0 comments on commit 889e2e9

Please sign in to comment.