Documentation
¶
Overview ¶
Package typed provides typed wrappers around the generic Murmur QueryService — the building block for application services that want to expose typed protos to their callers rather than the generic Value{bytes} shape.
Why this exists ¶
Murmur's `pkg/query/grpc.QueryService` returns `Value{present, data}` where `data` is the wire-encoded monoid value (int64-LE for Sum/Count/Min/Max, marshaled HLL/TopK/Bloom for sketches). Clients decode the bytes per the pipeline's monoid kind. This is right for Murmur — it keeps the service monoid-agnostic — but it pushes decoding boilerplate to every caller.
The typed-wrapper pattern: an application service exposes its OWN Connect-RPC API with typed responses (e.g. count-core's `BotInteractionCountService.GetBotInteractionCount(...) → int64`). The implementation calls the underlying Murmur QueryService, decodes the bytes via this package, and returns the typed shape. Callers see typed protos; Murmur stays generic.
This package ships the decoders + thin typed-client wrappers for the shipped monoid kinds: Sum/Count/Min/Max (int64), HLL, TopK, Bloom. Full per-pipeline codegen — generating a typed `*ServerStub` per pipeline — is Phase 2 roadmap; this package is the building block it would generate against.
Usage ¶
Wrap a generic Murmur QueryService client once:
rawClient := murmurv1connect.NewQueryServiceClient(httpClient, baseURL)
likes := typed.NewSumClient(rawClient)
// Now: typed Get / GetMany / GetWindow.
count, present, err := likes.Get(ctx, "post-123")
counts, err := likes.GetMany(ctx, []string{"post-123", "post-456"})
last24h, err := likes.GetWindow(ctx, "post-123", 24*time.Hour)
Build your own Connect-RPC service against the typed client:
type CountCoreServer struct {
likes *typed.SumClient
unique *typed.HLLClient
}
func (s *CountCoreServer) GetBotInteractionCount(ctx, req) (resp, error) {
n, ok, err := s.likes.Get(ctx, req.GetEntity())
if err != nil { return nil, connect.NewError(...) }
return &countpb.GetBotInteractionCountResponse{
Count: n,
Present: ok,
}, nil
}
The application's Connect-RPC service is whatever proto shape it wants; the typed client hides the bytes-decoding from it.
Index ¶
- Variables
- func DecodeInt64(data []byte) int64
- type BloomClient
- func (c *BloomClient) Get(ctx context.Context, entity string, opts ...Option) (BloomValue, bool, error)
- func (c *BloomClient) GetMany(ctx context.Context, entities []string, opts ...Option) ([]BloomValue, []bool, error)
- func (c *BloomClient) GetRange(ctx context.Context, entity string, start, end time.Time, opts ...Option) (BloomValue, error)
- func (c *BloomClient) GetWindow(ctx context.Context, entity string, duration time.Duration, opts ...Option) (BloomValue, error)
- func (c *BloomClient) GetWindowMany(ctx context.Context, entities []string, duration time.Duration, opts ...Option) ([]BloomValue, error)
- type BloomValue
- type HLLClient
- func (c *HLLClient) Get(ctx context.Context, entity string, opts ...Option) (HLLValue, bool, error)
- func (c *HLLClient) GetMany(ctx context.Context, entities []string, opts ...Option) ([]HLLValue, []bool, error)
- func (c *HLLClient) GetRange(ctx context.Context, entity string, start, end time.Time, opts ...Option) (HLLValue, error)
- func (c *HLLClient) GetWindow(ctx context.Context, entity string, duration time.Duration, opts ...Option) (HLLValue, error)
- func (c *HLLClient) GetWindowMany(ctx context.Context, entities []string, duration time.Duration, opts ...Option) ([]HLLValue, error)
- type HLLValue
- type Inner
- type Option
- type SumClient
- func (c *SumClient) Get(ctx context.Context, entity string, opts ...Option) (int64, bool, error)
- func (c *SumClient) GetMany(ctx context.Context, entities []string, opts ...Option) ([]int64, []bool, error)
- func (c *SumClient) GetRange(ctx context.Context, entity string, start, end time.Time, opts ...Option) (int64, error)
- func (c *SumClient) GetWindow(ctx context.Context, entity string, duration time.Duration, opts ...Option) (int64, error)
- func (c *SumClient) GetWindowMany(ctx context.Context, entities []string, duration time.Duration, opts ...Option) ([]int64, error)
- type TopKClient
- func (c *TopKClient) Get(ctx context.Context, entity string, opts ...Option) ([]TopKItem, bool, error)
- func (c *TopKClient) GetMany(ctx context.Context, entities []string, opts ...Option) ([][]TopKItem, []bool, error)
- func (c *TopKClient) GetRange(ctx context.Context, entity string, start, end time.Time, opts ...Option) ([]TopKItem, error)
- func (c *TopKClient) GetWindow(ctx context.Context, entity string, duration time.Duration, opts ...Option) ([]TopKItem, error)
- func (c *TopKClient) GetWindowMany(ctx context.Context, entities []string, duration time.Duration, opts ...Option) ([][]TopKItem, error)
- type TopKItem
Constants ¶
This section is empty.
Variables ¶
var ErrUnsupported = errors.New("typed client: operation not supported by underlying pipeline")
ErrUnsupported is returned by adapters that don't implement an optional method (e.g., calling GetWindow on a SumClient that only wraps a non-windowed pipeline). Wrapped via fmt.Errorf at the call site.
Functions ¶
func DecodeInt64 ¶
DecodeInt64 decodes an 8-byte little-endian int64. Mirrors the `mgrpc.Int64LE` encoder used server-side. Returns 0 for short inputs.
Types ¶
type BloomClient ¶
type BloomClient struct {
// contains filtered or unexported fields
}
BloomClient is the typed wrapper for Bloom-filter pipelines.
func NewBloomClient ¶
func NewBloomClient(inner Inner) *BloomClient
NewBloomClient wraps the generic QueryService client with Bloom approximate-size responses.
func (*BloomClient) Get ¶
func (c *BloomClient) Get(ctx context.Context, entity string, opts ...Option) (BloomValue, bool, error)
Get returns the Bloom filter's shape for the entity's all-time sketch.
func (*BloomClient) GetMany ¶ added in v0.2.0
func (c *BloomClient) GetMany(ctx context.Context, entities []string, opts ...Option) ([]BloomValue, []bool, error)
GetMany batches Get for many entities (all-time, non-windowed). Order matches input order; missing entities yield a zero-valued BloomValue with the corresponding bool false in the present slice.
func (*BloomClient) GetRange ¶ added in v0.2.0
func (c *BloomClient) GetRange(ctx context.Context, entity string, start, end time.Time, opts ...Option) (BloomValue, error)
GetRange returns the merged Bloom-filter shape over the absolute time range [start, end] for the given entity. Pipeline must be windowed. CapacityBits and HashFunctions reflect the per-bucket filter shape (stable filter-construction constants); ApproxSize is the union over the buckets in range.
func (*BloomClient) GetWindow ¶
func (c *BloomClient) GetWindow(ctx context.Context, entity string, duration time.Duration, opts ...Option) (BloomValue, error)
GetWindow returns the merged Bloom-filter shape over the most-recent `duration`. The merged sketch's capacity / hash count match the per-bucket sketches' shape; ApproxSize reflects the union over the window's buckets.
func (*BloomClient) GetWindowMany ¶
func (c *BloomClient) GetWindowMany(ctx context.Context, entities []string, duration time.Duration, opts ...Option) ([]BloomValue, error)
GetWindowMany is the batched analog of GetWindow — fetches the merged Bloom-filter shape for N entities in one round-trip. Returns parallel arrays: out[i] is the BloomValue for entities[i]; missing entities yield a zero-valued BloomValue.
type BloomValue ¶
BloomValue carries the Bloom filter's shape — capacity (bits), the number of hash functions, and the approximate set size derived from the populated bit count.
type HLLClient ¶
type HLLClient struct {
// contains filtered or unexported fields
}
HLLClient is the typed wrapper for HLL pipelines whose state is the axiomhq/hyperloglog byte format. Returns cardinality estimates rather than raw sketch bytes.
func NewHLLClient ¶
NewHLLClient wraps the generic QueryService client with HLL cardinality-estimate responses.
func (*HLLClient) GetMany ¶ added in v0.2.0
func (c *HLLClient) GetMany(ctx context.Context, entities []string, opts ...Option) ([]HLLValue, []bool, error)
GetMany batches Get for many entities (all-time, non-windowed). Order matches input order; missing entities return a zero-valued HLLValue plus the corresponding bool false in the present slice. Use this when you need to distinguish "absent" from "present-and-empty" — GetWindowMany cannot, since the underlying generic RPC returns the merged value without a per-entity present flag.
func (*HLLClient) GetRange ¶ added in v0.2.0
func (c *HLLClient) GetRange(ctx context.Context, entity string, start, end time.Time, opts ...Option) (HLLValue, error)
GetRange returns the cardinality estimate over the absolute time range [start, end] for the given entity. Pipeline must be windowed. The server merges the buckets falling in range via HLL union before the estimate is taken, so the result is the merged cardinality, not the sum of per-bucket cardinalities.
func (*HLLClient) GetWindow ¶
func (c *HLLClient) GetWindow(ctx context.Context, entity string, duration time.Duration, opts ...Option) (HLLValue, error)
GetWindow returns the cardinality estimate over the most-recent `duration`.
func (*HLLClient) GetWindowMany ¶
func (c *HLLClient) GetWindowMany(ctx context.Context, entities []string, duration time.Duration, opts ...Option) ([]HLLValue, error)
GetWindowMany is the batched analog of GetWindow — fetches windowed cardinalities for N entities in one round-trip. Returns parallel arrays: out[i] is the cardinality estimate for entities[i]; missing entities yield a zero-valued HLLValue.
type HLLValue ¶
HLLValue carries the estimated cardinality plus the byte length of the underlying sketch (useful for cluster-wide capacity tracking).
type Inner ¶
type Inner = murmurv1connect.QueryServiceClient
Inner is the underlying Connect-RPC client shape this package wraps. Production: the generated `murmurv1connect.QueryServiceClient`. Tests: a fake satisfying the same shape.
type Option ¶
type Option func(*queryOptions)
Option configures a typed Get / GetMany / GetWindow / GetRange call.
func WithFreshRead ¶
func WithFreshRead() Option
WithFreshRead sets the underlying request's fresh_read flag, bypassing server-side singleflight + cache layers. Used for read-your-writes flows.
type SumClient ¶
type SumClient struct {
// contains filtered or unexported fields
}
SumClient is the typed wrapper for Sum / Count / Min / Max pipelines whose state is `int64` and whose wire shape is 8-byte little-endian. The same client works against any of those four monoid kinds — they all encode int64 the same way.
func NewSumClient ¶
NewSumClient wraps the generic QueryService client with typed int64 responses. Use for any pipeline whose monoid is Sum / Count / Min / Max.
func (*SumClient) Get ¶
Get returns the all-time aggregation value for entity. The bool reports whether the entity exists in the store; missing entities return (0, false, nil). Use this for non-windowed pipelines.
func (*SumClient) GetMany ¶
func (c *SumClient) GetMany(ctx context.Context, entities []string, opts ...Option) ([]int64, []bool, error)
GetMany batches Get for many entities. Order matches input order; missing entities return 0 in the value slice with the corresponding bool false in the present slice.
func (*SumClient) GetRange ¶
func (c *SumClient) GetRange(ctx context.Context, entity string, start, end time.Time, opts ...Option) (int64, error)
GetRange returns the merged value over the absolute time range [start, end] for the given entity. Pipeline must be windowed.
type TopKClient ¶
type TopKClient struct {
// contains filtered or unexported fields
}
TopKClient is the typed wrapper for Misra-Gries Top-K pipelines. Returns ranked items rather than raw sketch bytes.
func NewTopKClient ¶
func NewTopKClient(inner Inner) *TopKClient
NewTopKClient wraps the generic QueryService client with TopK item-list responses.
func (*TopKClient) Get ¶
func (c *TopKClient) Get(ctx context.Context, entity string, opts ...Option) ([]TopKItem, bool, error)
Get returns the ranked top-K items for the entity's all-time sketch. Items are ordered by descending count.
func (*TopKClient) GetMany ¶ added in v0.2.0
func (c *TopKClient) GetMany(ctx context.Context, entities []string, opts ...Option) ([][]TopKItem, []bool, error)
GetMany batches Get for many entities (all-time, non-windowed). Order matches input order; missing entities return a nil slice plus the corresponding bool false in the present slice.
func (*TopKClient) GetRange ¶ added in v0.2.0
func (c *TopKClient) GetRange(ctx context.Context, entity string, start, end time.Time, opts ...Option) ([]TopKItem, error)
GetRange returns the ranked top-K items over the absolute time range [start, end] for the given entity. Pipeline must be windowed. The server merges per-bucket Misra-Gries summaries before returning, so the ranking reflects merged-summary order — not a simple union of per-bucket rankings.
func (*TopKClient) GetWindow ¶
func (c *TopKClient) GetWindow(ctx context.Context, entity string, duration time.Duration, opts ...Option) ([]TopKItem, error)
GetWindow returns the ranked top-K items over the most-recent `duration`.
func (*TopKClient) GetWindowMany ¶
func (c *TopKClient) GetWindowMany(ctx context.Context, entities []string, duration time.Duration, opts ...Option) ([][]TopKItem, error)
GetWindowMany is the batched analog of GetWindow — fetches windowed ranked-item lists for N entities in one round-trip. Returns parallel arrays: out[i] is the ranked items for entities[i]; missing entities yield a nil slice.
type TopKItem ¶
type TopKItem struct {
Key string
// Count is a Misra-Gries LOWER BOUND, not a count. It understates the true
// count by up to n/(K+1), where n is the total weight the sketch ingested —
// and n is not visible from this item list. A sketch that retained 0.1% of
// its stream returns a handful of counts in the single digits and looks
// exactly like an exact answer over a handful of events.
//
// The sketch does not record n, so the bound cannot be derived from what
// this client returns — carry n out of band (an event counter on the same
// pipeline is the usual answer) if the difference matters to you.
Count uint64
}
TopKItem is one (key, count) pair from a Misra-Gries summary.