@onurege3467/zerohelper 8.0.0 → 9.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +292 -612
- package/dist/database/IDatabase.d.ts +77 -0
- package/dist/database/IDatabase.js +10 -0
- package/dist/database/cacheWrapper.d.ts +31 -0
- package/dist/database/cacheWrapper.js +228 -0
- package/dist/database/index.d.ts +11 -0
- package/dist/database/index.js +94 -0
- package/dist/database/json.d.ts +32 -0
- package/dist/database/json.js +210 -0
- package/dist/database/migration.d.ts +21 -0
- package/dist/database/migration.js +97 -0
- package/dist/database/mongodb.d.ts +24 -0
- package/dist/database/mongodb.js +153 -0
- package/dist/database/mysql.d.ts +31 -0
- package/dist/database/mysql.js +385 -0
- package/dist/database/pg.d.ts +30 -0
- package/dist/database/pg.js +300 -0
- package/dist/database/redis.d.ts +23 -0
- package/dist/database/redis.js +157 -0
- package/dist/database/sqlite.d.ts +25 -0
- package/dist/database/sqlite.js +273 -0
- package/dist/database/types.d.ts +76 -0
- package/dist/database/types.js +2 -0
- package/dist/database/zpack.d.ts +59 -0
- package/dist/database/zpack.js +462 -0
- package/dist/functions/index.d.ts +183 -0
- package/dist/functions/index.js +636 -0
- package/dist/functions/temp_isphone.d.ts +1 -0
- package/dist/functions/temp_isphone.js +7 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +45 -0
- package/dist/test.d.ts +1 -0
- package/dist/test.js +55 -0
- package/dist/test_zpack.d.ts +1 -0
- package/dist/test_zpack.js +64 -0
- package/package.json +23 -6
- package/database/IDatabase.js +0 -92
- package/database/cacheWrapper.js +0 -585
- package/database/index.js +0 -72
- package/database/json.js +0 -281
- package/database/migration.js +0 -227
- package/database/mongodb.js +0 -203
- package/database/mysql.js +0 -526
- package/database/pg.js +0 -527
- package/database/redis.js +0 -342
- package/database/sqlite.js +0 -551
- package/functions/index.js +0 -705
- package/index.js +0 -7
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PostgreSQLDatabase = void 0;
|
|
4
|
+
const IDatabase_1 = require("./IDatabase");
|
|
5
|
+
const pg_1 = require("pg");
|
|
6
|
+
class PostgreSQLDatabase extends IDatabase_1.IDatabase {
|
|
7
|
+
constructor(config) {
|
|
8
|
+
super();
|
|
9
|
+
this.pool = null;
|
|
10
|
+
this._queue = [];
|
|
11
|
+
this._connected = false;
|
|
12
|
+
this.config = config;
|
|
13
|
+
this._connectionPromise = new Promise(async (resolve, reject) => {
|
|
14
|
+
try {
|
|
15
|
+
const tempPool = new pg_1.Pool({
|
|
16
|
+
host: config.host,
|
|
17
|
+
port: config.port || 5432,
|
|
18
|
+
user: config.user,
|
|
19
|
+
password: config.password,
|
|
20
|
+
database: 'postgres'
|
|
21
|
+
});
|
|
22
|
+
try {
|
|
23
|
+
await tempPool.query(`CREATE DATABASE "${config.database}"`);
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
if (!error.message.includes('already exists')) {
|
|
27
|
+
console.warn('Database creation warning:', error.message);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
await tempPool.end();
|
|
31
|
+
this.pool = new pg_1.Pool({
|
|
32
|
+
host: config.host,
|
|
33
|
+
port: config.port || 5432,
|
|
34
|
+
user: config.user,
|
|
35
|
+
password: config.password,
|
|
36
|
+
database: config.database,
|
|
37
|
+
max: config.connectionLimit || 10,
|
|
38
|
+
idleTimeoutMillis: 30000,
|
|
39
|
+
connectionTimeoutMillis: 2000,
|
|
40
|
+
});
|
|
41
|
+
this._connected = true;
|
|
42
|
+
resolve(this.pool);
|
|
43
|
+
this._processQueue();
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
console.error("PostgreSQL connection error:", error);
|
|
47
|
+
reject(error);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
_getColumnType(value) {
|
|
52
|
+
if (value === null || value === undefined)
|
|
53
|
+
return 'TEXT';
|
|
54
|
+
if (typeof value === 'boolean')
|
|
55
|
+
return 'BOOLEAN';
|
|
56
|
+
if (typeof value === 'number') {
|
|
57
|
+
if (Number.isInteger(value)) {
|
|
58
|
+
if (value >= -32768 && value <= 32767)
|
|
59
|
+
return 'SMALLINT';
|
|
60
|
+
if (value >= -2147483648 && value <= 2147483647)
|
|
61
|
+
return 'INTEGER';
|
|
62
|
+
return 'BIGINT';
|
|
63
|
+
}
|
|
64
|
+
return 'DOUBLE PRECISION';
|
|
65
|
+
}
|
|
66
|
+
if (typeof value === 'string') {
|
|
67
|
+
return value.length <= 255 ? 'VARCHAR(255)' : 'TEXT';
|
|
68
|
+
}
|
|
69
|
+
if (typeof value === 'object')
|
|
70
|
+
return 'JSONB';
|
|
71
|
+
if (value instanceof Date)
|
|
72
|
+
return 'TIMESTAMP';
|
|
73
|
+
return 'TEXT';
|
|
74
|
+
}
|
|
75
|
+
_getBestColumnType(values) {
|
|
76
|
+
const types = values.map(val => this._getColumnType(val));
|
|
77
|
+
const uniqueTypes = [...new Set(types)];
|
|
78
|
+
if (uniqueTypes.length === 1)
|
|
79
|
+
return uniqueTypes[0];
|
|
80
|
+
const typePriority = {
|
|
81
|
+
'TEXT': 10, 'JSONB': 9, 'VARCHAR(255)': 8, 'TIMESTAMP': 7,
|
|
82
|
+
'DOUBLE PRECISION': 6, 'BIGINT': 5, 'INTEGER': 4, 'SMALLINT': 3, 'BOOLEAN': 2
|
|
83
|
+
};
|
|
84
|
+
return uniqueTypes.sort((a, b) => (typePriority[b] || 0) - (typePriority[a] || 0))[0];
|
|
85
|
+
}
|
|
86
|
+
async _ensureMissingColumns(table, data) {
|
|
87
|
+
const existingColumns = await this.query(`
|
|
88
|
+
SELECT column_name
|
|
89
|
+
FROM information_schema.columns
|
|
90
|
+
WHERE table_name = $1 AND table_schema = 'public'
|
|
91
|
+
`, [table]);
|
|
92
|
+
if (!existingColumns || existingColumns.length === 0)
|
|
93
|
+
throw new Error(`Table ${table} does not exist.`);
|
|
94
|
+
const existingColumnNames = existingColumns.map(col => col.column_name);
|
|
95
|
+
for (const key of Object.keys(data)) {
|
|
96
|
+
if (!existingColumnNames.includes(key)) {
|
|
97
|
+
const columnType = this._getColumnType(data[key]);
|
|
98
|
+
await this.query(`ALTER TABLE "${table}" ADD COLUMN "${key}" ${columnType}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async _queueRequest(operation) {
|
|
103
|
+
if (this._connected) {
|
|
104
|
+
return operation();
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
return new Promise((resolve, reject) => {
|
|
108
|
+
this._queue.push({ operation, resolve, reject });
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
async _processQueue() {
|
|
113
|
+
if (!this._connected)
|
|
114
|
+
return;
|
|
115
|
+
while (this._queue.length > 0) {
|
|
116
|
+
const item = this._queue.shift();
|
|
117
|
+
if (item) {
|
|
118
|
+
try {
|
|
119
|
+
const result = await item.operation();
|
|
120
|
+
item.resolve(result);
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
item.reject(error);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
async query(sql, params = []) {
|
|
129
|
+
return this._queueRequest(async () => {
|
|
130
|
+
const pool = await this._connectionPromise;
|
|
131
|
+
const result = await pool.query(sql, params);
|
|
132
|
+
return result.rows;
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
async ensureTable(table, data = {}) {
|
|
136
|
+
return this._queueRequest(async () => {
|
|
137
|
+
const tables = await this.query(`
|
|
138
|
+
SELECT table_name
|
|
139
|
+
FROM information_schema.tables
|
|
140
|
+
WHERE table_schema = 'public' AND table_name = $1
|
|
141
|
+
`, [table]);
|
|
142
|
+
if (tables.length === 0) {
|
|
143
|
+
const columnDefinitions = Object.keys(data).map(col => {
|
|
144
|
+
const columnType = this._getColumnType(data[col]);
|
|
145
|
+
return `"${col}" ${columnType}`;
|
|
146
|
+
});
|
|
147
|
+
const columnsPart = columnDefinitions.length > 0 ? ', ' + columnDefinitions.join(", ") : '';
|
|
148
|
+
const createTableSQL = `CREATE TABLE "${table}" ("_id" SERIAL PRIMARY KEY ${columnsPart})`;
|
|
149
|
+
await this.query(createTableSQL);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
async insert(table, data) {
|
|
154
|
+
return this._queueRequest(async () => {
|
|
155
|
+
const copy = { ...data };
|
|
156
|
+
await this.ensureTable(table, copy);
|
|
157
|
+
await this._ensureMissingColumns(table, copy);
|
|
158
|
+
const existingColumns = await this.query(`
|
|
159
|
+
SELECT column_name, column_default
|
|
160
|
+
FROM information_schema.columns
|
|
161
|
+
WHERE table_name = $1 AND table_schema = 'public'
|
|
162
|
+
`, [table]);
|
|
163
|
+
const primaryKeyColumn = existingColumns.find(col => col.column_default && col.column_default.includes('nextval'));
|
|
164
|
+
if (primaryKeyColumn && copy[primaryKeyColumn.column_name] !== undefined) {
|
|
165
|
+
delete copy[primaryKeyColumn.column_name];
|
|
166
|
+
}
|
|
167
|
+
const keys = Object.keys(copy);
|
|
168
|
+
const placeholders = keys.map((_, index) => `$${index + 1}`).join(",");
|
|
169
|
+
const values = Object.values(copy).map(value => this._serializeValue(value));
|
|
170
|
+
const sql = `INSERT INTO "${table}" (${keys.map(k => `"${k}"`).join(",")}) VALUES (${placeholders}) RETURNING "_id"`;
|
|
171
|
+
const result = await this.query(sql, values);
|
|
172
|
+
return result[0]._id;
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
async update(table, data, where) {
|
|
176
|
+
return this._queueRequest(async () => {
|
|
177
|
+
await this.ensureTable(table, { ...data, ...where });
|
|
178
|
+
await this._ensureMissingColumns(table, { ...data, ...where });
|
|
179
|
+
const setString = Object.keys(data).map((k, i) => `"${k}" = $${i + 1}`).join(", ");
|
|
180
|
+
const whereString = Object.keys(where).map((k, i) => `"${k}" = $${Object.keys(data).length + i + 1}`).join(" AND ");
|
|
181
|
+
const sql = `UPDATE "${table}" SET ${setString} WHERE ${whereString}`;
|
|
182
|
+
const pool = await this._connectionPromise;
|
|
183
|
+
const result = await pool.query(sql, [...Object.values(data).map(v => this._serializeValue(v)), ...Object.values(where).map(v => this._serializeValue(v))]);
|
|
184
|
+
return result.rowCount ?? 0;
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
async delete(table, where) {
|
|
188
|
+
return this._queueRequest(async () => {
|
|
189
|
+
if (!where || Object.keys(where).length === 0)
|
|
190
|
+
return 0;
|
|
191
|
+
await this.ensureTable(table, { ...where });
|
|
192
|
+
await this._ensureMissingColumns(table, where);
|
|
193
|
+
const whereString = Object.keys(where).map((k, i) => `"${k}" = $${i + 1}`).join(" AND ");
|
|
194
|
+
const sql = `DELETE FROM "${table}" WHERE ${whereString}`;
|
|
195
|
+
const pool = await this._connectionPromise;
|
|
196
|
+
const result = await pool.query(sql, Object.values(where).map(v => this._serializeValue(v)));
|
|
197
|
+
return result.rowCount ?? 0;
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
async select(table, where = null) {
|
|
201
|
+
return this._queueRequest(async () => {
|
|
202
|
+
await this.ensureTable(table, where || {});
|
|
203
|
+
if (where && Object.keys(where).length > 0) {
|
|
204
|
+
await this._ensureMissingColumns(table, where);
|
|
205
|
+
}
|
|
206
|
+
let sql = `SELECT * FROM "${table}"`;
|
|
207
|
+
let params = [];
|
|
208
|
+
if (where && Object.keys(where).length > 0) {
|
|
209
|
+
const whereString = Object.keys(where).map((k, i) => `"${k}" = $${i + 1}`).join(" AND ");
|
|
210
|
+
sql += ` WHERE ${whereString}`;
|
|
211
|
+
params = Object.values(where).map(v => this._serializeValue(v));
|
|
212
|
+
}
|
|
213
|
+
const rows = await this.query(sql, params);
|
|
214
|
+
return rows;
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
async set(table, data, where) {
|
|
218
|
+
return this._queueRequest(async () => {
|
|
219
|
+
const existing = await this.select(table, where);
|
|
220
|
+
if (existing.length === 0) {
|
|
221
|
+
return await this.insert(table, { ...where, ...data });
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
return await this.update(table, data, where);
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
async selectOne(table, where = null) {
|
|
229
|
+
const results = await this.select(table, where);
|
|
230
|
+
return results[0] || null;
|
|
231
|
+
}
|
|
232
|
+
async bulkInsert(table, dataArray) {
|
|
233
|
+
return this._queueRequest(async () => {
|
|
234
|
+
if (!Array.isArray(dataArray) || dataArray.length === 0)
|
|
235
|
+
return 0;
|
|
236
|
+
await this.ensureTable(table, dataArray[0]);
|
|
237
|
+
const allKeys = new Set();
|
|
238
|
+
dataArray.forEach(obj => Object.keys(obj).forEach(key => allKeys.add(key)));
|
|
239
|
+
const existingColumns = await this.query(`
|
|
240
|
+
SELECT column_name
|
|
241
|
+
FROM information_schema.columns
|
|
242
|
+
WHERE table_name = $1 AND table_schema = 'public'
|
|
243
|
+
`, [table]);
|
|
244
|
+
const existingColumnNames = existingColumns.map(col => col.column_name);
|
|
245
|
+
for (const key of allKeys) {
|
|
246
|
+
if (!existingColumnNames.includes(key)) {
|
|
247
|
+
const columnValues = dataArray.map(obj => obj[key]).filter(val => val !== undefined && val !== null);
|
|
248
|
+
const columnType = columnValues.length > 0 ? this._getBestColumnType(columnValues) : 'TEXT';
|
|
249
|
+
await this.query(`ALTER TABLE "${table}" ADD COLUMN "${key}" ${columnType}`);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
const keys = Array.from(allKeys);
|
|
253
|
+
const placeholders = dataArray.map((_, rowIndex) => `(${keys.map((_, colIndex) => `$${rowIndex * keys.length + colIndex + 1}`).join(',')})`).join(',');
|
|
254
|
+
const values = dataArray.flatMap(obj => keys.map(k => this._serializeValue(obj[k])));
|
|
255
|
+
const sql = `INSERT INTO "${table}" (${keys.map(k => `"${k}"`).join(",")}) VALUES ${placeholders}`;
|
|
256
|
+
const pool = await this._connectionPromise;
|
|
257
|
+
const result = await pool.query(sql, values);
|
|
258
|
+
return result.rowCount ?? 0;
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
async close() {
|
|
262
|
+
if (this.pool)
|
|
263
|
+
await this.pool.end();
|
|
264
|
+
}
|
|
265
|
+
_serializeValue(value) {
|
|
266
|
+
if (value instanceof Date)
|
|
267
|
+
return value.toISOString();
|
|
268
|
+
if (Array.isArray(value) || (typeof value === 'object' && value !== null))
|
|
269
|
+
return JSON.stringify(value);
|
|
270
|
+
return value;
|
|
271
|
+
}
|
|
272
|
+
async increment(table, increments, where = {}) {
|
|
273
|
+
const incrementClauses = Object.keys(increments).map((field, index) => `"${field}" = "${field}" + $${index + 1}`).join(', ');
|
|
274
|
+
const incrementValues = Object.values(increments);
|
|
275
|
+
const { whereClause, values: whereValues } = this._buildWhereClause(where, incrementValues.length);
|
|
276
|
+
const sql = `UPDATE "${table}" SET ${incrementClauses}${whereClause}`;
|
|
277
|
+
const pool = await this._connectionPromise;
|
|
278
|
+
const result = await pool.query(sql, [...incrementValues, ...whereValues]);
|
|
279
|
+
return result.rowCount ?? 0;
|
|
280
|
+
}
|
|
281
|
+
async decrement(table, decrements, where = {}) {
|
|
282
|
+
const decrementClauses = Object.keys(decrements).map((field, index) => `"${field}" = "${field}" - $${index + 1}`).join(', ');
|
|
283
|
+
const decrementValues = Object.values(decrements);
|
|
284
|
+
const { whereClause, values: whereValues } = this._buildWhereClause(where, decrementValues.length);
|
|
285
|
+
const sql = `UPDATE "${table}" SET ${decrementClauses}${whereClause}`;
|
|
286
|
+
const pool = await this._connectionPromise;
|
|
287
|
+
const result = await pool.query(sql, [...decrementValues, ...whereValues]);
|
|
288
|
+
return result.rowCount ?? 0;
|
|
289
|
+
}
|
|
290
|
+
_buildWhereClause(where = {}, startIndex = 0) {
|
|
291
|
+
const conditions = Object.keys(where);
|
|
292
|
+
if (conditions.length === 0)
|
|
293
|
+
return { whereClause: '', values: [] };
|
|
294
|
+
const whereClause = ' WHERE ' + conditions.map((key, index) => `"${key}" = $${startIndex + index + 1}`).join(' AND ');
|
|
295
|
+
const values = Object.values(where).map(v => this._serializeValue(v));
|
|
296
|
+
return { whereClause, values };
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
exports.PostgreSQLDatabase = PostgreSQLDatabase;
|
|
300
|
+
exports.default = PostgreSQLDatabase;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { IDatabase } from './IDatabase';
|
|
2
|
+
import { RedisClientType } from 'redis';
|
|
3
|
+
export declare class RedisDatabase extends IDatabase {
|
|
4
|
+
private config;
|
|
5
|
+
private client;
|
|
6
|
+
private isConnecting;
|
|
7
|
+
private keyPrefix;
|
|
8
|
+
constructor(config?: any);
|
|
9
|
+
connect(): Promise<RedisClientType>;
|
|
10
|
+
private _getKey;
|
|
11
|
+
private _getTableKey;
|
|
12
|
+
select<T = any>(table: string, where?: Record<string, any>): Promise<T[]>;
|
|
13
|
+
selectOne<T = any>(table: string, where?: Record<string, any>): Promise<T | null>;
|
|
14
|
+
insert(table: string, data: Record<string, any>): Promise<any>;
|
|
15
|
+
update(table: string, data: Record<string, any>, where: Record<string, any>): Promise<number>;
|
|
16
|
+
delete(table: string, where: Record<string, any>): Promise<number>;
|
|
17
|
+
set(table: string, data: Record<string, any>, where: Record<string, any>): Promise<any>;
|
|
18
|
+
bulkInsert(table: string, dataArray: Record<string, any>[]): Promise<number>;
|
|
19
|
+
increment(table: string, increments: Record<string, number>, where?: Record<string, any>): Promise<number>;
|
|
20
|
+
decrement(table: string, decrements: Record<string, number>, where?: Record<string, any>): Promise<number>;
|
|
21
|
+
close(): Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
export default RedisDatabase;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RedisDatabase = void 0;
|
|
4
|
+
const IDatabase_1 = require("./IDatabase");
|
|
5
|
+
const redis_1 = require("redis");
|
|
6
|
+
class RedisDatabase extends IDatabase_1.IDatabase {
|
|
7
|
+
constructor(config = {}) {
|
|
8
|
+
super();
|
|
9
|
+
this.client = null;
|
|
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
|
+
};
|
|
18
|
+
this.keyPrefix = config.keyPrefix || 'app:';
|
|
19
|
+
}
|
|
20
|
+
async connect() {
|
|
21
|
+
if (this.client && this.client.isReady)
|
|
22
|
+
return this.client;
|
|
23
|
+
if (this.isConnecting) {
|
|
24
|
+
while (this.isConnecting) {
|
|
25
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
26
|
+
}
|
|
27
|
+
return this.client;
|
|
28
|
+
}
|
|
29
|
+
this.isConnecting = true;
|
|
30
|
+
try {
|
|
31
|
+
this.client = (0, redis_1.createClient)({
|
|
32
|
+
socket: {
|
|
33
|
+
host: this.config.host,
|
|
34
|
+
port: this.config.port,
|
|
35
|
+
connectTimeout: this.config.connectTimeout,
|
|
36
|
+
},
|
|
37
|
+
password: this.config.password,
|
|
38
|
+
database: this.config.db,
|
|
39
|
+
});
|
|
40
|
+
this.client.on('error', (err) => console.error('Redis Error:', err.message));
|
|
41
|
+
await this.client.connect();
|
|
42
|
+
return this.client;
|
|
43
|
+
}
|
|
44
|
+
finally {
|
|
45
|
+
this.isConnecting = false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
_getKey(table, id) {
|
|
49
|
+
return `${this.keyPrefix}${table}:${id}`;
|
|
50
|
+
}
|
|
51
|
+
_getTableKey(table) {
|
|
52
|
+
return `${this.keyPrefix}${table}:*`;
|
|
53
|
+
}
|
|
54
|
+
async select(table, where = {}) {
|
|
55
|
+
const client = await this.connect();
|
|
56
|
+
const pattern = this._getTableKey(table);
|
|
57
|
+
const keys = await client.keys(pattern);
|
|
58
|
+
if (!keys.length)
|
|
59
|
+
return [];
|
|
60
|
+
const values = await client.mGet(keys);
|
|
61
|
+
return values
|
|
62
|
+
.map(v => {
|
|
63
|
+
try {
|
|
64
|
+
return v ? JSON.parse(v) : null;
|
|
65
|
+
}
|
|
66
|
+
catch (e) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
.filter(Boolean)
|
|
71
|
+
.filter(item => Object.entries(where).every(([k, val]) => item[k] === val));
|
|
72
|
+
}
|
|
73
|
+
async selectOne(table, where = {}) {
|
|
74
|
+
const results = await this.select(table, where);
|
|
75
|
+
return results.length ? results[0] : null;
|
|
76
|
+
}
|
|
77
|
+
async insert(table, data) {
|
|
78
|
+
const client = await this.connect();
|
|
79
|
+
const insertData = { ...data };
|
|
80
|
+
if (!insertData._id && !insertData.id) {
|
|
81
|
+
insertData._id = Date.now().toString() + Math.random().toString(36).slice(2, 9);
|
|
82
|
+
}
|
|
83
|
+
const id = insertData._id || insertData.id;
|
|
84
|
+
const key = this._getKey(table, id);
|
|
85
|
+
await client.set(key, JSON.stringify(insertData));
|
|
86
|
+
return insertData;
|
|
87
|
+
}
|
|
88
|
+
async update(table, data, where) {
|
|
89
|
+
const existing = await this.select(table, where);
|
|
90
|
+
if (!existing.length)
|
|
91
|
+
return 0;
|
|
92
|
+
const client = await this.connect();
|
|
93
|
+
for (const item of existing) {
|
|
94
|
+
const merged = { ...item, ...data };
|
|
95
|
+
const id = item._id || item.id;
|
|
96
|
+
await client.set(this._getKey(table, id), JSON.stringify(merged));
|
|
97
|
+
}
|
|
98
|
+
return existing.length;
|
|
99
|
+
}
|
|
100
|
+
async delete(table, where) {
|
|
101
|
+
const existing = await this.select(table, where);
|
|
102
|
+
if (!existing.length)
|
|
103
|
+
return 0;
|
|
104
|
+
const client = await this.connect();
|
|
105
|
+
const keys = existing.map(item => this._getKey(table, item._id || item.id));
|
|
106
|
+
await client.del(keys);
|
|
107
|
+
return existing.length;
|
|
108
|
+
}
|
|
109
|
+
async set(table, data, where) {
|
|
110
|
+
const existing = await this.selectOne(table, where);
|
|
111
|
+
if (existing) {
|
|
112
|
+
await this.update(table, data, where);
|
|
113
|
+
return existing;
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
return await this.insert(table, { ...data, ...where });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
async bulkInsert(table, dataArray) {
|
|
120
|
+
for (const data of dataArray) {
|
|
121
|
+
await this.insert(table, data);
|
|
122
|
+
}
|
|
123
|
+
return dataArray.length;
|
|
124
|
+
}
|
|
125
|
+
async increment(table, increments, where = {}) {
|
|
126
|
+
const records = await this.select(table, where);
|
|
127
|
+
const client = await this.connect();
|
|
128
|
+
for (const record of records) {
|
|
129
|
+
for (const [field, value] of Object.entries(increments)) {
|
|
130
|
+
record[field] = (Number(record[field]) || 0) + value;
|
|
131
|
+
}
|
|
132
|
+
const id = record._id || record.id;
|
|
133
|
+
await client.set(this._getKey(table, id), JSON.stringify(record));
|
|
134
|
+
}
|
|
135
|
+
return records.length;
|
|
136
|
+
}
|
|
137
|
+
async decrement(table, decrements, where = {}) {
|
|
138
|
+
const records = await this.select(table, where);
|
|
139
|
+
const client = await this.connect();
|
|
140
|
+
for (const record of records) {
|
|
141
|
+
for (const [field, value] of Object.entries(decrements)) {
|
|
142
|
+
record[field] = (Number(record[field]) || 0) - value;
|
|
143
|
+
}
|
|
144
|
+
const id = record._id || record.id;
|
|
145
|
+
await client.set(this._getKey(table, id), JSON.stringify(record));
|
|
146
|
+
}
|
|
147
|
+
return records.length;
|
|
148
|
+
}
|
|
149
|
+
async close() {
|
|
150
|
+
if (this.client) {
|
|
151
|
+
await this.client.quit();
|
|
152
|
+
this.client = null;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
exports.RedisDatabase = RedisDatabase;
|
|
157
|
+
exports.default = RedisDatabase;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { IDatabase } from './IDatabase';
|
|
2
|
+
import { SQLiteConfig } from './types';
|
|
3
|
+
export declare class SQLiteDatabase extends IDatabase {
|
|
4
|
+
private db;
|
|
5
|
+
constructor(config: SQLiteConfig);
|
|
6
|
+
private _detectColumnType;
|
|
7
|
+
private _determineBestColumnType;
|
|
8
|
+
private _ensureMissingColumns;
|
|
9
|
+
query(sql: string, params?: any[]): Promise<any>;
|
|
10
|
+
ensureTable(table: string, data?: Record<string, any>): Promise<void>;
|
|
11
|
+
private _serializeValue;
|
|
12
|
+
private _deserializeValue;
|
|
13
|
+
insert(table: string, data: Record<string, any>): Promise<number>;
|
|
14
|
+
update(table: string, data: Record<string, any>, where: Record<string, any>): Promise<number>;
|
|
15
|
+
delete(table: string, where: Record<string, any>): Promise<number>;
|
|
16
|
+
select<T = any>(table: string, where?: Record<string, any> | null): Promise<T[]>;
|
|
17
|
+
set(table: string, data: Record<string, any>, where: Record<string, any>): Promise<any>;
|
|
18
|
+
selectOne<T = any>(table: string, where?: Record<string, any> | null): Promise<T | null>;
|
|
19
|
+
bulkInsert(table: string, dataArray: Record<string, any>[]): Promise<number>;
|
|
20
|
+
increment(table: string, increments: Record<string, number>, where?: Record<string, any>): Promise<number>;
|
|
21
|
+
decrement(table: string, decrements: Record<string, number>, where?: Record<string, any>): Promise<number>;
|
|
22
|
+
private _buildWhereClause;
|
|
23
|
+
close(): Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
export default SQLiteDatabase;
|