From 0b6a0b06a6a681bbb17bfd985a8d2f70f916dcb4 Mon Sep 17 00:00:00 2001 From: Edison-Hsu Date: Wed, 27 Jul 2016 19:26:01 +0800 Subject: [PATCH 1/6] expose Session.Query2 and add Engine.QueryMapString by using Session.Query2 - add Query a raw sql and return records as []map[string]string --- engine.go | 7 +++++++ session.go | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/engine.go b/engine.go index 6caa45a0..1f83ec94 100644 --- a/engine.go +++ b/engine.go @@ -1479,6 +1479,13 @@ func (engine *Engine) Query(sql string, paramStr ...interface{}) (resultsSlice [ return session.Query(sql, paramStr...) } +// Query a raw sql and return records as []map[string]string +func (engine *Engine) QueryMapString(sql string, paramStr ...interface{}) (resultsSlice []map[string]string, err error) { + session := engine.NewSession() + defer session.Close() + return session.Query2(sql, paramStr...) +} + // Insert one or more records func (engine *Engine) Insert(beans ...interface{}) (int64, error) { session := engine.NewSession() diff --git a/session.go b/session.go index 35e7a306..a7dc9fb8 100644 --- a/session.go +++ b/session.go @@ -2182,7 +2182,7 @@ func (session *Session) Query(sqlStr string, paramStr ...interface{}) (resultsSl // ============================= // for string // ============================= -func (session *Session) query2(sqlStr string, paramStr ...interface{}) (resultsSlice []map[string]string, err error) { +func (session *Session) Query2(sqlStr string, paramStr ...interface{}) (resultsSlice []map[string]string, err error) { session.queryPreprocess(&sqlStr, paramStr...) if session.IsAutoCommit { From ae6235169ce747378bb3722e06642a8ba23e4b92 Mon Sep 17 00:00:00 2001 From: Edison-Hsu Date: Thu, 28 Jul 2016 12:34:00 +0800 Subject: [PATCH 2/6] add QueryMapInterface function in engine.go Query a raw sql and return records as []map[string]interface{} --- engine.go | 7 +++++++ helpers.go | 41 +++++++++++++++++++++++++++++++++++++++++ session.go | 41 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+) diff --git a/engine.go b/engine.go index 1f83ec94..2e389055 100644 --- a/engine.go +++ b/engine.go @@ -1486,6 +1486,13 @@ func (engine *Engine) QueryMapString(sql string, paramStr ...interface{}) (resul return session.Query2(sql, paramStr...) } +// Query a raw sql and return records as []map[string]interface{} +func (engine *Engine) QueryMapInterface(sql string, paramStr ...interface{}) (resultsSlice []map[string]interface{}, err error) { + session := engine.NewSession() + defer session.Close() + return session.QueryInterfaces(sql, paramStr...) +} + // Insert one or more records func (engine *Engine) Insert(beans ...interface{}) (int64, error) { session := engine.NewSession() diff --git a/helpers.go b/helpers.go index 9a461c0e..f04c35f6 100644 --- a/helpers.go +++ b/helpers.go @@ -377,6 +377,22 @@ func rows2maps(rows *core.Rows) (resultsSlice []map[string][]byte, err error) { return resultsSlice, nil } +func rows2interfaces(rows *core.Rows) (resultsSlice []map[string]interface{}, err error) { + fields, err := rows.Columns() + if err != nil { + return nil, err + } + for rows.Next() { + result, err := row2mapInterface(rows, fields) + if err != nil { + return nil, err + } + resultsSlice = append(resultsSlice, result) + } + + return resultsSlice, nil +} + func row2map(rows *core.Rows, fields []string) (resultsMap map[string][]byte, err error) { result := make(map[string][]byte) scanResultContainers := make([]interface{}, len(fields)) @@ -433,6 +449,31 @@ func row2mapStr(rows *core.Rows, fields []string) (resultsMap map[string]string, return result, nil } +func row2mapInterface(rows *core.Rows, fields []string) (resultsMap map[string]interface{}, err error) { + result := make(map[string]interface{}) + scanResultContainers := make([]interface{}, len(fields)) + + for i := 0; i < len(fields); i++ { + var scanResultContainer interface{} + scanResultContainers[i] = &scanResultContainer + } + if err := rows.Scan(scanResultContainers...); err != nil { + return nil, err + } + + for ii, key := range fields { + rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii])) + //if row is null then ignore + if rawValue.Interface() == nil { + //fmt.Println("ignore ...", key, rawValue) + continue + } + + result[key] = scanResultContainers[ii] + } + return result, nil +} + func txQuery2(tx *core.Tx, sqlStr string, params ...interface{}) (resultsSlice []map[string]string, err error) { rows, err := tx.Query(sqlStr, params...) if err != nil { diff --git a/session.go b/session.go index a7dc9fb8..b978ba87 100644 --- a/session.go +++ b/session.go @@ -2118,6 +2118,16 @@ func (session *Session) query(sqlStr string, paramStr ...interface{}) (resultsSl return session.txQuery(session.Tx, sqlStr, paramStr...) } +func (session *Session) queryInterfaces(sqlStr string, paramStr ...interface{}) (resultsSlice []map[string]interface{}, err error) { + + session.queryPreprocess(&sqlStr, paramStr...) + + if session.IsAutoCommit { + return session.innerQuery3(sqlStr, paramStr...) + } + return session.txQueryInterface(session.Tx, sqlStr, paramStr...) +} + func (session *Session) txQuery(tx *core.Tx, sqlStr string, params ...interface{}) (resultsSlice []map[string][]byte, err error) { rows, err := tx.Query(sqlStr, params...) if err != nil { @@ -2128,6 +2138,16 @@ func (session *Session) txQuery(tx *core.Tx, sqlStr string, params ...interface{ return rows2maps(rows) } +func (session *Session) txQueryInterface(tx *core.Tx, sqlStr string, params ...interface{}) (resultsSlice []map[string]interface{}, err error) { + rows, err := tx.Query(sqlStr, params...) + if err != nil { + return nil, err + } + defer rows.Close() + + return rows2interfaces(rows) +} + func (session *Session) innerQuery(sqlStr string, params ...interface{}) (*core.Stmt, *core.Rows, error) { var callback func() (*core.Stmt, *core.Rows, error) if session.prepareStmt { @@ -2169,6 +2189,17 @@ func (session *Session) innerQuery2(sqlStr string, params ...interface{}) ([]map return rows2maps(rows) } +func (session *Session) innerQuery3(sqlStr string, params ...interface{}) ([]map[string]interface{}, error) { + _, rows, err := session.innerQuery(sqlStr, params...) + if rows != nil { + defer rows.Close() + } + if err != nil { + return nil, err + } + return rows2interfaces(rows) +} + // Query a raw sql and return records as []map[string][]byte func (session *Session) Query(sqlStr string, paramStr ...interface{}) (resultsSlice []map[string][]byte, err error) { defer session.resetStatement() @@ -2179,6 +2210,16 @@ func (session *Session) Query(sqlStr string, paramStr ...interface{}) (resultsSl return session.query(sqlStr, paramStr...) } +// for interfaces +func (session *Session) QueryInterfaces(sqlStr string, paramStr ...interface{}) (resultsSlice []map[string]interface{}, err error) { + defer session.resetStatement() + if session.IsAutoClose { + defer session.Close() + } + + return session.queryInterfaces(sqlStr, paramStr...) +} + // ============================= // for string // ============================= From 4b8086c979313b699ee73775c91ca0363bd0ab03 Mon Sep 17 00:00:00 2001 From: Edison-Hsu Date: Thu, 28 Jul 2016 13:16:36 +0800 Subject: [PATCH 3/6] get rawValue.Interface() --- helpers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helpers.go b/helpers.go index f04c35f6..185cbb1d 100644 --- a/helpers.go +++ b/helpers.go @@ -469,7 +469,7 @@ func row2mapInterface(rows *core.Rows, fields []string) (resultsMap map[string]i continue } - result[key] = scanResultContainers[ii] + result[key] = rawValue.Interface() } return result, nil } From 5baba4c28b7da5e7a5f452a0079f9ede1cbab427 Mon Sep 17 00:00:00 2001 From: Edison-Hsu Date: Thu, 28 Jul 2016 14:19:38 +0800 Subject: [PATCH 4/6] fix rawValue.Interface to (*rawValue).Interface() --- helpers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helpers.go b/helpers.go index 185cbb1d..8984c177 100644 --- a/helpers.go +++ b/helpers.go @@ -469,7 +469,7 @@ func row2mapInterface(rows *core.Rows, fields []string) (resultsMap map[string]i continue } - result[key] = rawValue.Interface() + result[key] = (*rawValue).Interface() } return result, nil } From 55fa6f9176fafdb6555d99c569ba8e5068af9b63 Mon Sep 17 00:00:00 2001 From: Edison-Hsu Date: Thu, 28 Jul 2016 14:26:22 +0800 Subject: [PATCH 5/6] revert --- helpers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helpers.go b/helpers.go index 8984c177..185cbb1d 100644 --- a/helpers.go +++ b/helpers.go @@ -469,7 +469,7 @@ func row2mapInterface(rows *core.Rows, fields []string) (resultsMap map[string]i continue } - result[key] = (*rawValue).Interface() + result[key] = rawValue.Interface() } return result, nil } From 719c58a95291aac4be6052ea8c59f794c736ad70 Mon Sep 17 00:00:00 2001 From: Edison-Hsu Date: Thu, 28 Jul 2016 16:13:58 +0800 Subject: [PATCH 6/6] add reflect2truevalue --- helpers.go | 50 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/helpers.go b/helpers.go index 185cbb1d..0d81f3e0 100644 --- a/helpers.go +++ b/helpers.go @@ -283,6 +283,50 @@ func sliceEq(left, right []string) bool { return true } +func reflect2truevalue(rawValue *reflect.Value) (str interface{}, err error) { + aa := reflect.TypeOf((*rawValue).Interface()) + vv := reflect.ValueOf((*rawValue).Interface()) + switch aa.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + str = vv.Int() + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + str = vv.Uint() + case reflect.Float32, reflect.Float64: + str = vv.Float() + case reflect.String: + str = vv.String() + case reflect.Array, reflect.Slice: + switch aa.Elem().Kind() { + case reflect.Uint8: + data := rawValue.Interface().([]byte) + str = string(data) + default: + err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name()) + } + // time type + case reflect.Struct: + if aa.ConvertibleTo(core.TimeType) { + str = vv.Convert(core.TimeType).Interface().(time.Time).Format(time.RFC3339Nano) + } else { + err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name()) + } + case reflect.Bool: + str = vv.Bool() + case reflect.Complex128, reflect.Complex64: + str = fmt.Sprintf("%v", vv.Complex()) + /* TODO: unsupported types below + case reflect.Map: + case reflect.Ptr: + case reflect.Uintptr: + case reflect.UnsafePointer: + case reflect.Chan, reflect.Func, reflect.Interface: + */ + default: + err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name()) + } + return +} + func reflect2value(rawValue *reflect.Value) (str string, err error) { aa := reflect.TypeOf((*rawValue).Interface()) vv := reflect.ValueOf((*rawValue).Interface()) @@ -469,7 +513,11 @@ func row2mapInterface(rows *core.Rows, fields []string) (resultsMap map[string]i continue } - result[key] = rawValue.Interface() + if data, err := reflect2truevalue(&rawValue); err == nil { + result[key] = data + } else { + return nil, err // !nashtsai! REVIEW, should return err or just error log? + } } return result, nil }