forked from fogfish/dynamo
/
schema.go
64 lines (53 loc) · 1.28 KB
/
schema.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
//
// Copyright (C) 2022 Dmitry Kolesnikov
//
// This file may be modified and distributed under the terms
// of the MIT license. See the LICENSE file for details.
// https://github.com/holmes89/dynamo
//
package s3
import (
"reflect"
"github.com/fogfish/golem/pure/hseq"
"github.com/holmes89/dynamo"
)
/*
Schema is utility that merges two struct
*/
type Schema[T dynamo.Thing] struct{ hseq.Seq[T] }
func NewSchema[T dynamo.Thing]() *Schema[T] {
return &Schema[T]{hseq.Generic[T]()}
}
func (schema Schema[T]) Merge(a, b T) (c T) {
va := reflect.ValueOf(a)
if va.Kind() == reflect.Pointer {
va = va.Elem()
}
vb := reflect.ValueOf(b)
if vb.Kind() == reflect.Pointer {
vb = vb.Elem()
}
// pointer to c makes reflect.ValueOf settable
// see The third law of reflection
// https://go.dev/blog/laws-of-reflection
vc := reflect.ValueOf(&c).Elem()
if vc.Kind() == reflect.Pointer {
// T is a pointer type, therefore c is nil
// it has to be filled with empty value before merging
empty := reflect.New(vc.Type().Elem())
vc.Set(empty)
vc = vc.Elem()
}
for _, f := range schema.Seq {
fa := va.FieldByIndex(f.Index)
fb := vb.FieldByIndex(f.Index)
fc := vc.FieldByIndex(f.Index)
switch {
case !fa.IsZero():
fc.Set(fa)
case !fb.IsZero():
fc.Set(fb)
}
}
return
}