diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..081b737 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 数据源本地存储已忽略文件 +/dataSources/ +/dataSources.local.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..fc80dce --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/stardb.iml b/.idea/stardb.iml new file mode 100644 index 0000000..5e764c4 --- /dev/null +++ b/.idea/stardb.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/orm_v1.go b/orm_v1.go new file mode 100644 index 0000000..ea09c06 --- /dev/null +++ b/orm_v1.go @@ -0,0 +1,93 @@ +package stardb + +import ( + "database/sql" + "errors" + "reflect" + "strings" +) + +func (star *StarRows) Orm(ins interface{}) error { + //check if is slice + if !star.parsed { + if err := star.parserows(); err != nil { + return err + } + } + t := reflect.TypeOf(ins) + v := reflect.ValueOf(ins) + if t.Kind() != reflect.Ptr { + return errors.New("interface not writable") + } + //now convert to slice + t = t.Elem() + v = v.Elem() + if star.Length == 0 { + return nil + } + if v.Kind() == reflect.Slice || v.Kind() == reflect.Array { + //get type of slice + sigType := t.Elem() + var result reflect.Value + result = reflect.New(t).Elem() + for i := 0; i < star.Length; i++ { + val := reflect.New(sigType) + star.setAllRefValue(val.Interface(), "db", i) + result = reflect.Append(result, val.Elem()) + } + v.Set(result) + return nil + } + + return star.setAllRefValue(ins, "db", 0) +} + +func (star *StarDB) QueryX(sql string, ins interface{}, args ...interface{}) (*StarRows, error) { + kvMap, err := getAllRefValue(ins, "db") + if err != nil { + return nil, err + } + for k, v := range args { + switch v.(type) { + case string: + str := v.(string) + if strings.Index(str, ":") == 0 { + if _, ok := kvMap[str[1:]]; ok { + args[k] = kvMap[str[1:]] + } else { + args[k] = "" + } + continue + } + if strings.Index(str, `\:`) == 0 { + args[k] = kvMap[str[1:]] + } + } + } + return star.Query(sql, args) +} + +func (star *StarDB) ExecX(sql string, ins interface{}, args ...interface{}) (sql.Result, error) { + kvMap, err := getAllRefValue(ins, "db") + if err != nil { + return nil, err + } + for k, v := range args { + switch v.(type) { + case string: + str := v.(string) + if strings.Index(str, ":") == 0 { + if _, ok := kvMap[str[1:]]; ok { + args[k] = kvMap[str[1:]] + } else { + args[k] = "" + } + continue + } + if strings.Index(str, `\:`) == 0 { + args[k] = kvMap[str[1:]] + } + } + } + return star.Exec(sql, args) +} diff --git a/reflect.go b/reflect.go new file mode 100644 index 0000000..021abbd --- /dev/null +++ b/reflect.go @@ -0,0 +1,162 @@ +package stardb + +import ( + "errors" + "reflect" +) + +func (star *StarRows) setAllRefValue(stc interface{}, skey string, rows int) error { + t := reflect.TypeOf(stc) + v := reflect.ValueOf(stc).Elem() + if t.Kind() != reflect.Ptr || !v.CanSet() { + return errors.New("interface{} is not writable") + } + if v.Kind() != reflect.Struct { + return errors.New("interface{} is not a struct") + } + t = t.Elem() + for i := 0; i < t.NumField(); i++ { + tp := t.Field(i) + seg := tp.Tag.Get(skey) + if seg == "" { + continue + } + if _, ok := star.Row(rows).columnref[seg]; !ok { + continue + } + myInt64 := star.Row(rows).MustInt64(seg) + myUint64 := uint64(star.Row(rows).MustInt64(seg)) + switch v.Field(i).Kind() { + case reflect.String: + v.Field(i).SetString(star.Row(rows).MustString(seg)) + case reflect.Int64: + v.Field(i).SetInt(myInt64) + case reflect.Int32: + v.Field(i).SetInt(int64(star.Row(rows).MustInt32(seg))) + case reflect.Int16: + v.Field(i).SetInt(int64(int16(myInt64))) + case reflect.Int8: + v.Field(i).SetInt(int64(int8(myInt64))) + case reflect.Uint64: + v.Field(i).SetUint(myUint64) + case reflect.Uint32: + v.Field(i).SetUint(uint64(uint32(myUint64))) + case reflect.Uint16: + v.Field(i).SetUint(uint64(uint16(myUint64))) + case reflect.Uint8: + v.Field(i).SetUint(uint64(uint8(myUint64))) + case reflect.Bool: + v.Field(i).SetBool(star.Row(rows).MustBool(seg)) + case reflect.Float64: + v.Field(i).SetFloat(star.Row(rows).MustFloat64(seg)) + case reflect.Float32: + v.Field(i).SetFloat(float64(star.Row(rows).MustFloat32(seg))) + default: + } + + } + return nil +} + +func setAllRefValue(stc interface{}, skey string, kv map[string]interface{}) error { + t := reflect.TypeOf(stc) + v := reflect.ValueOf(stc).Elem() + if t.Kind() != reflect.Ptr || !v.CanSet() { + return errors.New("interface{} is not writable") + } + if v.Kind() != reflect.Struct { + return errors.New("interface{} is not a struct") + } + t = t.Elem() + for i := 0; i < t.NumField(); i++ { + tp := t.Field(i) + seg := tp.Tag.Get(skey) + if seg == "" { + continue + } + if _, ok := kv[seg]; !ok { + continue + } + v.Field(i).Set(reflect.ValueOf(kv[seg])) + } + return nil +} + +func setRefValue(stc interface{}, skey, key string, value interface{}) error { + t := reflect.TypeOf(stc) + v := reflect.ValueOf(stc).Elem() + if t.Kind() != reflect.Ptr || !v.CanSet() { + return errors.New("interface{} is not writable") + } + if v.Kind() != reflect.Struct { + return errors.New("interface{} is not a struct") + } + t = t.Elem() + for i := 0; i < t.NumField(); i++ { + tp := t.Field(i) + seg := tp.Tag.Get(skey) + if seg == "" || key != seg { + continue + } + v.Field(i).Set(reflect.ValueOf(value)) + } + return nil +} + +func getAllRefValue(stc interface{}, skey string) (map[string]interface{}, error) { + result := make(map[string]interface{}) + t := reflect.TypeOf(stc) + v := reflect.ValueOf(stc) + if v.Kind() != reflect.Struct { + return nil, errors.New("interface{} is not a struct") + } + if t.Kind() == reflect.Ptr { + t = t.Elem() + v = v.Elem() + } + for i := 0; i < t.NumField(); i++ { + tp := t.Field(i) + seg := tp.Tag.Get(skey) + if seg == "" { + continue + } + value := v.Field(i) + if !value.CanInterface() { + continue + } + result[seg] = value.Interface() + } + return result, nil +} + +func getAllRefKey(stc interface{}, skey string) ([]string, error) { + var result []string + _, isStruct := isWritableStruct(stc) + if !isStruct { + return []string{}, errors.New("interface{} is not a struct") + } + t := reflect.TypeOf(stc) + if t.Kind() == reflect.Ptr { + t = t.Elem() + } + for i := 0; i < t.NumField(); i++ { + profile := t.Field(i) + seg := profile.Tag.Get(skey) + if seg != "" { + result = append(result, seg) + } + } + return result, nil +} + +func isWritableStruct(stc interface{}) (isWritable bool, isStruct bool) { + t := reflect.TypeOf(stc) + v := reflect.ValueOf(stc) + if t.Kind() == reflect.Ptr && v.Elem().CanSet() { + isWritable = true + } + if v.Kind() == reflect.Struct { + isStruct = true + } + return +} diff --git a/reflect_test.go b/reflect_test.go new file mode 100644 index 0000000..9445aad --- /dev/null +++ b/reflect_test.go @@ -0,0 +1,44 @@ +package stardb + +import ( + "fmt" + "reflect" + "testing" +) + +type Useless struct { + Leader string `db:"leader"` + Usable bool `db:"use"` +} + +func Test_SetRefVal(t *testing.T) { + var hehe = Useless{ + Leader: "no", + } + mmval := map[string]interface{}{ + "leader": "hehe", + "use": true, + } + fmt.Printf("%+v\n", hehe) + fmt.Println(setRefValue(&hehe, "db", "leader", "sb")) + fmt.Printf("%+v\n", hehe) + fmt.Println(setAllRefValue(&hehe, "db", mmval)) + fmt.Printf("%+v\n", hehe) + fmt.Println(getAllRefKey(hehe, "db")) +} + +func Test_Ref(t *testing.T) { + var me []Useless + p := reflect.TypeOf(&me).Elem() + v := reflect.ValueOf(&me).Elem() + mmval := map[string]interface{}{ + "leader": "hehe", + "use": true, + } + newVal := reflect.New(p) + val := reflect.New(p.Elem()) + setAllRefValue(val.Interface(), "db", mmval) + mynum:= reflect.Append(newVal.Elem(), val.Elem()) + v.Set(mynum) + fmt.Println(val.Interface(), me, v) +} diff --git a/stardb_v1.go b/stardb_v1.go index 842f452..4db6e5f 100644 --- a/stardb_v1.go +++ b/stardb_v1.go @@ -10,8 +10,8 @@ import ( // StarDB 一个简单封装的DB库 type StarDB struct { - DB *sql.DB - Rows *sql.Rows + DB *sql.DB + ManualScan bool } // StarRows 为查询结果集(按行) @@ -23,6 +23,7 @@ type StarRows struct { ColumnsType []reflect.Type columnref map[string]int result [][]interface{} + parsed bool } // StarResult 为查询结果集(总) @@ -674,7 +675,10 @@ func (star *StarRows) Close() error { return star.Rows.Close() } -func (star *StarRows) parserows() { +func (star *StarRows) parserows() error { + defer func() { + star.parsed = true + }() star.result = [][]interface{}{} star.columnref = make(map[string]int) star.StringResult = []map[string]string{} @@ -691,7 +695,7 @@ func (star *StarRows) parserows() { } for star.Rows.Next() { if err := star.Rows.Scan(scanArgs...); err != nil { - return + return err } record := make(map[string]string) var rescopy []interface{} @@ -724,11 +728,13 @@ func (star *StarRows) parserows() { star.StringResult = append(star.StringResult, record) } star.Length = len(star.StringResult) + return nil } // Query 进行Query操作 func (star *StarDB) Query(args ...interface{}) (*StarRows, error) { var err error + var rows *sql.Rows effect := new(StarRows) if err = star.DB.Ping(); err != nil { return effect, err @@ -738,10 +744,10 @@ func (star *StarDB) Query(args ...interface{}) (*StarRows, error) { } if len(args) == 1 { sql := args[0] - if star.Rows, err = star.DB.Query(sql.(string)); err != nil { + if rows, err = star.DB.Query(sql.(string)); err != nil { return effect, err } - effect.Rows = star.Rows + effect.Rows = rows effect.parserows() return effect, nil } @@ -760,12 +766,14 @@ func (star *StarDB) Query(args ...interface{}) (*StarRows, error) { } } } - if star.Rows, err = stmt.Query(para...); err != nil { + if rows, err = stmt.Query(para...); err != nil { return effect, err } - effect.Rows = star.Rows - effect.parserows() - return effect, nil + effect.Rows = rows + if !star.ManualScan { + err = effect.parserows() + } + return effect, err } // Open 打开一个新的数据库