inventory

package
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: May 30, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package inventory is a generic owned-item ledger: "subject owns N of item type X" with atomic transfers, idempotent mutations, and reservation holds.

The semantics are domain-agnostic:

  • Player inventories and currency (games).
  • Portfolio positions, lot-tracked holdings (trading).
  • Shop stock and cart contents (e-commerce).
  • Warehouse asset registers (logistics).

Every mutation is identified by an idempotency key so retries are safe. Holds reserve quantity for a TTL; they can be committed (turn into a consume) or released (return to free balance). This package ships an in-memory Ledger; Postgres- and event-sourced backends are pluggable behind the Ledger interface.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrInsufficient    = errors.New("inventory: insufficient quantity")
	ErrInvalidQuantity = errors.New("inventory: quantity must be > 0")
	ErrHoldUnknown     = errors.New("inventory: hold not found")
	ErrHoldExpired     = errors.New("inventory: hold expired")
)

Errors surfaced by Ledger implementations.

Functions

This section is empty.

Types

type Balance

type Balance struct {
	Subject  SubjectID
	Item     ItemTypeID
	Quantity int64
	OnHold   int64
}

Balance is the projected free + held quantity for a (subject, item) pair.

type HoldID

type HoldID string

HoldID identifies a reservation against a balance.

type Idempotency

type Idempotency string

Idempotency is a client-supplied key that makes a mutation safe to retry. Two calls with the same key must have the effect of one.

type ItemTypeID

type ItemTypeID string

ItemTypeID identifies the kind of thing being held (sku, currency, item-id, asset symbol).

type Ledger

type Ledger interface {
	// Acquire credits qty of item to subject. Idempotent on key.
	Acquire(ctx context.Context, key Idempotency, subj SubjectID, item ItemTypeID, qty int64) error

	// Consume debits qty. Returns ErrInsufficient if free quantity is
	// less than qty. Idempotent on key.
	Consume(ctx context.Context, key Idempotency, subj SubjectID, item ItemTypeID, qty int64) error

	// Transfer moves qty from one subject to another atomically.
	// Idempotent on key.
	Transfer(ctx context.Context, key Idempotency, from, to SubjectID, item ItemTypeID, qty int64) error

	// Hold reserves qty for ttl. Held quantity is debited from free
	// (Quantity) and added to OnHold until Commit or Release.
	Hold(ctx context.Context, key Idempotency, subj SubjectID, item ItemTypeID, qty int64, ttl time.Duration) (HoldID, error)

	// Commit turns a hold into a consume.
	Commit(ctx context.Context, hold HoldID) error

	// Release returns held quantity to free balance.
	Release(ctx context.Context, hold HoldID) error

	// Balance returns the current balance for a (subject, item) pair.
	Balance(ctx context.Context, subj SubjectID, item ItemTypeID) (Balance, error)

	// List returns all non-zero balances for a subject.
	List(ctx context.Context, subj SubjectID) ([]Balance, error)
}

Ledger is the public interface for an inventory ledger. Implementations must be safe for concurrent use.

type MemoryConfig

type MemoryConfig struct {
	// Clock supplies the current time; defaults to time.Now if nil.
	Clock func() time.Time
}

MemoryConfig configures a MemoryLedger.

type MemoryLedger

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

MemoryLedger is an in-process Ledger. Goroutine-safe; mutations are serialised behind a single mutex which is plenty for tests and single-binary use cases.

func NewMemoryLedger

func NewMemoryLedger(cfg MemoryConfig) *MemoryLedger

NewMemoryLedger constructs a MemoryLedger.

func (*MemoryLedger) Acquire

func (l *MemoryLedger) Acquire(_ context.Context, key Idempotency, subj SubjectID, item ItemTypeID, qty int64) error

Acquire implements Ledger.

func (*MemoryLedger) Balance

func (l *MemoryLedger) Balance(_ context.Context, subj SubjectID, item ItemTypeID) (Balance, error)

Balance implements Ledger.

func (*MemoryLedger) Commit

func (l *MemoryLedger) Commit(_ context.Context, hold HoldID) error

Commit implements Ledger.

func (*MemoryLedger) Consume

func (l *MemoryLedger) Consume(_ context.Context, key Idempotency, subj SubjectID, item ItemTypeID, qty int64) error

Consume implements Ledger.

func (*MemoryLedger) Hold

func (l *MemoryLedger) Hold(_ context.Context, key Idempotency, subj SubjectID, item ItemTypeID, qty int64, ttl time.Duration) (HoldID, error)

Hold implements Ledger.

func (*MemoryLedger) List

func (l *MemoryLedger) List(_ context.Context, subj SubjectID) ([]Balance, error)

List implements Ledger.

func (*MemoryLedger) Release

func (l *MemoryLedger) Release(_ context.Context, hold HoldID) error

Release implements Ledger.

func (*MemoryLedger) Transfer

func (l *MemoryLedger) Transfer(_ context.Context, key Idempotency, from, to SubjectID, item ItemTypeID, qty int64) error

Transfer implements Ledger.

type SubjectID

type SubjectID string

SubjectID identifies the owner of a balance (player, account, wallet, warehouse, etc.).

Jump to

Keyboard shortcuts

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