wrapper

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 12, 2026 License: Apache-2.0 Imports: 6 Imported by: 0

README

Example: typed wrapper around Murmur's QueryService

A count-core-shaped reference implementation of the typed-wrapper pattern. Murmur's QueryService returns generic Value{bytes}; application services wrap it with their own typed Connect-RPC API so the bytes-decoding boilerplate doesn't leak into every caller.

The pattern

Caller                      Application's typed proto              Generic Murmur proto
                            (your repo)                            (this repo)

ranker / ui  ──────────►   BotInteractionCountService.Get()  ──►  QueryService.Get()
                            returns int64                          returns Value{bytes}
                                  │                                       │
                                  │   Server is a thin wrapper:           │
                                  │   1. typed request → entity-key      │
                                  │   2. call Murmur via                 │
                                  │      pkg/query/typed.SumClient        │
                                  │   3. return typed response            │

The application owns its proto. Murmur stays monoid-agnostic. Per-pipeline typed-server codegen is on Murmur's Phase 2 roadmap; until then, this thin-wrapper pattern is the right shape for production.

Files

  • wrapper.goServer struct that holds two *typed.SumClients (one all-time, one windowed) and exposes a typed BotInteractionService interface. Real count-core code substitutes its actual proto types; the structure is identical.
  • wrapper_test.go — exercises the wrapper end-to-end against an httptest-backed Murmur QueryService.

Why this beats the bytes-everywhere alternative

  • Type safety at the call site. Callers see int64, not Value{Present, Data []byte}. No accidental binary.LittleEndian.Uint64 typos.
  • Separation of concerns. The application's API is whatever shape it wants — count-core's BotInteractionCountService doesn't have to match Murmur's QueryService. Schema evolution is per-application.
  • Easy to test. Tests against the typed shape don't have to construct wire bytes.
  • Decoder lives in pkg/query/typed, not at every call site. When Murmur's wire format ever changes (Phase 2 codegen), the typed package absorbs the change; the wrapper code is unchanged.

When to use

Anyone running a Murmur counter pipeline behind their own typed RPC API. The two production patterns:

  1. One Murmur pipeline → one typed RPC. Simple case. Wrap once, expose the typed API.
  2. N Murmur pipelines → one typed RPC service. count-core's case. The wrapper holds N typed clients (one per Murmur pipeline) and exposes a single application-service surface that fans out internally to the right pipeline per request.

What this is NOT

  • Auto-codegen. No tool here generates the typed proto from a pipeline definition. That's Phase 2 in doc/architecture.md. This example is the building block the codegen would emit; until codegen lands, you write the wrapper yourself (typically ~50 lines per service).
  • A different Murmur API. Murmur's QueryService is unchanged. The typed wrapper is purely a client-side / application-side concern.

See pkg/query/typed for the underlying decoder + typed-client shipping.

Documentation

Overview

Package wrapper is a count-core-shaped example showing how to expose Murmur counter pipelines through your application's OWN typed Connect-RPC service rather than the generic Value{bytes} shape.

Pattern (the count-core integration plan from the review thread):

  • Murmur pipelines do the aggregation. Their query layer is a generic `QueryService.Get/GetMany/GetWindow → Value{bytes}`.
  • Your application defines its OWN proto with typed responses (e.g. count-core's `BotInteractionCountService.GetBotInteractionCount(...)` returning `int64`).
  • The application's server implementation is a thin wrapper: it takes the typed request, calls the underlying Murmur QueryService via `pkg/query/typed`, and returns a typed response. No bytes-decoding boilerplate; no leakage of Murmur's wire shape into the application's API.

This file shows that wrapper for a fictional "BotInteractionCount" service. Real count-core code would substitute its own proto definition; the structure is the same.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type BotInteractionRequest

type BotInteractionRequest struct {
	BotID  string
	UserID string
}

BotInteractionRequest is what the application's protobuf would define — here in Go for example purposes. Real code would use the generated proto types.

type BotInteractionResponse

type BotInteractionResponse struct {
	Count   int64
	Present bool
}

BotInteractionResponse is the typed response shape — no Value{bytes}, no decoder boilerplate at the call site.

type BotInteractionService

type BotInteractionService interface {
	GetBotInteractionCount(ctx context.Context, req *BotInteractionRequest) (*BotInteractionResponse, error)
	GetBotInteractionCountWindow(ctx context.Context, req *BotInteractionWindowRequest) (*BotInteractionResponse, error)
}

BotInteractionService is the application's typed Connect-RPC server shape (here as a Go interface for illustration). Real code would use a generated `connect.UnaryHandlerFunc` or the connect-go server stub.

type BotInteractionWindowRequest

type BotInteractionWindowRequest struct {
	BotID    string
	UserID   string
	Duration time.Duration
}

BotInteractionWindowRequest carries the windowed-query inputs.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server is the count-core-shaped wrapper. It holds two typed Murmur clients — one for the all-time counter, one for the windowed counter — and exposes the application's typed RPC surface on top of them.

In production, count-core's BotInteractionService server would embed this struct (or one with more fields for per-counter pipelines) and serve it via `connect.NewBotInteractionServiceHandler`.

func NewServer

func NewServer(likes, windowed murmurv1connect.QueryServiceClient) *Server

NewServer constructs the wrapper given the two underlying Murmur QueryService clients. In production you'd wire each client to its own gRPC endpoint (one Murmur worker per pipeline).

func (*Server) GetBotInteractionCount

func (s *Server) GetBotInteractionCount(ctx context.Context, req *BotInteractionRequest) (*BotInteractionResponse, error)

GetBotInteractionCount returns the all-time interaction count for a (bot, user) pair. The server-side wire shape is just this typed shape; Murmur's bytes layer is hidden from the caller.

func (*Server) GetBotInteractionCountWindow

func (s *Server) GetBotInteractionCountWindow(ctx context.Context, req *BotInteractionWindowRequest) (*BotInteractionResponse, error)

GetBotInteractionCountWindow returns the count over the last `duration` for a (bot, user) pair. Wraps the underlying Murmur GetWindow call with the typed shape.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL