Skip to content

Games

leadr.games

Modules:

leadr.games.adapters

Modules:

  • orm – Game ORM model.
leadr.games.adapters.orm

Game ORM model.

Classes:

leadr.games.adapters.orm.GameORM

Bases: Base

Game ORM model.

Represents a game that belongs to an account in the database. Maps to the games table with foreign key to accounts and unique constraint on (account_id, name) to prevent duplicate game names within the same account.

Attributes:

# leadr.games.adapters.orm.GameORM.account
account: Mapped[AccountORM] = relationship('AccountORM')
# leadr.games.adapters.orm.GameORM.account_id
account_id: Mapped[UUID] = mapped_column(ForeignKey('accounts.id', ondelete='CASCADE'), nullable=False, index=True)
# leadr.games.adapters.orm.GameORM.anti_cheat_enabled
anti_cheat_enabled: Mapped[bool] = mapped_column(nullable=False, default=True)
# leadr.games.adapters.orm.GameORM.created_at
created_at: Mapped[timestamp]
# leadr.games.adapters.orm.GameORM.default_board_id
default_board_id: Mapped[UUID | None] = mapped_column(nullable=True, default=None)
# leadr.games.adapters.orm.GameORM.deleted_at
deleted_at: Mapped[nullable_timestamp]
# leadr.games.adapters.orm.GameORM.description
description: Mapped[str | None] = mapped_column(String, nullable=True, default=None)
# leadr.games.adapters.orm.GameORM.id
id: Mapped[uuid_pk]
# leadr.games.adapters.orm.GameORM.name
name: Mapped[str] = mapped_column(String, nullable=False)
# leadr.games.adapters.orm.GameORM.page_url
page_url: Mapped[str | None] = mapped_column(String, nullable=True, default=None)
# leadr.games.adapters.orm.GameORM.slug
slug: Mapped[str] = mapped_column(String, nullable=False, unique=True, index=True)
# leadr.games.adapters.orm.GameORM.steam_app_id
steam_app_id: Mapped[str | None] = mapped_column(String, nullable=True, default=None)
# leadr.games.adapters.orm.GameORM.tags
tags: Mapped[list[str]] = mapped_column(ARRAY(String), nullable=False, default=list, server_default='{}')
# leadr.games.adapters.orm.GameORM.updated_at
updated_at: Mapped[timestamp] = mapped_column(onupdate=(func.now()))

leadr.games.api

Modules:

leadr.games.api.game_routes

Game API routes.

Functions:

Attributes:

leadr.games.api.game_routes.create_game
create_game(request, service, auth)

Create a new game.

Creates a new game associated with an existing account. Games can optionally be configured with Steam integration and a default leaderboard.

For regular users, account_id must match their API key's account. For superadmins, any account_id is accepted.

Parameters:

Returns:

  • GameResponse – GameResponse with the created game including auto-generated ID and timestamps.

Raises:

  • 403 – User does not have access to the specified account.
  • 404 – Account not found.
leadr.games.api.game_routes.get_game
get_game(game_id, service, auth)

Get a game by ID.

Parameters:

Returns:

Raises:

  • 403 – User does not have access to this game's account.
  • 404 – Game not found.
leadr.games.api.game_routes.list_games
list_games(auth, service, pagination, account_id=None, slug=None)

List all games for an account with pagination and optional filtering.

Returns paginated games for the specified account. Supports cursor-based pagination with bidirectional navigation and custom sorting.

For regular users, account_id is automatically derived from their API key. For superadmins, account_id is optional - if omitted, returns games from all accounts.

Filtering:

  • Use ?slug={slug} to find a specific game by its globally unique slug

Pagination:

  • Default: 20 items per page, sorted by created_at:desc,id:asc
  • Custom sort: Use ?sort=name:asc,created_at:desc
  • Valid sort fields: id, name, slug, created_at, updated_at
  • Navigation: Use next_cursor/prev_cursor from response
Example GET /v1/games?slug=my-game GET /v1/games?account_id=acc_123&limit=50&sort=name:asc

Parameters:

Returns:

