From e90cc79dac026550dd153f10e75974f41c560e36 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 27 Aug 2021 14:50:08 +0800 Subject: [PATCH 1/3] Expose ScanString / ScanInterface and etc --- scan.go | 214 ++++++++++++++++++++++++++++++++++++----------- session_query.go | 89 +++----------------- session_raw.go | 10 --- 3 files changed, 178 insertions(+), 135 deletions(-) diff --git a/scan.go b/scan.go index 2788453e..ff678244 100644 --- a/scan.go +++ b/scan.go @@ -129,41 +129,6 @@ func genScanResultsByBean(bean interface{}) (interface{}, bool, error) { } } -func (engine *Engine) row2mapStr(rows *core.Rows, types []*sql.ColumnType, fields []string) (map[string]string, error) { - var scanResults = make([]interface{}, len(fields)) - for i := 0; i < len(fields); i++ { - var s sql.NullString - scanResults[i] = &s - } - - if err := engine.driver.Scan(&dialects.ScanContext{ - DBLocation: engine.DatabaseTZ, - UserLocation: engine.TZLocation, - }, rows, types, scanResults...); err != nil { - return nil, err - } - - result := make(map[string]string, len(fields)) - for i, key := range fields { - s := scanResults[i].(*sql.NullString) - if s.String == "" { - result[key] = "" - continue - } - - if schemas.TIME_TYPE == engine.dialect.ColumnTypeKind(types[i].DatabaseTypeName()) { - t, err := convert.String2Time(s.String, engine.DatabaseTZ, engine.TZLocation) - if err != nil { - return nil, err - } - result[key] = t.Format("2006-01-02 15:04:05") - } else { - result[key] = s.String - } - } - return result, nil -} - func row2mapBytes(rows *core.Rows, types []*sql.ColumnType, fields []string) (map[string][]byte, error) { var scanResults = make([]interface{}, len(fields)) for i := 0; i < len(fields); i++ { @@ -262,19 +227,6 @@ func (engine *Engine) scanInterfaces(rows *core.Rows, fields []string, types []* return scanResultContainers, nil } -func (engine *Engine) row2sliceStr(rows *core.Rows, types []*sql.ColumnType, fields []string) ([]string, error) { - scanResults, err := engine.scanStringInterface(rows, fields, types) - if err != nil { - return nil, err - } - - var results = make([]string, 0, len(fields)) - for i := 0; i < len(fields); i++ { - results = append(results, scanResults[i].(*sql.NullString).String) - } - return results, nil -} - func rows2maps(rows *core.Rows) (resultsSlice []map[string][]byte, err error) { fields, err := rows.Columns() if err != nil { @@ -298,6 +250,9 @@ func rows2maps(rows *core.Rows) (resultsSlice []map[string][]byte, err error) { return resultsSlice, nil } +//////////////////// +// row -> map[string]interface{} + func (engine *Engine) row2mapInterface(rows *core.Rows, types []*sql.ColumnType, fields []string) (map[string]interface{}, error) { var resultsMap = make(map[string]interface{}, len(fields)) var scanResultContainers = make([]interface{}, len(fields)) @@ -321,3 +276,166 @@ func (engine *Engine) row2mapInterface(rows *core.Rows, types []*sql.ColumnType, } return resultsMap, nil } + +func (engine *Engine) ScanInterfaceMap(rows *core.Rows) (map[string]interface{}, error) { + fields, err := rows.Columns() + if err != nil { + return nil, err + } + types, err := rows.ColumnTypes() + if err != nil { + return nil, err + } + + return engine.row2mapInterface(rows, types, fields) +} + +func (engine *Engine) ScanInterfaceMaps(rows *core.Rows) (resultsSlice []map[string]interface{}, err error) { + fields, err := rows.Columns() + if err != nil { + return nil, err + } + types, err := rows.ColumnTypes() + if err != nil { + return nil, err + } + for rows.Next() { + result, err := engine.row2mapInterface(rows, types, fields) + if err != nil { + return nil, err + } + resultsSlice = append(resultsSlice, result) + } + if rows.Err() != nil { + return nil, rows.Err() + } + + return resultsSlice, nil +} + +//////////////////// +// row -> map[string]string + +func (engine *Engine) row2mapStr(rows *core.Rows, types []*sql.ColumnType, fields []string) (map[string]string, error) { + var scanResults = make([]interface{}, len(fields)) + for i := 0; i < len(fields); i++ { + var s sql.NullString + scanResults[i] = &s + } + + if err := engine.driver.Scan(&dialects.ScanContext{ + DBLocation: engine.DatabaseTZ, + UserLocation: engine.TZLocation, + }, rows, types, scanResults...); err != nil { + return nil, err + } + + result := make(map[string]string, len(fields)) + for i, key := range fields { + s := scanResults[i].(*sql.NullString) + if s.String == "" { + result[key] = "" + continue + } + + if schemas.TIME_TYPE == engine.dialect.ColumnTypeKind(types[i].DatabaseTypeName()) { + t, err := convert.String2Time(s.String, engine.DatabaseTZ, engine.TZLocation) + if err != nil { + return nil, err + } + result[key] = t.Format("2006-01-02 15:04:05") + } else { + result[key] = s.String + } + } + return result, nil +} + +func (engine *Engine) ScanStringMap(rows *core.Rows) (map[string]string, error) { + fields, err := rows.Columns() + if err != nil { + return nil, err + } + types, err := rows.ColumnTypes() + if err != nil { + return nil, err + } + return engine.row2mapStr(rows, types, fields) +} + +func (engine *Engine) ScanStringMaps(rows *core.Rows) (resultsSlice []map[string]string, err error) { + fields, err := rows.Columns() + if err != nil { + return nil, err + } + types, err := rows.ColumnTypes() + if err != nil { + return nil, err + } + + for rows.Next() { + result, err := engine.row2mapStr(rows, types, fields) + if err != nil { + return nil, err + } + resultsSlice = append(resultsSlice, result) + } + if rows.Err() != nil { + return nil, rows.Err() + } + + return resultsSlice, nil +} + +//////////////////// +// row -> []string + +func (engine *Engine) row2sliceStr(rows *core.Rows, types []*sql.ColumnType, fields []string) ([]string, error) { + scanResults, err := engine.scanStringInterface(rows, fields, types) + if err != nil { + return nil, err + } + + var results = make([]string, 0, len(fields)) + for i := 0; i < len(fields); i++ { + results = append(results, scanResults[i].(*sql.NullString).String) + } + return results, nil +} + +func (engine *Engine) ScanStringSlice(rows *core.Rows) ([]string, error) { + fields, err := rows.Columns() + if err != nil { + return nil, err + } + types, err := rows.ColumnTypes() + if err != nil { + return nil, err + } + + return engine.row2sliceStr(rows, types, fields) +} + +func (engine *Engine) ScanStringSlices(rows *core.Rows) (resultsSlice [][]string, err error) { + fields, err := rows.Columns() + if err != nil { + return nil, err + } + types, err := rows.ColumnTypes() + if err != nil { + return nil, err + } + + for rows.Next() { + record, err := engine.row2sliceStr(rows, types, fields) + if err != nil { + return nil, err + } + resultsSlice = append(resultsSlice, record) + } + if rows.Err() != nil { + return nil, rows.Err() + } + + return resultsSlice, nil +} diff --git a/session_query.go b/session_query.go index a4070985..a6951711 100644 --- a/session_query.go +++ b/session_query.go @@ -4,9 +4,15 @@ package xorm -import ( - "xorm.io/xorm/core" -) +func (session *Session) queryBytes(sqlStr string, args ...interface{}) ([]map[string][]byte, error) { + rows, err := session.queryRows(sqlStr, args...) + if err != nil { + return nil, err + } + defer rows.Close() + + return rows2maps(rows) +} // Query runs a raw sql and return records as []map[string][]byte func (session *Session) Query(sqlOrArgs ...interface{}) ([]map[string][]byte, error) { @@ -22,54 +28,6 @@ func (session *Session) Query(sqlOrArgs ...interface{}) ([]map[string][]byte, er return session.queryBytes(sqlStr, args...) } -func (session *Session) rows2Strings(rows *core.Rows) (resultsSlice []map[string]string, err error) { - fields, err := rows.Columns() - if err != nil { - return nil, err - } - types, err := rows.ColumnTypes() - if err != nil { - return nil, err - } - - for rows.Next() { - result, err := session.engine.row2mapStr(rows, types, fields) - if err != nil { - return nil, err - } - resultsSlice = append(resultsSlice, result) - } - if rows.Err() != nil { - return nil, rows.Err() - } - - return resultsSlice, nil -} - -func (session *Session) rows2SliceString(rows *core.Rows) (resultsSlice [][]string, err error) { - fields, err := rows.Columns() - if err != nil { - return nil, err - } - types, err := rows.ColumnTypes() - if err != nil { - return nil, err - } - - for rows.Next() { - record, err := session.engine.row2sliceStr(rows, types, fields) - if err != nil { - return nil, err - } - resultsSlice = append(resultsSlice, record) - } - if rows.Err() != nil { - return nil, rows.Err() - } - - return resultsSlice, nil -} - // QueryString runs a raw sql and return records as []map[string]string func (session *Session) QueryString(sqlOrArgs ...interface{}) ([]map[string]string, error) { if session.isAutoClose { @@ -87,7 +45,7 @@ func (session *Session) QueryString(sqlOrArgs ...interface{}) ([]map[string]stri } defer rows.Close() - return session.rows2Strings(rows) + return session.engine.ScanStringMaps(rows) } // QuerySliceString runs a raw sql and return records as [][]string @@ -107,30 +65,7 @@ func (session *Session) QuerySliceString(sqlOrArgs ...interface{}) ([][]string, } defer rows.Close() - return session.rows2SliceString(rows) -} - -func (session *Session) rows2Interfaces(rows *core.Rows) (resultsSlice []map[string]interface{}, err error) { - fields, err := rows.Columns() - if err != nil { - return nil, err - } - types, err := rows.ColumnTypes() - if err != nil { - return nil, err - } - for rows.Next() { - result, err := session.engine.row2mapInterface(rows, types, fields) - if err != nil { - return nil, err - } - resultsSlice = append(resultsSlice, result) - } - if rows.Err() != nil { - return nil, rows.Err() - } - - return resultsSlice, nil + return session.engine.ScanStringSlices(rows) } // QueryInterface runs a raw sql and return records as []map[string]interface{} @@ -150,5 +85,5 @@ func (session *Session) QueryInterface(sqlOrArgs ...interface{}) ([]map[string]i } defer rows.Close() - return session.rows2Interfaces(rows) + return session.engine.ScanInterfaceMaps(rows) } diff --git a/session_raw.go b/session_raw.go index 2b488988..3edb7c24 100644 --- a/session_raw.go +++ b/session_raw.go @@ -71,16 +71,6 @@ func (session *Session) queryRow(sqlStr string, args ...interface{}) *core.Row { return core.NewRow(session.queryRows(sqlStr, args...)) } -func (session *Session) queryBytes(sqlStr string, args ...interface{}) ([]map[string][]byte, error) { - rows, err := session.queryRows(sqlStr, args...) - if err != nil { - return nil, err - } - defer rows.Close() - - return rows2maps(rows) -} - func (session *Session) exec(sqlStr string, args ...interface{}) (sql.Result, error) { defer session.resetStatement() -- 2.40.1 From f9f79d11c1fe9d3a86b4bcbc1c628a86b8627c1b Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 27 Aug 2021 15:08:39 +0800 Subject: [PATCH 2/3] Remove function queryBytes --- scan.go | 76 +++++++++++++++++++++-------------------------- session_delete.go | 12 ++++++-- session_query.go | 18 +++++------ 3 files changed, 50 insertions(+), 56 deletions(-) diff --git a/scan.go b/scan.go index ff678244..d562abbc 100644 --- a/scan.go +++ b/scan.go @@ -129,25 +129,6 @@ func genScanResultsByBean(bean interface{}) (interface{}, bool, error) { } } -func row2mapBytes(rows *core.Rows, types []*sql.ColumnType, fields []string) (map[string][]byte, error) { - var scanResults = make([]interface{}, len(fields)) - for i := 0; i < len(fields); i++ { - var s sql.NullString - scanResults[i] = &s - } - - if err := rows.Scan(scanResults...); err != nil { - return nil, err - } - - result := make(map[string][]byte, len(fields)) - for ii, key := range fields { - s := scanResults[ii].(*sql.NullString) - result[key] = []byte(s.String) - } - return result, nil -} - func (engine *Engine) scanStringInterface(rows *core.Rows, fields []string, types []*sql.ColumnType) ([]interface{}, error) { var scanResults = make([]interface{}, len(types)) for i := 0; i < len(types); i++ { @@ -227,29 +208,6 @@ func (engine *Engine) scanInterfaces(rows *core.Rows, fields []string, types []* return scanResultContainers, nil } -func rows2maps(rows *core.Rows) (resultsSlice []map[string][]byte, err error) { - fields, err := rows.Columns() - if err != nil { - return nil, err - } - types, err := rows.ColumnTypes() - if err != nil { - return nil, err - } - for rows.Next() { - result, err := row2mapBytes(rows, types, fields) - if err != nil { - return nil, err - } - resultsSlice = append(resultsSlice, result) - } - if rows.Err() != nil { - return nil, rows.Err() - } - - return resultsSlice, nil -} - //////////////////// // row -> map[string]interface{} @@ -387,6 +345,40 @@ func (engine *Engine) ScanStringMaps(rows *core.Rows) (resultsSlice []map[string return resultsSlice, nil } +//////////////////// +// row -> map[string][]byte + +func convertMapStr2Bytes(m map[string]string) map[string][]byte { + var r = make(map[string][]byte, len(m)) + for k, v := range m { + r[k] = []byte(v) + } + return r +} + +func (engine *Engine) scanByteMaps(rows *core.Rows) (resultsSlice []map[string][]byte, err error) { + fields, err := rows.Columns() + if err != nil { + return nil, err + } + types, err := rows.ColumnTypes() + if err != nil { + return nil, err + } + for rows.Next() { + result, err := engine.row2mapStr(rows, types, fields) + if err != nil { + return nil, err + } + resultsSlice = append(resultsSlice, convertMapStr2Bytes(result)) + } + if rows.Err() != nil { + return nil, rows.Err() + } + + return resultsSlice, nil +} + //////////////////// // row -> []string diff --git a/session_delete.go b/session_delete.go index 37b9c1cd..9c19e43e 100644 --- a/session_delete.go +++ b/session_delete.go @@ -40,7 +40,13 @@ func (session *Session) cacheDelete(table *schemas.Table, tableName, sqlStr stri pkColumns := table.PKColumns() ids, err := caches.GetCacheSql(cacher, tableName, newsql, args) if err != nil { - resultsSlice, err := session.queryBytes(newsql, args...) + rows, err := session.queryRows(newsql, args...) + if err != nil { + return err + } + defer rows.Close() + + resultsSlice, err := session.engine.ScanStringMaps(rows) if err != nil { return err } @@ -53,9 +59,9 @@ func (session *Session) cacheDelete(table *schemas.Table, tableName, sqlStr stri if v, ok := data[col.Name]; !ok { return errors.New("no id") } else if col.SQLType.IsText() { - pk = append(pk, string(v)) + pk = append(pk, v) } else if col.SQLType.IsNumeric() { - id, err = strconv.ParseInt(string(v), 10, 64) + id, err = strconv.ParseInt(v, 10, 64) if err != nil { return err } diff --git a/session_query.go b/session_query.go index a6951711..58696dd1 100644 --- a/session_query.go +++ b/session_query.go @@ -4,16 +4,6 @@ package xorm -func (session *Session) queryBytes(sqlStr string, args ...interface{}) ([]map[string][]byte, error) { - rows, err := session.queryRows(sqlStr, args...) - if err != nil { - return nil, err - } - defer rows.Close() - - return rows2maps(rows) -} - // Query runs a raw sql and return records as []map[string][]byte func (session *Session) Query(sqlOrArgs ...interface{}) ([]map[string][]byte, error) { if session.isAutoClose { @@ -25,7 +15,13 @@ func (session *Session) Query(sqlOrArgs ...interface{}) ([]map[string][]byte, er return nil, err } - return session.queryBytes(sqlStr, args...) + rows, err := session.queryRows(sqlStr, args...) + if err != nil { + return nil, err + } + defer rows.Close() + + return session.engine.scanByteMaps(rows) } // QueryString runs a raw sql and return records as []map[string]string -- 2.40.1 From 02f42a3412fee2ed5bbf567e109cdb361639a5ce Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 27 Aug 2021 15:17:35 +0800 Subject: [PATCH 3/3] Some more refactors --- session.go | 17 +++++----- session_query.go | 85 ------------------------------------------------ session_raw.go | 80 +++++++++++++++++++++++++++++++++++++++++++++ session_stats.go | 4 +-- 4 files changed, 90 insertions(+), 96 deletions(-) delete mode 100644 session_query.go diff --git a/session.go b/session.go index a96d2fc9..0e2c48ca 100644 --- a/session.go +++ b/session.go @@ -123,9 +123,9 @@ func newSession(engine *Engine) *Session { autoResetStatement: true, prepareStmt: false, - afterInsertBeans: make(map[interface{}]*[]func(interface{}), 0), - afterUpdateBeans: make(map[interface{}]*[]func(interface{}), 0), - afterDeleteBeans: make(map[interface{}]*[]func(interface{}), 0), + afterInsertBeans: make(map[interface{}]*[]func(interface{})), + afterUpdateBeans: make(map[interface{}]*[]func(interface{})), + afterDeleteBeans: make(map[interface{}]*[]func(interface{})), beforeClosures: make([]func(interface{}), 0), afterClosures: make([]func(interface{}), 0), afterProcessors: make([]executedProcessor, 0), @@ -684,13 +684,12 @@ func (session *Session) slice2Bean(scanResults []interface{}, fields []string, b tempMap[lKey] = idx col, fieldValue, err := session.getField(dataStruct, table, colName, idx) - if err != nil { - if _, ok := err.(ErrFieldIsNotExist); ok { - continue - } else { - return nil, err - } + if _, ok := err.(ErrFieldIsNotExist); ok { + continue + } else if err != nil { + return nil, err } + if fieldValue == nil { continue } diff --git a/session_query.go b/session_query.go deleted file mode 100644 index 58696dd1..00000000 --- a/session_query.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2017 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -// Query runs a raw sql and return records as []map[string][]byte -func (session *Session) Query(sqlOrArgs ...interface{}) ([]map[string][]byte, error) { - if session.isAutoClose { - defer session.Close() - } - - sqlStr, args, err := session.statement.GenQuerySQL(sqlOrArgs...) - if err != nil { - return nil, err - } - - rows, err := session.queryRows(sqlStr, args...) - if err != nil { - return nil, err - } - defer rows.Close() - - return session.engine.scanByteMaps(rows) -} - -// QueryString runs a raw sql and return records as []map[string]string -func (session *Session) QueryString(sqlOrArgs ...interface{}) ([]map[string]string, error) { - if session.isAutoClose { - defer session.Close() - } - - sqlStr, args, err := session.statement.GenQuerySQL(sqlOrArgs...) - if err != nil { - return nil, err - } - - rows, err := session.queryRows(sqlStr, args...) - if err != nil { - return nil, err - } - defer rows.Close() - - return session.engine.ScanStringMaps(rows) -} - -// QuerySliceString runs a raw sql and return records as [][]string -func (session *Session) QuerySliceString(sqlOrArgs ...interface{}) ([][]string, error) { - if session.isAutoClose { - defer session.Close() - } - - sqlStr, args, err := session.statement.GenQuerySQL(sqlOrArgs...) - if err != nil { - return nil, err - } - - rows, err := session.queryRows(sqlStr, args...) - if err != nil { - return nil, err - } - defer rows.Close() - - return session.engine.ScanStringSlices(rows) -} - -// QueryInterface runs a raw sql and return records as []map[string]interface{} -func (session *Session) QueryInterface(sqlOrArgs ...interface{}) ([]map[string]interface{}, error) { - if session.isAutoClose { - defer session.Close() - } - - sqlStr, args, err := session.statement.GenQuerySQL(sqlOrArgs...) - if err != nil { - return nil, err - } - - rows, err := session.queryRows(sqlStr, args...) - if err != nil { - return nil, err - } - defer rows.Close() - - return session.engine.ScanInterfaceMaps(rows) -} diff --git a/session_raw.go b/session_raw.go index 3edb7c24..cee29fc7 100644 --- a/session_raw.go +++ b/session_raw.go @@ -71,6 +71,86 @@ func (session *Session) queryRow(sqlStr string, args ...interface{}) *core.Row { return core.NewRow(session.queryRows(sqlStr, args...)) } +// Query runs a raw sql and return records as []map[string][]byte +func (session *Session) Query(sqlOrArgs ...interface{}) ([]map[string][]byte, error) { + if session.isAutoClose { + defer session.Close() + } + + sqlStr, args, err := session.statement.GenQuerySQL(sqlOrArgs...) + if err != nil { + return nil, err + } + + rows, err := session.queryRows(sqlStr, args...) + if err != nil { + return nil, err + } + defer rows.Close() + + return session.engine.scanByteMaps(rows) +} + +// QueryString runs a raw sql and return records as []map[string]string +func (session *Session) QueryString(sqlOrArgs ...interface{}) ([]map[string]string, error) { + if session.isAutoClose { + defer session.Close() + } + + sqlStr, args, err := session.statement.GenQuerySQL(sqlOrArgs...) + if err != nil { + return nil, err + } + + rows, err := session.queryRows(sqlStr, args...) + if err != nil { + return nil, err + } + defer rows.Close() + + return session.engine.ScanStringMaps(rows) +} + +// QuerySliceString runs a raw sql and return records as [][]string +func (session *Session) QuerySliceString(sqlOrArgs ...interface{}) ([][]string, error) { + if session.isAutoClose { + defer session.Close() + } + + sqlStr, args, err := session.statement.GenQuerySQL(sqlOrArgs...) + if err != nil { + return nil, err + } + + rows, err := session.queryRows(sqlStr, args...) + if err != nil { + return nil, err + } + defer rows.Close() + + return session.engine.ScanStringSlices(rows) +} + +// QueryInterface runs a raw sql and return records as []map[string]interface{} +func (session *Session) QueryInterface(sqlOrArgs ...interface{}) ([]map[string]interface{}, error) { + if session.isAutoClose { + defer session.Close() + } + + sqlStr, args, err := session.statement.GenQuerySQL(sqlOrArgs...) + if err != nil { + return nil, err + } + + rows, err := session.queryRows(sqlStr, args...) + if err != nil { + return nil, err + } + defer rows.Close() + + return session.engine.ScanInterfaceMaps(rows) +} + func (session *Session) exec(sqlStr string, args ...interface{}) (sql.Result, error) { defer session.resetStatement() diff --git a/session_stats.go b/session_stats.go index 17d0a675..5d0da5e9 100644 --- a/session_stats.go +++ b/session_stats.go @@ -70,12 +70,12 @@ func (session *Session) SumInt(bean interface{}, columnName string) (res int64, // Sums call sum some columns. bean's non-empty fields are conditions. func (session *Session) Sums(bean interface{}, columnNames ...string) ([]float64, error) { - var res = make([]float64, len(columnNames), len(columnNames)) + var res = make([]float64, len(columnNames)) return res, session.sum(&res, bean, columnNames...) } // SumsInt sum specify columns and return as []int64 instead of []float64 func (session *Session) SumsInt(bean interface{}, columnNames ...string) ([]int64, error) { - var res = make([]int64, len(columnNames), len(columnNames)) + var res = make([]int64, len(columnNames)) return res, session.sum(&res, bean, columnNames...) } -- 2.40.1