get-indexes-from-filter_test.go raw
1 package database
2
3 import (
4 "bytes"
5 "math"
6 "testing"
7
8 "next.orly.dev/pkg/lol/chk"
9 "github.com/minio/sha256-simd"
10 "next.orly.dev/pkg/database/indexes"
11 types2 "next.orly.dev/pkg/database/indexes/types"
12 "next.orly.dev/pkg/nostr/encoders/filter"
13 "next.orly.dev/pkg/nostr/encoders/kind"
14 "next.orly.dev/pkg/nostr/encoders/tag"
15 "next.orly.dev/pkg/nostr/encoders/timestamp"
16 "next.orly.dev/pkg/utils"
17 )
18
19 // TestGetIndexesFromFilter tests the GetIndexesFromFilter function
20 func TestGetIndexesFromFilter(t *testing.T) {
21 t.Run("ID", testIdFilter)
22 t.Run("Pubkey", testPubkeyFilter)
23 t.Run("CreatedAt", testCreatedAtFilter)
24 t.Run("CreatedAtUntil", testCreatedAtUntilFilter)
25 t.Run("TagPubkey", testPubkeyTagFilter)
26 t.Run("Tag", testTagFilter)
27 t.Run("Kind", testKindFilter)
28 t.Run("KindPubkey", testKindPubkeyFilter)
29 t.Run("MultipleKindPubkey", testMultipleKindPubkeyFilter)
30 t.Run("TagKind", testKindTagFilter)
31 t.Run("TagKindPubkey", testKindPubkeyTagFilter)
32 }
33
34 // Helper function to verify that the generated index matches the expected indexes
35 func verifyIndex(
36 t *testing.T, idxs []Range, expectedStartIdx, expectedEndIdx *indexes.T,
37 ) {
38 if len(idxs) != 1 {
39 t.Fatalf("Expected 1 index, got %d", len(idxs))
40 }
41
42 // Marshal the expected start index
43 startBuf := new(bytes.Buffer)
44 err := expectedStartIdx.MarshalWrite(startBuf)
45 if chk.E(err) {
46 t.Fatalf("Failed to marshal expected start index: %v", err)
47 }
48
49 // Compare the generated start index with the expected start index
50 if !utils.FastEqual(idxs[0].Start, startBuf.Bytes()) {
51 t.Errorf("Generated start index does not match expected start index")
52 t.Errorf("Generated: %v", idxs[0].Start)
53 t.Errorf("Expected: %v", startBuf.Bytes())
54 }
55
56 // If expectedEndIdx is nil, use expectedStartIdx
57 endIdx := expectedEndIdx
58 if endIdx == nil {
59 endIdx = expectedStartIdx
60 }
61
62 // Marshal the expected end index
63 endBuf := new(bytes.Buffer)
64 err = endIdx.MarshalWrite(endBuf)
65 if chk.E(err) {
66 t.Fatalf("Failed to marshal expected End index: %v", err)
67 }
68
69 // Compare the generated end index with the expected end index
70 if !utils.FastEqual(idxs[0].End, endBuf.Bytes()) {
71 t.Errorf("Generated End index does not match expected End index")
72 t.Errorf("Generated: %v", idxs[0].End)
73 t.Errorf("Expected: %v", endBuf.Bytes())
74 }
75 }
76
77 // Test ID filter
78 func testIdFilter(t *testing.T) {
79 // Create a filter with an ID
80 f := filter.New()
81 id := make([]byte, sha256.Size)
82 for i := range id {
83 id[i] = byte(i)
84 }
85 f.Ids.T = append(f.Ids.T, id)
86
87 // Generate indexes
88 idxs, err := GetIndexesFromFilter(f)
89 if chk.E(err) {
90 t.Fatalf("GetIndexesFromFilter failed: %v", err)
91 }
92
93 // Create the expected index
94 idHash := new(types2.IdHash)
95 err = idHash.FromId(id)
96 if chk.E(err) {
97 t.Fatalf("Failed to create IdHash: %v", err)
98 }
99 expectedIdx := indexes.IdEnc(idHash, nil)
100
101 // Verify the generated index
102 // For ID filter, both start and end indexes are the same
103 verifyIndex(t, idxs, expectedIdx, expectedIdx)
104 }
105
106 // Test Pubkey filter
107 func testPubkeyFilter(t *testing.T) {
108 // Create a filter with an Author, Since, and Until
109 f := filter.New()
110 pubkey := make([]byte, 32)
111 for i := range pubkey {
112 pubkey[i] = byte(i)
113 }
114 f.Authors.T = append(f.Authors.T, pubkey)
115 f.Since = timestamp.FromUnix(12345)
116 f.Until = timestamp.FromUnix(67890) // Added Until field
117
118 // Generate indexes
119 idxs, err := GetIndexesFromFilter(f)
120 if chk.E(err) {
121 t.Fatalf("GetIndexesFromFilter failed: %v", err)
122 }
123
124 // Create the expected indexes
125 p := new(types2.PubHash)
126 err = p.FromPubkey(pubkey)
127 if chk.E(err) {
128 t.Fatalf("Failed to create PubHash: %v", err)
129 }
130
131 // Start index uses Since
132 caStart := new(types2.Uint64)
133 caStart.Set(uint64(f.Since.V))
134 expectedStartIdx := indexes.PubkeyEnc(p, caStart, nil)
135
136 // End index uses Until
137 caEnd := new(types2.Uint64)
138 caEnd.Set(uint64(f.Until.V))
139 expectedEndIdx := indexes.PubkeyEnc(p, caEnd, nil)
140
141 // Verify the generated index
142 verifyIndex(t, idxs, expectedStartIdx, expectedEndIdx)
143 }
144
145 // Test CreatedAt filter
146 func testCreatedAtFilter(t *testing.T) {
147 // Create a filter with Since
148 f := filter.New()
149 f.Since = timestamp.FromUnix(12345)
150
151 // Generate indexes
152 idxs, err := GetIndexesFromFilter(f)
153 if chk.E(err) {
154 t.Fatalf("GetIndexesFromFilter failed: %v", err)
155 }
156
157 // Create the expected start index (using Since)
158 caStart := new(types2.Uint64)
159 caStart.Set(uint64(f.Since.V))
160 expectedStartIdx := indexes.CreatedAtEnc(caStart, nil)
161
162 // Create the expected end index (using math.MaxInt64 since Until is not specified)
163 caEnd := new(types2.Uint64)
164 caEnd.Set(uint64(math.MaxInt64))
165 expectedEndIdx := indexes.CreatedAtEnc(caEnd, nil)
166
167 // Verify the generated index
168 verifyIndex(t, idxs, expectedStartIdx, expectedEndIdx)
169 }
170
171 // Test CreatedAt filter with Until
172 func testCreatedAtUntilFilter(t *testing.T) {
173 // Create a filter with Until
174 f := filter.New()
175 f.Until = timestamp.FromUnix(67890)
176
177 // Generate indexes
178 idxs, err := GetIndexesFromFilter(f)
179 if chk.E(err) {
180 t.Fatalf("GetIndexesFromFilter failed: %v", err)
181 }
182
183 // Create the expected start index (using 0 since Since is not specified)
184 caStart := new(types2.Uint64)
185 caStart.Set(uint64(0))
186 expectedStartIdx := indexes.CreatedAtEnc(caStart, nil)
187
188 // Create the expected end index (using Until)
189 caEnd := new(types2.Uint64)
190 caEnd.Set(uint64(f.Until.V))
191 expectedEndIdx := indexes.CreatedAtEnc(caEnd, nil)
192
193 // Verify the generated index
194 verifyIndex(t, idxs, expectedStartIdx, expectedEndIdx)
195 }
196
197 // Test TagPubkey filter
198 func testPubkeyTagFilter(t *testing.T) {
199 // Create a filter with an Author, a Tag, and Since
200 f := filter.New()
201 pubkey := make([]byte, 32)
202 for i := range pubkey {
203 pubkey[i] = byte(i)
204 }
205 f.Authors.T = append(f.Authors.T, pubkey)
206 // Create a tag
207 tagKey := "e"
208 tagValue := "test-value"
209 tagT := tag.NewFromAny(tagKey, tagValue)
210 *f.Tags = append(*f.Tags, tagT)
211
212 f.Since = timestamp.FromUnix(12345)
213
214 // Generate indexes
215 idxs, err := GetIndexesFromFilter(f)
216 if chk.E(err) {
217 t.Fatalf("GetIndexesFromFilter failed: %v", err)
218 }
219
220 // Create the expected indexes
221 p := new(types2.PubHash)
222 err = p.FromPubkey(pubkey)
223 if chk.E(err) {
224 t.Fatalf("Failed to create PubHash: %v", err)
225 }
226 key := new(types2.Letter)
227 key.Set(tagKey[0])
228 valueHash := new(types2.Ident)
229 valueHash.FromIdent([]byte(tagValue))
230
231 // Start index uses Since
232 caStart := new(types2.Uint64)
233 caStart.Set(uint64(f.Since.V))
234 expectedStartIdx := indexes.TagPubkeyEnc(key, valueHash, p, caStart, nil)
235
236 // End index uses math.MaxInt64 since Until is not specified
237 caEnd := new(types2.Uint64)
238 caEnd.Set(uint64(math.MaxInt64))
239 expectedEndIdx := indexes.TagPubkeyEnc(key, valueHash, p, caEnd, nil)
240
241 // Verify the generated index
242 verifyIndex(t, idxs, expectedStartIdx, expectedEndIdx)
243 }
244
245 // Test Tag filter
246 func testTagFilter(t *testing.T) {
247 // Create a filter with a Tag and Since
248 f := filter.New()
249
250 // Create a tag
251 tagKey := "e"
252 tagValue := "test-value"
253 tagT := tag.NewFromAny(tagKey, tagValue)
254 *f.Tags = append(*f.Tags, tagT)
255
256 f.Since = timestamp.FromUnix(12345)
257
258 // Generate indexes
259 idxs, err := GetIndexesFromFilter(f)
260 if chk.E(err) {
261 t.Fatalf("GetIndexesFromFilter failed: %v", err)
262 }
263
264 // Create the expected indexes
265 key := new(types2.Letter)
266 key.Set(tagKey[0])
267 valueHash := new(types2.Ident)
268 valueHash.FromIdent([]byte(tagValue))
269
270 // Start index uses Since
271 caStart := new(types2.Uint64)
272 caStart.Set(uint64(f.Since.V))
273 expectedStartIdx := indexes.TagEnc(key, valueHash, caStart, nil)
274
275 // End index uses math.MaxInt64 since Until is not specified
276 caEnd := new(types2.Uint64)
277 caEnd.Set(uint64(math.MaxInt64))
278 expectedEndIdx := indexes.TagEnc(key, valueHash, caEnd, nil)
279
280 // Verify the generated index
281 verifyIndex(t, idxs, expectedStartIdx, expectedEndIdx)
282 }
283
284 // Test Kind filter
285 func testKindFilter(t *testing.T) {
286 // Create a filter with a Kind and Since
287 f := filter.New()
288 f.Kinds = kind.NewS(kind.TextNote)
289 f.Since = timestamp.FromUnix(12345)
290
291 // Generate indexes
292 idxs, err := GetIndexesFromFilter(f)
293 if chk.E(err) {
294 t.Fatalf("GetIndexesFromFilter failed: %v", err)
295 }
296
297 // Create the expected indexes
298 k := new(types2.Uint16)
299 k.Set(1)
300
301 // Start index uses Since
302 caStart := new(types2.Uint64)
303 caStart.Set(uint64(f.Since.V))
304 expectedStartIdx := indexes.KindEnc(k, caStart, nil)
305
306 // End index uses math.MaxInt64 since Until is not specified
307 caEnd := new(types2.Uint64)
308 caEnd.Set(uint64(math.MaxInt64))
309 expectedEndIdx := indexes.KindEnc(k, caEnd, nil)
310
311 // Verify the generated index
312 verifyIndex(t, idxs, expectedStartIdx, expectedEndIdx)
313 }
314
315 // Test KindPubkey filter
316 func testKindPubkeyFilter(t *testing.T) {
317 // Create a filter with a Kind, an Author, and Since
318 f := filter.New()
319 f.Kinds = kind.NewS(kind.TextNote)
320 pubkey := make([]byte, 32)
321 for i := range pubkey {
322 pubkey[i] = byte(i)
323 }
324 f.Authors.T = append(f.Authors.T, pubkey)
325 f.Since = timestamp.FromUnix(12345)
326
327 // Generate indexes
328 idxs, err := GetIndexesFromFilter(f)
329 if chk.E(err) {
330 t.Fatalf("GetIndexesFromFilter failed: %v", err)
331 }
332
333 // Create the expected indexes
334 k := new(types2.Uint16)
335 k.Set(1)
336 p := new(types2.PubHash)
337 err = p.FromPubkey(pubkey)
338 if chk.E(err) {
339 t.Fatalf("Failed to create PubHash: %v", err)
340 }
341
342 // Start index uses Since
343 caStart := new(types2.Uint64)
344 caStart.Set(uint64(f.Since.V))
345 expectedStartIdx := indexes.KindPubkeyEnc(k, p, caStart, nil)
346
347 // End index uses math.MaxInt64 since Until is not specified
348 caEnd := new(types2.Uint64)
349 caEnd.Set(uint64(math.MaxInt64))
350 expectedEndIdx := indexes.KindPubkeyEnc(k, p, caEnd, nil)
351
352 // Verify the generated index
353 verifyIndex(t, idxs, expectedStartIdx, expectedEndIdx)
354 }
355
356 // Test TagKind filter
357 func testKindTagFilter(t *testing.T) {
358 // Create a filter with a Kind, a Tag, and Since
359 f := filter.New()
360 f.Kinds = kind.NewS(kind.TextNote)
361
362 // Create a tag
363 tagKey := "e"
364 tagValue := "test-value"
365 tagT := tag.NewFromAny(tagKey, tagValue)
366 *f.Tags = append(*f.Tags, tagT)
367
368 f.Since = timestamp.FromUnix(12345)
369
370 // Generate indexes
371 idxs, err := GetIndexesFromFilter(f)
372 if chk.E(err) {
373 t.Fatalf("GetIndexesFromFilter failed: %v", err)
374 }
375
376 // Create the expected indexes
377 k := new(types2.Uint16)
378 k.Set(1)
379 key := new(types2.Letter)
380 key.Set(tagKey[0])
381 valueHash := new(types2.Ident)
382 valueHash.FromIdent([]byte(tagValue))
383
384 // Start index uses Since
385 caStart := new(types2.Uint64)
386 caStart.Set(uint64(f.Since.V))
387 expectedStartIdx := indexes.TagKindEnc(key, valueHash, k, caStart, nil)
388
389 // End index uses math.MaxInt64 since Until is not specified
390 caEnd := new(types2.Uint64)
391 caEnd.Set(uint64(math.MaxInt64))
392 expectedEndIdx := indexes.TagKindEnc(key, valueHash, k, caEnd, nil)
393
394 // Verify the generated index
395 verifyIndex(t, idxs, expectedStartIdx, expectedEndIdx)
396 }
397
398 // Test Multiple KindPubkey filter
399 func testMultipleKindPubkeyFilter(t *testing.T) {
400 // Create a filter with multiple Kinds and multiple Authors
401 f := filter.New()
402 f.Kinds = kind.NewS(kind.New(1), kind.New(2))
403
404 // Create two pubkeys
405 pubkey1 := make([]byte, 32)
406 pubkey2 := make([]byte, 32)
407 for i := range pubkey1 {
408 pubkey1[i] = byte(i)
409 pubkey2[i] = byte(i + 100)
410 }
411 f.Authors.T = append(f.Authors.T, pubkey1)
412 f.Authors.T = append(f.Authors.T, pubkey2)
413 f.Since = timestamp.FromUnix(12345)
414
415 // Generate indexes
416 idxs, err := GetIndexesFromFilter(f)
417 if chk.E(err) {
418 t.Fatalf("GetIndexesFromFilter failed: %v", err)
419 }
420
421 // We should have 4 indexes (2 kinds * 2 pubkeys)
422 if len(idxs) != 4 {
423 t.Fatalf("Expected 4 indexes, got %d", len(idxs))
424 }
425
426 // Create the expected indexes
427 k1 := new(types2.Uint16)
428 k1.Set(1)
429 k2 := new(types2.Uint16)
430 k2.Set(2)
431
432 p1 := new(types2.PubHash)
433 err = p1.FromPubkey(pubkey1)
434 if chk.E(err) {
435 t.Fatalf("Failed to create PubHash: %v", err)
436 }
437
438 p2 := new(types2.PubHash)
439 err = p2.FromPubkey(pubkey2)
440 if chk.E(err) {
441 t.Fatalf("Failed to create PubHash: %v", err)
442 }
443
444 // Start index uses Since
445 caStart := new(types2.Uint64)
446 caStart.Set(uint64(f.Since.V))
447
448 // End index uses math.MaxInt64 since Until is not specified
449 caEnd := new(types2.Uint64)
450 caEnd.Set(uint64(math.MaxInt64))
451
452 // Create all expected combinations
453 expectedIdxs := make([][]byte, 8) // 4 combinations * 2 (start/end)
454
455 // Kind 1, Pubkey 1
456 startBuf1 := new(bytes.Buffer)
457 idxS1 := indexes.KindPubkeyEnc(k1, p1, caStart, nil)
458 if err = idxS1.MarshalWrite(startBuf1); chk.E(err) {
459 t.Fatalf("Failed to marshal index: %v", err)
460 }
461 expectedIdxs[0] = startBuf1.Bytes()
462
463 endBuf1 := new(bytes.Buffer)
464 idxE1 := indexes.KindPubkeyEnc(k1, p1, caEnd, nil)
465 if err = idxE1.MarshalWrite(endBuf1); chk.E(err) {
466 t.Fatalf("Failed to marshal index: %v", err)
467 }
468 expectedIdxs[1] = endBuf1.Bytes()
469
470 // Kind 1, Pubkey 2
471 startBuf2 := new(bytes.Buffer)
472 idxS2 := indexes.KindPubkeyEnc(k1, p2, caStart, nil)
473 if err = idxS2.MarshalWrite(startBuf2); chk.E(err) {
474 t.Fatalf("Failed to marshal index: %v", err)
475 }
476 expectedIdxs[2] = startBuf2.Bytes()
477
478 endBuf2 := new(bytes.Buffer)
479 idxE2 := indexes.KindPubkeyEnc(k1, p2, caEnd, nil)
480 if err = idxE2.MarshalWrite(endBuf2); chk.E(err) {
481 t.Fatalf("Failed to marshal index: %v", err)
482 }
483 expectedIdxs[3] = endBuf2.Bytes()
484
485 // Kind 2, Pubkey 1
486 startBuf3 := new(bytes.Buffer)
487 idxS3 := indexes.KindPubkeyEnc(k2, p1, caStart, nil)
488 if err = idxS3.MarshalWrite(startBuf3); chk.E(err) {
489 t.Fatalf("Failed to marshal index: %v", err)
490 }
491 expectedIdxs[4] = startBuf3.Bytes()
492
493 endBuf3 := new(bytes.Buffer)
494 idxE3 := indexes.KindPubkeyEnc(k2, p1, caEnd, nil)
495 if err = idxE3.MarshalWrite(endBuf3); chk.E(err) {
496 t.Fatalf("Failed to marshal index: %v", err)
497 }
498 expectedIdxs[5] = endBuf3.Bytes()
499
500 // Kind 2, Pubkey 2
501 startBuf4 := new(bytes.Buffer)
502 idxS4 := indexes.KindPubkeyEnc(k2, p2, caStart, nil)
503 if err = idxS4.MarshalWrite(startBuf4); chk.E(err) {
504 t.Fatalf("Failed to marshal index: %v", err)
505 }
506 expectedIdxs[6] = startBuf4.Bytes()
507
508 endBuf4 := new(bytes.Buffer)
509 idxE4 := indexes.KindPubkeyEnc(k2, p2, caEnd, nil)
510 if err = idxE4.MarshalWrite(endBuf4); chk.E(err) {
511 t.Fatalf("Failed to marshal index: %v", err)
512 }
513 expectedIdxs[7] = endBuf4.Bytes()
514
515 // Verify that all expected combinations are present
516 foundCombinations := 0
517 for _, idx := range idxs {
518 for i := 0; i < len(expectedIdxs); i += 2 {
519 if utils.FastEqual(idx.Start, expectedIdxs[i]) && utils.FastEqual(
520 idx.End, expectedIdxs[i+1],
521 ) {
522 foundCombinations++
523 break
524 }
525 }
526 }
527
528 if foundCombinations != 4 {
529 t.Fatalf("Expected to find 4 combinations, found %d", foundCombinations)
530 }
531 }
532
533 // Test TagKindPubkey filter
534 func testKindPubkeyTagFilter(t *testing.T) {
535 // Create a filter with a Kind, an Author, a Tag, and Since
536 f := filter.New()
537 f.Kinds = kind.NewS(kind.New(1))
538 pubkey := make([]byte, 32)
539 for i := range pubkey {
540 pubkey[i] = byte(i)
541 }
542 f.Authors.T = append(f.Authors.T, pubkey)
543
544 // Create a tag
545 tagKey := "e"
546 tagValue := "test-value"
547 tagT := tag.NewFromAny(tagKey, tagValue)
548 *f.Tags = append(*f.Tags, tagT)
549
550 f.Since = timestamp.FromUnix(12345)
551
552 // Generate indexes
553 idxs, err := GetIndexesFromFilter(f)
554 if chk.E(err) {
555 t.Fatalf("GetIndexesFromFilter failed: %v", err)
556 }
557
558 // Create the expected indexes
559 k := new(types2.Uint16)
560 k.Set(1)
561 p := new(types2.PubHash)
562 err = p.FromPubkey(pubkey)
563 if chk.E(err) {
564 t.Fatalf("Failed to create PubHash: %v", err)
565 }
566 key := new(types2.Letter)
567 key.Set(tagKey[0])
568 valueHash := new(types2.Ident)
569 valueHash.FromIdent([]byte(tagValue))
570
571 // Start index uses Since
572 caStart := new(types2.Uint64)
573 caStart.Set(uint64(f.Since.V))
574 expectedStartIdx := indexes.TagKindPubkeyEnc(
575 key, valueHash, k, p, caStart, nil,
576 )
577
578 // End index uses math.MaxInt64 since Until is not specified
579 caEnd := new(types2.Uint64)
580 caEnd.Set(uint64(math.MaxInt64))
581 expectedEndIdx := indexes.TagKindPubkeyEnc(
582 key, valueHash, k, p, caEnd, nil,
583 )
584
585 // Verify the generated index
586 verifyIndex(t, idxs, expectedStartIdx, expectedEndIdx)
587 }
588