Raises:

  • 400 – Invalid cursor, sort field, or cursor state mismatch.
  • 403 – User does not have access to the specified account.
  • 404 – Game not found when filtering by slug.
leadr.games.api.game_routes.router
router = APIRouter()
leadr.games.api.game_routes.update_game
update_game(game_id, request, service, auth)

Update a game.

Supports updating name, Steam App ID, default board ID, or soft-deleting the game.

Parameters:

Returns:

  • GameResponse – GameResponse with the updated game details.

Raises:

  • 403 – User does not have access to this game's account.
  • 404 – Game not found.
leadr.games.api.game_schemas

API request and response models for games.

Classes:

leadr.games.api.game_schemas.GameCreateRequest

Bases: BaseModel

Request model for creating a game.

Attributes:

# leadr.games.api.game_schemas.GameCreateRequest.account_id
account_id: AccountID = Field(description='ID of the account this game belongs to')
# leadr.games.api.game_schemas.GameCreateRequest.anti_cheat_enabled
anti_cheat_enabled: bool = Field(default=True, description='Whether anti-cheat is enabled for this game (defaults to True)')
# leadr.games.api.game_schemas.GameCreateRequest.default_board_id
default_board_id: BoardID | None = Field(default=None, description='Optional ID of the default leaderboard for this game')
# leadr.games.api.game_schemas.GameCreateRequest.description
description: str | None = Field(default=None, description='Optional game description')
# leadr.games.api.game_schemas.GameCreateRequest.name
name: str = Field(description='Name of the game')
# leadr.games.api.game_schemas.GameCreateRequest.page_url
page_url: str | None = Field(default=None, description="Optional URL to the game's page")
# leadr.games.api.game_schemas.GameCreateRequest.slug
slug: str | None = Field(default=None, description='Optional URL-friendly slug (globally unique). If not provided, will be auto-generated from name')
# leadr.games.api.game_schemas.GameCreateRequest.steam_app_id
steam_app_id: str | None = Field(default=None, description='Optional Steam App ID for Steam integration')
# leadr.games.api.game_schemas.GameCreateRequest.tags
tags: list[str] | None = Field(default=None, description='Optional list of tags for categorization')
leadr.games.api.game_schemas.GameResponse

Bases: BaseModel

Response model for a game.

Functions:

  • from_domain – Convert domain entity to response model.

Attributes:

# leadr.games.api.game_schemas.GameResponse.account_id
account_id: AccountID = Field(description='ID of the account this game belongs to')
# leadr.games.api.game_schemas.GameResponse.anti_cheat_enabled
anti_cheat_enabled: bool = Field(description='Whether anti-cheat is enabled for this game')
# leadr.games.api.game_schemas.GameResponse.created_at
created_at: datetime = Field(description='Timestamp when the game was created (UTC)')
# leadr.games.api.game_schemas.GameResponse.default_board_id
default_board_id: BoardID | None = Field(default=None, description='ID of the default leaderboard, or null if not set')
# leadr.games.api.game_schemas.GameResponse.description
description: str | None = Field(default=None, description='Game description')
# leadr.games.api.game_schemas.GameResponse.from_domain
from_domain(game)

Convert domain entity to response model.

Parameters:

  • game (Game) – The domain Game entity to convert.

Returns:

  • GameResponse – GameResponse with all fields populated from the domain entity.
# leadr.games.api.game_schemas.GameResponse.id
id: GameID = Field(description='Unique identifier for the game')
# leadr.games.api.game_schemas.GameResponse.name
name: str = Field(description='Name of the game')
# leadr.games.api.game_schemas.GameResponse.page_url
page_url: str | None = Field(default=None, description="URL to the game's page")
# leadr.games.api.game_schemas.GameResponse.slug
slug: str = Field(description='URL-friendly slug for the game (globally unique, immutable)')
# leadr.games.api.game_schemas.GameResponse.steam_app_id
steam_app_id: str | None = Field(default=None, description='Steam App ID if Steam integration is configured')
# leadr.games.api.game_schemas.GameResponse.tags
tags: list[str] = Field(default_factory=list, description='List of tags for categorization')
# leadr.games.api.game_schemas.GameResponse.updated_at
updated_at: datetime = Field(description='Timestamp of last update (UTC)')
leadr.games.api.game_schemas.GameUpdateRequest

