// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. // // This Source Code Form is subject to the terms of the MIT License. // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. package gdb import ( "context" "database/sql" "fmt" "github.com/gogf/gf/v2/container/gvar" "github.com/gogf/gf/v2/encoding/gjson" "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/internal/intlog" "github.com/gogf/gf/v2/os/gcache" "github.com/gogf/gf/v2/text/gstr" "github.com/gogf/gf/v2/util/gutil" ) // DriverWrapperDB is a DB wrapper for extending features with embedded DB. type DriverWrapperDB struct { DB } // Open creates and returns an underlying sql.DB object for pgsql. // https://pkg.go.dev/github.com/lib/pq func (d *DriverWrapperDB) Open(node *ConfigNode) (db *sql.DB, err error) { var ctx = d.GetCtx() intlog.PrintFunc(ctx, func() string { return fmt.Sprintf(`open new connection:%s`, gjson.MustEncode(node)) }) return d.DB.Open(node) } // Tables retrieves and returns the tables of current schema. // It's mainly used in cli tool chain for automatically generating the models. func (d *DriverWrapperDB) Tables(ctx context.Context, schema ...string) (tables []string, err error) { ctx = context.WithValue(ctx, ctxKeyInternalProducedSQL, struct{}{}) return d.DB.Tables(ctx, schema...) } // TableFields retrieves and returns the fields' information of specified table of current // schema. // // The parameter `link` is optional, if given nil it automatically retrieves a raw sql connection // as its link to proceed necessary sql query. // // Note that it returns a map containing the field name and its corresponding fields. // As a map is unsorted, the TableField struct has an "Index" field marks its sequence in // the fields. // // It's using cache feature to enhance the performance, which is never expired util the // process restarts. func (d *DriverWrapperDB) TableFields( ctx context.Context, table string, schema ...string, ) (fields map[string]*TableField, err error) { if table == "" { return nil, nil } charL, charR := d.GetChars() table = gstr.Trim(table, charL+charR) if gstr.Contains(table, " ") { return nil, gerror.NewCode( gcode.CodeInvalidParameter, "function TableFields supports only single table operations", ) } var ( innerMemCache = d.GetCore().GetInnerMemCache() // prefix:group@schema#table cacheKey = genTableFieldsCacheKey( d.GetGroup(), gutil.GetOrDefaultStr(d.GetSchema(), schema...), table, ) cacheFunc = func(ctx context.Context) (interface{}, error) { return d.DB.TableFields( context.WithValue(ctx, ctxKeyInternalProducedSQL, struct{}{}), table, schema..., ) } value *gvar.Var ) value, err = innerMemCache.GetOrSetFuncLock( ctx, cacheKey, cacheFunc, gcache.DurationNoExpire, ) if err != nil { return } if !value.IsNil() { fields = value.Val().(map[string]*TableField) } return } // DoInsert inserts or updates data for given table. // This function is usually used for custom interface definition, you do not need call it manually. // The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc. // Eg: // Data(g.Map{"uid": 10000, "name":"john"}) // Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"}) // // The parameter `option` values are as follows: // InsertOptionDefault: just insert, if there's unique/primary key in the data, it returns error; // InsertOptionReplace: if there's unique/primary key in the data, it deletes it from table and inserts a new one; // InsertOptionSave: if there's unique/primary key in the data, it updates it or else inserts a new one; // InsertOptionIgnore: if there's unique/primary key in the data, it ignores the inserting; func (d *DriverWrapperDB) DoInsert(ctx context.Context, link Link, table string, list List, option DoInsertOption) (result sql.Result, err error) { // Convert data type before commit it to underlying db driver. for i, item := range list { list[i], err = d.GetCore().ConvertDataForRecord(ctx, item, table) if err != nil { return nil, err } } return d.DB.DoInsert(ctx, link, table, list, option) }