forked from uptrace/bun
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhook.go
128 lines (103 loc) · 2.34 KB
/
hook.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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package bun
import (
"context"
"database/sql"
"reflect"
"strings"
"sync/atomic"
"time"
"github.com/uptrace/bun/schema"
)
type IQuery interface {
schema.QueryAppender
Operation() string
GetModel() Model
GetTableName() string
}
type QueryEvent struct {
DB *DB
QueryAppender schema.QueryAppender // Deprecated: use IQuery instead
IQuery IQuery
Query string
QueryArgs []interface{}
Model Model
StartTime time.Time
Result sql.Result
Err error
Stash map[interface{}]interface{}
}
func (e *QueryEvent) Operation() string {
if e.IQuery != nil {
return e.IQuery.Operation()
}
return queryOperation(e.Query)
}
func queryOperation(query string) string {
if idx := strings.IndexByte(query, ' '); idx > 0 {
query = query[:idx]
}
if len(query) > 16 {
query = query[:16]
}
return query
}
type QueryHook interface {
BeforeQuery(context.Context, *QueryEvent) context.Context
AfterQuery(context.Context, *QueryEvent)
}
func (db *DB) beforeQuery(
ctx context.Context,
iquery IQuery,
query string,
queryArgs []interface{},
model Model,
) (context.Context, *QueryEvent) {
atomic.AddUint32(&db.stats.Queries, 1)
if len(db.queryHooks) == 0 {
return ctx, nil
}
event := &QueryEvent{
DB: db,
Model: model,
QueryAppender: iquery,
IQuery: iquery,
Query: query,
QueryArgs: queryArgs,
StartTime: time.Now(),
}
for _, hook := range db.queryHooks {
ctx = hook.BeforeQuery(ctx, event)
}
return ctx, event
}
func (db *DB) afterQuery(
ctx context.Context,
event *QueryEvent,
res sql.Result,
err error,
) {
switch err {
case nil, sql.ErrNoRows:
// nothing
default:
atomic.AddUint32(&db.stats.Errors, 1)
}
if event == nil {
return
}
event.Result = res
event.Err = err
db.afterQueryFromIndex(ctx, event, len(db.queryHooks)-1)
}
func (db *DB) afterQueryFromIndex(ctx context.Context, event *QueryEvent, hookIndex int) {
for ; hookIndex >= 0; hookIndex-- {
db.queryHooks[hookIndex].AfterQuery(ctx, event)
}
}
//------------------------------------------------------------------------------
func callBeforeScanHook(ctx context.Context, v reflect.Value) error {
return v.Interface().(schema.BeforeScanHook).BeforeScan(ctx)
}
func callAfterScanHook(ctx context.Context, v reflect.Value) error {
return v.Interface().(schema.AfterScanHook).AfterScan(ctx)
}