1 Commits

Author SHA1 Message Date
9d03bc8e16 feat: 修改包名 2024-09-14 15:57:03 +08:00
9 changed files with 116 additions and 476 deletions

View File

@@ -34,7 +34,7 @@ type TableNamer interface {
### 批量插入 -- 示例 ### 示例
```go ```go
@@ -52,12 +52,12 @@ func (u *User) SuperTableName() string {
} }
func TestSimpleInsert(t *testing.T) { func TestSimpleInsert(t *testing.T) {
tdMapper := NewMapper() tdMapping := NewTdMapping()
data := []any{ data := []any{
&User{Name: "张三", Age: 18}, &User{Name: "张三", Age: 18},
&User{Name: "李四", Age: 20}, &User{Name: "李四", Age: 20},
} }
insertSql, err := tdMapper.ToInsertSQL(data...) insertSql, err := tdMapping.ToInsertSQL(data...)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -70,44 +70,6 @@ INSERT INTO
`user_李四` USING `super_user` (`name`) TAGS ('李四') (`age`) VALUES (20) `user_李四` USING `super_user` (`name`) TAGS ('李四') (`age`) VALUES (20)
``` ```
### 查询映射 -- 示例
```go
// 如果没有结果,会返回 sql.ErrNoRows
func QueryOne(db *sql.DB) (*User,error){
tdMapper := NewMapper()
rows,err:=db.Query("select * from User limit 100")
if err!=nil {
return err
}
def rows.Close()
var user User
if err:=ScanRows(&user,rows);err!=nil {
return err
}
return &user, nil
}
// 如果查询结果数量为0不会返回错误
func QueryAll(db *sql.DB)([]*User, error) {
tdMapper := NewMapper()
rows,err:=db.Query("select * from User limit 100")
if err!=nil {
return err
}
def rows.Close()
var users []*User
if err:=ScanRows(&users,rows);err!=nil {
return err
}
return &users, nil
}
```

0
go.sum
View File

View File

@@ -1,4 +1,4 @@
package tdmap package tmapping
import ( import (
"database/sql" "database/sql"
@@ -137,7 +137,7 @@ func formatRowValues(values ...any) string {
} }
case sql.NullTime: case sql.NullTime:
if v.Valid { if v.Valid {
formattedValues[i] = fmt.Sprintf("'%s'", v.Time.Format(time.RFC3339Nano)) formattedValues[i] = fmt.Sprintf("'%s'", v.Time.Format(time.RFC3339))
} else { } else {
formattedValues[i] = "null" formattedValues[i] = "null"
} }
@@ -148,7 +148,7 @@ func formatRowValues(values ...any) string {
case nil: case nil:
formattedValues[i] = "null" formattedValues[i] = "null"
case time.Time: case time.Time:
formattedValues[i] = fmt.Sprintf("'%s'", v.Format(time.RFC3339Nano)) formattedValues[i] = fmt.Sprintf("'%s'", v.Format("2006-01-02 15:04:05"))
default: default:
if reflect.TypeOf(val).Kind() == reflect.Ptr && reflect.ValueOf(val).IsNil() { if reflect.TypeOf(val).Kind() == reflect.Ptr && reflect.ValueOf(val).IsNil() {
formattedValues[i] = "null" formattedValues[i] = "null"

View File

@@ -1,16 +1,13 @@
package tdmap package tmapping
import ( import (
"context"
"database/sql"
"errors"
"fmt" "fmt"
"reflect" "reflect"
"strings" "strings"
) )
func NewMapper() *Mapper { func NewMapping() *TdMapping {
return &Mapper{} return &TdMapping{}
} }
// TableNamer 定义了一个获取表名的方法。 // TableNamer 定义了一个获取表名的方法。
@@ -18,21 +15,20 @@ type TableNamer interface {
TableName() string TableName() string
} }
type Mapper struct { type TdMapping struct {
structMateMap SyncMap[string, *StructMate] // 结构体 元信息缓存 key: struct 的唯一类型名称 value: 元信息 modelMates Map[string, *StructMate]
} }
func (b *Mapper) scanStruct(data ...any) error { func (b *TdMapping) scanStruct(data ...any) error {
for _, datum := range data { for _, datum := range data {
if reflect.TypeOf(datum).Kind() != reflect.Ptr { if reflect.TypeOf(datum).Kind() != reflect.Ptr {
//return fmt.Errorf("需要指针类型:%v", reflect.TypeOf(datum)) return fmt.Errorf("需要指针类型:%v", reflect.TypeOf(datum))
return fmt.Errorf("need a pointer type: %v", reflect.TypeOf(datum))
} }
if mate, err := scan(datum); err != nil { if mate, err := scan(datum); err != nil {
return err return err
} else { } else {
b.structMateMap.Store(mate.UniqueTypeName, mate) b.modelMates.Store(mate.UniqueTypeName, mate)
} }
} }
@@ -42,7 +38,7 @@ func (b *Mapper) scanStruct(data ...any) error {
// 提取 struct 内的信息 // 提取 struct 内的信息
// @param data 包含 struct 类型的数据 // @param data 包含 struct 类型的数据
// @return 返回一个 map[表名][]*TableRowMateria 如果超级表名为空,则表示普通表 // @return 返回一个 map[表名][]*TableRowMateria 如果超级表名为空,则表示普通表
func (b *Mapper) extractStructData(data ...any) (map[string][]*TableRowMateria, error) { func (b *TdMapping) extractStructData(data ...any) (map[string][]*TableRowMateria, error) {
result := make(map[string][]*TableRowMateria) result := make(map[string][]*TableRowMateria)
for _, item := range data { for _, item := range data {
@@ -65,11 +61,11 @@ func (b *Mapper) extractStructData(data ...any) (map[string][]*TableRowMateria,
} }
if tableName == "" { if tableName == "" {
return nil, fmt.Errorf("not func TableName() string func for struct type: %s", uniqueTypeName) return nil, fmt.Errorf("not import TableName() string func for struct type: %s", uniqueTypeName)
} }
} }
mate, ok := b.structMateMap.Load(uniqueTypeName) mate, ok := b.modelMates.Load(uniqueTypeName)
if !ok { if !ok {
return nil, fmt.Errorf("not found struct type: %s", uniqueTypeName) return nil, fmt.Errorf("not found struct type: %s", uniqueTypeName)
} }
@@ -85,9 +81,9 @@ func (b *Mapper) extractStructData(data ...any) (map[string][]*TableRowMateria,
for _, name := range mate.DBAnnotatedNames { for _, name := range mate.DBAnnotatedNames {
// db tag 名称 -- 数据库列名 // db tag 名称 -- 数据库列名
dbColumn := mate.Filed2DBNameCache[name] dbColumn := mate.FiledDBNameCache[name]
field := vf.FieldByIndex(mate.Field2IndexCache[name]) field := vf.FieldByIndex(mate.FieldIndexCache[name])
for field.Kind() == reflect.Ptr { for field.Kind() == reflect.Ptr {
if field.IsNil() { if field.IsNil() {
break break
@@ -103,8 +99,8 @@ func (b *Mapper) extractStructData(data ...any) (map[string][]*TableRowMateria,
for _, name := range mate.TaggedFieldNames { for _, name := range mate.TaggedFieldNames {
// db tag 名称 -- 数据库列名 // db tag 名称 -- 数据库列名
tagColumn := mate.Filed2DBNameCache[name] tagColumn := mate.FiledDBNameCache[name]
field := vf.FieldByIndex(mate.Field2IndexCache[name]) field := vf.FieldByIndex(mate.FieldIndexCache[name])
for field.Kind() == reflect.Ptr { for field.Kind() == reflect.Ptr {
if field.IsNil() { if field.IsNil() {
break break
@@ -125,71 +121,14 @@ func (b *Mapper) extractStructData(data ...any) (map[string][]*TableRowMateria,
return result, nil return result, nil
} }
// normalizeData 对输入数据进行统一处理和规范化 func (b *TdMapping) ToInsertSQL(data ...any) (string, error) {
// 支持输入为任意数量的参数,参数可以是单个结构体指针或结构体,也可以是结构体切片或指针切片
// 处理逻辑包括:
// 1. 将切片类型的参数拆开放入一个统一的一维切片中(展平)
// 2. 跳过其中的 nil 元素,确保数据有效性
// 3. 将所有非指针类型的元素转换为对应的指针类型,方便后续统一处理
func (b *Mapper) normalizeData(data ...any) []any {
var normalizedData []any
for _, item := range data {
if item == nil {
// 跳过nil值避免后续反射调用panic
continue
}
itemType := reflect.TypeOf(item)
if itemType.Kind() == reflect.Slice {
// 处理切片类型参数,展平成单个元素
sliceValue := reflect.ValueOf(item)
for i := 0; i < sliceValue.Len(); i++ {
elem := sliceValue.Index(i).Interface()
if elem == nil {
// 跳过nil元素
continue
}
normalizedData = append(normalizedData, elem)
}
} else {
// 非切片类型直接追加
normalizedData = append(normalizedData, item)
}
}
// 转换所有元素为指针类型,便于后续一致性处理
for i, item := range normalizedData {
if item == nil {
continue
}
itemType := reflect.TypeOf(item)
if itemType.Kind() != reflect.Ptr {
// 创建对应类型的指针
itemPtr := reflect.New(itemType)
// 设置指针指向的值为元素本身
itemPtr.Elem().Set(reflect.ValueOf(item))
// 替换切片中的元素为指针类型
normalizedData[i] = itemPtr.Interface()
}
}
return normalizedData
}
func (b *Mapper) ToInsertSQL(data ...any) (string, error) {
// 统一规范化处理输入数据,将切片拆平并转换元素为指针
normalizedData := b.normalizeData(data...)
if len(normalizedData) == 0 {
return "", fmt.Errorf("data is empty")
}
// 扫描 struct 类型数据 // 扫描 struct 类型数据
if err := b.scanStruct(normalizedData...); err != nil { if err := b.scanStruct(data...); err != nil {
return "", fmt.Errorf("failed to scan struct: %w", err) return "", fmt.Errorf("failed to scan struct: %w", err)
} }
// 提取 struct 内的信息 // 提取 struct 内的信息
tableMap, err := b.extractStructData(normalizedData...) tableMap, err := b.extractStructData(data...)
if err != nil { if err != nil {
return "", fmt.Errorf("failed to extract struct data: %w", err) return "", fmt.Errorf("failed to extract struct data: %w", err)
} }
@@ -232,160 +171,3 @@ func (b *Mapper) ToInsertSQL(data ...any) (string, error) {
return buf.String(), nil return buf.String(), nil
} }
// ScanRows 扫描多行数据
// A Superior Option: Use ScanRowsWithContext instead.
func (b *Mapper) ScanRows(target any, rows *sql.Rows) error {
return b.ScanRowsWithContext(context.Background(), target, rows)
}
// ScanRowsWithContext 扫描多行数据
// @param ctx 上下文
// @param target 结构体的指针 或 slice 指针 结构体需要使用 db 标签注解
// @param rows 数据库返回的行数据
// @return 返回错误
func (b *Mapper) ScanRowsWithContext(ctx context.Context, target any, rows *sql.Rows) error {
// 确保rows不为nil
if rows == nil {
return errors.New("rows cannot be nil")
}
// 获取target的反射类型和值
vf := reflect.ValueOf(target)
// 检查target是否为指针类型
if vf.Kind() != reflect.Ptr {
return errors.New("target must be a pointer to a struct or a slice of structs")
}
if vf.IsNil() {
return errors.New("target is nil, please pass a pointer to a struct or a slice of structs")
}
vf = vf.Elem() // 解引用指针以获取目标值
switch vf.Kind() {
case reflect.Struct:
// 提取 struct 内的信息
if err := b.scanStruct(target); err != nil {
return err
}
// target是指向单个struct的指针扫描一行数据
if !rows.Next() {
return sql.ErrNoRows
}
return b.scanRow(vf, rows)
case reflect.Slice:
// target是slice的指针
sliceElementType := vf.Type().Elem()
if sliceElementType.Kind() != reflect.Ptr || sliceElementType.Elem().Kind() != reflect.Struct {
return errors.New("target must be a pointer to a slice of structs")
}
// 提取 slice 中 struct 内的信息
if err := b.scanStruct(reflect.New(sliceElementType.Elem()).Interface()); err != nil { // 这里在抛出 不是指针类型
return err
}
for rows.Next() {
select {
case <-ctx.Done():
vf.SetLen(0) // 清空 slice
return ctx.Err()
default:
}
// 创建slice元素的新实例
newStruct := reflect.New(sliceElementType.Elem())
if err := b.scanRow(newStruct, rows); err != nil {
return err
}
// 将新实例添加到slice中
vf.Set(reflect.Append(vf, newStruct))
}
return nil
default:
return errors.New("target must be a pointer to a struct or a slice of structs")
}
}
// scanRow 用于扫描单行数据到结构体
func (b *Mapper) scanRow(target reflect.Value, rows *sql.Rows) error {
target = reflect.Indirect(target)
uniqueTypeName := getUniqueTypeName(target.Type())
mate, ok := b.structMateMap.Load(uniqueTypeName)
if !ok {
return fmt.Errorf("not found struct type mate: %s", uniqueTypeName)
}
// 假设我们有一个函数来获取列的值
columns, err := rows.Columns()
if err != nil {
return err
}
// 准备目标结构体的地址
dest := make([]interface{}, len(columns))
for i, colName := range columns {
// 拿到缓存的字段索引
idx, ok := mate.DBName2IndexCache[colName]
if !ok {
return fmt.Errorf("no corresponding field found for column %s", colName)
}
dest[i] = target.FieldByIndex(idx).Addr().Interface()
}
// 扫描数据
return rows.Scan(dest...)
}
// ScanRowsToMap 扫描多行数据到map
// @param rows 数据库返回的行数据
// @return 返回map数组和错误
func (b *Mapper) ScanRowsToMap(rows *sql.Rows) ([]map[string]any, error) {
return b.ScanRowsToMapWithContext(context.Background(), rows)
}
// ScanRowsToMapWithContext 扫描多行数据到map
// @param ctx 上下文
// @param rows 数据库返回的行数据
// @return 返回map数组和错误
func (b *Mapper) ScanRowsToMapWithContext(ctx context.Context, rows *sql.Rows) ([]map[string]any, error) {
columns, err := rows.Columns()
if err != nil {
return nil, err
}
result := make([]map[string]any, 0)
for rows.Next() {
// 检查上下文是否已取消
select {
case <-ctx.Done():
return nil, ctx.Err()
default:
}
// 创建一个切片来存储列的值
values := make([]any, len(columns))
for i := range values {
values[i] = new(any)
}
// 扫描行数据到切片中
if err := rows.Scan(values...); err != nil {
return nil, err
}
// 构建 结果映射
rowMap := make(map[string]any, len(columns))
for i := range values {
column := columns[i]
value := *(values[i].(*any))
rowMap[column] = value
}
result = append(result, rowMap)
}
return result, err
}

View File

@@ -1,10 +1,8 @@
package tdmap package tmapping
import ( import (
"database/sql" "database/sql"
"encoding/json"
"fmt" "fmt"
//_ "github.com/taosdata/driver-go/v3/taosWS"
"testing" "testing"
"time" "time"
) )
@@ -51,26 +49,50 @@ func (s *TaosUser) TableName() string {
} }
func TestBuilderInsert(t *testing.T) { func TestBuilderInsert(t *testing.T) {
tdMapper := NewMapper() tdMapping := NewMapping()
p := 1 p := 1
data := []any{ data := []any{
&TaosDevice{ &TaosDevice{
TaosTAG: &TaosTAG{DevId: "设备ID", DevType: "测试设备", DataType: "测试数据"}, TaosTAG: &TaosTAG{
Ts: time.Now(), LoadUnitId: "负载单体ID", PInt: &p, NullInt32: sql.NullInt32{Int32: 32, Valid: true}, DevId: "设备ID",
DevType: "测试设备",
DataType: "测试数据",
},
Ts: time.Now(),
LoadUnitId: "负载单体ID",
PInt: &p,
NullInt32: sql.NullInt32{Int32: 32, Valid: true},
}, },
&TaosUser{ &TaosUser{
TaosTAG: &TaosTAG{DevId: "User001", DevType: "User类型", DataType: "User数据类型001", Alias: "三儿"}, TaosTAG: &TaosTAG{
Ts: time.Now(), Name: "张三", DevId: "User001",
DevType: "User类型",
DataType: "User数据类型001",
},
Ts: time.Now(),
Name: "张三",
}, &TaosUser{ }, &TaosUser{
TaosTAG: &TaosTAG{DevId: "User002", DevType: "User类型", DataType: "User数据类型002"}, TaosTAG: &TaosTAG{
Ts: time.Now(), Name: "李四", Weight: 110, DevId: "User002",
DevType: "User类型",
DataType: "User数据类型002",
},
Ts: time.Now(),
Name: "李四",
Weight: 110,
}, &TaosUser{ }, &TaosUser{
TaosTAG: &TaosTAG{DevId: "User002", DevType: "User类型", DataType: "User数据类型002"}, TaosTAG: &TaosTAG{
Name: "李四", Ts: time.Now(), Weight: 100, DevId: "User002",
DevType: "User类型",
DataType: "User数据类型002",
},
Name: "李四",
Ts: time.Now(),
Weight: 100,
}, },
} }
insertSql, err := tdMapper.ToInsertSQL(data) insertSql, err := tdMapping.ToInsertSQL(data...)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -91,152 +113,14 @@ func (u *User) SuperTableName() string {
} }
func TestSimpleInsert(t *testing.T) { func TestSimpleInsert(t *testing.T) {
tdMapper := NewMapper() tdMapping := NewMapping()
data := []User{ data := []any{
{Name: "张三", Age: 18}, &User{Name: "张三", Age: 18},
{Name: "李四", Age: 20}, &User{Name: "李四", Age: 20},
} }
insertSql, err := tdMapping.ToInsertSQL(data...)
insertSql, err := tdMapper.ToInsertSQL(data)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
fmt.Println(insertSql) fmt.Println(insertSql)
} }
type SuperDevTAG struct {
DevId string `db:"dev_id" taos:"tag"`
DevType string `db:"dev_type" taos:"tag"`
}
type SuperDev struct {
SuperDevTAG
Ts time.Time `db:"ts"` // 时间戳
AppSn string `db:"app_sn"`
Ct float64 `db:"ct"`
}
func (s *SuperDev) SuperTableName() string {
return "super_dev"
}
func (s *SuperDev) TableName() string {
return "dev_" + s.DevId
}
func TestSuperDevInsert(t *testing.T) {
var data = []any{
SuperDev{
SuperDevTAG: SuperDevTAG{DevId: "SN001", DevType: "模拟设备"},
Ts: time.Now(), AppSn: "a0001", Ct: 1.0,
},
SuperDev{
SuperDevTAG: SuperDevTAG{DevId: "SN001", DevType: "模拟设备"},
Ts: time.Now().Add(time.Second), AppSn: "a0002", Ct: 2.0,
},
SuperDev{
SuperDevTAG: SuperDevTAG{DevId: "SN002", DevType: "模拟设备"},
Ts: time.Now(), AppSn: "a0003", Ct: 3.0,
},
}
tdMapper := NewMapper()
insertSql, err := tdMapper.ToInsertSQL(data...)
if err != nil {
t.Fatal(err)
}
fmt.Println(insertSql)
}
func TestScanRows(t *testing.T) {
/*
文档参考: https://docs.taosdata.com/reference/connector/go/#websocket-%E8%BF%9E%E6%8E%A5
go get github.com/taosdata/driver-go/v3
import _ "github.com/taosdata/driver-go/v3/taosWS"
超级表创建
CREATE STABLE `super_dev` (`ts` TIMESTAMP , `app_sn` VARCHAR(500) , `ct` INT ) TAGS (`dev_id` VARCHAR(50), `dev_type` VARCHAR(50))
批量插入
INSERT INTO
`dev_SN001` USING `super_dev` (`dev_id`,`dev_type`) TAGS ('SN001','模拟设备') (`ts`,`app_sn`,`ct`)
VALUES ('2024-09-18T16:22:17+08:00','a0001',1),('2024-09-18T16:22:18+08:00','a0002',2)
`dev_SN002` USING `super_dev` (`dev_id`,`dev_type`) TAGS ('SN002','模拟设备') (`ts`,`app_sn`,`ct`)
VALUES ('2024-09-18T16:22:17+08:00','a0003',3)
*/
var taosUri = "root:taosdata@localhost:6041/test"
db, err := sql.Open("taosWS", taosUri)
if err != nil {
t.Fatal(err)
}
rows, err := db.Query("select * from super_dev order by ts desc limit 100")
if err != nil {
t.Fatal(err)
}
defer func() { _ = rows.Close() }()
tdMapper := NewMapper()
var sd SuperDev
if err = tdMapper.ScanRows(&sd, rows); err != nil {
t.Fatal(err)
}
indent, _ := json.MarshalIndent(&sd, "", " ")
fmt.Println(string(indent))
//var sdArray []SuperDev
//if err = tdMapper.ScanRows(&sdArray, rows); err != nil {
// t.Fatal(err)
//}
//marshal, _ := json.MarshalIndent(sdArray, "", " ")
//fmt.Println(len(sdArray), string(marshal))
}
func TestScanRowsToMap(t *testing.T) {
/*
文档参考: https://docs.taosdata.com/reference/connector/go/#websocket-%E8%BF%9E%E6%8E%A5
go get github.com/taosdata/driver-go/v3
import _ "github.com/taosdata/driver-go/v3/taosWS"
超级表创建
CREATE STABLE `super_dev` (`ts` TIMESTAMP , `app_sn` VARCHAR(500) , `ct` INT ) TAGS (`dev_id` VARCHAR(50), `dev_type` VARCHAR(50))
批量插入
INSERT INTO
`dev_SN001` USING `super_dev` (`dev_id`,`dev_type`) TAGS ('SN001','模拟设备') (`ts`,`app_sn`,`ct`)
VALUES ('2024-09-18T16:22:17+08:00','a0001',1),('2024-09-18T16:22:18+08:00','a0002',2)
`dev_SN002` USING `super_dev` (`dev_id`,`dev_type`) TAGS ('SN002','模拟设备') (`ts`,`app_sn`,`ct`)
VALUES ('2024-09-18T16:22:17+08:00','a0003',3)
*/
var taosUri = "root:taosdata@localhost:6041/test"
db, err := sql.Open("taosWS", taosUri)
if err != nil {
t.Fatal(err)
}
rows, err := db.Query("select * from super_dev order by ts desc limit 100")
if err != nil {
t.Fatal(err)
}
defer func() { _ = rows.Close() }()
tdMapper := NewMapper()
toMap, err := tdMapper.ScanRowsToMap(rows)
if err != nil {
t.Fatal(err)
}
indent, _ := json.MarshalIndent(toMap, "", " ")
fmt.Println(string(indent))
fmt.Println("len:", len(toMap))
}

59
scan.go
View File

@@ -1,4 +1,4 @@
package tdmap package tmapping
import ( import (
"fmt" "fmt"
@@ -20,9 +20,8 @@ func scan(data interface{}) (*StructMate, error) {
// 初始化结果结构体 // 初始化结果结构体
sr := StructMate{ sr := StructMate{
UniqueTypeName: uniqueTypeName, UniqueTypeName: uniqueTypeName,
DBName2IndexCache: make(map[string][]int, t.NumField()), FieldIndexCache: make(map[string][]int, t.NumField()),
Field2IndexCache: make(map[string][]int, t.NumField()), FiledDBNameCache: make(map[string]string, t.NumField()),
Filed2DBNameCache: make(map[string]string, t.NumField()),
DBAnnotatedNames: make([]string, 0, t.NumField()), DBAnnotatedNames: make([]string, 0, t.NumField()),
TaggedFieldNames: make([]string, 0, t.NumField()), TaggedFieldNames: make([]string, 0, t.NumField()),
SuperTableName: "", SuperTableName: "",
@@ -56,38 +55,52 @@ func scan(data interface{}) (*StructMate, error) {
return nil, err return nil, err
} }
for k, v := range subResult.DBName2IndexCache { for k, v := range subResult.FieldIndexCache {
sr.DBName2IndexCache[k] = append(sr.DBName2IndexCache[k], i) sr.FieldIndexCache[k] = append(sr.FieldIndexCache[k], i)
sr.DBName2IndexCache[k] = append(sr.DBName2IndexCache[k], v...) sr.FieldIndexCache[k] = append(sr.FieldIndexCache[k], v...)
} }
for k, v := range subResult.FiledDBNameCache {
for k, v := range subResult.Field2IndexCache { sr.FiledDBNameCache[k] = v
sr.Field2IndexCache[k] = append(sr.Field2IndexCache[k], i)
sr.Field2IndexCache[k] = append(sr.Field2IndexCache[k], v...)
} }
for k, v := range subResult.Filed2DBNameCache {
sr.Filed2DBNameCache[k] = v
}
sr.DBAnnotatedNames = append(sr.DBAnnotatedNames, subResult.DBAnnotatedNames...) sr.DBAnnotatedNames = append(sr.DBAnnotatedNames, subResult.DBAnnotatedNames...)
sr.TaggedFieldNames = append(sr.TaggedFieldNames, subResult.TaggedFieldNames...) sr.TaggedFieldNames = append(sr.TaggedFieldNames, subResult.TaggedFieldNames...)
continue continue
} }
//// 如果字段是结构体或结构体指针,递归处理
//if (field.Type.Kind() == reflect.Struct || field.Type.Kind() == reflect.Ptr) && field.Type != timeType {
//
// if field.Type.Kind() == reflect.Ptr {
// if fieldValue.IsNil() {
// // 如果指针是 nil创建一个该类型的零值实例
// zeroValue := reflect.Zero(field.Type.Elem())
// fieldValue = zeroValue
// } else {
// fieldValue = fieldValue.Elem()
// }
// }
//
// if !fieldValue.CanInterface() {
// continue
// }
//
// subResult, err := scan(fieldValue.Interface())
// if err != nil {
// return nil, err
// }
// sr.merge(subResult)
// continue
//}
// 检查字段是否有db注解 // 检查字段是否有db注解
columnName := field.Tag.Get("db") columnName := field.Tag.Get("db")
if columnName == "-" || columnName == "" { if columnName == "-" || columnName == "" {
continue continue
} }
if len(sr.Field2IndexCache[field.Name]) > 0 { sr.FieldIndexCache[field.Name] = []int{i}
return nil, fmt.Errorf("duplicate field [%s %s `db:%s`]", field.Name, field.Type.Name(), columnName) sr.FiledDBNameCache[field.Name] = columnName
}
sr.Field2IndexCache[field.Name] = append([]int{}, i)
sr.DBName2IndexCache[columnName] = append(sr.DBName2IndexCache[columnName], i)
sr.Filed2DBNameCache[field.Name] = columnName
// 检查字段是否有taos注解 // 检查字段是否有taos注解
if field.Tag.Get("taos") == "tag" { if field.Tag.Get("taos") == "tag" {
@@ -109,7 +122,7 @@ func getUniqueTypeName(t reflect.Type) string {
return uniqueTypeName return uniqueTypeName
} }
func getReflectTypeAndValue(data any) (reflect.Type, reflect.Value) { func getReflectTypeAndValue(data interface{}) (reflect.Type, reflect.Value) {
t := reflect.TypeOf(data) t := reflect.TypeOf(data)
v := reflect.ValueOf(data) v := reflect.ValueOf(data)

View File

@@ -1,19 +1,19 @@
package tdmap package tmapping
import ( import (
"sync" "sync"
) )
type SyncMap[T any, V any] struct { type Map[T any, V any] struct {
sMap sync.Map sMap sync.Map
} }
func (m *SyncMap[T, V]) Store(key T, value V) { func (m *Map[T, V]) Store(key T, value V) {
m.sMap.Store(key, value) m.sMap.Store(key, value)
} }
func (m *SyncMap[T, V]) Load(key T) (value V, ok bool) { func (m *Map[T, V]) Load(key T) (value V, ok bool) {
v, ok := m.sMap.Load(key) v, ok := m.sMap.Load(key)
if ok { if ok {
return v.(V), ok return v.(V), ok
@@ -21,17 +21,17 @@ func (m *SyncMap[T, V]) Load(key T) (value V, ok bool) {
return return
} }
func (m *SyncMap[T, V]) Delete(key T) { func (m *Map[T, V]) Delete(key T) {
m.sMap.Delete(key) m.sMap.Delete(key)
} }
func (m *SyncMap[T, V]) Range(f func(T, V) bool) { func (m *Map[T, V]) Range(f func(T, V) bool) {
m.sMap.Range(func(key, value any) bool { m.sMap.Range(func(key, value any) bool {
return f(key.(T), value.(V)) return f(key.(T), value.(V))
}) })
} }
func (m *SyncMap[T, V]) LoadOrStore(key T, value V) (actual V, loaded bool) { func (m *Map[T, V]) LoadOrStore(key T, value V) (actual V, loaded bool) {
_actual, loaded := m.sMap.LoadOrStore(key, value) _actual, loaded := m.sMap.LoadOrStore(key, value)
if loaded { if loaded {
actual = _actual.(V) actual = _actual.(V)

View File

@@ -1,4 +1,4 @@
package tdmap package tmapping
import ( import (
"log" "log"
@@ -6,7 +6,7 @@ import (
) )
func TestAA(t *testing.T) { func TestAA(t *testing.T) {
var m SyncMap[string, int] var m Map[string, int]
m.Store("a", 1234) m.Store("a", 1234)
value, _ := m.Load("a") value, _ := m.Load("a")

View File

@@ -1,4 +1,4 @@
package tdmap package tmapping
type TableRowMateria struct { type TableRowMateria struct {
SuperTableName string SuperTableName string
@@ -15,9 +15,8 @@ type TableRowMateria struct {
type StructMate struct { type StructMate struct {
UniqueTypeName string // 结构体的唯一标识符 UniqueTypeName string // 结构体的唯一标识符
DBName2IndexCache map[string][]int // db 注解的名称到索引的映射缓存 FieldIndexCache map[string][]int // 字段名到索引的映射缓存
Field2IndexCache map[string][]int // 字段名到索引的映射缓存 FiledDBNameCache map[string]string // 字段名到 db 注解的名称的映射缓存
Filed2DBNameCache map[string]string // 字段名到 db 注解的名称的映射缓存
DBAnnotatedNames []string // 包含 db 注解的 属性的名称 DBAnnotatedNames []string // 包含 db 注解的 属性的名称
TaggedFieldNames []string // 包含的 tag 注解的 属性的名称 TaggedFieldNames []string // 包含的 tag 注解的 属性的名称