Bases: BaseModel

Request model for updating a game.

Attributes:

# leadr.games.api.game_schemas.GameUpdateRequest.anti_cheat_enabled
anti_cheat_enabled: bool | None = Field(default=None, description='Whether anti-cheat is enabled for this game')
# leadr.games.api.game_schemas.GameUpdateRequest.default_board_id
default_board_id: BoardID | None = Field(default=None, description='Updated default leaderboard ID')
# leadr.games.api.game_schemas.GameUpdateRequest.deleted
deleted: bool | None = Field(default=None, description='Set to true to soft delete the game')
# leadr.games.api.game_schemas.GameUpdateRequest.description
description: str | None = Field(default=None, description='Updated game description')
# leadr.games.api.game_schemas.GameUpdateRequest.name
name: str | None = Field(default=None, description='Updated game name')
# leadr.games.api.game_schemas.GameUpdateRequest.page_url
page_url: str | None = Field(default=None, description='Updated page URL')
# leadr.games.api.game_schemas.GameUpdateRequest.steam_app_id
steam_app_id: str | None = Field(default=None, description='Updated Steam App ID')
# leadr.games.api.game_schemas.GameUpdateRequest.tags
tags: list[str] | None = Field(default=None, description='Updated tags list')

leadr.games.domain

Modules:

  • game – Game domain model.
leadr.games.domain.game

Game domain model.

Classes:

  • Game – Game domain entity.
leadr.games.domain.game.Game

Bases: Entity

Game domain entity.

Represents a game that belongs to an account. Games can have optional Steam integration via steam_app_id and can reference a default leaderboard.

Each game belongs to exactly one account and cannot be transferred. Games can be configured with Steam integration for syncing achievements or other Steam platform features.

Functions:

Attributes:

# leadr.games.domain.game.Game.account_id
account_id: AccountID = Field(frozen=True, description='ID of the account this game belongs to (immutable)')
# leadr.games.domain.game.Game.anti_cheat_enabled
anti_cheat_enabled: bool = Field(default=True, description='Whether anti-cheat is enabled for this game (defaults to enabled)')
# leadr.games.domain.game.Game.created_at
created_at: datetime = Field(default_factory=(lambda: datetime.now(UTC)), description='Timestamp when entity was created (UTC)')
# leadr.games.domain.game.Game.default_board_id
default_board_id: BoardID | None = Field(default=None, description='Optional default leaderboard ID for this game')
# leadr.games.domain.game.Game.deleted_at
deleted_at: datetime | None = Field(default=None, description='Timestamp when entity was soft-deleted (UTC), or null if active')
# leadr.games.domain.game.Game.description
description: str | None = Field(default=None, description='Short description of the game')
# leadr.games.domain.game.Game.id
id: GameID = Field(frozen=True, default_factory=GameID, description='Unique game identifier')
# leadr.games.domain.game.Game.is_deleted
is_deleted: bool

Check if entity is soft-deleted.

Returns:

  • bool – True if the entity has a deleted_at timestamp, False otherwise.
# leadr.games.domain.game.Game.model_config
model_config = ConfigDict(validate_assignment=True)
# leadr.games.domain.game.Game.name
name: str = Field(description='Name of the game')
# leadr.games.domain.game.Game.page_url
page_url: str | None = Field(default=None, description="URL to the game's page or website")
# leadr.games.domain.game.Game.restore
restore()

Restore a soft-deleted entity.

Clears the deleted_at timestamp, making the entity active again.

Example > > > account.soft_delete() > > > account.restore() > > > assert account.is_deleted is False
# leadr.games.domain.game.Game.slug
slug: str = Field(description='URL-friendly slug for the game (globally unique)')
# leadr.games.domain.game.Game.soft_delete
soft_delete()

Mark entity as soft-deleted.

