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

Add option to use stdout #63

Merged
merged 2 commits into from
Nov 10, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions analyzer/analyzer.go
Original file line number Diff line number Diff line change
@@ -123,7 +123,7 @@ func (a analyzer) GetTables(db database.Connector, selectedSchemas []string) ([]
return util.Map2(selectedTables, func(value string) database.TableDetail {
res, err := database.ParseTableName(value, selectedSchemas)
if err != nil {
logrus.Error("Could not parse table name", value)
logrus.Error("Could not parse table name ", value)
}

return res
@@ -165,7 +165,7 @@ func (a analyzer) GetTables(db database.Connector, selectedSchemas []string) ([]
return util.Map2(surveyResult, func(value string) database.TableDetail {
res, err := database.ParseTableName(value, selectedSchemas)
if err != nil {
logrus.Error("Could not parse table name", value)
logrus.Error("Could not parse table name ", value)
}

return res
11 changes: 9 additions & 2 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -4,15 +4,20 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres
to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) (after version 0.0.5).

## [0.12.0] - 2024-0
### Added
- new `--outputMode` option ([PR #63](https://github.com/KarnerTh/mermerd/pull/63))

### Changed
- go 1.23 is now used

## [0.11.0] - 2024-06-16
### Added
- new `--ignoreTables` option ([PR #59](https://github.com/KarnerTh/mermerd/pull/59))

### Changed
- go 1.22 is now used

### Fixed

## [0.10.0] - 2023-11-21
### Added
- Support relationship labels ([PR #50](https://github.com/KarnerTh/mermerd/pull/50))
@@ -155,6 +160,8 @@ by `--showDescriptions enumValues` (for details see [PR #32](https://github.com/
### Added
- Initial release of mermerd

[0.12.0]: https://github.com/KarnerTh/mermerd/releases/tag/v0.12.0

[0.11.0]: https://github.com/KarnerTh/mermerd/releases/tag/v0.11.0

[0.10.0]: https://github.com/KarnerTh/mermerd/releases/tag/v0.10.0
60 changes: 42 additions & 18 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -5,7 +5,6 @@ import (
"io"
"os"

"github.com/fatih/color"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/viper"
@@ -24,14 +23,18 @@ var rootCmd = &cobra.Command{
Short: "Create Mermaid ERD diagrams from existing tables",
Long: "Create Mermaid ERD diagrams from existing tables",
Run: func(cmd *cobra.Command, args []string) {
presentation.ShowIntro()
config := config.NewConfig()
conf := config.NewConfig()
if runConfig != "" {
presentation.ShowInfo(conf, fmt.Sprintf("Using run configuration (from %s)", runConfig))
}

presentation.ShowIntro(conf)
connectorFactory := database.NewConnectorFactory()
questioner := analyzer.NewQuestioner()
analyzer := analyzer.NewAnalyzer(config, connectorFactory, questioner)
diagram := diagram.NewDiagram(config)
analyzer := analyzer.NewAnalyzer(conf, connectorFactory, questioner)
diagram := diagram.NewDiagram(conf)

if !config.Debug() {
if !conf.Debug() {
logrus.SetOutput(io.Discard)
}

@@ -42,14 +45,33 @@ var rootCmd = &cobra.Command{
os.Exit(1)
}

err = diagram.Create(result)
var wr io.Writer
if conf.OutputMode() == config.File {
f, err := os.Create(conf.OutputFileName())
defer f.Close()
if err != nil {
logrus.Error(err)
presentation.ShowError()
os.Exit(1)
}

wr = f
} else if conf.OutputMode() == config.Stdout {
wr = os.Stdout
} else {
logrus.Errorf("Output mode %s not suppported", conf.OutputMode())
presentation.ShowError()
os.Exit(1)
}

err = diagram.Create(wr, result)
if err != nil {
logrus.Error(err)
presentation.ShowError()
os.Exit(1)
}

presentation.ShowSuccess(config.OutputFileName())
presentation.ShowSuccess(conf, conf.OutputFileName())
},
}

@@ -76,24 +98,27 @@ func init() {
rootCmd.Flags().StringP(config.SchemaKey, "s", "", "schema that should be used")
rootCmd.Flags().StringP(config.OutputFileNameKey, "o", "result.mmd", "output file name")
rootCmd.Flags().String(config.SchemaPrefixSeparator, ".", "the separator that should be used between schema and table name")
var outputMode = config.File
rootCmd.Flags().Var(&outputMode, config.OutputMode, `output mode (file, stdout)`)
rootCmd.Flags().StringSlice(config.ShowDescriptionsKey, []string{""}, "show 'notNull', 'enumValues' and/or 'columnComments' in the description column")
rootCmd.Flags().StringSlice(config.SelectedTablesKey, []string{""}, "tables to include")

bindFlagToViper(config.ShowAllConstraintsKey)
bindFlagToViper(config.UseAllTablesKey)
bindFlagToViper(config.IgnoreTables)
bindFlagToViper(config.UseAllSchemasKey)
bindFlagToViper(config.ConnectionStringKey)
bindFlagToViper(config.DebugKey)
bindFlagToViper(config.OmitConstraintLabelsKey)
bindFlagToViper(config.OmitAttributeKeysKey)
bindFlagToViper(config.EncloseWithMermaidBackticksKey)
bindFlagToViper(config.ConnectionStringKey)
bindFlagToViper(config.SchemaKey)
bindFlagToViper(config.IgnoreTables)
bindFlagToViper(config.OmitAttributeKeysKey)
bindFlagToViper(config.OmitConstraintLabelsKey)
bindFlagToViper(config.OutputFileNameKey)
bindFlagToViper(config.OutputMode)
bindFlagToViper(config.SchemaKey)
bindFlagToViper(config.SchemaPrefixSeparator)
bindFlagToViper(config.SelectedTablesKey)
bindFlagToViper(config.ShowAllConstraintsKey)
bindFlagToViper(config.ShowDescriptionsKey)
bindFlagToViper(config.ShowSchemaPrefix)
bindFlagToViper(config.SchemaPrefixSeparator)
bindFlagToViper(config.UseAllSchemasKey)
bindFlagToViper(config.UseAllTablesKey)
}

func bindFlagToViper(key string) {
@@ -102,7 +127,6 @@ func bindFlagToViper(key string) {

func initConfig() {
if runConfig != "" {
color.Blue(fmt.Sprintf("Using run configuration (from %s)", runConfig))
viper.SetConfigFile(runConfig)
} else {
home, err := os.UserHomeDir()
50 changes: 28 additions & 22 deletions config/config.go
Original file line number Diff line number Diff line change
@@ -3,45 +3,47 @@ package config
import "github.com/spf13/viper"

const (
ShowAllConstraintsKey = "showAllConstraints"
UseAllTablesKey = "useAllTables"
IgnoreTables = "ignoreTables"
SelectedTablesKey = "selectedTables"
SchemaKey = "schema"
ConnectionStringKey = "connectionString"
ConnectionStringSuggestionsKey = "connectionStringSuggestions"
OutputFileNameKey = "outputFileName"
EncloseWithMermaidBackticksKey = "encloseWithMermaidBackticks"
DebugKey = "debug"
OmitConstraintLabelsKey = "omitConstraintLabels"
EncloseWithMermaidBackticksKey = "encloseWithMermaidBackticks"
IgnoreTables = "ignoreTables"
OmitAttributeKeysKey = "omitAttributeKeys"
OmitConstraintLabelsKey = "omitConstraintLabels"
OutputFileNameKey = "outputFileName"
OutputMode = "outputMode"
RelationshipLabelsKey = "relationshipLabels"
SchemaKey = "schema"
SchemaPrefixSeparator = "schemaPrefixSeparator"
SelectedTablesKey = "selectedTables"
ShowAllConstraintsKey = "showAllConstraints"
ShowDescriptionsKey = "showDescriptions"
UseAllSchemasKey = "useAllSchemas"
ShowSchemaPrefix = "showSchemaPrefix"
SchemaPrefixSeparator = "schemaPrefixSeparator"
RelationshipLabelsKey = "relationshipLabels"
UseAllSchemasKey = "useAllSchemas"
UseAllTablesKey = "useAllTables"
)

type config struct{}

type MermerdConfig interface {
ShowAllConstraints() bool
UseAllTables() bool
IgnoreTables() []string
Schemas() []string
ConnectionString() string
OutputFileName() string
ConnectionStringSuggestions() []string
SelectedTables() []string
EncloseWithMermaidBackticks() bool
Debug() bool
OmitConstraintLabels() bool
EncloseWithMermaidBackticks() bool
IgnoreTables() []string
OmitAttributeKeys() bool
OmitConstraintLabels() bool
OutputFileName() string
OutputMode() OutputModeType
RelationshipLabels() []RelationshipLabel
SchemaPrefixSeparator() string
Schemas() []string
SelectedTables() []string
ShowAllConstraints() bool
ShowDescriptions() []string
UseAllSchemas() bool
ShowSchemaPrefix() bool
SchemaPrefixSeparator() string
RelationshipLabels() []RelationshipLabel
UseAllSchemas() bool
UseAllTables() bool
}

func NewConfig() MermerdConfig {
@@ -116,3 +118,7 @@ func (c config) ShowSchemaPrefix() bool {
func (c config) SchemaPrefixSeparator() string {
return viper.GetString(SchemaPrefixSeparator)
}

func (c config) OutputMode() OutputModeType {
return OutputModeType(viper.GetString(OutputMode))
}
28 changes: 28 additions & 0 deletions config/output_mode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package config

import "errors"

type OutputModeType string

const (
File OutputModeType = "file"
Stdout OutputModeType = "stdout"
)

func (o *OutputModeType) String() string {
return string(*o)
}

func (o *OutputModeType) Set(v string) error {
switch v {
case "file", "stdout":
*o = OutputModeType(v)
return nil
}

return errors.New(`must be one of "file" or "stdout"`)
}

func (o *OutputModeType) Type() string {
return "OutputModeType"
}
16 changes: 4 additions & 12 deletions diagram/diagram.go
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ package diagram

import (
_ "embed"
"os"
"io"
"text/template"

"github.com/sirupsen/logrus"
@@ -19,22 +19,14 @@ type diagram struct {
}

type Diagram interface {
Create(result *database.Result) error
Create(wr io.Writer, result *database.Result) error
}

func NewDiagram(config config.MermerdConfig) Diagram {
return diagram{config}
}

func (d diagram) Create(result *database.Result) error {
f, err := os.Create(d.config.OutputFileName())
if err != nil {
logrus.Error("Could not create output file", " | ", err)
return err
}

defer f.Close()

func (d diagram) Create(wr io.Writer, result *database.Result) error {
tmpl, err := template.New("erd_template").Parse(erdTemplate)
if err != nil {
logrus.Error("Could not load template file", " | ", err)
@@ -74,7 +66,7 @@ func (d diagram) Create(result *database.Result) error {
Constraints: constraints,
}

if err = tmpl.Execute(f, diagramData); err != nil {
if err = tmpl.Execute(wr, diagramData); err != nil {
logrus.Error("Could not create diagram", " | ", err)
return err
}
5 changes: 3 additions & 2 deletions exampleRunConfig.yaml
Original file line number Diff line number Diff line change
@@ -10,8 +10,8 @@ schema:
# Define what tables should be used
#useAllTables: true
selectedTables:
- article
- label
- public.article
- public.label

# Additional flags
showAllConstraints: true
@@ -20,6 +20,7 @@ encloseWithMermaidBackticks: false
debug: false
omitConstraintLabels: false
omitAttributeKeys: false
outputMode: stdout
showDescriptions:
- enumValues
- columnComments
4 changes: 1 addition & 3 deletions go.mod
Original file line number Diff line number Diff line change
@@ -3,9 +3,7 @@ module github.com/KarnerTh/mermerd
go 1.23

// https://github.com/microsoft/mssql-docker/issues/895#issuecomment-2327988940
godebug (
x509negativeserial=1
)
godebug x509negativeserial=1

require (
github.com/AlecAivazis/survey/v2 v2.3.7
63 changes: 8 additions & 55 deletions go.sum

Large diffs are not rendered by default.

12 changes: 7 additions & 5 deletions mocks/Diagram.go
14 changes: 14 additions & 0 deletions mocks/MermerdConfig.go
14 changes: 14 additions & 0 deletions presentation/info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package presentation

import (
"github.com/KarnerTh/mermerd/config"
"github.com/fatih/color"
)

func ShowInfo(c config.MermerdConfig, value string) {
if c.OutputMode() == config.Stdout {
return
}

color.Blue(value)
}
7 changes: 6 additions & 1 deletion presentation/intro.go
Original file line number Diff line number Diff line change
@@ -3,11 +3,16 @@ package presentation
import (
"fmt"

"github.com/KarnerTh/mermerd/config"
"github.com/fatih/color"
"github.com/spf13/viper"
)

func ShowIntro() {
func ShowIntro(c config.MermerdConfig) {
if c.OutputMode() == config.Stdout {
return
}

color.Green(fmt.Sprintf(`
. ..___.__ . ..___.__ .__
|\/|[__ [__)|\/|[__ [__)| \
7 changes: 6 additions & 1 deletion presentation/outro.go
Original file line number Diff line number Diff line change
@@ -3,10 +3,15 @@ package presentation
import (
"fmt"

"github.com/KarnerTh/mermerd/config"
"github.com/fatih/color"
)

func ShowSuccess(fileName string) {
func ShowSuccess(c config.MermerdConfig, fileName string) {
if c.OutputMode() == config.Stdout {
return
}

color.Green(fmt.Sprintf(`
✓ Diagram was created successfully (%s)
5 changes: 5 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
@@ -78,6 +78,7 @@ via `mermerd -h`
--omitAttributeKeys omit the attribute keys (PK, FK, UK)
--omitConstraintLabels omit the constraint labels
-o, --outputFileName string output file name (default "result.mmd")
--outputMode OutputModeType output mode (file, stdout) (default file)
--runConfig string run configuration (replaces global configuration)
-s, --schema string schema that should be used
--schemaPrefixSeparator string the separator that should be used between schema and table name (default ".")
@@ -146,6 +147,7 @@ selectedTables:
showAllConstraints: true
encloseWithMermaidBackticks: true
outputFileName: "my-db.mmd"
outputMode: stdout
debug: true
omitConstraintLabels: true
omitAttributeKeys: true
@@ -181,6 +183,9 @@ mermerd -c "postgresql://user:password@localhost:5432/yourDb" -s public
# same as previous one, but use all available tables without interaction
mermerd -c "postgresql://user:password@localhost:5432/yourDb" -s public --useAllTables
# same as previous one, but get the result in stdout instead of a file
mermerd -c "postgresql://user:password@localhost:5432/yourDb" -s public --useAllTables --outputMode stdout
# same as previous one, but use a list of tables without interaction
mermerd -c "postgresql://user:password@localhost:5432/yourDb" -s public --selectedTables article,article_label