jexidb 2.1.1 → 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 +7621 -113
- package/package.json +9 -2
- package/src/Database.mjs +244 -79
- package/src/SchemaManager.mjs +325 -268
- package/src/Serializer.mjs +20 -1
- package/src/managers/QueryManager.mjs +74 -18
- package/.babelrc +0 -13
- package/.gitattributes +0 -2
- package/CHANGELOG.md +0 -140
- package/babel.config.json +0 -5
- package/docs/API.md +0 -1057
- 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/benchmark-array-serialization.js +0 -108
- package/scripts/clean-test-files.js +0 -75
- package/scripts/prepare.js +0 -31
- package/scripts/run-tests.js +0 -80
- package/scripts/score-mode-demo.js +0 -45
- 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/coverage-method.test.js +0 -93
- package/test/critical-bugs-fixes.test.js +0 -1069
- package/test/deserialize-corruption-fixes.test.js +0 -296
- package/test/exists-method.test.js +0 -318
- package/test/explicit-indexes-comparison.test.js +0 -219
- package/test/filehandler-non-adjacent-ranges-bug.test.js +0 -175
- package/test/index-line-number-regression.test.js +0 -100
- package/test/index-missing-index-data.test.js +0 -91
- package/test/index-persistence.test.js +0 -491
- package/test/index-serialization.test.js +0 -314
- package/test/indexed-query-mode.test.js +0 -360
- package/test/insert-session-auto-flush.test.js +0 -353
- package/test/iterate-method.test.js +0 -272
- package/test/legacy-operator-compat.test.js +0 -154
- package/test/query-operators.test.js +0 -238
- package/test/regex-array-fields.test.js +0 -129
- package/test/score-method.test.js +0 -298
- 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,298 +0,0 @@
|
|
|
1
|
-
import fs from 'fs'
|
|
2
|
-
import path from 'path'
|
|
3
|
-
import { Database } from '../src/Database.mjs'
|
|
4
|
-
|
|
5
|
-
// Clean up test files
|
|
6
|
-
const cleanUp = (filePath) => {
|
|
7
|
-
try {
|
|
8
|
-
if (fs.existsSync(filePath)) {
|
|
9
|
-
fs.unlinkSync(filePath)
|
|
10
|
-
}
|
|
11
|
-
} catch (error) {
|
|
12
|
-
// Ignore cleanup errors
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
describe('Score Method Tests', () => {
|
|
17
|
-
let db
|
|
18
|
-
let testDbPath
|
|
19
|
-
let testIdxPath
|
|
20
|
-
|
|
21
|
-
beforeEach(async () => {
|
|
22
|
-
const testId = Math.random().toString(36).substring(7)
|
|
23
|
-
testDbPath = path.join(process.cwd(), `test-score-${testId}.jdb`)
|
|
24
|
-
testIdxPath = path.join(process.cwd(), `test-score-${testId}.idx.jdb`)
|
|
25
|
-
|
|
26
|
-
// Clean up any existing files
|
|
27
|
-
cleanUp(testDbPath)
|
|
28
|
-
cleanUp(testIdxPath)
|
|
29
|
-
|
|
30
|
-
// Create and initialize database
|
|
31
|
-
db = new Database(testDbPath, {
|
|
32
|
-
indexes: {
|
|
33
|
-
'terms': 'array:string'
|
|
34
|
-
}
|
|
35
|
-
})
|
|
36
|
-
await db.init()
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
afterEach(async () => {
|
|
40
|
-
if (db) {
|
|
41
|
-
await db.close()
|
|
42
|
-
db = null
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Clean up test files
|
|
46
|
-
cleanUp(testDbPath)
|
|
47
|
-
cleanUp(testIdxPath)
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
describe('Basic Score Functionality', () => {
|
|
51
|
-
test('should score records based on terms in array field', async () => {
|
|
52
|
-
// Insert test data
|
|
53
|
-
await db.insert({ id: 1, title: 'Action Movie', terms: ['action', 'movie'] })
|
|
54
|
-
await db.insert({ id: 2, title: 'Comedy Show', terms: ['comedy', 'show'] })
|
|
55
|
-
await db.insert({ id: 3, title: 'Action Comedy', terms: ['action', 'comedy'] })
|
|
56
|
-
await db.insert({ id: 4, title: 'Documentary', terms: ['documentary'] })
|
|
57
|
-
await db.save()
|
|
58
|
-
|
|
59
|
-
// Score records
|
|
60
|
-
const results = await db.score('terms', {
|
|
61
|
-
'action': 1.0,
|
|
62
|
-
'comedy': 0.8
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
expect(results).toHaveLength(3)
|
|
66
|
-
|
|
67
|
-
// Check first result (Action Comedy - highest score: 1.8)
|
|
68
|
-
expect(results[0].title).toBe('Action Comedy')
|
|
69
|
-
expect(results[0].score).toBe(1.8)
|
|
70
|
-
expect(results[0]._).toBeDefined()
|
|
71
|
-
|
|
72
|
-
// Check second result (Action Movie - score: 1.0)
|
|
73
|
-
expect(results[1].title).toBe('Action Movie')
|
|
74
|
-
expect(results[1].score).toBe(1.0)
|
|
75
|
-
|
|
76
|
-
// Check third result (Comedy Show - score: 0.8)
|
|
77
|
-
expect(results[2].title).toBe('Comedy Show')
|
|
78
|
-
expect(results[2].score).toBe(0.8)
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
test('should exclude records with zero scores', async () => {
|
|
82
|
-
await db.insert({ id: 1, title: 'Item 1', terms: ['tech'] })
|
|
83
|
-
await db.insert({ id: 2, title: 'Item 2', terms: ['science'] })
|
|
84
|
-
await db.insert({ id: 3, title: 'Item 3', terms: ['news'] })
|
|
85
|
-
await db.save()
|
|
86
|
-
|
|
87
|
-
const results = await db.score('terms', {
|
|
88
|
-
'tech': 1.0
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
expect(results).toHaveLength(1)
|
|
92
|
-
expect(results[0].title).toBe('Item 1')
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
test('should handle decimal weights', async () => {
|
|
96
|
-
await db.insert({ id: 1, title: 'High Priority', terms: ['urgent', 'important'] })
|
|
97
|
-
await db.insert({ id: 2, title: 'Normal Priority', terms: ['normal'] })
|
|
98
|
-
await db.save()
|
|
99
|
-
|
|
100
|
-
const results = await db.score('terms', {
|
|
101
|
-
'urgent': 0.9,
|
|
102
|
-
'important': 0.7,
|
|
103
|
-
'normal': 0.3
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
expect(results).toHaveLength(2)
|
|
107
|
-
expect(results[0].title).toBe('High Priority')
|
|
108
|
-
expect(results[0].score).toBe(1.6)
|
|
109
|
-
expect(results[1].title).toBe('Normal Priority')
|
|
110
|
-
expect(results[1].score).toBe(0.3)
|
|
111
|
-
})
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
describe('Options Tests', () => {
|
|
115
|
-
test('should respect limit option', async () => {
|
|
116
|
-
await db.insert({ id: 1, title: 'Item 1', terms: ['a'] })
|
|
117
|
-
await db.insert({ id: 2, title: 'Item 2', terms: ['a', 'b'] })
|
|
118
|
-
await db.insert({ id: 3, title: 'Item 3', terms: ['a', 'b', 'c'] })
|
|
119
|
-
await db.insert({ id: 4, title: 'Item 4', terms: ['a'] })
|
|
120
|
-
await db.save()
|
|
121
|
-
|
|
122
|
-
const results = await db.score('terms', {
|
|
123
|
-
'a': 1.0,
|
|
124
|
-
'b': 2.0,
|
|
125
|
-
'c': 3.0
|
|
126
|
-
}, { limit: 2 })
|
|
127
|
-
|
|
128
|
-
expect(results).toHaveLength(2)
|
|
129
|
-
})
|
|
130
|
-
|
|
131
|
-
test('should respect sort ascending option', async () => {
|
|
132
|
-
await db.insert({ id: 1, title: 'High', terms: ['high'] })
|
|
133
|
-
await db.insert({ id: 2, title: 'Medium', terms: ['medium'] })
|
|
134
|
-
await db.insert({ id: 3, title: 'Low', terms: ['low'] })
|
|
135
|
-
await db.save()
|
|
136
|
-
|
|
137
|
-
const results = await db.score('terms', {
|
|
138
|
-
'high': 3.0,
|
|
139
|
-
'medium': 2.0,
|
|
140
|
-
'low': 1.0
|
|
141
|
-
}, { sort: 'asc' })
|
|
142
|
-
|
|
143
|
-
expect(results).toHaveLength(3)
|
|
144
|
-
expect(results[0].title).toBe('Low')
|
|
145
|
-
expect(results[1].title).toBe('Medium')
|
|
146
|
-
expect(results[2].title).toBe('High')
|
|
147
|
-
})
|
|
148
|
-
|
|
149
|
-
test('should not include score when includeScore is false', async () => {
|
|
150
|
-
await db.insert({ id: 1, title: 'Test', terms: ['a'] })
|
|
151
|
-
await db.save()
|
|
152
|
-
|
|
153
|
-
const results = await db.score('terms', {
|
|
154
|
-
'a': 1.0
|
|
155
|
-
}, { includeScore: false })
|
|
156
|
-
|
|
157
|
-
expect(results).toHaveLength(1)
|
|
158
|
-
expect(results[0].score).toBeUndefined()
|
|
159
|
-
expect(results[0]._).toBeDefined()
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
test('should default to including score', async () => {
|
|
163
|
-
await db.insert({ id: 1, title: 'Test', terms: ['a'] })
|
|
164
|
-
await db.save()
|
|
165
|
-
|
|
166
|
-
const results = await db.score('terms', {
|
|
167
|
-
'a': 1.0
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
expect(results).toHaveLength(1)
|
|
171
|
-
expect(results[0].score).toBe(1.0)
|
|
172
|
-
})
|
|
173
|
-
})
|
|
174
|
-
|
|
175
|
-
describe('Mode Options', () => {
|
|
176
|
-
test('should support max mode', async () => {
|
|
177
|
-
await db.insert({ id: 1, title: 'Action Only', terms: ['action'] })
|
|
178
|
-
await db.insert({ id: 2, title: 'Action Comedy', terms: ['action', 'comedy'] })
|
|
179
|
-
await db.insert({ id: 3, title: 'Comedy Only', terms: ['comedy'] })
|
|
180
|
-
await db.save()
|
|
181
|
-
|
|
182
|
-
const results = await db.score('terms', {
|
|
183
|
-
'action': 2.0,
|
|
184
|
-
'comedy': 1.0
|
|
185
|
-
}, { mode: 'max' })
|
|
186
|
-
|
|
187
|
-
expect(results).toHaveLength(3)
|
|
188
|
-
expect(results[0].title).toBe('Action Only')
|
|
189
|
-
expect(results[0].score).toBe(2.0)
|
|
190
|
-
expect(results[1].title).toBe('Action Comedy')
|
|
191
|
-
expect(results[1].score).toBe(2.0)
|
|
192
|
-
expect(results[2].title).toBe('Comedy Only')
|
|
193
|
-
expect(results[2].score).toBe(1.0)
|
|
194
|
-
})
|
|
195
|
-
|
|
196
|
-
test('should support avg mode', async () => {
|
|
197
|
-
await db.insert({ id: 1, title: 'Mixed', terms: ['action', 'comedy'] })
|
|
198
|
-
await db.insert({ id: 2, title: 'Action Only', terms: ['action'] })
|
|
199
|
-
await db.insert({ id: 3, title: 'Comedy Only', terms: ['comedy'] })
|
|
200
|
-
await db.save()
|
|
201
|
-
|
|
202
|
-
const results = await db.score('terms', {
|
|
203
|
-
'action': 1.5,
|
|
204
|
-
'comedy': 0.9
|
|
205
|
-
}, { mode: 'avg' })
|
|
206
|
-
|
|
207
|
-
expect(results).toHaveLength(3)
|
|
208
|
-
expect(results[0].title).toBe('Action Only')
|
|
209
|
-
expect(results[0].score).toBeCloseTo(1.5)
|
|
210
|
-
expect(results[1].title).toBe('Mixed')
|
|
211
|
-
expect(results[1].score).toBeCloseTo((1.5 + 0.9) / 2)
|
|
212
|
-
expect(results[2].title).toBe('Comedy Only')
|
|
213
|
-
expect(results[2].score).toBeCloseTo(0.9)
|
|
214
|
-
})
|
|
215
|
-
|
|
216
|
-
test('should support first mode with term priority', async () => {
|
|
217
|
-
await db.insert({ id: 1, title: 'High Priority', terms: ['primary', 'secondary'] })
|
|
218
|
-
await db.insert({ id: 2, title: 'Secondary Only', terms: ['secondary'] })
|
|
219
|
-
await db.insert({ id: 3, title: 'Unmatched', terms: ['other'] })
|
|
220
|
-
await db.save()
|
|
221
|
-
|
|
222
|
-
const results = await db.score('terms', {
|
|
223
|
-
'primary': 5,
|
|
224
|
-
'secondary': 2
|
|
225
|
-
}, { mode: 'first' })
|
|
226
|
-
|
|
227
|
-
expect(results).toHaveLength(2)
|
|
228
|
-
expect(results[0].title).toBe('High Priority')
|
|
229
|
-
expect(results[0].score).toBe(5)
|
|
230
|
-
expect(results[1].title).toBe('Secondary Only')
|
|
231
|
-
expect(results[1].score).toBe(2)
|
|
232
|
-
})
|
|
233
|
-
})
|
|
234
|
-
|
|
235
|
-
describe('Edge Cases', () => {
|
|
236
|
-
test('should return empty array for empty scores', async () => {
|
|
237
|
-
await db.insert({ id: 1, title: 'Test', terms: ['a'] })
|
|
238
|
-
await db.save()
|
|
239
|
-
|
|
240
|
-
const results = await db.score('terms', {})
|
|
241
|
-
expect(results).toHaveLength(0)
|
|
242
|
-
})
|
|
243
|
-
|
|
244
|
-
test('should return empty array when no terms match', async () => {
|
|
245
|
-
await db.insert({ id: 1, title: 'Test', terms: ['a'] })
|
|
246
|
-
await db.save()
|
|
247
|
-
|
|
248
|
-
const results = await db.score('terms', {
|
|
249
|
-
'nonexistent': 1.0
|
|
250
|
-
})
|
|
251
|
-
|
|
252
|
-
expect(results).toHaveLength(0)
|
|
253
|
-
})
|
|
254
|
-
|
|
255
|
-
test('should handle empty database', async () => {
|
|
256
|
-
const results = await db.score('terms', {
|
|
257
|
-
'a': 1.0
|
|
258
|
-
})
|
|
259
|
-
|
|
260
|
-
expect(results).toHaveLength(0)
|
|
261
|
-
})
|
|
262
|
-
|
|
263
|
-
test('should handle multiple occurrences of same term', async () => {
|
|
264
|
-
await db.insert({ id: 1, title: 'Test 1', terms: ['important', 'important'] })
|
|
265
|
-
await db.insert({ id: 2, title: 'Test 2', terms: ['important'] })
|
|
266
|
-
await db.save()
|
|
267
|
-
|
|
268
|
-
const results = await db.score('terms', {
|
|
269
|
-
'important': 1.0
|
|
270
|
-
})
|
|
271
|
-
|
|
272
|
-
// Both should have score 1.0 (duplicates in array don't multiply score)
|
|
273
|
-
expect(results).toHaveLength(2)
|
|
274
|
-
})
|
|
275
|
-
})
|
|
276
|
-
|
|
277
|
-
describe('Error Handling', () => {
|
|
278
|
-
test('should throw error for invalid fieldName', async () => {
|
|
279
|
-
await expect(db.score('', { 'a': 1.0 })).rejects.toThrow('non-empty string')
|
|
280
|
-
await expect(db.score(null, { 'a': 1.0 })).rejects.toThrow('non-empty string')
|
|
281
|
-
})
|
|
282
|
-
|
|
283
|
-
test('should throw error for non-indexed field', async () => {
|
|
284
|
-
await expect(db.score('nonexistent', { 'a': 1.0 }))
|
|
285
|
-
.rejects.toThrow('not indexed')
|
|
286
|
-
})
|
|
287
|
-
|
|
288
|
-
test('should throw error for invalid scores object', async () => {
|
|
289
|
-
await expect(db.score('terms', null)).rejects.toThrow('must be an object')
|
|
290
|
-
await expect(db.score('terms', [])).rejects.toThrow('must be an object')
|
|
291
|
-
})
|
|
292
|
-
|
|
293
|
-
test('should throw error for non-numeric scores', async () => {
|
|
294
|
-
await expect(db.score('terms', { 'a': 'invalid' }))
|
|
295
|
-
.rejects.toThrow('must be a number')
|
|
296
|
-
})
|
|
297
|
-
})
|
|
298
|
-
})
|
package/test/setup.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
// Setup file to add Mocha-style matchers to Jest
|
|
2
|
-
import { expect } from '@jest/globals'
|
|
3
|
-
|
|
4
|
-
// Add the chai-style API to expect
|
|
5
|
-
expect.to = {
|
|
6
|
-
deep: {
|
|
7
|
-
equal: (received, expected) => {
|
|
8
|
-
return expect(received).toEqual(expected)
|
|
9
|
-
}
|
|
10
|
-
},
|
|
11
|
-
equal: (received, expected) => {
|
|
12
|
-
return expect(received).toBe(expected)
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
// Also add to global expect
|
|
17
|
-
global.expect = expect
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
import fs from 'fs'
|
|
2
|
-
import path from 'path'
|
|
3
|
-
import TermManager from '../src/managers/TermManager.mjs'
|
|
4
|
-
|
|
5
|
-
describe('Term Mapping - Minimal Tests', () => {
|
|
6
|
-
let termManager
|
|
7
|
-
|
|
8
|
-
beforeEach(() => {
|
|
9
|
-
termManager = new TermManager()
|
|
10
|
-
})
|
|
11
|
-
|
|
12
|
-
describe('TermManager', () => {
|
|
13
|
-
it('should create and retrieve term IDs', () => {
|
|
14
|
-
const id1 = termManager.getTermId('bra')
|
|
15
|
-
const id2 = termManager.getTermId('globo')
|
|
16
|
-
const id3 = termManager.getTermId('bra') // Same term
|
|
17
|
-
|
|
18
|
-
expect(id1).toBe(1)
|
|
19
|
-
expect(id2).toBe(2)
|
|
20
|
-
expect(id3).toBe(1) // Should return same ID
|
|
21
|
-
|
|
22
|
-
expect(termManager.getTerm(1)).toBe('bra')
|
|
23
|
-
expect(termManager.getTerm(2)).toBe('globo')
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
it('should track term usage counts', () => {
|
|
27
|
-
const id1 = termManager.getTermId('bra')
|
|
28
|
-
const id2 = termManager.getTermId('bra')
|
|
29
|
-
const id3 = termManager.getTermId('bra')
|
|
30
|
-
|
|
31
|
-
expect(termManager.termCounts.get(id1)).toBe(3)
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
it('should clean up orphaned terms', () => {
|
|
35
|
-
const id1 = termManager.getTermId('bra')
|
|
36
|
-
const id2 = termManager.getTermId('globo')
|
|
37
|
-
|
|
38
|
-
// Decrement counts to make them orphaned
|
|
39
|
-
termManager.decrementTermCount(id1)
|
|
40
|
-
termManager.decrementTermCount(id1)
|
|
41
|
-
termManager.decrementTermCount(id2)
|
|
42
|
-
|
|
43
|
-
const orphanedCount = termManager.cleanupOrphanedTerms(true)
|
|
44
|
-
expect(orphanedCount).toBe(2)
|
|
45
|
-
|
|
46
|
-
// Terms should be removed
|
|
47
|
-
expect(termManager.getTerm(id1)).toBeNull()
|
|
48
|
-
expect(termManager.getTerm(id2)).toBeNull()
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
it('should load and save terms', () => {
|
|
52
|
-
// Create some terms
|
|
53
|
-
termManager.getTermId('bra')
|
|
54
|
-
termManager.getTermId('globo')
|
|
55
|
-
termManager.getTermId('brasil')
|
|
56
|
-
|
|
57
|
-
// Save terms
|
|
58
|
-
const savedTerms = termManager.saveTerms()
|
|
59
|
-
expect(savedTerms).toEqual({
|
|
60
|
-
'1': 'bra',
|
|
61
|
-
'2': 'globo',
|
|
62
|
-
'3': 'brasil'
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
// Create new manager and load terms
|
|
66
|
-
const newManager = new TermManager()
|
|
67
|
-
newManager.loadTerms(savedTerms)
|
|
68
|
-
|
|
69
|
-
expect(newManager.getTerm(1)).toBe('bra')
|
|
70
|
-
expect(newManager.getTerm(2)).toBe('globo')
|
|
71
|
-
expect(newManager.getTerm(3)).toBe('brasil')
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
it('should provide statistics', () => {
|
|
75
|
-
termManager.getTermId('bra')
|
|
76
|
-
termManager.getTermId('globo')
|
|
77
|
-
|
|
78
|
-
const stats = termManager.getStats()
|
|
79
|
-
expect(stats.totalTerms).toBe(2)
|
|
80
|
-
expect(stats.nextId).toBe(3)
|
|
81
|
-
})
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
describe('Term Mapping Concept', () => {
|
|
85
|
-
it('should demonstrate term mapping benefits', () => {
|
|
86
|
-
// Simulate a large dataset with repeated terms
|
|
87
|
-
const terms = ['bra', 'globo', 'brasil', 'discovery', 'channel']
|
|
88
|
-
const repeatedTerms = []
|
|
89
|
-
|
|
90
|
-
// Create 1000 records with repeated terms
|
|
91
|
-
for (let i = 0; i < 1000; i++) {
|
|
92
|
-
const randomTerms = []
|
|
93
|
-
for (let j = 0; j < 5; j++) {
|
|
94
|
-
randomTerms.push(terms[Math.floor(Math.random() * terms.length)])
|
|
95
|
-
}
|
|
96
|
-
repeatedTerms.push(randomTerms)
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Map all terms to IDs
|
|
100
|
-
const startTime = Date.now()
|
|
101
|
-
const mappedData = repeatedTerms.map(record =>
|
|
102
|
-
record.map(term => termManager.getTermId(term))
|
|
103
|
-
)
|
|
104
|
-
const mappingTime = Date.now() - startTime
|
|
105
|
-
|
|
106
|
-
// Verify mapping worked
|
|
107
|
-
expect(mappedData.length).toBe(1000)
|
|
108
|
-
expect(mappedData[0].length).toBe(5)
|
|
109
|
-
expect(termManager.getStats().totalTerms).toBe(5) // Only 5 unique terms
|
|
110
|
-
|
|
111
|
-
console.log(`✅ Mapped 5000 terms to 5 unique IDs in ${mappingTime}ms`)
|
|
112
|
-
console.log(`📊 Term mapping stats:`, termManager.getStats())
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
it('should show size reduction potential', () => {
|
|
116
|
-
// Original data with repeated strings
|
|
117
|
-
const originalData = [
|
|
118
|
-
{ id: 1, nameTerms: ['bra', 'globo', 'brasil'] },
|
|
119
|
-
{ id: 2, nameTerms: ['bra', 'discovery', 'channel'] },
|
|
120
|
-
{ id: 3, nameTerms: ['globo', 'brasil', 'discovery'] },
|
|
121
|
-
{ id: 4, nameTerms: ['bra', 'globo', 'channel'] },
|
|
122
|
-
{ id: 5, nameTerms: ['brasil', 'discovery', 'channel'] }
|
|
123
|
-
]
|
|
124
|
-
|
|
125
|
-
// Calculate original size
|
|
126
|
-
const originalSize = JSON.stringify(originalData).length
|
|
127
|
-
|
|
128
|
-
// Map terms to IDs
|
|
129
|
-
const mappedData = originalData.map(record => ({
|
|
130
|
-
id: record.id,
|
|
131
|
-
nameTerms: record.nameTerms.map(term => termManager.getTermId(term))
|
|
132
|
-
}))
|
|
133
|
-
|
|
134
|
-
// Create term mapping
|
|
135
|
-
const termMapping = termManager.saveTerms()
|
|
136
|
-
|
|
137
|
-
// Calculate new size
|
|
138
|
-
const mappedSize = JSON.stringify(mappedData).length
|
|
139
|
-
const termMappingSize = JSON.stringify(termMapping).length
|
|
140
|
-
const totalNewSize = mappedSize + termMappingSize
|
|
141
|
-
|
|
142
|
-
const reduction = ((originalSize - totalNewSize) / originalSize * 100).toFixed(1)
|
|
143
|
-
|
|
144
|
-
console.log(`📊 Size comparison:`)
|
|
145
|
-
console.log(` Original: ${originalSize} bytes`)
|
|
146
|
-
console.log(` Mapped: ${mappedSize} bytes`)
|
|
147
|
-
console.log(` Terms: ${termMappingSize} bytes`)
|
|
148
|
-
console.log(` Total: ${totalNewSize} bytes`)
|
|
149
|
-
console.log(` Reduction: ${reduction}%`)
|
|
150
|
-
|
|
151
|
-
expect(totalNewSize).toBeLessThan(originalSize)
|
|
152
|
-
})
|
|
153
|
-
})
|
|
154
|
-
})
|