Sets the deleted_at timestamp to the current UTC time. Entities that are already deleted are not affected (deleted_at remains at original deletion time).

Example > > > account = Account(name="Test", slug="test") > > > account.soft_delete() > > > assert account.is_deleted is True
# leadr.games.domain.game.Game.steam_app_id
steam_app_id: str | None = Field(default=None, description='Optional Steam App ID for platform integration')
# leadr.games.domain.game.Game.tags
tags: list[str] = Field(default_factory=list, description='List of tags for categorizing the game')
# leadr.games.domain.game.Game.updated_at
updated_at: datetime = Field(default_factory=(lambda: datetime.now(UTC)), description='Timestamp of last update (UTC)')
# leadr.games.domain.game.Game.validate_name
validate_name(value)

Validate game name is not empty.

Parameters:

  • value (str) – The game name to validate.

Returns:

  • str – The validated and trimmed game name.

Raises:

  • ValueError – If game name is empty or whitespace only.
# leadr.games.domain.game.Game.validate_slug
validate_slug(value)

Validate slug format (lowercase alphanumeric with hyphens).

Parameters:

  • value (str) – The slug to validate.

Returns:

  • str – The validated slug.

Raises:

leadr.games.services

Modules:

  • dependencies – Game service dependencies for FastAPI dependency injection.
  • game_service – Game service for managing game operations.
  • repositories – Game repository services.
leadr.games.services.dependencies

Game service dependencies for FastAPI dependency injection.

Functions:

Attributes:

leadr.games.services.dependencies.GameServiceDep
GameServiceDep = Annotated[GameService, Depends(get_game_service)]
leadr.games.services.dependencies.get_game_service
get_game_service(db)

Get GameService dependency.

leadr.games.services.game_service

Game service for managing game operations.

Classes:

  • GameService – Service for managing game lifecycle and operations.
leadr.games.services.game_service.GameService

Bases: BaseService[Game, GameRepository]

Service for managing game lifecycle and operations.

This service orchestrates game creation, updates, and retrieval by coordinating between the domain models and repository layer.

Functions:

Attributes:

# leadr.games.services.game_service.GameService.create_game
create_game(account_id, name, slug=None, steam_app_id=None, default_board_id=None, anti_cheat_enabled=True, description=None, tags=None, page_url=None)

Create a new game.

Parameters:

  • account_id (AccountID) – The ID of the account that owns this game.
  • name (str) – The game name.
  • slug (str | None) – Optional URL-friendly slug. If not provided, auto-generated from name.
  • steam_app_id (str | None) – Optional Steam application ID.
  • default_board_id (BoardID | None) – Optional default leaderboard ID.
  • anti_cheat_enabled (bool) – Whether anti-cheat is enabled (defaults to True).
  • description (str | None) – Optional short description of the game.
  • tags (list[str] | None) – Optional list of tags for categorizing the game.
  • page_url (str | None) – Optional URL to the game's page or website.

Returns:

  • Game – The created Game domain entity.

Raises:

  • ValueError – If slug is invalid or already exists globally.
Example > > > game = await service.create_game( > > > ... account_id=account.id, > > > ... name="Super Awesome Game", > > > ... steam_app_id="123456", > > > ... )
# leadr.games.services.game_service.GameService.delete
delete(entity_id)

Soft-delete an entity.

Parameters:

Raises:

# leadr.games.services.game_service.GameService.get_by_id
get_by_id(entity_id)

Get an entity by its ID.

Parameters:

Returns:

  • DomainEntityT | None – The domain entity if found, None otherwise
# leadr.games.services.game_service.GameService.get_by_id_or_raise
get_by_id_or_raise(entity_id)

Get an entity by its ID or raise EntityNotFoundError.

Parameters:

Returns:

Raises:

# leadr.games.services.game_service.GameService.get_game
get_game(game_id)

Get a game by its ID.

Parameters:

  • game_id (GameID) – The ID of the game to retrieve.

Returns:

  • Game | None – The Game domain entity if found, None otherwise.
# leadr.games.services.game_service.GameService.get_game_by_slug
get_game_by_slug(slug)

