keys.go raw

   1  package indexes
   2  
   3  import (
   4  	"io"
   5  	"reflect"
   6  
   7  	"next.orly.dev/pkg/lol/chk"
   8  	"next.orly.dev/pkg/database/indexes/types"
   9  	"next.orly.dev/pkg/nostr/interfaces/codec"
  10  )
  11  
  12  var counter int
  13  
  14  func init() {
  15  	// Initialize the counter to ensure it starts from 0
  16  	counter = 0
  17  }
  18  
  19  func next() int { counter++; return counter - 1 }
  20  
  21  type P struct {
  22  	val []byte
  23  }
  24  
  25  func NewPrefix(prf ...int) (p *P) {
  26  	if len(prf) > 0 {
  27  		prefix := Prefix(prf[0])
  28  		if prefix == "" {
  29  			panic("unknown prefix")
  30  		}
  31  		return &P{[]byte(prefix)}
  32  	} else {
  33  		return &P{[]byte{0, 0, 0}}
  34  	}
  35  }
  36  
  37  func (p *P) Bytes() (b []byte) { return p.val }
  38  
  39  func (p *P) MarshalWrite(w io.Writer) (err error) {
  40  	_, err = w.Write(p.val)
  41  	return
  42  }
  43  
  44  func (p *P) UnmarshalRead(r io.Reader) (err error) {
  45  	// Allocate a buffer for val if it's nil or empty
  46  	if p.val == nil || len(p.val) == 0 {
  47  		p.val = make([]byte, 3) // Prefixes are 3 bytes
  48  	}
  49  	_, err = r.Read(p.val)
  50  	return
  51  }
  52  
  53  type I string
  54  
  55  func (i I) Write(w io.Writer) (n int, err error) { return w.Write([]byte(i)) }
  56  
  57  const (
  58  	EventPrefix            = I("evt")
  59  	SmallEventPrefix       = I("sev") // small event with inline data (<=384 bytes)
  60  	ReplaceableEventPrefix = I("rev") // replaceable event (kinds 0,3,10000-19999) with inline data
  61  	AddressableEventPrefix = I("aev") // addressable event (kinds 30000-39999) with inline data
  62  	IdPrefix               = I("eid")
  63  	FullIdPubkeyPrefix     = I("fpc") // full id, pubkey, created at
  64  
  65  	CreatedAtPrefix  = I("c--") // created at
  66  	KindPrefix       = I("kc-") // kind, created at
  67  	PubkeyPrefix     = I("pc-") // pubkey, created at
  68  	KindPubkeyPrefix = I("kpc") // kind, pubkey, created at
  69  
  70  	TagPrefix           = I("tc-") // tag, created at
  71  	TagKindPrefix       = I("tkc") // tag, kind, created at
  72  	TagPubkeyPrefix     = I("tpc") // tag, pubkey, created at
  73  	TagKindPubkeyPrefix = I("tkp") // tag, kind, pubkey, created at
  74  
  75  	WordPrefix       = I("wrd") // word hash, serial
  76  	ExpirationPrefix = I("exp") // timestamp of expiration
  77  	VersionPrefix    = I("ver") // database version number, for triggering reindexes when new keys are added (policy is add-only).
  78  
  79  	// Pubkey graph indexes
  80  	PubkeySerialPrefix       = I("pks") // pubkey hash -> pubkey serial
  81  	SerialPubkeyPrefix       = I("spk") // pubkey serial -> pubkey hash (full 32 bytes)
  82  	EventPubkeyGraphPrefix   = I("epg") // event serial -> pubkey serial (graph edges)
  83  	PubkeyEventGraphPrefix   = I("peg") // pubkey serial -> event serial (reverse edges)
  84  
  85  	// Compact event storage indexes
  86  	SerialEventIdPrefix = I("sei") // event serial -> full 32-byte event ID
  87  	CompactEventPrefix  = I("cmp") // compact event storage with serial references
  88  
  89  	// Event-to-event graph indexes (for e-tag references)
  90  	EventEventGraphPrefix = I("eeg") // source event serial -> target event serial (outbound e-tags)
  91  	GraphEventEventPrefix = I("gee") // target event serial -> source event serial (reverse e-tags)
  92  
  93  	// Pubkey-to-pubkey graph indexes (noun-noun edges)
  94  	// Materialized from events containing p-tags, collapsing the two-hop
  95  	// pubkey→event→pubkey traversal into a direct single-hop lookup.
  96  	PubkeyPubkeyGraphPrefix = I("ppg") // source pubkey serial -> target pubkey serial (outbound)
  97  	GraphPubkeyPubkeyPrefix = I("gpp") // target pubkey serial -> source pubkey serial (reverse)
  98  )
  99  
 100  // Prefix returns the three byte human-readable prefixes that go in front of
 101  // database indexes.
 102  func Prefix(prf int) (i I) {
 103  	switch prf {
 104  	case Event:
 105  		return EventPrefix
 106  	case SmallEvent:
 107  		return SmallEventPrefix
 108  	case ReplaceableEvent:
 109  		return ReplaceableEventPrefix
 110  	case AddressableEvent:
 111  		return AddressableEventPrefix
 112  	case Id:
 113  		return IdPrefix
 114  	case FullIdPubkey:
 115  		return FullIdPubkeyPrefix
 116  
 117  	case CreatedAt:
 118  		return CreatedAtPrefix
 119  	case Kind:
 120  		return KindPrefix
 121  	case Pubkey:
 122  		return PubkeyPrefix
 123  	case KindPubkey:
 124  		return KindPubkeyPrefix
 125  
 126  	case Tag:
 127  		return TagPrefix
 128  	case TagKind:
 129  		return TagKindPrefix
 130  	case TagPubkey:
 131  		return TagPubkeyPrefix
 132  	case TagKindPubkey:
 133  		return TagKindPubkeyPrefix
 134  
 135  	case Expiration:
 136  		return ExpirationPrefix
 137  	case Version:
 138  		return VersionPrefix
 139  	case Word:
 140  		return WordPrefix
 141  
 142  	case PubkeySerial:
 143  		return PubkeySerialPrefix
 144  	case SerialPubkey:
 145  		return SerialPubkeyPrefix
 146  	case EventPubkeyGraph:
 147  		return EventPubkeyGraphPrefix
 148  	case PubkeyEventGraph:
 149  		return PubkeyEventGraphPrefix
 150  
 151  	case SerialEventId:
 152  		return SerialEventIdPrefix
 153  	case CompactEvent:
 154  		return CompactEventPrefix
 155  
 156  	case EventEventGraph:
 157  		return EventEventGraphPrefix
 158  	case GraphEventEvent:
 159  		return GraphEventEventPrefix
 160  
 161  	case PubkeyPubkeyGraph:
 162  		return PubkeyPubkeyGraphPrefix
 163  	case GraphPubkeyPubkey:
 164  		return GraphPubkeyPubkeyPrefix
 165  	}
 166  	return
 167  }
 168  
 169  func Identify(r io.Reader) (i int, err error) {
 170  	// this is here for completeness; however, searches don't need to identify
 171  	// this as they work via generated prefixes made using Prefix.
 172  	var b [3]byte
 173  	_, err = r.Read(b[:])
 174  	if err != nil {
 175  		i = -1
 176  		return
 177  	}
 178  	switch I(b[:]) {
 179  	case EventPrefix:
 180  		i = Event
 181  	case SmallEventPrefix:
 182  		i = SmallEvent
 183  	case ReplaceableEventPrefix:
 184  		i = ReplaceableEvent
 185  	case AddressableEventPrefix:
 186  		i = AddressableEvent
 187  	case IdPrefix:
 188  		i = Id
 189  	case FullIdPubkeyPrefix:
 190  		i = FullIdPubkey
 191  
 192  	case CreatedAtPrefix:
 193  		i = CreatedAt
 194  	case KindPrefix:
 195  		i = Kind
 196  	case PubkeyPrefix:
 197  		i = Pubkey
 198  	case KindPubkeyPrefix:
 199  		i = KindPubkey
 200  
 201  	case TagPrefix:
 202  		i = Tag
 203  	case TagKindPrefix:
 204  		i = TagKind
 205  	case TagPubkeyPrefix:
 206  		i = TagPubkey
 207  	case TagKindPubkeyPrefix:
 208  		i = TagKindPubkey
 209  
 210  	case ExpirationPrefix:
 211  		i = Expiration
 212  	case WordPrefix:
 213  		i = Word
 214  
 215  	case PubkeySerialPrefix:
 216  		i = PubkeySerial
 217  	case SerialPubkeyPrefix:
 218  		i = SerialPubkey
 219  	case EventPubkeyGraphPrefix:
 220  		i = EventPubkeyGraph
 221  	case PubkeyEventGraphPrefix:
 222  		i = PubkeyEventGraph
 223  
 224  	case SerialEventIdPrefix:
 225  		i = SerialEventId
 226  	case CompactEventPrefix:
 227  		i = CompactEvent
 228  
 229  	case EventEventGraphPrefix:
 230  		i = EventEventGraph
 231  	case GraphEventEventPrefix:
 232  		i = GraphEventEvent
 233  
 234  	case PubkeyPubkeyGraphPrefix:
 235  		i = PubkeyPubkeyGraph
 236  	case GraphPubkeyPubkeyPrefix:
 237  		i = GraphPubkeyPubkey
 238  	}
 239  	return
 240  }
 241  
 242  type Encs []codec.I
 243  
 244  // T is a wrapper around an array of codec.I. The caller provides the Encs so
 245  // they can then call the accessor methods of the codec.I implementation.
 246  type T struct{ Encs }
 247  
 248  // New creates a new indexes.T. The helper functions below have an encode and
 249  // decode variant, the decode variant doesn't add the prefix encoder because it
 250  // has been read by Identify or just is being read, and found because it was
 251  // written for the prefix in the iteration.
 252  func New(encoders ...codec.I) (i *T) { return &T{encoders} }
 253  func (t *T) MarshalWrite(w io.Writer) (err error) {
 254  	for _, e := range t.Encs {
 255  		if e == nil || reflect.ValueOf(e).IsNil() {
 256  			// Skip nil encoders instead of returning early. This enables
 257  			// generating search prefixes.
 258  			continue
 259  		}
 260  		if err = e.MarshalWrite(w); chk.E(err) {
 261  			return
 262  		}
 263  	}
 264  	return
 265  }
 266  func (t *T) UnmarshalRead(r io.Reader) (err error) {
 267  	for _, e := range t.Encs {
 268  		if err = e.UnmarshalRead(r); chk.E(err) {
 269  			return
 270  		}
 271  	}
 272  	return
 273  }
 274  
 275  // Event is the whole event stored in binary format
 276  //
 277  //	prefix|5 serial - event in binary format
 278  var Event = next()
 279  
 280  func EventVars() (ser *types.Uint40) { return new(types.Uint40) }
 281  func EventEnc(ser *types.Uint40) (enc *T) {
 282  	return New(NewPrefix(Event), ser)
 283  }
 284  func EventDec(ser *types.Uint40) (enc *T) { return New(NewPrefix(), ser) }
 285  
 286  // SmallEvent stores events <=384 bytes with inline data to avoid double lookup.
 287  // This is a Reiser4-inspired optimization for small event packing.
 288  // 384 bytes covers: ID(32) + Pubkey(32) + Sig(64) + basic fields + small content
 289  //
 290  //	prefix|5 serial|2 size_uint16|data (variable length, max 384 bytes)
 291  var SmallEvent = next()
 292  
 293  func SmallEventVars() (ser *types.Uint40) { return new(types.Uint40) }
 294  func SmallEventEnc(ser *types.Uint40) (enc *T) {
 295  	return New(NewPrefix(SmallEvent), ser)
 296  }
 297  func SmallEventDec(ser *types.Uint40) (enc *T) { return New(NewPrefix(), ser) }
 298  
 299  // ReplaceableEvent stores replaceable events (kinds 0,3,10000-19999) with inline data.
 300  // Optimized storage for metadata events that are frequently replaced.
 301  // Key format enables direct lookup by pubkey+kind without additional index traversal.
 302  //
 303  //	prefix|8 pubkey_hash|2 kind|2 size_uint16|data (variable length, max 384 bytes)
 304  var ReplaceableEvent = next()
 305  
 306  func ReplaceableEventVars() (p *types.PubHash, ki *types.Uint16) {
 307  	return new(types.PubHash), new(types.Uint16)
 308  }
 309  func ReplaceableEventEnc(p *types.PubHash, ki *types.Uint16) (enc *T) {
 310  	return New(NewPrefix(ReplaceableEvent), p, ki)
 311  }
 312  func ReplaceableEventDec(p *types.PubHash, ki *types.Uint16) (enc *T) {
 313  	return New(NewPrefix(), p, ki)
 314  }
 315  
 316  // AddressableEvent stores parameterized replaceable events (kinds 30000-39999) with inline data.
 317  // Optimized storage for addressable events identified by pubkey+kind+d-tag.
 318  // Key format enables direct lookup without additional index traversal.
 319  //
 320  //	prefix|8 pubkey_hash|2 kind|8 dtag_hash|2 size_uint16|data (variable length, max 384 bytes)
 321  var AddressableEvent = next()
 322  
 323  func AddressableEventVars() (p *types.PubHash, ki *types.Uint16, d *types.Ident) {
 324  	return new(types.PubHash), new(types.Uint16), new(types.Ident)
 325  }
 326  func AddressableEventEnc(p *types.PubHash, ki *types.Uint16, d *types.Ident) (enc *T) {
 327  	return New(NewPrefix(AddressableEvent), p, ki, d)
 328  }
 329  func AddressableEventDec(p *types.PubHash, ki *types.Uint16, d *types.Ident) (enc *T) {
 330  	return New(NewPrefix(), p, ki, d)
 331  }
 332  
 333  // Id contains a truncated 8-byte hash of an event index. This is the secondary
 334  // key of an event, the primary key is the serial found in the Event.
 335  //
 336  //	3 prefix|8 ID hash|5 serial
 337  var Id = next()
 338  
 339  func IdVars() (id *types.IdHash, ser *types.Uint40) {
 340  	return new(types.IdHash), new(types.Uint40)
 341  }
 342  func IdEnc(id *types.IdHash, ser *types.Uint40) (enc *T) {
 343  	return New(NewPrefix(Id), id, ser)
 344  }
 345  func IdDec(id *types.IdHash, ser *types.Uint40) (enc *T) {
 346  	return New(NewPrefix(), id, ser)
 347  }
 348  
 349  // FullIdPubkey is an index designed to enable sorting and filtering of
 350  // results found via other indexes, without having to decode the event.
 351  //
 352  //	3 prefix|5 serial|32 ID|8 pubkey hash|8 timestamp
 353  var FullIdPubkey = next()
 354  
 355  func FullIdPubkeyVars() (
 356  	ser *types.Uint40, fid *types.Id, p *types.PubHash, ca *types.Uint64,
 357  ) {
 358  	return new(types.Uint40), new(types.Id), new(types.PubHash), new(types.Uint64)
 359  }
 360  func FullIdPubkeyEnc(
 361  	ser *types.Uint40, fid *types.Id, p *types.PubHash, ca *types.Uint64,
 362  ) (enc *T) {
 363  	return New(NewPrefix(FullIdPubkey), ser, fid, p, ca)
 364  }
 365  func FullIdPubkeyDec(
 366  	ser *types.Uint40, fid *types.Id, p *types.PubHash, ca *types.Uint64,
 367  ) (enc *T) {
 368  	return New(NewPrefix(), ser, fid, p, ca)
 369  }
 370  
 371  // Word index for tokenized search terms
 372  //
 373  //	3 prefix|8 word-hash|5 serial
 374  var Word = next()
 375  
 376  func WordVars() (w *types.Word, ser *types.Uint40) {
 377  	return new(types.Word), new(types.Uint40)
 378  }
 379  func WordEnc(w *types.Word, ser *types.Uint40) (enc *T) {
 380  	return New(NewPrefix(Word), w, ser)
 381  }
 382  func WordDec(w *types.Word, ser *types.Uint40) (enc *T) {
 383  	return New(NewPrefix(), w, ser)
 384  }
 385  
 386  // CreatedAt is an index that allows search for the timestamp on the event.
 387  //
 388  //	3 prefix|8 timestamp|5 serial
 389  var CreatedAt = next()
 390  
 391  func CreatedAtVars() (ca *types.Uint64, ser *types.Uint40) {
 392  	return new(types.Uint64), new(types.Uint40)
 393  }
 394  func CreatedAtEnc(ca *types.Uint64, ser *types.Uint40) (enc *T) {
 395  	return New(NewPrefix(CreatedAt), ca, ser)
 396  }
 397  func CreatedAtDec(ca *types.Uint64, ser *types.Uint40) (enc *T) {
 398  	return New(NewPrefix(), ca, ser)
 399  }
 400  
 401  // Kind
 402  //
 403  //	3 prefix|2 kind|8 timestamp|5 serial
 404  var Kind = next()
 405  
 406  func KindVars() (ki *types.Uint16, ca *types.Uint64, ser *types.Uint40) {
 407  	return new(types.Uint16), new(types.Uint64), new(types.Uint40)
 408  }
 409  func KindEnc(ki *types.Uint16, ca *types.Uint64, ser *types.Uint40) (enc *T) {
 410  	return New(NewPrefix(Kind), ki, ca, ser)
 411  }
 412  func KindDec(ki *types.Uint16, ca *types.Uint64, ser *types.Uint40) (enc *T) {
 413  	return New(NewPrefix(), ki, ca, ser)
 414  }
 415  
 416  // Pubkey is a composite index that allows search by pubkey
 417  // filtered by timestamp.
 418  //
 419  //	3 prefix|8 pubkey hash|8 timestamp|5 serial
 420  var Pubkey = next()
 421  
 422  func PubkeyVars() (p *types.PubHash, ca *types.Uint64, ser *types.Uint40) {
 423  	return new(types.PubHash), new(types.Uint64), new(types.Uint40)
 424  }
 425  func PubkeyEnc(p *types.PubHash, ca *types.Uint64, ser *types.Uint40) (enc *T) {
 426  	return New(NewPrefix(Pubkey), p, ca, ser)
 427  }
 428  func PubkeyDec(p *types.PubHash, ca *types.Uint64, ser *types.Uint40) (enc *T) {
 429  	return New(NewPrefix(), p, ca, ser)
 430  }
 431  
 432  // KindPubkey
 433  //
 434  //	3 prefix|2 kind|8 pubkey hash|8 timestamp|5 serial
 435  var KindPubkey = next()
 436  
 437  func KindPubkeyVars() (
 438  	ki *types.Uint16, p *types.PubHash, ca *types.Uint64, ser *types.Uint40,
 439  ) {
 440  	return new(types.Uint16), new(types.PubHash), new(types.Uint64), new(types.Uint40)
 441  }
 442  func KindPubkeyEnc(
 443  	ki *types.Uint16, p *types.PubHash, ca *types.Uint64, ser *types.Uint40,
 444  ) (enc *T) {
 445  	return New(NewPrefix(KindPubkey), ki, p, ca, ser)
 446  }
 447  func KindPubkeyDec(
 448  	ki *types.Uint16, p *types.PubHash, ca *types.Uint64, ser *types.Uint40,
 449  ) (enc *T) {
 450  	return New(NewPrefix(), ki, p, ca, ser)
 451  }
 452  
 453  // Tag allows searching for a tag and filter by timestamp.
 454  //
 455  //	3 prefix|1 key letter|8 value hash|8 timestamp|5 serial
 456  var Tag = next()
 457  
 458  func TagVars() (
 459  	k *types.Letter, v *types.Ident, ca *types.Uint64, ser *types.Uint40,
 460  ) {
 461  	return new(types.Letter), new(types.Ident), new(types.Uint64), new(types.Uint40)
 462  }
 463  func TagEnc(
 464  	k *types.Letter, v *types.Ident, ca *types.Uint64, ser *types.Uint40,
 465  ) (enc *T) {
 466  	return New(NewPrefix(Tag), k, v, ca, ser)
 467  }
 468  func TagDec(
 469  	k *types.Letter, v *types.Ident, ca *types.Uint64, ser *types.Uint40,
 470  ) (enc *T) {
 471  	return New(NewPrefix(), k, v, ca, ser)
 472  }
 473  
 474  // TagKind
 475  //
 476  //	3 prefix|1 key letter|8 value hash|2 kind|8 timestamp|5 serial
 477  var TagKind = next()
 478  
 479  func TagKindVars() (
 480  	k *types.Letter, v *types.Ident, ki *types.Uint16, ca *types.Uint64,
 481  	ser *types.Uint40,
 482  ) {
 483  	return new(types.Letter), new(types.Ident), new(types.Uint16), new(types.Uint64), new(types.Uint40)
 484  }
 485  func TagKindEnc(
 486  	k *types.Letter, v *types.Ident, ki *types.Uint16, ca *types.Uint64,
 487  	ser *types.Uint40,
 488  ) (enc *T) {
 489  	return New(NewPrefix(TagKind), ki, k, v, ca, ser)
 490  }
 491  func TagKindDec(
 492  	k *types.Letter, v *types.Ident, ki *types.Uint16, ca *types.Uint64,
 493  	ser *types.Uint40,
 494  ) (enc *T) {
 495  	return New(NewPrefix(), ki, k, v, ca, ser)
 496  }
 497  
 498  // TagPubkey allows searching for a pubkey, tag and timestamp.
 499  //
 500  //	3 prefix|1 key letter|8 value hash|8 pubkey hash|8 timestamp|5 serial
 501  var TagPubkey = next()
 502  
 503  func TagPubkeyVars() (
 504  	k *types.Letter, v *types.Ident, p *types.PubHash, ca *types.Uint64,
 505  	ser *types.Uint40,
 506  ) {
 507  	return new(types.Letter), new(types.Ident), new(types.PubHash), new(types.Uint64), new(types.Uint40)
 508  }
 509  func TagPubkeyEnc(
 510  	k *types.Letter, v *types.Ident, p *types.PubHash, ca *types.Uint64,
 511  	ser *types.Uint40,
 512  ) (enc *T) {
 513  	return New(NewPrefix(TagPubkey), p, k, v, ca, ser)
 514  }
 515  func TagPubkeyDec(
 516  	k *types.Letter, v *types.Ident, p *types.PubHash, ca *types.Uint64,
 517  	ser *types.Uint40,
 518  ) (enc *T) {
 519  	return New(NewPrefix(), p, k, v, ca, ser)
 520  }
 521  
 522  // TagKindPubkey
 523  //
 524  //	3 prefix|1 key letter|8 value hash|2 kind|8 pubkey hash|8 bytes timestamp|5 serial
 525  var TagKindPubkey = next()
 526  
 527  func TagKindPubkeyVars() (
 528  	k *types.Letter, v *types.Ident, ki *types.Uint16, p *types.PubHash,
 529  	ca *types.Uint64,
 530  	ser *types.Uint40,
 531  ) {
 532  	return new(types.Letter), new(types.Ident), new(types.Uint16), new(types.PubHash), new(types.Uint64), new(types.Uint40)
 533  }
 534  func TagKindPubkeyEnc(
 535  	k *types.Letter, v *types.Ident, ki *types.Uint16, p *types.PubHash,
 536  	ca *types.Uint64,
 537  	ser *types.Uint40,
 538  ) (enc *T) {
 539  	return New(NewPrefix(TagKindPubkey), ki, p, k, v, ca, ser)
 540  }
 541  func TagKindPubkeyDec(
 542  	k *types.Letter, v *types.Ident, ki *types.Uint16, p *types.PubHash,
 543  	ca *types.Uint64,
 544  	ser *types.Uint40,
 545  ) (enc *T) {
 546  	return New(NewPrefix(), ki, p, k, v, ca, ser)
 547  }
 548  
 549  // Expiration
 550  //
 551  // 3 prefix|8 timestamp|5 serial
 552  var Expiration = next()
 553  
 554  func ExpirationVars() (
 555  	exp *types.Uint64, ser *types.Uint40,
 556  ) {
 557  	return new(types.Uint64), new(types.Uint40)
 558  }
 559  func ExpirationEnc(
 560  	exp *types.Uint64, ser *types.Uint40,
 561  ) (enc *T) {
 562  	return New(NewPrefix(Expiration), exp, ser)
 563  }
 564  func ExpirationDec(
 565  	exp *types.Uint64, ser *types.Uint40,
 566  ) (enc *T) {
 567  	return New(NewPrefix(), exp, ser)
 568  }
 569  
 570  // Version
 571  //
 572  // 3 prefix|4 version
 573  var Version = next()
 574  
 575  func VersionVars() (
 576  	ver *types.Uint32,
 577  ) {
 578  	return new(types.Uint32)
 579  }
 580  func VersionEnc(
 581  	ver *types.Uint32,
 582  ) (enc *T) {
 583  	return New(NewPrefix(Version), ver)
 584  }
 585  func VersionDec(
 586  	ver *types.Uint32,
 587  ) (enc *T) {
 588  	return New(NewPrefix(), ver)
 589  }
 590  
 591  // PubkeySerial maps a pubkey hash to its unique serial number
 592  //
 593  //	3 prefix|8 pubkey hash|5 serial
 594  var PubkeySerial = next()
 595  
 596  func PubkeySerialVars() (p *types.PubHash, ser *types.Uint40) {
 597  	return new(types.PubHash), new(types.Uint40)
 598  }
 599  func PubkeySerialEnc(p *types.PubHash, ser *types.Uint40) (enc *T) {
 600  	return New(NewPrefix(PubkeySerial), p, ser)
 601  }
 602  func PubkeySerialDec(p *types.PubHash, ser *types.Uint40) (enc *T) {
 603  	return New(NewPrefix(), p, ser)
 604  }
 605  
 606  // SerialPubkey maps a pubkey serial to the full 32-byte pubkey
 607  // This stores the full pubkey (32 bytes) as the value, not inline
 608  //
 609  //	3 prefix|5 serial -> 32 byte pubkey value
 610  var SerialPubkey = next()
 611  
 612  func SerialPubkeyVars() (ser *types.Uint40) {
 613  	return new(types.Uint40)
 614  }
 615  func SerialPubkeyEnc(ser *types.Uint40) (enc *T) {
 616  	return New(NewPrefix(SerialPubkey), ser)
 617  }
 618  func SerialPubkeyDec(ser *types.Uint40) (enc *T) {
 619  	return New(NewPrefix(), ser)
 620  }
 621  
 622  // EventPubkeyGraph creates a bidirectional graph edge between events and pubkeys
 623  // This stores event_serial -> pubkey_serial relationships with event kind and direction
 624  // Direction: 0=author, 1=p-tag-out (event references pubkey)
 625  //
 626  //	3 prefix|5 event serial|5 pubkey serial|2 kind|1 direction
 627  var EventPubkeyGraph = next()
 628  
 629  func EventPubkeyGraphVars() (eventSer *types.Uint40, pubkeySer *types.Uint40, kind *types.Uint16, direction *types.Letter) {
 630  	return new(types.Uint40), new(types.Uint40), new(types.Uint16), new(types.Letter)
 631  }
 632  func EventPubkeyGraphEnc(eventSer *types.Uint40, pubkeySer *types.Uint40, kind *types.Uint16, direction *types.Letter) (enc *T) {
 633  	return New(NewPrefix(EventPubkeyGraph), eventSer, pubkeySer, kind, direction)
 634  }
 635  func EventPubkeyGraphDec(eventSer *types.Uint40, pubkeySer *types.Uint40, kind *types.Uint16, direction *types.Letter) (enc *T) {
 636  	return New(NewPrefix(), eventSer, pubkeySer, kind, direction)
 637  }
 638  
 639  // PubkeyEventGraph creates the reverse edge: pubkey_serial -> event_serial with event kind and direction
 640  // This enables querying all events related to a pubkey, optionally filtered by kind and direction
 641  // Direction: 0=is-author, 2=p-tag-in (pubkey is referenced by event)
 642  //
 643  //	3 prefix|5 pubkey serial|2 kind|1 direction|5 event serial
 644  var PubkeyEventGraph = next()
 645  
 646  func PubkeyEventGraphVars() (pubkeySer *types.Uint40, kind *types.Uint16, direction *types.Letter, eventSer *types.Uint40) {
 647  	return new(types.Uint40), new(types.Uint16), new(types.Letter), new(types.Uint40)
 648  }
 649  func PubkeyEventGraphEnc(pubkeySer *types.Uint40, kind *types.Uint16, direction *types.Letter, eventSer *types.Uint40) (enc *T) {
 650  	return New(NewPrefix(PubkeyEventGraph), pubkeySer, kind, direction, eventSer)
 651  }
 652  func PubkeyEventGraphDec(pubkeySer *types.Uint40, kind *types.Uint16, direction *types.Letter, eventSer *types.Uint40) (enc *T) {
 653  	return New(NewPrefix(), pubkeySer, kind, direction, eventSer)
 654  }
 655  
 656  // SerialEventId maps an event serial to its full 32-byte event ID.
 657  // This enables reconstruction of the original event ID from compact storage.
 658  // The event ID is stored as the value (32 bytes), not inline in the key.
 659  //
 660  //	3 prefix|5 serial -> 32 byte event ID value
 661  var SerialEventId = next()
 662  
 663  func SerialEventIdVars() (ser *types.Uint40) {
 664  	return new(types.Uint40)
 665  }
 666  func SerialEventIdEnc(ser *types.Uint40) (enc *T) {
 667  	return New(NewPrefix(SerialEventId), ser)
 668  }
 669  func SerialEventIdDec(ser *types.Uint40) (enc *T) {
 670  	return New(NewPrefix(), ser)
 671  }
 672  
 673  // CompactEvent stores events using serial references instead of full IDs/pubkeys.
 674  // This dramatically reduces storage size by replacing:
 675  // - 32-byte event ID with 5-byte serial
 676  // - 32-byte author pubkey with 5-byte pubkey serial
 677  // - 32-byte e-tag values with 5-byte event serials (or full ID if unknown)
 678  // - 32-byte p-tag values with 5-byte pubkey serials
 679  //
 680  // Format: cmp|5 serial|compact event data (variable length)
 681  var CompactEvent = next()
 682  
 683  func CompactEventVars() (ser *types.Uint40) { return new(types.Uint40) }
 684  func CompactEventEnc(ser *types.Uint40) (enc *T) {
 685  	return New(NewPrefix(CompactEvent), ser)
 686  }
 687  func CompactEventDec(ser *types.Uint40) (enc *T) { return New(NewPrefix(), ser) }
 688  
 689  // EventEventGraph creates a bidirectional graph edge between events via e-tags.
 690  // This stores source_event_serial -> target_event_serial relationships with event kind and direction.
 691  // Used for thread traversal and finding replies/reactions/reposts to events.
 692  // Direction: 0=outbound (this event references target)
 693  //
 694  //	3 prefix|5 source event serial|5 target event serial|2 kind|1 direction
 695  var EventEventGraph = next()
 696  
 697  func EventEventGraphVars() (srcSer *types.Uint40, tgtSer *types.Uint40, kind *types.Uint16, direction *types.Letter) {
 698  	return new(types.Uint40), new(types.Uint40), new(types.Uint16), new(types.Letter)
 699  }
 700  func EventEventGraphEnc(srcSer *types.Uint40, tgtSer *types.Uint40, kind *types.Uint16, direction *types.Letter) (enc *T) {
 701  	return New(NewPrefix(EventEventGraph), srcSer, tgtSer, kind, direction)
 702  }
 703  func EventEventGraphDec(srcSer *types.Uint40, tgtSer *types.Uint40, kind *types.Uint16, direction *types.Letter) (enc *T) {
 704  	return New(NewPrefix(), srcSer, tgtSer, kind, direction)
 705  }
 706  
 707  // GraphEventEvent creates the reverse edge: target_event_serial -> source_event_serial with kind and direction.
 708  // This enables querying all events that reference a target event (e.g., all replies to a post).
 709  // Direction: 1=inbound (target is referenced by source)
 710  //
 711  //	3 prefix|5 target event serial|2 kind|1 direction|5 source event serial
 712  var GraphEventEvent = next()
 713  
 714  func GraphEventEventVars() (tgtSer *types.Uint40, kind *types.Uint16, direction *types.Letter, srcSer *types.Uint40) {
 715  	return new(types.Uint40), new(types.Uint16), new(types.Letter), new(types.Uint40)
 716  }
 717  func GraphEventEventEnc(tgtSer *types.Uint40, kind *types.Uint16, direction *types.Letter, srcSer *types.Uint40) (enc *T) {
 718  	return New(NewPrefix(GraphEventEvent), tgtSer, kind, direction, srcSer)
 719  }
 720  func GraphEventEventDec(tgtSer *types.Uint40, kind *types.Uint16, direction *types.Letter, srcSer *types.Uint40) (enc *T) {
 721  	return New(NewPrefix(), tgtSer, kind, direction, srcSer)
 722  }
 723  
 724  // PubkeyPubkeyGraph creates a direct noun-noun edge between pubkeys.
 725  // This materializes the pubkey→event→pubkey two-hop traversal into a single-hop
 726  // lookup, enabling direct social graph queries without event decode.
 727  // The event kind that created the relationship is preserved for filtering
 728  // (e.g., kind 3 = follow, kind 1 = mention, kind 7 = reaction).
 729  // The event serial is included to enable back-traversal to the originating event.
 730  //
 731  //	3 prefix|5 source pubkey serial|5 target pubkey serial|2 kind|1 direction|5 event serial
 732  var PubkeyPubkeyGraph = next()
 733  
 734  func PubkeyPubkeyGraphVars() (srcPk *types.Uint40, tgtPk *types.Uint40, kind *types.Uint16, direction *types.Letter, eventSer *types.Uint40) {
 735  	return new(types.Uint40), new(types.Uint40), new(types.Uint16), new(types.Letter), new(types.Uint40)
 736  }
 737  func PubkeyPubkeyGraphEnc(srcPk *types.Uint40, tgtPk *types.Uint40, kind *types.Uint16, direction *types.Letter, eventSer *types.Uint40) (enc *T) {
 738  	return New(NewPrefix(PubkeyPubkeyGraph), srcPk, tgtPk, kind, direction, eventSer)
 739  }
 740  func PubkeyPubkeyGraphDec(srcPk *types.Uint40, tgtPk *types.Uint40, kind *types.Uint16, direction *types.Letter, eventSer *types.Uint40) (enc *T) {
 741  	return New(NewPrefix(), srcPk, tgtPk, kind, direction, eventSer)
 742  }
 743  
 744  // GraphPubkeyPubkey creates the reverse noun-noun edge: target pubkey -> source pubkey.
 745  // This enables querying "who references this pubkey?" as a single prefix scan.
 746  // Kind and direction are positioned before the trailing serial for efficient
 747  // filtered scans (e.g., "all kind-3 followers of pubkey X").
 748  //
 749  //	3 prefix|5 target pubkey serial|2 kind|1 direction|5 source pubkey serial|5 event serial
 750  var GraphPubkeyPubkey = next()
 751  
 752  func GraphPubkeyPubkeyVars() (tgtPk *types.Uint40, kind *types.Uint16, direction *types.Letter, srcPk *types.Uint40, eventSer *types.Uint40) {
 753  	return new(types.Uint40), new(types.Uint16), new(types.Letter), new(types.Uint40), new(types.Uint40)
 754  }
 755  func GraphPubkeyPubkeyEnc(tgtPk *types.Uint40, kind *types.Uint16, direction *types.Letter, srcPk *types.Uint40, eventSer *types.Uint40) (enc *T) {
 756  	return New(NewPrefix(GraphPubkeyPubkey), tgtPk, kind, direction, srcPk, eventSer)
 757  }
 758  func GraphPubkeyPubkeyDec(tgtPk *types.Uint40, kind *types.Uint16, direction *types.Letter, srcPk *types.Uint40, eventSer *types.Uint40) (enc *T) {
 759  	return New(NewPrefix(), tgtPk, kind, direction, srcPk, eventSer)
 760  }
 761