jexidb 2.0.3 → 2.1.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.
Files changed (67) hide show
  1. package/.babelrc +13 -0
  2. package/.gitattributes +2 -0
  3. package/CHANGELOG.md +132 -101
  4. package/LICENSE +21 -21
  5. package/README.md +301 -639
  6. package/babel.config.json +5 -0
  7. package/dist/Database.cjs +3896 -0
  8. package/docs/API.md +1051 -390
  9. package/docs/EXAMPLES.md +701 -177
  10. package/docs/README.md +194 -184
  11. package/examples/iterate-usage-example.js +157 -0
  12. package/examples/simple-iterate-example.js +115 -0
  13. package/jest.config.js +24 -0
  14. package/package.json +63 -54
  15. package/scripts/README.md +47 -0
  16. package/scripts/clean-test-files.js +75 -0
  17. package/scripts/prepare.js +31 -0
  18. package/scripts/run-tests.js +80 -0
  19. package/src/Database.mjs +4130 -0
  20. package/src/FileHandler.mjs +1101 -0
  21. package/src/OperationQueue.mjs +279 -0
  22. package/src/SchemaManager.mjs +268 -0
  23. package/src/Serializer.mjs +511 -0
  24. package/src/managers/ConcurrencyManager.mjs +257 -0
  25. package/src/managers/IndexManager.mjs +1403 -0
  26. package/src/managers/QueryManager.mjs +1273 -0
  27. package/src/managers/StatisticsManager.mjs +262 -0
  28. package/src/managers/StreamingProcessor.mjs +429 -0
  29. package/src/managers/TermManager.mjs +278 -0
  30. package/test/$not-operator-with-and.test.js +282 -0
  31. package/test/README.md +8 -0
  32. package/test/close-init-cycle.test.js +256 -0
  33. package/test/critical-bugs-fixes.test.js +1069 -0
  34. package/test/index-persistence.test.js +306 -0
  35. package/test/index-serialization.test.js +314 -0
  36. package/test/indexed-query-mode.test.js +360 -0
  37. package/test/iterate-method.test.js +272 -0
  38. package/test/query-operators.test.js +238 -0
  39. package/test/regex-array-fields.test.js +129 -0
  40. package/test/score-method.test.js +238 -0
  41. package/test/setup.js +17 -0
  42. package/test/term-mapping-minimal.test.js +154 -0
  43. package/test/term-mapping-simple.test.js +257 -0
  44. package/test/term-mapping.test.js +514 -0
  45. package/test/writebuffer-flush-resilience.test.js +204 -0
  46. package/dist/FileHandler.js +0 -688
  47. package/dist/IndexManager.js +0 -353
  48. package/dist/IntegrityChecker.js +0 -364
  49. package/dist/JSONLDatabase.js +0 -1333
  50. package/dist/index.js +0 -617
  51. package/docs/MIGRATION.md +0 -295
  52. package/examples/auto-save-example.js +0 -158
  53. package/examples/cjs-usage.cjs +0 -82
  54. package/examples/close-vs-delete-example.js +0 -71
  55. package/examples/esm-usage.js +0 -113
  56. package/examples/example-columns.idx.jdb +0 -0
  57. package/examples/example-columns.jdb +0 -9
  58. package/examples/example-options.idx.jdb +0 -0
  59. package/examples/example-options.jdb +0 -0
  60. package/examples/example-users.idx.jdb +0 -0
  61. package/examples/example-users.jdb +0 -5
  62. package/examples/simple-test.js +0 -55
  63. package/src/FileHandler.js +0 -674
  64. package/src/IndexManager.js +0 -363
  65. package/src/IntegrityChecker.js +0 -379
  66. package/src/JSONLDatabase.js +0 -1391
  67. package/src/index.js +0 -608
