169 lines
3.4 KiB
Go
169 lines
3.4 KiB
Go
// Package mysql wraps the github.com/go-sql-driver/mysql MySQL driver. See
|
|
// https://github.com/upper/db/adapter/mysql for documentation, particularities and usage
|
|
// examples.
|
|
package mysql
|
|
|
|
import (
|
|
"reflect"
|
|
"strings"
|
|
|
|
"database/sql"
|
|
|
|
"git.hexq.cn/tiglog/mydb"
|
|
"git.hexq.cn/tiglog/mydb/internal/sqladapter"
|
|
"git.hexq.cn/tiglog/mydb/internal/sqladapter/exql"
|
|
_ "github.com/go-sql-driver/mysql" // MySQL driver.
|
|
)
|
|
|
|
// database is the actual implementation of Database
|
|
type database struct {
|
|
}
|
|
|
|
func (*database) Template() *exql.Template {
|
|
return template
|
|
}
|
|
|
|
func (*database) OpenDSN(sess sqladapter.Session, dsn string) (*sql.DB, error) {
|
|
return sql.Open("mysql", dsn)
|
|
}
|
|
|
|
func (*database) Collections(sess sqladapter.Session) (collections []string, err error) {
|
|
q := sess.SQL().
|
|
Select("table_name").
|
|
From("information_schema.tables").
|
|
Where("table_schema = ?", sess.Name())
|
|
|
|
iter := q.Iterator()
|
|
defer iter.Close()
|
|
|
|
for iter.Next() {
|
|
var tableName string
|
|
if err := iter.Scan(&tableName); err != nil {
|
|
return nil, err
|
|
}
|
|
collections = append(collections, tableName)
|
|
}
|
|
if err := iter.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return collections, nil
|
|
}
|
|
|
|
func (d *database) ConvertValue(in interface{}) interface{} {
|
|
switch v := in.(type) {
|
|
case *map[string]interface{}:
|
|
return (*JSONMap)(v)
|
|
|
|
case map[string]interface{}:
|
|
return (*JSONMap)(&v)
|
|
}
|
|
|
|
dv := reflect.ValueOf(in)
|
|
if dv.IsValid() {
|
|
if dv.Type().Kind() == reflect.Ptr {
|
|
dv = dv.Elem()
|
|
}
|
|
|
|
switch dv.Kind() {
|
|
case reflect.Map:
|
|
if reflect.TypeOf(in).Kind() == reflect.Ptr {
|
|
w := reflect.ValueOf(in)
|
|
z := reflect.New(w.Elem().Type())
|
|
w.Elem().Set(z.Elem())
|
|
}
|
|
return &JSON{in}
|
|
case reflect.Slice:
|
|
return &JSON{in}
|
|
}
|
|
}
|
|
|
|
return in
|
|
}
|
|
|
|
func (*database) Err(err error) error {
|
|
if err != nil {
|
|
// This error is not exported so we have to check it by its string value.
|
|
s := err.Error()
|
|
if strings.Contains(s, `many connections`) {
|
|
return mydb.ErrTooManyClients
|
|
}
|
|
}
|
|
return err
|
|
}
|
|
|
|
func (*database) NewCollection() sqladapter.CollectionAdapter {
|
|
return &collectionAdapter{}
|
|
}
|
|
|
|
func (*database) LookupName(sess sqladapter.Session) (string, error) {
|
|
q := sess.SQL().
|
|
Select(mydb.Raw("DATABASE() AS name"))
|
|
|
|
iter := q.Iterator()
|
|
defer iter.Close()
|
|
|
|
if iter.Next() {
|
|
var name string
|
|
if err := iter.Scan(&name); err != nil {
|
|
return "", err
|
|
}
|
|
return name, nil
|
|
}
|
|
|
|
return "", iter.Err()
|
|
}
|
|
|
|
func (*database) TableExists(sess sqladapter.Session, name string) error {
|
|
q := sess.SQL().
|
|
Select("table_name").
|
|
From("information_schema.tables").
|
|
Where("table_schema = ? AND table_name = ?", sess.Name(), name)
|
|
|
|
iter := q.Iterator()
|
|
defer iter.Close()
|
|
|
|
if iter.Next() {
|
|
var name string
|
|
if err := iter.Scan(&name); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
if err := iter.Err(); err != nil {
|
|
return err
|
|
}
|
|
|
|
return mydb.ErrCollectionDoesNotExist
|
|
}
|
|
|
|
func (*database) PrimaryKeys(sess sqladapter.Session, tableName string) ([]string, error) {
|
|
q := sess.SQL().
|
|
Select("k.column_name").
|
|
From("information_schema.key_column_usage AS k").
|
|
Where(`
|
|
k.constraint_name = 'PRIMARY'
|
|
AND k.table_schema = ?
|
|
AND k.table_name = ?
|
|
`, sess.Name(), tableName).
|
|
OrderBy("k.ordinal_position")
|
|
|
|
iter := q.Iterator()
|
|
defer iter.Close()
|
|
|
|
pk := []string{}
|
|
|
|
for iter.Next() {
|
|
var k string
|
|
if err := iter.Scan(&k); err != nil {
|
|
return nil, err
|
|
}
|
|
pk = append(pk, k)
|
|
}
|
|
if err := iter.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return pk, nil
|
|
}
|