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

     1  // Package adapters offers adapters for pouplar databases
     2  package adapters
     3  
     4  import (
     5  	"database/sql"
     6  	"fmt"
     7  	"time"
     8  )
     9  
    10  // Database provides an interface for database adapters to conform to
    11  type Database interface {
    12  
    13  	// Open and close
    14  	Open(opts map[string]string) error
    15  	Close() error
    16  	SQLDB() *sql.DB
    17  
    18  	// Execute queries with or without returned rows
    19  	Exec(query string, args ...interface{}) (sql.Result, error)
    20  	Query(query string, args ...interface{}) (*sql.Rows, error)
    21  
    22  	// Insert a record, returning id
    23  	Insert(sql string, args ...interface{}) (id int64, err error)
    24  
    25  	// Return extra SQL for insert statement (see psql)
    26  	InsertSQL(pk string) string
    27  
    28  	// A format string for the arg placeholder
    29  	Placeholder(i int) string
    30  
    31  	// Quote Table and Column names
    32  	QuoteField(name string) string
    33  
    34  	// Convert a time to a string
    35  	TimeString(t time.Time) string
    36  
    37  	// Convert a string to a time
    38  	ParseTime(s string) (time.Time, error)
    39  }
    40  
    41  // Adapter is a struct defining a few functions used by all adapters
    42  type Adapter struct {
    43  	queries map[string]interface{}
    44  }
    45  
    46  // ReplaceArgPlaceholder does no replacements by default, and use default ? placeholder for args
    47  // psql requires a different placeholder numericall labelled
    48  func (db *Adapter) ReplaceArgPlaceholder(sql string, args []interface{}) string {
    49  	return sql
    50  }
    51  
    52  // Placeholder is the argument placeholder for this adapter
    53  func (db *Adapter) Placeholder(i int) string {
    54  	return "?"
    55  }
    56  
    57  // TimeString - given a time, return the standard string representation
    58  func (db *Adapter) TimeString(t time.Time) string {
    59  	return t.Format("2006-01-02 15:04:05.000 -0700")
    60  }
    61  
    62  // ParseTime - given a string, return a time object built from it
    63  func (db *Adapter) ParseTime(s string) (time.Time, error) {
    64  
    65  	// Deal with broken mysql dates - deal better with this?
    66  	if s == "0000-00-00 00:00:00" {
    67  		return time.Now(), nil
    68  	}
    69  
    70  	// Try to choose the right format for date string
    71  	format := "2006-01-02 15:04:05"
    72  	if len(s) > len(format) {
    73  		format = "2006-01-02 15:04:05.000"
    74  	}
    75  	if len(s) > len(format) {
    76  		format = "2006-01-02 15:04:05.000 -0700"
    77  	}
    78  
    79  	t, err := time.Parse(format, s)
    80  	if err != nil {
    81  		fmt.Println("Unhandled field type:", s, "\n", err)
    82  	}
    83  
    84  	return t, err
    85  }
    86  
    87  // QuoteField quotes a table name or column name
    88  func (db *Adapter) QuoteField(name string) string {
    89  	return fmt.Sprintf(`"%s"`, name)
    90  }
    91  
    92  // InsertSQL provides extra SQL for end of insert statement (RETURNING for psql)
    93  func (db *Adapter) InsertSQL(pk string) string {
    94  	return ""
    95  }
    96  
    97  // performQuery executes Query SQL on the given sqlDB and return the rows.
    98  // NB caller must call use defer rows.Close() with rows returned
    99  func (db *Adapter) performQuery(sqlDB *sql.DB, debug bool, query string, args ...interface{}) (*sql.Rows, error) {
   100  
   101  	if sqlDB == nil {
   102  		return nil, fmt.Errorf("No database available.")
   103  	}
   104  
   105  	if debug {
   106  		fmt.Println("QUERY:", query, "ARGS", args)
   107  	}
   108  
   109  	// This should be cached, perhaps hold a map in memory of queries strings and compiled queries?
   110  	// use queries map to store this
   111  	stmt, err := sqlDB.Prepare(query)
   112  	if err != nil {
   113  		return nil, err
   114  	}
   115  	defer stmt.Close()
   116  
   117  	rows, err := stmt.Query(args...)
   118  
   119  	if err != nil {
   120  		return nil, err
   121  	}
   122  
   123  	// Caller is responsible for closing rows with defer rows.Close()
   124  	return rows, err
   125  }
   126  
   127  // performExec executes Query SQL on the given sqlDB with no rows returned, just result
   128  func (db *Adapter) performExec(sqlDB *sql.DB, debug bool, query string, args ...interface{}) (sql.Result, error) {
   129  
   130  	if sqlDB == nil {
   131  		return nil, fmt.Errorf("No database available.")
   132  	}
   133  
   134  	if debug {
   135  		fmt.Println("QUERY:", query, "ARGS", args)
   136  	}
   137  
   138  	stmt, err := sqlDB.Prepare(query)
   139  	if err != nil {
   140  		return nil, err
   141  	}
   142  	defer stmt.Close()
   143  
   144  	result, err := stmt.Exec(args...)
   145  
   146  	if err != nil {
   147  		return result, err
   148  	}
   149  
   150  	// Caller is responsible for closing rows with defer rows.Close()
   151  	return result, err
   152  }