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