gorm/schema/utils.go

209 lines
5.3 KiB
Go
Raw Normal View History

2020-01-31 07:22:37 +03:00
package schema
import (
"context"
"fmt"
2020-01-31 07:22:37 +03:00
"reflect"
2020-02-01 13:02:19 +03:00
"regexp"
2020-01-31 07:22:37 +03:00
"strings"
2020-05-18 08:07:11 +03:00
"gorm.io/gorm/clause"
2020-06-02 04:16:07 +03:00
"gorm.io/gorm/utils"
2020-01-31 07:22:37 +03:00
)
var embeddedCacheKey = "embedded_cache_store"
2020-02-21 19:02:05 +03:00
func ParseTagSetting(str string, sep string) map[string]string {
settings := map[string]string{}
names := strings.Split(str, sep)
for i := 0; i < len(names); i++ {
j := i
if len(names[j]) > 0 {
for {
if names[j][len(names[j])-1] == '\\' {
i++
names[j] = names[j][0:len(names[j])-1] + sep + names[i]
names[i] = ""
} else {
break
}
2020-01-31 07:22:37 +03:00
}
}
2020-02-21 19:02:05 +03:00
values := strings.Split(names[j], ":")
k := strings.TrimSpace(strings.ToUpper(values[0]))
if len(values) >= 2 {
settings[k] = strings.Join(values[1:], ":")
} else if k != "" {
settings[k] = k
}
2020-01-31 07:22:37 +03:00
}
2020-02-21 19:02:05 +03:00
return settings
2020-01-31 07:22:37 +03:00
}
func toColumns(val string) (results []string) {
if val != "" {
for _, v := range strings.Split(val, ",") {
results = append(results, strings.TrimSpace(v))
}
}
return
}
2020-02-01 13:02:19 +03:00
func removeSettingFromTag(tag reflect.StructTag, names ...string) reflect.StructTag {
for _, name := range names {
tag = reflect.StructTag(regexp.MustCompile(`(?i)(gorm:.*?)(`+name+`(:.*?)?)(;|("))`).ReplaceAllString(string(tag), "${1}${5}"))
}
return tag
2020-02-01 13:02:19 +03:00
}
2020-05-18 08:07:11 +03:00
func appendSettingFromTag(tag reflect.StructTag, value string) reflect.StructTag {
t := tag.Get("gorm")
if strings.Contains(t, value) {
return tag
}
return reflect.StructTag(fmt.Sprintf(`gorm:"%s;%s"`, value, t))
}
2020-05-18 08:07:11 +03:00
// GetRelationsValues get relations's values from a reflect value
func GetRelationsValues(ctx context.Context, reflectValue reflect.Value, rels []*Relationship) (reflectResults reflect.Value) {
2020-05-18 08:07:11 +03:00
for _, rel := range rels {
2020-11-10 13:38:24 +03:00
reflectResults = reflect.MakeSlice(reflect.SliceOf(reflect.PtrTo(rel.FieldSchema.ModelType)), 0, 1)
2020-05-18 08:07:11 +03:00
appendToResults := func(value reflect.Value) {
if _, isZero := rel.Field.ValueOf(ctx, value); !isZero {
result := reflect.Indirect(rel.Field.ReflectValueOf(ctx, value))
2020-05-18 08:07:11 +03:00
switch result.Kind() {
case reflect.Struct:
2020-05-23 19:52:25 +03:00
reflectResults = reflect.Append(reflectResults, result.Addr())
2020-05-18 08:07:11 +03:00
case reflect.Slice, reflect.Array:
2020-05-23 19:52:25 +03:00
for i := 0; i < result.Len(); i++ {
if elem := result.Index(i); elem.Kind() == reflect.Ptr {
reflectResults = reflect.Append(reflectResults, elem)
2020-05-23 19:52:25 +03:00
} else {
reflectResults = reflect.Append(reflectResults, elem.Addr())
2020-05-23 19:52:25 +03:00
}
2020-05-18 08:07:11 +03:00
}
}
}
}
switch reflectValue.Kind() {
case reflect.Struct:
appendToResults(reflectValue)
case reflect.Slice:
for i := 0; i < reflectValue.Len(); i++ {
appendToResults(reflectValue.Index(i))
}
}
reflectValue = reflectResults
}
return
}
// GetIdentityFieldValuesMap get identity map from fields
func GetIdentityFieldValuesMap(ctx context.Context, reflectValue reflect.Value, fields []*Field) (map[string][]reflect.Value, [][]interface{}) {
2020-05-18 08:07:11 +03:00
var (
2020-05-23 16:03:28 +03:00
results = [][]interface{}{}
dataResults = map[string][]reflect.Value{}
2020-06-01 19:44:48 +03:00
loaded = map[interface{}]bool{}
2020-05-23 16:03:28 +03:00
notZero, zero bool
2020-05-18 08:07:11 +03:00
)
switch reflectValue.Kind() {
case reflect.Struct:
results = [][]interface{}{make([]interface{}, len(fields))}
for idx, field := range fields {
results[0][idx], zero = field.ValueOf(ctx, reflectValue)
2020-05-23 16:03:28 +03:00
notZero = notZero || !zero
2020-05-18 08:07:11 +03:00
}
2020-05-23 16:03:28 +03:00
if !notZero {
return nil, nil
}
dataResults[utils.ToStringKey(results[0]...)] = []reflect.Value{reflectValue}
2020-05-18 08:07:11 +03:00
case reflect.Slice, reflect.Array:
for i := 0; i < reflectValue.Len(); i++ {
2020-06-01 19:44:48 +03:00
elem := reflectValue.Index(i)
elemKey := elem.Interface()
if elem.Kind() != reflect.Ptr {
elemKey = elem.Addr().Interface()
}
if _, ok := loaded[elemKey]; ok {
continue
}
loaded[elemKey] = true
2020-05-23 16:35:12 +03:00
fieldValues := make([]interface{}, len(fields))
2020-05-23 16:03:28 +03:00
notZero = false
2020-05-18 08:07:11 +03:00
for idx, field := range fields {
fieldValues[idx], zero = field.ValueOf(ctx, elem)
2020-05-23 16:03:28 +03:00
notZero = notZero || !zero
2020-05-18 08:07:11 +03:00
}
2020-05-23 16:03:28 +03:00
if notZero {
dataKey := utils.ToStringKey(fieldValues...)
if _, ok := dataResults[dataKey]; !ok {
results = append(results, fieldValues)
2020-06-01 19:44:48 +03:00
dataResults[dataKey] = []reflect.Value{elem}
2020-05-23 16:03:28 +03:00
} else {
2020-06-01 19:44:48 +03:00
dataResults[dataKey] = append(dataResults[dataKey], elem)
2020-05-18 08:07:11 +03:00
}
}
}
}
return dataResults, results
}
2020-05-19 21:03:43 +03:00
// GetIdentityFieldValuesMapFromValues get identity map from fields
func GetIdentityFieldValuesMapFromValues(ctx context.Context, values []interface{}, fields []*Field) (map[string][]reflect.Value, [][]interface{}) {
2020-05-19 21:03:43 +03:00
resultsMap := map[string][]reflect.Value{}
results := [][]interface{}{}
for _, v := range values {
rm, rs := GetIdentityFieldValuesMap(ctx, reflect.Indirect(reflect.ValueOf(v)), fields)
2020-05-19 21:03:43 +03:00
for k, v := range rm {
resultsMap[k] = append(resultsMap[k], v...)
}
results = append(results, rs...)
}
return resultsMap, results
}
2020-05-18 08:07:11 +03:00
// ToQueryValues to query values
func ToQueryValues(table string, foreignKeys []string, foreignValues [][]interface{}) (interface{}, []interface{}) {
2020-05-18 08:07:11 +03:00
queryValues := make([]interface{}, len(foreignValues))
if len(foreignKeys) == 1 {
for idx, r := range foreignValues {
queryValues[idx] = r[0]
}
return clause.Column{Table: table, Name: foreignKeys[0]}, queryValues
}
columns := make([]clause.Column, len(foreignKeys))
for idx, key := range foreignKeys {
columns[idx] = clause.Column{Table: table, Name: key}
2020-05-18 08:07:11 +03:00
}
for idx, r := range foreignValues {
queryValues[idx] = r
}
return columns, queryValues
2020-05-18 08:07:11 +03:00
}
type embeddedNamer struct {
Table string
Namer
}