@onurege3467/zerohelper 7.1.0 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +762 -0
- package/database/IDatabase.js +18 -0
- package/database/cacheWrapper.js +526 -62
- package/database/index.js +9 -2
- package/database/json.js +59 -0
- package/database/migration.js +227 -0
- package/database/mongodb.js +45 -0
- package/database/mysql.js +61 -0
- package/database/pg.js +64 -0
- package/database/redis.js +342 -0
- package/database/sqlite.js +69 -0
- package/functions/index.js +267 -0
- package/package.json +11 -7
- package/.snapshots/config.json +0 -151
- package/.snapshots/readme.md +0 -11
- package/.snapshots/sponsors.md +0 -44
- package/1.json +0 -15
- package/readme.md +0 -418
- package/test.js +0 -261
- package/test_mysqlonly.js +0 -144
package/database/IDatabase.js
CHANGED
|
@@ -61,6 +61,24 @@ class IDatabase {
|
|
|
61
61
|
*/
|
|
62
62
|
bulkInsert(table, dataArray) {}
|
|
63
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Numerik alanları artırır (increment).
|
|
66
|
+
* @param {string} table - Verinin güncelleneceği tablo veya koleksiyonun adı.
|
|
67
|
+
* @param {object} increments - Artırılacak alanlar ve miktarları (örn: { views: 1, likes: 2 }).
|
|
68
|
+
* @param {object} where - Hangi kayıtların güncelleneceğini belirleyen koşul nesnesi.
|
|
69
|
+
* @returns {Promise<number>} Etkilenen kayıt sayısını içeren bir Promise.
|
|
70
|
+
*/
|
|
71
|
+
increment(table, increments, where) {}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Numerik alanları azaltır (decrement).
|
|
75
|
+
* @param {string} table - Verinin güncelleneceği tablo veya koleksiyonun adı.
|
|
76
|
+
* @param {object} decrements - Azaltılacak alanlar ve miktarları (örn: { stock: 1, count: 5 }).
|
|
77
|
+
* @param {object} where - Hangi kayıtların güncelleneceğini belirleyen koşul nesnesi.
|
|
78
|
+
* @returns {Promise<number>} Etkilenen kayıt sayısını içeren bir Promise.
|
|
79
|
+
*/
|
|
80
|
+
decrement(table, decrements, where) {}
|
|
81
|
+
|
|
64
82
|
/**
|
|
65
83
|
* Veritabanı bağlantısını güvenli bir şekilde sonlandırır.
|
|
66
84
|
* @returns {Promise<void>}
|
package/database/cacheWrapper.js
CHANGED
|
@@ -1,120 +1,584 @@
|
|
|
1
|
+
// cacheWrapper.js - Redis@4 ve Memory Cache Uyumlu (Düzeltilmiş)
|
|
1
2
|
const { LRUCache } = require('lru-cache');
|
|
3
|
+
const { createClient } = require('redis');
|
|
2
4
|
|
|
3
5
|
class CacheWrapper {
|
|
4
6
|
constructor(databaseInstance, options = {}) {
|
|
5
7
|
this.db = databaseInstance;
|
|
8
|
+
this.cacheType = options.type || 'memory'; // 'memory' or 'redis'
|
|
9
|
+
this.tableCaches = {};
|
|
10
|
+
|
|
11
|
+
// Redis client için başlangıç değerleri
|
|
12
|
+
this.redisClient = null;
|
|
13
|
+
this.redisAvailable = false;
|
|
14
|
+
|
|
15
|
+
if (this.cacheType === 'redis') {
|
|
16
|
+
this._initRedisCache(options);
|
|
17
|
+
} else {
|
|
18
|
+
this._initMemoryCache(options);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
_initMemoryCache(options) {
|
|
6
23
|
this.cache = new LRUCache({
|
|
7
|
-
max: options.max || 500,
|
|
8
|
-
ttl: options.ttl || 1000 * 60 * 5, //
|
|
9
|
-
updateAgeOnGet: options.updateAgeOnGet
|
|
24
|
+
max: options.max || 500,
|
|
25
|
+
ttl: options.ttl || 1000 * 60 * 5, // milliseconds
|
|
26
|
+
updateAgeOnGet: options.updateAgeOnGet || false,
|
|
10
27
|
});
|
|
11
|
-
this.
|
|
28
|
+
this.redisAvailable = false;
|
|
29
|
+
this.redisClient = null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async _initRedisCache(options) {
|
|
33
|
+
const redisConfig = {
|
|
34
|
+
socket: {
|
|
35
|
+
host: options.host || '127.0.0.1',
|
|
36
|
+
port: options.port || 6379,
|
|
37
|
+
connectTimeout: options.connectTimeout || 5000,
|
|
38
|
+
},
|
|
39
|
+
password: options.password,
|
|
40
|
+
database: options.db || 0,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
this.redisClient = createClient(redisConfig);
|
|
44
|
+
this.ttl = options.ttl || 300; // 5 dakika (saniye cinsinden)
|
|
45
|
+
this.keyPrefix = options.keyPrefix || 'db_cache:';
|
|
46
|
+
this.redisAvailable = false;
|
|
47
|
+
|
|
48
|
+
this.redisClient.on('error', (err) => {
|
|
49
|
+
console.warn('Redis Cache Error, memory cache fallback:', err.message);
|
|
50
|
+
this.redisAvailable = false;
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
this.redisClient.on('connect', () => {
|
|
54
|
+
console.log('Redis Cache Connected');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
this.redisClient.on('ready', () => {
|
|
58
|
+
console.log('Redis Cache Ready');
|
|
59
|
+
this.redisAvailable = true;
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
this.redisClient.on('end', () => {
|
|
63
|
+
console.log('Redis Cache Disconnected');
|
|
64
|
+
this.redisAvailable = false;
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
await Promise.race([
|
|
69
|
+
this.redisClient.connect(),
|
|
70
|
+
new Promise((_, reject) =>
|
|
71
|
+
setTimeout(() => reject(new Error('Redis connection timeout')), 5000)
|
|
72
|
+
),
|
|
73
|
+
]);
|
|
74
|
+
this.redisAvailable = true;
|
|
75
|
+
} catch (error) {
|
|
76
|
+
console.warn('Redis bağlantısı başarısız, memory cache kullanılacak:', error.message);
|
|
77
|
+
this._initMemoryCache(options);
|
|
78
|
+
if (this.redisClient) {
|
|
79
|
+
this.redisClient.removeAllListeners();
|
|
80
|
+
this.redisClient = null;
|
|
81
|
+
}
|
|
82
|
+
this.redisAvailable = false;
|
|
83
|
+
}
|
|
12
84
|
}
|
|
13
85
|
|
|
14
86
|
_getCache(table) {
|
|
87
|
+
if (this.cacheType === 'redis' && this.redisAvailable && this.redisClient) {
|
|
88
|
+
return this.redisClient;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Memory fallback - tablo bazlı cache oluştur
|
|
15
92
|
if (!this.tableCaches[table]) {
|
|
16
93
|
this.tableCaches[table] = new LRUCache({
|
|
17
|
-
max: this.cache.max,
|
|
18
|
-
ttl: this.cache.ttl,
|
|
19
|
-
updateAgeOnGet: this.cache.updateAgeOnGet,
|
|
94
|
+
max: this.cache ? this.cache.max : 500,
|
|
95
|
+
ttl: this.cache ? this.cache.ttl : 300000,
|
|
96
|
+
updateAgeOnGet: this.cache ? this.cache.updateAgeOnGet : false,
|
|
20
97
|
});
|
|
21
98
|
}
|
|
22
99
|
return this.tableCaches[table];
|
|
23
100
|
}
|
|
24
101
|
|
|
25
102
|
_generateKey(table, where) {
|
|
26
|
-
|
|
103
|
+
const sortedWhere = where ? this._sortObject(where) : {};
|
|
104
|
+
const key = `${table}:${JSON.stringify(sortedWhere)}`;
|
|
105
|
+
return this.cacheType === 'redis' ? `${this.keyPrefix}${key}` : key;
|
|
27
106
|
}
|
|
28
107
|
|
|
29
|
-
//
|
|
30
|
-
|
|
108
|
+
// Where objelerini sıralama (tutarlı key oluşturma için)
|
|
109
|
+
_sortObject(obj) {
|
|
110
|
+
if (!obj || typeof obj !== 'object') return obj;
|
|
111
|
+
return Object.keys(obj)
|
|
112
|
+
.sort()
|
|
113
|
+
.reduce((sorted, key) => {
|
|
114
|
+
sorted[key] = obj[key];
|
|
115
|
+
return sorted;
|
|
116
|
+
}, {});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async _getCacheValue(cache, key, table) {
|
|
120
|
+
if (this.cacheType === 'redis' && this.redisAvailable && this.redisClient) {
|
|
121
|
+
try {
|
|
122
|
+
const value = await cache.get(key);
|
|
123
|
+
return value ? JSON.parse(value) : null;
|
|
124
|
+
} catch (err) {
|
|
125
|
+
console.warn('Redis get error, memory fallback:', err.message);
|
|
126
|
+
this.redisAvailable = false;
|
|
127
|
+
// Memory cache'e geçiş yap
|
|
128
|
+
const memoryCache = this._getCache(table);
|
|
129
|
+
return memoryCache.get(key);
|
|
130
|
+
}
|
|
131
|
+
} else {
|
|
132
|
+
return cache.get(key);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async _setCacheValue(cache, key, value, table) {
|
|
137
|
+
if (this.cacheType === 'redis' && this.redisAvailable && this.redisClient) {
|
|
138
|
+
try {
|
|
139
|
+
await cache.setEx(key, this.ttl, JSON.stringify(value));
|
|
140
|
+
} catch (err) {
|
|
141
|
+
console.warn('Redis set error, memory fallback:', err.message);
|
|
142
|
+
this.redisAvailable = false;
|
|
143
|
+
// Memory cache'e geçiş yap
|
|
144
|
+
const memoryCache = this._getCache(table);
|
|
145
|
+
memoryCache.set(key, value);
|
|
146
|
+
}
|
|
147
|
+
} else {
|
|
148
|
+
cache.set(key, value);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async _clearCache(table) {
|
|
153
|
+
if (this.cacheType === 'redis' && this.redisAvailable && this.redisClient) {
|
|
154
|
+
try {
|
|
155
|
+
const keys = await this.redisClient.keys(`${this.keyPrefix}${table}:*`);
|
|
156
|
+
if (keys.length) await this.redisClient.del(keys);
|
|
157
|
+
} catch (err) {
|
|
158
|
+
console.warn('Redis clear error, memory fallback:', err.message);
|
|
159
|
+
this.redisAvailable = false;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Memory cache'i de temizle
|
|
164
|
+
if (this.tableCaches[table]) {
|
|
165
|
+
this.tableCaches[table].clear();
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Belirli bir cache key'i sil
|
|
170
|
+
async _deleteCacheKey(table, key) {
|
|
171
|
+
if (this.cacheType === 'redis' && this.redisAvailable && this.redisClient) {
|
|
172
|
+
try {
|
|
173
|
+
await this.redisClient.del(`${this.keyPrefix}${table}:${key}`);
|
|
174
|
+
} catch (err) {
|
|
175
|
+
console.warn('Redis delete key error:', err.message);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Memory cache'ten de sil
|
|
31
180
|
const cache = this._getCache(table);
|
|
32
|
-
|
|
33
|
-
|
|
181
|
+
if (cache && cache.delete) {
|
|
182
|
+
cache.delete(key);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
34
185
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
186
|
+
// Cache'teki veriyi güncelle
|
|
187
|
+
async _updateCacheValue(table, key, newData) {
|
|
188
|
+
const cache = this._getCache(table);
|
|
189
|
+
if (newData !== null && newData !== undefined) {
|
|
190
|
+
await this._setCacheValue(cache, key, newData, table);
|
|
191
|
+
} else {
|
|
192
|
+
await this._deleteCacheKey(table, key);
|
|
38
193
|
}
|
|
194
|
+
}
|
|
39
195
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
196
|
+
// Where koşuluna uyan tüm cache key'lerini bul ve güncelle/sil
|
|
197
|
+
async _updateCacheByWhere(table, where, newData = null) {
|
|
198
|
+
// Eğer where boşsa veya çok karmaşıksa, cache'i tamamen temizle
|
|
199
|
+
if (!where || Object.keys(where).length === 0) {
|
|
200
|
+
await this._clearCache(table);
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Redis için
|
|
205
|
+
if (this.cacheType === 'redis' && this.redisAvailable && this.redisClient) {
|
|
206
|
+
try {
|
|
207
|
+
const keys = await this.redisClient.keys(`${this.keyPrefix}${table}:*`);
|
|
208
|
+
for (const fullKey of keys) {
|
|
209
|
+
const cacheData = await this.redisClient.get(fullKey);
|
|
210
|
+
if (cacheData) {
|
|
211
|
+
try {
|
|
212
|
+
const parsedData = JSON.parse(cacheData);
|
|
213
|
+
// Eğer cached data where koşuluna uyuyorsa güncelle/sil
|
|
214
|
+
if (this._matchesWhere(parsedData, where)) {
|
|
215
|
+
if (newData) {
|
|
216
|
+
await this.redisClient.setEx(fullKey, this.ttl, JSON.stringify(newData));
|
|
217
|
+
} else {
|
|
218
|
+
await this.redisClient.del(fullKey);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
} catch (parseErr) {
|
|
222
|
+
// Parse edilemeyen veriyi sil
|
|
223
|
+
await this.redisClient.del(fullKey);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
} catch (err) {
|
|
228
|
+
console.warn('Redis update by where error:', err.message);
|
|
229
|
+
// Hata durumunda cache'i temizle
|
|
230
|
+
await this._clearCache(table);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Memory cache için
|
|
235
|
+
const cache = this._getCache(table);
|
|
236
|
+
if (cache && cache.forEach) {
|
|
237
|
+
const keysToUpdate = [];
|
|
238
|
+
const keysToDelete = [];
|
|
239
|
+
|
|
240
|
+
cache.forEach((value, key) => {
|
|
241
|
+
try {
|
|
242
|
+
if (this._matchesWhere(value, where)) {
|
|
243
|
+
if (newData) {
|
|
244
|
+
keysToUpdate.push({ key, data: newData });
|
|
245
|
+
} else {
|
|
246
|
+
keysToDelete.push(key);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
} catch (err) {
|
|
250
|
+
// Hatalı veriyi sil
|
|
251
|
+
keysToDelete.push(key);
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
// Güncellemeleri uygula
|
|
256
|
+
keysToUpdate.forEach(({ key, data }) => {
|
|
257
|
+
cache.set(key, data);
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
keysToDelete.forEach(key => {
|
|
261
|
+
cache.delete(key);
|
|
262
|
+
});
|
|
263
|
+
}
|
|
44
264
|
}
|
|
45
265
|
|
|
46
|
-
|
|
266
|
+
// Basit where matching (nested object desteği ile)
|
|
267
|
+
_matchesWhere(data, where) {
|
|
268
|
+
if (!data || !where) return false;
|
|
269
|
+
|
|
270
|
+
for (const [key, value] of Object.entries(where)) {
|
|
271
|
+
if (data[key] !== value) {
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return true;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Read Operations
|
|
279
|
+
async select(table, where) {
|
|
47
280
|
const cache = this._getCache(table);
|
|
48
281
|
const key = this._generateKey(table, where);
|
|
49
|
-
let data =
|
|
282
|
+
let data = await this._getCacheValue(cache, key, table);
|
|
283
|
+
if (data !== null && data !== undefined) return data;
|
|
50
284
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
285
|
+
data = await this.db.select(table, where);
|
|
286
|
+
if (data !== null && data !== undefined) {
|
|
287
|
+
await this._setCacheValue(cache, key, data, table);
|
|
54
288
|
}
|
|
289
|
+
return data;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
async selectOne(table, where) {
|
|
293
|
+
const cache = this._getCache(table);
|
|
294
|
+
const key = this._generateKey(table + '_one', where); // selectOne için farklı key
|
|
295
|
+
let data = await this._getCacheValue(cache, key, table);
|
|
296
|
+
if (data !== null && data !== undefined) return data;
|
|
55
297
|
|
|
56
|
-
// console.log(`Cache miss for selectOne: ${key}`);
|
|
57
298
|
data = await this.db.selectOne(table, where);
|
|
58
|
-
|
|
299
|
+
if (data !== null && data !== undefined) {
|
|
300
|
+
await this._setCacheValue(cache, key, data, table);
|
|
301
|
+
}
|
|
59
302
|
return data;
|
|
60
303
|
}
|
|
61
304
|
|
|
62
|
-
// Write
|
|
305
|
+
// Write Operations (smart cache management)
|
|
63
306
|
async insert(table, data) {
|
|
64
|
-
this.
|
|
65
|
-
|
|
307
|
+
const result = await this.db.insert(table, data);
|
|
308
|
+
|
|
309
|
+
// Insert için cache'i tamamen temizlemek yerine, sadece genel sorguları temizle
|
|
310
|
+
// Çünkü yeni veri eklendiğinde select() sonuçları değişebilir
|
|
311
|
+
await this._clearCache(table);
|
|
312
|
+
|
|
313
|
+
return result;
|
|
66
314
|
}
|
|
67
315
|
|
|
68
316
|
async update(table, data, where) {
|
|
69
|
-
this.
|
|
70
|
-
|
|
317
|
+
const result = await this.db.update(table, data, where);
|
|
318
|
+
|
|
319
|
+
if (result > 0) {
|
|
320
|
+
// Güncellenen verileri cache'te de güncelle
|
|
321
|
+
await this._updateCacheByWhere(table, where, null); // Önce sil
|
|
322
|
+
|
|
323
|
+
// Güncellenen veriyi cache'e eklemek için fresh data'yı al
|
|
324
|
+
try {
|
|
325
|
+
const updatedData = await this.db.selectOne(table, where);
|
|
326
|
+
if (updatedData) {
|
|
327
|
+
// selectOne cache'ine ekle
|
|
328
|
+
const cache = this._getCache(table);
|
|
329
|
+
const key = this._generateKey(table + '_one', where);
|
|
330
|
+
await this._setCacheValue(cache, key, updatedData, table);
|
|
331
|
+
}
|
|
332
|
+
} catch (err) {
|
|
333
|
+
// Hata durumunda cache'i temizle
|
|
334
|
+
await this._clearCache(table);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
return result;
|
|
71
339
|
}
|
|
72
340
|
|
|
73
341
|
async set(table, data, where) {
|
|
74
|
-
this.
|
|
75
|
-
|
|
342
|
+
const result = await this.db.set(table, data, where);
|
|
343
|
+
|
|
344
|
+
// Set operasyonu için güncellenmiş/eklenen veriyi cache'e al
|
|
345
|
+
try {
|
|
346
|
+
const newData = await this.db.selectOne(table, where);
|
|
347
|
+
if (newData) {
|
|
348
|
+
// Cache'teki eski veriyi güncelle
|
|
349
|
+
const cache = this._getCache(table);
|
|
350
|
+
const key = this._generateKey(table + '_one', where);
|
|
351
|
+
await this._setCacheValue(cache, key, newData, table);
|
|
352
|
+
|
|
353
|
+
// Select cache'lerini de güncelle (where koşuluna uyarsa)
|
|
354
|
+
await this._updateCacheByWhere(table, where, null); // Eski cache'leri temizle
|
|
355
|
+
}
|
|
356
|
+
} catch (err) {
|
|
357
|
+
// Hata durumunda cache'i temizle
|
|
358
|
+
await this._clearCache(table);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
return result;
|
|
76
362
|
}
|
|
77
363
|
|
|
78
364
|
async delete(table, where) {
|
|
79
|
-
this.
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
365
|
+
const result = await this.db.delete(table, where);
|
|
366
|
+
|
|
367
|
+
if (result > 0) {
|
|
368
|
+
// Silinen verileri cache'ten de sil
|
|
369
|
+
await this._updateCacheByWhere(table, where, null);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
return result;
|
|
86
373
|
}
|
|
87
374
|
|
|
88
375
|
async deleteOne(table, where) {
|
|
89
|
-
this.
|
|
90
|
-
|
|
376
|
+
const result = await this.db.deleteOne(table, where);
|
|
377
|
+
|
|
378
|
+
if (result > 0) {
|
|
379
|
+
// Silinen veriyi cache'ten de sil
|
|
380
|
+
await this._updateCacheByWhere(table, where, null);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
return result;
|
|
91
384
|
}
|
|
92
385
|
|
|
93
386
|
async updateOne(table, data, where) {
|
|
94
|
-
this.
|
|
95
|
-
|
|
387
|
+
const result = await this.db.updateOne(table, data, where);
|
|
388
|
+
|
|
389
|
+
if (result > 0) {
|
|
390
|
+
// Güncellenen veriyi cache'te de güncelle
|
|
391
|
+
try {
|
|
392
|
+
const updatedData = await this.db.selectOne(table, where);
|
|
393
|
+
if (updatedData) {
|
|
394
|
+
const cache = this._getCache(table);
|
|
395
|
+
const key = this._generateKey(table + '_one', where);
|
|
396
|
+
await this._setCacheValue(cache, key, updatedData, table);
|
|
397
|
+
}
|
|
398
|
+
} catch (err) {
|
|
399
|
+
// Hata durumunda ilgili cache'leri temizle
|
|
400
|
+
await this._updateCacheByWhere(table, where, null);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
return result;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
async bulkInsert(table, dataArray) {
|
|
408
|
+
const result = await this.db.bulkInsert(table, dataArray);
|
|
409
|
+
|
|
410
|
+
// Bulk insert için cache'i tamamen temizle
|
|
411
|
+
// Çünkü çok sayıda yeni veri eklendiğinde select sonuçları değişir
|
|
412
|
+
await this._clearCache(table);
|
|
413
|
+
|
|
414
|
+
return result;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
async clearAllCache() {
|
|
418
|
+
if (this.cacheType === 'redis' && this.redisAvailable && this.redisClient) {
|
|
419
|
+
try {
|
|
420
|
+
const keys = await this.redisClient.keys(`${this.keyPrefix}*`);
|
|
421
|
+
if (keys.length) await this.redisClient.del(keys);
|
|
422
|
+
} catch (err) {
|
|
423
|
+
console.warn('Redis clearAll error:', err.message);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// Tüm memory cache'leri temizle
|
|
428
|
+
Object.values(this.tableCaches).forEach(c => c.clear());
|
|
429
|
+
if (this.cache) this.cache.clear();
|
|
430
|
+
this.tableCaches = {}; // Referansları da temizle
|
|
96
431
|
}
|
|
97
432
|
|
|
98
|
-
// Pass-through for other methods (e.g., close, ensureTable, query for MySQL/SQLite)
|
|
99
433
|
async close() {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
434
|
+
await this.clearAllCache();
|
|
435
|
+
if (this.redisClient) {
|
|
436
|
+
try {
|
|
437
|
+
this.redisClient.removeAllListeners();
|
|
438
|
+
if (this.redisAvailable && this.redisClient.isOpen) {
|
|
439
|
+
await this.redisClient.quit();
|
|
440
|
+
} else if (this.redisClient.isOpen) {
|
|
441
|
+
await this.redisClient.disconnect();
|
|
442
|
+
}
|
|
443
|
+
} catch (err) {
|
|
444
|
+
console.warn('Redis close error:', err.message);
|
|
445
|
+
}
|
|
446
|
+
this.redisClient = null;
|
|
447
|
+
this.redisAvailable = false;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// Database bağlantısını kapat
|
|
451
|
+
if (this.db && typeof this.db.close === 'function') {
|
|
452
|
+
return this.db.close();
|
|
117
453
|
}
|
|
454
|
+
return Promise.resolve();
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Numerik alanları artırır (increment) ve cache'i akıllıca günceller.
|
|
459
|
+
* @param {string} table - Verinin güncelleneceği tablo adı.
|
|
460
|
+
* @param {object} increments - Artırılacak alanlar ve miktarları.
|
|
461
|
+
* @param {object} where - Güncelleme koşulları.
|
|
462
|
+
* @returns {Promise<number>} Etkilenen kayıt sayısı.
|
|
463
|
+
*/
|
|
464
|
+
async increment(table, increments, where = {}) {
|
|
465
|
+
const result = await this.db.increment(table, increments, where);
|
|
466
|
+
|
|
467
|
+
if (result > 0) {
|
|
468
|
+
// Cache'teki değerleri de increment et
|
|
469
|
+
await this._incrementCacheValues(table, increments, where);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
return result;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Numerik alanları azaltır (decrement) ve cache'i akıllıca günceller.
|
|
477
|
+
* @param {string} table - Verinin güncelleneceği tablo adı.
|
|
478
|
+
* @param {object} decrements - Azaltılacak alanlar ve miktarları.
|
|
479
|
+
* @param {object} where - Güncelleme koşulları.
|
|
480
|
+
* @returns {Promise<number>} Etkilenen kayıt sayısı.
|
|
481
|
+
*/
|
|
482
|
+
async decrement(table, decrements, where = {}) {
|
|
483
|
+
const result = await this.db.decrement(table, decrements, where);
|
|
484
|
+
|
|
485
|
+
if (result > 0) {
|
|
486
|
+
// Cache'teki değerleri de decrement et
|
|
487
|
+
const negativeIncrements = {};
|
|
488
|
+
for (const [key, value] of Object.entries(decrements)) {
|
|
489
|
+
negativeIncrements[key] = -value;
|
|
490
|
+
}
|
|
491
|
+
await this._incrementCacheValues(table, negativeIncrements, where);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
return result;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// Cache'teki numerik değerleri increment/decrement et
|
|
498
|
+
async _incrementCacheValues(table, increments, where) {
|
|
499
|
+
// Redis için
|
|
500
|
+
if (this.cacheType === 'redis' && this.redisAvailable && this.redisClient) {
|
|
501
|
+
try {
|
|
502
|
+
const keys = await this.redisClient.keys(`${this.keyPrefix}${table}:*`);
|
|
503
|
+
for (const fullKey of keys) {
|
|
504
|
+
const cacheData = await this.redisClient.get(fullKey);
|
|
505
|
+
if (cacheData) {
|
|
506
|
+
try {
|
|
507
|
+
const parsedData = JSON.parse(cacheData);
|
|
508
|
+
if (this._matchesWhere(parsedData, where)) {
|
|
509
|
+
// Cache'teki değerleri increment et
|
|
510
|
+
const updatedData = { ...parsedData };
|
|
511
|
+
for (const [field, increment] of Object.entries(increments)) {
|
|
512
|
+
if (typeof updatedData[field] === 'number') {
|
|
513
|
+
updatedData[field] += increment;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
await this.redisClient.setEx(fullKey, this.ttl, JSON.stringify(updatedData));
|
|
517
|
+
}
|
|
518
|
+
} catch (parseErr) {
|
|
519
|
+
// Parse edilemeyen veriyi sil
|
|
520
|
+
await this.redisClient.del(fullKey);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
} catch (err) {
|
|
525
|
+
console.warn('Redis increment cache error:', err.message);
|
|
526
|
+
// Hata durumunda cache'i temizle
|
|
527
|
+
await this._clearCache(table);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// Memory cache için
|
|
532
|
+
const cache = this._getCache(table);
|
|
533
|
+
if (cache && cache.forEach) {
|
|
534
|
+
const keysToUpdate = [];
|
|
535
|
+
|
|
536
|
+
cache.forEach((value, key) => {
|
|
537
|
+
try {
|
|
538
|
+
if (this._matchesWhere(value, where)) {
|
|
539
|
+
const updatedData = { ...value };
|
|
540
|
+
for (const [field, increment] of Object.entries(increments)) {
|
|
541
|
+
if (typeof updatedData[field] === 'number') {
|
|
542
|
+
updatedData[field] += increment;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
keysToUpdate.push({ key, data: updatedData });
|
|
546
|
+
}
|
|
547
|
+
} catch (err) {
|
|
548
|
+
// Hatalı veriyi sil
|
|
549
|
+
cache.delete(key);
|
|
550
|
+
}
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
// Güncellemeleri uygula
|
|
554
|
+
keysToUpdate.forEach(({ key, data }) => {
|
|
555
|
+
cache.set(key, data);
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// Utility methods
|
|
561
|
+
getCacheStats() {
|
|
562
|
+
const stats = {
|
|
563
|
+
type: this.cacheType,
|
|
564
|
+
redisAvailable: this.redisAvailable,
|
|
565
|
+
memoryTables: Object.keys(this.tableCaches),
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
if (this.cacheType === 'memory') {
|
|
569
|
+
stats.mainCache = {
|
|
570
|
+
size: this.cache ? this.cache.size : 0,
|
|
571
|
+
max: this.cache ? this.cache.max : 0,
|
|
572
|
+
};
|
|
573
|
+
stats.tableCaches = Object.fromEntries(
|
|
574
|
+
Object.entries(this.tableCaches).map(([table, cache]) => [
|
|
575
|
+
table,
|
|
576
|
+
{ size: cache.size, max: cache.max }
|
|
577
|
+
])
|
|
578
|
+
);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
return stats;
|
|
118
582
|
}
|
|
119
583
|
}
|
|
120
584
|
|