Files
pro-go-study/26-data/data/database.go
yanzuoguang f9ea51b500 refactor(database):优化字段扫描与转换逻辑- 重命名 fieldVal 为 field 以提高代码可读性- 改进字段存在性和类型转换检查逻辑
- 添加详细注释说明字段处理流程
- 确保字段地址获取和转换正确处理
- 更新结构体复制和结果切片追加逻辑
2025-10-28 21:28:28 +08:00

88 lines
2.3 KiB
Go

package main
import (
"database/sql"
_ "modernc.org/sqlite"
"reflect"
"strings"
)
func listDrivers() {
for _, driver := range sql.Drivers() {
Printfln("Driver: %s", driver)
}
}
var insertNewCategory *sql.Stmt
var changeProductCategory *sql.Stmt
func openDatabase() (db *sql.DB, err error) {
db, err = sql.Open("sqlite", "products.db")
if err == nil {
Printfln("Opened database")
insertNewCategory, _ = db.Prepare(`
INSERT INTO categories (name) VALUES (?)
`)
changeProductCategory, _ = db.Prepare(`
UPDATE products SET category = ? WHERE id = ?
`)
}
return
}
func scanIntoStruct(rows *sql.Rows, target interface{}) (results interface{}, err error) {
targetVal := reflect.ValueOf(target)
if targetVal.Kind() == reflect.Ptr {
targetVal = targetVal.Elem()
}
if targetVal.Kind() != reflect.Struct {
return
}
colNames, _ := rows.Columns()
colTypes, _ := rows.ColumnTypes()
references := []interface{}{}
var placeholder interface{}
for i, colName := range colNames {
Printfln("Column: %s", colName)
// 获取字段
colNameParts := strings.Split(colName, ".")
field := targetVal.FieldByName(colNameParts[0])
if field.IsValid() && field.Kind() == reflect.Struct && len(colNameParts) > 1 {
for _, namePart := range colNameParts[1:] {
comFunction := matchColName(namePart)
field = field.FieldByNameFunc(comFunction)
}
}
if !field.IsValid() || !colTypes[i].ScanType().ConvertibleTo(field.Type()) {
// 字段不存在或者不可以转换
Printfln("Column placeholder: %s", colName)
references = append(references, &placeholder)
} else if field.Kind() != reflect.Ptr && field.CanAddr() {
// 字段存在并且可以转换,不为指针并且可以获取到地址
Printfln("Column Addr: %s", colName)
field = field.Addr()
references = append(references, field.Interface())
}
}
// 创建结果集合
resultSlice := reflect.MakeSlice(reflect.SliceOf(targetVal.Type()), 0, 10)
for rows.Next() {
err = rows.Scan(references...)
if err != nil {
break
}
// 将指针转换为结构体,从而可以复制该结构体,并增加到切片中
resultSlice = reflect.Append(resultSlice, targetVal)
}
results = resultSlice.Interface()
return
}
func matchColName(colName string) func(string) bool {
return func(fieldName string) bool {
return strings.EqualFold(colName, fieldName)
}
}