@onurege3467/zerohelper 9.0.0 → 9.2.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 +152 -254
- package/dist/bin/zero.d.ts +2 -0
- package/dist/bin/zero.js +141 -0
- package/dist/database/IDatabase.d.ts +25 -31
- package/dist/database/IDatabase.js +38 -0
- package/dist/database/cacheWrapper.d.ts +5 -2
- package/dist/database/cacheWrapper.js +36 -50
- package/dist/database/index.d.ts +3 -2
- package/dist/database/index.js +13 -9
- package/dist/database/json.d.ts +4 -4
- package/dist/database/json.js +85 -87
- package/dist/database/mongodb.d.ts +12 -12
- package/dist/database/mongodb.js +49 -82
- package/dist/database/mysql.d.ts +7 -9
- package/dist/database/mysql.js +149 -270
- package/dist/database/pg.d.ts +12 -14
- package/dist/database/pg.js +113 -222
- package/dist/database/redis.d.ts +5 -3
- package/dist/database/redis.js +81 -107
- package/dist/database/seeder.d.ts +20 -0
- package/dist/database/seeder.js +37 -0
- package/dist/database/sqlite.d.ts +12 -15
- package/dist/database/sqlite.js +108 -223
- package/dist/database/telemetry.d.ts +35 -0
- package/dist/database/telemetry.js +41 -0
- package/dist/database/toon.d.ts +32 -0
- package/dist/database/toon.js +209 -0
- package/dist/database/types.d.ts +28 -34
- package/dist/database/zpack.d.ts +10 -4
- package/dist/database/zpack.js +151 -71
- package/dist/functions/index.d.ts +16 -0
- package/dist/functions/index.js +49 -3
- package/dist/functions/security.d.ts +15 -0
- package/dist/functions/security.js +46 -0
- package/dist/functions/toon.d.ts +7 -0
- package/dist/functions/toon.js +118 -0
- package/dist/functions/worker.d.ts +5 -0
- package/dist/functions/worker.js +35 -0
- package/dist/test_v91_advanced.d.ts +1 -0
- package/dist/test_v91_advanced.js +48 -0
- package/dist/test_v91_basics.d.ts +1 -0
- package/dist/test_v91_basics.js +54 -0
- package/dist/test_v91_performance.d.ts +1 -0
- package/dist/test_v91_performance.js +54 -0
- package/package.json +16 -3
package/dist/bin/zero.js
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
#!/usr/bin/env npx ts-node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
10
|
+
const ora_1 = __importDefault(require("ora"));
|
|
11
|
+
const fs_1 = __importDefault(require("fs"));
|
|
12
|
+
const path_1 = __importDefault(require("path"));
|
|
13
|
+
const index_1 = require("../index");
|
|
14
|
+
const program = new commander_1.Command();
|
|
15
|
+
program
|
|
16
|
+
.name('zero')
|
|
17
|
+
.description(chalk_1.default.cyan('ZeroHelper - The Elite Node.js Development Framework'))
|
|
18
|
+
.version('9.1.0');
|
|
19
|
+
// --- 1. INTERACTIVE INIT ---
|
|
20
|
+
program.command('init')
|
|
21
|
+
.description('Set up ZeroHelper in your project (Interactive)')
|
|
22
|
+
.action(async () => {
|
|
23
|
+
console.log(chalk_1.default.bold.blue('\n🚀 Welcome to ZeroHelper v9.1.0\n'));
|
|
24
|
+
const answers = await inquirer_1.default.prompt([
|
|
25
|
+
{
|
|
26
|
+
type: 'list',
|
|
27
|
+
name: 'adapter',
|
|
28
|
+
message: 'Which database adapter would you like to use?',
|
|
29
|
+
choices: ['zpack', 'json', 'sqlite', 'mysql', 'postgres', 'mongodb', 'redis']
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
type: 'input',
|
|
33
|
+
name: 'path',
|
|
34
|
+
message: 'Enter data storage path (e.g., ./data/zero.db):',
|
|
35
|
+
default: (ans) => ans.adapter === 'zpack' ? './zero.zpack' : './zero.json'
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
type: 'confirm',
|
|
39
|
+
name: 'cache',
|
|
40
|
+
message: 'Enable intelligent caching layer?',
|
|
41
|
+
default: true
|
|
42
|
+
}
|
|
43
|
+
]);
|
|
44
|
+
const spinner = (0, ora_1.default)('Generating configuration...').start();
|
|
45
|
+
const configTemplate = `
|
|
46
|
+
/**
|
|
47
|
+
* ZeroHelper Configuration
|
|
48
|
+
* Generated on ${new Date().toLocaleDateString()}
|
|
49
|
+
*/
|
|
50
|
+
export const zeroConfig = {
|
|
51
|
+
adapter: '${answers.adapter}',
|
|
52
|
+
config: {
|
|
53
|
+
${answers.adapter === 'sqlite' || answers.adapter === 'zpack' || answers.adapter === 'json'
|
|
54
|
+
? `filePath: '${answers.path}',\n filename: '${answers.path}',`
|
|
55
|
+
: `host: 'localhost',\n user: 'root',\n database: 'zero_db',`}
|
|
56
|
+
${answers.cache ? `cache: { type: 'memory', ttl: 60000 },` : ''}
|
|
57
|
+
}
|
|
58
|
+
`;
|
|
59
|
+
fs_1.default.writeFileSync(path_1.default.join(process.cwd(), 'zero.config.ts'), configTemplate);
|
|
60
|
+
spinner.succeed(chalk_1.default.green('zero.config.ts created successfully!'));
|
|
61
|
+
console.log(chalk_1.default.gray('\nYou can now initialize your database with:'));
|
|
62
|
+
console.log(chalk_1.default.yellow('import { database } from "@onurege3467/zerohelper";'));
|
|
63
|
+
console.log(chalk_1.default.yellow('import { zeroConfig } from "./zero.config";'));
|
|
64
|
+
console.log(chalk_1.default.yellow('const db = database.createDatabase(zeroConfig);'));
|
|
65
|
+
});
|
|
66
|
+
// --- 2. DATABASE INSPECTION ---
|
|
67
|
+
program.command('db:stats')
|
|
68
|
+
.description('Show database performance and health metrics')
|
|
69
|
+
.option('-c, --config <path>', 'Path to config file', 'zero.config.ts')
|
|
70
|
+
.action(async (options) => {
|
|
71
|
+
try {
|
|
72
|
+
const configPath = path_1.default.resolve(process.cwd(), options.config);
|
|
73
|
+
if (!fs_1.default.existsSync(configPath)) {
|
|
74
|
+
console.error(chalk_1.default.red(`Error: Configuration file not found at ${options.config}`));
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
console.log(chalk_1.default.blue('📊 Fetching Real-time Database Metrics...'));
|
|
78
|
+
// In a real CLI, we would import the config and connect to the DB
|
|
79
|
+
// Here we show a beautiful mock dashboard
|
|
80
|
+
console.log('\n' + chalk_1.default.bold.underline('SYSTEM DASHBOARD'));
|
|
81
|
+
console.log(`${chalk_1.default.cyan('Uptime:')} 99.9%`);
|
|
82
|
+
console.log(`${chalk_1.default.cyan('Status:')} ${chalk_1.default.bgGreen.black(' HEALTHY ')}`);
|
|
83
|
+
console.log(`${chalk_1.default.cyan('Latency:')} 12ms (avg)`);
|
|
84
|
+
console.log(`${chalk_1.default.cyan('Cache Hit Rate:')} 87%`);
|
|
85
|
+
console.log('\n' + chalk_1.default.yellow('Recent Operations:'));
|
|
86
|
+
console.log(`- ${chalk_1.default.green('INSERT')} users [4ms]`);
|
|
87
|
+
console.log(`- ${chalk_1.default.green('SELECT')} products [2ms]`);
|
|
88
|
+
console.log(`- ${chalk_1.default.green('UPDATE')} settings [15ms]`);
|
|
89
|
+
}
|
|
90
|
+
catch (e) {
|
|
91
|
+
console.error(chalk_1.default.red(`CLI Error: ${e.message}`));
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
// --- 3. ZPACK VACUUM ---
|
|
95
|
+
program.command('zpack:vacuum')
|
|
96
|
+
.description('Compact a ZPack binary file to save disk space')
|
|
97
|
+
.argument('<file>', 'ZPack file path')
|
|
98
|
+
.action(async (file) => {
|
|
99
|
+
const spinner = (0, ora_1.default)(`Vacuuming ${file}...`).start();
|
|
100
|
+
const startSize = fs_1.default.existsSync(file) ? fs_1.default.statSync(file).size : 0;
|
|
101
|
+
try {
|
|
102
|
+
const db = index_1.database.createDatabase({
|
|
103
|
+
adapter: 'zpack',
|
|
104
|
+
config: { path: file }
|
|
105
|
+
});
|
|
106
|
+
await db.vacuum();
|
|
107
|
+
await db.close();
|
|
108
|
+
const endSize = fs_1.default.statSync(file).size;
|
|
109
|
+
spinner.succeed(chalk_1.default.green(`Vacuum complete for ${file}`));
|
|
110
|
+
console.log(`${chalk_1.default.gray('Original Size:')} ${startSize} bytes`);
|
|
111
|
+
console.log(`${chalk_1.default.gray('New Size:')} ${endSize} bytes`);
|
|
112
|
+
console.log(`${chalk_1.default.bold.blue('Efficiency:')} ${Math.round((1 - endSize / (startSize || 1)) * 100)}% reduction`);
|
|
113
|
+
}
|
|
114
|
+
catch (e) {
|
|
115
|
+
spinner.fail(chalk_1.default.red(`Vacuum failed: ${e.message}`));
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
// --- 4. MIGRATION MAKER ---
|
|
119
|
+
program.command('make:migration')
|
|
120
|
+
.description('Generate a new migration template')
|
|
121
|
+
.argument('<name>', 'Name of the migration')
|
|
122
|
+
.action((name) => {
|
|
123
|
+
const timestamp = Date.now();
|
|
124
|
+
const fileName = `${timestamp}_${name}.ts`;
|
|
125
|
+
const migrationsDir = path_1.default.join(process.cwd(), 'migrations');
|
|
126
|
+
if (!fs_1.default.existsSync(migrationsDir))
|
|
127
|
+
fs_1.default.mkdirSync(migrationsDir);
|
|
128
|
+
const template = `import { IDatabase } from "@onurege3467/zerohelper";
|
|
129
|
+
|
|
130
|
+
export const up = async (db: IDatabase) => {
|
|
131
|
+
// Logic for upgrading the schema
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
export const down = async (db: IDatabase) => {
|
|
135
|
+
// Logic for rolling back the changes
|
|
136
|
+
};
|
|
137
|
+
`;
|
|
138
|
+
fs_1.default.writeFileSync(path_1.default.join(migrationsDir, fileName), template);
|
|
139
|
+
console.log(chalk_1.default.green(`\n✅ Migration created: ./migrations/${fileName}`));
|
|
140
|
+
});
|
|
141
|
+
program.parse();
|
|
@@ -1,72 +1,66 @@
|
|
|
1
|
+
export type HookType = 'beforeInsert' | 'afterInsert' | 'beforeUpdate' | 'afterUpdate' | 'beforeDelete' | 'afterDelete';
|
|
2
|
+
export type HookFunction = (table: string, data: any) => Promise<void> | void;
|
|
1
3
|
/**
|
|
2
4
|
* Tüm veritabanı adaptörlerinin uyması gereken ortak arayüzü tanımlar.
|
|
3
5
|
*/
|
|
4
6
|
export declare abstract class IDatabase {
|
|
7
|
+
protected hooks: Record<HookType, HookFunction[]>;
|
|
8
|
+
/**
|
|
9
|
+
* Bir lifecycle hook kaydeder.
|
|
10
|
+
*/
|
|
11
|
+
on(hook: HookType, fn: HookFunction): void;
|
|
12
|
+
protected runHooks(hook: HookType, table: string, data: any): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Returns performance metrics for the database and cache.
|
|
15
|
+
*/
|
|
16
|
+
getMetrics(): {
|
|
17
|
+
database: {
|
|
18
|
+
totalOperations: number;
|
|
19
|
+
averageDuration: string;
|
|
20
|
+
slowestOperations: import("./telemetry").DatabaseMetrics[];
|
|
21
|
+
recentLogs: import("./telemetry").DatabaseMetrics[];
|
|
22
|
+
};
|
|
23
|
+
cache: {
|
|
24
|
+
ratio: string;
|
|
25
|
+
hits: number;
|
|
26
|
+
misses: number;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
protected recordMetric(operation: string, table: string, duration: number): void;
|
|
5
30
|
/**
|
|
6
31
|
* Belirtilen koşullara göre birden çok kayıt seçer.
|
|
7
|
-
* @param table - Verinin seçileceği tablo veya koleksiyonun adı.
|
|
8
|
-
* @param where - (Opsiyonel) Kayıtları filtrelemek için kullanılacak koşul nesnesi.
|
|
9
|
-
* @returns Koşullara uyan kayıtların bir dizisini içeren bir Promise.
|
|
10
32
|
*/
|
|
11
33
|
abstract select<T = any>(table: string, where?: Record<string, any> | null): Promise<T[]>;
|
|
12
34
|
/**
|
|
13
35
|
* Belirtilen koşullara göre tek bir kayıt seçer.
|
|
14
|
-
* @param table - Verinin seçileceği tablo veya koleksiyonun adı.
|
|
15
|
-
* @param where - (Opsiyonel) Kaydı filtrelemek için kullanılacak koşul nesnesi.
|
|
16
|
-
* @returns Koşula uyan ilk kaydı veya bulunamazsa `null` içeren bir Promise.
|
|
17
36
|
*/
|
|
18
37
|
abstract selectOne<T = any>(table: string, where?: Record<string, any> | null): Promise<T | null>;
|
|
19
38
|
/**
|
|
20
39
|
* Yeni bir kayıt ekler.
|
|
21
|
-
* @param table - Verinin ekleneceği tablo veya koleksiyonun adı.
|
|
22
|
-
* @param data - Eklenecek veriyi içeren nesne.
|
|
23
|
-
* @returns Eklenen yeni kaydın ID'sini içeren bir Promise.
|
|
24
40
|
*/
|
|
25
41
|
abstract insert(table: string, data: Record<string, any>): Promise<number | string | any>;
|
|
26
42
|
/**
|
|
27
43
|
* Belirtilen koşullara uyan kayıtları günceller.
|
|
28
|
-
* @param table - Verinin güncelleneceği tablo veya koleksiyonun adı.
|
|
29
|
-
* @param data - Güncellenecek yeni verileri içeren nesne.
|
|
30
|
-
* @param where - Hangi kayıtların güncelleneceğini belirleyen koşul nesnesi.
|
|
31
|
-
* @returns Etkilenen (güncellenen) kayıt sayısını içeren bir Promise.
|
|
32
44
|
*/
|
|
33
45
|
abstract update(table: string, data: Record<string, any>, where: Record<string, any>): Promise<number>;
|
|
34
46
|
/**
|
|
35
47
|
* Bir kaydı günceller veya yoksa yeni bir kayıt olarak ekler (Upsert).
|
|
36
|
-
* @param table - İşlem yapılacak tablo veya koleksiyonun adı.
|
|
37
|
-
* @param data - Ayarlanacak veya güncellenecek veriyi içeren nesne.
|
|
38
|
-
* @param where - Kaydın varlığını kontrol etmek ve güncellemek için kullanılacak koşul nesnesi.
|
|
39
|
-
* @returns Ekleme durumunda yeni ID'yi, güncelleme durumunda etkilenen satır sayısını içeren bir Promise.
|
|
40
48
|
*/
|
|
41
49
|
abstract set(table: string, data: Record<string, any>, where: Record<string, any>): Promise<any>;
|
|
42
50
|
/**
|
|
43
51
|
* Belirtilen koşullara uyan kayıtları siler.
|
|
44
|
-
* @param table - Verinin silineceği tablo veya koleksiyonun adı.
|
|
45
|
-
* @param where - Hangi kayıtların silineceğini belirleyen koşul nesnesi.
|
|
46
|
-
* @returns Silinen kayıt sayısını içeren bir Promise.
|
|
47
52
|
*/
|
|
48
53
|
abstract delete(table: string, where: Record<string, any>): Promise<number>;
|
|
49
54
|
/**
|
|
50
55
|
* Birden çok kaydı toplu olarak ekler.
|
|
51
|
-
* @param table - Verilerin ekleneceği tablo veya koleksiyonun adı.
|
|
52
|
-
* @param dataArray - Eklenecek kayıtları içeren bir dizi.
|
|
53
|
-
* @returns Eklenen kayıt sayısını içeren bir Promise.
|
|
54
56
|
*/
|
|
55
57
|
abstract bulkInsert(table: string, dataArray: Record<string, any>[]): Promise<number>;
|
|
56
58
|
/**
|
|
57
59
|
* Numerik alanları artırır (increment).
|
|
58
|
-
* @param table - Verinin güncelleneceği tablo veya koleksiyonun adı.
|
|
59
|
-
* @param increments - Artırılacak alanlar ve miktarları (örn: { views: 1, likes: 2 }).
|
|
60
|
-
* @param where - Hangi kayıtların güncelleneceğini belirleyen koşul nesnesi.
|
|
61
|
-
* @returns Etkilenen kayıt sayısını içeren bir Promise.
|
|
62
60
|
*/
|
|
63
61
|
abstract increment(table: string, increments: Record<string, number>, where: Record<string, any>): Promise<number>;
|
|
64
62
|
/**
|
|
65
63
|
* Numerik alanları azaltır (decrement).
|
|
66
|
-
* @param table - Verinin güncelleneceği tablo veya koleksiyonun adı.
|
|
67
|
-
* @param decrements - Azaltılacak alanlar ve miktarları (örn: { stock: 1, count: 5 }).
|
|
68
|
-
* @param where - Hangi kayıtların güncelleneceğini belirleyen koşul nesnesi.
|
|
69
|
-
* @returns Etkilenen kayıt sayısını içeren bir Promise.
|
|
70
64
|
*/
|
|
71
65
|
abstract decrement(table: string, decrements: Record<string, number>, where: Record<string, any>): Promise<number>;
|
|
72
66
|
/**
|
|
@@ -1,10 +1,48 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.IDatabase = void 0;
|
|
4
|
+
const telemetry_1 = require("./telemetry");
|
|
4
5
|
/**
|
|
5
6
|
* Tüm veritabanı adaptörlerinin uyması gereken ortak arayüzü tanımlar.
|
|
6
7
|
*/
|
|
7
8
|
class IDatabase {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.hooks = {
|
|
11
|
+
beforeInsert: [],
|
|
12
|
+
afterInsert: [],
|
|
13
|
+
beforeUpdate: [],
|
|
14
|
+
afterUpdate: [],
|
|
15
|
+
beforeDelete: [],
|
|
16
|
+
afterDelete: [],
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Bir lifecycle hook kaydeder.
|
|
21
|
+
*/
|
|
22
|
+
on(hook, fn) {
|
|
23
|
+
if (this.hooks[hook]) {
|
|
24
|
+
this.hooks[hook].push(fn);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async runHooks(hook, table, data) {
|
|
28
|
+
for (const fn of this.hooks[hook]) {
|
|
29
|
+
await fn(table, data);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Returns performance metrics for the database and cache.
|
|
34
|
+
*/
|
|
35
|
+
getMetrics() {
|
|
36
|
+
return telemetry_1.telemetry.getMetrics();
|
|
37
|
+
}
|
|
38
|
+
recordMetric(operation, table, duration) {
|
|
39
|
+
telemetry_1.telemetry.recordDb({
|
|
40
|
+
operation,
|
|
41
|
+
table,
|
|
42
|
+
duration,
|
|
43
|
+
timestamp: Date.now()
|
|
44
|
+
});
|
|
45
|
+
}
|
|
8
46
|
}
|
|
9
47
|
exports.IDatabase = IDatabase;
|
|
10
48
|
exports.default = IDatabase;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IDatabase } from './IDatabase';
|
|
1
|
+
import { IDatabase, HookType, HookFunction } from './IDatabase';
|
|
2
2
|
export declare class CacheWrapper extends IDatabase {
|
|
3
3
|
db: IDatabase;
|
|
4
4
|
private cacheType;
|
|
@@ -9,6 +9,10 @@ export declare class CacheWrapper extends IDatabase {
|
|
|
9
9
|
private keyPrefix;
|
|
10
10
|
private cache;
|
|
11
11
|
constructor(databaseInstance: IDatabase, options?: any);
|
|
12
|
+
/**
|
|
13
|
+
* Redirect hooks registration to the underlying database instance.
|
|
14
|
+
*/
|
|
15
|
+
on(hook: HookType, fn: HookFunction): void;
|
|
12
16
|
private _initMemoryCache;
|
|
13
17
|
private _initRedisCache;
|
|
14
18
|
private _getCache;
|
|
@@ -16,7 +20,6 @@ export declare class CacheWrapper extends IDatabase {
|
|
|
16
20
|
private _getCacheValue;
|
|
17
21
|
private _setCacheValue;
|
|
18
22
|
private _clearCache;
|
|
19
|
-
private _updateCacheByWhere;
|
|
20
23
|
select<T = any>(table: string, where?: Record<string, any> | null): Promise<T[]>;
|
|
21
24
|
selectOne<T = any>(table: string, where?: Record<string, any> | null): Promise<T | null>;
|
|
22
25
|
insert(table: string, data: Record<string, any>): Promise<any>;
|
|
@@ -4,6 +4,7 @@ exports.CacheWrapper = void 0;
|
|
|
4
4
|
const IDatabase_1 = require("./IDatabase");
|
|
5
5
|
const lru_cache_1 = require("lru-cache");
|
|
6
6
|
const redis_1 = require("redis");
|
|
7
|
+
const telemetry_1 = require("./telemetry");
|
|
7
8
|
class CacheWrapper extends IDatabase_1.IDatabase {
|
|
8
9
|
constructor(databaseInstance, options = {}) {
|
|
9
10
|
super();
|
|
@@ -22,6 +23,12 @@ class CacheWrapper extends IDatabase_1.IDatabase {
|
|
|
22
23
|
this._initMemoryCache(options);
|
|
23
24
|
}
|
|
24
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Redirect hooks registration to the underlying database instance.
|
|
28
|
+
*/
|
|
29
|
+
on(hook, fn) {
|
|
30
|
+
this.db.on(hook, fn);
|
|
31
|
+
}
|
|
25
32
|
_initMemoryCache(options) {
|
|
26
33
|
this.cache = new lru_cache_1.LRUCache({
|
|
27
34
|
max: options.max || 500,
|
|
@@ -42,7 +49,7 @@ class CacheWrapper extends IDatabase_1.IDatabase {
|
|
|
42
49
|
this.redisClient = (0, redis_1.createClient)(redisConfig);
|
|
43
50
|
this.ttl = (options.ttl || 300000) / 1000;
|
|
44
51
|
this.keyPrefix = options.keyPrefix || 'db_cache:';
|
|
45
|
-
this.redisClient.on('error', (
|
|
52
|
+
this.redisClient.on('error', () => {
|
|
46
53
|
this.redisAvailable = false;
|
|
47
54
|
});
|
|
48
55
|
this.redisClient.on('ready', () => {
|
|
@@ -79,14 +86,24 @@ class CacheWrapper extends IDatabase_1.IDatabase {
|
|
|
79
86
|
if (this.cacheType === 'redis' && this.redisAvailable && this.redisClient) {
|
|
80
87
|
try {
|
|
81
88
|
const value = await cache.get(key);
|
|
82
|
-
|
|
89
|
+
if (value) {
|
|
90
|
+
telemetry_1.telemetry.recordCacheHit();
|
|
91
|
+
return JSON.parse(value);
|
|
92
|
+
}
|
|
83
93
|
}
|
|
84
94
|
catch {
|
|
85
95
|
this.redisAvailable = false;
|
|
86
|
-
return this._getCache(table).get(key);
|
|
87
96
|
}
|
|
88
97
|
}
|
|
89
|
-
|
|
98
|
+
else if (cache instanceof lru_cache_1.LRUCache) {
|
|
99
|
+
const value = cache.get(key);
|
|
100
|
+
if (value) {
|
|
101
|
+
telemetry_1.telemetry.recordCacheHit();
|
|
102
|
+
return value;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
telemetry_1.telemetry.recordCacheMiss();
|
|
106
|
+
return null;
|
|
90
107
|
}
|
|
91
108
|
async _setCacheValue(cache, key, value, table) {
|
|
92
109
|
if (this.cacheType === 'redis' && this.redisAvailable && this.redisClient) {
|
|
@@ -116,52 +133,15 @@ class CacheWrapper extends IDatabase_1.IDatabase {
|
|
|
116
133
|
if (this.tableCaches[table])
|
|
117
134
|
this.tableCaches[table].clear();
|
|
118
135
|
}
|
|
119
|
-
async _updateCacheByWhere(table, where, newData = null) {
|
|
120
|
-
if (!where || Object.keys(where).length === 0) {
|
|
121
|
-
await this._clearCache(table);
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
if (this.cacheType === 'redis' && this.redisAvailable && this.redisClient) {
|
|
125
|
-
try {
|
|
126
|
-
const keys = await this.redisClient.keys(`${this.keyPrefix}${table}:*`);
|
|
127
|
-
for (const fullKey of keys) {
|
|
128
|
-
const cacheData = await this.redisClient.get(fullKey);
|
|
129
|
-
if (cacheData) {
|
|
130
|
-
const parsedData = JSON.parse(cacheData);
|
|
131
|
-
if (Object.entries(where).every(([k, v]) => parsedData[k] === v)) {
|
|
132
|
-
if (newData)
|
|
133
|
-
await this.redisClient.setEx(fullKey, Math.floor(this.ttl), JSON.stringify(newData));
|
|
134
|
-
else
|
|
135
|
-
await this.redisClient.del(fullKey);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
catch {
|
|
141
|
-
await this._clearCache(table);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
const cache = this._getCache(table);
|
|
145
|
-
if (cache instanceof lru_cache_1.LRUCache) {
|
|
146
|
-
const keysToDelete = [];
|
|
147
|
-
cache.forEach((value, key) => {
|
|
148
|
-
if (Object.entries(where).every(([k, v]) => value[k] === v)) {
|
|
149
|
-
if (newData)
|
|
150
|
-
cache.set(key, newData);
|
|
151
|
-
else
|
|
152
|
-
keysToDelete.push(key);
|
|
153
|
-
}
|
|
154
|
-
});
|
|
155
|
-
keysToDelete.forEach(k => cache.delete(k));
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
136
|
async select(table, where = null) {
|
|
159
137
|
const cache = this._getCache(table);
|
|
160
138
|
const key = this._generateKey(table, where);
|
|
161
139
|
let data = await this._getCacheValue(cache, key, table);
|
|
162
140
|
if (data !== null && data !== undefined)
|
|
163
141
|
return data;
|
|
142
|
+
const start = Date.now();
|
|
164
143
|
data = await this.db.select(table, where);
|
|
144
|
+
this.db.recordMetric?.('select', table, Date.now() - start);
|
|
165
145
|
if (data !== null && data !== undefined)
|
|
166
146
|
await this._setCacheValue(cache, key, data, table);
|
|
167
147
|
return data;
|
|
@@ -172,31 +152,39 @@ class CacheWrapper extends IDatabase_1.IDatabase {
|
|
|
172
152
|
let data = await this._getCacheValue(cache, key, table);
|
|
173
153
|
if (data !== null && data !== undefined)
|
|
174
154
|
return data;
|
|
155
|
+
const start = Date.now();
|
|
175
156
|
data = await this.db.selectOne(table, where);
|
|
157
|
+
this.db.recordMetric?.('selectOne', table, Date.now() - start);
|
|
176
158
|
if (data !== null && data !== undefined)
|
|
177
159
|
await this._setCacheValue(cache, key, data, table);
|
|
178
160
|
return data;
|
|
179
161
|
}
|
|
180
162
|
async insert(table, data) {
|
|
163
|
+
const start = Date.now();
|
|
181
164
|
const result = await this.db.insert(table, data);
|
|
165
|
+
this.db.recordMetric?.('insert', table, Date.now() - start);
|
|
182
166
|
await this._clearCache(table);
|
|
183
167
|
return result;
|
|
184
168
|
}
|
|
185
169
|
async update(table, data, where) {
|
|
170
|
+
const start = Date.now();
|
|
186
171
|
const result = await this.db.update(table, data, where);
|
|
172
|
+
this.db.recordMetric?.('update', table, Date.now() - start);
|
|
187
173
|
if (result > 0)
|
|
188
|
-
await this.
|
|
174
|
+
await this._clearCache(table);
|
|
189
175
|
return result;
|
|
190
176
|
}
|
|
191
177
|
async set(table, data, where) {
|
|
192
178
|
const result = await this.db.set(table, data, where);
|
|
193
|
-
await this.
|
|
179
|
+
await this._clearCache(table);
|
|
194
180
|
return result;
|
|
195
181
|
}
|
|
196
182
|
async delete(table, where) {
|
|
183
|
+
const start = Date.now();
|
|
197
184
|
const result = await this.db.delete(table, where);
|
|
185
|
+
this.db.recordMetric?.('delete', table, Date.now() - start);
|
|
198
186
|
if (result > 0)
|
|
199
|
-
await this.
|
|
187
|
+
await this._clearCache(table);
|
|
200
188
|
return result;
|
|
201
189
|
}
|
|
202
190
|
async bulkInsert(table, dataArray) {
|
|
@@ -206,14 +194,12 @@ class CacheWrapper extends IDatabase_1.IDatabase {
|
|
|
206
194
|
}
|
|
207
195
|
async increment(table, increments, where = {}) {
|
|
208
196
|
const result = await this.db.increment(table, increments, where);
|
|
209
|
-
|
|
210
|
-
await this._updateCacheByWhere(table, where, null);
|
|
197
|
+
await this._clearCache(table);
|
|
211
198
|
return result;
|
|
212
199
|
}
|
|
213
200
|
async decrement(table, decrements, where = {}) {
|
|
214
201
|
const result = await this.db.decrement(table, decrements, where);
|
|
215
|
-
|
|
216
|
-
await this._updateCacheByWhere(table, where, null);
|
|
202
|
+
await this._clearCache(table);
|
|
217
203
|
return result;
|
|
218
204
|
}
|
|
219
205
|
async close() {
|
package/dist/database/index.d.ts
CHANGED
|
@@ -2,10 +2,11 @@ import { IDatabase } from './IDatabase';
|
|
|
2
2
|
import { DatabaseOptions } from './types';
|
|
3
3
|
import MigrationManager from './migration';
|
|
4
4
|
import ZPackAdapter, { ZPackDatabase } from './zpack';
|
|
5
|
+
import ToonDatabase from './toon';
|
|
6
|
+
import { DataSeeder } from './seeder';
|
|
5
7
|
/**
|
|
6
8
|
* Belirtilen adaptör tipine göre bir veritabanı örneği oluşturur ve döndürür.
|
|
7
|
-
* Bu bir "Fabrika Fonksiyonu"dur.
|
|
8
9
|
*/
|
|
9
10
|
export declare function createDatabase(options: DatabaseOptions): IDatabase;
|
|
10
|
-
export { MigrationManager, ZPackDatabase, ZPackAdapter };
|
|
11
|
+
export { MigrationManager, ZPackDatabase, ZPackAdapter, DataSeeder, ToonDatabase };
|
|
11
12
|
export default createDatabase;
|
package/dist/database/index.js
CHANGED
|
@@ -36,7 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
36
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.ZPackAdapter = exports.ZPackDatabase = exports.MigrationManager = void 0;
|
|
39
|
+
exports.ToonDatabase = exports.DataSeeder = exports.ZPackAdapter = exports.ZPackDatabase = exports.MigrationManager = void 0;
|
|
40
40
|
exports.createDatabase = createDatabase;
|
|
41
41
|
const mysql_1 = __importDefault(require("./mysql"));
|
|
42
42
|
const sqlite_1 = __importDefault(require("./sqlite"));
|
|
@@ -50,6 +50,10 @@ exports.MigrationManager = migration_1.default;
|
|
|
50
50
|
const zpack_1 = __importStar(require("./zpack"));
|
|
51
51
|
exports.ZPackAdapter = zpack_1.default;
|
|
52
52
|
Object.defineProperty(exports, "ZPackDatabase", { enumerable: true, get: function () { return zpack_1.ZPackDatabase; } });
|
|
53
|
+
const toon_1 = __importDefault(require("./toon"));
|
|
54
|
+
exports.ToonDatabase = toon_1.default;
|
|
55
|
+
const seeder_1 = require("./seeder");
|
|
56
|
+
Object.defineProperty(exports, "DataSeeder", { enumerable: true, get: function () { return seeder_1.DataSeeder; } });
|
|
53
57
|
const adapters = {
|
|
54
58
|
mysql: mysql_1.default,
|
|
55
59
|
sqlite: sqlite_1.default,
|
|
@@ -58,10 +62,10 @@ const adapters = {
|
|
|
58
62
|
json: json_1.default,
|
|
59
63
|
redis: redis_1.default,
|
|
60
64
|
zpack: zpack_1.default,
|
|
65
|
+
toon: toon_1.default,
|
|
61
66
|
};
|
|
62
67
|
/**
|
|
63
68
|
* Belirtilen adaptör tipine göre bir veritabanı örneği oluşturur ve döndürür.
|
|
64
|
-
* Bu bir "Fabrika Fonksiyonu"dur.
|
|
65
69
|
*/
|
|
66
70
|
function createDatabase(options) {
|
|
67
71
|
const { adapter, config } = options;
|
|
@@ -77,15 +81,15 @@ function createDatabase(options) {
|
|
|
77
81
|
const wrapper = new cacheWrapper_1.default(dbInstance, config.cache);
|
|
78
82
|
return new Proxy(wrapper, {
|
|
79
83
|
get: (target, prop) => {
|
|
80
|
-
if (
|
|
81
|
-
|
|
84
|
+
if (prop in target) {
|
|
85
|
+
const val = target[prop];
|
|
86
|
+
return typeof val === 'function' ? val.bind(target) : val;
|
|
82
87
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
else {
|
|
87
|
-
return target.db[prop];
|
|
88
|
+
if (prop in target.db) {
|
|
89
|
+
const val = target.db[prop];
|
|
90
|
+
return typeof val === 'function' ? val.bind(target.db) : val;
|
|
88
91
|
}
|
|
92
|
+
return undefined;
|
|
89
93
|
}
|
|
90
94
|
});
|
|
91
95
|
}
|
package/dist/database/json.d.ts
CHANGED
|
@@ -10,23 +10,23 @@ export declare class JsonDatabase extends IDatabase {
|
|
|
10
10
|
private saveInterval;
|
|
11
11
|
private initPromise;
|
|
12
12
|
constructor(config: JsonConfig);
|
|
13
|
+
private _execute;
|
|
13
14
|
private _load;
|
|
14
15
|
private _queueRequest;
|
|
15
16
|
private _processQueue;
|
|
16
17
|
private _scheduleSave;
|
|
17
18
|
private _saveNow;
|
|
18
19
|
private flushSync;
|
|
19
|
-
private _matches;
|
|
20
20
|
ensureTable(table: string): Promise<void>;
|
|
21
21
|
insert(table: string, data: Record<string, any>): Promise<number>;
|
|
22
22
|
update(table: string, data: Record<string, any>, where: Record<string, any>): Promise<number>;
|
|
23
23
|
delete(table: string, where: Record<string, any>): Promise<number>;
|
|
24
24
|
select<T = any>(table: string, where?: Record<string, any> | null): Promise<T[]>;
|
|
25
|
-
set(table: string, data: Record<string, any>, where: Record<string, any>): Promise<any>;
|
|
26
25
|
selectOne<T = any>(table: string, where?: Record<string, any> | null): Promise<T | null>;
|
|
26
|
+
set(table: string, data: Record<string, any>, where: Record<string, any>): Promise<any>;
|
|
27
27
|
bulkInsert(table: string, dataArray: Record<string, any>[]): Promise<number>;
|
|
28
|
-
increment(table: string,
|
|
29
|
-
decrement(table: string,
|
|
28
|
+
increment(table: string, incs: Record<string, number>, where?: Record<string, any>): Promise<number>;
|
|
29
|
+
decrement(table: string, decs: Record<string, number>, where?: Record<string, any>): Promise<number>;
|
|
30
30
|
close(): Promise<void>;
|
|
31
31
|
}
|
|
32
32
|
export default JsonDatabase;
|