Documentation
¶
Overview ¶
Package menu provides domain models and repository interfaces for menu management.
Index ¶
- Constants
- Variables
- func ValidLinkType(lt string) bool
- func ValidLocation(loc string) bool
- type CreateMenuInput
- type CreateMenuItemInput
- type Menu
- type MenuItem
- type PostgresRepository
- func (r *PostgresRepository) CreateMenu(ctx context.Context, input *CreateMenuInput) (*Menu, error)
- func (r *PostgresRepository) CreateMenuItem(ctx context.Context, menuID uuid.UUID, input *CreateMenuItemInput) (*MenuItem, error)
- func (r *PostgresRepository) DeleteMenu(ctx context.Context, id uuid.UUID) error
- func (r *PostgresRepository) DeleteMenuItem(ctx context.Context, id uuid.UUID) error
- func (r *PostgresRepository) GetMenuByID(ctx context.Context, id uuid.UUID) (*Menu, error)
- func (r *PostgresRepository) GetMenuByLocation(ctx context.Context, location string) (*Menu, error)
- func (r *PostgresRepository) GetMenuBySlug(ctx context.Context, slug string) (*Menu, error)
- func (r *PostgresRepository) GetMenuItemByID(ctx context.Context, id uuid.UUID) (*MenuItem, error)
- func (r *PostgresRepository) GetMenuWithItems(ctx context.Context, menuID uuid.UUID) (*Menu, error)
- func (r *PostgresRepository) ListMenus(ctx context.Context) ([]*Menu, error)
- func (r *PostgresRepository) ReorderItems(ctx context.Context, menuID uuid.UUID, items []ReorderInput) error
- func (r *PostgresRepository) ReplaceMenu(ctx context.Context, id uuid.UUID, fields *UpdateMenuInput, ...) error
- func (r *PostgresRepository) UpdateMenu(ctx context.Context, id uuid.UUID, input *UpdateMenuInput) (*Menu, error)
- func (r *PostgresRepository) UpdateMenuItem(ctx context.Context, id uuid.UUID, input *UpdateMenuItemInput) (*MenuItem, error)
- type ReorderInput
- type ReplaceItem
- type Repository
- type Service
- func (s *Service) CreateMenu(ctx context.Context, input *CreateMenuInput) (*Menu, error)
- func (s *Service) CreateMenuItem(ctx context.Context, menuID uuid.UUID, input *CreateMenuItemInput) (*MenuItem, error)
- func (s *Service) DeleteMenu(ctx context.Context, id uuid.UUID) error
- func (s *Service) DeleteMenuItem(ctx context.Context, id uuid.UUID) error
- func (s *Service) GetMenu(ctx context.Context, id uuid.UUID) (*Menu, error)
- func (s *Service) GetMenuByLocation(ctx context.Context, location string) (*Menu, error)
- func (s *Service) GetMenuBySlug(ctx context.Context, slug string) (*Menu, error)
- func (s *Service) GetMenuItem(ctx context.Context, id uuid.UUID) (*MenuItem, error)
- func (s *Service) GetMenuWithItems(ctx context.Context, menuID uuid.UUID) (*Menu, error)
- func (s *Service) ListMenus(ctx context.Context) ([]*Menu, error)
- func (s *Service) ReorderItems(ctx context.Context, menuID uuid.UUID, items []ReorderInput) error
- func (s *Service) ReplaceMenu(ctx context.Context, id uuid.UUID, fields *UpdateMenuInput, ...) (*Menu, error)
- func (s *Service) SetChangeObserver(f func(ctx context.Context))
- func (s *Service) UpdateMenu(ctx context.Context, id uuid.UUID, input *UpdateMenuInput) (*Menu, error)
- func (s *Service) UpdateMenuItem(ctx context.Context, id uuid.UUID, input *UpdateMenuItemInput) (*MenuItem, error)
- type UpdateMenuInput
- type UpdateMenuItemInput
Constants ¶
const ( LinkTypeEntity = "entity" LinkTypeExternal = "external" LinkTypeArchive = "archive" LinkTypeCustom = "custom" )
Link types for menu items.
const ( LocationHeader = "header" LocationSidebar = "sidebar" )
Menu locations.
Variables ¶
var ( ErrMenuNotFound = errors.New("menu not found") ErrMenuItemNotFound = errors.New("menu item not found") ErrSlugAlreadyExists = errors.New("menu slug already exists") ErrInvalidLinkType = errors.New("invalid link type") ErrInvalidLocation = errors.New("invalid menu location") ErrEntityMissing = errors.New("menu item links to an entity that does not exist") ErrCircularParent = errors.New("circular parent reference") )
Common errors.
Functions ¶
func ValidLinkType ¶
ValidLinkType checks if a link type is valid.
func ValidLocation ¶
ValidLocation checks if a menu location is valid.
Types ¶
type CreateMenuInput ¶
type CreateMenuInput struct {
Name string `json:"name"`
Slug string `json:"slug,omitempty"`
Location *string `json:"location,omitempty"`
}
CreateMenuInput represents input for creating a new menu.
type CreateMenuItemInput ¶
type CreateMenuItemInput struct {
ParentID *uuid.UUID `json:"parent_id,omitempty"`
Label string `json:"label"`
LinkType string `json:"link_type"`
EntityID *uuid.UUID `json:"entity_id,omitempty"`
URL *string `json:"url,omitempty"`
SchemaSlug *string `json:"schema_slug,omitempty"`
Position *int `json:"position,omitempty"`
OpenInNewTab bool `json:"open_in_new_tab"`
CSSClasses *string `json:"css_classes,omitempty"`
}
CreateMenuItemInput represents input for creating a menu item.
type Menu ¶
type Menu struct {
ID uuid.UUID `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
Location *string `json:"location,omitempty"`
Items []*MenuItem `json:"items,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Menu represents a navigation menu.
type MenuItem ¶
type MenuItem struct {
ID uuid.UUID `json:"id"`
MenuID uuid.UUID `json:"menu_id"`
ParentID *uuid.UUID `json:"parent_id,omitempty"`
Label string `json:"label"`
LinkType string `json:"link_type"` // entity, external, archive, custom
EntityID *uuid.UUID `json:"entity_id,omitempty"`
URL *string `json:"url,omitempty"`
SchemaSlug *string `json:"schema_slug,omitempty"`
Position int `json:"position"`
OpenInNewTab bool `json:"open_in_new_tab"`
CSSClasses *string `json:"css_classes,omitempty"`
Children []*MenuItem `json:"children,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
// Computed from entity (not stored in DB)
EntitySlug *string `json:"entity_slug,omitempty"`
EntityName *string `json:"entity_name,omitempty"`
// EntitySchemaSlug is the linked entity's schema (render-side URL
// building); hidden from JSON so the API shape is unchanged.
EntitySchemaSlug *string `json:"-"`
}
MenuItem represents a single item in a menu with optional nesting.
type PostgresRepository ¶
type PostgresRepository struct {
// contains filtered or unexported fields
}
PostgresRepository implements Repository using PostgreSQL.
func NewPostgresRepository ¶
func NewPostgresRepository(db *database.DB) *PostgresRepository
NewPostgresRepository creates a new PostgreSQL menu repository.
func (*PostgresRepository) CreateMenu ¶
func (r *PostgresRepository) CreateMenu(ctx context.Context, input *CreateMenuInput) (*Menu, error)
CreateMenu inserts a new menu.
func (*PostgresRepository) CreateMenuItem ¶
func (r *PostgresRepository) CreateMenuItem(ctx context.Context, menuID uuid.UUID, input *CreateMenuItemInput) (*MenuItem, error)
CreateMenuItem inserts a new menu item.
func (*PostgresRepository) DeleteMenu ¶
DeleteMenu removes a menu and all its items.
func (*PostgresRepository) DeleteMenuItem ¶
DeleteMenuItem removes a menu item and reassigns children to parent.
func (*PostgresRepository) GetMenuByID ¶
GetMenuByID retrieves a menu by ID.
func (*PostgresRepository) GetMenuByLocation ¶
GetMenuByLocation retrieves a menu by location.
func (*PostgresRepository) GetMenuBySlug ¶
GetMenuBySlug retrieves a menu by slug.
func (*PostgresRepository) GetMenuItemByID ¶
GetMenuItemByID retrieves a menu item by ID.
func (*PostgresRepository) GetMenuWithItems ¶
GetMenuWithItems retrieves a menu with all items in nested structure.
func (*PostgresRepository) ListMenus ¶
func (r *PostgresRepository) ListMenus(ctx context.Context) ([]*Menu, error)
ListMenus retrieves all menus for the tenant.
func (*PostgresRepository) ReorderItems ¶
func (r *PostgresRepository) ReorderItems(ctx context.Context, menuID uuid.UUID, items []ReorderInput) error
ReorderItems updates positions and parent relationships for multiple items.
func (*PostgresRepository) ReplaceMenu ¶
func (r *PostgresRepository) ReplaceMenu(ctx context.Context, id uuid.UUID, fields *UpdateMenuInput, items []ReplaceItem) error
ReplaceMenu implements Repository. The menu row is locked for the whole call, so concurrent replacements run one after the other.
func (*PostgresRepository) UpdateMenu ¶
func (r *PostgresRepository) UpdateMenu(ctx context.Context, id uuid.UUID, input *UpdateMenuInput) (*Menu, error)
UpdateMenu modifies a menu.
func (*PostgresRepository) UpdateMenuItem ¶
func (r *PostgresRepository) UpdateMenuItem(ctx context.Context, id uuid.UUID, input *UpdateMenuItemInput) (*MenuItem, error)
UpdateMenuItem modifies a menu item.
type ReorderInput ¶
type ReorderInput struct {
ID uuid.UUID `json:"id"`
ParentID *uuid.UUID `json:"parent_id,omitempty"`
Position int `json:"position"`
}
ReorderInput represents a single item in a reorder request.
type ReplaceItem ¶
type ReplaceItem struct {
Label string
LinkType string
EntityID *uuid.UUID
URL *string
SchemaSlug *string
OpenInNewTab bool
Parent int
}
ReplaceItem is one item of a ReplaceMenu call. Parent is the index of an earlier item in the same list, or -1 for the top level.
type Repository ¶
type Repository interface {
// Menu operations
CreateMenu(ctx context.Context, input *CreateMenuInput) (*Menu, error)
GetMenuByID(ctx context.Context, id uuid.UUID) (*Menu, error)
GetMenuBySlug(ctx context.Context, slug string) (*Menu, error)
GetMenuByLocation(ctx context.Context, location string) (*Menu, error)
ListMenus(ctx context.Context) ([]*Menu, error)
UpdateMenu(ctx context.Context, id uuid.UUID, input *UpdateMenuInput) (*Menu, error)
DeleteMenu(ctx context.Context, id uuid.UUID) error
// Menu item operations
CreateMenuItem(ctx context.Context, menuID uuid.UUID, input *CreateMenuItemInput) (*MenuItem, error)
GetMenuItemByID(ctx context.Context, id uuid.UUID) (*MenuItem, error)
UpdateMenuItem(ctx context.Context, id uuid.UUID, input *UpdateMenuItemInput) (*MenuItem, error)
DeleteMenuItem(ctx context.Context, id uuid.UUID) error
// Nested operations
GetMenuWithItems(ctx context.Context, menuID uuid.UUID) (*Menu, error)
ReorderItems(ctx context.Context, menuID uuid.UUID, items []ReorderInput) error
// ReplaceMenu applies the menu fields (when set) and replaces every item
// in one transaction: either all of it happens or none of it.
ReplaceMenu(ctx context.Context, id uuid.UUID, fields *UpdateMenuInput, items []ReplaceItem) error
}
Repository defines the interface for menu data operations.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service provides business logic for menu management.
func NewService ¶
func NewService(repo Repository, logger *slog.Logger) *Service
NewService creates a new menu service.
func (*Service) CreateMenu ¶
CreateMenu creates a new menu.
func (*Service) CreateMenuItem ¶
func (s *Service) CreateMenuItem(ctx context.Context, menuID uuid.UUID, input *CreateMenuItemInput) (*MenuItem, error)
CreateMenuItem adds an item to a menu.
func (*Service) DeleteMenu ¶
DeleteMenu removes a menu.
func (*Service) DeleteMenuItem ¶
DeleteMenuItem removes a menu item.
func (*Service) GetMenuByLocation ¶
GetMenuByLocation retrieves a menu by location.
func (*Service) GetMenuBySlug ¶
GetMenuBySlug retrieves a menu by slug.
func (*Service) GetMenuItem ¶
GetMenuItem retrieves a menu item by ID.
func (*Service) GetMenuWithItems ¶
GetMenuWithItems retrieves a menu with all nested items.
func (*Service) ReorderItems ¶
ReorderItems updates positions and parent relationships for multiple items.
func (*Service) ReplaceMenu ¶
func (s *Service) ReplaceMenu(ctx context.Context, id uuid.UUID, fields *UpdateMenuInput, items []ReplaceItem) (*Menu, error)
ReplaceMenu updates a menu's name/location and replaces its items in one transaction. A nil items list leaves the items alone.
func (*Service) SetChangeObserver ¶
SetChangeObserver installs the callback run after a menu or menu item was written; nil disables it.
func (*Service) UpdateMenu ¶
func (s *Service) UpdateMenu(ctx context.Context, id uuid.UUID, input *UpdateMenuInput) (*Menu, error)
UpdateMenu modifies a menu.
func (*Service) UpdateMenuItem ¶
func (s *Service) UpdateMenuItem(ctx context.Context, id uuid.UUID, input *UpdateMenuItemInput) (*MenuItem, error)
UpdateMenuItem modifies a menu item.
type UpdateMenuInput ¶
type UpdateMenuInput struct {
Name *string `json:"name,omitempty"`
Location *string `json:"location,omitempty"`
}
UpdateMenuInput represents input for updating a menu.
type UpdateMenuItemInput ¶
type UpdateMenuItemInput struct {
ParentID *uuid.UUID `json:"parent_id,omitempty"`
Label *string `json:"label,omitempty"`
LinkType *string `json:"link_type,omitempty"`
EntityID *uuid.UUID `json:"entity_id,omitempty"`
URL *string `json:"url,omitempty"`
SchemaSlug *string `json:"schema_slug,omitempty"`
Position *int `json:"position,omitempty"`
OpenInNewTab *bool `json:"open_in_new_tab,omitempty"`
CSSClasses *string `json:"css_classes,omitempty"`
}
UpdateMenuItemInput represents input for updating a menu item.