github.com/gogf/gf/v2@v2.7.4/database/gdb/gdb_driver_wrapper_db.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/gogf/gf. 6 7 package gdb 8 9 import ( 10 "context" 11 "database/sql" 12 "fmt" 13 14 "github.com/gogf/gf/v2/container/gvar" 15 "github.com/gogf/gf/v2/encoding/gjson" 16 "github.com/gogf/gf/v2/errors/gcode" 17 "github.com/gogf/gf/v2/errors/gerror" 18 "github.com/gogf/gf/v2/internal/intlog" 19 "github.com/gogf/gf/v2/os/gcache" 20 "github.com/gogf/gf/v2/text/gstr" 21 "github.com/gogf/gf/v2/util/gutil" 22 ) 23 24 // DriverWrapperDB is a DB wrapper for extending features with embedded DB. 25 type DriverWrapperDB struct { 26 DB 27 } 28 29 // Open creates and returns an underlying sql.DB object for pgsql. 30 // https://pkg.go.dev/github.com/lib/pq 31 func (d *DriverWrapperDB) Open(node *ConfigNode) (db *sql.DB, err error) { 32 var ctx = d.GetCtx() 33 intlog.PrintFunc(ctx, func() string { 34 return fmt.Sprintf(`open new connection:%s`, gjson.MustEncode(node)) 35 }) 36 return d.DB.Open(node) 37 } 38 39 // Tables retrieves and returns the tables of current schema. 40 // It's mainly used in cli tool chain for automatically generating the models. 41 func (d *DriverWrapperDB) Tables(ctx context.Context, schema ...string) (tables []string, err error) { 42 ctx = context.WithValue(ctx, ctxKeyInternalProducedSQL, struct{}{}) 43 return d.DB.Tables(ctx, schema...) 44 } 45 46 // TableFields retrieves and returns the fields' information of specified table of current 47 // schema. 48 // 49 // The parameter `link` is optional, if given nil it automatically retrieves a raw sql connection 50 // as its link to proceed necessary sql query. 51 // 52 // Note that it returns a map containing the field name and its corresponding fields. 53 // As a map is unsorted, the TableField struct has an "Index" field marks its sequence in 54 // the fields. 55 // 56 // It's using cache feature to enhance the performance, which is never expired util the 57 // process restarts. 58 func (d *DriverWrapperDB) TableFields( 59 ctx context.Context, table string, schema ...string, 60 ) (fields map[string]*TableField, err error) { 61 if table == "" { 62 return nil, nil 63 } 64 charL, charR := d.GetChars() 65 table = gstr.Trim(table, charL+charR) 66 if gstr.Contains(table, " ") { 67 return nil, gerror.NewCode( 68 gcode.CodeInvalidParameter, 69 "function TableFields supports only single table operations", 70 ) 71 } 72 var ( 73 innerMemCache = d.GetCore().GetInnerMemCache() 74 // prefix:group@schema#table 75 cacheKey = genTableFieldsCacheKey( 76 d.GetGroup(), 77 gutil.GetOrDefaultStr(d.GetSchema(), schema...), 78 table, 79 ) 80 cacheFunc = func(ctx context.Context) (interface{}, error) { 81 return d.DB.TableFields( 82 context.WithValue(ctx, ctxKeyInternalProducedSQL, struct{}{}), 83 table, schema..., 84 ) 85 } 86 value *gvar.Var 87 ) 88 value, err = innerMemCache.GetOrSetFuncLock( 89 ctx, cacheKey, cacheFunc, gcache.DurationNoExpire, 90 ) 91 if err != nil { 92 return 93 } 94 if !value.IsNil() { 95 fields = value.Val().(map[string]*TableField) 96 } 97 return 98 } 99 100 // DoInsert inserts or updates data for given table. 101 // This function is usually used for custom interface definition, you do not need call it manually. 102 // The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc. 103 // Eg: 104 // Data(g.Map{"uid": 10000, "name":"john"}) 105 // Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"}) 106 // 107 // The parameter `option` values are as follows: 108 // InsertOptionDefault: just insert, if there's unique/primary key in the data, it returns error; 109 // InsertOptionReplace: if there's unique/primary key in the data, it deletes it from table and inserts a new one; 110 // InsertOptionSave: if there's unique/primary key in the data, it updates it or else inserts a new one; 111 // InsertOptionIgnore: if there's unique/primary key in the data, it ignores the inserting; 112 func (d *DriverWrapperDB) DoInsert(ctx context.Context, link Link, table string, list List, option DoInsertOption) (result sql.Result, err error) { 113 // Convert data type before commit it to underlying db driver. 114 for i, item := range list { 115 list[i], err = d.GetCore().ConvertDataForRecord(ctx, item, table) 116 if err != nil { 117 return nil, err 118 } 119 } 120 return d.DB.DoInsert(ctx, link, table, list, option) 121 }