sehawq.db 3.0.0 → 4.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/src/index.js CHANGED
@@ -1,760 +1,116 @@
1
- const fs = require("fs").promises;
2
- const path = require("path");
3
- const EventEmitter = require("events");
4
- const http = require("http");
5
- const express = require("express");
6
- const { Server } = require("socket.io");
7
- const cors = require("cors");
1
+ // src/index.js - The heart of SehawqDB v4.0.0
2
+ const Database = require('./core/Database');
3
+ const QueryEngine = require('./core/QueryEngine');
4
+ const IndexManager = require('./core/IndexManager');
5
+ const Storage = require('./core/Storage');
8
6
 
9
- class SehawqDB extends EventEmitter {
10
- /**
11
- * Create a new SehawqDB instance.
12
- * @param {Object} options
13
- * @param {string} [options.path="sehawq.json"] File path for storage.
14
- * @param {number} [options.autoSaveInterval=0] Autosave interval in ms (0 disables autosave).
15
- * @param {boolean} [options.enableServer=false] Enable REST API server
16
- * @param {number} [options.serverPort=3000] Server port
17
- * @param {boolean} [options.enableRealtime=true] Enable real-time sync via WebSocket
18
- * @param {string} [options.apiKey] Optional API key for authentication
19
- */
7
+ class SehawqDB {
20
8
  constructor(options = {}) {
21
- super();
22
- this.filePath = path.resolve(options.path || "sehawq.json");
23
- this.autoSaveInterval = options.autoSaveInterval || 0;
24
- this.data = {};
25
-
26
- // Server options
27
- this.enableServer = options.enableServer || false;
28
- this.serverPort = options.serverPort || 3000;
29
- this.enableRealtime = options.enableRealtime !== false;
30
- this.apiKey = options.apiKey || null;
31
-
32
- // Server instances
33
- this.app = null;
34
- this.server = null;
35
- this.io = null;
36
- this.isServerRunning = false;
37
-
38
- this._init();
39
-
40
- if (this.autoSaveInterval > 0) {
41
- this._interval = setInterval(() => this.save(), this.autoSaveInterval);
42
- }
43
-
44
- if (this.enableServer) {
45
- this.startServer(this.serverPort);
46
- }
47
- }
48
-
49
- async _init() {
50
- try {
51
- await fs.access(this.filePath);
52
- } catch {
53
- await fs.writeFile(this.filePath, JSON.stringify({}), "utf8");
54
- }
55
-
56
- try {
57
- const content = await fs.readFile(this.filePath, "utf8");
58
- this.data = JSON.parse(content);
59
- } catch {
60
- this.data = {};
61
- }
62
- }
63
-
64
- // ---------------- Core methods ----------------
65
- set(key, value) {
66
- this._setByPath(key, value);
67
- this.emit("set", { key, value });
68
-
69
- // Real-time broadcast
70
- if (this.io) {
71
- this.io.emit("data:changed", {
72
- action: "set",
73
- key,
74
- value,
75
- timestamp: Date.now()
76
- });
77
- }
78
-
79
- this.save();
80
- return value;
81
- }
82
-
83
- get(key) {
84
- return this._getByPath(key);
85
- }
86
-
87
- delete(key) {
88
- this._deleteByPath(key);
89
- this.emit("delete", { key });
90
-
91
- // Real-time broadcast
92
- if (this.io) {
93
- this.io.emit("data:changed", {
94
- action: "delete",
95
- key,
96
- timestamp: Date.now()
97
- });
98
- }
99
-
100
- this.save();
101
- }
102
-
103
- has(key) {
104
- return this._getByPath(key) !== undefined;
105
- }
106
-
107
- all() {
108
- return this.data;
109
- }
110
-
111
- clear() {
112
- this.data = {};
113
- this.emit("clear");
114
-
115
- // Real-time broadcast
116
- if (this.io) {
117
- this.io.emit("data:changed", {
118
- action: "clear",
119
- timestamp: Date.now()
120
- });
121
- }
122
-
123
- this.save();
124
- }
125
-
126
- keys() {
127
- return Object.keys(this.data);
128
- }
129
-
130
- values() {
131
- return Object.values(this.data);
132
- }
133
-
134
- // ---------------- Array helpers ----------------
135
- push(key, value) {
136
- let arr = this._getByPath(key);
137
- if (!Array.isArray(arr)) arr = [];
138
- arr.push(value);
139
- this._setByPath(key, arr);
140
- this.emit("push", { key, value });
141
-
142
- // Real-time broadcast
143
- if (this.io) {
144
- this.io.emit("data:changed", {
145
- action: "push",
146
- key,
147
- value,
148
- timestamp: Date.now()
149
- });
150
- }
151
-
152
- this.save();
153
- return arr;
154
- }
155
-
156
- pull(key, value) {
157
- let arr = this._getByPath(key);
158
- if (!Array.isArray(arr)) return [];
159
- arr = arr.filter(v => v !== value);
160
- this._setByPath(key, arr);
161
- this.emit("pull", { key, value });
162
-
163
- // Real-time broadcast
164
- if (this.io) {
165
- this.io.emit("data:changed", {
166
- action: "pull",
167
- key,
168
- value,
169
- timestamp: Date.now()
170
- });
171
- }
172
-
173
- this.save();
174
- return arr;
175
- }
176
-
177
- // ---------------- Math helpers ----------------
178
- add(key, number) {
179
- let val = this._getByPath(key);
180
- if (typeof val !== "number") val = 0;
181
- val += number;
182
- this._setByPath(key, val);
183
- this.emit("add", { key, number });
184
-
185
- // Real-time broadcast
186
- if (this.io) {
187
- this.io.emit("data:changed", {
188
- action: "add",
189
- key,
190
- number,
191
- newValue: val,
192
- timestamp: Date.now()
193
- });
194
- }
195
-
196
- this.save();
197
- return val;
198
- }
199
-
200
- subtract(key, number) {
201
- return this.add(key, -number);
202
- }
203
-
204
- // ---------------- Query System ----------------
205
-
206
- find(filter) {
207
- const results = [];
208
-
209
- if (typeof filter === 'function') {
210
- for (const [key, value] of Object.entries(this.data)) {
211
- if (filter(value, key)) {
212
- results.push({ key, value });
213
- }
214
- }
215
- } else {
216
- for (const [key, value] of Object.entries(this.data)) {
217
- results.push({ key, value });
218
- }
219
- }
220
-
221
- return new QueryResult(results);
222
- }
223
-
224
- findOne(filter) {
225
- if (typeof filter === 'function') {
226
- for (const [key, value] of Object.entries(this.data)) {
227
- if (filter(value, key)) {
228
- return { key, value };
229
- }
230
- }
231
- }
232
- return undefined;
233
- }
234
-
235
- where(field, operator, value) {
236
- return this.find((item, key) => {
237
- const fieldValue = this._getValueByPath(item, field);
238
-
239
- switch (operator) {
240
- case '=':
241
- case '==':
242
- return fieldValue === value;
243
- case '!=':
244
- return fieldValue !== value;
245
- case '>':
246
- return fieldValue > value;
247
- case '<':
248
- return fieldValue < value;
249
- case '>=':
250
- return fieldValue >= value;
251
- case '<=':
252
- return fieldValue <= value;
253
- case 'in':
254
- return Array.isArray(value) && value.includes(fieldValue);
255
- case 'contains':
256
- return typeof fieldValue === 'string' && fieldValue.includes(value);
257
- case 'startsWith':
258
- return typeof fieldValue === 'string' && fieldValue.startsWith(value);
259
- case 'endsWith':
260
- return typeof fieldValue === 'string' && fieldValue.endsWith(value);
261
- default:
262
- return false;
263
- }
264
- });
265
- }
266
-
267
- // ---------------- Aggregation System ----------------
268
-
269
- count(filter) {
270
- if (filter) {
271
- return this.find(filter).count();
272
- }
273
- return Object.keys(this.data).length;
274
- }
275
-
276
- sum(field, filter) {
277
- const items = filter ? this.find(filter).toArray() : this.find().toArray();
278
- return items.reduce((sum, item) => {
279
- const val = this._getValueByPath(item.value, field);
280
- return sum + (typeof val === 'number' ? val : 0);
281
- }, 0);
282
- }
283
-
284
- avg(field, filter) {
285
- const items = filter ? this.find(filter).toArray() : this.find().toArray();
286
- if (items.length === 0) return 0;
287
-
288
- const sum = items.reduce((total, item) => {
289
- const val = this._getValueByPath(item.value, field);
290
- return total + (typeof val === 'number' ? val : 0);
291
- }, 0);
292
-
293
- return sum / items.length;
294
- }
295
-
296
- min(field, filter) {
297
- const items = filter ? this.find(filter).toArray() : this.find().toArray();
298
- if (items.length === 0) return undefined;
299
-
300
- return Math.min(...items.map(item => {
301
- const val = this._getValueByPath(item.value, field);
302
- return typeof val === 'number' ? val : Infinity;
303
- }).filter(val => val !== Infinity));
304
- }
305
-
306
- max(field, filter) {
307
- const items = filter ? this.find(filter).toArray() : this.find().toArray();
308
- if (items.length === 0) return undefined;
309
-
310
- return Math.max(...items.map(item => {
311
- const val = this._getValueByPath(item.value, field);
312
- return typeof val === 'number' ? val : -Infinity;
313
- }).filter(val => val !== -Infinity));
314
- }
315
-
316
- groupBy(field, filter) {
317
- const items = filter ? this.find(filter).toArray() : this.find().toArray();
318
- const groups = {};
319
-
320
- items.forEach(item => {
321
- const groupKey = this._getValueByPath(item.value, field);
322
- const key = groupKey !== undefined ? String(groupKey) : 'undefined';
323
-
324
- if (!groups[key]) {
325
- groups[key] = [];
326
- }
327
- groups[key].push(item);
328
- });
329
-
330
- return groups;
331
- }
332
-
333
- // ---------------- REST API Server ----------------
334
-
335
- /**
336
- * Start REST API server with real-time sync
337
- * @param {number} port - Server port
338
- * @returns {Promise<void>}
339
- */
340
- async startServer(port = 3000) {
341
- if (this.isServerRunning) {
342
- console.log(`⚠️ Server is already running on port ${this.serverPort}`);
343
- return;
344
- }
345
-
346
- this.app = express();
347
- this.server = http.createServer(this.app);
348
-
349
- // Enable real-time if requested
350
- if (this.enableRealtime) {
351
- this.io = new Server(this.server, {
352
- cors: {
353
- origin: "*",
354
- methods: ["GET", "POST", "PUT", "DELETE"]
355
- }
356
- });
357
-
358
- this._setupWebSocket();
359
- }
360
-
361
- // Middleware
362
- this.app.use(cors());
363
- this.app.use(express.json());
364
-
365
- // API Key middleware
366
- if (this.apiKey) {
367
- this.app.use((req, res, next) => {
368
- const key = req.headers['x-api-key'];
369
- if (key !== this.apiKey) {
370
- return res.status(401).json({ error: 'Unauthorized' });
371
- }
372
- next();
373
- });
374
- }
375
-
376
- this._setupRoutes();
377
-
378
- return new Promise((resolve, reject) => {
379
- this.server.listen(port, () => {
380
- this.isServerRunning = true;
381
- this.serverPort = port;
382
- console.log(`🚀 SehawqDB Server running on http://localhost:${port}`);
383
- console.log(`📡 Real-time sync: ${this.enableRealtime ? 'ENABLED' : 'DISABLED'}`);
384
- console.log(`🔒 API Key: ${this.apiKey ? 'ENABLED' : 'DISABLED'}`);
385
- this.emit('server:started', { port });
386
- resolve();
387
- }).on('error', reject);
388
- });
389
- }
390
-
391
- /**
392
- * Stop the REST API server
393
- */
394
- stopServer() {
395
- if (!this.isServerRunning) return;
396
-
397
- if (this.io) this.io.close();
398
- if (this.server) this.server.close();
399
-
400
- this.isServerRunning = false;
401
- console.log('🛑 SehawqDB Server stopped');
402
- this.emit('server:stopped');
403
- }
404
-
405
- _setupRoutes() {
406
- const router = express.Router();
407
-
408
- // Health check
409
- router.get('/health', (req, res) => {
410
- res.json({
411
- status: 'ok',
412
- uptime: process.uptime(),
413
- realtime: this.enableRealtime,
414
- dataSize: Object.keys(this.data).length
415
- });
416
- });
417
-
418
- // Get all data
419
- router.get('/data', (req, res) => {
420
- res.json({ success: true, data: this.data });
421
- });
422
-
423
- // Get by key
424
- router.get('/data/:key', (req, res) => {
425
- const { key } = req.params;
426
- const value = this.get(key);
427
-
428
- if (value === undefined) {
429
- return res.status(404).json({ success: false, error: 'Key not found' });
430
- }
431
-
432
- res.json({ success: true, key, value });
433
- });
434
-
435
- // Set data
436
- router.post('/data/:key', (req, res) => {
437
- const { key } = req.params;
438
- const { value } = req.body;
439
-
440
- if (value === undefined) {
441
- return res.status(400).json({ success: false, error: 'Value is required' });
442
- }
443
-
444
- const result = this.set(key, value);
445
- res.json({ success: true, key, value: result });
446
- });
447
-
448
- // Update data (alias for set)
449
- router.put('/data/:key', (req, res) => {
450
- const { key } = req.params;
451
- const { value } = req.body;
452
-
453
- if (value === undefined) {
454
- return res.status(400).json({ success: false, error: 'Value is required' });
455
- }
456
-
457
- const result = this.set(key, value);
458
- res.json({ success: true, key, value: result });
459
- });
460
-
461
- // Delete data
462
- router.delete('/data/:key', (req, res) => {
463
- const { key } = req.params;
464
-
465
- if (!this.has(key)) {
466
- return res.status(404).json({ success: false, error: 'Key not found' });
467
- }
468
-
469
- this.delete(key);
470
- res.json({ success: true, key });
471
- });
472
-
473
- // Query with find
474
- router.post('/query', (req, res) => {
475
- try {
476
- const { filter, sort, limit, skip } = req.body;
477
-
478
- let query = this.find();
479
-
480
- // Apply sorting
481
- if (sort && sort.field) {
482
- query = query.sort(sort.field, sort.direction || 'asc');
483
- }
484
-
485
- // Apply pagination
486
- if (skip) query = query.skip(skip);
487
- if (limit) query = query.limit(limit);
488
-
489
- const results = query.toArray();
490
-
491
- res.json({
492
- success: true,
493
- results,
494
- count: results.length
495
- });
496
- } catch (error) {
497
- res.status(400).json({ success: false, error: error.message });
498
- }
499
- });
500
-
501
- // Aggregation
502
- router.get('/aggregate/:operation', (req, res) => {
503
- try {
504
- const { operation } = req.params;
505
- const { field } = req.query;
506
-
507
- let result;
508
-
509
- switch (operation) {
510
- case 'count':
511
- result = this.count();
512
- break;
513
- case 'sum':
514
- if (!field) return res.status(400).json({ error: 'Field is required' });
515
- result = this.sum(field);
516
- break;
517
- case 'avg':
518
- if (!field) return res.status(400).json({ error: 'Field is required' });
519
- result = this.avg(field);
520
- break;
521
- case 'min':
522
- if (!field) return res.status(400).json({ error: 'Field is required' });
523
- result = this.min(field);
524
- break;
525
- case 'max':
526
- if (!field) return res.status(400).json({ error: 'Field is required' });
527
- result = this.max(field);
528
- break;
529
- default:
530
- return res.status(400).json({ error: 'Invalid operation' });
531
- }
532
-
533
- res.json({ success: true, operation, field, result });
534
- } catch (error) {
535
- res.status(400).json({ success: false, error: error.message });
536
- }
537
- });
538
-
539
- // Array operations
540
- router.post('/array/:key/push', (req, res) => {
541
- const { key } = req.params;
542
- const { value } = req.body;
543
-
544
- const result = this.push(key, value);
545
- res.json({ success: true, key, value: result });
546
- });
547
-
548
- router.post('/array/:key/pull', (req, res) => {
549
- const { key } = req.params;
550
- const { value } = req.body;
551
-
552
- const result = this.pull(key, value);
553
- res.json({ success: true, key, value: result });
554
- });
555
-
556
- // Math operations
557
- router.post('/math/:key/add', (req, res) => {
558
- const { key } = req.params;
559
- const { number } = req.body;
560
-
561
- if (typeof number !== 'number') {
562
- return res.status(400).json({ error: 'Number is required' });
563
- }
564
-
565
- const result = this.add(key, number);
566
- res.json({ success: true, key, value: result });
567
- });
568
-
569
- router.post('/math/:key/subtract', (req, res) => {
570
- const { key } = req.params;
571
- const { number } = req.body;
572
-
573
- if (typeof number !== 'number') {
574
- return res.status(400).json({ error: 'Number is required' });
575
- }
576
-
577
- const result = this.subtract(key, number);
578
- res.json({ success: true, key, value: result });
579
- });
580
-
581
- this.app.use('/api', router);
582
- }
583
-
584
- _setupWebSocket() {
585
- this.io.on('connection', (socket) => {
586
- console.log(`✅ Client connected: ${socket.id}`);
587
- this.emit('client:connected', { socketId: socket.id });
588
-
589
- // Send current data on connection
590
- socket.emit('data:init', this.data);
591
-
592
- // Handle client operations
593
- socket.on('data:set', ({ key, value }) => {
594
- this.set(key, value);
595
- });
596
-
597
- socket.on('data:delete', ({ key }) => {
598
- this.delete(key);
599
- });
600
-
601
- socket.on('data:get', ({ key }, callback) => {
602
- const value = this.get(key);
603
- callback({ success: true, value });
604
- });
605
-
606
- socket.on('disconnect', () => {
607
- console.log(`❌ Client disconnected: ${socket.id}`);
608
- this.emit('client:disconnected', { socketId: socket.id });
609
- });
610
- });
611
- }
612
-
613
- // ---------------- Backup & Restore ----------------
614
- async backup(backupPath) {
615
- await fs.writeFile(backupPath, JSON.stringify(this.data, null, 2), "utf8");
616
- this.emit("backup", { backupPath });
617
- }
618
-
619
- async restore(backupPath) {
620
- const content = await fs.readFile(backupPath, "utf8");
621
- this.data = JSON.parse(content);
622
- await this.save();
623
- this.emit("restore", { backupPath });
624
- }
625
-
626
- // ---------------- Save ----------------
627
- async save() {
628
- const tmpPath = `${this.filePath}.tmp`;
629
- await fs.writeFile(tmpPath, JSON.stringify(this.data, null, 2), "utf8");
630
- await fs.rename(tmpPath, this.filePath);
631
- }
632
-
633
- // ---------------- Internal utilities ----------------
634
- _getByPath(pathStr) {
635
- const keys = pathStr.split(".");
636
- let obj = this.data;
637
- for (const k of keys) {
638
- if (obj && Object.prototype.hasOwnProperty.call(obj, k)) {
639
- obj = obj[k];
640
- } else {
641
- return undefined;
642
- }
643
- }
644
- return obj;
645
- }
646
-
647
- _setByPath(pathStr, value) {
648
- const keys = pathStr.split(".");
649
- let obj = this.data;
650
- while (keys.length > 1) {
651
- const k = keys.shift();
652
- if (!obj[k] || typeof obj[k] !== "object") obj[k] = {};
653
- obj = obj[k];
654
- }
655
- obj[keys[0]] = value;
656
- }
657
-
658
- _deleteByPath(pathStr) {
659
- const keys = pathStr.split(".");
660
- let obj = this.data;
661
- while (keys.length > 1) {
662
- const k = keys.shift();
663
- if (!obj[k]) return;
664
- obj = obj[k];
665
- }
666
- delete obj[keys[0]];
667
- }
668
-
669
- _getValueByPath(obj, pathStr) {
670
- const keys = pathStr.split(".");
671
- let result = obj;
672
- for (const key of keys) {
673
- if (result && Object.prototype.hasOwnProperty.call(result, key)) {
674
- result = result[key];
675
- } else {
676
- return undefined;
677
- }
678
- }
679
- return result;
680
- }
681
- }
682
-
683
- // ---------------- QueryResult Class ----------------
684
- class QueryResult {
685
- constructor(results) {
686
- this.results = results || [];
687
- }
688
-
689
- sort(field, direction = 'asc') {
690
- this.results.sort((a, b) => {
691
- const aVal = this._getValueByPath(a.value, field);
692
- const bVal = this._getValueByPath(b.value, field);
693
-
694
- if (aVal === bVal) return 0;
695
-
696
- const comparison = aVal > bVal ? 1 : -1;
697
- return direction === 'desc' ? -comparison : comparison;
698
- });
699
-
9
+ this.database = new Database(options);
10
+ this.queryEngine = new QueryEngine(this.database);
11
+ this.indexManager = new IndexManager(this.database, options);
12
+
13
+ // Database methods
14
+ this.set = this.database.set.bind(this.database);
15
+ this.get = this.database.get.bind(this.database);
16
+ this.delete = this.database.delete.bind(this.database);
17
+ this.has = this.database.has.bind(this.database);
18
+ this.all = this.database.all.bind(this.database);
19
+ this.clear = this.database.clear.bind(this.database);
20
+
21
+ // 🔥 Query methods
22
+ this.find = this.queryEngine.find.bind(this.queryEngine);
23
+ this.where = this.queryEngine.where.bind(this.queryEngine);
24
+ this.findAll = this.queryEngine.findAll.bind(this.queryEngine);
25
+ this.count = this.queryEngine.count.bind(this.queryEngine);
26
+ this.sum = this.queryEngine.sum.bind(this.queryEngine);
27
+ this.avg = this.queryEngine.avg.bind(this.queryEngine);
28
+ this.min = this.queryEngine.min.bind(this.queryEngine);
29
+ this.max = this.queryEngine.max.bind(this.queryEngine);
30
+ this.groupBy = this.queryEngine.groupBy.bind(this.queryEngine);
31
+
32
+ // 🔥 Index methods
33
+ this.createIndex = this.indexManager.createIndex.bind(this.indexManager);
34
+ this.dropIndex = this.indexManager.dropIndex.bind(this.indexManager);
35
+ this.getIndexes = this.indexManager.getIndexes.bind(this.indexManager);
36
+
37
+ // 🔥 ARRAY & MATH Methods
38
+ this.push = this.database.push?.bind(this.database) || this._fallbackPush.bind(this);
39
+ this.pull = this.database.pull?.bind(this.database) || this._fallbackPull.bind(this);
40
+ this.add = this.database.add?.bind(this.database) || this._fallbackAdd.bind(this);
41
+ this.subtract = this.database.subtract?.bind(this.database) || this._fallbackSubtract.bind(this);
42
+
43
+ // 🔥 BACKUP & RESTORE Methods
44
+ this.backup = this.database.backup?.bind(this.database) || this._fallbackBackup.bind(this);
45
+ this.restore = this.database.restore?.bind(this.database) || this._fallbackRestore.bind(this);
46
+ }
47
+
48
+ // 🔥 FALLBACK Methods
49
+ _fallbackPush(key, value) {
50
+ const array = this.get(key) || [];
51
+ array.push(value);
52
+ this.set(key, array);
53
+ return array.length;
54
+ }
55
+
56
+ _fallbackPull(key, value) {
57
+ const array = this.get(key) || [];
58
+ const index = array.indexOf(value);
59
+ if (index > -1) {
60
+ array.splice(index, 1);
61
+ this.set(key, array);
62
+ return true;
63
+ }
64
+ return false;
65
+ }
66
+
67
+ _fallbackAdd(key, number) {
68
+ const current = this.get(key) || 0;
69
+ const newValue = current + number;
70
+ this.set(key, newValue);
71
+ return newValue;
72
+ }
73
+
74
+ _fallbackSubtract(key, number) {
75
+ return this._fallbackAdd(key, -number);
76
+ }
77
+
78
+ // 🔥 BACKUP FALLBACK Methods
79
+ async _fallbackBackup(backupPath = null) {
80
+ const path = backupPath || `./sehawq-backup-${Date.now()}.json`;
81
+ const storage = new Storage(path);
82
+ const data = this.all();
83
+ await storage.write(data);
84
+ return path;
85
+ }
86
+
87
+ async _fallbackRestore(backupPath) {
88
+ const storage = new Storage(backupPath);
89
+ const data = await storage.read();
90
+ this.clear();
91
+ for (const [key, value] of Object.entries(data)) {
92
+ this.set(key, value);
93
+ }
94
+ return true;
95
+ }
96
+
97
+ async start() {
98
+ await new Promise(resolve => this.database.on('ready', resolve));
700
99
  return this;
701
100
  }
702
101
 
703
- limit(count) {
704
- this.results = this.results.slice(0, count);
705
- return this;
102
+ async stop() {
103
+ await this.database.close();
706
104
  }
707
105
 
708
- skip(count) {
709
- this.results = this.results.slice(count);
710
- return this;
711
- }
712
-
713
- count() {
714
- return this.results.length;
715
- }
716
-
717
- first() {
718
- return this.results[0];
719
- }
720
-
721
- last() {
722
- return this.results[this.results.length - 1];
723
- }
724
-
725
- toArray() {
726
- return this.results;
727
- }
728
-
729
- values() {
730
- return this.results.map(item => item.value);
731
- }
732
-
733
- keys() {
734
- return this.results.map(item => item.key);
735
- }
736
-
737
- filter(filter) {
738
- this.results = this.results.filter(item => filter(item.value, item.key));
739
- return this;
740
- }
741
-
742
- map(mapper) {
743
- return this.results.map(item => mapper(item.value, item.key));
744
- }
745
-
746
- _getValueByPath(obj, pathStr) {
747
- const keys = pathStr.split(".");
748
- let result = obj;
749
- for (const key of keys) {
750
- if (result && Object.prototype.hasOwnProperty.call(result, key)) {
751
- result = result[key];
752
- } else {
753
- return undefined;
754
- }
755
- }
756
- return result;
106
+ // 🔥 STATS Methods
107
+ getStats() {
108
+ return {
109
+ database: this.database.getStats?.(),
110
+ query: this.queryEngine.getStats?.(),
111
+ indexes: this.indexManager.getStats?.()
112
+ };
757
113
  }
758
114
  }
759
115
 
760
- module.exports = SehawqDB;
116
+ module.exports = { SehawqDB };