@onurege3467/zerohelper 9.1.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/dist/bin/zero.js +1 -1
- package/dist/database/json.js +9 -9
- package/dist/database/mongodb.d.ts +2 -1
- package/dist/database/mongodb.js +2 -4
- package/dist/database/mysql.d.ts +5 -5
- package/dist/database/mysql.js +112 -93
- package/dist/database/pg.d.ts +1 -2
- package/dist/database/pg.js +40 -44
- package/dist/database/redis.d.ts +2 -1
- package/dist/database/redis.js +17 -21
- package/dist/database/sqlite.d.ts +2 -4
- package/dist/database/sqlite.js +44 -43
- package/dist/database/toon.d.ts +1 -5
- package/dist/database/toon.js +4 -5
- package/dist/database/types.d.ts +22 -37
- package/dist/database/zpack.d.ts +3 -5
- package/dist/database/zpack.js +24 -27
- package/package.json +2 -2
package/dist/bin/zero.js
CHANGED
package/dist/database/json.js
CHANGED
|
@@ -16,10 +16,10 @@ class JsonDatabase extends IDatabase_1.IDatabase {
|
|
|
16
16
|
this.isWriting = false;
|
|
17
17
|
this.writeQueue = [];
|
|
18
18
|
this.saveDebounceTimeout = null;
|
|
19
|
-
if (!config || !config.
|
|
20
|
-
throw new Error('
|
|
21
|
-
this.filePath = config.
|
|
22
|
-
this.saveInterval = 500;
|
|
19
|
+
if (!config || !config.path)
|
|
20
|
+
throw new Error('JsonDB: "path" gereklidir.');
|
|
21
|
+
this.filePath = config.path;
|
|
22
|
+
this.saveInterval = config.saveInterval || 500;
|
|
23
23
|
process.on('exit', () => this.flushSync());
|
|
24
24
|
this.initPromise = this._load();
|
|
25
25
|
}
|
|
@@ -89,7 +89,7 @@ class JsonDatabase extends IDatabase_1.IDatabase {
|
|
|
89
89
|
this.isDirty = false;
|
|
90
90
|
}
|
|
91
91
|
catch (error) {
|
|
92
|
-
console.error("
|
|
92
|
+
console.error("JsonDB save error:", error);
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
flushSync() {
|
|
@@ -128,7 +128,7 @@ class JsonDatabase extends IDatabase_1.IDatabase {
|
|
|
128
128
|
return this._queueRequest(() => {
|
|
129
129
|
let affected = 0;
|
|
130
130
|
this.db[table].forEach(row => {
|
|
131
|
-
if (Object.keys(where).every(k => row[k] === where[k])) {
|
|
131
|
+
if (Object.keys(where).every(k => String(row[k]) === String(where[k]))) {
|
|
132
132
|
Object.assign(row, data);
|
|
133
133
|
affected++;
|
|
134
134
|
}
|
|
@@ -144,7 +144,7 @@ class JsonDatabase extends IDatabase_1.IDatabase {
|
|
|
144
144
|
await this.ensureTable(table);
|
|
145
145
|
return this._queueRequest(() => {
|
|
146
146
|
const initial = this.db[table].length;
|
|
147
|
-
this.db[table] = this.db[table].filter(row => !Object.keys(where).every(k => row[k] === where[k]));
|
|
147
|
+
this.db[table] = this.db[table].filter(row => !Object.keys(where).every(k => String(row[k]) === String(where[k])));
|
|
148
148
|
const affected = initial - this.db[table].length;
|
|
149
149
|
this.runHooks('afterDelete', table, { affected });
|
|
150
150
|
return affected;
|
|
@@ -155,7 +155,7 @@ class JsonDatabase extends IDatabase_1.IDatabase {
|
|
|
155
155
|
return this._execute('select', table, async () => {
|
|
156
156
|
await this.initPromise;
|
|
157
157
|
const results = where && Object.keys(where).length > 0
|
|
158
|
-
? (this.db[table] || []).filter(row => Object.keys(where).every(k => row[k] === where[k]))
|
|
158
|
+
? (this.db[table] || []).filter(row => Object.keys(where).every(k => String(row[k]) === String(where[k])))
|
|
159
159
|
: (this.db[table] || []);
|
|
160
160
|
return JSON.parse(JSON.stringify(results));
|
|
161
161
|
});
|
|
@@ -186,7 +186,7 @@ class JsonDatabase extends IDatabase_1.IDatabase {
|
|
|
186
186
|
return this._queueRequest(() => {
|
|
187
187
|
let affected = 0;
|
|
188
188
|
this.db[table].forEach(row => {
|
|
189
|
-
if (Object.keys(where).every(k => row[k] === where[k])) {
|
|
189
|
+
if (Object.keys(where).every(k => String(row[k]) === String(where[k]))) {
|
|
190
190
|
for (const [f, v] of Object.entries(incs))
|
|
191
191
|
row[f] = (Number(row[f]) || 0) + v;
|
|
192
192
|
affected++;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { IDatabase } from './IDatabase';
|
|
2
|
+
import { MongoDBConfig } from './types';
|
|
2
3
|
export declare class MongoDBDatabase extends IDatabase {
|
|
3
4
|
private config;
|
|
4
5
|
private client;
|
|
@@ -6,7 +7,7 @@ export declare class MongoDBDatabase extends IDatabase {
|
|
|
6
7
|
private _queue;
|
|
7
8
|
private _connected;
|
|
8
9
|
private _connectionPromise;
|
|
9
|
-
constructor(config:
|
|
10
|
+
constructor(config: MongoDBConfig);
|
|
10
11
|
private _execute;
|
|
11
12
|
private _processQueue;
|
|
12
13
|
insert(collection: string, data: any): Promise<any>;
|
package/dist/database/mongodb.js
CHANGED
|
@@ -10,11 +10,11 @@ class MongoDBDatabase extends IDatabase_1.IDatabase {
|
|
|
10
10
|
this._queue = [];
|
|
11
11
|
this._connected = false;
|
|
12
12
|
this.config = config;
|
|
13
|
-
this.client = new mongodb_1.MongoClient(config.url || config.
|
|
13
|
+
this.client = new mongodb_1.MongoClient(config.url || `mongodb://${config.host || 'localhost'}:${config.port || 27017}`);
|
|
14
14
|
this._connectionPromise = new Promise(async (resolve, reject) => {
|
|
15
15
|
try {
|
|
16
16
|
await this.client.connect();
|
|
17
|
-
this.db = this.client.db(config.database ||
|
|
17
|
+
this.db = this.client.db(config.database || 'test');
|
|
18
18
|
this._connected = true;
|
|
19
19
|
resolve(this.db);
|
|
20
20
|
this._processQueue();
|
|
@@ -65,7 +65,6 @@ class MongoDBDatabase extends IDatabase_1.IDatabase {
|
|
|
65
65
|
return this._execute('update', collection, async () => {
|
|
66
66
|
const db = await this._connectionPromise;
|
|
67
67
|
const res = await db.collection(collection).updateMany(where, { $set: data });
|
|
68
|
-
await this.runHooks('afterUpdate', collection, { affected: res.modifiedCount });
|
|
69
68
|
return Number(res.modifiedCount);
|
|
70
69
|
});
|
|
71
70
|
}
|
|
@@ -74,7 +73,6 @@ class MongoDBDatabase extends IDatabase_1.IDatabase {
|
|
|
74
73
|
return this._execute('delete', collection, async () => {
|
|
75
74
|
const db = await this._connectionPromise;
|
|
76
75
|
const res = await db.collection(collection).deleteMany(where);
|
|
77
|
-
await this.runHooks('afterDelete', collection, { affected: res.deletedCount });
|
|
78
76
|
return res.deletedCount;
|
|
79
77
|
});
|
|
80
78
|
}
|
package/dist/database/mysql.d.ts
CHANGED
|
@@ -7,10 +7,11 @@ export declare class MySQLDatabase extends IDatabase {
|
|
|
7
7
|
private _connected;
|
|
8
8
|
private _connectionPromise;
|
|
9
9
|
constructor(config: MySQLConfig);
|
|
10
|
-
private
|
|
10
|
+
private _execute;
|
|
11
11
|
private _processQueue;
|
|
12
12
|
query(sql: string, params?: any[]): Promise<any>;
|
|
13
|
-
|
|
13
|
+
private _ensureMissingColumns;
|
|
14
|
+
ensureTable(table: string, data?: any): Promise<void>;
|
|
14
15
|
insert(table: string, data: Record<string, any>): Promise<number>;
|
|
15
16
|
update(table: string, data: Record<string, any>, where: Record<string, any>): Promise<number>;
|
|
16
17
|
delete(table: string, where: Record<string, any>): Promise<number>;
|
|
@@ -18,12 +19,11 @@ export declare class MySQLDatabase extends IDatabase {
|
|
|
18
19
|
selectOne<T = any>(table: string, where?: Record<string, any> | null): Promise<T | null>;
|
|
19
20
|
set(table: string, data: Record<string, any>, where: Record<string, any>): Promise<any>;
|
|
20
21
|
bulkInsert(table: string, dataArray: Record<string, any>[]): Promise<number>;
|
|
21
|
-
increment(table: string,
|
|
22
|
-
decrement(table: string,
|
|
22
|
+
increment(table: string, incs: Record<string, number>, where: Record<string, any>): Promise<number>;
|
|
23
|
+
decrement(table: string, decs: Record<string, number>, where: Record<string, any>): Promise<number>;
|
|
23
24
|
close(): Promise<void>;
|
|
24
25
|
private _getColumnType;
|
|
25
26
|
private _serializeValue;
|
|
26
|
-
private _deserializeValue;
|
|
27
27
|
private _buildWhereClause;
|
|
28
28
|
}
|
|
29
29
|
export default MySQLDatabase;
|
package/dist/database/mysql.js
CHANGED
|
@@ -16,32 +16,24 @@ class MySQLDatabase extends IDatabase_1.IDatabase {
|
|
|
16
16
|
this._connectionPromise = new Promise(async (resolve, reject) => {
|
|
17
17
|
try {
|
|
18
18
|
const connection = await promise_1.default.createConnection({
|
|
19
|
-
host: config.host,
|
|
19
|
+
host: config.host || 'localhost',
|
|
20
20
|
port: config.port || 3306,
|
|
21
|
-
user: config.
|
|
21
|
+
user: config.username,
|
|
22
22
|
password: config.password,
|
|
23
|
-
typeCast: (field, next) => {
|
|
24
|
-
if (field.type === 'TINY' && field.length === 1)
|
|
25
|
-
return (field.string() === '1');
|
|
26
|
-
if (['INT', 'DECIMAL', 'NEWDECIMAL', 'FLOAT', 'DOUBLE'].includes(field.type))
|
|
27
|
-
return Number(field.string());
|
|
28
|
-
return next();
|
|
29
|
-
}
|
|
30
23
|
});
|
|
31
|
-
await connection.query(`CREATE DATABASE IF NOT EXISTS
|
|
24
|
+
await connection.query(`CREATE DATABASE IF NOT EXISTS
|
|
32
25
|
${config.database}
|
|
33
26
|
`);
|
|
34
27
|
await connection.end();
|
|
35
28
|
this.pool = promise_1.default.createPool({
|
|
36
|
-
host: config.host
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
29
|
+
host: config.host || 'localhost',
|
|
30
|
+
port: config.port || 3306,
|
|
31
|
+
user: config.username,
|
|
32
|
+
password: config.password,
|
|
33
|
+
database: config.database,
|
|
34
|
+
waitForConnections: true,
|
|
35
|
+
connectionLimit: config.poolSize || 10,
|
|
36
|
+
queueLimit: 0,
|
|
45
37
|
});
|
|
46
38
|
this._connected = true;
|
|
47
39
|
resolve(this.pool);
|
|
@@ -52,18 +44,16 @@ ${config.database}
|
|
|
52
44
|
}
|
|
53
45
|
});
|
|
54
46
|
}
|
|
55
|
-
async
|
|
47
|
+
async _execute(op, table, fn) {
|
|
56
48
|
const start = Date.now();
|
|
57
49
|
const execute = async () => {
|
|
58
|
-
const res = await
|
|
59
|
-
this.recordMetric(
|
|
50
|
+
const res = await fn();
|
|
51
|
+
this.recordMetric(op, table, Date.now() - start);
|
|
60
52
|
return res;
|
|
61
53
|
};
|
|
62
54
|
if (this._connected)
|
|
63
55
|
return execute();
|
|
64
|
-
return new Promise((resolve, reject) => {
|
|
65
|
-
this._queue.push({ operation: execute, resolve, reject });
|
|
66
|
-
});
|
|
56
|
+
return new Promise((resolve, reject) => this._queue.push({ operation: execute, resolve, reject }));
|
|
67
57
|
}
|
|
68
58
|
async _processQueue() {
|
|
69
59
|
if (!this._connected)
|
|
@@ -85,122 +75,155 @@ ${config.database}
|
|
|
85
75
|
const [rows] = await pool.execute(sql, params);
|
|
86
76
|
return rows;
|
|
87
77
|
}
|
|
78
|
+
async _ensureMissingColumns(table, data) {
|
|
79
|
+
const existingColumns = await this.query(`DESCRIBE
|
|
80
|
+
${table}
|
|
81
|
+
`).catch(() => []);
|
|
82
|
+
const columnNames = existingColumns.map(col => col.Field);
|
|
83
|
+
for (const key of Object.keys(data)) {
|
|
84
|
+
if (key !== '_id' && !columnNames.includes(key)) {
|
|
85
|
+
await this.query(`ALTER TABLE
|
|
86
|
+
${table}
|
|
87
|
+
ADD COLUMN
|
|
88
|
+
${key}
|
|
89
|
+
TEXT`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
88
93
|
async ensureTable(table, data = {}) {
|
|
89
94
|
const escapedTable = promise_1.default.escape(table);
|
|
90
95
|
const tables = await this.query(`SHOW TABLES LIKE ${escapedTable}`);
|
|
91
96
|
if (tables.length === 0) {
|
|
92
|
-
const
|
|
93
|
-
${
|
|
94
|
-
|
|
95
|
-
const columnsPart =
|
|
96
|
-
await this.query(`CREATE TABLE
|
|
97
|
+
const defs = Object.keys(data).map(k => `
|
|
98
|
+
${k}
|
|
99
|
+
TEXT`);
|
|
100
|
+
const columnsPart = defs.length > 0 ? ', ' + defs.join(", ") : '';
|
|
101
|
+
await this.query(`CREATE TABLE
|
|
97
102
|
${table}
|
|
98
103
|
(_id INT PRIMARY KEY AUTO_INCREMENT ${columnsPart}) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4`);
|
|
99
104
|
}
|
|
105
|
+
else {
|
|
106
|
+
await this._ensureMissingColumns(table, data);
|
|
107
|
+
}
|
|
100
108
|
}
|
|
101
109
|
async insert(table, data) {
|
|
102
110
|
await this.runHooks('beforeInsert', table, data);
|
|
103
|
-
return this.
|
|
111
|
+
return this._execute('insert', table, async () => {
|
|
104
112
|
await this.ensureTable(table, data);
|
|
105
113
|
const keys = Object.keys(data);
|
|
106
|
-
const
|
|
107
|
-
const values = Object.values(data).map(v => this._serializeValue(v));
|
|
108
|
-
const sql = `INSERT INTO
|
|
114
|
+
const sql = `INSERT INTO
|
|
109
115
|
${table}
|
|
110
116
|
(${keys.map(k => `
|
|
111
117
|
${k}
|
|
112
|
-
`).join(",")}) VALUES (${
|
|
113
|
-
const result = await this.query(sql, values);
|
|
118
|
+
`).join(",")}) VALUES (${keys.map(() => '?').join(",")})`;
|
|
119
|
+
const result = await this.query(sql, Object.values(data).map(v => typeof v === 'object' ? JSON.stringify(v) : v));
|
|
114
120
|
const finalData = { _id: result.insertId, ...data };
|
|
115
121
|
await this.runHooks('afterInsert', table, finalData);
|
|
116
122
|
return result.insertId;
|
|
117
|
-
}
|
|
123
|
+
});
|
|
118
124
|
}
|
|
119
125
|
async update(table, data, where) {
|
|
120
126
|
await this.runHooks('beforeUpdate', table, { data, where });
|
|
121
|
-
return this.
|
|
122
|
-
|
|
127
|
+
return this._execute('update', table, async () => {
|
|
128
|
+
await this.ensureTable(table, { ...data, ...where });
|
|
129
|
+
const set = Object.keys(data).map(k => `
|
|
123
130
|
${k}
|
|
124
131
|
= ?`).join(", ");
|
|
125
|
-
const
|
|
126
|
-
const sql = `UPDATE
|
|
132
|
+
const wKeys = Object.keys(where);
|
|
133
|
+
const sql = `UPDATE
|
|
127
134
|
${table}
|
|
128
|
-
SET ${
|
|
129
|
-
|
|
130
|
-
|
|
135
|
+
SET ${set} WHERE ${wKeys.map(k => `
|
|
136
|
+
${k}
|
|
137
|
+
= ?`).join(" AND ")}`;
|
|
138
|
+
const result = await this.query(sql, [...Object.values(data).map(v => typeof v === 'object' ? JSON.stringify(v) : v), ...Object.values(where).map(v => typeof v === 'object' ? JSON.stringify(v) : v)]);
|
|
131
139
|
return result.affectedRows;
|
|
132
|
-
}
|
|
140
|
+
});
|
|
133
141
|
}
|
|
134
142
|
async delete(table, where) {
|
|
135
143
|
await this.runHooks('beforeDelete', table, where);
|
|
136
|
-
return this.
|
|
137
|
-
|
|
138
|
-
const
|
|
144
|
+
return this._execute('delete', table, async () => {
|
|
145
|
+
await this.ensureTable(table, where);
|
|
146
|
+
const keys = Object.keys(where);
|
|
147
|
+
const sql = `DELETE FROM
|
|
139
148
|
${table}
|
|
140
|
-
${
|
|
141
|
-
|
|
142
|
-
|
|
149
|
+
WHERE ${keys.map(k => `
|
|
150
|
+
${k}
|
|
151
|
+
= ?`).join(" AND ")}`;
|
|
152
|
+
const result = await this.query(sql, Object.values(where).map(v => typeof v === 'object' ? JSON.stringify(v) : v));
|
|
143
153
|
return result.affectedRows;
|
|
144
|
-
}
|
|
154
|
+
});
|
|
145
155
|
}
|
|
146
156
|
async select(table, where = null) {
|
|
147
|
-
return this.
|
|
148
|
-
|
|
149
|
-
const
|
|
157
|
+
return this._execute('select', table, async () => {
|
|
158
|
+
await this.ensureTable(table, where || {});
|
|
159
|
+
const keys = where ? Object.keys(where) : [];
|
|
160
|
+
const sql = `SELECT * FROM
|
|
150
161
|
${table}
|
|
151
|
-
|
|
162
|
+
` + (keys.length ? ' WHERE ' + keys.map(k => `
|
|
163
|
+
${k}
|
|
164
|
+
= ?`).join(" AND ") : '');
|
|
165
|
+
const rows = await this.query(sql, keys.map(k => typeof where[k] === 'object' ? JSON.stringify(where[k]) : where[k]));
|
|
152
166
|
return rows.map((row) => {
|
|
153
|
-
const
|
|
154
|
-
for (const
|
|
155
|
-
|
|
156
|
-
|
|
167
|
+
const nr = {};
|
|
168
|
+
for (const k in row) {
|
|
169
|
+
try {
|
|
170
|
+
nr[k] = JSON.parse(row[k]);
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
nr[k] = row[k];
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return nr;
|
|
157
177
|
});
|
|
158
|
-
}
|
|
178
|
+
});
|
|
159
179
|
}
|
|
160
180
|
async selectOne(table, where = null) {
|
|
161
|
-
const
|
|
162
|
-
return
|
|
181
|
+
const res = await this.select(table, where);
|
|
182
|
+
return res[0] || null;
|
|
163
183
|
}
|
|
164
184
|
async set(table, data, where) {
|
|
165
185
|
const existing = await this.selectOne(table, where);
|
|
166
186
|
return existing ? this.update(table, data, where) : this.insert(table, { ...where, ...data });
|
|
167
187
|
}
|
|
168
188
|
async bulkInsert(table, dataArray) {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
189
|
+
if (!dataArray.length)
|
|
190
|
+
return 0;
|
|
191
|
+
return this._execute('bulkInsert', table, async () => {
|
|
172
192
|
await this.ensureTable(table, dataArray[0]);
|
|
173
193
|
const keys = Object.keys(dataArray[0]);
|
|
174
194
|
const placeholders = dataArray.map(() => `(${keys.map(() => '?').join(',')})`).join(',');
|
|
175
195
|
const values = dataArray.flatMap(obj => keys.map(k => this._serializeValue(obj[k])));
|
|
176
|
-
const sql = `INSERT INTO
|
|
196
|
+
const sql = `INSERT INTO
|
|
177
197
|
${table}
|
|
178
198
|
(${keys.map(k => `
|
|
179
199
|
${k}
|
|
180
200
|
`).join(",")}) VALUES ${placeholders}`;
|
|
181
201
|
const result = await this.query(sql, values);
|
|
182
202
|
return result.affectedRows;
|
|
183
|
-
}
|
|
203
|
+
});
|
|
184
204
|
}
|
|
185
|
-
async increment(table,
|
|
186
|
-
return this.
|
|
187
|
-
|
|
205
|
+
async increment(table, incs, where) {
|
|
206
|
+
return this._execute('increment', table, async () => {
|
|
207
|
+
await this.ensureTable(table, where);
|
|
208
|
+
const set = Object.keys(incs).map(f => `
|
|
188
209
|
${f}
|
|
189
|
-
=
|
|
210
|
+
=
|
|
190
211
|
${f}
|
|
191
212
|
+ ?`).join(', ');
|
|
192
|
-
const
|
|
193
|
-
const sql = `UPDATE
|
|
213
|
+
const wKeys = Object.keys(where);
|
|
214
|
+
const sql = `UPDATE
|
|
194
215
|
${table}
|
|
195
|
-
SET ${
|
|
196
|
-
|
|
216
|
+
SET ${set} WHERE ${wKeys.map(k => `
|
|
217
|
+
${k}
|
|
218
|
+
= ?`).join(" AND ")}`;
|
|
219
|
+
const result = await this.query(sql, [...Object.values(incs), ...Object.values(where).map(v => typeof v === 'object' ? JSON.stringify(v) : v)]);
|
|
197
220
|
return result.affectedRows;
|
|
198
|
-
}
|
|
221
|
+
});
|
|
199
222
|
}
|
|
200
|
-
async decrement(table,
|
|
223
|
+
async decrement(table, decs, where) {
|
|
201
224
|
const incs = {};
|
|
202
|
-
for (const k in
|
|
203
|
-
incs[k] = -
|
|
225
|
+
for (const k in decs)
|
|
226
|
+
incs[k] = -decs[k];
|
|
204
227
|
return this.increment(table, incs, where);
|
|
205
228
|
}
|
|
206
229
|
async close() { if (this.pool)
|
|
@@ -214,6 +237,8 @@ ${table}
|
|
|
214
237
|
return Number.isInteger(v) ? 'INT' : 'DOUBLE';
|
|
215
238
|
if (v instanceof Date)
|
|
216
239
|
return 'DATETIME';
|
|
240
|
+
if (typeof v === 'object')
|
|
241
|
+
return 'JSON';
|
|
217
242
|
return 'TEXT';
|
|
218
243
|
}
|
|
219
244
|
_serializeValue(v) {
|
|
@@ -221,24 +246,18 @@ ${table}
|
|
|
221
246
|
return v.toISOString().slice(0, 19).replace('T', ' ');
|
|
222
247
|
return (typeof v === 'object' && v !== null) ? JSON.stringify(v) : v;
|
|
223
248
|
}
|
|
224
|
-
_deserializeValue(v) {
|
|
225
|
-
if (typeof v === 'string' && (v.startsWith('{') || v.startsWith('['))) {
|
|
226
|
-
try {
|
|
227
|
-
return JSON.parse(v);
|
|
228
|
-
}
|
|
229
|
-
catch {
|
|
230
|
-
return v;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
return v;
|
|
234
|
-
}
|
|
235
249
|
_buildWhereClause(where) {
|
|
250
|
+
if (!where)
|
|
251
|
+
return { whereClause: '', values: [] };
|
|
236
252
|
const keys = Object.keys(where);
|
|
237
253
|
if (!keys.length)
|
|
238
254
|
return { whereClause: '', values: [] };
|
|
239
|
-
return {
|
|
255
|
+
return {
|
|
256
|
+
whereClause: 'WHERE ' + keys.map(k => `
|
|
240
257
|
${k}
|
|
241
|
-
= ?`).join(' AND '),
|
|
258
|
+
= ?`).join(' AND '),
|
|
259
|
+
values: Object.values(where).map(v => this._serializeValue(v))
|
|
260
|
+
};
|
|
242
261
|
}
|
|
243
262
|
}
|
|
244
263
|
exports.MySQLDatabase = MySQLDatabase;
|
package/dist/database/pg.d.ts
CHANGED
|
@@ -10,7 +10,6 @@ export declare class PostgreSQLDatabase extends IDatabase {
|
|
|
10
10
|
private _execute;
|
|
11
11
|
private _processQueue;
|
|
12
12
|
query(sql: string, params?: any[]): Promise<any>;
|
|
13
|
-
private _ensureMissingColumns;
|
|
14
13
|
ensureTable(table: string, data?: any): Promise<void>;
|
|
15
14
|
insert(table: string, data: any): Promise<any>;
|
|
16
15
|
update(table: string, data: any, where: any): Promise<number>;
|
|
@@ -24,6 +23,6 @@ export declare class PostgreSQLDatabase extends IDatabase {
|
|
|
24
23
|
close(): Promise<void>;
|
|
25
24
|
private _getColumnType;
|
|
26
25
|
private _serializeValue;
|
|
27
|
-
private
|
|
26
|
+
private _buildWhereClause;
|
|
28
27
|
}
|
|
29
28
|
export default PostgreSQLDatabase;
|
package/dist/database/pg.js
CHANGED
|
@@ -12,7 +12,7 @@ class PostgreSQLDatabase extends IDatabase_1.IDatabase {
|
|
|
12
12
|
this.config = config;
|
|
13
13
|
this._connectionPromise = new Promise(async (resolve, reject) => {
|
|
14
14
|
try {
|
|
15
|
-
const tempPool = new pg_1.Pool({ host: config.host, port: config.port || 5432, user: config.
|
|
15
|
+
const tempPool = new pg_1.Pool({ host: config.host || 'localhost', port: config.port || 5432, user: config.username, password: config.password, database: 'postgres' });
|
|
16
16
|
try {
|
|
17
17
|
await tempPool.query(`CREATE DATABASE "${config.database}"`);
|
|
18
18
|
}
|
|
@@ -21,7 +21,7 @@ class PostgreSQLDatabase extends IDatabase_1.IDatabase {
|
|
|
21
21
|
console.warn(e.message);
|
|
22
22
|
}
|
|
23
23
|
await tempPool.end();
|
|
24
|
-
this.pool = new pg_1.Pool({ host: config.host, port: config.port || 5432, user: config.
|
|
24
|
+
this.pool = new pg_1.Pool({ host: config.host || 'localhost', port: config.port || 5432, user: config.username, password: config.password, database: config.database, max: config.poolSize || 10 });
|
|
25
25
|
this._connected = true;
|
|
26
26
|
resolve(this.pool);
|
|
27
27
|
this._processQueue();
|
|
@@ -33,15 +33,11 @@ class PostgreSQLDatabase extends IDatabase_1.IDatabase {
|
|
|
33
33
|
}
|
|
34
34
|
async _execute(op, table, fn) {
|
|
35
35
|
const start = Date.now();
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return res;
|
|
40
|
-
};
|
|
41
|
-
if (this._connected)
|
|
42
|
-
return execute();
|
|
43
|
-
return new Promise((resolve, reject) => this._queue.push({ operation: execute, resolve, reject }));
|
|
36
|
+
const res = await fn();
|
|
37
|
+
this.recordMetric(op, table, Date.now() - start);
|
|
38
|
+
return res;
|
|
44
39
|
}
|
|
40
|
+
;
|
|
45
41
|
async _processQueue() {
|
|
46
42
|
if (!this._connected)
|
|
47
43
|
return;
|
|
@@ -62,24 +58,20 @@ class PostgreSQLDatabase extends IDatabase_1.IDatabase {
|
|
|
62
58
|
const res = await pool.query(sql, params);
|
|
63
59
|
return res.rows;
|
|
64
60
|
}
|
|
65
|
-
async _ensureMissingColumns(table, data) {
|
|
66
|
-
const existing = await this.query(`SELECT column_name FROM information_schema.columns WHERE table_name = $1 AND table_schema = 'public'`, [table]);
|
|
67
|
-
const names = existing.map((c) => c.column_name);
|
|
68
|
-
for (const key of Object.keys(data)) {
|
|
69
|
-
if (key !== '_id' && !names.includes(key)) {
|
|
70
|
-
const type = this._getColumnType(data[key]);
|
|
71
|
-
await this.query(`ALTER TABLE "${table}" ADD COLUMN "${key}" ${type}`);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
61
|
async ensureTable(table, data = {}) {
|
|
76
62
|
const tables = await this.query(`SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_name = $1`, [table]);
|
|
77
63
|
if (tables.length === 0) {
|
|
78
|
-
const defs = Object.keys(data).map(k => `"${k}"
|
|
64
|
+
const defs = Object.keys(data).map(k => `"${k}" TEXT`);
|
|
79
65
|
await this.query(`CREATE TABLE "${table}" ("_id" SERIAL PRIMARY KEY ${defs.length ? ', ' + defs.join(",") : ''})`);
|
|
80
66
|
}
|
|
81
67
|
else {
|
|
82
|
-
await this.
|
|
68
|
+
const existing = await this.query(`SELECT column_name FROM information_schema.columns WHERE table_name = $1 AND table_schema = 'public'`, [table]);
|
|
69
|
+
const names = existing.map((c) => c.column_name);
|
|
70
|
+
for (const key of Object.keys(data)) {
|
|
71
|
+
if (key !== '_id' && !names.includes(key)) {
|
|
72
|
+
await this.query(`ALTER TABLE "${table}" ADD COLUMN "${key}" TEXT`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
83
75
|
}
|
|
84
76
|
}
|
|
85
77
|
async insert(table, data) {
|
|
@@ -99,10 +91,10 @@ class PostgreSQLDatabase extends IDatabase_1.IDatabase {
|
|
|
99
91
|
return this._execute('update', table, async () => {
|
|
100
92
|
await this.ensureTable(table, { ...data, ...where });
|
|
101
93
|
const set = Object.keys(data).map((k, i) => `"${k}" = $${i + 1}`).join(",");
|
|
102
|
-
const
|
|
103
|
-
const sql = `UPDATE "${table}" SET ${set}
|
|
94
|
+
const { whereClause, values: whereValues } = this._buildWhereClause(where);
|
|
95
|
+
const sql = `UPDATE "${table}" SET ${set} ${whereClause}`;
|
|
104
96
|
const pool = await this._connectionPromise;
|
|
105
|
-
const res = await pool.query(sql, [...Object.values(data).map(v => this._serializeValue(v)), ...
|
|
97
|
+
const res = await pool.query(sql, [...Object.values(data).map(v => this._serializeValue(v)), ...whereValues]);
|
|
106
98
|
return res.rowCount ?? 0;
|
|
107
99
|
});
|
|
108
100
|
}
|
|
@@ -110,23 +102,22 @@ class PostgreSQLDatabase extends IDatabase_1.IDatabase {
|
|
|
110
102
|
await this.runHooks('beforeDelete', table, where);
|
|
111
103
|
return this._execute('delete', table, async () => {
|
|
112
104
|
await this.ensureTable(table, where);
|
|
113
|
-
const
|
|
114
|
-
const sql = `DELETE FROM "${table}"
|
|
105
|
+
const { whereClause, values } = this._buildWhereClause(where);
|
|
106
|
+
const sql = `DELETE FROM "${table}" ${whereClause}`;
|
|
115
107
|
const pool = await this._connectionPromise;
|
|
116
|
-
const res = await pool.query(sql,
|
|
108
|
+
const res = await pool.query(sql, values);
|
|
117
109
|
return res.rowCount ?? 0;
|
|
118
110
|
});
|
|
119
111
|
}
|
|
120
112
|
async select(table, where = null) {
|
|
121
113
|
return this._execute('select', table, async () => {
|
|
122
114
|
await this.ensureTable(table, where || {});
|
|
123
|
-
const
|
|
124
|
-
const
|
|
125
|
-
const rows = await this.query(sql, Object.values(where || {}).map(v => this._serializeValue(v)));
|
|
115
|
+
const { whereClause, values } = this._buildWhereClause(where);
|
|
116
|
+
const rows = await this.query(`SELECT * FROM "${table}" ${whereClause}`, values);
|
|
126
117
|
return rows.map((r) => {
|
|
127
118
|
const nr = {};
|
|
128
119
|
for (const k in r)
|
|
129
|
-
nr[k] =
|
|
120
|
+
nr[k] = r[k];
|
|
130
121
|
return nr;
|
|
131
122
|
});
|
|
132
123
|
});
|
|
@@ -142,21 +133,18 @@ class PostgreSQLDatabase extends IDatabase_1.IDatabase {
|
|
|
142
133
|
async bulkInsert(table, dataArray) {
|
|
143
134
|
if (!dataArray.length)
|
|
144
135
|
return 0;
|
|
145
|
-
|
|
146
|
-
await this.
|
|
147
|
-
|
|
148
|
-
await this.insert(table, d);
|
|
149
|
-
return dataArray.length;
|
|
150
|
-
});
|
|
136
|
+
for (const d of dataArray)
|
|
137
|
+
await this.insert(table, d);
|
|
138
|
+
return dataArray.length;
|
|
151
139
|
}
|
|
152
140
|
async increment(table, incs, where) {
|
|
153
141
|
return this._execute('increment', table, async () => {
|
|
154
142
|
await this.ensureTable(table, where);
|
|
155
143
|
const set = Object.keys(incs).map((f, i) => `"${f}" = "${f}" + $${i + 1}`).join(',');
|
|
156
|
-
const
|
|
157
|
-
const sql = `UPDATE "${table}" SET ${set}
|
|
144
|
+
const { whereClause, values } = this._buildWhereClause(where);
|
|
145
|
+
const sql = `UPDATE "${table}" SET ${set} ${whereClause}`;
|
|
158
146
|
const pool = await this._connectionPromise;
|
|
159
|
-
const res = await pool.query(sql, [...Object.values(incs), ...
|
|
147
|
+
const res = await pool.query(sql, [...Object.values(incs), ...values]);
|
|
160
148
|
return res.rowCount ?? 0;
|
|
161
149
|
});
|
|
162
150
|
}
|
|
@@ -186,9 +174,17 @@ class PostgreSQLDatabase extends IDatabase_1.IDatabase {
|
|
|
186
174
|
return v.toISOString();
|
|
187
175
|
return (typeof v === 'object' && v !== null) ? JSON.stringify(v) : v;
|
|
188
176
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
177
|
+
_buildWhereClause(where) {
|
|
178
|
+
if (!where)
|
|
179
|
+
return { whereClause: '', values: [] };
|
|
180
|
+
const safeWhere = where;
|
|
181
|
+
const keys = Object.keys(safeWhere);
|
|
182
|
+
if (!keys.length)
|
|
183
|
+
return { whereClause: '', values: [] };
|
|
184
|
+
return {
|
|
185
|
+
whereClause: 'WHERE ' + keys.map((k, i) => `"${k}" = $${i + 1}`).join(' AND '),
|
|
186
|
+
values: keys.map(k => this._serializeValue(safeWhere[k]))
|
|
187
|
+
};
|
|
192
188
|
}
|
|
193
189
|
}
|
|
194
190
|
exports.PostgreSQLDatabase = PostgreSQLDatabase;
|
package/dist/database/redis.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { IDatabase } from './IDatabase';
|
|
2
2
|
import { RedisClientType } from 'redis';
|
|
3
|
+
import { RedisConfig } from './types';
|
|
3
4
|
export declare class RedisDatabase extends IDatabase {
|
|
4
5
|
private config;
|
|
5
6
|
private client;
|
|
6
7
|
private isConnecting;
|
|
7
8
|
private keyPrefix;
|
|
8
|
-
constructor(config
|
|
9
|
+
constructor(config: RedisConfig);
|
|
9
10
|
private _execute;
|
|
10
11
|
connect(): Promise<RedisClientType>;
|
|
11
12
|
private _getKey;
|
package/dist/database/redis.js
CHANGED
|
@@ -4,17 +4,11 @@ exports.RedisDatabase = void 0;
|
|
|
4
4
|
const IDatabase_1 = require("./IDatabase");
|
|
5
5
|
const redis_1 = require("redis");
|
|
6
6
|
class RedisDatabase extends IDatabase_1.IDatabase {
|
|
7
|
-
constructor(config
|
|
7
|
+
constructor(config) {
|
|
8
8
|
super();
|
|
9
9
|
this.client = null;
|
|
10
10
|
this.isConnecting = false;
|
|
11
|
-
this.config =
|
|
12
|
-
host: config.host || '127.0.0.1',
|
|
13
|
-
port: config.port || 6379,
|
|
14
|
-
password: config.password,
|
|
15
|
-
db: config.db || 0,
|
|
16
|
-
connectTimeout: config.connectTimeout || 5000,
|
|
17
|
-
};
|
|
11
|
+
this.config = config;
|
|
18
12
|
this.keyPrefix = config.keyPrefix || 'app:';
|
|
19
13
|
}
|
|
20
14
|
async _execute(op, table, fn) {
|
|
@@ -23,6 +17,7 @@ class RedisDatabase extends IDatabase_1.IDatabase {
|
|
|
23
17
|
this.recordMetric(op, table, Date.now() - start);
|
|
24
18
|
return res;
|
|
25
19
|
}
|
|
20
|
+
;
|
|
26
21
|
async connect() {
|
|
27
22
|
if (this.client && this.client.isReady)
|
|
28
23
|
return this.client;
|
|
@@ -34,9 +29,10 @@ class RedisDatabase extends IDatabase_1.IDatabase {
|
|
|
34
29
|
this.isConnecting = true;
|
|
35
30
|
try {
|
|
36
31
|
this.client = (0, redis_1.createClient)({
|
|
37
|
-
|
|
32
|
+
url: this.config.url,
|
|
33
|
+
socket: { host: this.config.host || '127.0.0.1', port: this.config.port || 6379 },
|
|
38
34
|
password: this.config.password,
|
|
39
|
-
database: this.config.
|
|
35
|
+
database: Number(this.config.database) || 0,
|
|
40
36
|
});
|
|
41
37
|
await this.client.connect();
|
|
42
38
|
return this.client;
|
|
@@ -82,8 +78,7 @@ class RedisDatabase extends IDatabase_1.IDatabase {
|
|
|
82
78
|
const client = await this.connect();
|
|
83
79
|
for (const item of existing) {
|
|
84
80
|
const merged = { ...item, ...data };
|
|
85
|
-
|
|
86
|
-
await client.set(this._getKey(table, id), JSON.stringify(merged));
|
|
81
|
+
await client.set(this._getKey(table, item._id || item.id), JSON.stringify(merged));
|
|
87
82
|
}
|
|
88
83
|
return existing.length;
|
|
89
84
|
});
|
|
@@ -110,15 +105,16 @@ class RedisDatabase extends IDatabase_1.IDatabase {
|
|
|
110
105
|
return dataArray.length;
|
|
111
106
|
}
|
|
112
107
|
async increment(table, incs, where = {}) {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
for (const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
108
|
+
return this._execute('increment', table, async () => {
|
|
109
|
+
const recs = await this.select(table, where);
|
|
110
|
+
const client = await this.connect();
|
|
111
|
+
for (const r of recs) {
|
|
112
|
+
for (const [f, v] of Object.entries(incs))
|
|
113
|
+
r[f] = (Number(r[f]) || 0) + v;
|
|
114
|
+
await client.set(this._getKey(table, r._id || r.id), JSON.stringify(r));
|
|
115
|
+
}
|
|
116
|
+
return recs.length;
|
|
117
|
+
});
|
|
122
118
|
}
|
|
123
119
|
async decrement(table, decs, where = {}) {
|
|
124
120
|
const incs = {};
|
|
@@ -5,10 +5,6 @@ export declare class SQLiteDatabase extends IDatabase {
|
|
|
5
5
|
constructor(config: SQLiteConfig);
|
|
6
6
|
private _execute;
|
|
7
7
|
query(sql: string, params?: any[]): Promise<any>;
|
|
8
|
-
/**
|
|
9
|
-
* SQLite dynamically adds missing columns using ALTER TABLE.
|
|
10
|
-
*/
|
|
11
|
-
private _ensureMissingColumns;
|
|
12
8
|
ensureTable(table: string, data?: any): Promise<void>;
|
|
13
9
|
insert(table: string, data: any): Promise<number>;
|
|
14
10
|
update(table: string, data: any, where: any): Promise<number>;
|
|
@@ -20,5 +16,7 @@ export declare class SQLiteDatabase extends IDatabase {
|
|
|
20
16
|
increment(table: string, incs: any, where: any): Promise<number>;
|
|
21
17
|
decrement(table: string, decs: any, where: any): Promise<number>;
|
|
22
18
|
close(): Promise<void>;
|
|
19
|
+
private _serializeValue;
|
|
20
|
+
private _buildWhereClause;
|
|
23
21
|
}
|
|
24
22
|
export default SQLiteDatabase;
|
package/dist/database/sqlite.js
CHANGED
|
@@ -11,12 +11,12 @@ 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.
|
|
15
|
-
throw new Error('SQLite "
|
|
16
|
-
const dir = path_1.default.dirname(config.
|
|
14
|
+
if (!config || !config.path)
|
|
15
|
+
throw new Error('SQLite "path" gereklidir.');
|
|
16
|
+
const dir = path_1.default.dirname(config.path);
|
|
17
17
|
if (!fs_1.default.existsSync(dir))
|
|
18
18
|
fs_1.default.mkdirSync(dir, { recursive: true });
|
|
19
|
-
this.db = new sqlite3_1.default.Database(config.
|
|
19
|
+
this.db = new sqlite3_1.default.Database(config.path);
|
|
20
20
|
}
|
|
21
21
|
async _execute(op, table, fn) {
|
|
22
22
|
const start = Date.now();
|
|
@@ -24,6 +24,7 @@ class SQLiteDatabase extends IDatabase_1.IDatabase {
|
|
|
24
24
|
this.recordMetric(op, table, Date.now() - start);
|
|
25
25
|
return res;
|
|
26
26
|
}
|
|
27
|
+
;
|
|
27
28
|
async query(sql, params = []) {
|
|
28
29
|
return new Promise((resolve, reject) => {
|
|
29
30
|
const s = sql.trim().toUpperCase();
|
|
@@ -35,22 +36,16 @@ class SQLiteDatabase extends IDatabase_1.IDatabase {
|
|
|
35
36
|
}
|
|
36
37
|
});
|
|
37
38
|
}
|
|
38
|
-
/**
|
|
39
|
-
* SQLite dynamically adds missing columns using ALTER TABLE.
|
|
40
|
-
*/
|
|
41
|
-
async _ensureMissingColumns(table, data) {
|
|
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
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
39
|
async ensureTable(table, data = {}) {
|
|
51
40
|
try {
|
|
52
41
|
await this.query(`SELECT 1 FROM "${table}" LIMIT 1`);
|
|
53
|
-
await this.
|
|
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
|
+
}
|
|
48
|
+
}
|
|
54
49
|
}
|
|
55
50
|
catch {
|
|
56
51
|
const defs = Object.keys(data).map(k => `"${k}" TEXT`);
|
|
@@ -63,7 +58,7 @@ class SQLiteDatabase extends IDatabase_1.IDatabase {
|
|
|
63
58
|
await this.ensureTable(table, data);
|
|
64
59
|
const keys = Object.keys(data);
|
|
65
60
|
const sql = `INSERT INTO "${table}" (${keys.map(k => `"${k}"`).join(',')}) VALUES (${keys.map(() => '?').join(',')})`;
|
|
66
|
-
const res = await this.query(sql, Object.values(data).map(v => JSON.stringify(v)));
|
|
61
|
+
const res = await this.query(sql, Object.values(data).map(v => typeof v === 'object' ? JSON.stringify(v) : v));
|
|
67
62
|
const finalData = { _id: res.lastID, ...data };
|
|
68
63
|
await this.runHooks('afterInsert', table, finalData);
|
|
69
64
|
return res.lastID;
|
|
@@ -74,9 +69,9 @@ class SQLiteDatabase extends IDatabase_1.IDatabase {
|
|
|
74
69
|
return this._execute('update', table, async () => {
|
|
75
70
|
await this.ensureTable(table, { ...data, ...where });
|
|
76
71
|
const set = Object.keys(data).map(k => `"${k}" = ?`).join(',');
|
|
77
|
-
const
|
|
78
|
-
const sql = `UPDATE "${table}" SET ${set}
|
|
79
|
-
const res = await this.query(sql, [...Object.values(data).map(v =>
|
|
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]);
|
|
80
75
|
return res.changes;
|
|
81
76
|
});
|
|
82
77
|
}
|
|
@@ -84,18 +79,17 @@ class SQLiteDatabase extends IDatabase_1.IDatabase {
|
|
|
84
79
|
await this.runHooks('beforeDelete', table, where);
|
|
85
80
|
return this._execute('delete', table, async () => {
|
|
86
81
|
await this.ensureTable(table, where);
|
|
87
|
-
const
|
|
88
|
-
const sql = `DELETE FROM "${table}"
|
|
89
|
-
const res = await this.query(sql,
|
|
82
|
+
const { whereClause, values } = this._buildWhereClause(where);
|
|
83
|
+
const sql = `DELETE FROM "${table}" ${whereClause}`;
|
|
84
|
+
const res = await this.query(sql, values);
|
|
90
85
|
return res.changes;
|
|
91
86
|
});
|
|
92
87
|
}
|
|
93
88
|
async select(table, where = null) {
|
|
94
89
|
return this._execute('select', table, async () => {
|
|
95
90
|
await this.ensureTable(table, where || {});
|
|
96
|
-
const
|
|
97
|
-
const
|
|
98
|
-
const rows = await this.query(sql, keys.map(k => JSON.stringify(where[k])));
|
|
91
|
+
const { whereClause, values } = this._buildWhereClause(where);
|
|
92
|
+
const rows = await this.query(`SELECT * FROM "${table}" ${whereClause}`, values);
|
|
99
93
|
return rows.map((r) => {
|
|
100
94
|
const nr = {};
|
|
101
95
|
for (const k in r) {
|
|
@@ -103,20 +97,10 @@ class SQLiteDatabase extends IDatabase_1.IDatabase {
|
|
|
103
97
|
nr[k] = JSON.parse(r[k]);
|
|
104
98
|
}
|
|
105
99
|
catch {
|
|
106
|
-
nr[
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
const { _id, ...rest } = r; // Handle _id vs id
|
|
110
|
-
const finalObj = { _id };
|
|
111
|
-
for (const k in rest) {
|
|
112
|
-
try {
|
|
113
|
-
finalObj[k] = JSON.parse(rest[k]);
|
|
114
|
-
}
|
|
115
|
-
catch {
|
|
116
|
-
finalObj[k] = rest[k];
|
|
100
|
+
nr[k] = r[k];
|
|
117
101
|
}
|
|
118
102
|
}
|
|
119
|
-
return
|
|
103
|
+
return nr;
|
|
120
104
|
});
|
|
121
105
|
});
|
|
122
106
|
}
|
|
@@ -138,10 +122,10 @@ class SQLiteDatabase extends IDatabase_1.IDatabase {
|
|
|
138
122
|
async increment(table, incs, where) {
|
|
139
123
|
return this._execute('increment', table, async () => {
|
|
140
124
|
await this.ensureTable(table, where);
|
|
141
|
-
const set = Object.keys(incs).map(f => `"${f}" = CAST("${f}" AS
|
|
142
|
-
const
|
|
143
|
-
const sql = `UPDATE "${table}" SET ${set}
|
|
144
|
-
const res = await this.query(sql, [...Object.values(incs), ...
|
|
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]);
|
|
145
129
|
return res.changes;
|
|
146
130
|
});
|
|
147
131
|
}
|
|
@@ -152,6 +136,23 @@ class SQLiteDatabase extends IDatabase_1.IDatabase {
|
|
|
152
136
|
return this.increment(table, incs, where);
|
|
153
137
|
}
|
|
154
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;
|
|
143
|
+
}
|
|
144
|
+
_buildWhereClause(where) {
|
|
145
|
+
if (!where)
|
|
146
|
+
return { whereClause: '', values: [] };
|
|
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
|
+
};
|
|
155
|
+
}
|
|
155
156
|
}
|
|
156
157
|
exports.SQLiteDatabase = SQLiteDatabase;
|
|
157
158
|
exports.default = SQLiteDatabase;
|
package/dist/database/toon.d.ts
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import { IDatabase } from './IDatabase';
|
|
2
|
-
|
|
3
|
-
filePath: string;
|
|
4
|
-
saveInterval?: number;
|
|
5
|
-
cache?: any;
|
|
6
|
-
}
|
|
2
|
+
import { ToonConfig } from './types';
|
|
7
3
|
export declare class ToonDatabase extends IDatabase {
|
|
8
4
|
private filePath;
|
|
9
5
|
private db;
|
package/dist/database/toon.js
CHANGED
|
@@ -17,9 +17,9 @@ class ToonDatabase extends IDatabase_1.IDatabase {
|
|
|
17
17
|
this.isWriting = false;
|
|
18
18
|
this.writeQueue = [];
|
|
19
19
|
this.saveDebounceTimeout = null;
|
|
20
|
-
if (!config || !config.
|
|
21
|
-
throw new Error('ToonDB: "
|
|
22
|
-
this.filePath = config.
|
|
20
|
+
if (!config || !config.path)
|
|
21
|
+
throw new Error('ToonDB: "path" gereklidir.');
|
|
22
|
+
this.filePath = config.path;
|
|
23
23
|
this.saveInterval = config.saveInterval || 500;
|
|
24
24
|
process.on('exit', () => this.flushSync());
|
|
25
25
|
this.initPromise = this._load();
|
|
@@ -86,8 +86,7 @@ class ToonDatabase extends IDatabase_1.IDatabase {
|
|
|
86
86
|
clearTimeout(this.saveDebounceTimeout);
|
|
87
87
|
this.saveDebounceTimeout = null;
|
|
88
88
|
try {
|
|
89
|
-
|
|
90
|
-
await promises_1.default.writeFile(this.filePath, toonContent);
|
|
89
|
+
await promises_1.default.writeFile(this.filePath, (0, toon_1.stringify)(this.db));
|
|
91
90
|
this.isDirty = false;
|
|
92
91
|
}
|
|
93
92
|
catch (error) {
|
package/dist/database/types.d.ts
CHANGED
|
@@ -1,53 +1,38 @@
|
|
|
1
|
-
export interface
|
|
2
|
-
host: string;
|
|
3
|
-
user: string;
|
|
4
|
-
password?: string;
|
|
5
|
-
database: string;
|
|
6
|
-
port?: number;
|
|
7
|
-
connectionLimit?: number;
|
|
8
|
-
cache?: CacheConfig;
|
|
9
|
-
}
|
|
10
|
-
export interface SQLiteConfig {
|
|
11
|
-
filename: string;
|
|
12
|
-
cache?: CacheConfig;
|
|
13
|
-
}
|
|
14
|
-
export interface MongoDBConfig {
|
|
15
|
-
uri: string;
|
|
16
|
-
dbName: string;
|
|
17
|
-
cache?: CacheConfig;
|
|
18
|
-
}
|
|
19
|
-
export interface PostgreSQLConfig {
|
|
20
|
-
host: string;
|
|
21
|
-
user: string;
|
|
22
|
-
password?: string;
|
|
23
|
-
database: string;
|
|
24
|
-
port?: number;
|
|
25
|
-
connectionLimit?: number;
|
|
1
|
+
export interface BaseConfig {
|
|
26
2
|
cache?: CacheConfig;
|
|
27
3
|
}
|
|
28
|
-
export interface
|
|
4
|
+
export interface NetworkConfig extends BaseConfig {
|
|
29
5
|
host?: string;
|
|
30
6
|
port?: number;
|
|
7
|
+
username?: string;
|
|
31
8
|
password?: string;
|
|
32
|
-
|
|
9
|
+
database?: string;
|
|
10
|
+
url?: string;
|
|
11
|
+
poolSize?: number;
|
|
12
|
+
}
|
|
13
|
+
export interface FileConfig extends BaseConfig {
|
|
14
|
+
path: string;
|
|
15
|
+
}
|
|
16
|
+
export interface MySQLConfig extends NetworkConfig {
|
|
17
|
+
}
|
|
18
|
+
export interface PostgreSQLConfig extends NetworkConfig {
|
|
19
|
+
}
|
|
20
|
+
export interface SQLiteConfig extends FileConfig {
|
|
21
|
+
}
|
|
22
|
+
export interface MongoDBConfig extends NetworkConfig {
|
|
23
|
+
}
|
|
24
|
+
export interface RedisConfig extends NetworkConfig {
|
|
33
25
|
keyPrefix?: string;
|
|
34
|
-
cache?: CacheConfig;
|
|
35
26
|
}
|
|
36
|
-
export interface JsonConfig {
|
|
37
|
-
filePath: string;
|
|
27
|
+
export interface JsonConfig extends FileConfig {
|
|
38
28
|
saveInterval?: number;
|
|
39
|
-
cache?: CacheConfig;
|
|
40
29
|
}
|
|
41
|
-
export interface ZPackConfig {
|
|
42
|
-
filePath: string;
|
|
30
|
+
export interface ZPackConfig extends FileConfig {
|
|
43
31
|
autoFlush?: boolean;
|
|
44
|
-
cache?: CacheConfig;
|
|
45
32
|
indexFields?: Record<string, string[]>;
|
|
46
33
|
}
|
|
47
|
-
export interface ToonConfig {
|
|
48
|
-
filePath: string;
|
|
34
|
+
export interface ToonConfig extends FileConfig {
|
|
49
35
|
saveInterval?: number;
|
|
50
|
-
cache?: CacheConfig;
|
|
51
36
|
}
|
|
52
37
|
export interface CacheConfig {
|
|
53
38
|
type: 'memory' | 'redis';
|
package/dist/database/zpack.d.ts
CHANGED
|
@@ -44,9 +44,7 @@ export declare class ZPackAdapter extends IDatabase {
|
|
|
44
44
|
private rowCache;
|
|
45
45
|
private secondary;
|
|
46
46
|
private indexedFields;
|
|
47
|
-
constructor(config: ZPackConfig
|
|
48
|
-
indexFields?: Record<string, string[]>;
|
|
49
|
-
});
|
|
47
|
+
constructor(config: ZPackConfig);
|
|
50
48
|
private _init;
|
|
51
49
|
ensureTable(table: string): Promise<void>;
|
|
52
50
|
private _updateSecondaryIndex;
|
|
@@ -59,8 +57,8 @@ export declare class ZPackAdapter extends IDatabase {
|
|
|
59
57
|
delete(table: string, where: Record<string, any>): Promise<number>;
|
|
60
58
|
set(table: string, data: Record<string, any>, where: Record<string, any>): Promise<any>;
|
|
61
59
|
bulkInsert(table: string, dataArray: Record<string, any>[]): Promise<number>;
|
|
62
|
-
increment(table: string,
|
|
63
|
-
decrement(table: string,
|
|
60
|
+
increment(table: string, incs: Record<string, number>, where?: Record<string, any>): Promise<number>;
|
|
61
|
+
decrement(table: string, decs: Record<string, number>, where?: Record<string, any>): Promise<number>;
|
|
64
62
|
vacuum(): Promise<void>;
|
|
65
63
|
close(): Promise<void>;
|
|
66
64
|
}
|
package/dist/database/zpack.js
CHANGED
|
@@ -133,7 +133,7 @@ class ZPackDatabase {
|
|
|
133
133
|
}
|
|
134
134
|
else {
|
|
135
135
|
this.index.set(meta.docId, cur);
|
|
136
|
-
this.deleted.
|
|
136
|
+
this.deleted.add(meta.docId); // Bugfix: added to deleted, should be removed
|
|
137
137
|
if (meta.docId >= this._nextId)
|
|
138
138
|
this._nextId = meta.docId + 1;
|
|
139
139
|
}
|
|
@@ -254,9 +254,7 @@ class ZPackDatabase {
|
|
|
254
254
|
const decompressed = zlib_1.default.inflateSync(buf.subarray(6));
|
|
255
255
|
return { docId, fieldCount: 1, document: JSON.parse(decompressed.toString()) };
|
|
256
256
|
}
|
|
257
|
-
catch (e) {
|
|
258
|
-
// Fallback if not compressed or corrupted
|
|
259
|
-
}
|
|
257
|
+
catch (e) { }
|
|
260
258
|
}
|
|
261
259
|
let p = 6;
|
|
262
260
|
const end = 2 + payloadSize;
|
|
@@ -353,10 +351,7 @@ class ZPackAdapter extends IDatabase_1.IDatabase {
|
|
|
353
351
|
this.rowCache = new Map();
|
|
354
352
|
this.secondary = new Map();
|
|
355
353
|
this.indexedFields = new Map();
|
|
356
|
-
this.db = new ZPackDatabase(config.
|
|
357
|
-
autoFlush: !!config.autoFlush,
|
|
358
|
-
compression: !!config.cache
|
|
359
|
-
});
|
|
354
|
+
this.db = new ZPackDatabase(config.path, { autoFlush: !!config.autoFlush, compression: !!config.cache });
|
|
360
355
|
if (config.indexFields) {
|
|
361
356
|
for (const [table, fields] of Object.entries(config.indexFields)) {
|
|
362
357
|
this.indexedFields.set(table, new Set(fields));
|
|
@@ -395,9 +390,8 @@ class ZPackAdapter extends IDatabase_1.IDatabase {
|
|
|
395
390
|
if (!tableIndex.has(field))
|
|
396
391
|
tableIndex.set(field, new Map());
|
|
397
392
|
const fieldMap = tableIndex.get(field);
|
|
398
|
-
if (oldData && oldData[field] !== undefined)
|
|
393
|
+
if (oldData && oldData[field] !== undefined)
|
|
399
394
|
fieldMap.get(String(oldData[field]))?.delete(logicalId);
|
|
400
|
-
}
|
|
401
395
|
if (data[field] !== undefined) {
|
|
402
396
|
const newVal = String(data[field]);
|
|
403
397
|
if (!fieldMap.has(newVal))
|
|
@@ -420,6 +414,7 @@ class ZPackAdapter extends IDatabase_1.IDatabase {
|
|
|
420
414
|
return Object.entries(where).every(([k, v]) => String(row[k]) === String(v));
|
|
421
415
|
}
|
|
422
416
|
async select(table, where = null) {
|
|
417
|
+
const start = Date.now();
|
|
423
418
|
await this.initPromise;
|
|
424
419
|
await this.ensureTable(table);
|
|
425
420
|
if (where && Object.keys(where).length === 1) {
|
|
@@ -437,6 +432,7 @@ class ZPackAdapter extends IDatabase_1.IDatabase {
|
|
|
437
432
|
results.push(doc);
|
|
438
433
|
}
|
|
439
434
|
}
|
|
435
|
+
this.recordMetric('select', table, Date.now() - start);
|
|
440
436
|
return results;
|
|
441
437
|
}
|
|
442
438
|
return [];
|
|
@@ -455,6 +451,7 @@ class ZPackAdapter extends IDatabase_1.IDatabase {
|
|
|
455
451
|
if (this._matches(row, where))
|
|
456
452
|
results.push({ ...row });
|
|
457
453
|
}
|
|
454
|
+
this.recordMetric('select', table, Date.now() - start);
|
|
458
455
|
return results;
|
|
459
456
|
}
|
|
460
457
|
async selectOne(table, where = null) {
|
|
@@ -462,23 +459,24 @@ class ZPackAdapter extends IDatabase_1.IDatabase {
|
|
|
462
459
|
return res[0] || null;
|
|
463
460
|
}
|
|
464
461
|
async insert(table, data) {
|
|
462
|
+
const start = Date.now();
|
|
465
463
|
await this.initPromise;
|
|
466
464
|
await this.ensureTable(table);
|
|
467
|
-
// Trigger beforeInsert BEFORE coercion
|
|
468
465
|
await this.runHooks('beforeInsert', table, data);
|
|
469
466
|
const nextId = (this.tableMaxId.get(table) || 0) + 1;
|
|
470
467
|
const record = this._coerce(table, data, nextId);
|
|
471
468
|
const physicalId = await this.db.insert(record);
|
|
472
469
|
this.tableMaxId.set(table, nextId);
|
|
473
470
|
this.keyIndex.get(table).set(nextId, physicalId);
|
|
474
|
-
// Recover original data structure for cache and afterInsert hook
|
|
475
471
|
const fullRow = { _id: nextId, ...data };
|
|
476
472
|
this.rowCache.get(table).set(nextId, fullRow);
|
|
477
473
|
this._updateSecondaryIndex(table, nextId, fullRow);
|
|
478
474
|
await this.runHooks('afterInsert', table, fullRow);
|
|
475
|
+
this.recordMetric('insert', table, Date.now() - start);
|
|
479
476
|
return nextId;
|
|
480
477
|
}
|
|
481
478
|
async update(table, data, where) {
|
|
479
|
+
const start = Date.now();
|
|
482
480
|
const rows = await this.select(table, where);
|
|
483
481
|
for (const row of rows) {
|
|
484
482
|
const logicalId = row._id;
|
|
@@ -491,9 +489,11 @@ class ZPackAdapter extends IDatabase_1.IDatabase {
|
|
|
491
489
|
this._updateSecondaryIndex(table, logicalId, merged, row);
|
|
492
490
|
await this.runHooks('afterUpdate', table, merged);
|
|
493
491
|
}
|
|
492
|
+
this.recordMetric('update', table, Date.now() - start);
|
|
494
493
|
return rows.length;
|
|
495
494
|
}
|
|
496
495
|
async delete(table, where) {
|
|
496
|
+
const start = Date.now();
|
|
497
497
|
const rows = await this.select(table, where);
|
|
498
498
|
for (const row of rows) {
|
|
499
499
|
const logicalId = row._id;
|
|
@@ -507,36 +507,33 @@ class ZPackAdapter extends IDatabase_1.IDatabase {
|
|
|
507
507
|
}
|
|
508
508
|
await this.runHooks('afterDelete', table, row);
|
|
509
509
|
}
|
|
510
|
+
this.recordMetric('delete', table, Date.now() - start);
|
|
510
511
|
return rows.length;
|
|
511
512
|
}
|
|
512
513
|
async set(table, data, where) {
|
|
513
|
-
const
|
|
514
|
-
return
|
|
514
|
+
const ex = await this.selectOne(table, where);
|
|
515
|
+
return ex ? this.update(table, data, where) : this.insert(table, { ...where, ...data });
|
|
515
516
|
}
|
|
516
517
|
async bulkInsert(table, dataArray) {
|
|
517
|
-
for (const
|
|
518
|
-
await this.insert(table,
|
|
518
|
+
for (const d of dataArray)
|
|
519
|
+
await this.insert(table, d);
|
|
519
520
|
return dataArray.length;
|
|
520
521
|
}
|
|
521
|
-
async increment(table,
|
|
522
|
+
async increment(table, incs, where = {}) {
|
|
522
523
|
const rows = await this.select(table, where);
|
|
523
524
|
for (const row of rows) {
|
|
524
525
|
const updated = { ...row };
|
|
525
|
-
for (const [f, v] of Object.entries(
|
|
526
|
+
for (const [f, v] of Object.entries(incs))
|
|
526
527
|
updated[f] = (Number(updated[f]) || 0) + v;
|
|
527
528
|
await this.update(table, updated, { _id: row._id });
|
|
528
529
|
}
|
|
529
530
|
return rows.length;
|
|
530
531
|
}
|
|
531
|
-
async decrement(table,
|
|
532
|
-
const
|
|
533
|
-
for (const
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
updated[f] = (Number(updated[f]) || 0) - v;
|
|
537
|
-
await this.update(table, updated, { _id: row._id });
|
|
538
|
-
}
|
|
539
|
-
return rows.length;
|
|
532
|
+
async decrement(table, decs, where = {}) {
|
|
533
|
+
const incs = {};
|
|
534
|
+
for (const k in decs)
|
|
535
|
+
incs[k] = -decs[k];
|
|
536
|
+
return this.increment(table, incs, where);
|
|
540
537
|
}
|
|
541
538
|
async vacuum() { await this.db.vacuum(); }
|
|
542
539
|
async close() { await this.db.close(); }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onurege3467/zerohelper",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.2.0",
|
|
4
4
|
"description": "ZeroHelper is a versatile high-performance utility library and database framework for Node.js, fully written in TypeScript.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -76,4 +76,4 @@
|
|
|
76
76
|
"ts-jest": "^29.2.5",
|
|
77
77
|
"typescript": "^5.7.2"
|
|
78
78
|
}
|
|
79
|
-
}
|
|
79
|
+
}
|