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

Multi config support #138

Merged
merged 5 commits into from
Dec 1, 2022
Merged
Show file tree
Hide file tree
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
24 changes: 17 additions & 7 deletions .dblab.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
database:
host: "localhost"
port: 5432
db: "users"
password: "password"
user: "postgres"
schema: "public"
driver: "postgres"
- name: "test"
host: "localhost"
port: 5432
db: "users"
password: "password"
user: "postgres"
schema: "public"
driver: "postgres"
- name: "prod"
# example endpoint
host: "mydb.123456789012.us-east-1.rds.amazonaws.com"
port: 5432
db: "users"
password: "password"
user: "postgres"
schema: "public"
driver: "postgres"
limit: 50
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ run-url: build
run-mysql-url: build
./dblab --url "mysql://myuser:5@klkbN#ABC@tcp(localhost:3306)/mydb"

.PHONY: run-config
## run-config: Runs the client using the config file.
run-config: build
./dblab --config --cfg-name "test"

.PHONY: up
## up: Runs all the containers listed in the docker-compose.yml file
up:
Expand Down
50 changes: 35 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ Available Commands:
version The version of the project

Flags:
--cfg-name string Database config name section
--config get the connection data from a config file (default is $HOME/.dblab.yaml or the current directory)
--db string Database name
--driver string Database driver
Expand Down Expand Up @@ -116,41 +117,60 @@ $ dblab --host localhost --user myuser --db users --pass password --schema mysch
$ dblab --url postgres://user:password@host:port/database?sslmode=[mode] --schema myschema
```

Now, you can use a configuration file to make a connection to the database.
### Config

Enter previous flags every time is tedious, so `dblab` provides a couple of flags to help with it: `--config` and `--cfg-name`.

`dblab` is going to look for a file called `.dblab.yaml`. For now, the only two places where you can drop a config file are $HOME ($HOME/.dblab.yaml) and the current directory where you run the command line tool.
If you want to use this feature, `--config` is mandatory and `--cfg-name` may be omitted. The config file can store one or multiple database connection sections under the `database` field. `database` is an array, previously was an object only able to store a single connection section at a time. We strongly encourgae you to adopt the new format as of `v0.18.0`. `--cfg-name` takes the name of the desired database section to connect with. It can be omitted and its default values will be the first item on the array.

```sh
# default: test
$ dbladb --config
```

`dblab` is going to look for a file called `.dblab.yaml`. For now, the only two places where you can drop a config file are $HOME ($HOME/.dblab.yaml) and the current directory where you run the command line tool.
$ dblab --config --cfg-name "prod"
```

`.dblab.yaml` example:

```yaml
database:
host: "localhost"
port: 5432
db: "users"
password: "password"
user: "postgres"
driver: "postgres"
# optional
# postgres only
# default value: public
schema: "myschema"
- name: "test"
host: "localhost"
port: 5432
db: "users"
password: "password"
user: "postgres"
driver: "postgres"
# optional
# postgres only
# default value: public
schema: "myschema"
- name: "prod"
# example endpoint
host: "mydb.123456789012.us-east-1.rds.amazonaws.com"
port: 5432
db: "users"
password: "password"
user: "postgres"
schema: "public"
driver: "postgres"
limit: 50
```

Or for sqlite3:

```yaml
database:
db: "path/to/file.sqlite3"
driver: "sqlite3"
- name: "prod"
db: "path/to/file.sqlite3"
driver: "sqlite3"
```

Only the `host` and `ssl` fields are optionals. `127.0.0.1` and `disable`, respectively.

## Navigation

