-
Notifications
You must be signed in to change notification settings - Fork 8
/
binder.go
79 lines (67 loc) · 2.25 KB
/
binder.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
/*
Copyright 2023 eatmoreapple
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package juice
import (
"database/sql"
"reflect"
"time"
)
var (
// scannerType is the reflect.Type of sql.Scanner
// nolint:unused
scannerType = reflect.TypeOf((*sql.Scanner)(nil)).Elem()
// timeType is the reflect.Type of time.Time
timeType = reflect.TypeOf((*time.Time)(nil)).Elem()
)
// Bind sql.Rows to given entity with default mapper
func Bind[T any](rows *sql.Rows) (result T, err error) {
return BindWithResultMap[T](rows, nil)
}
func bindWithResultMap(rows *sql.Rows, v any, resultMap ResultMap) error {
if v == nil {
return ErrNilDestination
}
if rows == nil {
return ErrNilRows
}
// get reflect.Value of v
rv := reflect.ValueOf(v)
if rv.Kind() != reflect.Ptr {
return ErrPointerRequired
}
// get default mapper
if resultMap == nil {
if kd := reflect.Indirect(rv).Kind(); kd == reflect.Slice {
resultMap = MultiRowsResultMap{}
} else {
resultMap = SingleRowResultMap{}
}
}
return resultMap.MapTo(rv, rows)
}
// BindWithResultMap bind sql.Rows to given entity with given ResultMap
// bind cover sql.Rows to given entity
// dest can be a pointer to a struct, a pointer to a slice of struct, or a pointer to a slice of any type.
// rows won't be closed when the function returns.
func BindWithResultMap[T any](rows *sql.Rows, resultMap ResultMap) (result T, err error) {
// ptr is the pointer of the result, it is the destination of the binding.
var ptr any = &result
if _type := reflect.TypeOf(result); _type.Kind() == reflect.Ptr {
// if the result is a pointer, create a new instance of the element.
// you'd better not use a nil pointer as the result.
result = reflect.New(_type.Elem()).Interface().(T)
ptr = result
}
err = bindWithResultMap(rows, ptr, resultMap)
return
}