// Copyright (c) Mainflux // SPDX-License-Identifier: Apache-2.0 package postgres import ( "fmt" "github.com/jmoiron/sqlx" _ "github.com/lib/pq" // required for SQL access migrate "github.com/rubenv/sql-migrate" ) // Config defines the options that are used when connecting to a PostgreSQL instance type Config struct { Host string Port string User string Pass string Name string SSLMode string SSLCert string SSLKey string SSLRootCert string } // Connect creates a connection to the PostgreSQL instance and applies any // unapplied database migrations. A non-nil error is returned to indicate // failure. func Connect(cfg Config) (*sqlx.DB, error) { url := fmt.Sprintf("host=%s port=%s user=%s dbname=%s password=%s sslmode=%s sslcert=%s sslkey=%s sslrootcert=%s", cfg.Host, cfg.Port, cfg.User, cfg.Name, cfg.Pass, cfg.SSLMode, cfg.SSLCert, cfg.SSLKey, cfg.SSLRootCert) db, err := sqlx.Open("postgres", url) if err != nil { return nil, err } if err := migrateDB(db); err != nil { return nil, err } return db, nil } func migrateDB(db *sqlx.DB) error { migrations := &migrate.MemoryMigrationSource{ Migrations: []*migrate.Migration{ { Id: "configs_1", Up: []string{ `CREATE TABLE IF NOT EXISTS configs ( mainflux_thing TEXT UNIQUE NOT NULL, owner VARCHAR(254), name TEXT, mainflux_key CHAR(36) UNIQUE NOT NULL, external_id TEXT UNIQUE NOT NULL, external_key TEXT NOT NULL, content TEXT, client_cert TEXT, client_key TEXT, ca_cert TEXT, state BIGINT NOT NULL, PRIMARY KEY (mainflux_thing, owner) )`, `CREATE TABLE IF NOT EXISTS unknown_configs ( external_id TEXT UNIQUE NOT NULL, external_key TEXT NOT NULL, PRIMARY KEY (external_id, external_key) )`, `CREATE TABLE IF NOT EXISTS channels ( mainflux_channel TEXT UNIQUE NOT NULL, owner VARCHAR(254), name TEXT, metadata JSON, PRIMARY KEY (mainflux_channel, owner) )`, `CREATE TABLE IF NOT EXISTS connections ( channel_id TEXT, channel_owner VARCHAR(256), config_id TEXT, config_owner VARCHAR(256), FOREIGN KEY (channel_id, channel_owner) REFERENCES channels (mainflux_channel, owner) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY (config_id, config_owner) REFERENCES configs (mainflux_thing, owner) ON DELETE CASCADE ON UPDATE CASCADE, PRIMARY KEY (channel_id, channel_owner, config_id, config_owner) )`, }, Down: []string{ "DROP TABLE connections", "DROP TABLE configs", "DROP TABLE channels", "DROP TABLE unknown_configs", }, }, { Id: "configs_2", Up: []string{ "DROP TABLE IF EXISTS unknown_configs", }, Down: []string{ "CREATE TABLE IF NOT EXISTS unknown_configs", }, }, }, } _, err := migrate.Exec(db.DB, "postgres", migrations, migrate.Up) return err }