Skip to content

fgrzl/lexkey

Repository files navigation

ci Dependabot Updates

lexkey

lexkey is a lightweight lexicographically sortable key encoding library for Go. It provides consistent, ordered, and efficient encoding for common data types so they sort correctly in byte-wise order.

✨ Features

  • πŸš€ Lexicographically sortable encoding for structured keys.
  • πŸ”‘ Supports strings, integers, floats, UUIDs, booleans, timestamps, durations, and byte slices.
  • πŸ”„ Consistent ordering for mixed types like int32 and int64.
  • πŸ“¦ Optimized encoding for space efficiency and speed.
  • πŸ“‘ JSON serialization support for interoperability.

πŸ“¦ Installation

go get github.com/fgrzl/lexkey

Documentation

Guides: docs/ β€” overview, getting started. Wire format: SPEC.md.

πŸ›  Usage

Create a LexKey

key := lexkey.Encode("user", 123, true)
fmt.Println("Encoded Key (Hex):", key.ToHexString())

Sorting Keys

key1 := lexkey.Encode("apple")
key2 := lexkey.Encode("banana")

fmt.Println(string(key1) < string(key2)) // βœ… True (correct lexicographic order)

Handling Numbers

key1 := lexkey.Encode(int64(-100))
key2 := lexkey.Encode(int64(50))

fmt.Println(string(key1) < string(key2)) // βœ… True (correct sorting for signed integers)

Using UUIDs

import "github.com/google/uuid"

id := uuid.New()
key := lexkey.Encode("order", id)

fmt.Println("Encoded UUID Key:", key.ToHexString())

LexKey JSON Serialization

import "encoding/json"

key := lexkey.Encode("session", 42)
jsonData, _ := json.Marshal(key)
fmt.Println(string(jsonData)) // βœ… Encoded as a hex string

πŸ” Supported Data Types

Type Supported? Encoding Details
string βœ… Yes Stored as raw UTF-8 bytes
int32 βœ… Yes Canonicalized to int64 for uniform sorting
int64 βœ… Yes Sign-bit flipped for correct ordering
uint32 βœ… Yes Big-endian encoded
uint64 βœ… Yes Big-endian encoded
float32 βœ… Yes Canonicalized to float64 then transformed
float64 βœ… Yes IEEE 754 encoded with sign-bit transformation
bool βœ… Yes true β†’ 0x01, false β†’ 0x00
uuid.UUID βœ… Yes 16-byte raw representation
[]byte βœ… Yes Stored as-is
time.Time βœ… Yes Encoded as int64 nanoseconds since Unix epoch
time.Duration βœ… Yes Encoded as int64 nanoseconds

πŸ“Œ Key Functions

Encoding Keys

func Encode(parts ...any) LexKey
func NewLexKey(parts ...any) (LexKey, error)
func EncodeInto(dst []byte, parts ...any) (int, error)
func EncodeSize(parts ...any) int

Notes:

  • As of 2025-10-01, numeric width canonicalization is the default (breaking change):
    • int, int8, int16, int32 β†’ int64
    • uint8, uint16, uint32 β†’ uint64
    • float32 β†’ float64
  • For explicit use, the following helpers are provided (equivalent to default behavior):
    • EncodeCanonicalWidth / NewLexKeyCanonicalWidth / EncodeIntoCanonicalWidth / EncodeSizeCanonicalWidth

Sorting Helpers

func EncodeFirst(parts ...any) LexKey // lower bound: prefix + 0x00 (sorts before any extension of the prefix)
func EncodeLast(parts ...any) LexKey  // upper bound: prefix + 0xFF (sorts after any extension of the prefix)
func Compare(a, b LexKey) int         // -1/0/1 without allocations

Prefix scans:

// To scan all keys with a given prefix, use a half-open range [lower, upper):
lower := lexkey.EncodeFirst("tenant", "users") // ... 00
upper := lexkey.EncodeLast("tenant", "users")  // ... ff
// All keys that start with ("tenant", "users", ...) will satisfy: lower <= key && key < upper

Hex Encoding

func (e LexKey) ToHexString() string
func (e *LexKey) FromHexString(hexStr string) error

JSON Serialization

func (e LexKey) MarshalJSON() ([]byte, error)
func (e *LexKey) UnmarshalJSON(data []byte) error

πŸ† Why Use lexkey?

βœ… Fast & Efficient β†’ Uses compact, binary-safe encoding.
βœ… Correct Ordering β†’ Works across all supported types.
βœ… Minimal Dependencies β†’ Only uuid and standard Go packages.

πŸ›  Testing

Run the full test suite:

go test -cover ./...

πŸ”„ Breaking change (2025-10-01)

Numeric width canonicalization is now the default. This ensures logical numeric ordering across widths (e.g., uint32(1) and uint64(1) are equal on the wire). If you require the previous native-width bytes, pin an older release or re-encode using legacy rules as described in SPEC.md.

See SPEC.md for the full encoding specification and test vectors.

Test Coverage: βœ… 99.6% 🎯

About

Lexicographically sortable key encoding library for Go

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages