Documentation
¶
Overview ¶
Package tags provides Connect RPC adapters for the TagsService.
Package tags provides a reusable tagging and metadata service for any entity. The service supports both pure tags (labels) and metadata (name-value pairs) with denormalized counts for fast reads.
Architecture ¶
The package follows a layered architecture:
- TagsService interface: defines the contract for tag operations
- BaseTagsService: provides shared logic (normalization, caching, common operations)
- TagsStorageProvider: abstracts raw storage operations
- Backend implementations (gorm, gae): concrete storage providers
Usage ¶
Applications should use one of the concrete backend implementations:
// GORM backend (for PostgreSQL/MySQL/SQLite) tagsService := gorm.NewTagsService(db) // GAE Datastore backend (for Google Cloud) tagsService := gae.NewTagsService(client, "namespace")
Key Features ¶
- Pure tags: Simple labels like "favorites", "rock"
- Metadata: Name-value pairs like venue="Wembley", rating="5"
- Multi-user tagging: Same tag can be applied by multiple users
- Visibility control: Private, shared, and public tag applications
- Tag deduplication via normalization
- Denormalized usage counts
Index ¶
- Constants
- Variables
- func DefaultNormalizer(s string) string
- func GetMountedEntityID(ctx context.Context) string
- func GetUserIDFromContext(ctx context.Context, key any) string
- func WithMountedEntityID(ctx context.Context, entityID string) context.Context
- func WithUserID(ctx context.Context, key any, userID string) context.Context
- type AfterEntityTagDeleteHook
- type AfterEntityTagSaveHook
- type AfterTagDeleteHook
- type AfterTagSaveHook
- type AfterTagsReadHook
- type AuthorizeHook
- type BaseTagsService
- func (s *BaseTagsService) BatchGetEntityTags(ctx context.Context, req *v1.BatchGetEntityTagsRequest) (*v1.BatchGetEntityTagsResponse, error)
- func (s *BaseTagsService) BatchTagEntities(ctx context.Context, req *v1.BatchTagEntitiesRequest) (*v1.BatchTagEntitiesResponse, error)
- func (s *BaseTagsService) ConnectHandler(ctx context.Context, opts ...common.HandlerOption) (string, http.Handler)
- func (s *BaseTagsService) ConnectHandlerWithOptions(ctx context.Context, connectOpts []connect.HandlerOption, ...) (string, http.Handler)
- func (s *BaseTagsService) CreateTag(ctx context.Context, req *v1.CreateTagRequest) (*v1.CreateTagResponse, error)
- func (s *BaseTagsService) DeleteTag(ctx context.Context, req *v1.DeleteTagRequest) (*v1.DeleteTagResponse, error)
- func (s *BaseTagsService) GetEntitiesWithTag(ctx context.Context, req *v1.GetEntitiesWithTagRequest) (*v1.GetEntitiesWithTagResponse, error)
- func (s *BaseTagsService) GetEntityTags(ctx context.Context, req *v1.GetEntityTagsRequest) (*v1.GetEntityTagsResponse, error)
- func (s *BaseTagsService) GetPopularTags(ctx context.Context, req *v1.GetPopularTagsRequest) (*v1.GetPopularTagsResponse, error)
- func (s *BaseTagsService) GetTag(ctx context.Context, req *v1.GetTagRequest) (*v1.GetTagResponse, error)
- func (s *BaseTagsService) InitializeCache()
- func (s *BaseTagsService) ListTags(ctx context.Context, req *v1.ListTagsRequest) (*v1.ListTagsResponse, error)
- func (s *BaseTagsService) MergeTags(ctx context.Context, req *v1.MergeTagsRequest) (*v1.MergeTagsResponse, error)
- func (s *BaseTagsService) PromoteTag(ctx context.Context, req *v1.PromoteTagRequest) (*v1.PromoteTagResponse, error)
- func (s *BaseTagsService) RESTHandler(ctx context.Context, opts ...common.HandlerOption) http.Handler
- func (s *BaseTagsService) RegisterRESTHandlers(ctx context.Context, mux *runtime.ServeMux) error
- func (s *BaseTagsService) SearchTags(ctx context.Context, req *v1.SearchTagsRequest) (*v1.SearchTagsResponse, error)
- func (s *BaseTagsService) TagEntity(ctx context.Context, req *v1.TagEntityRequest) (*v1.TagEntityResponse, error)
- func (s *BaseTagsService) UntagEntity(ctx context.Context, req *v1.UntagEntityRequest) (*v1.UntagEntityResponse, error)
- func (s *BaseTagsService) UpdateTag(ctx context.Context, req *v1.UpdateTagRequest) (*v1.UpdateTagResponse, error)
- type BeforeEntityTagDeleteHook
- type BeforeEntityTagSaveHook
- type BeforeTagDeleteHook
- type BeforeTagSaveHook
- type ConnectTagsServer
- func (s *ConnectTagsServer) BatchGetEntityTags(ctx context.Context, req *connect.Request[v1.BatchGetEntityTagsRequest]) (*connect.Response[v1.BatchGetEntityTagsResponse], error)
- func (s *ConnectTagsServer) BatchTagEntities(ctx context.Context, req *connect.Request[v1.BatchTagEntitiesRequest]) (*connect.Response[v1.BatchTagEntitiesResponse], error)
- func (s *ConnectTagsServer) CreateTag(ctx context.Context, req *connect.Request[v1.CreateTagRequest]) (*connect.Response[v1.CreateTagResponse], error)
- func (s *ConnectTagsServer) DeleteTag(ctx context.Context, req *connect.Request[v1.DeleteTagRequest]) (*connect.Response[v1.DeleteTagResponse], error)
- func (s *ConnectTagsServer) GetEntitiesWithTag(ctx context.Context, req *connect.Request[v1.GetEntitiesWithTagRequest]) (*connect.Response[v1.GetEntitiesWithTagResponse], error)
- func (s *ConnectTagsServer) GetEntityTags(ctx context.Context, req *connect.Request[v1.GetEntityTagsRequest]) (*connect.Response[v1.GetEntityTagsResponse], error)
- func (s *ConnectTagsServer) GetPopularTags(ctx context.Context, req *connect.Request[v1.GetPopularTagsRequest]) (*connect.Response[v1.GetPopularTagsResponse], error)
- func (s *ConnectTagsServer) GetTag(ctx context.Context, req *connect.Request[v1.GetTagRequest]) (*connect.Response[v1.GetTagResponse], error)
- func (s *ConnectTagsServer) ListTags(ctx context.Context, req *connect.Request[v1.ListTagsRequest]) (*connect.Response[v1.ListTagsResponse], error)
- func (s *ConnectTagsServer) MergeTags(ctx context.Context, req *connect.Request[v1.MergeTagsRequest]) (*connect.Response[v1.MergeTagsResponse], error)
- func (s *ConnectTagsServer) PromoteTag(ctx context.Context, req *connect.Request[v1.PromoteTagRequest]) (*connect.Response[v1.PromoteTagResponse], error)
- func (s *ConnectTagsServer) SearchTags(ctx context.Context, req *connect.Request[v1.SearchTagsRequest]) (*connect.Response[v1.SearchTagsResponse], error)
- func (s *ConnectTagsServer) TagEntity(ctx context.Context, req *connect.Request[v1.TagEntityRequest]) (*connect.Response[v1.TagEntityResponse], error)
- func (s *ConnectTagsServer) UntagEntity(ctx context.Context, req *connect.Request[v1.UntagEntityRequest]) (*connect.Response[v1.UntagEntityResponse], error)
- func (s *ConnectTagsServer) UpdateTag(ctx context.Context, req *connect.Request[v1.UpdateTagRequest]) (*connect.Response[v1.UpdateTagResponse], error)
- type EntityTagsOptions
- type Event
- type EventType
- type HookContext
- type Hooks
- type ListTagsOptions
- type OnEventHook
- type PopularTagsOptions
- type SearchTagsOptions
- type ServiceOption
- func WithAfterEntityTagDelete(hook AfterEntityTagDeleteHook) ServiceOption
- func WithAfterEntityTagSave(hook AfterEntityTagSaveHook) ServiceOption
- func WithAfterTagDelete(hook AfterTagDeleteHook) ServiceOption
- func WithAfterTagSave(hook AfterTagSaveHook) ServiceOption
- func WithAfterTagsRead(hook AfterTagsReadHook) ServiceOption
- func WithBeforeEntityTagDelete(hook BeforeEntityTagDeleteHook) ServiceOption
- func WithBeforeEntityTagSave(hook BeforeEntityTagSaveHook) ServiceOption
- func WithBeforeTagDelete(hook BeforeTagDeleteHook) ServiceOption
- func WithBeforeTagSave(hook BeforeTagSaveHook) ServiceOption
- func WithCache() ServiceOption
- func WithHooks(hooks Hooks) ServiceOption
- func WithNormalizer(normalizer func(string) string) ServiceOption
- func WithOnAuthorize(hook AuthorizeHook) ServiceOption
- func WithOnEvent(hook OnEventHook) ServiceOption
- func WithUserIDContextKey(key any) ServiceOption
- func WithValidateEntity(hook ValidateEntityHook) ServiceOption
- type TagsError
- type TagsService
- type TagsStorageProvider
- type ValidateEntityHook
Constants ¶
const DefaultUserIDContextKey = common.DefaultUserIDContextKey
DefaultUserIDContextKey is the default context key for the authenticated user ID. Can be overridden per service instance via WithUserIDContextKey. Uses the common default so all goapplib services share the same key.
Variables ¶
var ( ErrTagIDRequired = &TagsError{Message: "tag id is required"} ErrValueRequired = &TagsError{Message: "value is required"} ErrEntityRequired = &TagsError{Message: "entity_id is required"} ErrTaggedByRequired = &TagsError{Message: "tagged_by is required"} ErrTagNotFound = &TagsError{Message: "tag not found"} ErrTagMigrating = &TagsError{Message: "tag is currently being migrated, new applications not allowed"} ErrTargetTagExists = &TagsError{Message: "target tag already exists, set merge_if_exists=true to merge"} )
Error types
Functions ¶
func DefaultNormalizer ¶
DefaultNormalizer is the default normalization function. It lowercases and trims whitespace.
func GetMountedEntityID ¶
GetMountedEntityID retrieves the entity ID from mount context. This is set by the mount middleware when the service is mounted at a path like /songs/{songId}/tags.
func GetUserIDFromContext ¶
GetUserIDFromContext returns the user ID from context using the given key. Returns empty string if not set.
func WithMountedEntityID ¶
WithMountedEntityID stores the entity ID in context. This is typically called by mount middleware after extracting the path parameter.
Types ¶
type AfterEntityTagDeleteHook ¶
AfterEntityTagDeleteHook is called after successfully deleting an entity tag association. Errors from this hook are logged but don't affect the response.
type AfterEntityTagSaveHook ¶
AfterEntityTagSaveHook is called after successfully saving an entity tag association. Errors from this hook are logged but don't affect the response.
type AfterTagDeleteHook ¶
AfterTagDeleteHook is called after successfully deleting a tag. Errors from this hook are logged but don't affect the response.
type AfterTagSaveHook ¶
AfterTagSaveHook is called after successfully saving a tag. Errors from this hook are logged but don't affect the response.
type AfterTagsReadHook ¶
AfterTagsReadHook is called after reading tags (for transformation/enrichment). Can modify the tags slice in place.
type AuthorizeHook ¶
type AuthorizeHook func(ctx context.Context, hookCtx *HookContext) error
AuthorizeHook is called before any operation to check authorization. The hook can: - Return an error to deny the operation - Modify the request via hookCtx.Request (e.g., set OwnerId from auth context) - Read/validate request fields
type BaseTagsService ¶
type BaseTagsService struct {
v1.UnimplementedTagsServiceServer
StorageProvider TagsStorageProvider
// Optional in-memory cache for tag lookups
CacheEnabled bool
TagCache map[string]*v1.Tag // key: tag ID
CacheMu sync.RWMutex
// Normalizer function (defaults to lowercase + trim)
Normalizer func(string) string
// UserIDContextKey is the context key for reading user ID.
// Defaults to DefaultUserIDContextKey if not set.
UserIDContextKey any
// Hooks for customization
Hooks Hooks
}
BaseTagsService provides shared logic for tags services. Embeds UnimplementedTagsServiceServer for gRPC forward compatibility.
func NewBaseTagsService ¶
func NewBaseTagsService(provider TagsStorageProvider, opts ...ServiceOption) *BaseTagsService
NewBaseTagsService creates a new BaseTagsService with the given storage provider.
func (*BaseTagsService) BatchGetEntityTags ¶
func (s *BaseTagsService) BatchGetEntityTags(ctx context.Context, req *v1.BatchGetEntityTagsRequest) (*v1.BatchGetEntityTagsResponse, error)
BatchGetEntityTags returns tags for multiple entities at once.
func (*BaseTagsService) BatchTagEntities ¶
func (s *BaseTagsService) BatchTagEntities(ctx context.Context, req *v1.BatchTagEntitiesRequest) (*v1.BatchTagEntitiesResponse, error)
BatchTagEntities applies a tag to multiple entities at once.
func (*BaseTagsService) ConnectHandler ¶
func (s *BaseTagsService) ConnectHandler(ctx context.Context, opts ...common.HandlerOption) (string, http.Handler)
ConnectHandler returns an http.Handler for Connect RPC. Must be mounted at a path that prefixes the Connect procedure paths.
Example: Mount at /songs/{songId}/rpc/ to handle:
- POST /songs/123/rpc/content.tags.v1.TagsService/TagEntity
Usage:
path, handler := tagsService.ConnectHandler(ctx,
common.WithEntityParam("songId"),
)
router.Handle("/songs/{songId}/rpc/", handler)
func (*BaseTagsService) ConnectHandlerWithOptions ¶
func (s *BaseTagsService) ConnectHandlerWithOptions(ctx context.Context, connectOpts []connect.HandlerOption, mountOpts ...common.HandlerOption) (string, http.Handler)
ConnectHandlerWithOptions returns an http.Handler for Connect RPC with additional connect options.
func (*BaseTagsService) CreateTag ¶
func (s *BaseTagsService) CreateTag(ctx context.Context, req *v1.CreateTagRequest) (*v1.CreateTagResponse, error)
CreateTag creates a new tag or returns existing if duplicate.
func (*BaseTagsService) DeleteTag ¶
func (s *BaseTagsService) DeleteTag(ctx context.Context, req *v1.DeleteTagRequest) (*v1.DeleteTagResponse, error)
DeleteTag removes a tag and optionally untags all entities.
func (*BaseTagsService) GetEntitiesWithTag ¶
func (s *BaseTagsService) GetEntitiesWithTag(ctx context.Context, req *v1.GetEntitiesWithTagRequest) (*v1.GetEntitiesWithTagResponse, error)
GetEntitiesWithTag returns all entities that have a specific tag.
func (*BaseTagsService) GetEntityTags ¶
func (s *BaseTagsService) GetEntityTags(ctx context.Context, req *v1.GetEntityTagsRequest) (*v1.GetEntityTagsResponse, error)
GetEntityTags returns all tags for a specific entity.
func (*BaseTagsService) GetPopularTags ¶
func (s *BaseTagsService) GetPopularTags(ctx context.Context, req *v1.GetPopularTagsRequest) (*v1.GetPopularTagsResponse, error)
GetPopularTags returns the most used tags.
func (*BaseTagsService) GetTag ¶
func (s *BaseTagsService) GetTag(ctx context.Context, req *v1.GetTagRequest) (*v1.GetTagResponse, error)
GetTag retrieves a tag by ID.
func (*BaseTagsService) InitializeCache ¶
func (s *BaseTagsService) InitializeCache()
InitializeCache sets up the in-memory cache.
func (*BaseTagsService) ListTags ¶
func (s *BaseTagsService) ListTags(ctx context.Context, req *v1.ListTagsRequest) (*v1.ListTagsResponse, error)
ListTags lists tags for an owner with filtering.
func (*BaseTagsService) MergeTags ¶
func (s *BaseTagsService) MergeTags(ctx context.Context, req *v1.MergeTagsRequest) (*v1.MergeTagsResponse, error)
MergeTags merges two tags into one (admin operation).
func (*BaseTagsService) PromoteTag ¶
func (s *BaseTagsService) PromoteTag(ctx context.Context, req *v1.PromoteTagRequest) (*v1.PromoteTagResponse, error)
PromoteTag promotes a private tag to public scope.
func (*BaseTagsService) RESTHandler ¶
func (s *BaseTagsService) RESTHandler(ctx context.Context, opts ...common.HandlerOption) http.Handler
RESTHandler returns an http.Handler for REST endpoints with a default mux. For more control over the mux configuration, use RegisterRESTHandlers instead.
Usage:
router.Handle("/songs/{songId}/tags/", tagsService.RESTHandler(ctx,
common.WithEntityParam("songId"),
))
func (*BaseTagsService) RegisterRESTHandlers ¶
RegisterRESTHandlers registers the tags service REST handlers with the given gRPC-gateway mux. The caller provides the mux so they can configure it with their own middleware, marshalers, etc.
Example: Mount at /songs/{songId}/tags/ to handle:
- POST /songs/123/tags/entity -> TagEntity with entity_id=123
- GET /songs/123/tags/entity/123 -> GetEntityTags for entity_id=123
Usage:
mux := runtime.NewServeMux(/* your options */)
tagsService.RegisterRESTHandlers(ctx, mux)
router.Handle("/songs/{songId}/tags/", common.WrapWithEntityExtraction("songId", mux))
func (*BaseTagsService) SearchTags ¶
func (s *BaseTagsService) SearchTags(ctx context.Context, req *v1.SearchTagsRequest) (*v1.SearchTagsResponse, error)
SearchTags searches for tags by query (prefix match on value).
func (*BaseTagsService) TagEntity ¶
func (s *BaseTagsService) TagEntity(ctx context.Context, req *v1.TagEntityRequest) (*v1.TagEntityResponse, error)
TagEntity applies a tag to an entity.
func (*BaseTagsService) UntagEntity ¶
func (s *BaseTagsService) UntagEntity(ctx context.Context, req *v1.UntagEntityRequest) (*v1.UntagEntityResponse, error)
UntagEntity removes a tag from an entity.
func (*BaseTagsService) UpdateTag ¶
func (s *BaseTagsService) UpdateTag(ctx context.Context, req *v1.UpdateTagRequest) (*v1.UpdateTagResponse, error)
UpdateTag updates a tag's properties.
type BeforeEntityTagDeleteHook ¶
BeforeEntityTagDeleteHook is called before deleting an entity tag association. Return an error to abort the delete.
type BeforeEntityTagSaveHook ¶
BeforeEntityTagSaveHook is called before saving an entity tag association. Return an error to abort the save.
type BeforeTagDeleteHook ¶
BeforeTagDeleteHook is called before deleting a tag. Return an error to abort the delete.
type BeforeTagSaveHook ¶
BeforeTagSaveHook is called before saving a tag. The hook can modify the tag before it's saved. Return an error to abort the save.
type ConnectTagsServer ¶
type ConnectTagsServer struct {
Service TagsService
}
ConnectTagsServer wraps TagsService for Connect RPC. Use with tagsv1connect.NewTagsServiceHandler().
func NewConnectTagsServer ¶
func NewConnectTagsServer(svc TagsService) *ConnectTagsServer
NewConnectTagsServer creates a new Connect RPC server wrapping the given TagsService.
func (*ConnectTagsServer) BatchGetEntityTags ¶
func (s *ConnectTagsServer) BatchGetEntityTags(ctx context.Context, req *connect.Request[v1.BatchGetEntityTagsRequest]) (*connect.Response[v1.BatchGetEntityTagsResponse], error)
BatchGetEntityTags returns tags for multiple entities at once.
func (*ConnectTagsServer) BatchTagEntities ¶
func (s *ConnectTagsServer) BatchTagEntities(ctx context.Context, req *connect.Request[v1.BatchTagEntitiesRequest]) (*connect.Response[v1.BatchTagEntitiesResponse], error)
BatchTagEntities applies a tag to multiple entities at once.
func (*ConnectTagsServer) CreateTag ¶
func (s *ConnectTagsServer) CreateTag(ctx context.Context, req *connect.Request[v1.CreateTagRequest]) (*connect.Response[v1.CreateTagResponse], error)
CreateTag creates a new tag definition.
func (*ConnectTagsServer) DeleteTag ¶
func (s *ConnectTagsServer) DeleteTag(ctx context.Context, req *connect.Request[v1.DeleteTagRequest]) (*connect.Response[v1.DeleteTagResponse], error)
DeleteTag removes a tag and optionally untags all entities.
func (*ConnectTagsServer) GetEntitiesWithTag ¶
func (s *ConnectTagsServer) GetEntitiesWithTag(ctx context.Context, req *connect.Request[v1.GetEntitiesWithTagRequest]) (*connect.Response[v1.GetEntitiesWithTagResponse], error)
GetEntitiesWithTag returns all entities that have a specific tag.
func (*ConnectTagsServer) GetEntityTags ¶
func (s *ConnectTagsServer) GetEntityTags(ctx context.Context, req *connect.Request[v1.GetEntityTagsRequest]) (*connect.Response[v1.GetEntityTagsResponse], error)
GetEntityTags returns all tags for a specific entity.
func (*ConnectTagsServer) GetPopularTags ¶
func (s *ConnectTagsServer) GetPopularTags(ctx context.Context, req *connect.Request[v1.GetPopularTagsRequest]) (*connect.Response[v1.GetPopularTagsResponse], error)
GetPopularTags returns the most used tags.
func (*ConnectTagsServer) GetTag ¶
func (s *ConnectTagsServer) GetTag(ctx context.Context, req *connect.Request[v1.GetTagRequest]) (*connect.Response[v1.GetTagResponse], error)
GetTag retrieves a tag by ID.
func (*ConnectTagsServer) ListTags ¶
func (s *ConnectTagsServer) ListTags(ctx context.Context, req *connect.Request[v1.ListTagsRequest]) (*connect.Response[v1.ListTagsResponse], error)
ListTags lists tags for an owner with filtering.
func (*ConnectTagsServer) MergeTags ¶
func (s *ConnectTagsServer) MergeTags(ctx context.Context, req *connect.Request[v1.MergeTagsRequest]) (*connect.Response[v1.MergeTagsResponse], error)
MergeTags merges two tags into one (admin operation).
func (*ConnectTagsServer) PromoteTag ¶
func (s *ConnectTagsServer) PromoteTag(ctx context.Context, req *connect.Request[v1.PromoteTagRequest]) (*connect.Response[v1.PromoteTagResponse], error)
PromoteTag promotes a private tag to public.
func (*ConnectTagsServer) SearchTags ¶
func (s *ConnectTagsServer) SearchTags(ctx context.Context, req *connect.Request[v1.SearchTagsRequest]) (*connect.Response[v1.SearchTagsResponse], error)
SearchTags searches for tags by name (autocomplete).
func (*ConnectTagsServer) TagEntity ¶
func (s *ConnectTagsServer) TagEntity(ctx context.Context, req *connect.Request[v1.TagEntityRequest]) (*connect.Response[v1.TagEntityResponse], error)
TagEntity applies a tag to an entity.
func (*ConnectTagsServer) UntagEntity ¶
func (s *ConnectTagsServer) UntagEntity(ctx context.Context, req *connect.Request[v1.UntagEntityRequest]) (*connect.Response[v1.UntagEntityResponse], error)
UntagEntity removes a tag from an entity.
func (*ConnectTagsServer) UpdateTag ¶
func (s *ConnectTagsServer) UpdateTag(ctx context.Context, req *connect.Request[v1.UpdateTagRequest]) (*connect.Response[v1.UpdateTagResponse], error)
UpdateTag updates a tag's properties.
type EntityTagsOptions ¶
EntityTagsOptions contains options for listing entity tags.
type Event ¶
type Event struct {
Type EventType
TagID string
EntityID string
UserID string
Tag *v1.Tag
// For merge operations
SourceTagID string
TargetTagID string
// Count of affected entities
EntitiesAffected int64
}
Event represents a tags service event for notifications.
type EventType ¶
type EventType string
EventType represents the type of event that occurred.
const ( EventTagCreated EventType = "tag.created" EventTagUpdated EventType = "tag.updated" EventTagDeleted EventType = "tag.deleted" EventEntityTagged EventType = "entity.tagged" EventEntityUntagged EventType = "entity.untagged" EventTagsMerged EventType = "tags.merged" EventTagPromoted EventType = "tag.promoted" )
type HookContext ¶
type HookContext struct {
// Operation being performed (e.g., "CreateTag", "TagEntity")
Operation string
// UserID of the user performing the operation (may be empty, hook can set it)
UserID string
// EntityID being operated on (for entity tagging operations)
EntityID string
// TagID being operated on
TagID string
// Request is the original request object (type assert to access specific fields).
// The hook can modify request fields (e.g., set OwnerId from auth context).
Request any
}
HookContext provides context information for hook invocations.
type Hooks ¶
type Hooks struct {
// Authorization hook - called before operations
OnAuthorize AuthorizeHook
// Entity validation hook - validates entity exists
ValidateEntity ValidateEntityHook
// Tag lifecycle hooks
BeforeTagSave BeforeTagSaveHook
AfterTagSave AfterTagSaveHook
BeforeTagDelete BeforeTagDeleteHook
AfterTagDelete AfterTagDeleteHook
// EntityTag lifecycle hooks
BeforeEntityTagSave BeforeEntityTagSaveHook
AfterEntityTagSave AfterEntityTagSaveHook
BeforeEntityTagDelete BeforeEntityTagDeleteHook
AfterEntityTagDelete AfterEntityTagDeleteHook
// Read hooks
AfterTagsRead AfterTagsReadHook
// Event hooks
OnEvent OnEventHook
}
Hooks contains all hook functions for the tags service.
type ListTagsOptions ¶
type ListTagsOptions struct {
OwnerID string
Scope v1.TagScope
NameFilter string // "" = all, empty string = pure tags, "venue" = specific name
OrderBy string // "name", "usage_count", "created_at", "display_order"
Limit int
Offset int
}
ListTagsOptions contains options for listing tags.
type OnEventHook ¶
OnEventHook is called when notable events occur (for notifications, analytics, etc.). Errors from this hook are logged but don't affect the response.
type PopularTagsOptions ¶
PopularTagsOptions contains options for getting popular tags.
type SearchTagsOptions ¶
SearchTagsOptions contains options for searching tags.
type ServiceOption ¶
type ServiceOption func(*BaseTagsService)
ServiceOption is a functional option for configuring the tags service.
func WithAfterEntityTagDelete ¶
func WithAfterEntityTagDelete(hook AfterEntityTagDeleteHook) ServiceOption
WithAfterEntityTagDelete sets the after entity tag delete hook.
func WithAfterEntityTagSave ¶
func WithAfterEntityTagSave(hook AfterEntityTagSaveHook) ServiceOption
WithAfterEntityTagSave sets the after entity tag save hook.
func WithAfterTagDelete ¶
func WithAfterTagDelete(hook AfterTagDeleteHook) ServiceOption
WithAfterTagDelete sets the after tag delete hook.
func WithAfterTagSave ¶
func WithAfterTagSave(hook AfterTagSaveHook) ServiceOption
WithAfterTagSave sets the after tag save hook.
func WithAfterTagsRead ¶
func WithAfterTagsRead(hook AfterTagsReadHook) ServiceOption
WithAfterTagsRead sets the after tags read hook.
func WithBeforeEntityTagDelete ¶
func WithBeforeEntityTagDelete(hook BeforeEntityTagDeleteHook) ServiceOption
WithBeforeEntityTagDelete sets the before entity tag delete hook.
func WithBeforeEntityTagSave ¶
func WithBeforeEntityTagSave(hook BeforeEntityTagSaveHook) ServiceOption
WithBeforeEntityTagSave sets the before entity tag save hook.
func WithBeforeTagDelete ¶
func WithBeforeTagDelete(hook BeforeTagDeleteHook) ServiceOption
WithBeforeTagDelete sets the before tag delete hook.
func WithBeforeTagSave ¶
func WithBeforeTagSave(hook BeforeTagSaveHook) ServiceOption
WithBeforeTagSave sets the before tag save hook.
func WithNormalizer ¶
func WithNormalizer(normalizer func(string) string) ServiceOption
WithNormalizer sets a custom normalizer function.
func WithOnAuthorize ¶
func WithOnAuthorize(hook AuthorizeHook) ServiceOption
WithOnAuthorize sets the authorization hook.
func WithOnEvent ¶
func WithOnEvent(hook OnEventHook) ServiceOption
WithOnEvent sets the event notification hook.
func WithUserIDContextKey ¶
func WithUserIDContextKey(key any) ServiceOption
WithUserIDContextKey sets the context key used to read user ID from context. This allows different apps to use their own context key conventions.
func WithValidateEntity ¶
func WithValidateEntity(hook ValidateEntityHook) ServiceOption
WithValidateEntity sets the entity validation hook.
type TagsError ¶
type TagsError struct {
Message string
}
TagsError represents an error in the tags service.
type TagsService ¶
type TagsService interface {
// Tag CRUD
CreateTag(ctx context.Context, req *v1.CreateTagRequest) (*v1.CreateTagResponse, error)
GetTag(ctx context.Context, req *v1.GetTagRequest) (*v1.GetTagResponse, error)
UpdateTag(ctx context.Context, req *v1.UpdateTagRequest) (*v1.UpdateTagResponse, error)
DeleteTag(ctx context.Context, req *v1.DeleteTagRequest) (*v1.DeleteTagResponse, error)
ListTags(ctx context.Context, req *v1.ListTagsRequest) (*v1.ListTagsResponse, error)
// Entity tagging
TagEntity(ctx context.Context, req *v1.TagEntityRequest) (*v1.TagEntityResponse, error)
UntagEntity(ctx context.Context, req *v1.UntagEntityRequest) (*v1.UntagEntityResponse, error)
GetEntityTags(ctx context.Context, req *v1.GetEntityTagsRequest) (*v1.GetEntityTagsResponse, error)
GetEntitiesWithTag(ctx context.Context, req *v1.GetEntitiesWithTagRequest) (*v1.GetEntitiesWithTagResponse, error)
// Batch operations
BatchTagEntities(ctx context.Context, req *v1.BatchTagEntitiesRequest) (*v1.BatchTagEntitiesResponse, error)
BatchGetEntityTags(ctx context.Context, req *v1.BatchGetEntityTagsRequest) (*v1.BatchGetEntityTagsResponse, error)
// Discovery
SearchTags(ctx context.Context, req *v1.SearchTagsRequest) (*v1.SearchTagsResponse, error)
GetPopularTags(ctx context.Context, req *v1.GetPopularTagsRequest) (*v1.GetPopularTagsResponse, error)
// Admin operations
MergeTags(ctx context.Context, req *v1.MergeTagsRequest) (*v1.MergeTagsResponse, error)
PromoteTag(ctx context.Context, req *v1.PromoteTagRequest) (*v1.PromoteTagResponse, error)
}
TagsService defines the interface for tag operations.
type TagsStorageProvider ¶
type TagsStorageProvider interface {
// Tag operations
SaveTag(ctx context.Context, tag *v1.Tag) error
GetTag(ctx context.Context, id string) (*v1.Tag, error)
DeleteTag(ctx context.Context, id string) error
ListTags(ctx context.Context, opts ListTagsOptions) ([]*v1.Tag, int, error)
FindTagByNormalizedValues(ctx context.Context, ownerID, normalizedName, normalizedValue string) (*v1.Tag, error)
SearchTags(ctx context.Context, opts SearchTagsOptions) ([]*v1.Tag, error)
GetPopularTags(ctx context.Context, opts PopularTagsOptions) ([]*v1.Tag, error)
// EntityTag operations
SaveEntityTag(ctx context.Context, entityTag *v1.EntityTag) error
DeleteEntityTag(ctx context.Context, tagID, entityID, taggedBy string) error
GetEntityTag(ctx context.Context, tagID, entityID, taggedBy string) (*v1.EntityTag, error)
ListEntityTagsByEntity(ctx context.Context, entityID string, opts EntityTagsOptions) ([]*v1.EntityTag, error)
ListEntityTagsByTag(ctx context.Context, tagID string, limit, offset int) ([]*v1.EntityTag, int, error)
DeleteEntityTagsByTag(ctx context.Context, tagID string) (int64, error)
// TagUsageCounts operations (optional - for denormalized counts)
GetTagUsageCounts(ctx context.Context, entityID string) (*v1.TagUsageCounts, error)
SaveTagUsageCounts(ctx context.Context, counts *v1.TagUsageCounts) error
}
TagsStorageProvider is implemented by concrete backends (gorm, gae) to provide raw storage operations for tags.