@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.
Files changed (45) hide show
  1. package/README.md +152 -254
  2. package/dist/bin/zero.d.ts +2 -0
  3. package/dist/bin/zero.js +141 -0
  4. package/dist/database/IDatabase.d.ts +25 -31
  5. package/dist/database/IDatabase.js +38 -0
  6. package/dist/database/cacheWrapper.d.ts +5 -2
  7. package/dist/database/cacheWrapper.js +36 -50
  8. package/dist/database/index.d.ts +3 -2
  9. package/dist/database/index.js +13 -9
  10. package/dist/database/json.d.ts +4 -4
  11. package/dist/database/json.js +85 -87
  12. package/dist/database/mongodb.d.ts +12 -12
  13. package/dist/database/mongodb.js +49 -82
  14. package/dist/database/mysql.d.ts +7 -9
  15. package/dist/database/mysql.js +149 -270
  16. package/dist/database/pg.d.ts +12 -14
  17. package/dist/database/pg.js +113 -222
  18. package/dist/database/redis.d.ts +5 -3
  19. package/dist/database/redis.js +81 -107
  20. package/dist/database/seeder.d.ts +20 -0
  21. package/dist/database/seeder.js +37 -0
  22. package/dist/database/sqlite.d.ts +12 -15
  23. package/dist/database/sqlite.js +108 -223
  24. package/dist/database/telemetry.d.ts +35 -0
  25. package/dist/database/telemetry.js +41 -0
  26. package/dist/database/toon.d.ts +32 -0
  27. package/dist/database/toon.js +209 -0
  28. package/dist/database/types.d.ts +28 -34
  29. package/dist/database/zpack.d.ts +10 -4
  30. package/dist/database/zpack.js +151 -71
  31. package/dist/functions/index.d.ts +16 -0
  32. package/dist/functions/index.js +49 -3
  33. package/dist/functions/security.d.ts +15 -0
  34. package/dist/functions/security.js +46 -0
  35. package/dist/functions/toon.d.ts +7 -0
  36. package/dist/functions/toon.js +118 -0
  37. package/dist/functions/worker.d.ts +5 -0
  38. package/dist/functions/worker.js +35 -0
  39. package/dist/test_v91_advanced.d.ts +1 -0
  40. package/dist/test_v91_advanced.js +48 -0
  41. package/dist/test_v91_basics.d.ts +1 -0
  42. package/dist/test_v91_basics.js +54 -0
  43. package/dist/test_v91_performance.d.ts +1 -0
  44. package/dist/test_v91_performance.js +54 -0
  45. package/package.json +16 -3
