Skip to content

Fix in url parser after go 1.12.8 #2

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

Merged
merged 2 commits into from
Nov 15, 2019
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
53 changes: 41 additions & 12 deletions common.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
package prana

import (
"fmt"
"net/url"
"errors"
"regexp"
"strings"

"github.com/go-sql-driver/mysql"
Expand All @@ -16,33 +16,62 @@ import (
// Logger used to log any output
type Logger = log.Logger

const (
// DriverMySQL represents the database driver name of MySQL
DriverMySQL = "mysql"
// DriverSQLite represents the database driver name of SQLite3
DriverSQLite = "sqlite3"
// DriverPostgres represents the databse driver name of Postgres
DriverPostgres = "postgres"
)

// Error codes returned by failures to parse a dsn.
var (
errNoDriverName = errors.New("no driver name")
errEmptyConnURL = errors.New("url cannot be empty")
errInvalidDSN = errors.New("invalid dsn")
)

// ParseURL parses a URL and returns the database driver and connection string to the database
func ParseURL(conn string) (string, string, error) {
uri, err := url.Parse(conn)
driver, source, err := parseRawURL(conn)
if err != nil {
return "", "", err
}

driver := strings.ToLower(uri.Scheme)

switch driver {
case "mysql":
source, err := parseMySQL(driver, conn)
case DriverMySQL:
mysqlSource, err := parseMySQL(driver, source)
if err != nil {
return "", "", err
}
return driver, mysqlSource, nil
case DriverSQLite:
return driver, source, nil
case "sqlite3":
source := strings.Replace(conn, fmt.Sprintf("%s://", driver), "", -1)
return driver, source, nil
case DriverPostgres:
return driver, conn, nil
default:
return driver, conn, nil
}
}

func parseMySQL(driver, conn string) (string, error) {
source := strings.Replace(conn, fmt.Sprintf("%s://", driver), "", -1)
// parseRawURL returns the db driver name from a URL string
func parseRawURL(url string) (driverName string, path string, err error) {
if url == "" {
return "", "", errEmptyConnURL
}

// scheme must match
prog := regexp.MustCompile(`^([a-zA-Z][a-zA-Z0-9+-.]*)://(.*)$`)
matches := prog.FindStringSubmatch(url)

if len(matches) > 2 {
return strings.ToLower(matches[1]), matches[2], nil
}
return "", "", errInvalidDSN
}

func parseMySQL(driver, source string) (string, error) {
cfg, err := mysql.ParseDSN(source)
if err != nil {
return "", err
Expand Down
18 changes: 17 additions & 1 deletion common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ var _ = Describe("ParseURL", func() {
Expect(source).To(Equal("root@tcp(127.0.0.1:3306)/prana?parseTime=true"))
})

It("parses the MySQL connection string with custom port successfully", func() {
driver, source, err := prana.ParseURL("mysql://root:password@tcp(127.0.0.1:13306)/prana")
Expect(err).NotTo(HaveOccurred())
Expect(driver).To(Equal("mysql"))
Expect(source).To(Equal("root:password@tcp(127.0.0.1:13306)/prana?parseTime=true"))
})

Context("when the DSN is invalid", func() {
It("returns the error", func() {
driver, source, err := prana.ParseURL("mysql://@net(addr/")
Expand All @@ -39,12 +46,21 @@ var _ = Describe("ParseURL", func() {
Expect(source).To(Equal("postgres://localhost/prana?sslmode=disable"))
})

Context("when the URL is empty", func() {
It("returns an error", func() {
driver, source, err := prana.ParseURL("")
Expect(driver).To(BeEmpty())
Expect(source).To(BeEmpty())
Expect(err).To(MatchError("url cannot be empty"))
})
})

Context("when the URL is invalid", func() {
It("returns an error", func() {
driver, source, err := prana.ParseURL("::")
Expect(driver).To(BeEmpty())
Expect(source).To(BeEmpty())
Expect(err).To(MatchError("parse ::: missing protocol scheme"))
Expect(err).To(MatchError("invalid dsn"))
})
})
})