jexidb 2.1.1 → 2.1.3

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 (47) hide show
  1. package/dist/Database.cjs +7981 -231
  2. package/package.json +9 -2
  3. package/src/Database.mjs +372 -154
  4. package/src/SchemaManager.mjs +325 -268
  5. package/src/Serializer.mjs +20 -1
  6. package/src/managers/QueryManager.mjs +74 -18
  7. package/.babelrc +0 -13
  8. package/.gitattributes +0 -2
  9. package/CHANGELOG.md +0 -140
  10. package/babel.config.json +0 -5
  11. package/docs/API.md +0 -1057
  12. package/docs/EXAMPLES.md +0 -701
  13. package/docs/README.md +0 -194
  14. package/examples/iterate-usage-example.js +0 -157
  15. package/examples/simple-iterate-example.js +0 -115
  16. package/jest.config.js +0 -24
  17. package/scripts/README.md +0 -47
  18. package/scripts/benchmark-array-serialization.js +0 -108
  19. package/scripts/clean-test-files.js +0 -75
  20. package/scripts/prepare.js +0 -31
  21. package/scripts/run-tests.js +0 -80
  22. package/scripts/score-mode-demo.js +0 -45
  23. package/test/$not-operator-with-and.test.js +0 -282
  24. package/test/README.md +0 -8
  25. package/test/close-init-cycle.test.js +0 -256
  26. package/test/coverage-method.test.js +0 -93
  27. package/test/critical-bugs-fixes.test.js +0 -1069
  28. package/test/deserialize-corruption-fixes.test.js +0 -296
  29. package/test/exists-method.test.js +0 -318
  30. package/test/explicit-indexes-comparison.test.js +0 -219
  31. package/test/filehandler-non-adjacent-ranges-bug.test.js +0 -175
  32. package/test/index-line-number-regression.test.js +0 -100
  33. package/test/index-missing-index-data.test.js +0 -91
  34. package/test/index-persistence.test.js +0 -491
  35. package/test/index-serialization.test.js +0 -314
  36. package/test/indexed-query-mode.test.js +0 -360
  37. package/test/insert-session-auto-flush.test.js +0 -353
  38. package/test/iterate-method.test.js +0 -272
  39. package/test/legacy-operator-compat.test.js +0 -154
  40. package/test/query-operators.test.js +0 -238
  41. package/test/regex-array-fields.test.js +0 -129
  42. package/test/score-method.test.js +0 -298
  43. package/test/setup.js +0 -17
  44. package/test/term-mapping-minimal.test.js +0 -154
  45. package/test/term-mapping-simple.test.js +0 -257
  46. package/test/term-mapping.test.js +0 -514
  47. package/test/writebuffer-flush-resilience.test.js +0 -204
@@ -337,9 +337,26 @@ export class QueryManager {
337
337
  }
338
338
  }
339
339
 
340
+ // Handle $not operator - include it if it can be processed by IndexManager
341
+ if (criteria.$not && typeof criteria.$not === 'object') {
342
+ // Check if $not condition contains only indexable fields
343
+ const notFields = Object.keys(criteria.$not);
344
+ const allNotFieldsIndexed = notFields.every(field =>
345
+ this.indexManager.opts.indexes && this.indexManager.opts.indexes[field]
346
+ );
347
+
348
+ if (allNotFieldsIndexed && notFields.length > 0) {
349
+ // Extract indexable criteria from $not condition
350
+ const indexableNotCriteria = this._extractIndexableCriteria(criteria.$not);
351
+ if (Object.keys(indexableNotCriteria).length > 0) {
352
+ indexableCriteria.$not = indexableNotCriteria;
353
+ }
354
+ }
355
+ }
356
+
340
357
  // Handle regular field conditions
