You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
187 lines
4.6 KiB
187 lines
4.6 KiB
package database |
|
|
|
import ( |
|
"bytes" |
|
|
|
"lol.mleku.dev/chk" |
|
"next.orly.dev/pkg/database/indexes" |
|
. "next.orly.dev/pkg/database/indexes/types" |
|
"git.mleku.dev/mleku/nostr/encoders/event" |
|
) |
|
|
|
// appendIndexBytes marshals an index to a byte slice and appends it to the idxs slice |
|
func appendIndexBytes(idxs *[][]byte, idx *indexes.T) (err error) { |
|
buf := new(bytes.Buffer) |
|
// Marshal the index to the buffer |
|
if err = idx.MarshalWrite(buf); chk.E(err) { |
|
return |
|
} |
|
// Copy the buffer's bytes to a new byte slice |
|
// Append the byte slice to the idxs slice |
|
*idxs = append(*idxs, buf.Bytes()) |
|
return |
|
} |
|
|
|
// GetIndexesForEvent creates all the indexes for an event.E instance as defined |
|
// in keys.go. It returns a slice of byte slices that can be used to store the |
|
// event in the database. |
|
func GetIndexesForEvent(ev *event.E, serial uint64) ( |
|
idxs [][]byte, err error, |
|
) { |
|
defer func() { |
|
if chk.E(err) { |
|
idxs = nil |
|
} |
|
}() |
|
// Convert serial to Uint40 |
|
ser := new(Uint40) |
|
if err = ser.Set(serial); chk.E(err) { |
|
return |
|
} |
|
// ID index |
|
idHash := new(IdHash) |
|
if err = idHash.FromId(ev.ID); chk.E(err) { |
|
return |
|
} |
|
idIndex := indexes.IdEnc(idHash, ser) |
|
if err = appendIndexBytes(&idxs, idIndex); chk.E(err) { |
|
return |
|
} |
|
// FullIdPubkey index |
|
fullID := new(Id) |
|
if err = fullID.FromId(ev.ID); chk.E(err) { |
|
return |
|
} |
|
pubHash := new(PubHash) |
|
if err = pubHash.FromPubkey(ev.Pubkey); chk.E(err) { |
|
return |
|
} |
|
createdAt := new(Uint64) |
|
createdAt.Set(uint64(ev.CreatedAt)) |
|
idPubkeyIndex := indexes.FullIdPubkeyEnc( |
|
ser, fullID, pubHash, createdAt, |
|
) |
|
if err = appendIndexBytes(&idxs, idPubkeyIndex); chk.E(err) { |
|
return |
|
} |
|
// CreatedAt index |
|
createdAtIndex := indexes.CreatedAtEnc(createdAt, ser) |
|
if err = appendIndexBytes(&idxs, createdAtIndex); chk.E(err) { |
|
return |
|
} |
|
// PubkeyCreatedAt index |
|
pubkeyIndex := indexes.PubkeyEnc(pubHash, createdAt, ser) |
|
if err = appendIndexBytes(&idxs, pubkeyIndex); chk.E(err) { |
|
return |
|
} |
|
// Process tags for tag-related indexes |
|
if ev.Tags != nil && ev.Tags.Len() > 0 { |
|
for _, t := range *ev.Tags { |
|
// only index tags with a value field and the key is a single character |
|
if t.Len() >= 2 { |
|
// Get the key and value from the tag |
|
keyBytes := t.Key() |
|
// require single-letter key |
|
if len(keyBytes) != 1 { |
|
continue |
|
} |
|
// if the key is not a-zA-Z skip |
|
if (keyBytes[0] < 'a' || keyBytes[0] > 'z') && |
|
(keyBytes[0] < 'A' || keyBytes[0] > 'Z') { |
|
continue |
|
} |
|
valueBytes := t.Value() |
|
// Create tag key and value |
|
key := new(Letter) |
|
key.Set(keyBytes[0]) |
|
valueHash := new(Ident) |
|
valueHash.FromIdent(valueBytes) |
|
// TagPubkey index |
|
pubkeyTagIndex := indexes.TagPubkeyEnc( |
|
key, valueHash, pubHash, createdAt, ser, |
|
) |
|
if err = appendIndexBytes( |
|
&idxs, pubkeyTagIndex, |
|
); chk.E(err) { |
|
return |
|
} |
|
// Tag index |
|
tagIndex := indexes.TagEnc( |
|
key, valueHash, createdAt, ser, |
|
) |
|
if err = appendIndexBytes( |
|
&idxs, tagIndex, |
|
); chk.E(err) { |
|
return |
|
} |
|
// Kind-related tag indexes |
|
kind := new(Uint16) |
|
kind.Set(ev.Kind) |
|
// TagKind index |
|
kindTagIndex := indexes.TagKindEnc( |
|
key, valueHash, kind, createdAt, ser, |
|
) |
|
if err = appendIndexBytes( |
|
&idxs, kindTagIndex, |
|
); chk.E(err) { |
|
return |
|
} |
|
// TagKindPubkey index |
|
kindPubkeyTagIndex := indexes.TagKindPubkeyEnc( |
|
key, valueHash, kind, pubHash, createdAt, ser, |
|
) |
|
if err = appendIndexBytes( |
|
&idxs, kindPubkeyTagIndex, |
|
); chk.E(err) { |
|
return |
|
} |
|
} |
|
} |
|
} |
|
kind := new(Uint16) |
|
kind.Set(uint16(ev.Kind)) |
|
// Kind index |
|
kindIndex := indexes.KindEnc(kind, createdAt, ser) |
|
if err = appendIndexBytes(&idxs, kindIndex); chk.E(err) { |
|
return |
|
} |
|
// KindPubkey index |
|
// Using the correct parameters based on the function signature |
|
kindPubkeyIndex := indexes.KindPubkeyEnc( |
|
kind, pubHash, createdAt, ser, |
|
) |
|
if err = appendIndexBytes(&idxs, kindPubkeyIndex); chk.E(err) { |
|
return |
|
} |
|
|
|
// Word token indexes (from content) |
|
if len(ev.Content) > 0 { |
|
for _, h := range TokenHashes(ev.Content) { |
|
w := new(Word) |
|
w.FromWord(h) // 8-byte truncated hash |
|
wIdx := indexes.WordEnc(w, ser) |
|
if err = appendIndexBytes(&idxs, wIdx); chk.E(err) { |
|
return |
|
} |
|
} |
|
} |
|
// Extend full-text search to include all fields of all tags |
|
if ev.Tags != nil && ev.Tags.Len() > 0 { |
|
for _, t := range *ev.Tags { |
|
for _, field := range t.T { // include key and all values |
|
if len(field) == 0 { |
|
continue |
|
} |
|
for _, h := range TokenHashes(field) { |
|
w := new(Word) |
|
w.FromWord(h) |
|
wIdx := indexes.WordEnc(w, ser) |
|
if err = appendIndexBytes(&idxs, wIdx); chk.E(err) { |
|
return |
|
} |
|
} |
|
} |
|
} |
|
} |
|
return |
|
}
|
|
|