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 }