query-for-serials_test.go raw

   1  package database
   2  
   3  import (
   4  	"bufio"
   5  	"bytes"
   6  	"context"
   7  	"os"
   8  	"sort"
   9  	"testing"
  10  
  11  	"next.orly.dev/pkg/nostr/encoders/event"
  12  	"next.orly.dev/pkg/nostr/encoders/event/examples"
  13  	"next.orly.dev/pkg/nostr/encoders/filter"
  14  	"next.orly.dev/pkg/nostr/encoders/kind"
  15  	"next.orly.dev/pkg/nostr/encoders/tag"
  16  	"next.orly.dev/pkg/nostr/encoders/timestamp"
  17  	"next.orly.dev/pkg/lol/chk"
  18  	"next.orly.dev/pkg/database/indexes/types"
  19  	"next.orly.dev/pkg/utils"
  20  )
  21  
  22  func TestQueryForSerials(t *testing.T) {
  23  	// Create a temporary directory for the database
  24  	tempDir, err := os.MkdirTemp("", "test-db-*")
  25  	if err != nil {
  26  		t.Fatalf("Failed to create temporary directory: %v", err)
  27  	}
  28  	defer os.RemoveAll(tempDir) // Clean up after the test
  29  
  30  	// Create a context and cancel function for the database
  31  	ctx, cancel := context.WithCancel(context.Background())
  32  	defer cancel()
  33  
  34  	// Initialize the database
  35  	db, err := New(ctx, cancel, tempDir, "info")
  36  	if err != nil {
  37  		t.Fatalf("Failed to create database: %v", err)
  38  	}
  39  	defer db.Close()
  40  
  41  	// Create a scanner to read events from examples.Cache
  42  	scanner := bufio.NewScanner(bytes.NewBuffer(examples.Cache))
  43  	scanner.Buffer(make([]byte, 0, 1_000_000_000), 1_000_000_000)
  44  
  45  	// Count the number of events processed
  46  	eventCount := 0
  47  
  48  	var events []*event.E
  49  	var eventSerials = make(map[string]*types.Uint40) // Map event ID (hex) to serial
  50  
  51  	// First, collect all events from examples.Cache
  52  	for scanner.Scan() {
  53  		chk.E(scanner.Err())
  54  		b := scanner.Bytes()
  55  		ev := event.New()
  56  
  57  		// Unmarshal the event
  58  		if _, err = ev.Unmarshal(b); chk.E(err) {
  59  			ev.Free()
  60  			t.Fatal(err)
  61  		}
  62  
  63  		events = append(events, ev)
  64  	}
  65  
  66  	// Check for scanner errors
  67  	if err = scanner.Err(); err != nil {
  68  		t.Fatalf("Scanner error: %v", err)
  69  	}
  70  
  71  	// Sort events by CreatedAt to ensure addressable events are processed in chronological order
  72  	sort.Slice(events, func(i, j int) bool {
  73  		return events[i].CreatedAt < events[j].CreatedAt
  74  	})
  75  
  76  	// Count the number of events processed
  77  	eventCount = 0
  78  	skippedCount := 0
  79  
  80  	// Now process each event in chronological order
  81  	for _, ev := range events {
  82  		// Save the event to the database
  83  		if _, err = db.SaveEvent(ctx, ev); err != nil {
  84  			// Skip events that fail validation (e.g., kind 3 without p tags)
  85  			skippedCount++
  86  			continue
  87  		}
  88  
  89  		// Get the serial for this event
  90  		serial, err := db.GetSerialById(ev.ID)
  91  		if err != nil {
  92  			t.Fatalf(
  93  				"Failed to get serial for event #%d: %v", eventCount+1, err,
  94  			)
  95  		}
  96  
  97  		if serial != nil {
  98  			eventSerials[string(ev.ID)] = serial
  99  		}
 100  
 101  		eventCount++
 102  	}
 103  
 104  	t.Logf("Successfully saved %d events to the database (skipped %d invalid events)", eventCount, skippedCount)
 105  
 106  	// Test QueryForSerials with an ID filter
 107  	testEvent := events[3] // Using the same event as in other tests
 108  
 109  	serials, err := db.QueryForSerials(
 110  		ctx, &filter.F{
 111  			Ids: tag.NewFromBytesSlice(testEvent.ID),
 112  		},
 113  	)
 114  	if err != nil {
 115  		t.Fatalf("Failed to query serials by ID: %v", err)
 116  	}
 117  
 118  	// Verify we got exactly one serial
 119  	if len(serials) != 1 {
 120  		t.Fatalf("Expected 1 serial, got %d", len(serials))
 121  	}
 122  
 123  	// Verify the serial corresponds to the correct event
 124  	// Fetch the event using the serial
 125  	ev, err := db.FetchEventBySerial(serials[0])
 126  	if err != nil {
 127  		t.Fatalf("Failed to fetch event for serial: %v", err)
 128  	}
 129  
 130  	if !utils.FastEqual(ev.ID, testEvent.ID) {
 131  		t.Fatalf(
 132  			"Event ID doesn't match. Got %x, expected %x",
 133  			ev.ID, testEvent.ID,
 134  		)
 135  	}
 136  
 137  	// Test querying by kind
 138  	testKind := kind.New(1) // Kind 1 is typically text notes
 139  	kindFilter := kind.NewS(testKind)
 140  
 141  	serials, err = db.QueryForSerials(
 142  		ctx, &filter.F{
 143  			Kinds: kindFilter,
 144  		},
 145  	)
 146  	if err != nil {
 147  		t.Fatalf("Failed to query serials by kind: %v", err)
 148  	}
 149  
 150  	// Verify we got results
 151  	if len(serials) == 0 {
 152  		t.Fatal("Expected serials for events with kind 1, but got none")
 153  	}
 154  
 155  	// Verify the serials correspond to events with the correct kind
 156  	for i, serial := range serials {
 157  		// Fetch the event using the serial
 158  		ev, err := db.FetchEventBySerial(serial)
 159  		if err != nil {
 160  			t.Fatalf("Failed to fetch event for serial %d: %v", i, err)
 161  		}
 162  
 163  		if ev.Kind != testKind.K {
 164  			t.Fatalf(
 165  				"Event %d has incorrect kind. Got %d, expected %d",
 166  				i, ev.Kind, testKind.K,
 167  			)
 168  		}
 169  	}
 170  
 171  	// Test querying by author
 172  	authorFilter := tag.NewFromBytesSlice(events[1].Pubkey)
 173  
 174  	serials, err = db.QueryForSerials(
 175  		ctx, &filter.F{
 176  			Authors: authorFilter,
 177  		},
 178  	)
 179  	if err != nil {
 180  		t.Fatalf("Failed to query serials by author: %v", err)
 181  	}
 182  
 183  	// Verify we got results
 184  	if len(serials) == 0 {
 185  		t.Fatal("Expected serials for events from author, but got none")
 186  	}
 187  
 188  	// Verify the serials correspond to events with the correct author
 189  	for i, serial := range serials {
 190  		// Fetch the event using the serial
 191  		ev, err := db.FetchEventBySerial(serial)
 192  		if err != nil {
 193  			t.Fatalf("Failed to fetch event for serial %d: %v", i, err)
 194  		}
 195  
 196  		if !utils.FastEqual(ev.Pubkey, events[1].Pubkey) {
 197  			t.Fatalf(
 198  				"Event %d has incorrect author. Got %x, expected %x",
 199  				i, ev.Pubkey, events[1].Pubkey,
 200  			)
 201  		}
 202  	}
 203  
 204  	// Test querying by time range
 205  	// Use the timestamp from the middle event as a reference
 206  	middleIndex := len(events) / 2
 207  	middleEvent := events[middleIndex]
 208  
 209  	// Create a timestamp range that includes events before and after the middle event
 210  	sinceTime := new(timestamp.T)
 211  	sinceTime.V = middleEvent.CreatedAt - 3600 // 1 hour before middle event
 212  
 213  	untilTime := new(timestamp.T)
 214  	untilTime.V = middleEvent.CreatedAt + 3600 // 1 hour after middle event
 215  
 216  	serials, err = db.QueryForSerials(
 217  		ctx, &filter.F{
 218  			Since: sinceTime,
 219  			Until: untilTime,
 220  		},
 221  	)
 222  	if err != nil {
 223  		t.Fatalf("Failed to query serials by time range: %v", err)
 224  	}
 225  
 226  	// Verify we got results
 227  	if len(serials) == 0 {
 228  		t.Fatal("Expected serials for events in time range, but got none")
 229  	}
 230  
 231  	// Verify the serials correspond to events within the time range
 232  	for i, serial := range serials {
 233  		// Fetch the event using the serial
 234  		ev, err := db.FetchEventBySerial(serial)
 235  		if err != nil {
 236  			t.Fatalf("Failed to fetch event for serial %d: %v", i, err)
 237  		}
 238  
 239  		if ev.CreatedAt < sinceTime.V || ev.CreatedAt > untilTime.V {
 240  			t.Fatalf(
 241  				"Event %d is outside the time range. Got %d, expected between %d and %d",
 242  				i, ev.CreatedAt, sinceTime.V, untilTime.V,
 243  			)
 244  		}
 245  	}
 246  }
 247