-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathmanager.go
161 lines (134 loc) · 4.64 KB
/
manager.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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/*
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 (
"context"
"database/sql"
"github.com/go-juicedev/juice/session"
)
// Manager is an interface for managing database operations.
// It provides a high-level abstraction for executing SQL operations
// through the Object method which returns a SQLRowsExecutor.
type Manager interface {
Object(v any) SQLRowsExecutor
}
// NewGenericManager returns a new GenericManager.
func NewGenericManager[T any](manager Manager) *GenericManager[T] {
return &GenericManager[T]{Manager: manager}
}
// GenericManager is a generic manager for a specific type T
// that provides type-safe database operations.
type GenericManager[T any] struct {
Manager
}
// Object implements the GenericManager interface.
func (s *GenericManager[T]) Object(v any) Executor[T] {
exe := &GenericExecutor[T]{SQLRowsExecutor: s.Manager.Object(v)}
return exe
}
// TxManager is a transactional manager that extends the base Manager interface
// with transaction control capabilities. It provides methods for beginning,
// committing, and rolling back database transactions.
type TxManager interface {
Manager
// Begin begins a new database transaction.
// Returns an error if transaction is already started or if there's a database error.
Begin() error
// Commit commits the current transaction.
// Returns an error if there's no active transaction or if commit fails.
Commit() error
// Rollback aborts the current transaction.
// Returns an error if there's no active transaction or if rollback fails.
Rollback() error
}
// BasicTxManager implements the TxManager interface providing basic
// transaction management functionality.
type BasicTxManager struct {
// engine is the database engine instance that handles database operations
engine *Engine
// txOptions configures the transaction behavior
// If nil, default database transaction options are used
txOptions *sql.TxOptions
// tx holds the current transaction session
// It's nil if no transaction is active
tx session.TransactionSession
ctx context.Context
}
// Object implements the Manager interface
func (t *BasicTxManager) Object(v any) SQLRowsExecutor {
if t.tx == nil {
return inValidExecutor(session.ErrTransactionNotBegun)
}
statement, err := t.engine.GetConfiguration().GetStatement(v)
if err != nil {
return inValidExecutor(err)
}
drv := t.engine.Driver()
statementHandler := NewBatchStatementHandler(drv, t.tx, t.engine.middlewares...)
return NewSQLRowsExecutor(statement, statementHandler, drv)
}
// Begin begins the transaction
func (t *BasicTxManager) Begin() error {
// If the transaction is already begun, return an error directly.
if t.tx != nil {
return session.ErrTransactionAlreadyBegun
}
tx, err := t.engine.DB().BeginTx(t.ctx, t.txOptions)
if err != nil {
return err
}
t.tx = tx
return nil
}
// Commit commits the transaction
func (t *BasicTxManager) Commit() error {
// If the transaction is not begun, return an error directly.
if t.tx == nil {
return session.ErrTransactionNotBegun
}
return t.tx.Commit()
}
// Rollback rollbacks the transaction
func (t *BasicTxManager) Rollback() error {
// If the transaction is not begun, return an error directly.
if t.tx == nil {
return session.ErrTransactionNotBegun
}
return t.tx.Rollback()
}
func (t *BasicTxManager) Raw(query string) Runner {
if t.tx == nil {
return NewErrorRunner(session.ErrTransactionNotBegun)
}
return NewRunner(query, t.engine, t.tx)
}
type managerKey struct{}
// managerFromContext returns the Manager from the context.
func managerFromContext(ctx context.Context) (Manager, bool) {
manager, ok := ctx.Value(managerKey{}).(Manager)
return manager, ok
}
// ManagerFromContext returns the Manager from the context.
func ManagerFromContext(ctx context.Context) Manager {
manager, _ := managerFromContext(ctx)
return manager
}
// ContextWithManager returns a new context with the given Manager.
func ContextWithManager(ctx context.Context, manager Manager) context.Context {
return context.WithValue(ctx, managerKey{}, manager)
}
// IsTxManager returns true if the manager is a TxManager.
func IsTxManager(manager Manager) bool {
_, ok := manager.(TxManager)
return ok
}