Migrate package imports from next.orly.dev to new orly domain structure; add new varint and binary encoders with comprehensive tests; enhance existing tag and envelope implementations with additional methods, validations, and test coverage; introduce shared test.sh script for streamlined testing across modules.
This commit is contained in:
439
pkg/database/indexes/keys.go
Normal file
439
pkg/database/indexes/keys.go
Normal file
@@ -0,0 +1,439 @@
|
||||
package indexes
|
||||
|
||||
import (
|
||||
"io"
|
||||
"reflect"
|
||||
|
||||
"database.orly/indexes/types"
|
||||
"interfaces.orly/codec"
|
||||
"lol.mleku.dev/chk"
|
||||
)
|
||||
|
||||
var counter int
|
||||
|
||||
func init() {
|
||||
// Initialize the counter to ensure it starts from 0
|
||||
counter = 0
|
||||
}
|
||||
|
||||
func next() int { counter++; return counter - 1 }
|
||||
|
||||
type P struct {
|
||||
val []byte
|
||||
}
|
||||
|
||||
func NewPrefix(prf ...int) (p *P) {
|
||||
if len(prf) > 0 {
|
||||
prefix := Prefix(prf[0])
|
||||
if prefix == "" {
|
||||
panic("unknown prefix")
|
||||
}
|
||||
return &P{[]byte(prefix)}
|
||||
} else {
|
||||
return &P{[]byte{0, 0, 0}}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *P) Bytes() (b []byte) { return p.val }
|
||||
|
||||
func (p *P) MarshalWrite(w io.Writer) (err error) {
|
||||
_, err = w.Write(p.val)
|
||||
return
|
||||
}
|
||||
|
||||
func (p *P) UnmarshalRead(r io.Reader) (err error) {
|
||||
// Allocate a buffer for val if it's nil or empty
|
||||
if p.val == nil || len(p.val) == 0 {
|
||||
p.val = make([]byte, 3) // Prefixes are 3 bytes
|
||||
}
|
||||
_, err = r.Read(p.val)
|
||||
return
|
||||
}
|
||||
|
||||
type I string
|
||||
|
||||
func (i I) Write(w io.Writer) (n int, err error) { return w.Write([]byte(i)) }
|
||||
|
||||
const (
|
||||
EventPrefix = I("evt")
|
||||
IdPrefix = I("eid")
|
||||
FullIdPubkeyPrefix = I("fpc") // full id, pubkey, created at
|
||||
|
||||
CreatedAtPrefix = I("c--") // created at
|
||||
KindPrefix = I("kc-") // kind, created at
|
||||
PubkeyPrefix = I("pc-") // pubkey, created at
|
||||
KindPubkeyPrefix = I("kpc") // kind, pubkey, created at
|
||||
|
||||
TagPrefix = I("tc-") // tag, created at
|
||||
TagKindPrefix = I("tkc") // tag, kind, created at
|
||||
TagPubkeyPrefix = I("tpc") // tag, pubkey, created at
|
||||
TagKindPubkeyPrefix = I("tkp") // tag, kind, pubkey, created at
|
||||
|
||||
ExpirationPrefix = I("exp") // timestamp of expiration
|
||||
VersionPrefix = I("ver") // database version number, for triggering reindexes when new keys are added (policy is add-only).
|
||||
)
|
||||
|
||||
// Prefix returns the three byte human-readable prefixes that go in front of
|
||||
// database indexes.
|
||||
func Prefix(prf int) (i I) {
|
||||
switch prf {
|
||||
case Event:
|
||||
return EventPrefix
|
||||
case Id:
|
||||
return IdPrefix
|
||||
case FullIdPubkey:
|
||||
return FullIdPubkeyPrefix
|
||||
|
||||
case CreatedAt:
|
||||
return CreatedAtPrefix
|
||||
case Kind:
|
||||
return KindPrefix
|
||||
case Pubkey:
|
||||
return PubkeyPrefix
|
||||
case KindPubkey:
|
||||
return KindPubkeyPrefix
|
||||
|
||||
case Tag:
|
||||
return TagPrefix
|
||||
case TagKind:
|
||||
return TagKindPrefix
|
||||
case TagPubkey:
|
||||
return TagPubkeyPrefix
|
||||
case TagKindPubkey:
|
||||
return TagKindPubkeyPrefix
|
||||
|
||||
case Expiration:
|
||||
return ExpirationPrefix
|
||||
case Version:
|
||||
return VersionPrefix
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Identify(r io.Reader) (i int, err error) {
|
||||
// this is here for completeness; however, searches don't need to identify
|
||||
// this as they work via generated prefixes made using Prefix.
|
||||
var b [3]byte
|
||||
_, err = r.Read(b[:])
|
||||
if err != nil {
|
||||
i = -1
|
||||
return
|
||||
}
|
||||
switch I(b[:]) {
|
||||
case EventPrefix:
|
||||
i = Event
|
||||
case IdPrefix:
|
||||
i = Id
|
||||
case FullIdPubkeyPrefix:
|
||||
i = FullIdPubkey
|
||||
|
||||
case CreatedAtPrefix:
|
||||
i = CreatedAt
|
||||
case KindPrefix:
|
||||
i = Kind
|
||||
case PubkeyPrefix:
|
||||
i = Pubkey
|
||||
case KindPubkeyPrefix:
|
||||
i = KindPubkey
|
||||
|
||||
case TagPrefix:
|
||||
i = Tag
|
||||
case TagKindPrefix:
|
||||
i = TagKind
|
||||
case TagPubkeyPrefix:
|
||||
i = TagPubkey
|
||||
case TagKindPubkeyPrefix:
|
||||
i = TagKindPubkey
|
||||
|
||||
case ExpirationPrefix:
|
||||
i = Expiration
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type Encs []codec.I
|
||||
|
||||
// T is a wrapper around an array of codec.I. The caller provides the Encs so
|
||||
// they can then call the accessor methods of the codec.I implementation.
|
||||
type T struct{ Encs }
|
||||
|
||||
// New creates a new indexes.T. The helper functions below have an encode and
|
||||
// decode variant, the decode variant doesn't add the prefix encoder because it
|
||||
// has been read by Identify or just is being read, and found because it was
|
||||
// written for the prefix in the iteration.
|
||||
func New(encoders ...codec.I) (i *T) { return &T{encoders} }
|
||||
func (t *T) MarshalWrite(w io.Writer) (err error) {
|
||||
for _, e := range t.Encs {
|
||||
if e == nil || reflect.ValueOf(e).IsNil() {
|
||||
// Skip nil encoders instead of returning early. This enables
|
||||
// generating search prefixes.
|
||||
continue
|
||||
}
|
||||
if err = e.MarshalWrite(w); chk.E(err) {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
func (t *T) UnmarshalRead(r io.Reader) (err error) {
|
||||
for _, e := range t.Encs {
|
||||
if err = e.UnmarshalRead(r); chk.E(err) {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Event is the whole event stored in binary format
|
||||
//
|
||||
// prefix|5 serial - event in binary format
|
||||
var Event = next()
|
||||
|
||||
func EventVars() (ser *types.Uint40) { return new(types.Uint40) }
|
||||
func EventEnc(ser *types.Uint40) (enc *T) {
|
||||
return New(NewPrefix(Event), ser)
|
||||
}
|
||||
func EventDec(ser *types.Uint40) (enc *T) { return New(NewPrefix(), ser) }
|
||||
|
||||
// Id contains a truncated 8-byte hash of an event index. This is the secondary
|
||||
// key of an event, the primary key is the serial found in the Event.
|
||||
//
|
||||
// 3 prefix|8 ID hash|5 serial
|
||||
var Id = next()
|
||||
|
||||
func IdVars() (id *types.IdHash, ser *types.Uint40) {
|
||||
return new(types.IdHash), new(types.Uint40)
|
||||
}
|
||||
func IdEnc(id *types.IdHash, ser *types.Uint40) (enc *T) {
|
||||
return New(NewPrefix(Id), id, ser)
|
||||
}
|
||||
func IdDec(id *types.IdHash, ser *types.Uint40) (enc *T) {
|
||||
return New(NewPrefix(), id, ser)
|
||||
}
|
||||
|
||||
// FullIdPubkey is an index designed to enable sorting and filtering of
|
||||
// results found via other indexes, without having to decode the event.
|
||||
//
|
||||
// 3 prefix|5 serial|32 ID|8 pubkey hash|8 timestamp
|
||||
var FullIdPubkey = next()
|
||||
|
||||
func FullIdPubkeyVars() (
|
||||
ser *types.Uint40, fid *types.Id, p *types.PubHash, ca *types.Uint64,
|
||||
) {
|
||||
return new(types.Uint40), new(types.Id), new(types.PubHash), new(types.Uint64)
|
||||
}
|
||||
func FullIdPubkeyEnc(
|
||||
ser *types.Uint40, fid *types.Id, p *types.PubHash, ca *types.Uint64,
|
||||
) (enc *T) {
|
||||
return New(NewPrefix(FullIdPubkey), ser, fid, p, ca)
|
||||
}
|
||||
func FullIdPubkeyDec(
|
||||
ser *types.Uint40, fid *types.Id, p *types.PubHash, ca *types.Uint64,
|
||||
) (enc *T) {
|
||||
return New(NewPrefix(), ser, fid, p, ca)
|
||||
}
|
||||
|
||||
// CreatedAt is an index that allows search for the timestamp on the event.
|
||||
//
|
||||
// 3 prefix|8 timestamp|5 serial
|
||||
var CreatedAt = next()
|
||||
|
||||
func CreatedAtVars() (ca *types.Uint64, ser *types.Uint40) {
|
||||
return new(types.Uint64), new(types.Uint40)
|
||||
}
|
||||
func CreatedAtEnc(ca *types.Uint64, ser *types.Uint40) (enc *T) {
|
||||
return New(NewPrefix(CreatedAt), ca, ser)
|
||||
}
|
||||
func CreatedAtDec(ca *types.Uint64, ser *types.Uint40) (enc *T) {
|
||||
return New(NewPrefix(), ca, ser)
|
||||
}
|
||||
|
||||
// Kind
|
||||
//
|
||||
// 3 prefix|2 kind|8 timestamp|5 serial
|
||||
var Kind = next()
|
||||
|
||||
func KindVars() (ki *types.Uint16, ca *types.Uint64, ser *types.Uint40) {
|
||||
return new(types.Uint16), new(types.Uint64), new(types.Uint40)
|
||||
}
|
||||
func KindEnc(ki *types.Uint16, ca *types.Uint64, ser *types.Uint40) (enc *T) {
|
||||
return New(NewPrefix(Kind), ki, ca, ser)
|
||||
}
|
||||
func KindDec(ki *types.Uint16, ca *types.Uint64, ser *types.Uint40) (enc *T) {
|
||||
return New(NewPrefix(), ki, ca, ser)
|
||||
}
|
||||
|
||||
// Pubkey is a composite index that allows search by pubkey
|
||||
// filtered by timestamp.
|
||||
//
|
||||
// 3 prefix|8 pubkey hash|8 timestamp|5 serial
|
||||
var Pubkey = next()
|
||||
|
||||
func PubkeyVars() (p *types.PubHash, ca *types.Uint64, ser *types.Uint40) {
|
||||
return new(types.PubHash), new(types.Uint64), new(types.Uint40)
|
||||
}
|
||||
func PubkeyEnc(p *types.PubHash, ca *types.Uint64, ser *types.Uint40) (enc *T) {
|
||||
return New(NewPrefix(Pubkey), p, ca, ser)
|
||||
}
|
||||
func PubkeyDec(p *types.PubHash, ca *types.Uint64, ser *types.Uint40) (enc *T) {
|
||||
return New(NewPrefix(), p, ca, ser)
|
||||
}
|
||||
|
||||
// KindPubkey
|
||||
//
|
||||
// 3 prefix|2 kind|8 pubkey hash|8 timestamp|5 serial
|
||||
var KindPubkey = next()
|
||||
|
||||
func KindPubkeyVars() (
|
||||
ki *types.Uint16, p *types.PubHash, ca *types.Uint64, ser *types.Uint40,
|
||||
) {
|
||||
return new(types.Uint16), new(types.PubHash), new(types.Uint64), new(types.Uint40)
|
||||
}
|
||||
func KindPubkeyEnc(
|
||||
ki *types.Uint16, p *types.PubHash, ca *types.Uint64, ser *types.Uint40,
|
||||
) (enc *T) {
|
||||
return New(NewPrefix(KindPubkey), ki, p, ca, ser)
|
||||
}
|
||||
func KindPubkeyDec(
|
||||
ki *types.Uint16, p *types.PubHash, ca *types.Uint64, ser *types.Uint40,
|
||||
) (enc *T) {
|
||||
return New(NewPrefix(), ki, p, ca, ser)
|
||||
}
|
||||
|
||||
// Tag allows searching for a tag and filter by timestamp.
|
||||
//
|
||||
// 3 prefix|1 key letter|8 value hash|8 timestamp|5 serial
|
||||
var Tag = next()
|
||||
|
||||
func TagVars() (
|
||||
k *types.Letter, v *types.Ident, ca *types.Uint64, ser *types.Uint40,
|
||||
) {
|
||||
return new(types.Letter), new(types.Ident), new(types.Uint64), new(types.Uint40)
|
||||
}
|
||||
func TagEnc(
|
||||
k *types.Letter, v *types.Ident, ca *types.Uint64, ser *types.Uint40,
|
||||
) (enc *T) {
|
||||
return New(NewPrefix(Tag), k, v, ca, ser)
|
||||
}
|
||||
func TagDec(
|
||||
k *types.Letter, v *types.Ident, ca *types.Uint64, ser *types.Uint40,
|
||||
) (enc *T) {
|
||||
return New(NewPrefix(), k, v, ca, ser)
|
||||
}
|
||||
|
||||
// TagKind
|
||||
//
|
||||
// 3 prefix|1 key letter|8 value hash|2 kind|8 timestamp|5 serial
|
||||
var TagKind = next()
|
||||
|
||||
func TagKindVars() (
|
||||
k *types.Letter, v *types.Ident, ki *types.Uint16, ca *types.Uint64,
|
||||
ser *types.Uint40,
|
||||
) {
|
||||
return new(types.Letter), new(types.Ident), new(types.Uint16), new(types.Uint64), new(types.Uint40)
|
||||
}
|
||||
func TagKindEnc(
|
||||
k *types.Letter, v *types.Ident, ki *types.Uint16, ca *types.Uint64,
|
||||
ser *types.Uint40,
|
||||
) (enc *T) {
|
||||
return New(NewPrefix(TagKind), ki, k, v, ca, ser)
|
||||
}
|
||||
func TagKindDec(
|
||||
k *types.Letter, v *types.Ident, ki *types.Uint16, ca *types.Uint64,
|
||||
ser *types.Uint40,
|
||||
) (enc *T) {
|
||||
return New(NewPrefix(), ki, k, v, ca, ser)
|
||||
}
|
||||
|
||||
// TagPubkey allows searching for a pubkey, tag and timestamp.
|
||||
//
|
||||
// 3 prefix|1 key letter|8 value hash|8 pubkey hash|8 timestamp|5 serial
|
||||
var TagPubkey = next()
|
||||
|
||||
func TagPubkeyVars() (
|
||||
k *types.Letter, v *types.Ident, p *types.PubHash, ca *types.Uint64,
|
||||
ser *types.Uint40,
|
||||
) {
|
||||
return new(types.Letter), new(types.Ident), new(types.PubHash), new(types.Uint64), new(types.Uint40)
|
||||
}
|
||||
func TagPubkeyEnc(
|
||||
k *types.Letter, v *types.Ident, p *types.PubHash, ca *types.Uint64,
|
||||
ser *types.Uint40,
|
||||
) (enc *T) {
|
||||
return New(NewPrefix(TagPubkey), p, k, v, ca, ser)
|
||||
}
|
||||
func TagPubkeyDec(
|
||||
k *types.Letter, v *types.Ident, p *types.PubHash, ca *types.Uint64,
|
||||
ser *types.Uint40,
|
||||
) (enc *T) {
|
||||
return New(NewPrefix(), p, k, v, ca, ser)
|
||||
}
|
||||
|
||||
// TagKindPubkey
|
||||
//
|
||||
// 3 prefix|1 key letter|8 value hash|2 kind|8 pubkey hash|8 bytes timestamp|5 serial
|
||||
var TagKindPubkey = next()
|
||||
|
||||
func TagKindPubkeyVars() (
|
||||
k *types.Letter, v *types.Ident, ki *types.Uint16, p *types.PubHash,
|
||||
ca *types.Uint64,
|
||||
ser *types.Uint40,
|
||||
) {
|
||||
return new(types.Letter), new(types.Ident), new(types.Uint16), new(types.PubHash), new(types.Uint64), new(types.Uint40)
|
||||
}
|
||||
func TagKindPubkeyEnc(
|
||||
k *types.Letter, v *types.Ident, ki *types.Uint16, p *types.PubHash,
|
||||
ca *types.Uint64,
|
||||
ser *types.Uint40,
|
||||
) (enc *T) {
|
||||
return New(NewPrefix(TagKindPubkey), ki, p, k, v, ca, ser)
|
||||
}
|
||||
func TagKindPubkeyDec(
|
||||
k *types.Letter, v *types.Ident, ki *types.Uint16, p *types.PubHash,
|
||||
ca *types.Uint64,
|
||||
ser *types.Uint40,
|
||||
) (enc *T) {
|
||||
return New(NewPrefix(), ki, p, k, v, ca, ser)
|
||||
}
|
||||
|
||||
// Expiration
|
||||
//
|
||||
// 3 prefix|8 timestamp|5 serial
|
||||
var Expiration = next()
|
||||
|
||||
func ExpirationVars() (
|
||||
exp *types.Uint64, ser *types.Uint40,
|
||||
) {
|
||||
return new(types.Uint64), new(types.Uint40)
|
||||
}
|
||||
func ExpirationEnc(
|
||||
exp *types.Uint64, ser *types.Uint40,
|
||||
) (enc *T) {
|
||||
return New(NewPrefix(Expiration), exp, ser)
|
||||
}
|
||||
func ExpirationDec(
|
||||
exp *types.Uint64, ser *types.Uint40,
|
||||
) (enc *T) {
|
||||
return New(NewPrefix(), exp, ser)
|
||||
}
|
||||
|
||||
// Version
|
||||
//
|
||||
// 3 prefix|4 version
|
||||
var Version = next()
|
||||
|
||||
func VersionVars() (
|
||||
ver *types.Uint32,
|
||||
) {
|
||||
return new(types.Uint32)
|
||||
}
|
||||
func VersionEnc(
|
||||
ver *types.Uint32,
|
||||
) (enc *T) {
|
||||
return New(NewPrefix(Version), ver)
|
||||
}
|
||||
func VersionDec(
|
||||
ver *types.Uint32,
|
||||
) (enc *T) {
|
||||
return New(NewPrefix(), ver)
|
||||
}
|
||||
Reference in New Issue
Block a user