-
Notifications
You must be signed in to change notification settings - Fork 1
/
driver.go
96 lines (81 loc) · 2.5 KB
/
driver.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
/*
Package mylogindriver provides a database/sql driver for MySQL using credentials stored in ~/.mylogin.cnf.
Connection string syntax:
[<filepath>//]<section>/[<database>]
Default filepath is $HOME/.mylogin.cnf or $MYSQL_TEST_LOGIN_FILE. See https://pkg.go.dev/github.com/dolmen-go/mylogin/#DefaultFile.
About mylogin.cnf:
https://dev.mysql.com/doc/refman/8.0/en/mysql-config-editor.html
https://dev.mysql.com/doc/mysql-utilities/1.5/en/mysql-utils-intro-connspec-mylogin.cnf.html
A package that auto-registers the driver is provided in https://pkg.go.dev/github.com/dolmen-go/mylogin-driver/register/.
*/
package mylogindriver
import (
"context"
"database/sql/driver"
"errors"
"path/filepath"
"strings"
"github.com/go-sql-driver/mysql"
"github.com/dolmen-go/mylogin"
)
// Driver is a database/sql driver.
//
// It implements interfaces [database/sql/driver.Driver] and [database/sql/driver.DriverContext].
type Driver struct {
private struct{} // just to make the internal representation secret.
}
var (
errInvalidSyntax = errors.New("invalid connection string")
)
// OpenConnector implements interface [database/sql/driver.DriverContext].
func (drv Driver) OpenConnector(name string) (driver.Connector, error) {
var path string
i := strings.Index(name, "//")
if i >= 0 {
path = filepath.FromSlash(name[:i])
name = name[i+2:]
}
if len(path) == 0 {
path = mylogin.DefaultFile()
}
i = strings.IndexByte(name, '/')
if i < 1 {
return nil, errInvalidSyntax
}
login, err := mylogin.ReadLogin(path, []string{name[:i], mylogin.DefaultSection})
if err != nil {
return nil, err
}
var options string
dbName := name[i+1:]
i = strings.IndexByte(dbName, '?')
if i >= 0 {
options = dbName[i:]
dbName = dbName[:i]
}
c, err := mysql.MySQLDriver{}.OpenConnector(login.DSN() + dbName + options)
if err != nil {
return nil, err
}
return connector{c: c}, nil
}
// Open implements interface [database/sql/driver.Driver].
func (drv Driver) Open(name string) (driver.Conn, error) {
cnt, err := drv.OpenConnector(name)
if err != nil {
return nil, err
}
return cnt.Connect(context.TODO())
}
// connector implements interface [database/sql/driver.Connector].
type connector struct {
c driver.Connector
}
// Driver implements interface [database/sql/driver.Connector].
func (cnt connector) Driver() driver.Driver {
return Driver{}
}
// Connect implements interface [database/sql/driver.Connector].
func (cnt connector) Connect(ctx context.Context) (driver.Conn, error) {
return cnt.c.Connect(ctx)
}