/
Entities.go
101 lines (84 loc) · 2.12 KB
/
Entities.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package dbexts
import (
convenience "github.com/rafaelbfs/GoConvenience/Convenience"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"reflect"
"regexp"
"strings"
)
const (
SET = "$set"
BSON = "bson"
OID = "_id"
)
var HexRegex *regexp.Regexp
type ReflectiveGet[C comparable] func(v reflect.Value) C
func init() {
HexRegex = regexp.MustCompilePOSIX("^(0x|0X)?[a-fA-F0-9]+$")
}
type Entity struct {
}
func returnNil(err error) *primitive.ObjectID {
return nil
}
type UpdateFn func(d bson.D) (*mongo.UpdateResult, error)
func ToOID(id string) *primitive.ObjectID {
if !HexRegex.MatchString(id) {
return nil
}
r, err := primitive.ObjectIDFromHex(id)
return convenience.Try(&r, err).HandleErr(returnNil)
}
func emptyD() bson.D {
return bson.D{}
}
func ExtractValue(v reflect.Value) interface{} {
switch v.Type().Kind() {
case reflect.Bool:
return v.Bool()
case reflect.Int, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8:
return v.Int()
case reflect.Float64, reflect.Float32:
return v.Float()
}
return v.String()
}
func GetUpdate(ty reflect.Type, fieldName string, v1 reflect.Value, v2 reflect.Value) *bson.E {
if !ty.Comparable() || reflect.DeepEqual(v1.Interface(), v2.Interface()) {
return nil
}
return &bson.E{Key: fieldName, Value: ExtractValue(v2)}
}
func MakeUpdateStatements[A any](o A, n A) bson.D {
if reflect.TypeOf(o).Kind() != reflect.Struct {
return emptyD()
}
t := reflect.TypeOf(o)
updates := make(bson.D, 0, t.NumField()-1)
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
if !field.Type.Comparable() {
continue
}
var name = field.Name
if str, ok := field.Tag.Lookup(BSON); ok {
if strings.Contains(str, OID) {
continue
}
elements := strings.Split(str, ",")
if len(elements) > 0 {
name = elements[0]
}
}
v := GetUpdate(field.Type, name, reflect.ValueOf(o).Field(i), reflect.ValueOf(n).Field(i))
if v != nil {
updates = append(updates, *v)
}
}
return updates
}
func MkUpdateSetStatement[A any](o A, n A) bson.D {
return bson.D{{SET, MakeUpdateStatements(o, n)}}
}