70 lines
1.8 KiB
Go
70 lines
1.8 KiB
Go
package cassandra
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
|
|
"github.com/scylladb/gocqlx/v3/table"
|
|
)
|
|
|
|
// GenerateTableMetadata 根據傳入的 struct 產生 table.Metadata
|
|
func GenerateTableMetadata(document any, keyspace string) (table.Metadata, error) {
|
|
// 取得型別資訊,若是指標則取 Elem
|
|
t := reflect.TypeOf(document)
|
|
if t.Kind() == reflect.Ptr {
|
|
t = t.Elem()
|
|
}
|
|
|
|
// 取得表名稱:若 model 有實作 TableName() 則使用該方法,否則轉換型別名稱為 snake_case
|
|
var tableName string
|
|
if tm, ok := document.(interface{ TableName() string }); ok {
|
|
tableName = fmt.Sprintf("%s.%s", keyspace, tm.TableName())
|
|
} else {
|
|
return table.Metadata{}, fmt.Errorf("failed to get table func")
|
|
}
|
|
|
|
columns := make([]string, 0, t.NumField())
|
|
partKeys := make([]string, 0, t.NumField())
|
|
sortKeys := make([]string, 0, t.NumField())
|
|
|
|
// 遍歷所有 exported 欄位
|
|
for i := 0; i < t.NumField(); i++ {
|
|
field := t.Field(i)
|
|
// 跳過 unexported 欄位
|
|
if field.PkgPath != "" {
|
|
continue
|
|
}
|
|
// 如果欄位有標記 db:"-" 則跳過
|
|
if tag := field.Tag.Get("db"); tag == "-" {
|
|
continue
|
|
}
|
|
// 取得欄位名稱
|
|
colName := field.Tag.Get("db")
|
|
if colName == "" {
|
|
colName = toSnakeCase(field.Name)
|
|
}
|
|
columns = append(columns, colName)
|
|
// 若有 partition:"true" 標記,加入 PartKey
|
|
if field.Tag.Get("partition_key") == "true" {
|
|
partKeys = append(partKeys, colName)
|
|
}
|
|
// 若有 sort:"true" 標記,加入 SortKey
|
|
if field.Tag.Get("clustering_key") == "true" {
|
|
sortKeys = append(sortKeys, colName)
|
|
}
|
|
}
|
|
if len(partKeys) == 0 {
|
|
return table.Metadata{}, fmt.Errorf("no partition key defined in struct")
|
|
}
|
|
|
|
// 組合 Metadata
|
|
meta := table.Metadata{
|
|
Name: tableName,
|
|
Columns: columns,
|
|
PartKey: partKeys,
|
|
SortKey: sortKeys,
|
|
}
|
|
|
|
return meta, nil
|
|
}
|