query-for-ids_test.go raw

   1  package database
   2  
   3  import (
   4  	"bytes"
   5  	"testing"
   6  
   7  	"next.orly.dev/pkg/nostr/encoders/filter"
   8  	"next.orly.dev/pkg/nostr/encoders/kind"
   9  	"next.orly.dev/pkg/nostr/encoders/tag"
  10  	"next.orly.dev/pkg/nostr/encoders/timestamp"
  11  )
  12  
  13  func TestQueryForIds(t *testing.T) {
  14  	// Use shared database (read-only test)
  15  	db, ctx := GetSharedDB(t)
  16  	events := GetSharedEvents(t)
  17  
  18  	if len(events) < 2 {
  19  		t.Fatalf("Need at least 2 saved events, got %d", len(events))
  20  	}
  21  
  22  	idTsPk, err := db.QueryForIds(
  23  		ctx, &filter.F{
  24  			Authors: tag.NewFromBytesSlice(events[1].Pubkey),
  25  		},
  26  	)
  27  	if err != nil {
  28  		t.Fatalf("Failed to query for authors: %v", err)
  29  	}
  30  
  31  	if len(idTsPk) < 1 {
  32  		t.Fatalf(
  33  			"got unexpected number of results, expect at least 1, got %d",
  34  			len(idTsPk),
  35  		)
  36  	}
  37  	// Verify that all returned events have the correct author
  38  	for i, result := range idTsPk {
  39  		// Find the event with this ID
  40  		var found bool
  41  		for _, ev := range events {
  42  			if bytes.Equal(result.Id[:], ev.ID[:]) {
  43  				found = true
  44  				if !bytes.Equal(ev.Pubkey[:], events[1].Pubkey[:]) {
  45  					t.Fatalf(
  46  						"result %d has incorrect author, got %x, expected %x",
  47  						i, ev.Pubkey, events[1].Pubkey,
  48  					)
  49  				}
  50  				break
  51  			}
  52  		}
  53  		if !found {
  54  			t.Fatalf("result %d with ID %x not found in events", i, result.Id)
  55  		}
  56  	}
  57  
  58  	// Test querying by kind
  59  	// Find an event with a specific kind
  60  	testKind := kind.New(1) // Kind 1 is typically text notes
  61  	kindFilter := kind.NewS(testKind)
  62  
  63  	idTsPk, err = db.QueryForIds(
  64  		ctx, &filter.F{
  65  			Kinds: kindFilter,
  66  		},
  67  	)
  68  	if err != nil {
  69  		t.Fatalf("Failed to query for kinds: %v", err)
  70  	}
  71  
  72  	// Verify we got results
  73  	if len(idTsPk) == 0 {
  74  		t.Fatal("did not find any events with the specified kind")
  75  	}
  76  
  77  	// Verify the results have the correct kind
  78  	for i, result := range idTsPk {
  79  		// Find the event with this ID
  80  		var found bool
  81  		for _, ev := range events {
  82  			if bytes.Equal(result.Id[:], ev.ID[:]) {
  83  				found = true
  84  				if ev.Kind != testKind.K {
  85  					t.Fatalf(
  86  						"result %d has incorrect kind, got %d, expected %d",
  87  						i, ev.Kind, testKind.K,
  88  					)
  89  				}
  90  				break
  91  			}
  92  		}
  93  		if !found {
  94  			t.Fatalf("result %d with ID %x not found in events", i, result.Id)
  95  		}
  96  	}
  97  
  98  	// Test querying by tag
  99  	// Find an event with tags to use for testing
 100  	var testTag *tag.T
 101  	var testEventForTag = findEventWithTag(events)
 102  
 103  	if testEventForTag != nil {
 104  		// Get the first tag with at least 2 elements and first element of length 1
 105  		for _, tg := range *testEventForTag.Tags {
 106  			if tg.Len() >= 2 && len(tg.Key()) == 1 {
 107  				testTag = tg
 108  				break
 109  			}
 110  		}
 111  
 112  		// Create a tags filter with the test tag
 113  		tagsFilter := tag.NewS(testTag)
 114  
 115  		idTsPk, err = db.QueryForIds(
 116  			ctx, &filter.F{
 117  				Tags: tagsFilter,
 118  			},
 119  		)
 120  		if err != nil {
 121  			t.Fatalf("Failed to query for tags: %v", err)
 122  		}
 123  
 124  		// Verify we got results
 125  		if len(idTsPk) == 0 {
 126  			t.Fatal("did not find any events with the specified tag")
 127  		}
 128  
 129  		// Verify the results have the correct tag
 130  		for i, result := range idTsPk {
 131  			// Find the event with this ID
 132  			var found bool
 133  			for _, ev := range events {
 134  				if bytes.Equal(result.Id[:], ev.ID[:]) {
 135  					found = true
 136  
 137  					// Check if the event has the tag we're looking for
 138  					var hasTag bool
 139  					for _, tg := range *ev.Tags {
 140  						if tg.Len() >= 2 && len(tg.Key()) == 1 {
 141  							if bytes.Equal(
 142  								tg.Key(), testTag.Key(),
 143  							) && bytes.Equal(tg.Value(), testTag.Value()) {
 144  								hasTag = true
 145  								break
 146  							}
 147  						}
 148  					}
 149  
 150  					if !hasTag {
 151  						t.Fatalf(
 152  							"result %d does not have the expected tag",
 153  							i,
 154  						)
 155  					}
 156  
 157  					break
 158  				}
 159  			}
 160  			if !found {
 161  				t.Fatalf(
 162  					"result %d with ID %x not found in events", i, result.Id,
 163  				)
 164  			}
 165  		}
 166  
 167  		// Test querying by kind and author
 168  		idTsPk, err = db.QueryForIds(
 169  			ctx, &filter.F{
 170  				Kinds:   kindFilter,
 171  				Authors: tag.NewFromBytesSlice(events[1].Pubkey),
 172  			},
 173  		)
 174  		if err != nil {
 175  			t.Fatalf("Failed to query for kinds and authors: %v", err)
 176  		}
 177  
 178  		// Verify we got results
 179  		if len(idTsPk) > 0 {
 180  			// Verify the results have the correct kind and author
 181  			for i, result := range idTsPk {
 182  				// Find the event with this ID
 183  				var found bool
 184  				for _, ev := range events {
 185  					if bytes.Equal(result.Id[:], ev.ID[:]) {
 186  						found = true
 187  						if ev.Kind != testKind.K {
 188  							t.Fatalf(
 189  								"result %d has incorrect kind, got %d, expected %d",
 190  								i, ev.Kind, testKind.K,
 191  							)
 192  						}
 193  						if !bytes.Equal(ev.Pubkey[:], events[1].Pubkey[:]) {
 194  							t.Fatalf(
 195  								"result %d has incorrect author, got %x, expected %x",
 196  								i, ev.Pubkey, events[1].Pubkey,
 197  							)
 198  						}
 199  						break
 200  					}
 201  				}
 202  				if !found {
 203  					t.Fatalf(
 204  						"result %d with ID %x not found in events", i,
 205  						result.Id,
 206  					)
 207  				}
 208  			}
 209  		}
 210  
 211  		// Test querying by kind and tag
 212  		idTsPk, err = db.QueryForIds(
 213  			ctx, &filter.F{
 214  				Kinds: kind.NewS(kind.New(testEventForTag.Kind)),
 215  				Tags:  tagsFilter,
 216  			},
 217  		)
 218  		if err != nil {
 219  			t.Fatalf("Failed to query for kinds and tags: %v", err)
 220  		}
 221  
 222  		// Verify we got results
 223  		if len(idTsPk) == 0 {
 224  			t.Fatal("did not find any events with the specified kind and tag")
 225  		}
 226  
 227  		// Verify the results have the correct kind and tag
 228  		for i, result := range idTsPk {
 229  			// Find the event with this ID
 230  			var found bool
 231  			for _, ev := range events {
 232  				if bytes.Equal(result.Id[:], ev.ID[:]) {
 233  					found = true
 234  					if ev.Kind != testEventForTag.Kind {
 235  						t.Fatalf(
 236  							"result %d has incorrect kind, got %d, expected %d",
 237  							i, ev.Kind, testEventForTag.Kind,
 238  						)
 239  					}
 240  
 241  					// Check if the event has the tag we're looking for
 242  					var hasTag bool
 243  					for _, tg := range *ev.Tags {
 244  						if tg.Len() >= 2 && len(tg.Key()) == 1 {
 245  							if bytes.Equal(
 246  								tg.Key(), testTag.Key(),
 247  							) && bytes.Equal(tg.Value(), testTag.Value()) {
 248  								hasTag = true
 249  								break
 250  							}
 251  						}
 252  					}
 253  
 254  					if !hasTag {
 255  						t.Fatalf(
 256  							"result %d does not have the expected tag",
 257  							i,
 258  						)
 259  					}
 260  
 261  					break
 262  				}
 263  			}
 264  			if !found {
 265  				t.Fatalf(
 266  					"result %d with ID %x not found in events", i, result.Id,
 267  				)
 268  			}
 269  		}
 270  
 271  		// Test querying by kind, author, and tag
 272  		idTsPk, err = db.QueryForIds(
 273  			ctx, &filter.F{
 274  				Kinds:   kind.NewS(kind.New(testEventForTag.Kind)),
 275  				Authors: tag.NewFromBytesSlice(testEventForTag.Pubkey),
 276  				Tags:    tagsFilter,
 277  			},
 278  		)
 279  		if err != nil {
 280  			t.Fatalf("Failed to query for kinds, authors, and tags: %v", err)
 281  		}
 282  
 283  		// Verify we got results
 284  		if len(idTsPk) == 0 {
 285  			t.Fatal("did not find any events with the specified kind, author, and tag")
 286  		}
 287  
 288  		// Verify the results have the correct kind, author, and tag
 289  		for i, result := range idTsPk {
 290  			// Find the event with this ID
 291  			var found bool
 292  			for _, ev := range events {
 293  				if bytes.Equal(result.Id[:], ev.ID[:]) {
 294  					found = true
 295  					if ev.Kind != testEventForTag.Kind {
 296  						t.Fatalf(
 297  							"result %d has incorrect kind, got %d, expected %d",
 298  							i, ev.Kind, testEventForTag.Kind,
 299  						)
 300  					}
 301  
 302  					if !bytes.Equal(ev.Pubkey[:], testEventForTag.Pubkey[:]) {
 303  						t.Fatalf(
 304  							"result %d has incorrect author, got %x, expected %x",
 305  							i, ev.Pubkey, testEventForTag.Pubkey,
 306  						)
 307  					}
 308  
 309  					// Check if the event has the tag we're looking for
 310  					var hasTag bool
 311  					for _, tg := range *ev.Tags {
 312  						if tg.Len() >= 2 && len(tg.Key()) == 1 {
 313  							if bytes.Equal(
 314  								tg.Key(), testTag.Key(),
 315  							) && bytes.Equal(tg.Value(), testTag.Value()) {
 316  								hasTag = true
 317  								break
 318  							}
 319  						}
 320  					}
 321  
 322  					if !hasTag {
 323  						t.Fatalf(
 324  							"result %d does not have the expected tag",
 325  							i,
 326  						)
 327  					}
 328  
 329  					break
 330  				}
 331  			}
 332  			if !found {
 333  				t.Fatalf(
 334  					"result %d with ID %x not found in events", i, result.Id,
 335  				)
 336  			}
 337  		}
 338  
 339  		// Test querying by author and tag
 340  		idTsPk, err = db.QueryForIds(
 341  			ctx, &filter.F{
 342  				Authors: tag.NewFromBytesSlice(testEventForTag.Pubkey),
 343  				Tags:    tagsFilter,
 344  			},
 345  		)
 346  		if err != nil {
 347  			t.Fatalf("Failed to query for authors and tags: %v", err)
 348  		}
 349  
 350  		// Verify we got results
 351  		if len(idTsPk) == 0 {
 352  			t.Fatal("did not find any events with the specified author and tag")
 353  		}
 354  
 355  		// Verify the results have the correct author and tag
 356  		for i, result := range idTsPk {
 357  			// Find the event with this ID
 358  			var found bool
 359  			for _, ev := range events {
 360  				if bytes.Equal(result.Id[:], ev.ID[:]) {
 361  					found = true
 362  
 363  					if !bytes.Equal(ev.Pubkey[:], testEventForTag.Pubkey[:]) {
 364  						t.Fatalf(
 365  							"result %d has incorrect author, got %x, expected %x",
 366  							i, ev.Pubkey, testEventForTag.Pubkey,
 367  						)
 368  					}
 369  
 370  					// Check if the event has the tag we're looking for
 371  					var hasTag bool
 372  					for _, tg := range *ev.Tags {
 373  						if tg.Len() >= 2 && len(tg.Key()) == 1 {
 374  							if bytes.Equal(
 375  								tg.Key(), testTag.Key(),
 376  							) && bytes.Equal(tg.Value(), testTag.Value()) {
 377  								hasTag = true
 378  								break
 379  							}
 380  						}
 381  					}
 382  
 383  					if !hasTag {
 384  						t.Fatalf(
 385  							"result %d does not have the expected tag",
 386  							i,
 387  						)
 388  					}
 389  
 390  					break
 391  				}
 392  			}
 393  			if !found {
 394  				t.Fatalf(
 395  					"result %d with ID %x not found in events", i, result.Id,
 396  				)
 397  			}
 398  		}
 399  	}
 400  
 401  	// Test querying by created_at range
 402  	// Use the timestamp from the middle event as a reference
 403  	middleIndex := len(events) / 2
 404  	middleEvent := events[middleIndex]
 405  
 406  	// Create a timestamp range that includes events before and after the middle event
 407  	sinceTime := new(timestamp.T)
 408  	sinceTime.V = middleEvent.CreatedAt - 3600 // 1 hour before middle event
 409  
 410  	untilTime := new(timestamp.T)
 411  	untilTime.V = middleEvent.CreatedAt + 3600 // 1 hour after middle event
 412  
 413  	idTsPk, err = db.QueryForIds(
 414  		ctx, &filter.F{
 415  			Since: sinceTime,
 416  			Until: untilTime,
 417  		},
 418  	)
 419  	if err != nil {
 420  		t.Fatalf("Failed to query for created_at range: %v", err)
 421  	}
 422  
 423  	// Verify we got results
 424  	if len(idTsPk) == 0 {
 425  		t.Fatal("did not find any events in the specified time range")
 426  	}
 427  
 428  	// Verify the results exist in our events slice
 429  	for i, result := range idTsPk {
 430  		// Find the event with this ID
 431  		var found bool
 432  		for _, ev := range events {
 433  			if bytes.Equal(result.Id[:], ev.ID[:]) {
 434  				found = true
 435  				break
 436  			}
 437  		}
 438  		if !found {
 439  			t.Fatalf("result %d with ID %x not found in events", i, result.Id)
 440  		}
 441  	}
 442  }
 443