@onurege3467/zerohelper 9.2.0 → 10.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 +3 -3
- package/dist/bin/zero.js +0 -0
- package/dist/database/IDatabase.d.ts +12 -12
- package/dist/database/IDatabase.js +2 -2
- package/dist/database/index.d.ts +1 -1
- package/dist/database/index.js +3 -1
- package/dist/database/mongodb.d.ts +7 -5
- package/dist/database/mongodb.js +87 -62
- package/dist/database/mysql.js +24 -6
- package/dist/database/pg.js +18 -9
- package/dist/database/redis.d.ts +9 -3
- package/dist/database/redis.js +89 -44
- package/dist/database/sqlite.d.ts +4 -0
- package/dist/database/sqlite.js +63 -10
- package/dist/database/toon.d.ts +1 -0
- package/dist/database/toon.js +43 -12
- package/dist/database/types.d.ts +1 -0
- package/dist/database/zpack.d.ts +10 -0
- package/dist/database/zpack.js +187 -113
- package/dist/functions/toon.d.ts +3 -0
- package/dist/functions/toon.js +74 -48
- package/dist/tests/test.js +22 -0
- package/package.json +1 -1
- package/dist/functions/temp_isphone.d.ts +0 -1
- package/dist/functions/temp_isphone.js +0 -7
- package/dist/test.js +0 -55
- package/dist/test_v91_advanced.d.ts +0 -1
- package/dist/test_v91_advanced.js +0 -48
- package/dist/test_v91_basics.d.ts +0 -1
- package/dist/test_v91_basics.js +0 -54
- package/dist/test_v91_performance.d.ts +0 -1
- package/dist/test_v91_performance.js +0 -54
- package/dist/test_zpack.d.ts +0 -1
- package/dist/test_zpack.js +0 -64
- /package/dist/{test.d.ts → tests/test.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -75,7 +75,7 @@ import { database } from '@onurege3467/zerohelper';
|
|
|
75
75
|
const db = database.createDatabase({
|
|
76
76
|
adapter: 'zpack',
|
|
77
77
|
config: {
|
|
78
|
-
|
|
78
|
+
path: './data.zpack',
|
|
79
79
|
indexFields: { 'users': ['email'] }, // Intelligent autocomplete for ZPack
|
|
80
80
|
autoFlush: true
|
|
81
81
|
}
|
|
@@ -136,7 +136,7 @@ await db.decrement('inventory', { stock: 1 }, { sku: 'PRO-123' });
|
|
|
136
136
|
```typescript
|
|
137
137
|
const zpack = database.createDatabase({
|
|
138
138
|
adapter: 'zpack',
|
|
139
|
-
config: {
|
|
139
|
+
config: { path: './storage/engine.zpack', autoFlush: true }
|
|
140
140
|
});
|
|
141
141
|
```
|
|
142
142
|
|
|
@@ -151,7 +151,7 @@ The **world's first native TOON database**. It stores data in a YAML-like compac
|
|
|
151
151
|
const toonDb = database.createDatabase({
|
|
152
152
|
adapter: 'toon',
|
|
153
153
|
config: {
|
|
154
|
-
|
|
154
|
+
path: './data.toon',
|
|
155
155
|
saveInterval: 1000 // Debounced disk write for high performance
|
|
156
156
|
}
|
|
157
157
|
});
|
package/dist/bin/zero.js
CHANGED
|
File without changes
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
export type HookType = 'beforeInsert' | 'afterInsert' | 'beforeUpdate' | 'afterUpdate' | 'beforeDelete' | 'afterDelete';
|
|
2
2
|
export type HookFunction = (table: string, data: any) => Promise<void> | void;
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Defines the common interface that all database adapters must implement.
|
|
5
5
|
*/
|
|
6
6
|
export declare abstract class IDatabase {
|
|
7
7
|
protected hooks: Record<HookType, HookFunction[]>;
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
9
|
+
* Registers a lifecycle hook.
|
|
10
10
|
*/
|
|
11
11
|
on(hook: HookType, fn: HookFunction): void;
|
|
12
12
|
protected runHooks(hook: HookType, table: string, data: any): Promise<void>;
|
|
@@ -28,43 +28,43 @@ export declare abstract class IDatabase {
|
|
|
28
28
|
};
|
|
29
29
|
protected recordMetric(operation: string, table: string, duration: number): void;
|
|
30
30
|
/**
|
|
31
|
-
*
|
|
31
|
+
* Selects multiple records based on the specified conditions.
|
|
32
32
|
*/
|
|
33
33
|
abstract select<T = any>(table: string, where?: Record<string, any> | null): Promise<T[]>;
|
|
34
34
|
/**
|
|
35
|
-
*
|
|
35
|
+
* Selects a single record based on the specified conditions.
|
|
36
36
|
*/
|
|
37
37
|
abstract selectOne<T = any>(table: string, where?: Record<string, any> | null): Promise<T | null>;
|
|
38
38
|
/**
|
|
39
|
-
*
|
|
39
|
+
* Inserts a new record.
|
|
40
40
|
*/
|
|
41
41
|
abstract insert(table: string, data: Record<string, any>): Promise<number | string | any>;
|
|
42
42
|
/**
|
|
43
|
-
*
|
|
43
|
+
* Updates records matching the specified conditions.
|
|
44
44
|
*/
|
|
45
45
|
abstract update(table: string, data: Record<string, any>, where: Record<string, any>): Promise<number>;
|
|
46
46
|
/**
|
|
47
|
-
*
|
|
47
|
+
* Updates a record or inserts it as a new record if it doesn't exist (Upsert).
|
|
48
48
|
*/
|
|
49
49
|
abstract set(table: string, data: Record<string, any>, where: Record<string, any>): Promise<any>;
|
|
50
50
|
/**
|
|
51
|
-
*
|
|
51
|
+
* Deletes records matching the specified conditions.
|
|
52
52
|
*/
|
|
53
53
|
abstract delete(table: string, where: Record<string, any>): Promise<number>;
|
|
54
54
|
/**
|
|
55
|
-
*
|
|
55
|
+
* Inserts multiple records in bulk.
|
|
56
56
|
*/
|
|
57
57
|
abstract bulkInsert(table: string, dataArray: Record<string, any>[]): Promise<number>;
|
|
58
58
|
/**
|
|
59
|
-
*
|
|
59
|
+
* Increments numeric fields.
|
|
60
60
|
*/
|
|
61
61
|
abstract increment(table: string, increments: Record<string, number>, where: Record<string, any>): Promise<number>;
|
|
62
62
|
/**
|
|
63
|
-
*
|
|
63
|
+
* Decrements numeric fields.
|
|
64
64
|
*/
|
|
65
65
|
abstract decrement(table: string, decrements: Record<string, number>, where: Record<string, any>): Promise<number>;
|
|
66
66
|
/**
|
|
67
|
-
*
|
|
67
|
+
* Safely closes the database connection.
|
|
68
68
|
*/
|
|
69
69
|
abstract close(): Promise<void>;
|
|
70
70
|
}
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.IDatabase = void 0;
|
|
4
4
|
const telemetry_1 = require("./telemetry");
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* Defines the common interface that all database adapters must implement.
|
|
7
7
|
*/
|
|
8
8
|
class IDatabase {
|
|
9
9
|
constructor() {
|
|
@@ -17,7 +17,7 @@ class IDatabase {
|
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
|
-
*
|
|
20
|
+
* Registers a lifecycle hook.
|
|
21
21
|
*/
|
|
22
22
|
on(hook, fn) {
|
|
23
23
|
if (this.hooks[hook]) {
|
package/dist/database/index.d.ts
CHANGED
|
@@ -8,5 +8,5 @@ import { DataSeeder } from './seeder';
|
|
|
8
8
|
* Belirtilen adaptör tipine göre bir veritabanı örneği oluşturur ve döndürür.
|
|
9
9
|
*/
|
|
10
10
|
export declare function createDatabase(options: DatabaseOptions): IDatabase;
|
|
11
|
-
export { MigrationManager, ZPackDatabase, ZPackAdapter, DataSeeder, ToonDatabase };
|
|
11
|
+
export { IDatabase, MigrationManager, ZPackDatabase, ZPackAdapter, DataSeeder, ToonDatabase };
|
|
12
12
|
export default createDatabase;
|
package/dist/database/index.js
CHANGED
|
@@ -36,8 +36,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
36
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.ToonDatabase = exports.DataSeeder = exports.ZPackAdapter = exports.ZPackDatabase = exports.MigrationManager = void 0;
|
|
39
|
+
exports.ToonDatabase = exports.DataSeeder = exports.ZPackAdapter = exports.ZPackDatabase = exports.MigrationManager = exports.IDatabase = void 0;
|
|
40
40
|
exports.createDatabase = createDatabase;
|
|
41
|
+
const IDatabase_1 = require("./IDatabase");
|
|
42
|
+
Object.defineProperty(exports, "IDatabase", { enumerable: true, get: function () { return IDatabase_1.IDatabase; } });
|
|
41
43
|
const mysql_1 = __importDefault(require("./mysql"));
|
|
42
44
|
const sqlite_1 = __importDefault(require("./sqlite"));
|
|
43
45
|
const mongodb_1 = __importDefault(require("./mongodb"));
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { IDatabase } from './IDatabase';
|
|
2
2
|
import { MongoDBConfig } from './types';
|
|
3
3
|
export declare class MongoDBDatabase extends IDatabase {
|
|
4
|
-
private config;
|
|
5
4
|
private client;
|
|
6
5
|
private db;
|
|
6
|
+
private _isConnected;
|
|
7
7
|
private _queue;
|
|
8
|
-
private _connected;
|
|
9
|
-
private _connectionPromise;
|
|
10
8
|
constructor(config: MongoDBConfig);
|
|
9
|
+
private _connect;
|
|
10
|
+
private _flushQueue;
|
|
11
|
+
private _flushQueueWithError;
|
|
11
12
|
private _execute;
|
|
12
|
-
|
|
13
|
-
insert(collection: string, data: any): Promise<any>;
|
|
13
|
+
insert(collection: string, data: any): Promise<string>;
|
|
14
14
|
update(collection: string, data: any, where: any): Promise<number>;
|
|
15
15
|
delete(collection: string, where: any): Promise<number>;
|
|
16
16
|
select<T = any>(collection: string, where?: any): Promise<T[]>;
|
|
@@ -20,5 +20,7 @@ export declare class MongoDBDatabase extends IDatabase {
|
|
|
20
20
|
increment(collection: string, incs: Record<string, number>, where?: any): Promise<number>;
|
|
21
21
|
decrement(collection: string, decs: Record<string, number>, where?: any): Promise<number>;
|
|
22
22
|
close(): Promise<void>;
|
|
23
|
+
private _formatQuery;
|
|
24
|
+
private _serialize;
|
|
23
25
|
}
|
|
24
26
|
export default MongoDBDatabase;
|
package/dist/database/mongodb.js
CHANGED
|
@@ -7,85 +7,90 @@ class MongoDBDatabase extends IDatabase_1.IDatabase {
|
|
|
7
7
|
constructor(config) {
|
|
8
8
|
super();
|
|
9
9
|
this.db = null;
|
|
10
|
+
this._isConnected = false;
|
|
10
11
|
this._queue = [];
|
|
11
|
-
|
|
12
|
-
this.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
try {
|
|
16
|
-
await this.client.connect();
|
|
17
|
-
this.db = this.client.db(config.database || 'test');
|
|
18
|
-
this._connected = true;
|
|
19
|
-
resolve(this.db);
|
|
20
|
-
this._processQueue();
|
|
21
|
-
}
|
|
22
|
-
catch (error) {
|
|
23
|
-
reject(error);
|
|
24
|
-
}
|
|
12
|
+
const uri = config.url || (config.uri ?? `mongodb://${config.host || 'localhost'}:${config.port || 27017}`);
|
|
13
|
+
this.client = new mongodb_1.MongoClient(uri, {
|
|
14
|
+
serverSelectionTimeoutMS: 5000, // Fail fast if no server
|
|
15
|
+
connectTimeoutMS: 5000
|
|
25
16
|
});
|
|
17
|
+
this._connect(config.database || 'test');
|
|
18
|
+
}
|
|
19
|
+
async _connect(dbName) {
|
|
20
|
+
try {
|
|
21
|
+
await this.client.connect();
|
|
22
|
+
this.db = this.client.db(dbName);
|
|
23
|
+
this._isConnected = true;
|
|
24
|
+
this._flushQueue();
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
this._flushQueueWithError(error);
|
|
28
|
+
// Opsiyonel: Yeniden bağlanma mantığı buraya eklenebilir,
|
|
29
|
+
// ama testler için fail-fast daha iyidir.
|
|
30
|
+
}
|
|
26
31
|
}
|
|
27
|
-
|
|
28
|
-
const start = Date.now();
|
|
29
|
-
const execute = async () => {
|
|
30
|
-
const res = await fn();
|
|
31
|
-
this.recordMetric(op, table, Date.now() - start);
|
|
32
|
-
return res;
|
|
33
|
-
};
|
|
34
|
-
if (this._connected)
|
|
35
|
-
return execute();
|
|
36
|
-
return new Promise((resolve, reject) => this._queue.push({ operation: execute, resolve, reject }));
|
|
37
|
-
}
|
|
38
|
-
async _processQueue() {
|
|
39
|
-
if (!this._connected)
|
|
40
|
-
return;
|
|
32
|
+
_flushQueue() {
|
|
41
33
|
while (this._queue.length > 0) {
|
|
42
34
|
const item = this._queue.shift();
|
|
43
35
|
if (item) {
|
|
44
|
-
|
|
45
|
-
item.resolve(await item.operation());
|
|
46
|
-
}
|
|
47
|
-
catch (error) {
|
|
48
|
-
item.reject(error);
|
|
49
|
-
}
|
|
36
|
+
item.operation().then(item.resolve).catch(item.reject);
|
|
50
37
|
}
|
|
51
38
|
}
|
|
52
39
|
}
|
|
40
|
+
_flushQueueWithError(error) {
|
|
41
|
+
while (this._queue.length > 0) {
|
|
42
|
+
const item = this._queue.shift();
|
|
43
|
+
if (item)
|
|
44
|
+
item.reject(error);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async _execute(fn) {
|
|
48
|
+
if (this._isConnected) {
|
|
49
|
+
return fn();
|
|
50
|
+
}
|
|
51
|
+
return new Promise((resolve, reject) => {
|
|
52
|
+
this._queue.push({ operation: fn, resolve, reject });
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
// --- Implementations ---
|
|
53
56
|
async insert(collection, data) {
|
|
54
57
|
await this.runHooks('beforeInsert', collection, data);
|
|
55
|
-
return this._execute(
|
|
56
|
-
const
|
|
57
|
-
const
|
|
58
|
-
const finalData = { _id:
|
|
58
|
+
return this._execute(async () => {
|
|
59
|
+
const res = await this.db.collection(collection).insertOne(data);
|
|
60
|
+
const newId = res.insertedId.toString();
|
|
61
|
+
const finalData = { _id: newId, ...data };
|
|
59
62
|
await this.runHooks('afterInsert', collection, finalData);
|
|
60
|
-
return
|
|
63
|
+
return newId;
|
|
61
64
|
});
|
|
62
65
|
}
|
|
63
66
|
async update(collection, data, where) {
|
|
64
67
|
await this.runHooks('beforeUpdate', collection, { data, where });
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const res = await db.collection(collection).updateMany(
|
|
68
|
-
return
|
|
68
|
+
const formattedWhere = this._formatQuery(where);
|
|
69
|
+
return this._execute(async () => {
|
|
70
|
+
const res = await this.db.collection(collection).updateMany(formattedWhere, { $set: data });
|
|
71
|
+
return res.modifiedCount;
|
|
69
72
|
});
|
|
70
73
|
}
|
|
71
74
|
async delete(collection, where) {
|
|
72
75
|
await this.runHooks('beforeDelete', collection, where);
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const res = await db.collection(collection).deleteMany(
|
|
76
|
+
const formattedWhere = this._formatQuery(where);
|
|
77
|
+
return this._execute(async () => {
|
|
78
|
+
const res = await this.db.collection(collection).deleteMany(formattedWhere);
|
|
76
79
|
return res.deletedCount;
|
|
77
80
|
});
|
|
78
81
|
}
|
|
79
82
|
async select(collection, where = {}) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
+
const formattedWhere = this._formatQuery(where);
|
|
84
|
+
return this._execute(async () => {
|
|
85
|
+
const docs = await this.db.collection(collection).find(formattedWhere).toArray();
|
|
86
|
+
return docs.map(doc => this._serialize(doc));
|
|
83
87
|
});
|
|
84
88
|
}
|
|
85
89
|
async selectOne(collection, where = {}) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
90
|
+
const formattedWhere = this._formatQuery(where);
|
|
91
|
+
return this._execute(async () => {
|
|
92
|
+
const doc = await this.db.collection(collection).findOne(formattedWhere);
|
|
93
|
+
return doc ? this._serialize(doc) : null;
|
|
89
94
|
});
|
|
90
95
|
}
|
|
91
96
|
async set(collection, data, where) {
|
|
@@ -93,19 +98,18 @@ class MongoDBDatabase extends IDatabase_1.IDatabase {
|
|
|
93
98
|
return ex ? this.update(collection, data, where) : this.insert(collection, { ...where, ...data });
|
|
94
99
|
}
|
|
95
100
|
async bulkInsert(collection, dataArray) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
const
|
|
100
|
-
const res = await db.collection(collection).insertMany(dataArray);
|
|
101
|
+
if (!dataArray.length)
|
|
102
|
+
return 0;
|
|
103
|
+
return this._execute(async () => {
|
|
104
|
+
const res = await this.db.collection(collection).insertMany(dataArray);
|
|
101
105
|
return res.insertedCount;
|
|
102
106
|
});
|
|
103
107
|
}
|
|
104
108
|
async increment(collection, incs, where = {}) {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
const res = await db.collection(collection).updateMany(
|
|
108
|
-
return
|
|
109
|
+
const formattedWhere = this._formatQuery(where);
|
|
110
|
+
return this._execute(async () => {
|
|
111
|
+
const res = await this.db.collection(collection).updateMany(formattedWhere, { $inc: incs });
|
|
112
|
+
return res.modifiedCount;
|
|
109
113
|
});
|
|
110
114
|
}
|
|
111
115
|
async decrement(collection, decs, where = {}) {
|
|
@@ -114,7 +118,28 @@ class MongoDBDatabase extends IDatabase_1.IDatabase {
|
|
|
114
118
|
incs[k] = -decs[k];
|
|
115
119
|
return this.increment(collection, incs, where);
|
|
116
120
|
}
|
|
117
|
-
async close() {
|
|
121
|
+
async close() {
|
|
122
|
+
if (this.client)
|
|
123
|
+
await this.client.close();
|
|
124
|
+
this._isConnected = false;
|
|
125
|
+
}
|
|
126
|
+
// Helper: _id handling and query formatting
|
|
127
|
+
_formatQuery(where) {
|
|
128
|
+
if (!where)
|
|
129
|
+
return {};
|
|
130
|
+
const query = { ...where };
|
|
131
|
+
if (query._id && typeof query._id === 'string' && mongodb_1.ObjectId.isValid(query._id)) {
|
|
132
|
+
query._id = new mongodb_1.ObjectId(query._id);
|
|
133
|
+
}
|
|
134
|
+
return query;
|
|
135
|
+
}
|
|
136
|
+
_serialize(doc) {
|
|
137
|
+
if (!doc)
|
|
138
|
+
return doc;
|
|
139
|
+
const { _id, ...rest } = doc;
|
|
140
|
+
// _id'yi string olarak döndür, ZeroHelper standardı
|
|
141
|
+
return { _id: _id.toString(), ...rest };
|
|
142
|
+
}
|
|
118
143
|
}
|
|
119
144
|
exports.MongoDBDatabase = MongoDBDatabase;
|
|
120
145
|
exports.default = MongoDBDatabase;
|
package/dist/database/mysql.js
CHANGED
|
@@ -32,14 +32,18 @@ ${config.database}
|
|
|
32
32
|
password: config.password,
|
|
33
33
|
database: config.database,
|
|
34
34
|
waitForConnections: true,
|
|
35
|
-
connectionLimit: config.poolSize ||
|
|
35
|
+
connectionLimit: config.poolSize || 15, // Balanced limit
|
|
36
36
|
queueLimit: 0,
|
|
37
|
+
enableKeepAlive: true,
|
|
38
|
+
keepAliveInitialDelay: 10000
|
|
37
39
|
});
|
|
38
40
|
this._connected = true;
|
|
39
41
|
resolve(this.pool);
|
|
40
42
|
this._processQueue();
|
|
41
43
|
}
|
|
42
44
|
catch (error) {
|
|
45
|
+
this._queue.forEach(q => q.reject(error));
|
|
46
|
+
this._queue = [];
|
|
43
47
|
reject(error);
|
|
44
48
|
}
|
|
45
49
|
});
|
|
@@ -72,8 +76,21 @@ ${config.database}
|
|
|
72
76
|
}
|
|
73
77
|
async query(sql, params = []) {
|
|
74
78
|
const pool = await this._connectionPromise;
|
|
75
|
-
|
|
76
|
-
|
|
79
|
+
let retries = 3;
|
|
80
|
+
while (retries > 0) {
|
|
81
|
+
try {
|
|
82
|
+
const [rows] = await pool.execute(sql, params);
|
|
83
|
+
return rows;
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
if ((error.code === 'ER_CON_COUNT_ERROR' || error.message.includes('Too many connections')) && retries > 1) {
|
|
87
|
+
retries--;
|
|
88
|
+
await new Promise(r => setTimeout(r, 1000)); // Wait 1s and retry
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
throw error;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
77
94
|
}
|
|
78
95
|
async _ensureMissingColumns(table, data) {
|
|
79
96
|
const existingColumns = await this.query(`DESCRIBE
|
|
@@ -144,11 +161,12 @@ ${k}
|
|
|
144
161
|
return this._execute('delete', table, async () => {
|
|
145
162
|
await this.ensureTable(table, where);
|
|
146
163
|
const keys = Object.keys(where);
|
|
164
|
+
const whereClause = keys.length > 0 ? `WHERE ${keys.map(k => `
|
|
165
|
+
${k}
|
|
166
|
+
= ?`).join(" AND ")}` : '';
|
|
147
167
|
const sql = `DELETE FROM
|
|
148
168
|
${table}
|
|
149
|
-
|
|
150
|
-
${k}
|
|
151
|
-
= ?`).join(" AND ")}`;
|
|
169
|
+
${whereClause}`;
|
|
152
170
|
const result = await this.query(sql, Object.values(where).map(v => typeof v === 'object' ? JSON.stringify(v) : v));
|
|
153
171
|
return result.affectedRows;
|
|
154
172
|
});
|
package/dist/database/pg.js
CHANGED
|
@@ -27,6 +27,8 @@ class PostgreSQLDatabase extends IDatabase_1.IDatabase {
|
|
|
27
27
|
this._processQueue();
|
|
28
28
|
}
|
|
29
29
|
catch (error) {
|
|
30
|
+
this._queue.forEach(q => q.reject(error));
|
|
31
|
+
this._queue = [];
|
|
30
32
|
reject(error);
|
|
31
33
|
}
|
|
32
34
|
});
|
|
@@ -61,7 +63,7 @@ class PostgreSQLDatabase extends IDatabase_1.IDatabase {
|
|
|
61
63
|
async ensureTable(table, data = {}) {
|
|
62
64
|
const tables = await this.query(`SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_name = $1`, [table]);
|
|
63
65
|
if (tables.length === 0) {
|
|
64
|
-
const defs = Object.keys(data).map(k => `"${k}"
|
|
66
|
+
const defs = Object.keys(data).map(k => `"${k}" ${this._getColumnType(data[k])}`);
|
|
65
67
|
await this.query(`CREATE TABLE "${table}" ("_id" SERIAL PRIMARY KEY ${defs.length ? ', ' + defs.join(",") : ''})`);
|
|
66
68
|
}
|
|
67
69
|
else {
|
|
@@ -69,7 +71,7 @@ class PostgreSQLDatabase extends IDatabase_1.IDatabase {
|
|
|
69
71
|
const names = existing.map((c) => c.column_name);
|
|
70
72
|
for (const key of Object.keys(data)) {
|
|
71
73
|
if (key !== '_id' && !names.includes(key)) {
|
|
72
|
-
await this.query(`ALTER TABLE "${table}" ADD COLUMN "${key}"
|
|
74
|
+
await this.query(`ALTER TABLE "${table}" ADD COLUMN "${key}" ${this._getColumnType(data[key])}`);
|
|
73
75
|
}
|
|
74
76
|
}
|
|
75
77
|
}
|
|
@@ -90,8 +92,9 @@ class PostgreSQLDatabase extends IDatabase_1.IDatabase {
|
|
|
90
92
|
await this.runHooks('beforeUpdate', table, { data, where });
|
|
91
93
|
return this._execute('update', table, async () => {
|
|
92
94
|
await this.ensureTable(table, { ...data, ...where });
|
|
93
|
-
const
|
|
94
|
-
const
|
|
95
|
+
const dataKeys = Object.keys(data);
|
|
96
|
+
const set = dataKeys.map((k, i) => `"${k}" = $${i + 1}`).join(",");
|
|
97
|
+
const { whereClause, values: whereValues } = this._buildWhereClause(where, dataKeys.length);
|
|
95
98
|
const sql = `UPDATE "${table}" SET ${set} ${whereClause}`;
|
|
96
99
|
const pool = await this._connectionPromise;
|
|
97
100
|
const res = await pool.query(sql, [...Object.values(data).map(v => this._serializeValue(v)), ...whereValues]);
|
|
@@ -116,8 +119,13 @@ class PostgreSQLDatabase extends IDatabase_1.IDatabase {
|
|
|
116
119
|
const rows = await this.query(`SELECT * FROM "${table}" ${whereClause}`, values);
|
|
117
120
|
return rows.map((r) => {
|
|
118
121
|
const nr = {};
|
|
119
|
-
for (const k in r)
|
|
122
|
+
for (const k in r) {
|
|
123
|
+
// Postgres returns numbers as strings for safety sometimes,
|
|
124
|
+
// but since we used correct types now, driver might handle it better.
|
|
125
|
+
// If not, we can cast if it looks like a number.
|
|
126
|
+
// For now, let's trust the driver + schema.
|
|
120
127
|
nr[k] = r[k];
|
|
128
|
+
}
|
|
121
129
|
return nr;
|
|
122
130
|
});
|
|
123
131
|
});
|
|
@@ -140,8 +148,9 @@ class PostgreSQLDatabase extends IDatabase_1.IDatabase {
|
|
|
140
148
|
async increment(table, incs, where) {
|
|
141
149
|
return this._execute('increment', table, async () => {
|
|
142
150
|
await this.ensureTable(table, where);
|
|
143
|
-
const
|
|
144
|
-
const
|
|
151
|
+
const incKeys = Object.keys(incs);
|
|
152
|
+
const set = incKeys.map((f, i) => `"${f}" = "${f}" + $${i + 1}`).join(',');
|
|
153
|
+
const { whereClause, values } = this._buildWhereClause(where, incKeys.length);
|
|
145
154
|
const sql = `UPDATE "${table}" SET ${set} ${whereClause}`;
|
|
146
155
|
const pool = await this._connectionPromise;
|
|
147
156
|
const res = await pool.query(sql, [...Object.values(incs), ...values]);
|
|
@@ -174,7 +183,7 @@ class PostgreSQLDatabase extends IDatabase_1.IDatabase {
|
|
|
174
183
|
return v.toISOString();
|
|
175
184
|
return (typeof v === 'object' && v !== null) ? JSON.stringify(v) : v;
|
|
176
185
|
}
|
|
177
|
-
_buildWhereClause(where) {
|
|
186
|
+
_buildWhereClause(where, offset = 0) {
|
|
178
187
|
if (!where)
|
|
179
188
|
return { whereClause: '', values: [] };
|
|
180
189
|
const safeWhere = where;
|
|
@@ -182,7 +191,7 @@ class PostgreSQLDatabase extends IDatabase_1.IDatabase {
|
|
|
182
191
|
if (!keys.length)
|
|
183
192
|
return { whereClause: '', values: [] };
|
|
184
193
|
return {
|
|
185
|
-
whereClause: 'WHERE ' + keys.map((k, i) => `"${k}" = $${i + 1}`).join(' AND '),
|
|
194
|
+
whereClause: 'WHERE ' + keys.map((k, i) => `"${k}" = $${i + 1 + offset}`).join(' AND '),
|
|
186
195
|
values: keys.map(k => this._serializeValue(safeWhere[k]))
|
|
187
196
|
};
|
|
188
197
|
}
|
package/dist/database/redis.d.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { IDatabase } from './IDatabase';
|
|
2
|
-
import { RedisClientType } from 'redis';
|
|
3
2
|
import { RedisConfig } from './types';
|
|
4
3
|
export declare class RedisDatabase extends IDatabase {
|
|
5
4
|
private config;
|
|
6
5
|
private client;
|
|
7
|
-
private isConnecting;
|
|
8
6
|
private keyPrefix;
|
|
7
|
+
private _queue;
|
|
8
|
+
private _isReady;
|
|
9
|
+
private _connectionPromise;
|
|
9
10
|
constructor(config: RedisConfig);
|
|
11
|
+
private _ensureConnection;
|
|
12
|
+
private _flushQueue;
|
|
13
|
+
private _flushQueueWithError;
|
|
10
14
|
private _execute;
|
|
11
|
-
connect(): Promise<RedisClientType>;
|
|
12
15
|
private _getKey;
|
|
13
16
|
private _getTableKey;
|
|
14
17
|
select<T = any>(table: string, where?: Record<string, any>): Promise<T[]>;
|
|
@@ -18,6 +21,9 @@ export declare class RedisDatabase extends IDatabase {
|
|
|
18
21
|
delete(table: string, where: Record<string, any>): Promise<number>;
|
|
19
22
|
set(table: string, data: Record<string, any>, where: Record<string, any>): Promise<any>;
|
|
20
23
|
bulkInsert(table: string, dataArray: Record<string, any>[]): Promise<number>;
|
|
24
|
+
/**
|
|
25
|
+
* Atomic Increment using Lua for Redis
|
|
26
|
+
*/
|
|
21
27
|
increment(table: string, incs: Record<string, number>, where?: Record<string, any>): Promise<number>;
|
|
22
28
|
decrement(table: string, decs: Record<string, number>, where?: Record<string, any>): Promise<number>;
|
|
23
29
|
close(): Promise<void>;
|