github.com/fragmenta/query@v1.5.3/adapters/database_mysql.go (about)

     1  package adapters
     2  
     3  import (
     4  	"database/sql"
     5  	"fmt"
     6  
     7  	// Mysql driver
     8  	_ "github.com/go-sql-driver/mysql"
     9  )
    10  
    11  // MysqlAdapter conforms to the query.Database interface
    12  type MysqlAdapter struct {
    13  	*Adapter
    14  	options map[string]string
    15  	sqlDB   *sql.DB
    16  	debug   bool
    17  }
    18  
    19  // Open this database
    20  func (db *MysqlAdapter) Open(opts map[string]string) error {
    21  
    22  	db.debug = false
    23  	db.options = map[string]string{
    24  		"adapter":  "mysql",
    25  		"user":     "root", // sub your user
    26  		"password": "",
    27  		"db":       "query_test",
    28  		"protocol": "tcp",
    29  		"host":     "localhost",
    30  		"port":     "3306",
    31  		"params":   "charset=utf8&parseTime=true",
    32  	}
    33  
    34  	if opts["debug"] == "true" {
    35  		db.debug = true
    36  	}
    37  
    38  	// Merge options
    39  	for k, v := range opts {
    40  		db.options[k] = v
    41  	}
    42  
    43  	// A typical connection string is of the form:
    44  	//"user:password@tcp(localhost:3306)/dbname?charset=utf8&parseTime=true")
    45  	options := fmt.Sprintf("%s:%s@%s(%s:%s)/%s?%s",
    46  		db.options["user"],
    47  		db.options["password"],
    48  		db.options["protocol"],
    49  		db.options["host"],
    50  		db.options["port"],
    51  		db.options["db"],
    52  		db.options["params"])
    53  
    54  	var err error
    55  	db.sqlDB, err = sql.Open(db.options["adapter"], options)
    56  	if err != nil {
    57  		return err
    58  	}
    59  
    60  	if db.sqlDB == nil {
    61  		fmt.Printf("Mysql options:%s", options)
    62  		return fmt.Errorf("\nError creating database with options: %v", db.options)
    63  	}
    64  
    65  	// Call ping on the db to check it does actually exist!
    66  	err = db.sqlDB.Ping()
    67  	if err != nil {
    68  		return err
    69  	}
    70  
    71  	return err
    72  
    73  }
    74  
    75  // Close the database
    76  func (db *MysqlAdapter) Close() error {
    77  	if db.sqlDB != nil {
    78  		return db.sqlDB.Close()
    79  	}
    80  	return nil
    81  }
    82  
    83  // SQLDB returns the internal db.sqlDB pointer
    84  func (db *MysqlAdapter) SQLDB() *sql.DB {
    85  	return db.sqlDB
    86  }
    87  
    88  // Query SQL execute - NB caller must call use defer rows.Close() with rows returned
    89  func (db *MysqlAdapter) Query(query string, args ...interface{}) (*sql.Rows, error) {
    90  	return db.performQuery(db.sqlDB, db.debug, query, args...)
    91  }
    92  
    93  // Exec - use this for non-select statements
    94  func (db *MysqlAdapter) Exec(query string, args ...interface{}) (sql.Result, error) {
    95  	return db.performExec(db.sqlDB, db.debug, query, args...)
    96  }
    97  
    98  // QuoteField quotes a table name or column name
    99  func (db *MysqlAdapter) QuoteField(name string) string {
   100  	return fmt.Sprintf("`%s`", name)
   101  }
   102  
   103  // Insert a record with params and return the id - psql behaves differently
   104  func (db *MysqlAdapter) Insert(query string, args ...interface{}) (id int64, err error) {
   105  
   106  	tx, err := db.sqlDB.Begin()
   107  	if err != nil {
   108  		return 0, err
   109  	}
   110  
   111  	// Execute the sql using db
   112  	result, err := db.Exec(query, args...)
   113  	if err != nil {
   114  		return 0, err
   115  	}
   116  
   117  	// TODO - check this works on mysql under load with concurrent connections
   118  	// fine if connection not shared
   119  	id, err = result.LastInsertId()
   120  	if err != nil {
   121  		return 0, err
   122  	}
   123  
   124  	err = tx.Commit()
   125  	if err != nil {
   126  		return 0, err
   127  	}
   128  
   129  	return id, nil
   130  
   131  }