package/docs/MIGRATION.md DELETED
@@ -1,295 +0,0 @@
1
- # JexiDB Migration Guide
2
-
3
- ## Migrating from Other Databases
4
-
5
- ### From JSON Files
6
-
7
- ```javascript
8
- const fs = require('fs');
9
- const { Database } = require('jexidb');
10
-
11
- async function migrateFromJSON(jsonFilePath, dbPath) {
12
- // Read JSON file
13
- const jsonData = JSON.parse(fs.readFileSync(jsonFilePath, 'utf8'));
14
-
15
- // Create database
16
- const db = new Database(dbPath);
17
- await db.init();
18
-
19
- // Insert data
20
- if (Array.isArray(jsonData)) {
21
- await db.insertMany(jsonData);
22
- } else {
23
- await db.insert(jsonData);
24
- }
25
-
26
- await db.save();
27
- await db.destroy();
28
-
29
- console.log('Migration completed successfully');
30
- }
31
-
32
- // Usage
33
- migrateFromJSON('./old-data.json', './new-database.jsonl');
34
- ```
35
-
36
- ### From SQLite
37
-
38
- ```javascript
39
- const sqlite3 = require('sqlite3');
40
- const { Database } = require('jexidb');
41
-
42
- async function migrateFromSQLite(sqlitePath, dbPath) {
43
- const db = new sqlite3.Database(sqlitePath);
44
- const database = new Database(dbPath);
45
- await database.init();
46
-
47
- return new Promise((resolve, reject) => {
48
- db.all('SELECT * FROM users', async (err, rows) => {
49
- if (err) {
50
- reject(err);
51
- return;
52
- }
53
-
54
- try {
55
- await database.insertMany(rows);
56
- await database.save();
57
- await database.destroy();
58
- console.log('Migration completed successfully');
59
- resolve();
60
- } catch (error) {
61
- reject(error);
62
- }
63
- });
64
- });
65
- }
66
- ```
67
-
68
- ### From MongoDB (Local)
69
-
70
- ```javascript
71
- const { MongoClient } = require('mongodb');
72
- const { Database } = require('jexidb');
73
-
74
- async function migrateFromMongoDB(mongoUri, collectionName, dbPath) {
75
- const client = new MongoClient(mongoUri);
76
- await client.connect();
77
-
78
- const db = client.db();
79
- const collection = db.collection(collectionName);
80
-
81
- const database = new Database(dbPath);
82
- await database.init();
83
-
84
- const cursor = collection.find({});
85
- const batch = [];
86
-
87
- while (await cursor.hasNext()) {
88
- const doc = await cursor.next();
89
- batch.push(doc);
90
-
91
- if (batch.length >= 1000) {
92
- await database.insertMany(batch);
93
- batch.length = 0;
94
- }
95
- }
96
-
97
- if (batch.length > 0) {
98
- await database.insertMany(batch);
99
- }
100
-
101
- await database.save();
102
- await database.destroy();
103
- await client.close();
104
-
105
- console.log('Migration completed successfully');
106
- }
107
- ```
108
-
109
- ## Data Transformation
110
-
111
- ### Converting Data Types
112
-
113
- ```javascript
114
- function transformData(oldData) {
115
- return oldData.map(record => ({
116
- id: record._id || record.id,
117
- name: record.name || record.fullName,
118
- email: record.email?.toLowerCase(),
119
- age: parseInt(record.age) || 0,
120
- metadata: {
121
- created: record.createdAt || new Date().toISOString(),
122
- updated: record.updatedAt || new Date().toISOString()
123
- }
124
- }));
125
- }
126
-
127
- // Usage
128
- const transformedData = transformData(oldData);
129
- await db.insertMany(transformedData);
130
- ```
131
-
132
- ### Handling Different Schemas
133
-
134
- ```javascript
135
- function normalizeSchema(records) {
136
- return records.map(record => {
137
- const normalized = {
138
- id: record.id || record._id || record.userId,
139
- name: record.name || record.fullName || record.userName,
140
- email: record.email || record.emailAddress,
141
- age: record.age || record.userAge || 0
142
- };
143
-
144
- // Add optional fields
145
- if (record.metadata) {
146
- normalized.metadata = record.metadata;
147
- }
148
-
149
- if (record.tags) {
150
- normalized.tags = Array.isArray(record.tags) ? record.tags : [record.tags];
151
- }
152
-
153
- return normalized;
154
- });
155
- }
156
- ```
157
-
158
- ## Index Migration
159
-
160
- ### Creating Indexes for Existing Data
161
-
162
- ```javascript
163
- async function createIndexesForExistingData(dbPath) {
164
- const db = new Database(dbPath, {
165
- indexes: {
166
- id: true,
167
- email: true,
168
- 'metadata.created': true
169
- }
170
- });
171
-
172
- await db.init();
173
-
174
- // Rebuild indexes for existing data
175
- await db.rebuildIndexes({ verbose: true });
176
-
177
- await db.save();
178
- await db.destroy();
179
-
180
- console.log('Indexes created successfully');
181
- }
182
- ```
183
-
184
- ## Validation and Verification
185
-
186
- ### Verify Migration Success
187
-
188
- ```javascript
189
- async function verifyMigration(originalData, dbPath) {
190
- const db = new Database(dbPath);
191
- await db.init();
192
-
193
- // Check record count
194
- const count = await db.count();
195
- console.log(`Original: ${originalData.length}, Migrated: ${count}`);
196
-
197
- // Check data integrity
198
- const integrity = await db.validateIntegrity({ verbose: true });
199
- console.log('Integrity check:', integrity.isValid ? 'PASSED' : 'FAILED');
200
-
201
- // Sample verification
202
- const sample = await db.find({}, { limit: 5 });
203
- console.log('Sample records:', sample);
204
-
205
- await db.destroy();
206
- }
207
- ```
208
-
209
- ## Performance Considerations
210
-
211
- ### Large Dataset Migration
212
-
213
- ```javascript
214
- async function migrateLargeDataset(data, dbPath, batchSize = 1000) {
215
- const db = new Database(dbPath, {
216
- autoSave: false, // Disable auto-save for better performance
217
- backgroundMaintenance: false
218
- });
219
-
220
- await db.init();
221
-
222
- for (let i = 0; i < data.length; i += batchSize) {
223
- const batch = data.slice(i, i + batchSize);
224
- await db.insertMany(batch);
225
-
226
- // Progress indicator
227
- if (i % 10000 === 0) {
228
- console.log(`Migrated ${i} records...`);
229
- }
230
- }
231
-
232
- await db.save();
233
- await db.destroy();
234
-
235
- console.log('Large dataset migration completed');
236
- }
237
- ```
238
-
239
- ## Rollback Strategy
240
-
241
- ### Backup Before Migration
242
-
243
- ```javascript
244
- const fs = require('fs');
245
-
246
- async function backupBeforeMigration(originalPath) {
247
- const backupPath = `${originalPath}.backup.${Date.now()}`;
248
- await fs.copyFile(originalPath, backupPath);
249
- console.log(`Backup created: ${backupPath}`);
250
- return backupPath;
251
- }
252
-
253
- async function rollbackMigration(backupPath, currentPath) {
254
- await fs.copyFile(backupPath, currentPath);
255
- console.log('Rollback completed');
256
- }
257
- ```
258
-
259
- ## Migration Checklist
260
-
261
- - [ ] **Backup original data**
262
- - [ ] **Test migration with sample data**
263
- - [ ] **Verify data integrity**
264
- - [ ] **Check performance characteristics**
265
- - [ ] **Update application code**
266
- - [ ] **Test application functionality**
267
- - [ ] **Monitor for issues**
268
- - [ ] **Clean up old data** (after verification)
269
-
270
- ## Common Migration Issues
271
-
272
- ### 1. Data Type Mismatches
273
-
274
- **Issue:** Different data types between source and target
275
- **Solution:** Implement data transformation functions
276
-
277
- ### 2. Missing Required Fields
278
-
279
- **Issue:** Target schema requires fields not in source
280
- **Solution:** Provide default values or skip records
281
-
282
- ### 3. Duplicate Records
283
-
284
- **Issue:** Multiple records with same ID
285
- **Solution:** Use upsert operations or deduplication
286
-
287
- ### 4. Performance Issues
288
-
289
- **Issue:** Migration taking too long
290
- **Solution:** Use batch operations and disable auto-save
291
-
292
- ### 5. Memory Issues
293
-
294
- **Issue:** Running out of memory during migration
295
- **Solution:** Process data in smaller batches
@@ -1,158 +0,0 @@
1
- /**
2
- * Auto-Save Example - Demonstrates JexiDB's intelligent auto-save features
3
- *
4
- * This example shows:
5
- * - Auto-save based on record count threshold
6
- * - Auto-save based on time interval
7
- * - Event handling for buffer operations
8
- * - Buffer status monitoring
9
- * - Performance configuration
10
- */
11
-
12
- import Database from '../src/index.js';
13
- import path from 'path';
14
-
15
- async function autoSaveExample() {
16
- console.log('🚀 Starting Auto-Save Example...\n');
17
-
18
- // Create database with intelligent auto-save configuration
19
- const dbPath = path.join(process.cwd(), 'auto-save-example.jdb');
20
- const db = new Database(dbPath, {
21
- indexes: { category: 'string', priority: 'number' },
22
- create: true,
23
- clear: true,
24
-
25
- // Auto-save configuration
26
- autoSave: true,
27
- autoSaveThreshold: 10, // Flush every 10 records
28
- autoSaveInterval: 3000, // Flush every 3 seconds
29
- forceSaveOnClose: true,
30
-
31
- // Performance configuration
32
- batchSize: 20,
33
- adaptiveBatchSize: true,
34
- minBatchSize: 5,
35
- maxBatchSize: 50
36
- });
37
-
38
- // Set up event listeners
39
- db.on('buffer-flush', (count) => {
40
- console.log(`📤 Buffer flushed: ${count} records`);
41
- });
42
-
43
- db.on('buffer-full', () => {
44
- console.log('⚠️ Buffer reached threshold, flushing...');
45
- });
46
-
47
- db.on('auto-save-timer', () => {
48
- console.log('⏰ Auto-save timer triggered');
49
- });
50
-
51
- db.on('save-complete', () => {
52
- console.log('✅ Save completed');
53
- });
54
-
55
- db.on('close-save-complete', () => {
56
- console.log('🔒 Database closed with final save');
57
- });
58
-
59
- db.on('performance-configured', (config) => {
60
- console.log('⚙️ Performance reconfigured:', config);
61
- });
62
-
63
- await db.init();
64
- console.log('✅ Database initialized\n');
65
-
66
- // Show initial buffer status
67
- console.log('📊 Initial buffer status:');
68
- console.log(db.getBufferStatus());
69
- console.log('');
70
-
71
- // Insert records to demonstrate auto-save
72
- console.log('📝 Inserting records...');
73
-
74
- for (let i = 1; i <= 25; i++) {
75
- const record = {
76
- id: `item-${i}`,
77
- name: `Item ${i}`,
78
- category: i % 3 === 0 ? 'high' : i % 2 === 0 ? 'medium' : 'low',
79
- priority: i % 5 + 1,
80
- description: `This is item number ${i}`
81
- };
82
-
83
- await db.insert(record);
84
- console.log(` Inserted: ${record.name} (${record.category} priority)`);
85
-
86
- // Show buffer status every 5 records
87
- if (i % 5 === 0) {
88
- const status = db.getBufferStatus();
89
- console.log(` Buffer: ${status.pendingCount}/${status.bufferSize} records pending`);
90
- }
91
-
92
- // Small delay to demonstrate time-based auto-save
93
- await new Promise(resolve => setTimeout(resolve, 500));
94
- }
95
-
96
- console.log('\n📊 Final buffer status:');
97
- console.log(db.getBufferStatus());
98
- console.log('');
99
-
100
- // Demonstrate performance configuration
101
- console.log('⚙️ Reconfiguring performance...');
102
- db.configurePerformance({
103
- batchSize: 15,
104
- autoSaveThreshold: 8,
105
- autoSaveInterval: 2000
106
- });
107
-
108
- console.log('📊 New performance config:');
109
- console.log(db.getPerformanceConfig());
110
- console.log('');
111
-
112
- // Insert more records with new configuration
113
- console.log('📝 Inserting more records with new config...');
114
-
115
- for (let i = 26; i <= 35; i++) {
116
- const record = {
117
- id: `item-${i}`,
118
- name: `Item ${i}`,
119
- category: 'new',
120
- priority: 10,
121
- description: `New item ${i}`
122
- };
123
-
124
- await db.insert(record);
125
- console.log(` Inserted: ${record.name}`);
126
-
127
- await new Promise(resolve => setTimeout(resolve, 300));
128
- }
129
-
130
- // Query the database
131
- console.log('\n🔍 Querying database...');
132
- const highPriority = await db.find({ priority: { '>=': 8 } });
133
- console.log(`Found ${highPriority.length} high priority items`);
134
-
135
- const categories = await db.find({ category: 'high' });
136
- console.log(`Found ${categories.length} high category items`);
137
-
138
- // Show final statistics
139
- console.log('\n📈 Final database statistics:');
140
- const stats = db.stats;
141
- console.log(`Total records: ${stats.recordCount}`);
142
- console.log(`Buffer size: ${stats.insertionBufferSize}`);
143
- console.log(`Auto-save enabled: ${stats.autoSave.enabled}`);
144
- console.log(`Last flush: ${stats.autoSave.lastFlush ? new Date(stats.autoSave.lastFlush).toLocaleTimeString() : 'Never'}`);
145
-
146
- // Close database (will trigger final save)
147
- console.log('\n🔒 Closing database...');
148
- await db.close();
149
-
150
- // Clean up
151
- await db.destroy();
152
- console.log('🧹 Cleanup completed');
153
-
154
- console.log('\n✅ Auto-Save Example completed successfully!');
155
- }
156
-
157
- // Run the example
158
- autoSaveExample().catch(console.error);
@@ -1,82 +0,0 @@
1
- // Example: Using Database with CommonJS
2
- // This file demonstrates how to use the library in CommonJS environments
3
-
4
- const Database = require('../dist/index.js').default;
5
- const { utils, OPERATORS } = require('../dist/index.js');
6
-
7
- async function exampleCJS() {
8
- console.log('🚀 Database CommonJS Example');
9
- console.log('========================\n');
10
-
11
- // Create a new database
12
- const db = new Database('./example-cjs.jsonl', {
13
- indexes: {
14
- id: 'number',
15
- email: 'string',
16
- age: 'number'
17
- }
18
- });
19
-
20
- try {
21
- // Initialize the database
22
- await db.init();
23
- console.log('✅ Database initialized');
24
-
25
- // Insert some records
26
- const user1 = await db.insert({
27
- id: 1,
28
- name: 'John Doe',
29
- email: 'john@example.com',
30
- age: 30,
31
- city: 'New York'
32
- });
33
-
34
- const user2 = await db.insert({
35
- id: 2,
36
- name: 'Jane Smith',
37
- email: 'jane@example.com',
38
- age: 25,
39
- city: 'Los Angeles'
40
- });
41
-
42
- console.log('✅ Records inserted:', user1.name, user2.name);
43
-
44
- // Find records using different queries
45
- const allUsers = await db.find({});
46
- console.log('📋 All users:', allUsers.length);
47
-
48
- const youngUsers = await db.find({ age: { '<': 30 } });
49
- console.log('👶 Young users:', youngUsers.length);
50
-
51
- const johnUser = await db.find({ email: 'john@example.com' });
52
- console.log('👤 John user:', johnUser[0]?.name);
53
-
54
- // Update a record
55
- const updateResult = await db.update(
56
- { id: 1 },
57
- { age: 31, city: 'Boston' }
58
- );
59
- console.log('🔄 Updated records:', updateResult.updatedCount);
60
-
61
- // Use utility functions
62
- const stats = db.stats;
63
- console.log('📊 Database stats:', {
64
- recordCount: stats.recordCount,
65
- indexedFields: stats.indexedFields
66
- });
67
-
68
- // Save the database
69
- await db.save();
70
- console.log('💾 Database saved');
71
-
72
- // Close the database
73
- await db.close();
74
- console.log('🔒 Database closed');
75
-
76
- } catch (error) {
77
- console.error('❌ Error:', error.message);
78
- }
79
- }
80
-
81
- // Run the example
82
- exampleCJS().catch(console.error);
@@ -1,71 +0,0 @@
1
- import Database from '../src/index.js';
2
-
3
- async function demonstrateCloseVsDelete() {
4
- console.log('🔍 Demonstrating close() vs destroy() vs deleteDatabase()\n');
5
-
6
- // Example 1: close() - Fecha instância, mantém arquivo
7
- console.log('📁 Example 1: close() - Closes instance, keeps file');
8
- const db1 = new Database('./example-close.jdb', { indexes: { id: 'number' } });
9
- await db1.init();
10
- await db1.insert({ id: 1, name: 'John' });
11
- await db1.insert({ id: 2, name: 'Jane' });
12
-
13
- console.log(' Records before close:', await db1.count());
14
- await db1.close(); // Fecha instância, mantém arquivo
15
- console.log(' ✅ Instance closed, file preserved\n');
16
-
17
- // Reopen the same file
18
- const db1Reopened = new Database('./example-close.jdb', { indexes: { id: 'number' } });
19
- await db1Reopened.init();
20
- console.log(' Records after reopening:', await db1Reopened.count());
21
- await db1Reopened.close();
22
- console.log(' ✅ Same data preserved\n');
23
-
24
- // Example 2: destroy() - Equivalente a close()
25
- console.log('📁 Example 2: destroy() - Equivalent to close()');
26
- const db2 = new Database('./example-destroy.jdb', { indexes: { id: 'number' } });
27
- await db2.init();
28
- await db2.insert({ id: 1, name: 'Alice' });
29
- await db2.insert({ id: 2, name: 'Bob' });
30
-
31
- console.log(' Records before destroy:', await db2.count());
32
- await db2.destroy(); // Equivalente a close()
33
- console.log(' ✅ Instance destroyed, file preserved\n');
34
-
35
- // Reopen the same file
36
- const db2Reopened = new Database('./example-destroy.jdb', { indexes: { id: 'number' } });
37
- await db2Reopened.init();
38
- console.log(' Records after reopening:', await db2Reopened.count());
39
- await db2Reopened.close();
40
- console.log(' ✅ Same data preserved\n');
41
-
42
- // Example 3: deleteDatabase() - Remove arquivo físico
43
- console.log('🗑️ Example 3: deleteDatabase() - Removes physical file');
44
- const db3 = new Database('./example-delete.jdb', { indexes: { id: 'number' } });
45
- await db3.init();
46
- await db3.insert({ id: 1, name: 'Charlie' });
47
- await db3.insert({ id: 2, name: 'Diana' });
48
-
49
- console.log(' Records before delete:', await db3.count());
50
-
51
- // Delete database file permanently
52
- await db3.deleteDatabase();
53
- console.log(' ✅ Database file deleted\n');
54
-
55
- // Try to reopen - should fail
56
- try {
57
- const db3Reopened = new Database('./example-delete.jdb', { indexes: { id: 'number' } });
58
- await db3Reopened.init();
59
- } catch (error) {
60
- console.log(' ❌ Cannot reopen (expected):', error.message);
61
- }
62
-
63
- console.log('\n📋 Summary:');
64
- console.log(' • close() - Closes instance, keeps file');
65
- console.log(' • destroy() - Equivalent to close()');
66
- console.log(' • deleteDatabase() - Permanently deletes database file');
67
- console.log(' • removeDatabase() - Alias for deleteDatabase()');
68
- }
69
-
70
- // Run the demonstration
71
- demonstrateCloseVsDelete().catch(console.error);