jexidb 2.1.0 → 2.1.2
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/dist/Database.cjs +9253 -437
- package/package.json +9 -2
- package/src/Database.mjs +1572 -212
- package/src/FileHandler.mjs +83 -44
- package/src/OperationQueue.mjs +23 -23
- package/src/SchemaManager.mjs +325 -268
- package/src/Serializer.mjs +234 -24
- package/src/managers/IndexManager.mjs +778 -87
- package/src/managers/QueryManager.mjs +340 -67
- package/src/managers/TermManager.mjs +7 -7
- package/src/utils/operatorNormalizer.mjs +116 -0
- package/.babelrc +0 -13
- package/.gitattributes +0 -2
- package/CHANGELOG.md +0 -140
- package/babel.config.json +0 -5
- package/docs/API.md +0 -1051
- package/docs/EXAMPLES.md +0 -701
- package/docs/README.md +0 -194
- package/examples/iterate-usage-example.js +0 -157
- package/examples/simple-iterate-example.js +0 -115
- package/jest.config.js +0 -24
- package/scripts/README.md +0 -47
- package/scripts/clean-test-files.js +0 -75
- package/scripts/prepare.js +0 -31
- package/scripts/run-tests.js +0 -80
- package/test/$not-operator-with-and.test.js +0 -282
- package/test/README.md +0 -8
- package/test/close-init-cycle.test.js +0 -256
- package/test/critical-bugs-fixes.test.js +0 -1069
- package/test/index-persistence.test.js +0 -306
- package/test/index-serialization.test.js +0 -314
- package/test/indexed-query-mode.test.js +0 -360
- package/test/iterate-method.test.js +0 -272
- package/test/query-operators.test.js +0 -238
- package/test/regex-array-fields.test.js +0 -129
- package/test/score-method.test.js +0 -238
- package/test/setup.js +0 -17
- package/test/term-mapping-minimal.test.js +0 -154
- package/test/term-mapping-simple.test.js +0 -257
- package/test/term-mapping.test.js +0 -514
- package/test/writebuffer-flush-resilience.test.js +0 -204
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
const { Database } = require('../src/Database.mjs')
|
|
2
|
-
const fs = require('fs')
|
|
3
|
-
const path = require('path')
|
|
4
|
-
|
|
5
|
-
describe('WriteBuffer Flush Resilience', () => {
|
|
6
|
-
let testDir
|
|
7
|
-
let db
|
|
8
|
-
|
|
9
|
-
beforeEach(async () => {
|
|
10
|
-
testDir = path.join(__dirname, 'test-files', 'writebuffer-resilience')
|
|
11
|
-
if (fs.existsSync(testDir)) {
|
|
12
|
-
fs.rmSync(testDir, { recursive: true, force: true })
|
|
13
|
-
}
|
|
14
|
-
fs.mkdirSync(testDir, { recursive: true })
|
|
15
|
-
|
|
16
|
-
db = new Database(path.join(testDir, 'test'), {
|
|
17
|
-
indexes: { name: 'string', tags: 'array:string' },
|
|
18
|
-
debugMode: false, // Disable debug mode to reduce noise
|
|
19
|
-
})
|
|
20
|
-
await db.init()
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
afterEach(async () => {
|
|
24
|
-
if (db && !db.destroyed) {
|
|
25
|
-
await db.close()
|
|
26
|
-
}
|
|
27
|
-
// Retry mechanism for cleanup
|
|
28
|
-
let retries = 3
|
|
29
|
-
while (retries > 0) {
|
|
30
|
-
try {
|
|
31
|
-
if (fs.existsSync(testDir)) {
|
|
32
|
-
fs.rmSync(testDir, { recursive: true, force: true })
|
|
33
|
-
}
|
|
34
|
-
break
|
|
35
|
-
} catch (error) {
|
|
36
|
-
retries--
|
|
37
|
-
if (retries === 0) throw error
|
|
38
|
-
await new Promise(resolve => setTimeout(resolve, 100))
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
it('should handle concurrent operations that add to writeBuffer during flush', async () => {
|
|
44
|
-
// First, create the database file with some initial data
|
|
45
|
-
await db.insert({ name: 'initial', tags: ['initial'] })
|
|
46
|
-
// Don't flush the initial record - keep it in writeBuffer for the test
|
|
47
|
-
|
|
48
|
-
// Simulate concurrent operations that can add items to writeBuffer
|
|
49
|
-
const operations = []
|
|
50
|
-
|
|
51
|
-
// Start multiple concurrent operations
|
|
52
|
-
for (let i = 0; i < 10; i++) {
|
|
53
|
-
operations.push(
|
|
54
|
-
db.insert({ name: `item${i}`, tags: [`tag${i}`, `category${i % 3}`] }).then(() => {
|
|
55
|
-
console.log(`✅ Inserted item${i}`)
|
|
56
|
-
})
|
|
57
|
-
)
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Add more operations
|
|
61
|
-
for (let i = 10; i < 15; i++) {
|
|
62
|
-
operations.push(
|
|
63
|
-
db.insert({ name: `item${i}`, tags: [`tag${i}`, `category${i % 3}`] }).then(() => {
|
|
64
|
-
console.log(`✅ Inserted item${i}`)
|
|
65
|
-
})
|
|
66
|
-
)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Wait for all insert operations to complete first
|
|
70
|
-
await Promise.all(operations)
|
|
71
|
-
|
|
72
|
-
// Then flush to save all data
|
|
73
|
-
await db.flush()
|
|
74
|
-
|
|
75
|
-
// Verify all data was saved correctly (15 new items + 1 initial = 16 total)
|
|
76
|
-
const allItems = await db.find({})
|
|
77
|
-
expect(allItems).toHaveLength(16)
|
|
78
|
-
|
|
79
|
-
// Verify no data was lost
|
|
80
|
-
for (let i = 0; i < 15; i++) {
|
|
81
|
-
const item = await db.findOne({ name: `item${i}` })
|
|
82
|
-
expect(item).toBeTruthy()
|
|
83
|
-
expect(item.name).toBe(`item${i}`)
|
|
84
|
-
expect(item.tags).toContain(`tag${i}`)
|
|
85
|
-
}
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
it('should handle update operations that add indexOffset to writeBuffer during flush', async () => {
|
|
89
|
-
// Insert initial data and ensure it's saved to create the file
|
|
90
|
-
await db.insert({ name: 'item1', tags: ['tag1', 'tag2'] })
|
|
91
|
-
await db.insert({ name: 'item2', tags: ['tag2', 'tag3'] })
|
|
92
|
-
await db.insert({ name: 'item3', tags: ['tag1', 'tag3'] })
|
|
93
|
-
|
|
94
|
-
// Ensure initial data is saved to create the database file
|
|
95
|
-
await db.flush() // Use flush() to actually write data to file
|
|
96
|
-
|
|
97
|
-
// Verify all records exist before update
|
|
98
|
-
const beforeUpdate1 = await db.findOne({ name: 'item1' })
|
|
99
|
-
const beforeUpdate2 = await db.findOne({ name: 'item2' })
|
|
100
|
-
const beforeUpdate3 = await db.findOne({ name: 'item3' })
|
|
101
|
-
expect(beforeUpdate1).toBeTruthy()
|
|
102
|
-
expect(beforeUpdate2).toBeTruthy()
|
|
103
|
-
expect(beforeUpdate3).toBeTruthy()
|
|
104
|
-
|
|
105
|
-
// Use sequential operations to avoid Windows file locking conflicts
|
|
106
|
-
// Add update operations sequentially to avoid deadlocks
|
|
107
|
-
await db.update({ name: 'item1' }, { name: 'item1', tags: ['tag1', 'tag2', 'tag4'] })
|
|
108
|
-
await db.update({ name: 'item2' }, { name: 'item2', tags: ['tag2', 'tag3', 'tag5'] })
|
|
109
|
-
await db.update({ name: 'item3' }, { name: 'item3', tags: ['tag1', 'tag3', 'tag6'] })
|
|
110
|
-
|
|
111
|
-
// Then flush to save the updates
|
|
112
|
-
await db.flush()
|
|
113
|
-
|
|
114
|
-
// Verify updates were applied correctly
|
|
115
|
-
const updated1 = await db.findOne({ name: 'item1' })
|
|
116
|
-
expect(updated1).toBeTruthy()
|
|
117
|
-
expect(updated1.tags).toContain('tag4')
|
|
118
|
-
|
|
119
|
-
const updated2 = await db.findOne({ name: 'item2' })
|
|
120
|
-
expect(updated2).toBeTruthy()
|
|
121
|
-
expect(updated2.tags).toContain('tag5')
|
|
122
|
-
|
|
123
|
-
const updated3 = await db.findOne({ name: 'item3' })
|
|
124
|
-
expect(updated3).toBeTruthy()
|
|
125
|
-
expect(updated3.tags).toContain('tag6')
|
|
126
|
-
}, 30000) // 30 second timeout
|
|
127
|
-
|
|
128
|
-
it('should handle delete operations that add indexOffset to writeBuffer during flush', async () => {
|
|
129
|
-
// Insert initial data and ensure it's saved to create the file
|
|
130
|
-
await db.insert({ name: 'item1', tags: ['tag1', 'tag2'] })
|
|
131
|
-
await db.insert({ name: 'item2', tags: ['tag2', 'tag3'] })
|
|
132
|
-
await db.insert({ name: 'item3', tags: ['tag1', 'tag3'] })
|
|
133
|
-
await db.insert({ name: 'item4', tags: ['tag4', 'tag5'] })
|
|
134
|
-
|
|
135
|
-
// Ensure initial data is saved to create the database file
|
|
136
|
-
await db.flush() // Use flush() to actually write data to file
|
|
137
|
-
|
|
138
|
-
// Use sequential operations to avoid Windows file locking conflicts
|
|
139
|
-
// Add delete operations sequentially to avoid deadlocks
|
|
140
|
-
await db.delete({ name: 'item1' })
|
|
141
|
-
await db.delete({ name: 'item2' })
|
|
142
|
-
|
|
143
|
-
// Then flush to save the deletions
|
|
144
|
-
await db.flush()
|
|
145
|
-
|
|
146
|
-
// Verify deletions were applied correctly
|
|
147
|
-
const remaining = await db.find({})
|
|
148
|
-
expect(remaining).toHaveLength(2)
|
|
149
|
-
|
|
150
|
-
const item3 = await db.findOne({ name: 'item3' })
|
|
151
|
-
expect(item3).toBeTruthy()
|
|
152
|
-
|
|
153
|
-
const item4 = await db.findOne({ name: 'item4' })
|
|
154
|
-
expect(item4).toBeTruthy()
|
|
155
|
-
}, 30000) // 30 second timeout
|
|
156
|
-
|
|
157
|
-
it('should continue flushing until writeBuffer is completely empty', async () => {
|
|
158
|
-
// This test simulates the exact scenario that was causing the error
|
|
159
|
-
const operations = []
|
|
160
|
-
|
|
161
|
-
// Start multiple operations that will add to writeBuffer
|
|
162
|
-
for (let i = 0; i < 25; i++) {
|
|
163
|
-
operations.push(
|
|
164
|
-
db.insert({ name: `item${i}`, tags: [`tag${i}`] })
|
|
165
|
-
)
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Wait for all insert operations to complete first
|
|
169
|
-
await Promise.all(operations)
|
|
170
|
-
|
|
171
|
-
// Then save to persist all data
|
|
172
|
-
await db.save()
|
|
173
|
-
|
|
174
|
-
// Verify all data was saved
|
|
175
|
-
const allItems = await db.find({})
|
|
176
|
-
expect(allItems).toHaveLength(25)
|
|
177
|
-
})
|
|
178
|
-
|
|
179
|
-
it('should handle writeBuffer flush resilience without errors', async () => {
|
|
180
|
-
// This test verifies that the writeBuffer flush resilience works without throwing errors
|
|
181
|
-
const operations = []
|
|
182
|
-
|
|
183
|
-
// Add operations first
|
|
184
|
-
for (let i = 0; i < 5; i++) {
|
|
185
|
-
operations.push(
|
|
186
|
-
db.insert({ name: `item${i}`, tags: [`tag${i}`] })
|
|
187
|
-
)
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Wait for all insert operations to complete first
|
|
191
|
-
await Promise.all(operations)
|
|
192
|
-
|
|
193
|
-
// Then save to persist all data
|
|
194
|
-
await db.save()
|
|
195
|
-
|
|
196
|
-
// Verify data was saved correctly (be more tolerant of Windows file locking issues)
|
|
197
|
-
const allItems = await db.find({})
|
|
198
|
-
expect(allItems.length).toBeGreaterThan(0) // At least some data should be saved
|
|
199
|
-
expect(allItems.length).toBeLessThanOrEqual(5) // But not more than expected
|
|
200
|
-
|
|
201
|
-
// Verify the flush resilience mechanism worked (no "WriteBuffer not empty" errors)
|
|
202
|
-
// The test passes if we get here without throwing errors
|
|
203
|
-
}, 15000)
|
|
204
|
-
})
|