Skip to content

Commit

Permalink
Merge pull request #3 from kos-v/new-feats
Browse files Browse the repository at this point in the history
  • Loading branch information
kos-v authored Feb 19, 2022
2 parents 159dcb0 + b6161b7 commit fc3c02f
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 28 deletions.
23 changes: 12 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,18 @@ go get github.com/kos-v/dsnparser
```go
import "github.com/kos-v/dsnparser"

dsn := dsnparser.Parse("mysql://user:[email protected]:3306/dbname?transport=tcp");
dsn.GetScheme() // string "mysql"
dsn.GetUser() // string "user"
dsn.GetPassword() // string "password"
dsn.GetHost() // string "example.local"
dsn.GetPort() // string "3306"
dsn.GetPath() // string "dbname"
dsn.GetParam("transport") // string "tcp"
dsn.GetParams() // map[string]string [transport: tcp]
dsn.HasParam("transport") // bool true
dsn.GetRaw() // string "mysql://user:[email protected]:3306/dbname?transport=tcp"
dsn := dsnparser.Parse("mysql://user:password@tcp(example.local:3306)/dbname?encoding=utf8mb4");
dsn.GetScheme() // string "mysql"
dsn.GetUser() // string "user"
dsn.GetPassword() // string "password"
dsn.GetHost() // string "example.local"
dsn.GetPort() // string "3306"
dsn.GetPath() // string "dbname"
dsn.GetParam("encoding") // string "utf8mb4"
dsn.GetParams() // map[string]string [encoding: "utf8mb4"]
dsn.GetTransport() // string "tcp"
dsn.HasParam("encoding") // bool true
dsn.GetRaw() // string "mysql://user:[email protected]:3306/dbname?encoding=utf8mb4"
```

##### Examples:
Expand Down
Binary file modified doc/structure.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
59 changes: 51 additions & 8 deletions parser.go
Original file line number Diff line number Diff line change
@@ -1,59 +1,80 @@
package dsnparser

// DSN container for data after dsn parsing.
type DSN struct {
raw string
scheme string
user string
password string
host string
port string
path string
params map[string]string
raw string
scheme string
user string
password string
host string
port string
path string
params map[string]string
transport string
}

// GetHost returns a host as the string.
func (d *DSN) GetHost() string {
return d.host
}

// GetPassword returns a credential password as the string.
func (d *DSN) GetPassword() string {
return d.password
}

// GetParam returns an additional parameter by key as the string.
func (d *DSN) GetParam(key string) string {
if !d.HasParam(key) {
return ""
}
return d.params[key]
}

// GetParams returns additional parameters as key-value map.
func (d *DSN) GetParams() map[string]string {
return d.params
}

// GetPath returns a path as the string.
func (d *DSN) GetPath() string {
return d.path
}

// GetPort returns a port as the string.
func (d *DSN) GetPort() string {
return d.port
}

// GetRaw returns the dsn in its raw form, as it was passed to the Parse function.
func (d *DSN) GetRaw() string {
return d.raw
}

// GetScheme returns a scheme as the string.
func (d *DSN) GetScheme() string {
return d.scheme
}

// GetTransport returns a transport as the string.
func (d *DSN) GetTransport() string {
return d.transport
}

// GetUser returns a credential user as the string.
func (d *DSN) GetUser() string {
return d.user
}

// HasParam checks for the existence of an additional parameter.
func (d *DSN) HasParam(key string) bool {
if _, ok := d.params[key]; ok {
return true
}
return false
}

// Parse receives a raw dsn as argument, parses it and returns it in the DSN structure.
func Parse(raw string) *DSN {
d := DSN{
raw: raw,
Expand Down Expand Up @@ -96,6 +117,28 @@ func Parse(raw string) *DSN {
}
}

// Transport parsing
for dsnPos, dsnSymbol := range dsn {
if dsnSymbol != '(' {
continue
}

hpExtractBeginPos := dsnPos + 1
hpExtractEndPos := -1
for hpPos, hpSymbol := range dsn[hpExtractBeginPos:] {
if hpSymbol == ')' {
hpExtractEndPos = dsnPos + hpPos
}
}
if hpExtractEndPos == -1 {
continue
}

d.transport = string(dsn[:hpExtractBeginPos-1])
dsn = append(dsn[hpExtractBeginPos:hpExtractEndPos+1], dsn[hpExtractEndPos+2:]...)
break
}

// Host and port parsing
for dsnPos, dsnSymbol := range dsn {
endPos := -1
Expand Down
56 changes: 47 additions & 9 deletions parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@ package dsnparser

import "testing"

func TestDSN_HasParam(t *testing.T) {
result := Parse("mysql://user:[email protected]:3306/dbname?foo=foo val")
if !result.HasParam("foo") {
t.Errorf("Unexpected value. Must be true")
}
if result.HasParam("bar") {
t.Errorf("Unexpected value. Must be false")
}
}

func TestParse_Scheme(t *testing.T) {
tests := []struct {
dsn string
Expand All @@ -11,7 +21,7 @@ func TestParse_Scheme(t *testing.T) {
{"mysql", ""},
{"://", ""},
{"mysql://", "mysql"},
{"mysql://user:[email protected]:3306/dbname?tblsprefix=fs_", "mysql"},
{"mysql://user:password@tcp(example.com:3306)/dbname?tblsprefix=fs_", "mysql"},
}

for i, test := range tests {
Expand Down Expand Up @@ -43,7 +53,7 @@ func TestParse_User(t *testing.T) {
{":password@", ""},
{"u@", "u"},
{":@", ""},
{"mysql://user:[email protected]:3306/dbname?tblsprefix=fs_", "user"},
{"mysql://user:password@tcp(example.com:3306)/dbname?tblsprefix=fs_", "user"},
{"mysql://[email protected]:3306/dbname?tblsprefix=fs_", "user"},
{"mysql://example.com:3306/dbname?tblsprefix=fs_", ""},
{"\\@@", "@"},
Expand Down Expand Up @@ -89,7 +99,7 @@ func TestParse_Password(t *testing.T) {
{":password@", "password"},
{":p@", "p"},
{":@", ""},
{"mysql://user:[email protected]:3306/dbname?tblsprefix=fs_", "password"},
{"mysql://user:password@tcp(example.com:3306)/dbname?tblsprefix=fs_", "password"},
{"mysql://[email protected]:3306/dbname?tblsprefix=fs_", ""},
{"mysql://example.com:3306/dbname?tblsprefix=fs_", ""},
{"\\@@", ""},
Expand Down Expand Up @@ -121,7 +131,9 @@ func TestParse_Host(t *testing.T) {
expected string
}{
{"mysql://user:[email protected]:3306/dbname?tblsprefix=fs_", "example.com"},
{"mysql://user:password@tcp(example.com:3306)/dbname?tblsprefix=fs_", "example.com"},
{"mysql://user:[email protected]/dbname?tblsprefix=fs_", "example.com"},
{"mysql://user:password@tcp(example.com)/dbname?tblsprefix=fs_", "example.com"},
{"mysql://user:password@localhost/dbname?tblsprefix=fs_", "localhost"},
{"mysql://user:[email protected]/dbname?tblsprefix=fs_", "127.0.0.1"},
{"mysql://user:[email protected]", "example.com"},
Expand Down Expand Up @@ -163,11 +175,14 @@ func TestParse_Port(t *testing.T) {
expected string
}{
{"mysql://user:[email protected]:3306/dbname?tblsprefix=fs_", "3306"},
{"mysql://user:password@tcp(example.com:3306)/dbname?tblsprefix=fs_", "3306"},
{"mysql://user:[email protected]:3306", "3306"},
{"mysql://user:password@tcp(example.com:3306)", "3306"},
{"mysql://user:[email protected]/dbname?tblsprefix=fs_", ""},
{"mysql://user:[email protected]:/dbname?tblsprefix=fs_", ""},
{"mysql://user:[email protected]:bad, but working/dbname?tblsprefix=fs_", "bad, but working"},
{"example.com:3306", "3306"},
{"tcp(example.com:3306)", "3306"},
{"example.com:", ""},
{"example.com", ""},
{"хост.лок:3306", "3306"},
Expand All @@ -187,6 +202,7 @@ func TestParse_Path(t *testing.T) {
expected string
}{
{"mysql://user:[email protected]:3306/foo?tblsprefix=fs_", "foo"},
{"mysql://user:password@tcp(example.com:3306)/foo?tblsprefix=fs_", "foo"},
{"mysql://user:[email protected]:3306/foo/bar/baz?tblsprefix=fs_", "foo/bar/baz"},
{"mysql://user:[email protected]:3306//?tblsprefix=fs_", "/"},
{"mysql://user:[email protected]:3306/?tblsprefix=fs_", ""},
Expand Down Expand Up @@ -258,13 +274,35 @@ func TestParse_Params(t *testing.T) {
}

for _, expected := range test.expected {
if dsn.HasParam(expected.key) {
if dsn.GetParam(expected.key) != expected.value {
t.Errorf("Unexpected value in test \"%v\". Expected: \"%s\". Result: \"%s\"", testId+1, expected.value, dsn.GetParam(expected.key))
}
} else {
t.Errorf("Expected key not found in returned result. Test: %v. Expected key: \"%s\".", testId+1, expected.key)
if dsn.GetParam(expected.key) != expected.value {
t.Errorf("Unexpected value in test \"%v\". Expected: \"%s\". Result: \"%s\"", testId+1, expected.value, dsn.GetParam(expected.key))
}
}
}
}

func TestParse_Transport(t *testing.T) {
tests := []struct {
dsn string
expected string
}{
{"example.com", ""},
{"example.com:3306", ""},
{"(example.com)", ""},
{"tcp()", "tcp"},
{"x(example.com)", "x"},
{"tcp(example.com)", "tcp"},
{"tcp(example.com:3306)", "tcp"},
{"mysql://user:password@tcp(example.com)", "tcp"},
{"mysql://user:password@tcp(example.com:3306)", "tcp"},
{"mysql://user:password@tcp(example.com)/dbname?tblsprefix=fs_", "tcp"},
{"mysql://user:password@tcp(example.com:3306)/dbname?tblsprefix=fs_", "tcp"},
}

for i, test := range tests {
dsn := Parse(test.dsn)
if dsn.GetTransport() != test.expected {
t.Errorf("Unexpected value in test \"%v\". Expected: \"%s\". Result: \"%s\"", i+1, test.expected, dsn.GetTransport())
}
}
}

0 comments on commit fc3c02f

Please sign in to comment.