jexidb 2.1.0 → 2.1.1

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.
@@ -0,0 +1,154 @@
1
+ import { Database } from '../src/Database.mjs'
2
+ import fs from 'fs'
3
+
4
+ describe('Legacy operator compatibility', () => {
5
+ let testDbPath
6
+ let testIdxPath
7
+
8
+ beforeEach(() => {
9
+ const uniqueSuffix = `${Date.now()}-${Math.random().toString(36).slice(2)}`
10
+ testDbPath = `test-legacy-operators-${uniqueSuffix}.jdb`
11
+ testIdxPath = testDbPath.replace('.jdb', '.idx.jdb')
12
+ })
13
+
14
+ afterEach(() => {
15
+ for (const filePath of [testDbPath, testIdxPath]) {
16
+ if (filePath && fs.existsSync(filePath)) {
17
+ try {
18
+ fs.unlinkSync(filePath)
19
+ } catch (error) {
20
+ console.warn(`⚠️ Failed to delete ${filePath}: ${error.message}`)
21
+ }
22
+ }
23
+ }
24
+ })
25
+
26
+ test('should support string comparison operators for find/count', async () => {
27
+ const db = new Database(testDbPath, {
28
+ indexes: {
29
+ start: 'number',
30
+ end: 'number'
31
+ },
32
+ termMapping: true,
33
+ debugMode: false
34
+ })
35
+ await db.init()
36
+
37
+ const now = Math.floor(Date.now() / 1000)
38
+
39
+ await db.insert({
40
+ id: '1',
41
+ start: now - 60,
42
+ end: now + 60
43
+ })
44
+
45
+ await db.insert({
46
+ id: '2',
47
+ start: now - 3600,
48
+ end: now - 300
49
+ })
50
+
51
+ const legacyCount = await db.count({ end: { '>': now } })
52
+ const mongoCount = await db.count({ end: { $gt: now } })
53
+ expect(legacyCount).toBe(1)
54
+ expect(legacyCount).toBe(mongoCount)
55
+
56
+ const legacyResults = await db.find({
57
+ start: { '<=': now },
58
+ end: { '>': now }
59
+ })
60
+ const canonicalResults = await db.find({
61
+ start: { $lte: now },
62
+ end: { $gt: now }
63
+ })
64
+ const mongoResults = await db.find({
65
+ start: { $lte: now },
66
+ end: { $gt: now }
67
+ })
68
+
69
+ expect(legacyResults.map(record => record.id)).toEqual(['1'])
70
+ expect(canonicalResults.map(record => record.id)).toEqual(['1'])
71
+ expect(mongoResults.map(record => record.id)).toEqual(['1'])
72
+
73
+ await db.save()
74
+ await db.destroy()
75
+ })
76
+
77
+ test('should support string inequality operator', async () => {
78
+ const db = new Database(testDbPath, {
79
+ indexes: {
80
+ end: 'number'
81
+ },
82
+ termMapping: true,
83
+ debugMode: false
84
+ })
85
+ await db.init()
86
+
87
+ const now = Math.floor(Date.now() / 1000)
88
+
89
+ await db.insert({
90
+ id: 'A',
91
+ end: now + 120
92
+ })
93
+
94
+ await db.insert({
95
+ id: 'B',
96
+ end: now + 240
97
+ })
98
+
99
+ const legacyResults = await db.find({
100
+ end: { '!=': now + 120 }
101
+ })
102
+
103
+ expect(legacyResults.map(record => record.id)).toEqual(['B'])
104
+
105
+ await db.save()
106
+ await db.destroy()
107
+ })
108
+
109
+ test('should support mongo-style comparison operators when using indexes', async () => {
110
+ const db = new Database(testDbPath, {
111
+ indexes: {
112
+ numericField: 'number'
113
+ },
114
+ debugMode: false
115
+ })
116
+ await db.init()
117
+
118
+ await db.insert({ id: '10', numericField: 100 })
119
+ await db.insert({ id: '20', numericField: 200 })
120
+
121
+ await db.save()
122
+ await db.close()
123
+
124
+ const reopenedDb = new Database(testDbPath, {
125
+ create: false,
126
+ indexes: {
127
+ numericField: 'number'
128
+ },
129
+ debugMode: false
130
+ })
131
+ await reopenedDb.init()
132
+
133
+ const greaterThanResults = await reopenedDb.find({ numericField: { $gt: 150 } })
134
+ expect(greaterThanResults.map(record => record.id)).toEqual(['20'])
135
+
136
+ const greaterOrEqualResults = await reopenedDb.find({ numericField: { $gte: 200 } })
137
+ expect(greaterOrEqualResults.map(record => record.id)).toEqual(['20'])
138
+
139
+ const lessThanResults = await reopenedDb.find({ numericField: { $lt: 150 } })
140
+ expect(lessThanResults.map(record => record.id)).toEqual(['10'])
141
+
142
+ const lessOrEqualResults = await reopenedDb.find({ numericField: { $lte: 100 } })
143
+ expect(lessOrEqualResults.map(record => record.id)).toEqual(['10'])
144
+
145
+ const notEqualResults = await reopenedDb.find({ numericField: { $ne: 100 } })
146
+ expect(notEqualResults.map(record => record.id)).toEqual(['20'])
147
+
148
+ const countResults = await reopenedDb.count({ numericField: { $gt: 50, $lt: 250 } })
149
+ expect(countResults).toBe(2)
150
+
151
+ await reopenedDb.destroy()
152
+ })
153
+ })
154
+
@@ -172,6 +172,66 @@ describe('Score Method Tests', () => {
172
172
  })
173
173
  })
174
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
+
175
235
  describe('Edge Cases', () => {
176
236
  test('should return empty array for empty scores', async () => {
177
237
  await db.insert({ id: 1, title: 'Test', terms: ['a'] })