waengine 1.7.3 → 1.7.4

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.
@@ -0,0 +1,766 @@
1
+ import { getStorage } from "./storage.js";
2
+ import { ErrorHandler } from "./error-handler.js";
3
+
4
+ export class DatabaseManager {
5
+ constructor(client) {
6
+ this.client = client;
7
+ this.storage = getStorage();
8
+ this.errorHandler = new ErrorHandler();
9
+ this.databases = new Map();
10
+ this.schemas = new Map();
11
+ this.indexes = new Map();
12
+ this.queryCache = new Map();
13
+ this.transactions = new Map();
14
+
15
+ this.initializeDatabase();
16
+ }
17
+
18
+ // ===== INITIALIZATION =====
19
+
20
+ initializeDatabase() {
21
+ this.loadDatabases();
22
+ this.setupDefaultSchemas();
23
+ this.startMaintenanceJob();
24
+ }
25
+
26
+ loadDatabases() {
27
+ try {
28
+ const dbData = this.storage.read.from("database").get("data") || {};
29
+ this.databases = new Map(Object.entries(dbData.databases || {}));
30
+ this.schemas = new Map(Object.entries(dbData.schemas || {}));
31
+ this.indexes = new Map(Object.entries(dbData.indexes || {}));
32
+ } catch (error) {
33
+ this.errorHandler.handle(error, 'DatabaseManager.loadDatabases');
34
+ }
35
+ }
36
+
37
+ setupDefaultSchemas() {
38
+ // User schema
39
+ this.createSchema('users', {
40
+ id: { type: 'string', required: true, unique: true },
41
+ name: { type: 'string', required: true },
42
+ phone: { type: 'string', unique: true },
43
+ email: { type: 'string' },
44
+ createdAt: { type: 'date', default: () => new Date() },
45
+ updatedAt: { type: 'date', default: () => new Date() },
46
+ isActive: { type: 'boolean', default: true },
47
+ metadata: { type: 'object', default: {} }
48
+ });
49
+
50
+ // Messages schema
51
+ this.createSchema('messages', {
52
+ id: { type: 'string', required: true, unique: true },
53
+ chatId: { type: 'string', required: true },
54
+ senderId: { type: 'string', required: true },
55
+ content: { type: 'string', required: true },
56
+ type: { type: 'string', enum: ['text', 'image', 'video', 'audio', 'document'] },
57
+ timestamp: { type: 'date', default: () => new Date() },
58
+ isRead: { type: 'boolean', default: false },
59
+ metadata: { type: 'object', default: {} }
60
+ });
61
+
62
+ // Groups schema
63
+ this.createSchema('groups', {
64
+ id: { type: 'string', required: true, unique: true },
65
+ name: { type: 'string', required: true },
66
+ description: { type: 'string' },
67
+ members: { type: 'array', default: [] },
68
+ admins: { type: 'array', default: [] },
69
+ createdAt: { type: 'date', default: () => new Date() },
70
+ settings: { type: 'object', default: {} }
71
+ });
72
+ }
73
+
74
+ startMaintenanceJob() {
75
+ setInterval(() => {
76
+ this.cleanupCache();
77
+ this.optimizeIndexes();
78
+ }, 300000); // Every 5 minutes
79
+ }
80
+
81
+ // ===== SCHEMA MANAGEMENT =====
82
+
83
+ createSchema(tableName, schema) {
84
+ try {
85
+ this.schemas.set(tableName, {
86
+ name: tableName,
87
+ fields: schema,
88
+ createdAt: Date.now(),
89
+ version: 1
90
+ });
91
+
92
+ // Create database table if it doesn't exist
93
+ if (!this.databases.has(tableName)) {
94
+ this.databases.set(tableName, new Map());
95
+ }
96
+
97
+ // Create indexes for unique fields
98
+ this.createIndexesForSchema(tableName, schema);
99
+
100
+ this.saveDatabaseData();
101
+ console.log(`📊 Schema created: ${tableName}`);
102
+
103
+ return true;
104
+ } catch (error) {
105
+ this.errorHandler.handle(error, 'DatabaseManager.createSchema');
106
+ return false;
107
+ }
108
+ }
109
+
110
+ createIndexesForSchema(tableName, schema) {
111
+ const tableIndexes = new Map();
112
+
113
+ Object.entries(schema).forEach(([fieldName, fieldConfig]) => {
114
+ if (fieldConfig.unique || fieldConfig.index) {
115
+ tableIndexes.set(fieldName, new Map());
116
+ }
117
+ });
118
+
119
+ this.indexes.set(tableName, tableIndexes);
120
+ }
121
+
122
+ updateSchema(tableName, newSchema) {
123
+ try {
124
+ const existingSchema = this.schemas.get(tableName);
125
+ if (!existingSchema) {
126
+ throw new Error(`Schema not found: ${tableName}`);
127
+ }
128
+
129
+ existingSchema.fields = { ...existingSchema.fields, ...newSchema };
130
+ existingSchema.version++;
131
+ existingSchema.updatedAt = Date.now();
132
+
133
+ this.saveDatabaseData();
134
+ return true;
135
+ } catch (error) {
136
+ this.errorHandler.handle(error, 'DatabaseManager.updateSchema');
137
+ return false;
138
+ }
139
+ }
140
+
141
+ // ===== CRUD OPERATIONS =====
142
+
143
+ async insert(tableName, data) {
144
+ try {
145
+ const schema = this.schemas.get(tableName);
146
+ if (!schema) {
147
+ throw new Error(`Schema not found: ${tableName}`);
148
+ }
149
+
150
+ // Validate data
151
+ const validatedData = this.validateData(data, schema.fields);
152
+
153
+ // Check unique constraints
154
+ await this.checkUniqueConstraints(tableName, validatedData);
155
+
156
+ // Generate ID if not provided
157
+ if (!validatedData.id) {
158
+ validatedData.id = this.generateId();
159
+ }
160
+
161
+ // Get table
162
+ const table = this.databases.get(tableName);
163
+
164
+ // Insert data
165
+ table.set(validatedData.id, validatedData);
166
+
167
+ // Update indexes
168
+ this.updateIndexes(tableName, validatedData, 'insert');
169
+
170
+ this.saveDatabaseData();
171
+
172
+ console.log(`✅ Inserted into ${tableName}: ${validatedData.id}`);
173
+ return validatedData;
174
+ } catch (error) {
175
+ this.errorHandler.handle(error, 'DatabaseManager.insert');
176
+ throw error;
177
+ }
178
+ }
179
+
180
+ async findById(tableName, id) {
181
+ try {
182
+ const table = this.databases.get(tableName);
183
+ if (!table) {
184
+ throw new Error(`Table not found: ${tableName}`);
185
+ }
186
+
187
+ return table.get(id) || null;
188
+ } catch (error) {
189
+ this.errorHandler.handle(error, 'DatabaseManager.findById');
190
+ return null;
191
+ }
192
+ }
193
+
194
+ async find(tableName, query = {}, options = {}) {
195
+ try {
196
+ const table = this.databases.get(tableName);
197
+ if (!table) {
198
+ throw new Error(`Table not found: ${tableName}`);
199
+ }
200
+
201
+ // Check cache first
202
+ const cacheKey = this.generateCacheKey(tableName, query, options);
203
+ if (this.queryCache.has(cacheKey)) {
204
+ return this.queryCache.get(cacheKey);
205
+ }
206
+
207
+ let results = Array.from(table.values());
208
+
209
+ // Apply filters
210
+ if (Object.keys(query).length > 0) {
211
+ results = this.applyFilters(results, query);
212
+ }
213
+
214
+ // Apply sorting
215
+ if (options.sort) {
216
+ results = this.applySorting(results, options.sort);
217
+ }
218
+
219
+ // Apply pagination
220
+ if (options.limit || options.offset) {
221
+ results = this.applyPagination(results, options);
222
+ }
223
+
224
+ // Cache results
225
+ this.queryCache.set(cacheKey, results);
226
+
227
+ return results;
228
+ } catch (error) {
229
+ this.errorHandler.handle(error, 'DatabaseManager.find');
230
+ return [];
231
+ }
232
+ }
233
+
234
+ async update(tableName, id, updateData) {
235
+ try {
236
+ const table = this.databases.get(tableName);
237
+ if (!table) {
238
+ throw new Error(`Table not found: ${tableName}`);
239
+ }
240
+
241
+ const existingData = table.get(id);
242
+ if (!existingData) {
243
+ throw new Error(`Record not found: ${id}`);
244
+ }
245
+
246
+ const schema = this.schemas.get(tableName);
247
+ const validatedData = this.validateData(updateData, schema.fields, true);
248
+
249
+ // Merge with existing data
250
+ const updatedData = { ...existingData, ...validatedData, updatedAt: new Date() };
251
+
252
+ // Check unique constraints
253
+ await this.checkUniqueConstraints(tableName, updatedData, id);
254
+
255
+ // Update record
256
+ table.set(id, updatedData);
257
+
258
+ // Update indexes
259
+ this.updateIndexes(tableName, updatedData, 'update', existingData);
260
+
261
+ // Clear cache
262
+ this.clearCacheForTable(tableName);
263
+
264
+ this.saveDatabaseData();
265
+
266
+ console.log(`✅ Updated ${tableName}: ${id}`);
267
+ return updatedData;
268
+ } catch (error) {
269
+ this.errorHandler.handle(error, 'DatabaseManager.update');
270
+ throw error;
271
+ }
272
+ }
273
+
274
+ async delete(tableName, id) {
275
+ try {
276
+ const table = this.databases.get(tableName);
277
+ if (!table) {
278
+ throw new Error(`Table not found: ${tableName}`);
279
+ }
280
+
281
+ const existingData = table.get(id);
282
+ if (!existingData) {
283
+ return false;
284
+ }
285
+
286
+ // Remove from table
287
+ table.delete(id);
288
+
289
+ // Update indexes
290
+ this.updateIndexes(tableName, existingData, 'delete');
291
+
292
+ // Clear cache
293
+ this.clearCacheForTable(tableName);
294
+
295
+ this.saveDatabaseData();
296
+
297
+ console.log(`🗑️ Deleted from ${tableName}: ${id}`);
298
+ return true;
299
+ } catch (error) {
300
+ this.errorHandler.handle(error, 'DatabaseManager.delete');
301
+ return false;
302
+ }
303
+ }
304
+
305
+ // ===== ADVANCED QUERIES =====
306
+
307
+ async aggregate(tableName, pipeline) {
308
+ try {
309
+ const table = this.databases.get(tableName);
310
+ if (!table) {
311
+ throw new Error(`Table not found: ${tableName}`);
312
+ }
313
+
314
+ let data = Array.from(table.values());
315
+
316
+ for (const stage of pipeline) {
317
+ data = this.applyAggregationStage(data, stage);
318
+ }
319
+
320
+ return data;
321
+ } catch (error) {
322
+ this.errorHandler.handle(error, 'DatabaseManager.aggregate');
323
+ return [];
324
+ }
325
+ }
326
+
327
+ applyAggregationStage(data, stage) {
328
+ const [operation, params] = Object.entries(stage)[0];
329
+
330
+ switch (operation) {
331
+ case '$match':
332
+ return this.applyFilters(data, params);
333
+
334
+ case '$group':
335
+ return this.applyGrouping(data, params);
336
+
337
+ case '$sort':
338
+ return this.applySorting(data, params);
339
+
340
+ case '$limit':
341
+ return data.slice(0, params);
342
+
343
+ case '$skip':
344
+ return data.slice(params);
345
+
346
+ case '$project':
347
+ return data.map(item => this.applyProjection(item, params));
348
+
349
+ default:
350
+ return data;
351
+ }
352
+ }
353
+
354
+ applyGrouping(data, groupParams) {
355
+ const { _id, ...aggregations } = groupParams;
356
+ const groups = new Map();
357
+
358
+ data.forEach(item => {
359
+ const groupKey = this.evaluateGroupKey(item, _id);
360
+
361
+ if (!groups.has(groupKey)) {
362
+ groups.set(groupKey, []);
363
+ }
364
+
365
+ groups.get(groupKey).push(item);
366
+ });
367
+
368
+ return Array.from(groups.entries()).map(([key, items]) => {
369
+ const result = { _id: key };
370
+
371
+ Object.entries(aggregations).forEach(([field, operation]) => {
372
+ result[field] = this.applyAggregationOperation(items, operation);
373
+ });
374
+
375
+ return result;
376
+ });
377
+ }
378
+
379
+ // ===== TRANSACTIONS =====
380
+
381
+ async transaction(operations) {
382
+ const transactionId = this.generateId();
383
+ const rollbackData = new Map();
384
+
385
+ try {
386
+ this.transactions.set(transactionId, { status: 'active', operations: [] });
387
+
388
+ for (const operation of operations) {
389
+ const { type, tableName, data, id } = operation;
390
+
391
+ // Store rollback data
392
+ if (type === 'update' || type === 'delete') {
393
+ const existing = await this.findById(tableName, id);
394
+ rollbackData.set(`${tableName}:${id}`, existing);
395
+ }
396
+
397
+ // Execute operation
398
+ switch (type) {
399
+ case 'insert':
400
+ await this.insert(tableName, data);
401
+ break;
402
+ case 'update':
403
+ await this.update(tableName, id, data);
404
+ break;
405
+ case 'delete':
406
+ await this.delete(tableName, id);
407
+ break;
408
+ }
409
+
410
+ this.transactions.get(transactionId).operations.push(operation);
411
+ }
412
+
413
+ this.transactions.get(transactionId).status = 'committed';
414
+ console.log(`✅ Transaction committed: ${transactionId}`);
415
+
416
+ return { success: true, transactionId };
417
+ } catch (error) {
418
+ // Rollback
419
+ await this.rollbackTransaction(transactionId, rollbackData);
420
+ this.errorHandler.handle(error, 'DatabaseManager.transaction');
421
+
422
+ return { success: false, error: error.message };
423
+ } finally {
424
+ this.transactions.delete(transactionId);
425
+ }
426
+ }
427
+
428
+ async rollbackTransaction(transactionId, rollbackData) {
429
+ try {
430
+ const transaction = this.transactions.get(transactionId);
431
+ if (!transaction) return;
432
+
433
+ // Reverse operations
434
+ const operations = [...transaction.operations].reverse();
435
+
436
+ for (const operation of operations) {
437
+ const { type, tableName, id } = operation;
438
+ const rollbackKey = `${tableName}:${id}`;
439
+
440
+ switch (type) {
441
+ case 'insert':
442
+ await this.delete(tableName, id);
443
+ break;
444
+ case 'update':
445
+ const originalData = rollbackData.get(rollbackKey);
446
+ if (originalData) {
447
+ const table = this.databases.get(tableName);
448
+ table.set(id, originalData);
449
+ }
450
+ break;
451
+ case 'delete':
452
+ const deletedData = rollbackData.get(rollbackKey);
453
+ if (deletedData) {
454
+ await this.insert(tableName, deletedData);
455
+ }
456
+ break;
457
+ }
458
+ }
459
+
460
+ console.log(`🔄 Transaction rolled back: ${transactionId}`);
461
+ } catch (error) {
462
+ this.errorHandler.handle(error, 'DatabaseManager.rollbackTransaction');
463
+ }
464
+ }
465
+
466
+ // ===== VALIDATION =====
467
+
468
+ validateData(data, schema, isUpdate = false) {
469
+ const validatedData = {};
470
+
471
+ Object.entries(schema).forEach(([fieldName, fieldConfig]) => {
472
+ const value = data[fieldName];
473
+
474
+ // Check required fields
475
+ if (fieldConfig.required && !isUpdate && (value === undefined || value === null)) {
476
+ throw new Error(`Required field missing: ${fieldName}`);
477
+ }
478
+
479
+ // Skip validation if field not provided in update
480
+ if (isUpdate && value === undefined) {
481
+ return;
482
+ }
483
+
484
+ // Apply default values
485
+ if (value === undefined && fieldConfig.default !== undefined) {
486
+ validatedData[fieldName] = typeof fieldConfig.default === 'function'
487
+ ? fieldConfig.default()
488
+ : fieldConfig.default;
489
+ return;
490
+ }
491
+
492
+ // Type validation
493
+ if (value !== undefined && value !== null) {
494
+ validatedData[fieldName] = this.validateFieldType(value, fieldConfig, fieldName);
495
+ }
496
+ });
497
+
498
+ return validatedData;
499
+ }
500
+
501
+ validateFieldType(value, fieldConfig, fieldName) {
502
+ switch (fieldConfig.type) {
503
+ case 'string':
504
+ if (typeof value !== 'string') {
505
+ throw new Error(`Field ${fieldName} must be a string`);
506
+ }
507
+ if (fieldConfig.enum && !fieldConfig.enum.includes(value)) {
508
+ throw new Error(`Field ${fieldName} must be one of: ${fieldConfig.enum.join(', ')}`);
509
+ }
510
+ return value;
511
+
512
+ case 'number':
513
+ const num = Number(value);
514
+ if (isNaN(num)) {
515
+ throw new Error(`Field ${fieldName} must be a number`);
516
+ }
517
+ return num;
518
+
519
+ case 'boolean':
520
+ return Boolean(value);
521
+
522
+ case 'date':
523
+ return value instanceof Date ? value : new Date(value);
524
+
525
+ case 'array':
526
+ return Array.isArray(value) ? value : [value];
527
+
528
+ case 'object':
529
+ return typeof value === 'object' ? value : {};
530
+
531
+ default:
532
+ return value;
533
+ }
534
+ }
535
+
536
+ // ===== UTILITY METHODS =====
537
+
538
+ applyFilters(data, query) {
539
+ return data.filter(item => {
540
+ return Object.entries(query).every(([key, value]) => {
541
+ if (typeof value === 'object' && value !== null) {
542
+ return this.applyOperatorFilter(item[key], value);
543
+ }
544
+ return item[key] === value;
545
+ });
546
+ });
547
+ }
548
+
549
+ applyOperatorFilter(fieldValue, operators) {
550
+ return Object.entries(operators).every(([operator, value]) => {
551
+ switch (operator) {
552
+ case '$eq': return fieldValue === value;
553
+ case '$ne': return fieldValue !== value;
554
+ case '$gt': return fieldValue > value;
555
+ case '$gte': return fieldValue >= value;
556
+ case '$lt': return fieldValue < value;
557
+ case '$lte': return fieldValue <= value;
558
+ case '$in': return Array.isArray(value) && value.includes(fieldValue);
559
+ case '$nin': return Array.isArray(value) && !value.includes(fieldValue);
560
+ case '$regex': return new RegExp(value).test(fieldValue);
561
+ case '$exists': return value ? fieldValue !== undefined : fieldValue === undefined;
562
+ default: return true;
563
+ }
564
+ });
565
+ }
566
+
567
+ applySorting(data, sortOptions) {
568
+ return data.sort((a, b) => {
569
+ for (const [field, direction] of Object.entries(sortOptions)) {
570
+ const aVal = a[field];
571
+ const bVal = b[field];
572
+
573
+ if (aVal < bVal) return direction === 1 ? -1 : 1;
574
+ if (aVal > bVal) return direction === 1 ? 1 : -1;
575
+ }
576
+ return 0;
577
+ });
578
+ }
579
+
580
+ applyPagination(data, options) {
581
+ const offset = options.offset || 0;
582
+ const limit = options.limit;
583
+
584
+ if (limit) {
585
+ return data.slice(offset, offset + limit);
586
+ }
587
+
588
+ return data.slice(offset);
589
+ }
590
+
591
+ async checkUniqueConstraints(tableName, data, excludeId = null) {
592
+ const schema = this.schemas.get(tableName);
593
+ const table = this.databases.get(tableName);
594
+
595
+ for (const [fieldName, fieldConfig] of Object.entries(schema.fields)) {
596
+ if (fieldConfig.unique && data[fieldName] !== undefined) {
597
+ for (const [id, record] of table) {
598
+ if (id !== excludeId && record[fieldName] === data[fieldName]) {
599
+ throw new Error(`Duplicate value for unique field ${fieldName}: ${data[fieldName]}`);
600
+ }
601
+ }
602
+ }
603
+ }
604
+ }
605
+
606
+ updateIndexes(tableName, data, operation, oldData = null) {
607
+ const tableIndexes = this.indexes.get(tableName);
608
+ if (!tableIndexes) return;
609
+
610
+ for (const [fieldName, index] of tableIndexes) {
611
+ const value = data[fieldName];
612
+
613
+ switch (operation) {
614
+ case 'insert':
615
+ if (value !== undefined) {
616
+ index.set(value, data.id);
617
+ }
618
+ break;
619
+
620
+ case 'update':
621
+ if (oldData && oldData[fieldName] !== undefined) {
622
+ index.delete(oldData[fieldName]);
623
+ }
624
+ if (value !== undefined) {
625
+ index.set(value, data.id);
626
+ }
627
+ break;
628
+
629
+ case 'delete':
630
+ if (value !== undefined) {
631
+ index.delete(value);
632
+ }
633
+ break;
634
+ }
635
+ }
636
+ }
637
+
638
+ generateId() {
639
+ return `${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
640
+ }
641
+
642
+ generateCacheKey(tableName, query, options) {
643
+ return `${tableName}:${JSON.stringify(query)}:${JSON.stringify(options)}`;
644
+ }
645
+
646
+ clearCacheForTable(tableName) {
647
+ for (const key of this.queryCache.keys()) {
648
+ if (key.startsWith(`${tableName}:`)) {
649
+ this.queryCache.delete(key);
650
+ }
651
+ }
652
+ }
653
+
654
+ cleanupCache() {
655
+ // Remove old cache entries (older than 10 minutes)
656
+ const maxAge = 10 * 60 * 1000;
657
+ const now = Date.now();
658
+
659
+ for (const [key, entry] of this.queryCache) {
660
+ if (entry.timestamp && (now - entry.timestamp) > maxAge) {
661
+ this.queryCache.delete(key);
662
+ }
663
+ }
664
+ }
665
+
666
+ optimizeIndexes() {
667
+ // Rebuild indexes if needed
668
+ for (const [tableName, tableIndexes] of this.indexes) {
669
+ const table = this.databases.get(tableName);
670
+ if (!table) continue;
671
+
672
+ for (const [fieldName, index] of tableIndexes) {
673
+ index.clear();
674
+
675
+ for (const [id, record] of table) {
676
+ const value = record[fieldName];
677
+ if (value !== undefined) {
678
+ index.set(value, id);
679
+ }
680
+ }
681
+ }
682
+ }
683
+ }
684
+
685
+ saveDatabaseData() {
686
+ try {
687
+ const dbData = {
688
+ databases: Object.fromEntries(
689
+ Array.from(this.databases.entries()).map(([name, table]) => [
690
+ name,
691
+ Object.fromEntries(table)
692
+ ])
693
+ ),
694
+ schemas: Object.fromEntries(this.schemas),
695
+ indexes: Object.fromEntries(
696
+ Array.from(this.indexes.entries()).map(([name, tableIndexes]) => [
697
+ name,
698
+ Object.fromEntries(
699
+ Array.from(tableIndexes.entries()).map(([field, index]) => [
700
+ field,
701
+ Object.fromEntries(index)
702
+ ])
703
+ )
704
+ ])
705
+ )
706
+ };
707
+
708
+ this.storage.write.to("database").set("data", dbData);
709
+ } catch (error) {
710
+ this.errorHandler.handle(error, 'DatabaseManager.saveDatabaseData');
711
+ }
712
+ }
713
+
714
+ // ===== PUBLIC API =====
715
+
716
+ getTableStats(tableName) {
717
+ const table = this.databases.get(tableName);
718
+ const schema = this.schemas.get(tableName);
719
+
720
+ if (!table || !schema) return null;
721
+
722
+ return {
723
+ name: tableName,
724
+ recordCount: table.size,
725
+ schema: schema.fields,
726
+ version: schema.version,
727
+ createdAt: schema.createdAt,
728
+ updatedAt: schema.updatedAt
729
+ };
730
+ }
731
+
732
+ getAllTables() {
733
+ return Array.from(this.databases.keys());
734
+ }
735
+
736
+ exportTable(tableName) {
737
+ const table = this.databases.get(tableName);
738
+ if (!table) return null;
739
+
740
+ return {
741
+ tableName,
742
+ schema: this.schemas.get(tableName),
743
+ data: Array.from(table.values()),
744
+ exportedAt: new Date()
745
+ };
746
+ }
747
+
748
+ async importTable(tableData) {
749
+ const { tableName, schema, data } = tableData;
750
+
751
+ // Create schema
752
+ this.createSchema(tableName, schema.fields);
753
+
754
+ // Import data
755
+ const table = this.databases.get(tableName);
756
+ table.clear();
757
+
758
+ for (const record of data) {
759
+ table.set(record.id, record);
760
+ this.updateIndexes(tableName, record, 'insert');
761
+ }
762
+
763
+ this.saveDatabaseData();
764
+ console.log(`📥 Imported ${data.length} records into ${tableName}`);
765
+ }
766
+ }