-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patherrors.go
More file actions
212 lines (176 loc) · 8.56 KB
/
errors.go
File metadata and controls
212 lines (176 loc) · 8.56 KB
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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
package fluentsql
import (
"errors"
"fmt"
)
/*
================================================================================
📌 go-fluent-sql HATA YÖNETİM KATMANI
--------------------------------------------------------------------------------
Bu dosya, fluent SQL sorgulamayı amaçlayan yapının *en kritik merkezlerinden
biridir.* Modern ORM mantığında, hataların yalnızca oluşması değil — hangi
bağlamda, ne sebeple ve nasıl üretildiğinin izlenebilir olması gerekir. Tam da
bu nedenle; burada hem sabit hata tipleri (sentinel errors) hem de bağlam
taşıyabilen hata yapıları tanımlanmıştır.
Bu yaklaşım sayesinde geliştirici;
- nerede hata aldığını,
- hangi tablo üzerinde işlem yaptığını,
- hangi SQL çıktısının üretildiğini,
- hatanın asıl kaynağının ne olduğunu
net ve merkezi şekilde izleyebilir.
Özellikle `QueryError` ve `ValidationError` yapıları; Go’nun `errors.Is`,
`errors.As`, `Unwrap()` modelleriyle tam uyumlu tasarlanmıştır. Böylece
FluentSQL yalnızca bir query builder değil, aynı zamanda *profesyonel hata
izleme mimarisi* sunar.
Bu doküman şunları açıklar:
• Neden özel hata tipleri kullanıyoruz?
→ Her sorgu farklı bağlam taşır. Bağlamı kaybetmemek işletimsel teşhisi hızlandırır.
• Nasıl kullanıyoruz?
→ errors.Is(), errors.As(), context-wrap gibi Go standartlarına dayanarak.
• Bu tasarım ne kazandırır?
→ Şeffaflık, izlenebilirlik, debug kolaylığı ve kurumsal ölçek sürdürülebilirliği.
@author Ahmet ALTUN
@github github.com/biyonik
@linkedin linkedin.com/in/biyonik
@email ahmet.altun60@gmail.com
================================================================================
*/
// -------------------------------------------------------------------------------
// 🚨 Sabit Hata Tanımları (Sentinel Errors)
// -------------------------------------------------------------------------------
// Bu bölümde çatı seviyede paket hataları bulunur.
// errors.Is() ile doğrudan tespit edilmesi amaçlanmıştır.
// -------------------------------------------------------------------------------
// Sentinel errors for go-fluent-sql.
// These errors can be checked using errors.Is().
var (
// ErrNoRows is returned when a query returns no rows.
ErrNoRows = errors.New("fluentsql: no rows in result set")
// ErrNoTable is returned when no table is specified.
ErrNoTable = errors.New("fluentsql: no table specified")
// ErrNoColumns is returned when no columns are specified for insert/update.
ErrNoColumns = errors.New("fluentsql: no columns specified")
// ErrNoExecutor is returned when no database executor is set.
ErrNoExecutor = errors.New("fluentsql: no database executor")
// ErrInvalidIdentifier is returned for invalid SQL identifiers.
ErrInvalidIdentifier = errors.New("fluentsql: invalid identifier")
// ErrInvalidOperator is returned for disallowed operators.
ErrInvalidOperator = errors.New("fluentsql: invalid operator")
// ErrInvalidValue is returned for invalid values.
ErrInvalidValue = errors.New("fluentsql: invalid value")
// ErrNotAPointer is returned when dest is not a pointer.
ErrNotAPointer = errors.New("fluentsql: destination must be a pointer")
// ErrNotASlice is returned when dest is not a slice.
ErrNotASlice = errors.New("fluentsql: destination must be a slice")
// ErrNotAStruct is returned when dest element is not a struct.
ErrNotAStruct = errors.New("fluentsql: destination element must be a struct")
// ErrTxAlreadyClosed is returned when transaction is already committed/rolled back.
ErrTxAlreadyClosed = errors.New("fluentsql: transaction already closed")
// ErrEmptyBatch is returned when inserting empty batch.
ErrEmptyBatch = errors.New("fluentsql: cannot insert empty batch")
// ErrInconsistentBatch is returned when batch rows have different columns.
ErrInconsistentBatch = errors.New("fluentsql: inconsistent columns in batch")
// ErrEmptyWhereIn is returned when WhereIn is called with an empty slice.
ErrEmptyWhereIn = errors.New("fluentsql: empty slice passed to WhereIn")
// ErrInvalidBetweenValues is returned when WhereBetween doesn't receive exactly 2 values.
ErrInvalidBetweenValues = errors.New("fluentsql: BETWEEN requires exactly 2 values")
// ErrConnectionClosed is returned when trying to use a closed connection.
ErrConnectionClosed = errors.New("fluentsql: connection closed")
// ErrQueryTimeout is returned when a query exceeds the context deadline.
ErrQueryTimeout = errors.New("fluentsql: query timeout exceeded")
)
// -------------------------------------------------------------------------------
// 🏷 QueryError
// -------------------------------------------------------------------------------
// - Amaç: Sorgu işlemlerinde bağlam kaybı olmadan hata taşımak.
// - Neden var?: Hatanın "hangi tablo", "hangi operasyon", "hangi SQL çıktısı"
// ile ilişkili olduğunun tek bakışta anlaşılması gerekir.
// - Kullanım: `return &QueryError{ ... }` şeklinde veya `NewQueryError()` ile üretilir.
// errors.Unwrap() ile alt hata geri alınabilir.
// ------------------------------------------------------------------------------
type QueryError struct {
Op string // Operation: "select", "insert", "update", "delete", "compile"
Table string // Table name
SQL string // Generated SQL (sanitized, no actual values)
Err error // Underlying error
}
// Error implements the error interface.
// Bu fonksiyon hata mesajını okunabilir formatta döndürür.
// Eğer tablo adı mevcut ise → "select on table X" şeklinde detaylı yazılır.
func (e *QueryError) Error() string {
if e.Table != "" {
return fmt.Sprintf("fluentsql: %s on table %q: %v", e.Op, e.Table, e.Err)
}
return fmt.Sprintf("fluentsql: %s: %v", e.Op, e.Err)
}
// Unwrap returns the underlying error.
// Amaç: Go'nun error chain mekanizması ile hatanın köküne ulaşabilmek.
func (e *QueryError) Unwrap() error {
return e.Err
}
// NewQueryError creates a new QueryError with context.
// Bu yardımcı fonksiyon hata üretimini standartlaştırır; proje genelinde
// tek tip format ve izlenebilirlik sağlar.
func NewQueryError(op, table, sql string, err error) *QueryError {
return &QueryError{
Op: op,
Table: table,
SQL: sql,
Err: err,
}
}
// -------------------------------------------------------------------------------
// 🏷 ValidationError
// -------------------------------------------------------------------------------
// - Amaç: Identifier, operator veya value geçersiz olduğunda anlamlı geri dönüş üretmek.
// - Neden özel struct?: Çünkü bir hatanın yalnızca oluşması değil, *neden* oluştuğu
// da önemlidir. Örn: "identifier geçersiz" vs "value geçersiz" → farklı kök sebepler.
// - errors.Is() override edilmiştir, böylece ErrInvalidIdentifier gibi sabit
// hatalarla eşleştirilebilir.
// ------------------------------------------------------------------------------
type ValidationError struct {
Type string // "identifier", "operator", "value"
Value string // The invalid value
Reason string // Why it's invalid
}
// Error implements the error interface.
// Hatanın insan tarafından anlaşılabilir string halini döndürür.
func (e *ValidationError) Error() string {
return fmt.Sprintf("fluentsql: invalid %s %q: %s", e.Type, e.Value, e.Reason)
}
// Is allows errors.Is() to match against sentinel errors.
// Böylece errors.Is(err, ErrInvalidIdentifier) → true olabilir.
func (e *ValidationError) Is(target error) bool {
switch e.Type {
case "identifier":
return target == ErrInvalidIdentifier
case "operator":
return target == ErrInvalidOperator
case "value":
return target == ErrInvalidValue
default:
return false
}
}
// NewValidationError creates a new ValidationError.
// Kullanımı basitleştirilmiş factory fonksiyondur.
func NewValidationError(typ, value, reason string) *ValidationError {
return &ValidationError{
Type: typ,
Value: value,
Reason: reason,
}
}
// -------------------------------------------------------------------------------
// 🔄 WrapError
// -------------------------------------------------------------------------------
// Amaç: Operasyon ismiyle birlikte hata zinciri oluşturmak.
// Kullanım: return WrapError("insert", err)
// Sonuç: `fluentsql: insert: <wrapped error>` şeklinde takip edilebilir output üretir.
// ------------------------------------------------------------------------------
func WrapError(op string, err error) error {
if err == nil {
return nil
}
return fmt.Errorf("fluentsql: %s: %w", op, err)
}