88 lines
2.3 KiB
Go
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)
|
|
}
|
|
}
|