You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
200 lines
5.1 KiB
200 lines
5.1 KiB
3 years ago
|
package schema
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"reflect"
|
||
|
"regexp"
|
||
|
"strings"
|
||
|
|
||
|
"gorm.io/gorm/clause"
|
||
|
"gorm.io/gorm/utils"
|
||
|
)
|
||
|
|
||
|
var embeddedCacheKey = "embedded_cache_store"
|
||
|
|
||
|
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
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return settings
|
||
|
}
|
||
|
|
||
|
func toColumns(val string) (results []string) {
|
||
|
if val != "" {
|
||
|
for _, v := range strings.Split(val, ",") {
|
||
|
results = append(results, strings.TrimSpace(v))
|
||
|
}
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
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
|
||
|
}
|
||
|
|
||
|
// GetRelationsValues get relations's values from a reflect value
|
||
|
func GetRelationsValues(ctx context.Context, reflectValue reflect.Value, rels []*Relationship) (reflectResults reflect.Value) {
|
||
|
for _, rel := range rels {
|
||
|
reflectResults = reflect.MakeSlice(reflect.SliceOf(reflect.PtrTo(rel.FieldSchema.ModelType)), 0, 1)
|
||
|
|
||
|
appendToResults := func(value reflect.Value) {
|
||
|
if _, isZero := rel.Field.ValueOf(ctx, value); !isZero {
|
||
|
result := reflect.Indirect(rel.Field.ReflectValueOf(ctx, value))
|
||
|
switch result.Kind() {
|
||
|
case reflect.Struct:
|
||
|
reflectResults = reflect.Append(reflectResults, result.Addr())
|
||
|
case reflect.Slice, reflect.Array:
|
||
|
for i := 0; i < result.Len(); i++ {
|
||
|
if elem := result.Index(i); elem.Kind() == reflect.Ptr {
|
||
|
reflectResults = reflect.Append(reflectResults, elem)
|
||
|
} else {
|
||
|
reflectResults = reflect.Append(reflectResults, elem.Addr())
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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{}) {
|
||
|
var (
|
||
|
results = [][]interface{}{}
|
||
|
dataResults = map[string][]reflect.Value{}
|
||
|
loaded = map[interface{}]bool{}
|
||
|
notZero, zero bool
|
||
|
)
|
||
|
|
||
|
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)
|
||
|
notZero = notZero || !zero
|
||
|
}
|
||
|
|
||
|
if !notZero {
|
||
|
return nil, nil
|
||
|
}
|
||
|
|
||
|
dataResults[utils.ToStringKey(results[0]...)] = []reflect.Value{reflectValue}
|
||
|
case reflect.Slice, reflect.Array:
|
||
|
for i := 0; i < reflectValue.Len(); i++ {
|
||
|
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
|
||
|
|
||
|
fieldValues := make([]interface{}, len(fields))
|
||
|
notZero = false
|
||
|
for idx, field := range fields {
|
||
|
fieldValues[idx], zero = field.ValueOf(ctx, elem)
|
||
|
notZero = notZero || !zero
|
||
|
}
|
||
|
|
||
|
if notZero {
|
||
|
dataKey := utils.ToStringKey(fieldValues...)
|
||
|
if _, ok := dataResults[dataKey]; !ok {
|
||
|
results = append(results, fieldValues)
|
||
|
dataResults[dataKey] = []reflect.Value{elem}
|
||
|
} else {
|
||
|
dataResults[dataKey] = append(dataResults[dataKey], elem)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return dataResults, results
|
||
|
}
|
||
|
|
||
|
// GetIdentityFieldValuesMapFromValues get identity map from fields
|
||
|
func GetIdentityFieldValuesMapFromValues(ctx context.Context, values []interface{}, fields []*Field) (map[string][]reflect.Value, [][]interface{}) {
|
||
|
resultsMap := map[string][]reflect.Value{}
|
||
|
results := [][]interface{}{}
|
||
|
|
||
|
for _, v := range values {
|
||
|
rm, rs := GetIdentityFieldValuesMap(ctx, reflect.Indirect(reflect.ValueOf(v)), fields)
|
||
|
for k, v := range rm {
|
||
|
resultsMap[k] = append(resultsMap[k], v...)
|
||
|
}
|
||
|
results = append(results, rs...)
|
||
|
}
|
||
|
return resultsMap, results
|
||
|
}
|
||
|
|
||
|
// ToQueryValues to query values
|
||
|
func ToQueryValues(table string, foreignKeys []string, foreignValues [][]interface{}) (interface{}, []interface{}) {
|
||
|
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}
|
||
|
}
|
||
|
|
||
|
for idx, r := range foreignValues {
|
||
|
queryValues[idx] = r
|
||
|
}
|
||
|
|
||
|
return columns, queryValues
|
||
|
}
|
||
|
|
||
|
type embeddedNamer struct {
|
||
|
Table string
|
||
|
Namer
|
||
|
}
|