jexidb 1.1.0 → 2.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/LICENSE +2 -2
- package/README.md +556 -128
- package/dist/FileHandler.js +688 -0
- package/dist/IndexManager.js +353 -0
- package/dist/IntegrityChecker.js +364 -0
- package/dist/JSONLDatabase.js +1132 -0
- package/dist/index.js +598 -0
- package/package.json +65 -59
- package/src/FileHandler.js +674 -0
- package/src/IndexManager.js +363 -0
- package/src/IntegrityChecker.js +379 -0
- package/src/JSONLDatabase.js +1189 -0
- package/src/index.js +594 -0
- package/.gitattributes +0 -2
- package/babel.config.json +0 -5
- package/dist/Database.cjs +0 -1161
- package/src/Database.mjs +0 -376
- package/src/FileHandler.mjs +0 -202
- package/src/IndexManager.mjs +0 -230
- package/src/Serializer.mjs +0 -120
- package/test/README.md +0 -13
- package/test/test-json-compressed.jdb +0 -0
- package/test/test-json.jdb +0 -0
- package/test/test-v8-compressed.jdb +0 -0
- package/test/test-v8.jdb +0 -0
- package/test/test.mjs +0 -173
package/README.md
CHANGED
|
@@ -1,128 +1,556 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
await db.
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
```javascript
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
1
|
+
# JexiDB - Pure JavaScript JSONL Database
|
|
2
|
+
|
|
3
|
+
**JexiDB** is a lightweight, high-performance JSONL (JSON Lines) database for Node.js built in pure JavaScript that provides fast data storage and retrieval with persistent indexing.
|
|
4
|
+
|
|
5
|
+
## 🚀 Features
|
|
6
|
+
|
|
7
|
+
- **JSONL Architecture**: Each database is a single JSONL file for simplicity and portability
|
|
8
|
+
- **Persistent Indexes**: Fast searches with disk-persisted indexes that don't need rebuilding
|
|
9
|
+
- **Point Reading**: Efficient memory usage - only reads necessary data
|
|
10
|
+
- **Rich Query API**: Support for complex queries with operators, sorting, and pagination
|
|
11
|
+
- **Automatic Integrity Validation**: Built-in data integrity checking and repair
|
|
12
|
+
- **Event System**: Real-time notifications for database operations
|
|
13
|
+
- **Legacy Compatibility**: Automatic migration from JexiDB 1.x databases
|
|
14
|
+
- **Pure JavaScript**: No native dependencies, works everywhere, easy to deploy
|
|
15
|
+
|
|
16
|
+
## 📦 Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install jexidb
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## 🚀 Quick Start
|
|
23
|
+
|
|
24
|
+
```javascript
|
|
25
|
+
// import { Database } from 'jexidb'
|
|
26
|
+
const { Database } = require('jexidb');
|
|
27
|
+
|
|
28
|
+
// Create database with indexes (supports both .jdb and .jsonl)
|
|
29
|
+
const db = new Database('./users.jdb', {
|
|
30
|
+
indexes: {
|
|
31
|
+
id: 'number',
|
|
32
|
+
email: 'string',
|
|
33
|
+
age: 'number'
|
|
34
|
+
},
|
|
35
|
+
autoSave: true,
|
|
36
|
+
validateOnInit: true
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Initialize
|
|
40
|
+
await db.init();
|
|
41
|
+
|
|
42
|
+
// Event listeners
|
|
43
|
+
db.on('insert', (record, index) => console.log(`Record inserted at index ${index}`));
|
|
44
|
+
db.on('update', (record, index) => console.log(`Record updated at index ${index}`));
|
|
45
|
+
db.on('save', () => console.log('Changes saved'));
|
|
46
|
+
|
|
47
|
+
// Insert data
|
|
48
|
+
const user = await db.insert({
|
|
49
|
+
id: 1,
|
|
50
|
+
name: 'John Doe',
|
|
51
|
+
email: 'john@example.com',
|
|
52
|
+
age: 30
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Search data (both methods work)
|
|
56
|
+
const john = await db.findOne({ id: 1 });
|
|
57
|
+
const youngUsers = await db.find({ age: { '<': 30 } });
|
|
58
|
+
|
|
59
|
+
// JexiDB 1.x compatible query
|
|
60
|
+
const results = await db.query({ name: 'john doe' }, { caseInsensitive: true });
|
|
61
|
+
|
|
62
|
+
// Update data
|
|
63
|
+
await db.update({ id: 1 }, { age: 31 });
|
|
64
|
+
|
|
65
|
+
// Remove data
|
|
66
|
+
await db.delete({ id: 1 });
|
|
67
|
+
|
|
68
|
+
// Save changes
|
|
69
|
+
await db.save();
|
|
70
|
+
|
|
71
|
+
// Destroy database
|
|
72
|
+
await db.destroy();
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## 📚 API Reference
|
|
76
|
+
|
|
77
|
+
### Constructor
|
|
78
|
+
|
|
79
|
+
```javascript
|
|
80
|
+
const db = new Database(filePath, options);
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Parameters:**
|
|
84
|
+
- `filePath` (string): Path to the main file (.jdb)
|
|
85
|
+
- `options` (object): Configuration options
|
|
86
|
+
|
|
87
|
+
**Options:**
|
|
88
|
+
```javascript
|
|
89
|
+
{
|
|
90
|
+
indexes: {}, // Indexes for fields
|
|
91
|
+
markDeleted: true, // Mark as deleted instead of physically removing
|
|
92
|
+
autoSave: true, // Automatically save after operations
|
|
93
|
+
validateOnInit: false // Validate integrity on initialization
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Main Methods
|
|
98
|
+
|
|
99
|
+
#### `init()`
|
|
100
|
+
Initializes the database.
|
|
101
|
+
|
|
102
|
+
#### `insert(data)`
|
|
103
|
+
Inserts a record.
|
|
104
|
+
|
|
105
|
+
#### `insertMany(dataArray)`
|
|
106
|
+
Inserts multiple records.
|
|
107
|
+
|
|
108
|
+
#### `find(criteria, options)` / `query(criteria, options)`
|
|
109
|
+
Searches records with optional criteria. Both methods work identically.
|
|
110
|
+
|
|
111
|
+
**Supported operators:**
|
|
112
|
+
```javascript
|
|
113
|
+
// Comparison
|
|
114
|
+
{ age: { '>': 25 } }
|
|
115
|
+
{ age: { '>=': 25 } }
|
|
116
|
+
{ age: { '<': 30 } }
|
|
117
|
+
{ age: { '<=': 30 } }
|
|
118
|
+
{ age: { '!=': 25 } }
|
|
119
|
+
|
|
120
|
+
// Arrays
|
|
121
|
+
{ tags: { in: ['developer', 'admin'] } }
|
|
122
|
+
{ tags: { nin: ['designer'] } }
|
|
123
|
+
|
|
124
|
+
// Strings
|
|
125
|
+
{ name: { regex: 'john' } }
|
|
126
|
+
{ name: { contains: 'john' } }
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
**Options:**
|
|
130
|
+
```javascript
|
|
131
|
+
{
|
|
132
|
+
limit: 10, // Limit results
|
|
133
|
+
skip: 5, // Skip records
|
|
134
|
+
sort: { age: 1 }, // Sorting (1 = ascending, -1 = descending)
|
|
135
|
+
caseInsensitive: false, // Case insensitive matching (query() only)
|
|
136
|
+
matchAny: false // OR instead of AND
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
**JexiDB 1.x Compatibility:**
|
|
141
|
+
```javascript
|
|
142
|
+
// Both work identically
|
|
143
|
+
const results1 = await db.find({ name: 'John' });
|
|
144
|
+
const results2 = await db.query({ name: 'John' });
|
|
145
|
+
|
|
146
|
+
// Case insensitive query (JexiDB 1.x style)
|
|
147
|
+
const results = await db.query({ name: 'john' }, { caseInsensitive: true });
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
#### `findOne(criteria, options)`
|
|
151
|
+
Searches for one record.
|
|
152
|
+
|
|
153
|
+
#### `update(criteria, updateData, options)`
|
|
154
|
+
Updates records.
|
|
155
|
+
|
|
156
|
+
#### `delete(criteria, options)`
|
|
157
|
+
Removes records.
|
|
158
|
+
|
|
159
|
+
**Delete options:**
|
|
160
|
+
```javascript
|
|
161
|
+
{
|
|
162
|
+
physical: false, // Physically remove instead of marking as deleted
|
|
163
|
+
limit: 1 // Limit number of records to delete
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
#### `count(criteria, options)`
|
|
168
|
+
Counts records.
|
|
169
|
+
|
|
170
|
+
#### `save()`
|
|
171
|
+
Saves pending changes.
|
|
172
|
+
|
|
173
|
+
#### `destroy()`
|
|
174
|
+
Destroys the database.
|
|
175
|
+
|
|
176
|
+
#### `validateIntegrity(options)`
|
|
177
|
+
Validates database integrity.
|
|
178
|
+
|
|
179
|
+
#### `rebuildIndexes(options)`
|
|
180
|
+
Rebuilds indexes.
|
|
181
|
+
|
|
182
|
+
#### `getStats()`
|
|
183
|
+
Gets detailed statistics.
|
|
184
|
+
|
|
185
|
+
### `walk()` Iterator
|
|
186
|
+
|
|
187
|
+
For traversing large volumes of data:
|
|
188
|
+
|
|
189
|
+
```javascript
|
|
190
|
+
// Traverse all records
|
|
191
|
+
for await (const record of db.walk()) {
|
|
192
|
+
console.log(record.name);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// With options
|
|
196
|
+
for await (const record of db.walk({
|
|
197
|
+
limit: 100,
|
|
198
|
+
skip: 50,
|
|
199
|
+
includeDeleted: false
|
|
200
|
+
})) {
|
|
201
|
+
console.log(record.name);
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Properties
|
|
206
|
+
|
|
207
|
+
#### `length`
|
|
208
|
+
Total number of records.
|
|
209
|
+
|
|
210
|
+
#### `indexStats`
|
|
211
|
+
Index statistics.
|
|
212
|
+
|
|
213
|
+
### Events
|
|
214
|
+
|
|
215
|
+
```javascript
|
|
216
|
+
db.on('init', () => console.log('Database initialized'));
|
|
217
|
+
db.on('insert', (record, index) => console.log('Record inserted'));
|
|
218
|
+
db.on('update', (record, index) => console.log('Record updated'));
|
|
219
|
+
db.on('delete', (record, index) => console.log('Record deleted'));
|
|
220
|
+
db.on('before-save', () => console.log('Before save'));
|
|
221
|
+
db.on('save', () => console.log('Save completed'));
|
|
222
|
+
db.on('destroy', () => console.log('Database destroyed'));
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## 📁 File Structure
|
|
226
|
+
|
|
227
|
+
For each database, 2 files are created:
|
|
228
|
+
|
|
229
|
+
```
|
|
230
|
+
users.jdb # Data (JSON Lines format)
|
|
231
|
+
users.idx.jdb # Compressed persistent indexes
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### 🔄 Legacy Compatibility
|
|
235
|
+
|
|
236
|
+
JexiDB automatically detects and migrates JexiDB 1.x files:
|
|
237
|
+
|
|
238
|
+
**Legacy Format (JexiDB 1.x):**
|
|
239
|
+
```
|
|
240
|
+
users.jsonl # Data + indexes + offsets in single file
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
**New Format (JexiDB):**
|
|
244
|
+
```
|
|
245
|
+
users.jdb # Data + offsets
|
|
246
|
+
users.idx.jdb # Compressed indexes
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
### 🚀 Persistent Indexes
|
|
252
|
+
|
|
253
|
+
JexiDB implements **persistent indexes** that are saved to disk:
|
|
254
|
+
|
|
255
|
+
**Benefits:**
|
|
256
|
+
- **Fast startup**: No need to read all data to rebuild indexes
|
|
257
|
+
- **Scalable**: Works well with large databases (100k+ records)
|
|
258
|
+
- **Consistent**: Indexes synchronized with data
|
|
259
|
+
- **Portable**: Only 2 files to manage
|
|
260
|
+
- **Compressed**: Indexes compressed using gzip
|
|
261
|
+
|
|
262
|
+
**🔧 How it works:**
|
|
263
|
+
1. **First open**: Indexes are built by reading data
|
|
264
|
+
2. **Save**: Indexes are persisted and compressed to `users.idx.jdb`
|
|
265
|
+
3. **Reopen**: Indexes are loaded instantly from disk
|
|
266
|
+
4. **Fallback**: If index file is corrupted, rebuilds automatically
|
|
267
|
+
|
|
268
|
+
### JSONL Format
|
|
269
|
+
|
|
270
|
+
Each line is a valid JSON record:
|
|
271
|
+
|
|
272
|
+
```json
|
|
273
|
+
{"id":1,"name":"John","email":"john@example.com","_created":"2024-12-19T10:00:00.000Z","_updated":"2024-12-19T10:00:00.000Z"}
|
|
274
|
+
{"id":2,"name":"Jane","email":"jane@example.com","_created":"2024-12-19T10:01:00.000Z","_updated":"2024-12-19T10:01:00.000Z"}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
## 🔍 Advanced Examples
|
|
278
|
+
|
|
279
|
+
### Complex Search
|
|
280
|
+
|
|
281
|
+
```javascript
|
|
282
|
+
// Young users from New York who are developers
|
|
283
|
+
const users = await db.find({
|
|
284
|
+
age: { '<': 30 },
|
|
285
|
+
'profile.city': 'New York',
|
|
286
|
+
tags: { in: ['developer'] }
|
|
287
|
+
}, {
|
|
288
|
+
sort: { age: 1 },
|
|
289
|
+
limit: 10
|
|
290
|
+
});
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### Batch Update
|
|
294
|
+
|
|
295
|
+
```javascript
|
|
296
|
+
// Update age of all users from a city
|
|
297
|
+
const updated = await db.update(
|
|
298
|
+
{ 'profile.city': 'New York' },
|
|
299
|
+
{ 'profile.country': 'USA' }
|
|
300
|
+
);
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Integrity Validation
|
|
304
|
+
|
|
305
|
+
```javascript
|
|
306
|
+
// Validate integrity with details
|
|
307
|
+
const integrity = await db.validateIntegrity({
|
|
308
|
+
checkData: true,
|
|
309
|
+
checkIndexes: true,
|
|
310
|
+
checkOffsets: true,
|
|
311
|
+
verbose: true
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
if (!integrity.isValid) {
|
|
315
|
+
console.log('Errors:', integrity.errors);
|
|
316
|
+
console.log('Warnings:', integrity.warnings);
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### Detailed Statistics
|
|
321
|
+
|
|
322
|
+
```javascript
|
|
323
|
+
const stats = await db.getStats();
|
|
324
|
+
console.log('File size:', stats.file.size);
|
|
325
|
+
console.log('Total records:', stats.summary.totalRecords);
|
|
326
|
+
console.log('Indexes:', stats.indexes.indexCount);
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
## 🧪 Tests
|
|
330
|
+
|
|
331
|
+
```bash
|
|
332
|
+
npm test
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
**Automatic Cleanup**: The test script automatically removes all test files after execution to keep the project directory clean.
|
|
336
|
+
|
|
337
|
+
**Manual Cleanup**: If you need to clean up test files manually:
|
|
338
|
+
```bash
|
|
339
|
+
npm run test:clean
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
**Available Test Scripts**:
|
|
343
|
+
- `npm test` - Run all tests with automatic cleanup
|
|
344
|
+
- `npm run test:watch` - Run tests in watch mode
|
|
345
|
+
- `npm run test:clean` - Clean up test files manually
|
|
346
|
+
- `npm run test:optimized` - Run optimized performance tests
|
|
347
|
+
- `npm run test:parallel` - Run tests in parallel
|
|
348
|
+
- `npm run test:fast` - Run fast tests without isolation
|
|
349
|
+
|
|
350
|
+
## 📈 Performance
|
|
351
|
+
|
|
352
|
+
### JSONL Features
|
|
353
|
+
|
|
354
|
+
- **Point reading**: Only reads necessary lines
|
|
355
|
+
- **In-memory indexes**: Fast search by indexed fields
|
|
356
|
+
- **No complete parsing**: Doesn't load entire file into memory
|
|
357
|
+
- **Large volume support**: Scales with millions of records
|
|
358
|
+
|
|
359
|
+
### Comparison: JexiDB vs 1.x
|
|
360
|
+
|
|
361
|
+
| Feature | JexiDB | JexiDB 1.x |
|
|
362
|
+
|---------|---------------|------------|
|
|
363
|
+
| Safe truncation | ✅ | ❌ |
|
|
364
|
+
| Consistent offsets | ✅ | ❌ |
|
|
365
|
+
| Integrity validation | ✅ | ❌ |
|
|
366
|
+
| Isolated tests | ✅ | ❌ |
|
|
367
|
+
| No V8 dependency | ✅ | ❌ |
|
|
368
|
+
| Similar API | ✅ | ✅ |
|
|
369
|
+
|
|
370
|
+
## 🔧 Utilities
|
|
371
|
+
|
|
372
|
+
```javascript
|
|
373
|
+
const { utils } = require('jexidb');
|
|
374
|
+
|
|
375
|
+
// Validate JSONL file
|
|
376
|
+
const validation = await utils.validateJSONLFile('./data.jsonl');
|
|
377
|
+
|
|
378
|
+
// Convert JSON to JSONL (basic)
|
|
379
|
+
await utils.convertJSONToJSONL('./data.json', './data.jsonl');
|
|
380
|
+
|
|
381
|
+
// Convert JSONL to JSON
|
|
382
|
+
await utils.convertJSONLToJSON('./data.jsonl', './data.json');
|
|
383
|
+
|
|
384
|
+
// Create JexiDB database with automatic indexes
|
|
385
|
+
const result = await utils.createDatabaseFromJSON('./users.json', './users.jsonl', {
|
|
386
|
+
autoDetectIndexes: true,
|
|
387
|
+
autoIndexFields: ['id', 'email', 'name', 'username']
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
// Analyze JSON and suggest optimal indexes
|
|
391
|
+
const analysis = await utils.analyzeJSONForIndexes('./users.json', 100);
|
|
392
|
+
console.log('Recommended indexes:', analysis.suggestions.recommended);
|
|
393
|
+
|
|
394
|
+
// Migrate from JexiDB 1.x to JexiDB
|
|
395
|
+
await utils.migrateFromJexiDB('./jexidb-v1-database', './users.jsonl');
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
### 🔍 **How Utilities Work**
|
|
399
|
+
|
|
400
|
+
#### **1. Basic Conversion (No Indexes)**
|
|
401
|
+
```javascript
|
|
402
|
+
// Only converts format - DOES NOT add indexes
|
|
403
|
+
await utils.convertJSONToJSONL('./data.json', './data.jsonl');
|
|
404
|
+
```
|
|
405
|
+
- ✅ Converts JSON to JSONL
|
|
406
|
+
- ❌ **DOES NOT create indexes**
|
|
407
|
+
- ❌ **DOES NOT create JexiDB database**
|
|
408
|
+
- ✅ Pure JSONL file
|
|
409
|
+
|
|
410
|
+
#### **2. Database Creation with Automatic Indexes**
|
|
411
|
+
```javascript
|
|
412
|
+
// Create complete JexiDB database with indexes
|
|
413
|
+
const result = await utils.createDatabaseFromJSON('./users.json', './users.jsonl', {
|
|
414
|
+
autoDetectIndexes: true,
|
|
415
|
+
autoIndexFields: ['id', 'email', 'name']
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
console.log(result);
|
|
419
|
+
// {
|
|
420
|
+
// success: true,
|
|
421
|
+
// recordCount: 1000,
|
|
422
|
+
// indexes: ['id', 'email', 'name'],
|
|
423
|
+
// dbPath: './users.jsonl'
|
|
424
|
+
// }
|
|
425
|
+
```
|
|
426
|
+
- ✅ Converts JSON to JSONL
|
|
427
|
+
- ✅ **Creates indexes automatically**
|
|
428
|
+
- ✅ **Creates complete JexiDB database**
|
|
429
|
+
- ✅ File ready for use
|
|
430
|
+
|
|
431
|
+
#### **3. Intelligent Index Analysis**
|
|
432
|
+
```javascript
|
|
433
|
+
// Analyze data and suggest optimal indexes
|
|
434
|
+
const analysis = await utils.analyzeJSONForIndexes('./users.json');
|
|
435
|
+
|
|
436
|
+
console.log('Recommended:', analysis.suggestions.recommended);
|
|
437
|
+
// [
|
|
438
|
+
// { field: 'id', type: 'number', coverage: 100, uniqueness: 100 },
|
|
439
|
+
// { field: 'email', type: 'string', coverage: 95, uniqueness: 98 }
|
|
440
|
+
// ]
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
## 🔄 Migration from JexiDB 1.x
|
|
446
|
+
|
|
447
|
+
### Seamless Migration
|
|
448
|
+
|
|
449
|
+
JexiDB is **fully backward compatible** with JexiDB 1.x! You can use the same API:
|
|
450
|
+
|
|
451
|
+
```javascript
|
|
452
|
+
// JexiDB 1.x code works unchanged in JexiDB
|
|
453
|
+
import { Database } from 'jexidb';
|
|
454
|
+
|
|
455
|
+
const db = new Database('./database.jdb', {
|
|
456
|
+
indexes: { id: 'number', name: 'string' }
|
|
457
|
+
});
|
|
458
|
+
await db.init();
|
|
459
|
+
|
|
460
|
+
// All JexiDB 1.x methods work:
|
|
461
|
+
await db.insert({ id: 1, name: 'John Doe' });
|
|
462
|
+
const results = await db.query({ name: 'John Doe' }, { caseInsensitive: true });
|
|
463
|
+
await db.update({ id: 1 }, { name: 'John Smith' });
|
|
464
|
+
await db.delete({ id: 1 });
|
|
465
|
+
await db.save();
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
### File Format Support
|
|
469
|
+
|
|
470
|
+
JexiDB supports both file formats:
|
|
471
|
+
- **`.jdb`** (preferred) - JexiDB's branded extension
|
|
472
|
+
- **`.jsonl`** (standard) - JSON Lines format
|
|
473
|
+
|
|
474
|
+
```javascript
|
|
475
|
+
// Both work identically:
|
|
476
|
+
const db1 = new Database('./users.jdb', { indexes: { id: 'number' } });
|
|
477
|
+
const db2 = new Database('./users.jsonl', { indexes: { id: 'number' } });
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
### Key Improvements
|
|
481
|
+
|
|
482
|
+
| Feature | JexiDB 1.x | JexiDB |
|
|
483
|
+
|---------|------------|--------------|
|
|
484
|
+
| **API Compatibility** | Original | ✅ **100% Backward Compatible** |
|
|
485
|
+
| **Query Methods** | `db.query()` | ✅ `db.query()` + `db.find()` |
|
|
486
|
+
| **File Format** | `.jdb` (proprietary) | ✅ `.jdb` + `.jsonl` support |
|
|
487
|
+
| **Performance** | Basic | ✅ **10-100x faster** |
|
|
488
|
+
| **Memory Usage** | Higher | ✅ **25% less memory** |
|
|
489
|
+
| **Data Integrity** | Basic | ✅ **Advanced validation** |
|
|
490
|
+
|
|
491
|
+
## 📝 Changelog
|
|
492
|
+
|
|
493
|
+
See [CHANGELOG.md](CHANGELOG.md) for complete change history.
|
|
494
|
+
|
|
495
|
+
## 🤝 Contributing
|
|
496
|
+
|
|
497
|
+
1. Fork the project
|
|
498
|
+
2. Create a branch for your feature
|
|
499
|
+
3. Commit your changes
|
|
500
|
+
4. Push to the branch
|
|
501
|
+
5. Open a Pull Request
|
|
502
|
+
|
|
503
|
+
## 📄 License
|
|
504
|
+
|
|
505
|
+
MIT License - see [LICENSE](LICENSE) for details.
|
|
506
|
+
|
|
507
|
+
---
|
|
508
|
+
|
|
509
|
+
## 🎯 About JexiDB
|
|
510
|
+
|
|
511
|
+
JexiDB maintains the original JexiDB philosophy while fixing bugs and implementing a more robust architecture.
|
|
512
|
+
|
|
513
|
+
### 📈 Version 2.0.0 Changes
|
|
514
|
+
|
|
515
|
+
**JexiDB** addresses the problems of version 1.x:
|
|
516
|
+
|
|
517
|
+
| JexiDB 1.x Problem | JexiDB Solution |
|
|
518
|
+
|---------------------|----------------------|
|
|
519
|
+
| Unsafe truncation | ✅ Mandatory truncation after operations |
|
|
520
|
+
| Inconsistent offsets | ✅ Offsets always recalculated |
|
|
521
|
+
| No integrity validation | ✅ Automatic validation |
|
|
522
|
+
| V8 dependency | ✅ Pure JavaScript |
|
|
523
|
+
| Non-isolated tests | ✅ Tests always clean files |
|
|
524
|
+
| Inconsistent serialization | ✅ Standardized line breaks |
|
|
525
|
+
|
|
526
|
+
### 🚀 Performance
|
|
527
|
+
|
|
528
|
+
**JexiDB** performance compared to version 1.x:
|
|
529
|
+
|
|
530
|
+
- **Find operations**: 103x faster
|
|
531
|
+
- **Update operations**: 26x faster
|
|
532
|
+
- **Insert operations**: 6-11x faster
|
|
533
|
+
- **Memory usage**: 25% less memory
|
|
534
|
+
|
|
535
|
+
### 🔧 Simple Migration
|
|
536
|
+
|
|
537
|
+
Migration from JexiDB 1.x to JexiDB is simple:
|
|
538
|
+
|
|
539
|
+
```javascript
|
|
540
|
+
// Before (JexiDB 1.x)
|
|
541
|
+
const { Database } = require('jexidb');
|
|
542
|
+
const db = new Database('./database.jdb', {
|
|
543
|
+
indexes: { id: 'number', name: 'string' }
|
|
544
|
+
});
|
|
545
|
+
await db.init();
|
|
546
|
+
await db.insert({ id: 1, name: 'John Doe' });
|
|
547
|
+
await db.save();
|
|
548
|
+
|
|
549
|
+
// Now (JexiDB)
|
|
550
|
+
import { Database } from 'jexidb';
|
|
551
|
+
const db = new Database('./users.jdb', { indexes: { id: 'number' } });
|
|
552
|
+
await db.init();
|
|
553
|
+
await db.insert({ id: 1, name: 'John Doe' });
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
**We maintain compatibility with the JexiDB 1.x API with improved performance and reliability.**
|