Get a game by its slug (globally unique).

Parameters:

  • slug (str) – The game slug to search for.

Returns:

  • Game | None – The Game domain entity if found, None otherwise.
# leadr.games.services.game_service.GameService.list_all
list_all()

List all non-deleted entities.

Returns:

# leadr.games.services.game_service.GameService.list_games
list_games(account_id, pagination=None)

List all games for an account with optional pagination.

Parameters:

  • account_id (AccountID | None) – The ID of the account to list games for. If None, returns all games (superadmin use case).
  • pagination (PaginationParams | None) – Optional pagination parameters.

Returns:

# leadr.games.services.game_service.GameService.repository
repository = self._create_repository(session)
# leadr.games.services.game_service.GameService.soft_delete
soft_delete(entity_id)

Soft-delete an entity and return it before deletion.

Useful for endpoints that need to return the deleted entity in the response.

Parameters:

Returns:

Raises:

# leadr.games.services.game_service.GameService.update_game
update_game(game_id, name=None, steam_app_id=None, default_board_id=None, anti_cheat_enabled=None, description=None, tags=None, page_url=None)

Update game fields.

Parameters:

  • game_id (GameID) – The ID of the game to update
  • name (str | None) – New game name, if provided
  • steam_app_id (str | None) – New Steam app ID, if provided
  • default_board_id (BoardID | None) – New default board ID, if provided
  • anti_cheat_enabled (bool | None) – Whether anti-cheat is enabled, if provided
  • description (str | None) – New game description, if provided
  • tags (list[str] | None) – New list of tags, if provided
  • page_url (str | None) – New page URL, if provided

Returns:

  • Game – The updated Game domain entity

Raises:

leadr.games.services.repositories

Game repository services.

Classes:

leadr.games.services.repositories.GameRepository

Bases: BaseRepository[Game, GameORM]

Game repository for managing game persistence.

Functions:

  • create – Create a new entity in the database.
  • delete – Soft delete an entity by setting its deleted_at timestamp.
  • filter – Filter games by account and optional criteria.
  • get_by_id – Get an entity by its ID.
  • get_by_slug – Get game by slug (globally unique lookup).
  • update – Update an existing entity in the database.

Attributes:

# leadr.games.services.repositories.GameRepository.SORTABLE_FIELDS
SORTABLE_FIELDS = {'id', 'name', 'slug', 'created_at', 'updated_at'}
# leadr.games.services.repositories.GameRepository.create
create(entity)

Create a new entity in the database.

Parameters:

Returns:

# leadr.games.services.repositories.GameRepository.delete
delete(entity_id)

Soft delete an entity by setting its deleted_at timestamp.

Parameters:

Raises:

# leadr.games.services.repositories.GameRepository.filter
filter(account_id=None, pagination=None, **kwargs)

Filter games by account and optional criteria.

Parameters:

  • account_id (UUID4 | PrefixedID | None) – Optional account ID to filter by. If None, returns all games (superadmin use case). Regular users should always pass account_id.
  • pagination (PaginationParams | None) – Optional pagination parameters
  • **kwargs (Any) – Additional filter parameters (reserved for future use)

Returns:

Raises:

# leadr.games.services.repositories.GameRepository.get_by_id
get_by_id(entity_id, include_deleted=False)

Get an entity by its ID.

Parameters:

  • entity_id (UUID4 | PrefixedID) – Entity ID to retrieve
  • include_deleted (bool) – If True, include soft-deleted entities. Defaults to False.

Returns:

  • DomainEntityT | None – Domain entity if found, None otherwise
# leadr.games.services.repositories.GameRepository.get_by_slug
get_by_slug(slug)

Get game by slug (globally unique lookup).

Parameters:

  • slug (str) – The game slug to search for.

Returns:

  • Game | None – Game domain entity if found, None otherwise.
# leadr.games.services.repositories.GameRepository.session
session = session
# leadr.games.services.repositories.GameRepository.update
update(entity)

Update an existing entity in the database.

Parameters:

Returns:

Raises: