serviceregistry

package
v0.0.0-...-8c930d8 Latest Latest
Warning

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

Go to latest
Published: Nov 11, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package serviceregistry owns the framework-internal service registry used by controllers and modules.

Application code should use github.com/hydroan/gst/service instead. Keeping lookup and registry state in an internal package prevents external projects from mutating framework-owned service mappings.

The package-level API is intentionally small:

  • Register registers a service by its type, the registration the public service.Register forwards to.
  • RegisterInstance stores a concrete service instance for module/runtime registration.
  • Resolve returns the service a controller should execute.
  • Init fills loggers for services registered before logger setup.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Init

func Init() error

Init injects logger.Service into the services registered before the logger was initialized, once per process; a service registered later gets it as it registers. Bootstrap runs it once the loggers exist.

func Key

func Key(phase apiaction.Phase, route string) string

Key returns the registry key of the route and phase: the path the route is served at (see apiaction.APIPath) and the phase, so registration and resolution agree however either side spells the route, with or without the prefix or stray whitespace. A blank route, which RegisterInstance refuses, keys no service, not even one registered on the root of the prefix: the key of a handler built without a route resolves none.

The key deliberately carries no type information: Go type aliases collapse distinct request/response declarations into one type, so a type-derived key cannot tell two actions apart. The route is unique per action by HTTP routing rules, which makes route plus phase a collision-free identity.

func OverridesHook

func OverridesHook(svc any, method string) bool

OverridesHook reports whether svc overrides the named hook beyond Base's no-op implementation. Only the methods Base declares are tracked; any other name, and a nil service, report true, so a caller gating work on the answer keeps that work rather than skipping it for a hook the detection does not know.

func Register

func Register[S types.Service[M, REQ, RSP], M types.Model, REQ types.Request, RSP types.Response](phase apiaction.Phase, route string)

Register registers the service type S for the route and phase, the registration service.Register forwards to: S is normally a pointer to a struct type embedding Base, and a fresh pointer instance of it is stored. A pointer to any concrete type that satisfies the constraint implements the service interface, so only an interface type argument fails, with a panic: it names no service to dispatch to, and registering nothing in its place would leave the route on the built-in handling without a word.

func RegisterInstance

func RegisterInstance[M types.Model, REQ types.Request, RSP types.Response](phase apiaction.Phase, route string, svc types.Service[M, REQ, RSP])

RegisterInstance registers a concrete service instance for the route and phase.

The route names the one the HTTP layer registers the matching handler under, spelled either way apiaction.APIPath accepts, because Key derives the registry key from the path the route is served at and the controller handlers resolve services through that key. An empty route panics.

Registering a second service under one route and phase panics: a silent overwrite would dispatch requests to the wrong service, which is exactly the failure mode the route-derived key exists to prevent.

RegisterInstance preserves any preconfigured fields on svc. If svc is a non-pointer value, the registry stores a pointer copy so controller lookups always work with pointer service instances.

func Resolve

func Resolve[M types.Model, REQ types.Request, RSP types.Response](key string) types.Service[M, REQ, RSP]

Resolve returns the registered service for a key produced by Key.

The lookup deliberately stays per request: services registered after route registration remain visible, only the key construction is hoisted to route-registration time. When no service is registered under the key, a no-op Base service is returned so default CRUD hooks can continue without forcing application code to register services.

A service found under the key but failing the type assertion means the route and service registrations disagree about the service types — a wiring bug. It is reported at error level and degrades to the no-op Base instead of panicking mid-request.

Types

type Base

type Base[M types.Model, REQ types.Request, RSP types.Response] struct{ types.Logger }

func (Base[M, REQ, RSP]) Create

func (Base[M, REQ, RSP]) Create(*types.ServiceContext, REQ) (RSP, error)

func (Base[M, REQ, RSP]) CreateAfter

func (Base[M, REQ, RSP]) CreateAfter(*types.ServiceContext, M) error

func (Base[M, REQ, RSP]) CreateBefore

func (Base[M, REQ, RSP]) CreateBefore(*types.ServiceContext, M) error

func (Base[M, REQ, RSP]) CreateMany

func (Base[M, REQ, RSP]) CreateMany(*types.ServiceContext, REQ) (RSP, error)

func (Base[M, REQ, RSP]) CreateManyAfter

func (Base[M, REQ, RSP]) CreateManyAfter(*types.ServiceContext, ...M) error

func (Base[M, REQ, RSP]) CreateManyBefore

func (Base[M, REQ, RSP]) CreateManyBefore(*types.ServiceContext, ...M) error

func (Base[M, REQ, RSP]) Delete

func (Base[M, REQ, RSP]) Delete(*types.ServiceContext, REQ) (RSP, error)

func (Base[M, REQ, RSP]) DeleteAfter

func (Base[M, REQ, RSP]) DeleteAfter(*types.ServiceContext, M) error

func (Base[M, REQ, RSP]) DeleteBefore

func (Base[M, REQ, RSP]) DeleteBefore(*types.ServiceContext, M) error

func (Base[M, REQ, RSP]) DeleteMany

func (Base[M, REQ, RSP]) DeleteMany(*types.ServiceContext, REQ) (RSP, error)

func (Base[M, REQ, RSP]) DeleteManyAfter

func (Base[M, REQ, RSP]) DeleteManyAfter(*types.ServiceContext, ...M) error

func (Base[M, REQ, RSP]) DeleteManyBefore

func (Base[M, REQ, RSP]) DeleteManyBefore(*types.ServiceContext, ...M) error

func (Base[M, REQ, RSP]) Export

func (Base[M, REQ, RSP]) Export(*types.ServiceContext, ...M) ([]byte, error)

Export mirrors Import: an empty-bytes default would export an empty file instead of surfacing the missing service.

func (Base[M, REQ, RSP]) Filter

func (Base[M, REQ, RSP]) Filter(_ *types.ServiceContext, m M, opts types.QueryOptions) (M, types.QueryOptions, error)

func (Base[M, REQ, RSP]) Get

func (Base[M, REQ, RSP]) Get(*types.ServiceContext, REQ) (RSP, error)

func (Base[M, REQ, RSP]) GetAfter

func (Base[M, REQ, RSP]) GetAfter(*types.ServiceContext, M) error

func (Base[M, REQ, RSP]) GetBefore

func (Base[M, REQ, RSP]) GetBefore(*types.ServiceContext, M) error

func (Base[M, REQ, RSP]) Import

func (Base[M, REQ, RSP]) Import(*types.ServiceContext, io.Reader) ([]M, error)

Import has no built-in parsing behavior: the DSL requires every Import action to declare Service(), so reaching this default means the route was wired without its service implementation. Answering loudly beats an empty-slice default, which would silently import nothing and mask the wiring error.

func (Base[M, REQ, RSP]) List

func (Base[M, REQ, RSP]) List(*types.ServiceContext, REQ) (RSP, error)

func (Base[M, REQ, RSP]) ListAfter

func (Base[M, REQ, RSP]) ListAfter(*types.ServiceContext, *[]M) error

func (Base[M, REQ, RSP]) ListBefore

func (Base[M, REQ, RSP]) ListBefore(*types.ServiceContext, *[]M) error

func (Base[M, REQ, RSP]) Patch

func (Base[M, REQ, RSP]) Patch(*types.ServiceContext, REQ) (RSP, error)

func (Base[M, REQ, RSP]) PatchAfter

func (Base[M, REQ, RSP]) PatchAfter(*types.ServiceContext, M) error

func (Base[M, REQ, RSP]) PatchBefore

func (Base[M, REQ, RSP]) PatchBefore(*types.ServiceContext, M) error

func (Base[M, REQ, RSP]) PatchMany

func (Base[M, REQ, RSP]) PatchMany(*types.ServiceContext, REQ) (RSP, error)

func (Base[M, REQ, RSP]) PatchManyAfter

func (Base[M, REQ, RSP]) PatchManyAfter(*types.ServiceContext, ...M) error

func (Base[M, REQ, RSP]) PatchManyBefore

func (Base[M, REQ, RSP]) PatchManyBefore(*types.ServiceContext, ...M) error

func (Base[M, REQ, RSP]) QueryCursor

func (Base[M, REQ, RSP]) QueryCursor(ctx *types.ServiceContext) (types.Cursor, error)

QueryCursor returns the cursor position of the request, ready to be passed to Database.WithCursor. Models that did not embed model.Cursor yield a zero cursor, which WithCursor treats as a no-op; a request without _cursor_value yields the feed's first page, ordered but unbounded, and one with _sort_by and no _cursor_value yields a zero cursor, a list the client sorts. An unknown cursor column, or a cursor value the column's Go type cannot represent, is a client error and is reported as such.

func (Base[M, REQ, RSP]) QueryFilters

func (Base[M, REQ, RSP]) QueryFilters(ctx *types.ServiceContext) ([]types.Filter, error)

QueryFilters returns the field-level operator filters ("field[op]=value") of the request, plus the bare framework timestamp keys ("created_at", "updated_at"), which act as exact-match filters. The field must resolve to a filterable column of the model and the operator must be known; anything else is rejected so a mistyped filter can never silently widen the result set. Filters require the model to embed model.Query.

func (Base[M, REQ, RSP]) QueryModel

func (Base[M, REQ, RSP]) QueryModel(ctx *types.ServiceContext) (M, error)

QueryModel returns a new model with its own query fields filled from the request, ready to be passed to Database.WithQuery.

The keys QueryFilters owns never reach the decoder, and neither do framework parameters the model cannot carry, nor, in an export, the export's own _format and _limit; every other key must map to a field of the model, so a mistyped filter name is reported instead of silently widening the result set. The model is returned even when decoding fails, so a caller that tolerates partial input can still use it.

func (Base[M, REQ, RSP]) QueryOrders

func (Base[M, REQ, RSP]) QueryOrders(ctx *types.ServiceContext) ([]types.Order, error)

QueryOrders returns the ORDER BY terms of the request, ready to be passed to Database.WithOrder. Models embedding model.Query take them from _sort_by; any other model yields no order. An unknown column or direction is a client error and is reported as such.

func (Base[M, REQ, RSP]) QueryPagination

func (Base[M, REQ, RSP]) QueryPagination(ctx *types.ServiceContext) (page, size int)

QueryPagination returns the page and size arguments of the request, ready to be passed to Database.WithPagination. Models embedding model.Pagination take both from the request and models embedding model.Cursor take the size only; any other model keeps the framework's full-table safety limit. The returned page is always at least 1, so a service slicing in-memory pages or computing offsets itself can use it without normalizing again.

func (Base[M, REQ, RSP]) QueryPresentFields

func (Base[M, REQ, RSP]) QueryPresentFields(ctx *types.ServiceContext) map[string]struct{}

QueryPresentFields returns the model filter keys the request provided explicitly, so the database layer keeps their zero values (false, 0) as real conditions instead of dropping them as unset.

func (Base[M, REQ, RSP]) SSE

func (Base[M, REQ, RSP]) SSE(*types.ServiceContext) error

SSE has no default streaming behavior: the DSL requires every SSE action to declare Service(), so reaching this default means the route was wired without its service implementation, which is answered loudly instead of with a silently empty stream.

func (Base[M, REQ, RSP]) Update

func (Base[M, REQ, RSP]) Update(*types.ServiceContext, REQ) (RSP, error)

func (Base[M, REQ, RSP]) UpdateAfter

func (Base[M, REQ, RSP]) UpdateAfter(*types.ServiceContext, M) error

func (Base[M, REQ, RSP]) UpdateBefore

func (Base[M, REQ, RSP]) UpdateBefore(*types.ServiceContext, M) error

func (Base[M, REQ, RSP]) UpdateMany

func (Base[M, REQ, RSP]) UpdateMany(*types.ServiceContext, REQ) (RSP, error)

func (Base[M, REQ, RSP]) UpdateManyAfter

func (Base[M, REQ, RSP]) UpdateManyAfter(*types.ServiceContext, ...M) error

func (Base[M, REQ, RSP]) UpdateManyBefore

func (Base[M, REQ, RSP]) UpdateManyBefore(*types.ServiceContext, ...M) error

Jump to

Keyboard shortcuts

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