├── .gitignore ├── README.md ├── beedb.go ├── example ├── asta.db ├── gomysql.go ├── mssql.go ├── mysql.go ├── pg.go └── sqlite.go ├── util.go └── util_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Beedb 2 | ===== 3 | 4 | :exclamation: **IMPORTANT:** Beedb is being deprecated in favor of [Beego.orm](https://github.com/astaxie/beego/tree/master/orm) :exclamation: 5 | 6 | Beedb is an ORM for Go. It lets you map Go structs to tables in a database. It's intended to be very lightweight, doing very little beyond what you really want. For example, when fetching data, instead of re-inventing a query syntax, we just delegate your query to the underlying database, so you can write the "where" clause of your SQL statements directly. This allows you to have more flexibility while giving you a convenience layer. But beedb also has some smart defaults, for those times when complex queries aren't necessary. 7 | 8 | Right now, it interfaces with Mysql/SQLite/PostgreSQL/DB2/MS ADODB/ODBC/Oracle. The goal however is to add support for other databases in the future, including maybe MongoDb or NoSQL? 9 | 10 | Relationship-support is not implemented, for this we will recommend you to use [Beego.orm](https://github.com/astaxie/beego/tree/master/orm). 11 | 12 | All in all, it's not entirely ready for advanced use yet, but it's getting there. 13 | 14 | Drivers for Go's sql package which support database/sql includes: 15 | 16 | Mysql:[github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/godrv)`[*]` 17 | 18 | Mysql:[github.com/Go-SQL-Driver/MySQL](https://github.com/Go-SQL-Driver/MySQL)`[*]` 19 | 20 | PostgreSQL:[github.com/bmizerany/pq](https://github.com/bmizerany/pq)`[*]` 21 | 22 | SQLite:[github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)`[*]` 23 | 24 | DB2: [bitbucket.org/phiggins/go-db2-cli](https://bitbucket.org/phiggins/go-db2-cli) 25 | 26 | MS ADODB: [github.com/mattn/go-adodb](https://github.com/mattn/go-adodb)`[*]` 27 | 28 | ODBC: [bitbucket.org/miquella/mgodbc](https://bitbucket.org/miquella/mgodbc)`[*]` 29 | 30 | Oracle: [github.com/mattn/go-oci8](https://github.com/mattn/go-oci8) 31 | 32 | Drivers marked with a `[*]` are tested with Beedb 33 | 34 | ### API Interface 35 | [wiki/API-Interface](https://github.com/astaxie/beedb/wiki/API-Interface) 36 | 37 | ### Installing Beedb 38 | go get github.com/astaxie/beedb 39 | 40 | ### How do we use it? 41 | 42 | Open a database link(may be will support ConnectionPool in the future) 43 | 44 | ```go 45 | db, err := sql.Open("mymysql", "test/xiemengjun/123456") 46 | if err != nil { 47 | panic(err) 48 | } 49 | orm := beedb.New(db) 50 | ``` 51 | 52 | with PostgreSQL, 53 | 54 | ```go 55 | orm := beedb.New(db, "pg") 56 | ``` 57 | 58 | Open Debug log, turn on the debug 59 | 60 | ```go 61 | beedb.OnDebug=true 62 | ``` 63 | 64 | Model a struct after a table in the db 65 | 66 | ```go 67 | type Userinfo struct { 68 | Uid int `beedb:"PK" sql:"UID" tname:"USER_INFO"` //if the table's PrimaryKey is not "Id", use this tag 69 | Username string `sql:"USERNAME"` 70 | Departname string `sql:"DEPARTNAME"` 71 | Created time.Time `sql:"CREATED"` 72 | } 73 | ``` 74 | 75 | ###***Caution*** 76 | The structs Name 'UserInfo' will turn into the table name 'USER_INFO', as defined by the **tname** tag. 77 | If the key 'UserName' will turn into the select colum 'USERNAME' because of the **sql** tag. 78 | 79 | 80 | Create an object and save it 81 | 82 | ```go 83 | var saveone Userinfo 84 | saveone.Username = "Test Add User" 85 | saveone.Departname = "Test Add Departname" 86 | saveone.Created = time.Now() 87 | orm.Save(&saveone) 88 | ``` 89 | 90 | Saving new and existing objects 91 | 92 | ```go 93 | saveone.Username = "Update Username" 94 | saveone.Departname = "Update Departname" 95 | saveone.Created = time.Now() 96 | orm.Save(&saveone) //now saveone has the primarykey value it will update 97 | ``` 98 | 99 | Fetch a single object 100 | 101 | ```go 102 | var user Userinfo 103 | orm.Where("uid=?", 27).Find(&user) 104 | 105 | var user2 Userinfo 106 | orm.Where(3).Find(&user2) // this is shorthand for the version above 107 | 108 | var user3 Userinfo 109 | orm.Where("name = ?", "john").Find(&user3) // more complex query 110 | 111 | var user4 Userinfo 112 | orm.Where("name = ? and age < ?", "john", 88).Find(&user4) // even more complex 113 | ``` 114 | 115 | Fetch multiple objects 116 | 117 | ```go 118 | var allusers []Userinfo 119 | err := orm.Where("id > ?", "3").Limit(10,20).FindAll(&allusers) //Get id>3 limit 10 offset 20 120 | 121 | var tenusers []Userinfo 122 | err := orm.Where("id > ?", "3").Limit(10).FindAll(&tenusers) //Get id>3 limit 10 if omit offset the default is 0 123 | 124 | var everyone []Userinfo 125 | err := orm.FindAll(&everyone) 126 | ``` 127 | 128 | Find result as Map 129 | 130 | ```go 131 | //Original SQL Backinfo resultsSlice []map[string][]byte 132 | //default PrimaryKey id 133 | a, _ := orm.SetTable("userinfo").SetPK("uid").Where(2).Select("uid,username").FindMap() 134 | ``` 135 | 136 | Update with Map 137 | 138 | ```go 139 | t := make(map[string]interface{}) 140 | var j interface{} 141 | j = "astaxie" 142 | t["username"] = j 143 | //update one 144 | orm.SetTable("userinfo").SetPK("uid").Where(2).Update(t) 145 | ``` 146 | 147 | Update batch with Map 148 | ```go 149 | orm.SetTable("userinfo").Where("uid>?", 3).Update(t) 150 | ``` 151 | 152 | Insert data with Map 153 | 154 | ```go 155 | add := make(map[string]interface{}) 156 | j = "astaxie" 157 | add["username"] = j 158 | j = "cloud develop" 159 | add["departname"] = j 160 | j = "2012-12-02" 161 | add["created"] = j 162 | orm.SetTable("userinfo").Insert(add) 163 | ``` 164 | 165 | Insert batch with map 166 | 167 | ```go 168 | addslice := make([]map[string]interface{}) 169 | add:=make(map[string]interface{}) 170 | add2:=make(map[string]interface{}) 171 | j = "astaxie" 172 | add["username"] = j 173 | j = "cloud develop" 174 | add["departname"] = j 175 | j = "2012-12-02" 176 | add["created"] = j 177 | j = "astaxie2" 178 | add2["username"] = j 179 | j = "cloud develop2" 180 | add2["departname"] = j 181 | j = "2012-12-02" 182 | add2["created"] = j 183 | addslice =append(addslice, add, add2) 184 | orm.SetTable("userinfo").Insert(addslice) 185 | ``` 186 | 187 | Join Table 188 | 189 | ```go 190 | a, _ := orm.SetTable("userinfo").Join("LEFT", "userdeatail", "userinfo.uid=userdeatail.uid").Where("userinfo.uid=?", 1).Select("userinfo.uid,userinfo.username,userdeatail.profile").FindMap() 191 | ``` 192 | 193 | Group By And Having 194 | 195 | ```go 196 | a, _ := orm.SetTable("userinfo").GroupBy("username").Having("username='astaxie'").FindMap() 197 | ``` 198 | 199 | Nesting Models (inline) 200 | 201 | ```go 202 | type SQLModel struct { 203 | Id int `beedb:"PK" sql:"id"` 204 | Created time.Time `sql:"created"` 205 | Modified time.Time `sql:"modified"` 206 | } 207 | type User struct { 208 | SQLModel `sql:",inline"` 209 | Name string `sql:"name" tname:"fn_group"` 210 | Auth int `sql:"auth"` 211 | } 212 | // the SQL table has the columns: id, name, auth, created, modified 213 | // They are marshalled and unmarshalled automatically because of the inline keyword 214 | ``` 215 | 216 | ## LICENSE 217 | 218 | BSD License 219 | [http://creativecommons.org/licenses/BSD/](http://creativecommons.org/licenses/BSD/) 220 | -------------------------------------------------------------------------------- /beedb.go: -------------------------------------------------------------------------------- 1 | package beedb 2 | 3 | import ( 4 | "database/sql" 5 | "errors" 6 | "fmt" 7 | "reflect" 8 | "strconv" 9 | "strings" 10 | "time" 11 | ) 12 | 13 | var OnDebug = false 14 | var PluralizeTableNames = false 15 | 16 | type Model struct { 17 | Db *sql.DB 18 | TableName string 19 | LimitStr int 20 | OffsetStr int 21 | WhereStr string 22 | ParamStr []interface{} 23 | OrderStr string 24 | ColumnStr string 25 | PrimaryKey string 26 | JoinStr string 27 | GroupByStr string 28 | HavingStr string 29 | QuoteIdentifier string 30 | ParamIdentifier string 31 | ParamIteration int 32 | } 33 | 34 | /** 35 | * Add New sql.DB in the future i will add ConnectionPool.Get() 36 | */ 37 | func New(db *sql.DB, options ...interface{}) (m Model) { 38 | if len(options) == 0 { 39 | m = Model{Db: db, ColumnStr: "*", PrimaryKey: "Id", QuoteIdentifier: "`", ParamIdentifier: "?", ParamIteration: 1} 40 | } else if options[0] == "pg" { 41 | m = Model{Db: db, ColumnStr: "id", PrimaryKey: "Id", QuoteIdentifier: "\"", ParamIdentifier: options[0].(string), ParamIteration: 1} 42 | } else if options[0] == "mssql" { 43 | m = Model{Db: db, ColumnStr: "id", PrimaryKey: "id", QuoteIdentifier: "", ParamIdentifier: options[0].(string), ParamIteration: 1} 44 | } 45 | return 46 | } 47 | 48 | func (orm *Model) SetTable(tbname string) *Model { 49 | orm.TableName = tbname 50 | return orm 51 | } 52 | 53 | func (orm *Model) SetPK(pk string) *Model { 54 | orm.PrimaryKey = pk 55 | return orm 56 | } 57 | 58 | func (orm *Model) Where(querystring interface{}, args ...interface{}) *Model { 59 | switch querystring := querystring.(type) { 60 | case string: 61 | orm.WhereStr = querystring 62 | case int: 63 | if orm.ParamIdentifier == "pg" { 64 | orm.WhereStr = fmt.Sprintf("%v%v%v = $%v", orm.QuoteIdentifier, orm.PrimaryKey, orm.QuoteIdentifier, orm.ParamIteration) 65 | } else { 66 | orm.WhereStr = fmt.Sprintf("%v%v%v = ?", orm.QuoteIdentifier, orm.PrimaryKey, orm.QuoteIdentifier) 67 | orm.ParamIteration++ 68 | } 69 | args = append(args, querystring) 70 | } 71 | orm.ParamStr = args 72 | return orm 73 | } 74 | 75 | func (orm *Model) Limit(start int, size ...int) *Model { 76 | orm.LimitStr = start 77 | if len(size) > 0 { 78 | orm.OffsetStr = size[0] 79 | } 80 | return orm 81 | } 82 | 83 | func (orm *Model) Offset(offset int) *Model { 84 | orm.OffsetStr = offset 85 | return orm 86 | } 87 | 88 | func (orm *Model) OrderBy(order string) *Model { 89 | orm.OrderStr = order 90 | return orm 91 | } 92 | 93 | func (orm *Model) Select(colums string) *Model { 94 | orm.ColumnStr = colums 95 | return orm 96 | } 97 | 98 | func (orm *Model) ScanPK(output interface{}) *Model { 99 | if reflect.TypeOf(reflect.Indirect(reflect.ValueOf(output)).Interface()).Kind() == reflect.Slice { 100 | sliceValue := reflect.Indirect(reflect.ValueOf(output)) 101 | sliceElementType := sliceValue.Type().Elem() 102 | for i := 0; i < sliceElementType.NumField(); i++ { 103 | bb := sliceElementType.Field(i).Tag 104 | if bb.Get("beedb") == "PK" || reflect.ValueOf(bb).String() == "PK" { 105 | orm.PrimaryKey = sliceElementType.Field(i).Name 106 | } 107 | } 108 | } else { 109 | tt := reflect.TypeOf(reflect.Indirect(reflect.ValueOf(output)).Interface()) 110 | for i := 0; i < tt.NumField(); i++ { 111 | bb := tt.Field(i).Tag 112 | if bb.Get("beedb") == "PK" || reflect.ValueOf(bb).String() == "PK" { 113 | orm.PrimaryKey = tt.Field(i).Name 114 | } 115 | } 116 | } 117 | return orm 118 | 119 | } 120 | 121 | //The join_operator should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN 122 | func (orm *Model) Join(join_operator, tablename, condition string) *Model { 123 | if orm.JoinStr != "" { 124 | orm.JoinStr = orm.JoinStr + fmt.Sprintf(" %v JOIN %v ON %v", join_operator, tablename, condition) 125 | } else { 126 | orm.JoinStr = fmt.Sprintf("%v JOIN %v ON %v", join_operator, tablename, condition) 127 | } 128 | 129 | return orm 130 | } 131 | 132 | func (orm *Model) GroupBy(keys string) *Model { 133 | orm.GroupByStr = fmt.Sprintf("GROUP BY %v", keys) 134 | return orm 135 | } 136 | 137 | func (orm *Model) Having(conditions string) *Model { 138 | orm.HavingStr = fmt.Sprintf("HAVING %v", conditions) 139 | return orm 140 | } 141 | 142 | func (orm *Model) Find(output interface{}) error { 143 | orm.ScanPK(output) 144 | var keys []string 145 | results, err := scanStructIntoMap(output) 146 | if err != nil { 147 | return err 148 | } 149 | 150 | if orm.TableName == "" { 151 | orm.TableName = getTableName(output) 152 | } 153 | // If we've already specific columns with Select(), use that 154 | if orm.ColumnStr == "*" { 155 | for key, _ := range results { 156 | keys = append(keys, key) 157 | } 158 | orm.ColumnStr = strings.Join(keys, ", ") 159 | } 160 | orm.Limit(1) 161 | resultsSlice, err := orm.FindMap() 162 | if err != nil { 163 | return err 164 | } 165 | if len(resultsSlice) == 0 { 166 | return errors.New("No record found") 167 | } else if len(resultsSlice) == 1 { 168 | results := resultsSlice[0] 169 | err := scanMapIntoStruct(output, results) 170 | if err != nil { 171 | return err 172 | } 173 | } else { 174 | return errors.New("More than one record") 175 | } 176 | return nil 177 | } 178 | 179 | func (orm *Model) FindAll(rowsSlicePtr interface{}) error { 180 | orm.ScanPK(rowsSlicePtr) 181 | sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr)) 182 | if sliceValue.Kind() != reflect.Slice { 183 | return errors.New("needs a pointer to a slice") 184 | } 185 | 186 | sliceElementType := sliceValue.Type().Elem() 187 | st := reflect.New(sliceElementType) 188 | var keys []string 189 | results, err := scanStructIntoMap(st.Interface()) 190 | if err != nil { 191 | return err 192 | } 193 | 194 | if orm.TableName == "" { 195 | orm.TableName = getTableName(getTypeName(rowsSlicePtr)) 196 | } 197 | // If we've already specific columns with Select(), use that 198 | if orm.ColumnStr == "*" { 199 | for key, _ := range results { 200 | keys = append(keys, key) 201 | } 202 | orm.ColumnStr = strings.Join(keys, ", ") 203 | } 204 | resultsSlice, err := orm.FindMap() 205 | if err != nil { 206 | return err 207 | } 208 | 209 | for _, results := range resultsSlice { 210 | newValue := reflect.New(sliceElementType) 211 | err := scanMapIntoStruct(newValue.Interface(), results) 212 | if err != nil { 213 | return err 214 | } 215 | sliceValue.Set(reflect.Append(sliceValue, reflect.Indirect(reflect.ValueOf(newValue.Interface())))) 216 | } 217 | return nil 218 | } 219 | 220 | func (orm *Model) FindMap() (resultsSlice []map[string][]byte, err error) { 221 | defer orm.InitModel() 222 | sqls := orm.generateSql() 223 | if OnDebug { 224 | fmt.Println(sqls) 225 | fmt.Println(orm) 226 | } 227 | s, err := orm.Db.Prepare(sqls) 228 | if err != nil { 229 | return nil, err 230 | } 231 | defer s.Close() 232 | res, err := s.Query(orm.ParamStr...) 233 | if err != nil { 234 | return nil, err 235 | } 236 | defer res.Close() 237 | fields, err := res.Columns() 238 | if err != nil { 239 | return nil, err 240 | } 241 | for res.Next() { 242 | result := make(map[string][]byte) 243 | var scanResultContainers []interface{} 244 | for i := 0; i < len(fields); i++ { 245 | var scanResultContainer interface{} 246 | scanResultContainers = append(scanResultContainers, &scanResultContainer) 247 | } 248 | if err := res.Scan(scanResultContainers...); err != nil { 249 | return nil, err 250 | } 251 | for ii, key := range fields { 252 | rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii])) 253 | //if row is null then ignore 254 | if rawValue.Interface() == nil { 255 | continue 256 | } 257 | aa := reflect.TypeOf(rawValue.Interface()) 258 | vv := reflect.ValueOf(rawValue.Interface()) 259 | var str string 260 | switch aa.Kind() { 261 | case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 262 | str = strconv.FormatInt(vv.Int(), 10) 263 | result[key] = []byte(str) 264 | case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 265 | str = strconv.FormatUint(vv.Uint(), 10) 266 | result[key] = []byte(str) 267 | case reflect.Float32, reflect.Float64: 268 | str = strconv.FormatFloat(vv.Float(), 'f', -1, 64) 269 | result[key] = []byte(str) 270 | case reflect.Slice: 271 | if aa.Elem().Kind() == reflect.Uint8 { 272 | result[key] = rawValue.Interface().([]byte) 273 | break 274 | } 275 | case reflect.String: 276 | str = vv.String() 277 | result[key] = []byte(str) 278 | //时间类型 279 | case reflect.Struct: 280 | str = rawValue.Interface().(time.Time).Format("2006-01-02 15:04:05.000 -0700") 281 | result[key] = []byte(str) 282 | case reflect.Bool: 283 | if vv.Bool() { 284 | result[key] = []byte("1") 285 | } else { 286 | result[key] = []byte("0") 287 | } 288 | } 289 | } 290 | resultsSlice = append(resultsSlice, result) 291 | } 292 | return resultsSlice, nil 293 | } 294 | 295 | func (orm *Model) generateSql() (a string) { 296 | if orm.ParamIdentifier == "mssql" { 297 | if orm.OffsetStr > 0 { 298 | a = fmt.Sprintf("select ROW_NUMBER() OVER(order by %v )as rownum,%v from %v", 299 | orm.PrimaryKey, 300 | orm.ColumnStr, 301 | orm.TableName) 302 | if orm.WhereStr != "" { 303 | a = fmt.Sprintf("%v WHERE %v", a, orm.WhereStr) 304 | } 305 | a = fmt.Sprintf("select * from (%v) "+ 306 | "as a where rownum between %v and %v", 307 | a, 308 | orm.OffsetStr, 309 | orm.LimitStr) 310 | } else if orm.LimitStr > 0 { 311 | a = fmt.Sprintf("SELECT top %v %v FROM %v", orm.LimitStr, orm.ColumnStr, orm.TableName) 312 | if orm.WhereStr != "" { 313 | a = fmt.Sprintf("%v WHERE %v", a, orm.WhereStr) 314 | } 315 | if orm.GroupByStr != "" { 316 | a = fmt.Sprintf("%v %v", a, orm.GroupByStr) 317 | } 318 | if orm.HavingStr != "" { 319 | a = fmt.Sprintf("%v %v", a, orm.HavingStr) 320 | } 321 | if orm.OrderStr != "" { 322 | a = fmt.Sprintf("%v ORDER BY %v", a, orm.OrderStr) 323 | } 324 | } else { 325 | a = fmt.Sprintf("SELECT %v FROM %v", orm.ColumnStr, orm.TableName) 326 | if orm.WhereStr != "" { 327 | a = fmt.Sprintf("%v WHERE %v", a, orm.WhereStr) 328 | } 329 | if orm.GroupByStr != "" { 330 | a = fmt.Sprintf("%v %v", a, orm.GroupByStr) 331 | } 332 | if orm.HavingStr != "" { 333 | a = fmt.Sprintf("%v %v", a, orm.HavingStr) 334 | } 335 | if orm.OrderStr != "" { 336 | a = fmt.Sprintf("%v ORDER BY %v", a, orm.OrderStr) 337 | } 338 | } 339 | } else { 340 | a = fmt.Sprintf("SELECT %v FROM %v", orm.ColumnStr, orm.TableName) 341 | if orm.JoinStr != "" { 342 | a = fmt.Sprintf("%v %v", a, orm.JoinStr) 343 | } 344 | if orm.WhereStr != "" { 345 | a = fmt.Sprintf("%v WHERE %v", a, orm.WhereStr) 346 | } 347 | if orm.GroupByStr != "" { 348 | a = fmt.Sprintf("%v %v", a, orm.GroupByStr) 349 | } 350 | if orm.HavingStr != "" { 351 | a = fmt.Sprintf("%v %v", a, orm.HavingStr) 352 | } 353 | if orm.OrderStr != "" { 354 | a = fmt.Sprintf("%v ORDER BY %v", a, orm.OrderStr) 355 | } 356 | if orm.OffsetStr > 0 { 357 | a = fmt.Sprintf("%v LIMIT %v OFFSET %v", a, orm.LimitStr, orm.OffsetStr) 358 | } else if orm.LimitStr > 0 { 359 | a = fmt.Sprintf("%v LIMIT %v", a, orm.LimitStr) 360 | } 361 | } 362 | return 363 | } 364 | 365 | //Execute sql 366 | func (orm *Model) Exec(finalQueryString string, args ...interface{}) (sql.Result, error) { 367 | rs, err := orm.Db.Prepare(finalQueryString) 368 | if err != nil { 369 | return nil, err 370 | } 371 | defer rs.Close() 372 | 373 | res, err := rs.Exec(args...) 374 | if err != nil { 375 | return nil, err 376 | } 377 | return res, nil 378 | } 379 | 380 | //if the struct has PrimaryKey == 0 insert else update 381 | func (orm *Model) Save(output interface{}) error { 382 | orm.ScanPK(output) 383 | results, err := scanStructIntoMap(output) 384 | if err != nil { 385 | return err 386 | } 387 | 388 | if orm.TableName == "" { 389 | orm.TableName = getTableName(output) 390 | } 391 | id := results[orm.PrimaryKey] 392 | delete(results, orm.PrimaryKey) 393 | 394 | if id == nil { 395 | return fmt.Errorf("Unable to save because primary key %q was not found in struct", orm.PrimaryKey) 396 | } 397 | 398 | if reflect.ValueOf(id).Int() == 0 { 399 | structPtr := reflect.ValueOf(output) 400 | structVal := structPtr.Elem() 401 | structField := structVal.FieldByName(orm.PrimaryKey) 402 | id, err := orm.Insert(results) 403 | if err != nil { 404 | return err 405 | } 406 | var v interface{} 407 | x, err := strconv.Atoi(strconv.FormatInt(id, 10)) 408 | if err != nil { 409 | return err 410 | } 411 | v = x 412 | structField.Set(reflect.ValueOf(v)) 413 | return nil 414 | } else { 415 | var condition string 416 | if orm.ParamIdentifier == "pg" { 417 | condition = fmt.Sprintf("%v%v%v=$%v", orm.QuoteIdentifier, strings.ToLower(orm.PrimaryKey), orm.QuoteIdentifier, orm.ParamIteration) 418 | } else { 419 | condition = fmt.Sprintf("%v%v%v=?", orm.QuoteIdentifier, orm.PrimaryKey, orm.QuoteIdentifier) 420 | } 421 | orm.Where(condition, id) 422 | _, err := orm.Update(results) 423 | if err != nil { 424 | return err 425 | } 426 | } 427 | return nil 428 | } 429 | 430 | //inert one info 431 | func (orm *Model) Insert(properties map[string]interface{}) (int64, error) { 432 | defer orm.InitModel() 433 | var keys []string 434 | var placeholders []string 435 | var args []interface{} 436 | for key, val := range properties { 437 | keys = append(keys, key) 438 | if orm.ParamIdentifier == "pg" { 439 | ds := fmt.Sprintf("$%d", orm.ParamIteration) 440 | placeholders = append(placeholders, ds) 441 | } else { 442 | placeholders = append(placeholders, "?") 443 | } 444 | orm.ParamIteration++ 445 | args = append(args, val) 446 | } 447 | ss := fmt.Sprintf("%v,%v", orm.QuoteIdentifier, orm.QuoteIdentifier) 448 | statement := fmt.Sprintf("INSERT INTO %v%v%v (%v%v%v) VALUES (%v)", 449 | orm.QuoteIdentifier, 450 | orm.TableName, 451 | orm.QuoteIdentifier, 452 | orm.QuoteIdentifier, 453 | strings.Join(keys, ss), 454 | orm.QuoteIdentifier, 455 | strings.Join(placeholders, ", ")) 456 | if OnDebug { 457 | fmt.Println(statement) 458 | fmt.Println(orm) 459 | } 460 | if orm.ParamIdentifier == "pg" { 461 | statement = fmt.Sprintf("%v RETURNING %v", statement, snakeCasedName(orm.PrimaryKey)) 462 | var id int64 463 | orm.Db.QueryRow(statement, args...).Scan(&id) 464 | return id, nil 465 | } else { 466 | res, err := orm.Exec(statement, args...) 467 | if err != nil { 468 | return -1, err 469 | } 470 | 471 | id, err := res.LastInsertId() 472 | 473 | if err != nil { 474 | return -1, err 475 | } 476 | return id, nil 477 | } 478 | return -1, nil 479 | } 480 | 481 | //insert batch info 482 | func (orm *Model) InsertBatch(rows []map[string]interface{}) ([]int64, error) { 483 | var ids []int64 484 | tablename := orm.TableName 485 | if len(rows) <= 0 { 486 | return ids, nil 487 | } 488 | for i := 0; i < len(rows); i++ { 489 | orm.TableName = tablename 490 | id, err := orm.Insert(rows[i]) 491 | if err != nil { 492 | return ids, err 493 | } 494 | 495 | ids = append(ids, id) 496 | } 497 | return ids, nil 498 | } 499 | 500 | // update info 501 | func (orm *Model) Update(properties map[string]interface{}) (int64, error) { 502 | defer orm.InitModel() 503 | var updates []string 504 | var args []interface{} 505 | for key, val := range properties { 506 | if orm.ParamIdentifier == "pg" { 507 | ds := fmt.Sprintf("$%d", orm.ParamIteration) 508 | updates = append(updates, fmt.Sprintf("%v%v%v = %v", orm.QuoteIdentifier, key, orm.QuoteIdentifier, ds)) 509 | } else { 510 | updates = append(updates, fmt.Sprintf("%v%v%v = ?", orm.QuoteIdentifier, key, orm.QuoteIdentifier)) 511 | } 512 | args = append(args, val) 513 | orm.ParamIteration++ 514 | } 515 | args = append(args, orm.ParamStr...) 516 | if orm.ParamIdentifier == "pg" { 517 | if n := len(orm.ParamStr); n > 0 { 518 | for i := 1; i <= n; i++ { 519 | orm.WhereStr = strings.Replace(orm.WhereStr, "$"+strconv.Itoa(i), "$"+strconv.Itoa(orm.ParamIteration), 1) 520 | } 521 | } 522 | } 523 | var condition string 524 | if orm.WhereStr != "" { 525 | condition = fmt.Sprintf("WHERE %v", orm.WhereStr) 526 | } else { 527 | condition = "" 528 | } 529 | statement := fmt.Sprintf("UPDATE %v%v%v SET %v %v", 530 | orm.QuoteIdentifier, 531 | orm.TableName, 532 | orm.QuoteIdentifier, 533 | strings.Join(updates, ", "), 534 | condition) 535 | if OnDebug { 536 | fmt.Println(statement) 537 | fmt.Println(orm) 538 | } 539 | res, err := orm.Exec(statement, args...) 540 | if err != nil { 541 | return -1, err 542 | } 543 | id, err := res.RowsAffected() 544 | 545 | if err != nil { 546 | return -1, err 547 | } 548 | return id, nil 549 | } 550 | 551 | func (orm *Model) Delete(output interface{}) (int64, error) { 552 | defer orm.InitModel() 553 | orm.ScanPK(output) 554 | results, err := scanStructIntoMap(output) 555 | if err != nil { 556 | return 0, err 557 | } 558 | 559 | if orm.TableName == "" { 560 | orm.TableName = getTableName(output) 561 | } 562 | id := results[strings.ToLower(orm.PrimaryKey)] 563 | condition := fmt.Sprintf("%v%v%v='%v'", orm.QuoteIdentifier, strings.ToLower(orm.PrimaryKey), orm.QuoteIdentifier, id) 564 | statement := fmt.Sprintf("DELETE FROM %v%v%v WHERE %v", 565 | orm.QuoteIdentifier, 566 | orm.TableName, 567 | orm.QuoteIdentifier, 568 | condition) 569 | if OnDebug { 570 | fmt.Println(statement) 571 | fmt.Println(orm) 572 | } 573 | res, err := orm.Exec(statement) 574 | if err != nil { 575 | return -1, err 576 | } 577 | Affectid, err := res.RowsAffected() 578 | 579 | if err != nil { 580 | return -1, err 581 | } 582 | return Affectid, nil 583 | } 584 | 585 | func (orm *Model) DeleteAll(rowsSlicePtr interface{}) (int64, error) { 586 | defer orm.InitModel() 587 | orm.ScanPK(rowsSlicePtr) 588 | if orm.TableName == "" { 589 | //TODO: fix table name 590 | orm.TableName = getTableName(getTypeName(rowsSlicePtr)) 591 | } 592 | var ids []string 593 | val := reflect.Indirect(reflect.ValueOf(rowsSlicePtr)) 594 | if val.Len() == 0 { 595 | return 0, nil 596 | } 597 | for i := 0; i < val.Len(); i++ { 598 | results, err := scanStructIntoMap(val.Index(i).Interface()) 599 | if err != nil { 600 | return 0, err 601 | } 602 | 603 | id := results[strings.ToLower(orm.PrimaryKey)] 604 | switch id.(type) { 605 | case string: 606 | ids = append(ids, id.(string)) 607 | case int, int64, int32: 608 | str := strconv.Itoa(id.(int)) 609 | ids = append(ids, str) 610 | } 611 | } 612 | condition := fmt.Sprintf("%v%v%v in ('%v')", orm.QuoteIdentifier, strings.ToLower(orm.PrimaryKey), orm.QuoteIdentifier, strings.Join(ids, "','")) 613 | statement := fmt.Sprintf("DELETE FROM %v%v%v WHERE %v", 614 | orm.QuoteIdentifier, 615 | orm.TableName, 616 | orm.QuoteIdentifier, 617 | condition) 618 | if OnDebug { 619 | fmt.Println(statement) 620 | fmt.Println(orm) 621 | } 622 | res, err := orm.Exec(statement) 623 | if err != nil { 624 | return -1, err 625 | } 626 | Affectid, err := res.RowsAffected() 627 | 628 | if err != nil { 629 | return -1, err 630 | } 631 | return Affectid, nil 632 | } 633 | 634 | func (orm *Model) DeleteRow() (int64, error) { 635 | defer orm.InitModel() 636 | var condition string 637 | if orm.WhereStr != "" { 638 | condition = fmt.Sprintf("WHERE %v", orm.WhereStr) 639 | } else { 640 | condition = "" 641 | } 642 | statement := fmt.Sprintf("DELETE FROM %v%v%v %v", 643 | orm.QuoteIdentifier, 644 | orm.TableName, 645 | orm.QuoteIdentifier, 646 | condition) 647 | if OnDebug { 648 | fmt.Println(statement) 649 | fmt.Println(orm) 650 | } 651 | res, err := orm.Exec(statement, orm.ParamStr...) 652 | if err != nil { 653 | return -1, err 654 | } 655 | Affectid, err := res.RowsAffected() 656 | 657 | if err != nil { 658 | return -1, err 659 | } 660 | return Affectid, nil 661 | } 662 | 663 | func (orm *Model) InitModel() { 664 | orm.TableName = "" 665 | orm.LimitStr = 0 666 | orm.OffsetStr = 0 667 | orm.WhereStr = "" 668 | orm.ParamStr = make([]interface{}, 0) 669 | orm.OrderStr = "" 670 | orm.ColumnStr = "*" 671 | orm.PrimaryKey = "id" 672 | orm.JoinStr = "" 673 | orm.GroupByStr = "" 674 | orm.HavingStr = "" 675 | orm.ParamIteration = 1 676 | } 677 | -------------------------------------------------------------------------------- /example/asta.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/astaxie/beedb/1732292dfde40fab7b4ad38ba413492ec5633ad3/example/asta.db -------------------------------------------------------------------------------- /example/gomysql.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | _ "github.com/go-sql-driver/mysql" 5 | "database/sql" 6 | "fmt" 7 | "github.com/astaxie/beedb" 8 | "strconv" 9 | "time" 10 | ) 11 | 12 | /* 13 | CREATE TABLE `userinfo` ( 14 | `uid` INT(10) NULL AUTO_INCREMENT, 15 | `username` VARCHAR(64) NULL, 16 | `departname` VARCHAR(64) NULL, 17 | `created` DATE NULL, 18 | PRIMARY KEY (`uid`) 19 | ); 20 | CREATE TABLE `userdeatail` ( 21 | `uid` INT(10) NULL, 22 | `intro` TEXT NULL, 23 | `profile` TEXT NULL, 24 | PRIMARY KEY (`uid`) 25 | ); 26 | */ 27 | 28 | var orm beedb.Model 29 | 30 | type Userinfo struct { 31 | Uid int `beedb:"PK"` 32 | Username string 33 | Departname string 34 | Created time.Time 35 | } 36 | 37 | func main() { 38 | db, err := sql.Open("mysql", "xiemengjun:123456@/test?charset=utf8") 39 | if err != nil { 40 | panic(err) 41 | } 42 | orm = beedb.New(db) 43 | beedb.OnDebug = true 44 | insertbatch() 45 | //insert() 46 | //insertsql() 47 | // a := selectone() 48 | // fmt.Println(a) 49 | // b := selectall() 50 | // fmt.Println(b) 51 | // update() 52 | // updatesql() 53 | // findmap() 54 | //groupby() 55 | //jointable() 56 | //delete() 57 | //deleteall() 58 | //deletesql() 59 | } 60 | 61 | func insert() { 62 | //save data 63 | var saveone Userinfo 64 | saveone.Username = "Test Add User" 65 | saveone.Departname = "Test Add Departname" 66 | saveone.Created = time.Now() 67 | orm.Save(&saveone) 68 | fmt.Println(saveone) 69 | } 70 | 71 | func insertsql() { 72 | // add one 73 | add := make(map[string]interface{}) 74 | add["username"] = "astaxie" 75 | add["departname"] = "cloud develop" 76 | add["created"] = "2012-12-02" 77 | orm.SetTable("userinfo").Insert(add) 78 | } 79 | 80 | func insertbatch() { 81 | rows := make([]map[string]interface{}, 10) 82 | for i := 0; i < 10; i++ { 83 | add := make(map[string]interface{}) 84 | name := "person" + strconv.Itoa(i) 85 | add["username"] = name 86 | add["departname"] = "IT" 87 | add["created"] = "2012-06-13" 88 | rows[i] = add 89 | } 90 | fmt.Println(rows) 91 | orm.SetTable("userinfo").InsertBatch(rows) 92 | } 93 | 94 | func selectone() Userinfo { 95 | //get one info 96 | var one Userinfo 97 | orm.Where("uid=?", 1).Find(&one) 98 | return one 99 | } 100 | 101 | func selectall() []Userinfo { 102 | //get all data 103 | var alluser []Userinfo 104 | orm.Limit(10).Where("uid>?", 1).FindAll(&alluser) 105 | return alluser 106 | } 107 | func update() { 108 | // //update data 109 | var saveone Userinfo 110 | saveone.Uid = 1 111 | saveone.Username = "Update Username" 112 | saveone.Departname = "Update Departname" 113 | saveone.Created = time.Now() 114 | orm.Save(&saveone) 115 | fmt.Println(saveone) 116 | } 117 | 118 | func updatesql() { 119 | //original SQL update 120 | t := make(map[string]interface{}) 121 | t["username"] = "updateastaxie" 122 | //update one 123 | orm.SetTable("userinfo").SetPK("uid").Where(2).Update(t) 124 | //update batch 125 | //orm.SetTable("userinfo").Where("uid>?", 3).Update(t) 126 | } 127 | 128 | func findmap() { 129 | //Original SQL Backinfo resultsSlice []map[string][]byte 130 | //default PrimaryKey id 131 | c, _ := orm. 132 | SetTable("userinfo"). 133 | SetPK("uid"). 134 | Where("username like ?", "%per%"). 135 | Select("uid,username"). 136 | FindMap() 137 | fmt.Println(c) 138 | } 139 | 140 | func groupby() { 141 | //Original SQL Group By 142 | b, _ := orm.SetTable("userinfo").GroupBy("username").Having("username='updateastaxie'").FindMap() 143 | fmt.Println(b) 144 | } 145 | 146 | func jointable() { 147 | //Original SQL Join Table 148 | a, _ := orm.SetTable("userinfo").Join("LEFT", "userdeatail", "userinfo.uid=userdeatail.uid").Where("userinfo.uid=?", 1).Select("userinfo.uid,userinfo.username,userdeatail.profile").FindMap() 149 | fmt.Println(a) 150 | } 151 | 152 | func delete() { 153 | // // //delete one data 154 | saveone := selectone() 155 | orm.Delete(&saveone) 156 | } 157 | 158 | func deletesql() { 159 | //original SQL delete 160 | orm.SetTable("userinfo").Where("uid>?", 3).DeleteRow() 161 | } 162 | 163 | func deleteall() { 164 | // //delete all data 165 | alluser := selectall() 166 | orm.DeleteAll(&alluser) 167 | } 168 | -------------------------------------------------------------------------------- /example/mssql.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/astaxie/beedb" 6 | _ "github.com/mattn/go-adodb" 7 | "database/sql" 8 | ) 9 | 10 | /* 11 | CREATE TABLE userinfo ( 12 | uid INT IDENTITY(1,1) NOT NULL , 13 | username VARCHAR(64) NULL, 14 | departname VARCHAR(64) NULL, 15 | created datetime NULL, 16 | PRIMARY KEY (uid) 17 | ); 18 | CREATE TABLE userdeatail ( 19 | uid INT, 20 | intro TEXT NULL, 21 | profile TEXT NULL, 22 | PRIMARY KEY (uid) 23 | ); 24 | */ 25 | 26 | var orm beedb.Model 27 | 28 | type Userinfo struct { 29 | Uid int `beedb:"PK"` 30 | Username string 31 | Departname string 32 | Created string 33 | } 34 | 35 | func main() { 36 | db, err := sql.Open("adodb", "Provider=SQLOLEDB;Initial Catalog=test;Data Source=SH-XIEMENGJUN\\SQLEXPRESS;user id=sa;password=123456") 37 | 38 | if err != nil { 39 | panic(err) 40 | } 41 | rows, err := db.Query("select uid, username from userinfo") 42 | if err != nil { 43 | fmt.Println(err) 44 | return 45 | } 46 | defer rows.Close() 47 | 48 | for rows.Next() { 49 | var id int 50 | var name string 51 | rows.Scan(&id, &name) 52 | println(id, name) 53 | } 54 | 55 | //orm = beedb.New(db, "mssql") 56 | //insert() 57 | //insertsql() 58 | //a := selectone() 59 | //fmt.Println(a) 60 | // b := selectall() 61 | // fmt.Println(b) 62 | // update() 63 | //updatesql() 64 | //findmap() 65 | //groupby() 66 | //jointable() 67 | //delete() 68 | //deleteall() 69 | //deletesql() 70 | } 71 | 72 | func insert() { 73 | //save data 74 | var saveone Userinfo 75 | saveone.Username = "Test Add User" 76 | saveone.Departname = "Test Add Departname" 77 | saveone.Created = "2012-12-02" 78 | err := orm.Save(&saveone) 79 | if err != nil { 80 | fmt.Println(err) 81 | } 82 | fmt.Println(saveone) 83 | } 84 | 85 | func insertsql() { 86 | // add one 87 | add := make(map[string]interface{}) 88 | add["username"] = "astaxie" 89 | add["departname"] = "cloud develop" 90 | add["created"] = "2012-12-02" 91 | orm.SetTable("userinfo").Insert(add) 92 | } 93 | 94 | func selectone() Userinfo { 95 | //get one info 96 | var one Userinfo 97 | orm.Where("uid=?", 1).Find(&one) 98 | return one 99 | } 100 | 101 | func selectall() []Userinfo { 102 | //get all data 103 | var alluser []Userinfo 104 | orm.Limit(10).Where("uid>?", 1).FindAll(&alluser) 105 | return alluser 106 | } 107 | func update() { 108 | // //update data 109 | var saveone Userinfo 110 | saveone.Uid = 1 111 | saveone.Username = "Update Username" 112 | saveone.Departname = "Update Departname" 113 | saveone.Created = "2012-12-02" 114 | orm.Save(&saveone) 115 | fmt.Println(saveone) 116 | } 117 | 118 | func updatesql() { 119 | //original SQL update 120 | t := make(map[string]interface{}) 121 | t["username"] = "updateastaxie" 122 | //update one 123 | orm.SetTable("userinfo").SetPK("uid").Where(2).Update(t) 124 | //update batch 125 | orm.SetTable("userinfo").Where("uid>?", 3).Update(t) 126 | } 127 | 128 | func findmap() { 129 | //Original SQL Backinfo resultsSlice []map[string][]byte 130 | //default PrimaryKey id 131 | c, _ := orm.SetTable("userinfo").SetPK("uid").Where(2).Select("uid,username").FindMap() 132 | fmt.Println(c) 133 | } 134 | 135 | func groupby() { 136 | //Original SQL Group By 137 | b, _ := orm.SetTable("userinfo").GroupBy("username").Having("username='updateastaxie'").FindMap() 138 | fmt.Println(b) 139 | } 140 | 141 | func jointable() { 142 | //Original SQL Join Table 143 | a, _ := orm.SetTable("userinfo").Join("LEFT", "userdeatail", "userinfo.uid=userdeatail.uid").Where("userinfo.uid=?", 1).Select("userinfo.uid,userinfo.username,userdeatail.profile").FindMap() 144 | fmt.Println(a) 145 | } 146 | 147 | func delete() { 148 | // // //delete one data 149 | saveone := selectone() 150 | orm.Delete(&saveone) 151 | } 152 | 153 | func deletesql() { 154 | //original SQL delete 155 | orm.SetTable("userinfo").Where("uid>?", 3).DeleteRow() 156 | } 157 | 158 | func deleteall() { 159 | // //delete all data 160 | alluser := selectall() 161 | orm.DeleteAll(&alluser) 162 | } 163 | -------------------------------------------------------------------------------- /example/mysql.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "database/sql" 5 | "fmt" 6 | "github.com/astaxie/beedb" 7 | _ "github.com/ziutek/mymysql/godrv" 8 | "strconv" 9 | "time" 10 | ) 11 | 12 | /* 13 | CREATE TABLE `userinfo` ( 14 | `uid` INT(10) NULL AUTO_INCREMENT, 15 | `username` VARCHAR(64) NULL, 16 | `departname` VARCHAR(64) NULL, 17 | `created` DATE NULL, 18 | PRIMARY KEY (`uid`) 19 | ); 20 | CREATE TABLE `userdeatail` ( 21 | `uid` INT(10) NULL, 22 | `intro` TEXT NULL, 23 | `profile` TEXT NULL, 24 | PRIMARY KEY (`uid`) 25 | ); 26 | */ 27 | 28 | var orm beedb.Model 29 | 30 | type Userinfo struct { 31 | Uid int `beedb:"PK"` 32 | Username string 33 | Departname string 34 | Created time.Time 35 | } 36 | 37 | func main() { 38 | db, err := sql.Open("mymysql", "test/xiemengjun/123456") 39 | if err != nil { 40 | panic(err) 41 | } 42 | orm = beedb.New(db) 43 | //insertbatch() 44 | // insert() 45 | // insertsql() 46 | // a := selectone() 47 | // fmt.Println(a) 48 | // b := selectall() 49 | // fmt.Println(b) 50 | // update() 51 | //updatesql() 52 | findmap() 53 | //groupby() 54 | //jointable() 55 | //delete() 56 | //deleteall() 57 | //deletesql() 58 | } 59 | 60 | func insert() { 61 | //save data 62 | var saveone Userinfo 63 | saveone.Username = "Test Add User" 64 | saveone.Departname = "Test Add Departname" 65 | saveone.Created = time.Now() 66 | orm.Save(&saveone) 67 | fmt.Println(saveone) 68 | } 69 | 70 | func insertsql() { 71 | // add one 72 | add := make(map[string]interface{}) 73 | add["username"] = "astaxie" 74 | add["departname"] = "cloud develop" 75 | add["created"] = "2012-12-02" 76 | orm.SetTable("userinfo").Insert(add) 77 | } 78 | 79 | func insertbatch() { 80 | rows := make([]map[string]interface{}, 10) 81 | for i := 0; i < 10; i++ { 82 | add := make(map[string]interface{}) 83 | name := "person" + strconv.Itoa(i) 84 | add["username"] = name 85 | add["departname"] = "IT" 86 | add["created"] = "2012-06-13" 87 | rows[i] = add 88 | } 89 | fmt.Println(rows) 90 | orm.SetTable("userinfo").InsertBatch(rows) 91 | } 92 | 93 | func selectone() Userinfo { 94 | //get one info 95 | var one Userinfo 96 | orm.Where("uid=?", 1).Find(&one) 97 | return one 98 | } 99 | 100 | func selectall() []Userinfo { 101 | //get all data 102 | var alluser []Userinfo 103 | orm.Limit(10).Where("uid>?", 1).FindAll(&alluser) 104 | return alluser 105 | } 106 | func update() { 107 | // //update data 108 | var saveone Userinfo 109 | saveone.Uid = 1 110 | saveone.Username = "Update Username" 111 | saveone.Departname = "Update Departname" 112 | saveone.Created = time.Now() 113 | orm.Save(&saveone) 114 | fmt.Println(saveone) 115 | } 116 | 117 | func updatesql() { 118 | //original SQL update 119 | t := make(map[string]interface{}) 120 | t["username"] = "updateastaxie" 121 | //update one 122 | orm.SetTable("userinfo").SetPK("uid").Where(2).Update(t) 123 | //update batch 124 | //orm.SetTable("userinfo").Where("uid>?", 3).Update(t) 125 | } 126 | 127 | func findmap() { 128 | //Original SQL Backinfo resultsSlice []map[string][]byte 129 | //default PrimaryKey id 130 | c, _ := orm. 131 | SetTable("userinfo"). 132 | SetPK("uid"). 133 | Where("username like ?", "%per%"). 134 | Select("uid,username"). 135 | FindMap() 136 | fmt.Println(c) 137 | } 138 | 139 | func groupby() { 140 | //Original SQL Group By 141 | b, _ := orm.SetTable("userinfo").GroupBy("username").Having("username='updateastaxie'").FindMap() 142 | fmt.Println(b) 143 | } 144 | 145 | func jointable() { 146 | //Original SQL Join Table 147 | a, _ := orm.SetTable("userinfo").Join("LEFT", "userdeatail", "userinfo.uid=userdeatail.uid").Where("userinfo.uid=?", 1).Select("userinfo.uid,userinfo.username,userdeatail.profile").FindMap() 148 | fmt.Println(a) 149 | } 150 | 151 | func delete() { 152 | // // //delete one data 153 | saveone := selectone() 154 | orm.Delete(&saveone) 155 | } 156 | 157 | func deletesql() { 158 | //original SQL delete 159 | orm.SetTable("userinfo").Where("uid>?", 3).DeleteRow() 160 | } 161 | 162 | func deleteall() { 163 | // //delete all data 164 | alluser := selectall() 165 | orm.DeleteAll(&alluser) 166 | } 167 | -------------------------------------------------------------------------------- /example/pg.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/astaxie/beedb" 6 | _ "github.com/bmizerany/pq" 7 | //"time" 8 | "database/sql" 9 | ) 10 | 11 | /* 12 | CREATE TABLE userinfo 13 | ( 14 | uid serial NOT NULL, 15 | username character varying(100) NOT NULL, 16 | departname character varying(500) NOT NULL, 17 | Created date, 18 | CONSTRAINT userinfo_pkey PRIMARY KEY (uid) 19 | ) 20 | WITH (OIDS=FALSE); 21 | 22 | CREATE TABLE userdeatail 23 | ( 24 | uid integer, 25 | intro character varying(100), 26 | profile character varying(100) 27 | ) 28 | WITH(OIDS=FALSE); 29 | */ 30 | 31 | var orm beedb.Model 32 | 33 | type Userinfo struct { 34 | Uid int `beedb:"PK"` 35 | Username string 36 | Departname string 37 | Created string 38 | } 39 | 40 | func main() { 41 | db, err := sql.Open("postgres", "user=asta password=123456 dbname=test sslmode=disable") 42 | if err != nil { 43 | panic(err) 44 | } 45 | orm = beedb.New(db, "pg") 46 | insert() 47 | //insertsql() 48 | // a := selectone() 49 | // fmt.Println(a) 50 | // b := selectall() 51 | // fmt.Println(b) 52 | //update() 53 | //updatesql() 54 | //findmap() 55 | //groupby() 56 | //jointable() 57 | //delete() 58 | //deleteall() 59 | //deletesql() 60 | } 61 | 62 | func insert() { 63 | //save data 64 | var saveone Userinfo 65 | saveone.Username = "Test_Add_User" 66 | saveone.Departname = "Test_Add_Departname" 67 | saveone.Created = "2011-12-12" 68 | err := orm.Save(&saveone) 69 | if err != nil { 70 | fmt.Println(err) 71 | } 72 | fmt.Println(saveone) 73 | } 74 | 75 | func insertsql() { 76 | // add one 77 | add := make(map[string]interface{}) 78 | add["username"] = "astaxie" 79 | add["departname"] = "cloud develop" 80 | add["created"] = "2012-12-02" 81 | orm.SetTable("userinfo").Insert(add) 82 | } 83 | 84 | func selectone() Userinfo { 85 | //get one info 86 | var one Userinfo 87 | orm.Where("uid=$1", 1).Find(&one) 88 | return one 89 | } 90 | 91 | func selectall() []Userinfo { 92 | //get all data 93 | var alluser []Userinfo 94 | orm.Limit(10).Where("uid>$1", 1).FindAll(&alluser) 95 | return alluser 96 | } 97 | func update() { 98 | // //update data 99 | var saveone Userinfo 100 | saveone.Uid = 1 101 | saveone.Username = "Update Username" 102 | saveone.Departname = "Update Departname" 103 | saveone.Created = "2012-12-02" 104 | orm.Save(&saveone) 105 | fmt.Println(saveone) 106 | } 107 | 108 | func updatesql() { 109 | //original SQL update 110 | t := make(map[string]interface{}) 111 | t["username"] = "updateastaxie" 112 | //update one 113 | orm.SetTable("userinfo").SetPK("uid").Where(2).Update(t) 114 | //update batch 115 | orm.SetTable("userinfo").Where("uid>$1", 2).Update(t) 116 | } 117 | 118 | func findmap() { 119 | //Original SQL Backinfo resultsSlice []map[string][]byte 120 | //default PrimaryKey id 121 | c, _ := orm.SetTable("userinfo").SetPK("uid").Where(2).Select("uid,username").FindMap() 122 | fmt.Println(c) 123 | } 124 | 125 | func groupby() { 126 | //Original SQL Group By 127 | b, _ := orm.SetTable("userinfo").GroupBy("username").Having("username='updateastaxie'").Select("username").FindMap() 128 | fmt.Println(b) 129 | } 130 | 131 | func jointable() { 132 | //Original SQL Join Table 133 | a, _ := orm.SetTable("userinfo").Join("LEFT", "userdeatail", "userinfo.uid=userdeatail.uid").Where("userinfo.uid=$1", 1).Select("userinfo.uid,userinfo.username,userdeatail.profile").FindMap() 134 | fmt.Println(a) 135 | } 136 | 137 | func delete() { 138 | // // //delete one data 139 | saveone := selectone() 140 | orm.Delete(&saveone) 141 | } 142 | 143 | func deletesql() { 144 | //original SQL delete 145 | orm.SetTable("userinfo").Where("uid>$1", 3).DeleteRow() 146 | } 147 | 148 | func deleteall() { 149 | // //delete all data 150 | alluser := selectall() 151 | orm.DeleteAll(&alluser) 152 | } 153 | -------------------------------------------------------------------------------- /example/sqlite.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/astaxie/beedb" 6 | _ "github.com/mattn/go-sqlite3" 7 | "time" 8 | "database/sql" 9 | ) 10 | 11 | /* 12 | CREATE TABLE `userinfo` ( 13 | `uid` INTEGER PRIMARY KEY AUTOINCREMENT, 14 | `username` VARCHAR(64) NULL, 15 | `departname` VARCHAR(64) NULL, 16 | `created` DATE NULL 17 | ); 18 | CREATE TABLE `userdeatail` ( 19 | `uid` INT(10) NULL, 20 | `intro` TEXT NULL, 21 | `profile` TEXT NULL, 22 | PRIMARY KEY (`uid`) 23 | ); 24 | */ 25 | 26 | var orm beedb.Model 27 | 28 | type Userinfo struct { 29 | Uid int `beedb:"PK"` 30 | Username string 31 | Departname string 32 | Created string 33 | } 34 | 35 | func main() { 36 | db, err := sql.Open("sqlite3", "./asta.db") 37 | if err != nil { 38 | panic(err) 39 | } 40 | orm = beedb.New(db) 41 | //insert() 42 | //insertsql() 43 | // a := selectone() 44 | // fmt.Println(a) 45 | 46 | // b := selectall() 47 | // fmt.Println(b) 48 | 49 | // update() 50 | 51 | // updatesql() 52 | 53 | // findmap() 54 | 55 | // groupby() 56 | 57 | // jointable() 58 | 59 | // delete() 60 | 61 | //deletesql() 62 | 63 | //deleteall() 64 | } 65 | 66 | func insert() { 67 | //save data 68 | var saveone Userinfo 69 | saveone.Username = "Test Add User" 70 | saveone.Departname = "Test Add Departname" 71 | saveone.Created = time.Now().Format("2006-01-02 15:04:05") 72 | orm.Save(&saveone) 73 | fmt.Println(saveone) 74 | } 75 | 76 | func insertsql() { 77 | // add one 78 | add := make(map[string]interface{}) 79 | add["username"] = "astaxie" 80 | add["departname"] = "cloud develop" 81 | add["created"] = "2012-12-02" 82 | orm.SetTable("userinfo").Insert(add) 83 | } 84 | 85 | func selectone() Userinfo { 86 | //get one info 87 | var one Userinfo 88 | orm.Where("uid=?", 1).Find(&one) 89 | return one 90 | } 91 | 92 | func selectall() []Userinfo { 93 | //get all data 94 | var alluser []Userinfo 95 | orm.Limit(10).Where("uid>?", 1).FindAll(&alluser) 96 | return alluser 97 | } 98 | 99 | func update() { 100 | // //update data 101 | var saveone Userinfo 102 | saveone.Uid = 1 103 | saveone.Username = "Update Username" 104 | saveone.Departname = "Update Departname" 105 | saveone.Created = time.Now().Format("2006-01-02 15:04:05") 106 | orm.Save(&saveone) 107 | fmt.Println(saveone) 108 | } 109 | 110 | func updatesql() { 111 | //original SQL update 112 | t := make(map[string]interface{}) 113 | t["username"] = "updateastaxie" 114 | //update one 115 | orm.SetTable("userinfo").SetPK("uid").Where(2).Update(t) 116 | //update batch 117 | orm.SetTable("userinfo").Where("uid>?", 3).Update(t) 118 | } 119 | 120 | func findmap() { 121 | //Original SQL Backinfo resultsSlice []map[string][]byte 122 | //default PrimaryKey id 123 | c, _ := orm.SetTable("userinfo").SetPK("uid").Where(2).Select("uid,username").FindMap() 124 | fmt.Println(c) 125 | } 126 | 127 | func groupby() { 128 | //Original SQL Group By 129 | b, _ := orm.SetTable("userinfo").GroupBy("username").Having("username='updateastaxie'").FindMap() 130 | fmt.Println(b) 131 | } 132 | 133 | func jointable() { 134 | //Original SQL Join Table 135 | a, _ := orm.SetTable("userinfo").Join("LEFT", "userdeatail", "userinfo.uid=userdeatail.uid").Where("userinfo.uid=?", 1).Select("userinfo.uid,userinfo.username,userdeatail.profile").FindMap() 136 | fmt.Println(a) 137 | } 138 | 139 | func delete() { 140 | // // //delete one data 141 | saveone := selectone() 142 | orm.Delete(&saveone) 143 | } 144 | 145 | func deletesql() { 146 | //original SQL delete 147 | orm.SetTable("userinfo").Where("uid>?", 2).DeleteRow() 148 | } 149 | 150 | func deleteall() { 151 | // //delete all data 152 | alluser := selectall() 153 | orm.DeleteAll(&alluser) 154 | } 155 | -------------------------------------------------------------------------------- /util.go: -------------------------------------------------------------------------------- 1 | package beedb 2 | 3 | import ( 4 | "errors" 5 | "reflect" 6 | "strconv" 7 | "strings" 8 | "time" 9 | ) 10 | 11 | func getTypeName(obj interface{}) (typestr string) { 12 | typ := reflect.TypeOf(obj) 13 | typestr = typ.String() 14 | 15 | lastDotIndex := strings.LastIndex(typestr, ".") 16 | if lastDotIndex != -1 { 17 | typestr = typestr[lastDotIndex+1:] 18 | } 19 | 20 | return 21 | } 22 | 23 | func snakeCasedName(name string) string { 24 | newstr := make([]rune, 0) 25 | firstTime := true 26 | 27 | for _, chr := range name { 28 | if isUpper := 'A' <= chr && chr <= 'Z'; isUpper { 29 | if firstTime == true { 30 | firstTime = false 31 | } else { 32 | newstr = append(newstr, '_') 33 | } 34 | chr -= ('A' - 'a') 35 | } 36 | newstr = append(newstr, chr) 37 | } 38 | 39 | return string(newstr) 40 | } 41 | 42 | func titleCasedName(name string) string { 43 | newstr := make([]rune, 0) 44 | upNextChar := true 45 | 46 | for _, chr := range name { 47 | switch { 48 | case upNextChar: 49 | upNextChar = false 50 | chr -= ('a' - 'A') 51 | case chr == '_': 52 | upNextChar = true 53 | continue 54 | } 55 | 56 | newstr = append(newstr, chr) 57 | } 58 | 59 | return string(newstr) 60 | } 61 | 62 | func pluralizeString(str string) string { 63 | if strings.HasSuffix(str, "data") { 64 | return str 65 | } 66 | if strings.HasSuffix(str, "y") { 67 | str = str[:len(str)-1] + "ie" 68 | } 69 | return str + "s" 70 | } 71 | 72 | func scanMapIntoStruct(obj interface{}, objMap map[string][]byte) error { 73 | dataStruct := reflect.Indirect(reflect.ValueOf(obj)) 74 | if dataStruct.Kind() != reflect.Struct { 75 | return errors.New("expected a pointer to a struct") 76 | } 77 | 78 | dataStructType := dataStruct.Type() 79 | 80 | for i := 0; i < dataStructType.NumField(); i++ { 81 | field := dataStructType.Field(i) 82 | fieldv := dataStruct.Field(i) 83 | 84 | err := scanMapElement(fieldv, field, objMap) 85 | if err != nil { 86 | return err 87 | } 88 | } 89 | 90 | return nil 91 | } 92 | 93 | func scanMapElement(fieldv reflect.Value, field reflect.StructField, objMap map[string][]byte) error { 94 | 95 | objFieldName := field.Name 96 | bb := field.Tag 97 | sqlTag := bb.Get("sql") 98 | 99 | if bb.Get("beedb") == "-" || sqlTag == "-" || reflect.ValueOf(bb).String() == "-" { 100 | return nil 101 | } 102 | sqlTags := strings.Split(sqlTag, ",") 103 | sqlFieldName := objFieldName 104 | if len(sqlTags[0]) > 0 { 105 | sqlFieldName = sqlTags[0] 106 | } 107 | inline := false 108 | //omitempty := false //TODO! 109 | // CHECK INLINE 110 | if len(sqlTags) > 1 { 111 | if stringArrayContains("inline", sqlTags[1:]) { 112 | inline = true 113 | } 114 | } 115 | if inline { 116 | if field.Type.Kind() == reflect.Struct && field.Type.String() != "time.Time" { 117 | for i := 0; i < field.Type.NumField(); i++ { 118 | err := scanMapElement(fieldv.Field(i), field.Type.Field(i), objMap) 119 | if err != nil { 120 | return err 121 | } 122 | } 123 | } else { 124 | return errors.New("A non struct type can't be inline.") 125 | } 126 | } 127 | 128 | // not inline 129 | 130 | data, ok := objMap[sqlFieldName] 131 | 132 | if !ok { 133 | return nil 134 | } 135 | 136 | var v interface{} 137 | 138 | switch field.Type.Kind() { 139 | 140 | case reflect.Slice: 141 | v = data 142 | case reflect.String: 143 | v = string(data) 144 | case reflect.Bool: 145 | v = string(data) == "1" 146 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32: 147 | x, err := strconv.Atoi(string(data)) 148 | if err != nil { 149 | return errors.New("arg " + sqlFieldName + " as int: " + err.Error()) 150 | } 151 | v = x 152 | case reflect.Int64: 153 | x, err := strconv.ParseInt(string(data), 10, 64) 154 | if err != nil { 155 | return errors.New("arg " + sqlFieldName + " as int: " + err.Error()) 156 | } 157 | v = x 158 | case reflect.Float32, reflect.Float64: 159 | x, err := strconv.ParseFloat(string(data), 64) 160 | if err != nil { 161 | return errors.New("arg " + sqlFieldName + " as float64: " + err.Error()) 162 | } 163 | v = x 164 | case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 165 | x, err := strconv.ParseUint(string(data), 10, 64) 166 | if err != nil { 167 | return errors.New("arg " + sqlFieldName + " as int: " + err.Error()) 168 | } 169 | v = x 170 | //Supports Time type only (for now) 171 | case reflect.Struct: 172 | if fieldv.Type().String() != "time.Time" { 173 | return errors.New("unsupported struct type in Scan: " + fieldv.Type().String()) 174 | } 175 | 176 | x, err := time.Parse("2006-01-02 15:04:05", string(data)) 177 | if err != nil { 178 | x, err = time.Parse("2006-01-02 15:04:05.000 -0700", string(data)) 179 | 180 | if err != nil { 181 | return errors.New("unsupported time format: " + string(data)) 182 | } 183 | } 184 | 185 | v = x 186 | default: 187 | return errors.New("unsupported type in Scan: " + reflect.TypeOf(v).String()) 188 | } 189 | 190 | fieldv.Set(reflect.ValueOf(v)) 191 | 192 | return nil 193 | } 194 | 195 | func scanStructIntoMap(obj interface{}) (map[string]interface{}, error) { 196 | dataStruct := reflect.Indirect(reflect.ValueOf(obj)) 197 | if dataStruct.Kind() != reflect.Struct { 198 | return nil, errors.New("expected a pointer to a struct") 199 | } 200 | 201 | dataStructType := dataStruct.Type() 202 | 203 | mapped := make(map[string]interface{}) 204 | 205 | for i := 0; i < dataStructType.NumField(); i++ { 206 | field := dataStructType.Field(i) 207 | fieldv := dataStruct.Field(i) 208 | fieldName := field.Name 209 | bb := field.Tag 210 | sqlTag := bb.Get("sql") 211 | sqlTags := strings.Split(sqlTag, ",") 212 | var mapKey string 213 | 214 | inline := false 215 | 216 | if bb.Get("beedb") == "-" || sqlTag == "-" || reflect.ValueOf(bb).String() == "-" { 217 | continue 218 | } else if len(sqlTag) > 0 { 219 | //TODO: support tags that are common in json like omitempty 220 | if sqlTags[0] == "-" { 221 | continue 222 | } 223 | mapKey = sqlTags[0] 224 | } else { 225 | mapKey = fieldName 226 | } 227 | 228 | if len(sqlTags) > 1 { 229 | if stringArrayContains("inline", sqlTags[1:]) { 230 | inline = true 231 | } 232 | } 233 | 234 | if inline { 235 | // get an inner map and then put it inside the outer map 236 | map2, err2 := scanStructIntoMap(fieldv.Interface()) 237 | if err2 != nil { 238 | return mapped, err2 239 | } 240 | for k, v := range map2 { 241 | mapped[k] = v 242 | } 243 | } else { 244 | value := dataStruct.FieldByName(fieldName).Interface() 245 | mapped[mapKey] = value 246 | } 247 | } 248 | 249 | return mapped, nil 250 | } 251 | 252 | func StructName(s interface{}) string { 253 | v := reflect.TypeOf(s) 254 | for v.Kind() == reflect.Ptr { 255 | v = v.Elem() 256 | } 257 | return v.Name() 258 | } 259 | 260 | func getTableName(s interface{}) string { 261 | v := reflect.TypeOf(s) 262 | if v.Kind() == reflect.String { 263 | s2, _ := s.(string) 264 | return snakeCasedName(s2) 265 | } 266 | tn := scanTableName(s) 267 | if len(tn) > 0 { 268 | return tn 269 | } 270 | return getTableName(StructName(s)) 271 | } 272 | 273 | func scanTableName(s interface{}) string { 274 | if reflect.TypeOf(reflect.Indirect(reflect.ValueOf(s)).Interface()).Kind() == reflect.Slice { 275 | sliceValue := reflect.Indirect(reflect.ValueOf(s)) 276 | sliceElementType := sliceValue.Type().Elem() 277 | for i := 0; i < sliceElementType.NumField(); i++ { 278 | bb := sliceElementType.Field(i).Tag 279 | if len(bb.Get("tname")) > 0 { 280 | return bb.Get("tname") 281 | } 282 | } 283 | } else { 284 | tt := reflect.TypeOf(reflect.Indirect(reflect.ValueOf(s)).Interface()) 285 | for i := 0; i < tt.NumField(); i++ { 286 | bb := tt.Field(i).Tag 287 | if len(bb.Get("tname")) > 0 { 288 | return bb.Get("tname") 289 | } 290 | } 291 | } 292 | return "" 293 | 294 | } 295 | 296 | func stringArrayContains(needle string, haystack []string) bool { 297 | for _, v := range haystack { 298 | if needle == v { 299 | return true 300 | } 301 | } 302 | return false 303 | } 304 | -------------------------------------------------------------------------------- /util_test.go: -------------------------------------------------------------------------------- 1 | package beedb 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | ) 7 | 8 | type User struct { 9 | SQLModel `sql:",inline"` 10 | Name string `sql:"name" tname:"fn_group"` 11 | Auth int `sql:"auth"` 12 | } 13 | 14 | type SQLModel struct { 15 | Id int `beedb:"PK" sql:"id"` 16 | Created time.Time `sql:"created"` 17 | Modified time.Time `sql:"modified"` 18 | } 19 | 20 | func TestMapToStruct(t *testing.T) { 21 | target := &User{} 22 | input := map[string][]byte{ 23 | "name": []byte("Test User"), 24 | "auth": []byte("1"), 25 | "id": []byte("1"), 26 | "created": []byte("2014-01-01 10:10:10"), 27 | "modified": []byte("2014-01-01 10:10:10"), 28 | } 29 | err := scanMapIntoStruct(target, input) 30 | if err != nil { 31 | t.Errorf(err.Error()) 32 | } 33 | 34 | _, err = scanStructIntoMap(target) 35 | 36 | if err != nil { 37 | t.Errorf(err.Error()) 38 | } 39 | } 40 | --------------------------------------------------------------------------------