341
358
  for (const [field, condition] of Object.entries(criteria)) {
342
- if (field.startsWith('$')) continue; // Skip logical operators
359
+ if (field.startsWith('$')) continue; // Skip logical operators (already handled above)
343
360
 
344
361
  // RegExp conditions cannot be pre-filtered using indices
345
362
  if (condition instanceof RegExp) {
@@ -690,30 +707,69 @@ export class QueryManager {
690
707
  // Read specific records using the line numbers
691
708
  if (lineNumbers.size > 0) {
692
709
  const lineNumbersArray = Array.from(lineNumbers)
693
- const ranges = this.database.getRanges(lineNumbersArray)
694
- const groupedRanges = await this.database.fileHandler.groupedRanges(ranges)
710
+ const persistedCount = Array.isArray(this.database.offsets) ? this.database.offsets.length : 0
695
711
 
696
- const fs = await import('fs')
697
- const fd = await fs.promises.open(this.database.fileHandler.file, 'r')
712
+ // Separate lineNumbers into file records and writeBuffer records
713
+ const fileLineNumbers = []
714
+ const writeBufferLineNumbers = []
698
715
 
699
- try {
700
- for (const groupedRange of groupedRanges) {
701
- for await (const row of this.database.fileHandler.readGroupedRange(groupedRange, fd)) {
702
- try {
703
- const record = this.database.serializer.deserialize(row.line)
716
+ for (const lineNumber of lineNumbersArray) {
717
+ if (lineNumber >= persistedCount) {
718
+ // This lineNumber points to writeBuffer
719
+ writeBufferLineNumbers.push(lineNumber)
720
+ } else {
721
+ // This lineNumber points to file
722
+ fileLineNumbers.push(lineNumber)
723
+ }
724
+ }
725
+
726
+ // Read records from file
727
+ if (fileLineNumbers.length > 0) {
728
+ const ranges = this.database.getRanges(fileLineNumbers)
729
+ if (ranges.length > 0) {
730
+ const groupedRanges = await this.database.fileHandler.groupedRanges(ranges)
731
+
732
+ const fs = await import('fs')
733
+ const fd = await fs.promises.open(this.database.fileHandler.file, 'r')
734
+
735
+ try {
736
+ for (const groupedRange of groupedRanges) {
737
+ for await (const row of this.database.fileHandler.readGroupedRange(groupedRange, fd)) {
738
+ try {
739
+ const record = this.database.serializer.deserialize(row.line)
740
+ const recordWithTerms = options.restoreTerms !== false ?
741
+ this.database.restoreTermIdsAfterDeserialization(record) :
742
+ record
743
+ results.push(recordWithTerms)
744
+ if (limit && results.length >= limit) break
745
+ } catch (error) {
746
+ // Skip invalid lines
747
+ }
748
+ }
749
+ if (limit && results.length >= limit) break
750
+ }
751
+ } finally {
752
+ await fd.close()
753
+ }
754
+ }
755
+ }
756
+
757
+ // Read records from writeBuffer
758
+ if (writeBufferLineNumbers.length > 0 && this.database.writeBuffer) {
759
+ for (const lineNumber of writeBufferLineNumbers) {
760
+ if (limit && results.length >= limit) break
761
+
762
+ const writeBufferIndex = lineNumber - persistedCount
763
+ if (writeBufferIndex >= 0 && writeBufferIndex < this.database.writeBuffer.length) {
764
+ const record = this.database.writeBuffer[writeBufferIndex]
765
+ if (record) {
704
766
  const recordWithTerms = options.restoreTerms !== false ?
705
767
  this.database.restoreTermIdsAfterDeserialization(record) :
706
768
  record
707
769
  results.push(recordWithTerms)
708
- if (limit && results.length >= limit) break
709
- } catch (error) {
710
- // Skip invalid lines
711
770
  }
712
771
  }
713
- if (limit && results.length >= limit) break
714
772
  }
715
- } finally {
716
- await fd.close()
717
773
  }
718
774
  }
719
775
 
@@ -1138,8 +1194,8 @@ export class QueryManager {
1138
1194
  }
1139
1195
 
1140
1196
  const allFieldsIndexed = Object.keys(criteria).every(field => {
1141
- // Skip $and as it's handled separately above
1142
- if (field === '$and') return true;
1197
+ // Skip $and and $not as they're handled separately above
1198
+ if (field === '$and' || field === '$not') return true;
1143
1199
 
1144
1200
  if (!this.opts.indexes || !this.opts.indexes[field]) {
1145
1201
  if (this.opts.debugMode) {
package/.babelrc DELETED
@@ -1,13 +0,0 @@
1
-
2
- {
3
- "presets": [
4
- ["@babel/preset-env", {
5
- "targets": {
6
- "node": "current"
7
- }
8
- }]
9
- ],
10
- "plugins": [
11
- "@babel/plugin-transform-async-generator-functions"
12
- ]
13
- }
package/.gitattributes DELETED
@@ -1,2 +0,0 @@
1
- # Auto detect text files and perform LF normalization
2
- * text=auto
package/CHANGELOG.md DELETED
@@ -1,140 +0,0 @@
1
- # Changelog
2
-
3
- All notable changes to this project will be documented in this file.
4
-
5
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
-
8
- ## [2.1.0] - 2024-12-19
9
-
10
- ### ⚠️ BREAKING CHANGES
11
-
12
- This version is **NOT backward compatible** with databases created with previous versions.
13
-
14
- ### 🚀 Major Features
15
-
16
- #### **Term Mapping Auto-Detection**
17
-
18
- - **BREAKING**: `termMapping` is now `true` by default (was `false`)
19
- - **BREAKING**: `termMappingFields` is now auto-detected from `indexes` (was manual configuration)
20
- - **NEW**: Automatic detection of `string` and `array:string` fields for term mapping
21
- - **NEW**: Zero-configuration term mapping for optimal performance
22
-
23
- #### **Schema Requirements**
24
-
25
- - **BREAKING**: `fields` option is now **MANDATORY** (was optional)
26
- - **NEW**: Clear distinction between `fields` (schema definition) and `indexes` (performance optimization)
27
- - **NEW**: Enhanced schema validation and error messages
28
-
29
- #### **Index Management**
30
-
31
- - **BREAKING**: `array:string` fields now use term IDs in indexes (was string values)
32
- - **BREAKING**: `array:number` fields use direct numeric values (was incorrectly term-mapped)
33
- - **NEW**: Improved index performance for array fields
34
- - **NEW**: Better memory usage for repetitive string data
35
-
36
- ### 🔧 Improvements
37
-
38
- #### **Database Constructor**
39
-
40
- - **BREAKING**: `fields` parameter is now required
41
- - **NEW**: Auto-detection of term mapping fields
42
- - **NEW**: Enhanced error messages for missing schema
43
- - **NEW**: Better validation of field types
44
-
45
- #### **Query Performance**
46
-
47
- - **NEW**: Optimized query processing for term-mapped fields
48
- - **NEW**: Improved `$in` operator handling for arrays
49
- - **NEW**: Better support for mixed field types in queries
50
-
51
- #### **Documentation**
52
-
53
- - **NEW**: Complete API documentation overhaul
54
- - **NEW**: Practical examples with proper schema usage
55
- - **NEW**: Performance optimization guidelines
56
- - **NEW**: Migration guide for version 2.x
57
-
58
- ### 🐛 Bug Fixes
59
-
60
- - Fixed `array:string` fields incorrectly using string values instead of term IDs
61
- - Fixed `array:number` fields being incorrectly term-mapped
62
- - Fixed term mapping not being enabled by default
63
- - Fixed missing `termMappingFields` property on TermManager
64
- - Fixed IndexManager not correctly identifying term mapping fields
65
-
66
- ### 📚 Documentation Updates
67
-
68
- - **NEW**: Comprehensive API reference with examples
69
- - **NEW**: Schema vs Indexes distinction clearly explained
70
- - **NEW**: Performance tips and best practices
71
- - **NEW**: Migration guide for existing users
72
- - **NEW**: `beginInsertSession()` documentation
73
-
74
- ### 🔄 Migration Guide
75
-
76
- #### **For Existing Users (1.x.x → 2.1.0)**
77
-
78
- 1. **Update your database initialization:**
79
-
80
- ```javascript
81
- // ❌ OLD (1.x.x)
82
- const db = new Database('db.jdb', {
83
- indexes: { name: 'string', tags: 'array:string' }
84
- })
85
-
86
- // ✅ NEW (2.1.0)
87
- const db = new Database('db.jdb', {
88
- fields: { // REQUIRED - Define schema
89
- id: 'number',
90
- name: 'string',
91
- tags: 'array:string'
92
- },
93
- indexes: { // OPTIONAL - Performance optimization
94
- name: 'string',
95
- tags: 'array:string'
96
- }
97
- })
98
- ```
99
- 2. **Database files are NOT compatible:**
100
-
101
- - Existing `.jdb` files from 1.x.x will not work with 2.1.0
102
- - You need to export data from 1.x.x and re-import to 2.1.0
103
- - Consider this a fresh start for your database files
104
- 3. **Term mapping is now automatic:**
105
-
106
- - No need to manually configure `termMapping: true`
107
- - No need to specify `termMappingFields`
108
- - Fields are auto-detected from your `indexes` configuration
109
-
110
- ### 🎯 Performance Improvements
111
-
112
- - **Up to 77% reduction** in database size for repetitive string data
113
- - **Faster queries** on term-mapped fields
114
- - **Better memory usage** for large datasets
115
- - **Optimized indexing** for array fields
116
-
117
- ### 🧪 Testing
118
-
119
- - **NEW**: Comprehensive test suite for term mapping
120
- - **NEW**: Performance benchmarks for large datasets
121
- - **NEW**: Migration compatibility tests
122
- - **NEW**: Edge case testing for array fields
123
-
124
- ---
125
-
126
- ## [1.1.0] - Previous Version
127
-
128
- ### Features
129
-
130
- - Basic database functionality
131
- - Manual term mapping configuration
132
- - Optional schema definition
133
- - Basic indexing support
134
-
135
- ### Limitations
136
-
137
- - Term mapping required manual configuration
138
- - Schema was optional, leading to confusion
139
- - Array fields had indexing issues
140
- - Performance not optimized for repetitive data
package/babel.config.json DELETED
@@ -1,5 +0,0 @@
1
- {
2
- "presets": ["@babel/preset-env"],
3
- "plugins": ["@babel/plugin-transform-async-generator-functions"]
4
- }
5
-