@@ -11,262 +11,147 @@ const path_1 = __importDefault(require("path"));
11
11
  class SQLiteDatabase extends IDatabase_1.IDatabase {
12
12
  constructor(config) {
13
13
  super();
14
- if (!config || !config.filename) {
15
- throw new Error('SQLite yapılandırması için "filename" gereklidir.');
16
- }
17
- const dir = path_1.default.dirname(config.filename);
18
- if (!fs_1.default.existsSync(dir)) {
14
+ if (!config || !config.path)
15
+ throw new Error('SQLite "path" gereklidir.');
16
+ const dir = path_1.default.dirname(config.path);
17
+ if (!fs_1.default.existsSync(dir))
19
18
  fs_1.default.mkdirSync(dir, { recursive: true });
20
- }
21
- this.db = new sqlite3_1.default.Database(config.filename, (err) => {
22
- if (err) {
23
- console.error("SQLite connection error:", err.message);
24
- }
25
- });
26
- }
27
- _detectColumnType(value) {
28
- if (value === null || value === undefined)
29
- return 'TEXT';
30
- if (typeof value === 'boolean')
31
- return 'BOOLEAN';
32
- if (typeof value === 'number')
33
- return Number.isInteger(value) ? 'INTEGER' : 'REAL';
34
- if (value instanceof Date)
35
- return 'DATETIME';
36
- if (typeof value === 'string') {
37
- if (value.trim() === '')
38
- return 'TEXT';
39
- if (/^-?\d+$/.test(value.trim()))
40
- return 'INTEGER';
41
- if (/^-?\d+\.\d+$/.test(value.trim()))
42
- return 'REAL';
43
- const lowerValue = value.toLowerCase().trim();
44
- if (lowerValue === 'true' || lowerValue === 'false')
45
- return 'BOOLEAN';
46
- if (value.match(/^\d{4}-\d{2}-\d{2}/))
47
- return 'DATETIME';
48
- }
49
- return 'TEXT';
19
+ this.db = new sqlite3_1.default.Database(config.path);
50
20
  }
51
- _determineBestColumnType(values) {
52
- const types = values.map(v => this._detectColumnType(v));
53
- const typePriority = { 'INTEGER': 1, 'REAL': 2, 'BOOLEAN': 3, 'DATETIME': 4, 'TEXT': 5 };
54
- const maxPriority = Math.max(...types.map(t => typePriority[t] || 5));
55
- return Object.keys(typePriority).find(t => typePriority[t] === maxPriority) || 'TEXT';
21
+ async _execute(op, table, fn) {
22
+ const start = Date.now();
23
+ const res = await fn();
24
+ this.recordMetric(op, table, Date.now() - start);
25
+ return res;
56
26
  }
57
- async _ensureMissingColumns(table, data) {
58
- const columnsInfo = await this.query(`PRAGMA table_info(\`${table}\`)
59
- `);
60
- const existingNames = columnsInfo.map(col => col.name);
61
- for (const key of Object.keys(data)) {
62
- if (!existingNames.includes(key)) {
63
- const columnType = this._detectColumnType(data[key]);
64
- await this.query(`ALTER TABLE
65
- }
66
- }
67
- }
68
- query(sql, params = []) {
27
+ ;
28
+ async query(sql, params = []) {
69
29
  return new Promise((resolve, reject) => {
70
- const upperSql = sql.trim().toUpperCase();
71
- if (upperSql.startsWith('SELECT') || upperSql.startsWith('PRAGMA')) {
72
- this.db.all(sql, params, (err, rows) => {
73
- if (err)
74
- reject(err);
75
- else
76
- resolve(rows);
77
- });
30
+ const s = sql.trim().toUpperCase();
31
+ if (s.startsWith('SELECT') || s.startsWith('PRAGMA')) {
32
+ this.db.all(sql, params, (err, rows) => err ? reject(err) : resolve(rows));
78
33
  }
79
34
  else {
80
- this.db.run(sql, params, function (err) {
81
- if (err)
82
- reject(err);
83
- else
84
- resolve({ changes: this.changes, lastInsertRowid: this.lastID });
85
- });
35
+ this.db.run(sql, params, function (err) { err ? reject(err) : resolve({ changes: this.changes, lastID: this.lastID }); });
86
36
  }
87
37
  });
88
38
  }
89
39
  async ensureTable(table, data = {}) {
90
40
  try {
91
- await this.query(`SELECT 1 FROM
92
- }
93
- catch (error) {
94
- if (error.message.includes('no such table')) {
95
- const columnDefinitions = Object.keys(data).map(col => {
96
- const columnType = this._detectColumnType(data[col]);
97
- return `reverse{col}
98
- });
99
- const columnsPart = columnDefinitions.length > 0 ? ', ' + columnDefinitions.join(", ") : '';
100
- const createTableSQL = `CREATE TABLE
101
- await this.query(createTableSQL);
102
- }
103
- else {
104
- throw error;
41
+ await this.query(`SELECT 1 FROM "${table}" LIMIT 1`);
42
+ const info = await this.query(`PRAGMA table_info("${table}")`);
43
+ const names = info.map(c => c.name);
44
+ for (const key of Object.keys(data)) {
45
+ if (key !== '_id' && !names.includes(key)) {
46
+ await this.query(`ALTER TABLE "${table}" ADD COLUMN "${key}" TEXT`);
47
+ }
105
48
  }
106
49
  }
107
- }
108
- _serializeValue(value) {
109
- if (value instanceof Date)
110
- return value.toISOString();
111
- if (Array.isArray(value) || (typeof value === 'object' && value !== null))
112
- return JSON.stringify(value);
113
- return value;
114
- }
115
- _deserializeValue(value) {
116
- if (typeof value === 'string' && (value.startsWith('[') || value.startsWith('{'))) {
117
- try {
118
- const parsed = JSON.parse(value);
119
- if (typeof parsed === 'object' && parsed !== null)
120
- return parsed;
121
- }
122
- catch (e) { }
50
+ catch {
51
+ const defs = Object.keys(data).map(k => `"${k}" TEXT`);
52
+ await this.query(`CREATE TABLE "${table}" (_id INTEGER PRIMARY KEY AUTOINCREMENT ${defs.length ? ', ' + defs.join(',') : ''})`);
123
53
  }
124
- return value;
125
54
  }
126
55
  async insert(table, data) {
127
- const copy = { ...data };
128
- await this.ensureTable(table, copy);
129
- await this._ensureMissingColumns(table, copy);
130
- const keys = Object.keys(copy);
131
- const placeholders = keys.map(() => '?').join(',');
132
- const values = Object.values(copy).map(v => this._serializeValue(v));
133
- const sql = `INSERT INTO
134
- const result = await this.query(sql, values);
135
- return result.lastInsertRowid;
56
+ await this.runHooks('beforeInsert', table, data);
57
+ return this._execute('insert', table, async () => {
58
+ await this.ensureTable(table, data);
59
+ const keys = Object.keys(data);
60
+ const sql = `INSERT INTO "${table}" (${keys.map(k => `"${k}"`).join(',')}) VALUES (${keys.map(() => '?').join(',')})`;
61
+ const res = await this.query(sql, Object.values(data).map(v => typeof v === 'object' ? JSON.stringify(v) : v));
62
+ const finalData = { _id: res.lastID, ...data };
63
+ await this.runHooks('afterInsert', table, finalData);
64
+ return res.lastID;
65
+ });
136
66
  }
137
67
  async update(table, data, where) {
138
- await this.ensureTable(table, { ...data, ...where });
139
- await this._ensureMissingColumns(table, { ...data, ...where });
140
- const setString = Object.keys(data).map(k => `reverse{k}
141
- const whereString = Object.keys(where).map(k => `reverse{k}
142
- const sql = `UPDATE
143
- const result = await this.query(sql, [...Object.values(data).map(v => this._serializeValue(v)), ...Object.values(where).map(v => this._serializeValue(v))]);
144
- return result.changes;
68
+ await this.runHooks('beforeUpdate', table, { data, where });
69
+ return this._execute('update', table, async () => {
70
+ await this.ensureTable(table, { ...data, ...where });
71
+ const set = Object.keys(data).map(k => `"${k}" = ?`).join(',');
72
+ const { whereClause, values: whereValues } = this._buildWhereClause(where);
73
+ const sql = `UPDATE "${table}" SET ${set} ${whereClause}`;
74
+ const res = await this.query(sql, [...Object.values(data).map(v => typeof v === 'object' ? JSON.stringify(v) : v), ...whereValues]);
75
+ return res.changes;
76
+ });
145
77
  }
146
78
  async delete(table, where) {
147
- if (!where || Object.keys(where).length === 0)
148
- return 0;
149
- await this.ensureTable(table, { ...where });
150
- await this._ensureMissingColumns(table, where);
151
- const whereString = Object.keys(where).map(k => `reverse{k}
152
- const sql = `DELETE FROM
153
- const result = await this.query(sql, Object.values(where).map(v => this._serializeValue(v)));
154
- return result.changes;
79
+ await this.runHooks('beforeDelete', table, where);
80
+ return this._execute('delete', table, async () => {
81
+ await this.ensureTable(table, where);
82
+ const { whereClause, values } = this._buildWhereClause(where);
83
+ const sql = `DELETE FROM "${table}" ${whereClause}`;
84
+ const res = await this.query(sql, values);
85
+ return res.changes;
86
+ });
155
87
  }
156
88
  async select(table, where = null) {
157
- await this.ensureTable(table, where || {});
158
- if (where && Object.keys(where).length > 0) {
159
- await this._ensureMissingColumns(table, where);
160
- }
161
- let sql = `SELECT * FROM
162
- let params = [];
163
- if (where && Object.keys(where).length > 0) {
164
- const whereString = Object.keys(where).map(k => `reverse{k}
165
- sql += ` WHERE ${whereString}`;
166
- params = Object.values(where).map(v => this._serializeValue(v));
167
- }
168
- const rows = await this.query(sql, params);
169
- return rows.map((row) => {
170
- const newRow = {};
171
- for (const key in row) {
172
- newRow[key] = this._deserializeValue(row[key]);
173
- }
174
- return newRow;
89
+ return this._execute('select', table, async () => {
90
+ await this.ensureTable(table, where || {});
91
+ const { whereClause, values } = this._buildWhereClause(where);
92
+ const rows = await this.query(`SELECT * FROM "${table}" ${whereClause}`, values);
93
+ return rows.map((r) => {
94
+ const nr = {};
95
+ for (const k in r) {
96
+ try {
97
+ nr[k] = JSON.parse(r[k]);
98
+ }
99
+ catch {
100
+ nr[k] = r[k];
101
+ }
102
+ }
103
+ return nr;
104
+ });
175
105
  });
176
106
  }
177
- async set(table, data, where) {
178
- const existing = await this.select(table, where);
179
- if (existing.length === 0) {
180
- return await this.insert(table, { ...where, ...data });
181
- }
182
- else {
183
- return await this.update(table, data, where);
184
- }
185
- }
186
107
  async selectOne(table, where = null) {
187
- const results = await this.select(table, where);
188
- return results[0] || null;
108
+ const res = await this.select(table, where);
109
+ return res[0] || null;
110
+ }
111
+ async set(table, data, where) {
112
+ const ex = await this.selectOne(table, where);
113
+ return ex ? this.update(table, data, where) : this.insert(table, { ...where, ...data });
189
114
  }
190
115
  async bulkInsert(table, dataArray) {
191
- if (!Array.isArray(dataArray) || dataArray.length === 0)
116
+ if (!dataArray.length)
192
117
  return 0;
193
- await this.ensureTable(table, dataArray[0]);
194
- const allKeys = new Set();
195
- dataArray.forEach(obj => Object.keys(obj).forEach(key => allKeys.add(key)));
196
- for (const key of allKeys) {
197
- const columnsInfo = await this.query(`PRAGMA table_info(
198
- if (!columnsInfo.map(col => col.name).includes(key)) {
199
- const columnValues = dataArray.map(obj => obj[key]).filter(val => val !== undefined && val !== null);
200
- const columnType = columnValues.length > 0 ? this._determineBestColumnType(columnValues) : 'TEXT';
201
- await this.query(`ALTER TABLE
202
- }
203
- }
204
- const keys = Array.from(allKeys);
205
- const sql = `INSERT INTO
206
- return new Promise((resolve, reject) => {
207
- this.db.serialize(() => {
208
- this.db.run("BEGIN TRANSACTION;");
209
- let completed = 0;
210
- let hasError = false;
211
- const stmt = this.db.prepare(sql);
212
- for (const item of dataArray) {
213
- if (hasError)
214
- break;
215
- stmt.run(keys.map(k => this._serializeValue(item[k])), (err) => {
216
- if (err && !hasError) {
217
- hasError = true;
218
- this.db.run("ROLLBACK;");
219
- reject(err);
220
- }
221
- completed++;
222
- if (completed === dataArray.length && !hasError) {
223
- this.db.run("COMMIT;", (err) => {
224
- if (err)
225
- reject(err);
226
- else {
227
- stmt.finalize();
228
- resolve(dataArray.length);
229
- }
230
- });
231
- }
232
- });
233
- }
234
- });
118
+ for (const d of dataArray)
119
+ await this.insert(table, d);
120
+ return dataArray.length;
121
+ }
122
+ async increment(table, incs, where) {
123
+ return this._execute('increment', table, async () => {
124
+ await this.ensureTable(table, where);
125
+ const set = Object.keys(incs).map(f => `"${f}" = CAST("${f}" AS NUMERIC) + ?`);
126
+ const { whereClause, values } = this._buildWhereClause(where);
127
+ const sql = `UPDATE "${table}" SET ${set} ${whereClause}`;
128
+ const res = await this.query(sql, [...Object.values(incs), ...values]);
129
+ return res.changes;
235
130
  });
236
131
  }
237
- async increment(table, increments, where = {}) {
238
- const incrementClauses = Object.keys(increments).map(field => `reverse{field}
239
- const incrementValues = Object.values(increments);
240
- const { whereClause, values: whereValues } = this._buildWhereClause(where);
241
- const sql = `UPDATE
242
- const result = await this.query(sql, [...incrementValues, ...whereValues]);
243
- return result.changes;
132
+ async decrement(table, decs, where) {
133
+ const incs = {};
134
+ for (const k in decs)
135
+ incs[k] = -decs[k];
136
+ return this.increment(table, incs, where);
244
137
  }
245
- async decrement(table, decrements, where = {}) {
246
- const decrementClauses = Object.keys(decrements).map(field => `reverse{field}
247
- const decrementValues = Object.values(decrements);
248
- const { whereClause, values: whereValues } = this._buildWhereClause(where);
249
- const sql = `UPDATE
250
- const result = await this.query(sql, [...decrementValues, ...whereValues]);
251
- return result.changes;
138
+ async close() { return new Promise((resolve, reject) => this.db.close(err => err ? reject(err) : resolve())); }
139
+ _serializeValue(v) {
140
+ if (v instanceof Date)
141
+ return v.toISOString().slice(0, 19).replace('T', ' ');
142
+ return (typeof v === 'object' && v !== null) ? JSON.stringify(v) : v;
252
143
  }
253
- _buildWhereClause(where = {}) {
254
- const conditions = Object.keys(where);
255
- if (conditions.length === 0)
144
+ _buildWhereClause(where) {
145
+ if (!where)
256
146
  return { whereClause: '', values: [] };
257
- const whereClause = ' WHERE ' + conditions.map(key => `reverse{key}
258
- const values = Object.values(where).map(v => this._serializeValue(v));
259
- return { whereClause, values };
260
- }
261
- async close() {
262
- return new Promise((resolve, reject) => {
263
- this.db.close((err) => {
264
- if (err)
265
- reject(err);
266
- else
267
- resolve();
268
- });
269
- });
147
+ const safeWhere = where;
148
+ const keys = Object.keys(safeWhere);
149
+ if (!keys.length)
150
+ return { whereClause: '', values: [] };
151
+ return {
152
+ whereClause: 'WHERE ' + keys.map(k => `"${k}" = ?`).join(' AND '),
153
+ values: keys.map(k => this._serializeValue(safeWhere[k]))
154
+ };
270
155
  }
271
156
  }
272
157
  exports.SQLiteDatabase = SQLiteDatabase;
@@ -0,0 +1,35 @@
1
+ export interface DatabaseMetrics {
2
+ operation: string;
3
+ table: string;
4
+ duration: number;
5
+ timestamp: number;
6
+ }
7
+ export interface CacheMetrics {
8
+ hits: number;
9
+ misses: number;
10
+ keys: number;
11
+ }
12
+ declare class TelemetrySystem {
13
+ private dbMetrics;
14
+ private cacheStats;
15
+ private maxLogs;
16
+ recordDb(metric: DatabaseMetrics): void;
17
+ recordCacheHit(): void;
18
+ recordCacheMiss(): void;
19
+ getMetrics(): {
20
+ database: {
21
+ totalOperations: number;
22
+ averageDuration: string;
23
+ slowestOperations: DatabaseMetrics[];
24
+ recentLogs: DatabaseMetrics[];
25
+ };
26
+ cache: {
27
+ ratio: string;
28
+ hits: number;
29
+ misses: number;
30
+ };
31
+ };
32
+ clear(): void;
33
+ }
34
+ export declare const telemetry: TelemetrySystem;
35
+ export {};
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ // database/telemetry.ts
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.telemetry = void 0;
5
+ class TelemetrySystem {
6
+ constructor() {
7
+ this.dbMetrics = [];
8
+ this.cacheStats = { hits: 0, misses: 0 };
9
+ this.maxLogs = 1000;
10
+ }
11
+ recordDb(metric) {
12
+ this.dbMetrics.push(metric);
13
+ if (this.dbMetrics.length > this.maxLogs)
14
+ this.dbMetrics.shift();
15
+ }
16
+ recordCacheHit() { this.cacheStats.hits++; }
17
+ recordCacheMiss() { this.cacheStats.misses++; }
18
+ getMetrics() {
19
+ const totalOps = this.dbMetrics.length;
20
+ const avgDuration = totalOps > 0
21
+ ? this.dbMetrics.reduce((s, m) => s + m.duration, 0) / totalOps
22
+ : 0;
23
+ return {
24
+ database: {
25
+ totalOperations: totalOps,
26
+ averageDuration: avgDuration.toFixed(2) + 'ms',
27
+ slowestOperations: [...this.dbMetrics].sort((a, b) => b.duration - a.duration).slice(0, 5),
28
+ recentLogs: this.dbMetrics.slice(-10)
29
+ },
30
+ cache: {
31
+ ...this.cacheStats,
32
+ ratio: (this.cacheStats.hits / (this.cacheStats.hits + this.cacheStats.misses || 1) * 100).toFixed(2) + '%'
33
+ }
34
+ };
35
+ }
36
+ clear() {
37
+ this.dbMetrics = [];
38
+ this.cacheStats = { hits: 0, misses: 0 };
39
+ }
40
+ }
41
+ exports.telemetry = new TelemetrySystem();
@@ -0,0 +1,32 @@
1
+ import { IDatabase } from './IDatabase';
2
+ import { ToonConfig } from './types';
3
+ export declare class ToonDatabase extends IDatabase {
4
+ private filePath;
5
+ private db;
6
+ private isDirty;
7
+ private isWriting;
8
+ private writeQueue;
9
+ private saveDebounceTimeout;
10
+ private saveInterval;
11
+ private initPromise;
12
+ constructor(config: ToonConfig);
13
+ private _execute;
14
+ private _load;
15
+ private _queueRequest;
16
+ private _processQueue;
17
+ private _scheduleSave;
18
+ private _saveNow;
19
+ private flushSync;
20
+ ensureTable(table: string): Promise<void>;
21
+ insert(table: string, data: Record<string, any>): Promise<number>;
22
+ update(table: string, data: Record<string, any>, where: Record<string, any>): Promise<number>;
23
+ delete(table: string, where: Record<string, any>): Promise<number>;
24
+ select<T = any>(table: string, where?: Record<string, any> | null): Promise<T[]>;
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
+ bulkInsert(table: string, dataArray: Record<string, any>[]): Promise<number>;
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
+ close(): Promise<void>;
31
+ }
32
+ export default ToonDatabase;