If the query panel is active, type the desired query and press <kbd>Ctrl+Space</kbd> to see the results on the rows panel below.
Otherwise, you might me located at the tables panel, then you can navigate by using the arrows <kbd>Up</kbd> and <kbd>Down</kbd> (or the keys <kbd>k</kbd> and <kbd>j</kbd> respectively). If you want to see the rows of a table, press <kbd>Enter</kbd>. To see the the schema of a table, locate yourself on the `rows` panel and press <kbd>Ctrl+S</kbd> to switch to the `structure` panel, then switch <kbd>Ctrl+S</kbd> to switch back.
The same can be achieved for the `constraints` view by pressing <kbd>Ctrl+F</kbd> to go back and forth between the `rows` and the `constraints` panels.
Expand Down
30 changes: 18 additions & 12 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,18 @@ import (

// Define all the global flags.
var (
cfg bool
driver string
url string
host string
port string
user string
pass string
schema string
db string
ssl string
limit int
cfg bool
cfgName string
driver string
url string
host string
port string
user string
pass string
schema string
db string
ssl string
limit int
)

// NewRootCmd returns the root command.
Expand All @@ -36,7 +37,7 @@ func NewRootCmd() *cobra.Command {
var err error

if cfg {
opts, err = config.Init()
opts, err = config.Init(cfgName)
if err != nil {
return err
}
Expand Down Expand Up @@ -99,7 +100,12 @@ func init() {
// Cobra supports persistent flags, which, if defined here,
// will be global for your application.

// config file flag.
rootCmd.PersistentFlags().BoolVarP(&cfg, "config", "", false, "get the connection data from a config file (default is $HOME/.dblab.yaml or the current directory)")
// cfg-name is used to indicate the name of the config section to be used to establish a
// connection with desired database.
// default: if empty, the first item of the databases options is gonna be selected.
rootCmd.Flags().StringVarP(&cfgName, "cfg-name", "", "", "Database config name section")

// global flags used to open a database connection.
rootCmd.Flags().StringVarP(&driver, "driver", "", "", "Database driver")
Expand Down
24 changes: 17 additions & 7 deletions pkg/config/.dblab.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
database:
host: "localhost"
port: 5432
db: "users"
password: "password"
user: "postgres"
schema: "public"
driver: "postgres"
- name: "test"
host: "localhost"
port: 5432
db: "users"
password: "password"
user: "postgres"
schema: "public"
driver: "postgres"
- name: "prod"
# example endpoint
host: "mydb.123456789012.us-east-1.rds.amazonaws.com"
port: 5432
db: "users"
password: "password"
user: "postgres"
schema: "public"
driver: "postgres"
limit: 50
71 changes: 45 additions & 26 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package config

import (
"database/sql"
"errors"
"flag"
"fmt"
"os"
Expand All @@ -22,23 +23,26 @@ import (

// Config struct is used to store the db connection data.
type Config struct {
Database struct {
Host string
Port string
DB string `validate:"required"`
User string
Password string
Driver string `validate:"required"`
Schema string
SSL string `default:"disable"`
}
User string
Pswd string
Host string
Port string
DBName string
Driver string
Limit int `fig:"limit" default:"100"`
Database []Database
User string
Pswd string
Host string
Port string
DBName string
Driver string
Limit int `fig:"limit" default:"100"`
}

type Database struct {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💯

Name string
Host string
Port string
DB string `validate:"required"`
User string
Password string
Driver string `validate:"required"`
Schema string
SSL string `default:"disable"`
}

// New returns a config instance the with db connection data inplace based on the flags of a cobra command.
Expand All @@ -56,9 +60,10 @@ func New(cmd *cobra.Command) *Config {
}

// Init reads in config file and returns a commands/Options instance.
func Init() (command.Options, error) {
func Init(configName string) (command.Options, error) {
var opts command.Options
var cfg Config
var db Database

home, err := os.UserHomeDir()
if err != nil {
Expand All @@ -69,15 +74,29 @@ func Init() (command.Options, error) {
return opts, err
}

if len(cfg.Database) == 0 {
return opts, errors.New("empty database connection section on config file")
}

if configName != "" {
for _, d := range cfg.Database {
if configName == d.Name {
db = d
}
}
} else {
db = cfg.Database[0]
}

opts = command.Options{
Driver: cfg.Database.Driver,
Host: cfg.Database.Host,
Port: cfg.Database.Port,
User: cfg.Database.User,
Pass: cfg.Database.Password,
DBName: cfg.Database.DB,
SSL: cfg.Database.SSL,
Schema: cfg.Database.Schema,
Driver: db.Driver,
Host: db.Host,
Port: db.Port,
User: db.User,
Pass: db.Password,
DBName: db.DB,
SSL: db.SSL,
Schema: db.Schema,
Limit: cfg.Limit,
}

Expand Down
83 changes: 73 additions & 10 deletions pkg/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,78 @@ import (
)

func TestInit(t *testing.T) {
opts, err := config.Init()
type want struct {
host string
port string
dbname string
user string
pass string
driver string
schema string
limit int
}
var tests = []struct {
name string
input string
want want
}{
{
name: "empty config name",
input: "",
want: want{
host: "localhost",
port: "5432",
dbname: "users",
user: "postgres",
pass: "password",
driver: "postgres",
schema: "public",
limit: 50,
},
},
{
name: "test config",
input: "test",
want: want{
host: "localhost",
port: "5432",
dbname: "users",
user: "postgres",
pass: "password",
driver: "postgres",
schema: "public",
limit: 50,
},
},
{
name: "production config",
input: "prod",
want: want{
host: "mydb.123456789012.us-east-1.rds.amazonaws.com",
port: "5432",
dbname: "users",
user: "postgres",
pass: "password",
driver: "postgres",
schema: "public",
limit: 50,
},
},
}

assert.NoError(t, err)
assert.Equal(t, "localhost", opts.Host)
assert.Equal(t, "5432", opts.Port)
assert.Equal(t, "users", opts.DBName)
assert.Equal(t, "postgres", opts.User)
assert.Equal(t, "password", opts.Pass)
assert.Equal(t, "postgres", opts.Driver)
assert.Equal(t, "public", opts.Schema)
assert.Equal(t, 50, opts.Limit)
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
opts, err := config.Init(tt.input)

assert.NoError(t, err)
assert.Equal(t, tt.want.host, opts.Host)
assert.Equal(t, tt.want.port, opts.Port)
assert.Equal(t, tt.want.dbname, opts.DBName)
assert.Equal(t, tt.want.user, opts.User)
assert.Equal(t, tt.want.pass, opts.Pass)
assert.Equal(t, tt.want.driver, opts.Driver)
assert.Equal(t, tt.want.schema, opts.Schema)
assert.Equal(t, tt.want.limit, opts.Limit)
})
}
}