datastores

package
v0.0.0-...-2c31021 Latest Latest
Warning

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

Go to latest
Published: Jun 8, 2026 License: GPL-3.0 Imports: 16 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// HotLastPostAggregation feeds getLatestForumPostDates (the
	// last-forum-post column on lite rosters and full profiles). With
	// the user_id_post_date composite it plans a loose index scan.
	HotLastPostAggregation = "SELECT user_id, MAX(post_date) as date FROM xf_post GROUP BY user_id"
	// AwolLastPostAggregation feeds FindAwol. The extra MAX(post_id)
	// disqualifies the loose scan; the same composite instead serves a
	// covering index scan.
	AwolLastPostAggregation = "SELECT user_id, MAX(post_date) as date, MAX(post_id) as post_id FROM xf_post GROUP BY user_id"
)

HotLastPostAggregation and AwolLastPostAggregation are the derived-table bodies of the two xf_post GROUP BY hotspots (PRD #112). They are exported so the EXPLAIN-plan tests in testdb/indexes_test.go pin the exact strings production executes — editing a query here re-points the corresponding test automatically instead of leaving it green against a stale copy. The SQL is frozen per PRD #112: index, don't refactor.

Variables

View Source
var (
	Info  = log.New(os.Stdout, "INFO: ", log.LstdFlags)
	Warn  = log.New(os.Stdout, "WARNING: ", log.LstdFlags)
	Error = log.New(os.Stdout, "ERROR: ", log.LstdFlags)
)
View Source
var ErrInvalidCursor = errors.New("invalid cursor")

ErrInvalidCursor signals a malformed cursor string. Handlers should map errors wrapping this sentinel to codes.InvalidArgument → HTTP 400.

Functions

func ParseBearerToken

func ParseBearerToken(raw string, maxLen int) string

ParseBearerToken extracts the raw API token from an Authorization header value. Returns "" if no Bearer scheme is present, the token is empty, or the result exceeds maxLen. Scheme name is matched case-insensitively per RFC 7235.

Types

type ApiKeyResult

type ApiKeyResult struct {
	KeyId  uint
	UserId uint
	Scopes map[string]struct{}
}

func (*ApiKeyResult) HasScope

func (r *ApiKeyResult) HasScope(name string) bool

HasScope reports whether the API key has been granted the named scope.

type Datastore

type Datastore interface {
	// FindProfilesById and FindProfilesByUsername return a NON-EMPTY slice of
	// non-nil profiles on a nil error — no-match is gorm.ErrRecordNotFound,
	// never an empty slice. Handlers index [0] under this invariant (with a
	// defensive 500 guard for implementations that break it).
	FindProfilesById(userId ...uint64) ([]*proto.Profile, error)
	FindProfilesByUsername(username string) ([]*proto.Profile, error)
	FindRosterByType(rosterType proto.RosterType) (*proto.Roster, error)
	FindLiteRosterByType(rosterType proto.RosterType) (*proto.LiteRoster, error)
	FindProfileByKeycloakID(keycloakId string) (*proto.Profile, error)
	FindProfileByDiscordID(discordId string) (*proto.Profile, error)
	FindProfilesByPosition(positionQuery string) (*proto.LiteRoster, error)
	FindS1UniformsRosterByType(rosterType proto.RosterType) (*proto.S1UniformsRoster, error)
	FindAllRanks() ([]*proto.RankExpanded, error)
	FindAllPositionGroups() ([]*proto.PositionGroup, error)
	FindAwol() ([]*proto.Awol, error)
	FindProfileByGamertag(gamertag string) (*proto.Profile, error)
	ValidateApiKey(rawKey string) (*ApiKeyResult, error)

	// Tickets
	ListTickets(ctx context.Context, rc TicketReferenceCache, filter *ListTicketsFilter) (tickets []*proto.Ticket, nextCursor string, hasMore bool, err error)
	GetTicket(ctx context.Context, rc TicketReferenceCache, ticketID uint32, forumBaseURL string) (*proto.Ticket, error)
	GetTicketByRef(ctx context.Context, rc TicketReferenceCache, ref string, forumBaseURL string) (*proto.Ticket, error)
	GetTicketFirstMessages(ctx context.Context, ticketID uint32, n int, includeHidden bool) (msgs []*proto.Message, totalCount uint32, err error)
	ListTicketMessages(ctx context.Context, ticketID uint32, afterCursor string, perPage uint32, includeHidden bool) (msgs []*proto.Message, nextCursor string, hasMore bool, err error)
	ListCategories(ctx context.Context, rc TicketReferenceCache) ([]*proto.Category, error)
}

type ListTicketsFilter

type ListTicketsFilter struct {
	CategoryIDs          []uint32
	ExcludeSubcategories bool
	TicketStates         []string
	StatusIDs            []uint32
	PrefixIDs            []uint32
	AssignedUserIDs      []uint32
	StarterUserIDs       []uint32
	ModifiedSince        uint32
	IncludeHidden        bool

	PerPage     uint32
	AfterCursor string
}

ListTicketsFilter carries the conjunctive filter knobs supported by ListTickets. Empty slices and zero-valued scalars mean "no filter."

type Mysql

type Mysql struct {
	Db *gorm.DB
}

func (Mysql) FindAllPositionGroups

func (ds Mysql) FindAllPositionGroups() ([]*proto.PositionGroup, error)

func (Mysql) FindAllRanks

func (ds Mysql) FindAllRanks() ([]*proto.RankExpanded, error)

func (Mysql) FindAwol

func (ds Mysql) FindAwol() ([]*proto.Awol, error)

func (Mysql) FindLiteRosterByType

func (ds Mysql) FindLiteRosterByType(rosterType proto.RosterType) (*proto.LiteRoster, error)

func (Mysql) FindProfileByDiscordID

func (ds Mysql) FindProfileByDiscordID(discordId string) (*proto.Profile, error)

func (Mysql) FindProfileByGamertag

func (ds Mysql) FindProfileByGamertag(gamertag string) (*proto.Profile, error)

func (Mysql) FindProfileByKeycloakID

func (ds Mysql) FindProfileByKeycloakID(keycloakId string) (*proto.Profile, error)

func (Mysql) FindProfilesById

func (ds Mysql) FindProfilesById(userIds ...uint64) ([]*proto.Profile, error)

func (Mysql) FindProfilesByPosition

func (ds Mysql) FindProfilesByPosition(positionQuery string) (*proto.LiteRoster, error)

func (Mysql) FindProfilesByUsername

func (ds Mysql) FindProfilesByUsername(username string) ([]*proto.Profile, error)

func (Mysql) FindRosterByType

func (ds Mysql) FindRosterByType(rosterType proto.RosterType) (*proto.Roster, error)

func (Mysql) FindS1UniformsRosterByType

func (ds Mysql) FindS1UniformsRosterByType(rosterType proto.RosterType) (*proto.S1UniformsRoster, error)

func (*Mysql) GetTicket

func (ds *Mysql) GetTicket(ctx context.Context, rc TicketReferenceCache, ticketID uint32, forumBase string) (*proto.Ticket, error)

func (*Mysql) GetTicketByRef

func (ds *Mysql) GetTicketByRef(ctx context.Context, rc TicketReferenceCache, ref string, forumBase string) (*proto.Ticket, error)

func (*Mysql) GetTicketFirstMessages

func (ds *Mysql) GetTicketFirstMessages(ctx context.Context, ticketID uint32, n int, includeHidden bool) ([]*proto.Message, uint32, error)

func (*Mysql) ListCategories

func (ds *Mysql) ListCategories(ctx context.Context, rc TicketReferenceCache) ([]*proto.Category, error)

func (*Mysql) ListTicketMessages

func (ds *Mysql) ListTicketMessages(ctx context.Context, ticketID uint32, afterCursor string, perPage uint32, includeHidden bool) ([]*proto.Message, string, bool, error)

func (*Mysql) ListTickets

func (ds *Mysql) ListTickets(ctx context.Context, rc TicketReferenceCache, f *ListTicketsFilter) ([]*proto.Ticket, string, bool, error)

func (*Mysql) LoadCategories

func (ds *Mysql) LoadCategories(ctx context.Context) ([]*referencecache.CategoryRecord, error)

func (*Mysql) LoadPrefixNames

func (ds *Mysql) LoadPrefixNames(ctx context.Context) (map[uint32]string, error)

func (*Mysql) LoadPriorityNames

func (ds *Mysql) LoadPriorityNames(ctx context.Context) (map[uint32]string, error)

func (*Mysql) LoadStatusNames

func (ds *Mysql) LoadStatusNames(ctx context.Context) (map[uint32]string, error)

func (Mysql) ValidateApiKey

func (ds Mysql) ValidateApiKey(rawKey string) (*ApiKeyResult, error)

type TicketReferenceCache

type TicketReferenceCache interface {
	StatusName(id uint32) string
	PriorityName(id uint32) string
	PrefixName(id uint32) string
	Category(id uint32) *referencecache.CategoryRecord
	CategoryAncestors(id uint32) []uint32
	CategoryTree() []*referencecache.CategoryRecord
	ExpandSubtree(ids []uint32) []uint32
}

TicketReferenceCache is the slice of referencecache.ReferenceCache that tickets datastore methods need. Defined here (not pulled in via dependency) so the Datastore interface stays self-describing and easy to mock in tests.

Jump to

Keyboard shortcuts

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