Phase 3: Schema Layer - Pydantic v2 migration, deduplication, and missing schemas
- Migrated all schemas to Pydantic v2 syntax (model_config, ConfigDict) - Fixed mutable default in ProtoMessageBase using Field(default_factory=datetime.now) - Consolidated CardCollection and Wishlist schemas in user_card_collection.py - Created game_schemas.py with GameCreate, GameResponse, GameJoinRequest, etc. - Created mtg_card_schemas.py with MtgCardResponse, MtgCardSearchRequest, etc. - Added CardImportBatchCreate, CardImportBatchResponse, UserCardImportCreate/Response schemas - Fixed duplicate UserCardImportRecord class between card_import_batch.py and user_card_import_record.py - Updated __init__.py with comprehensive schema exports - Created verify_schemas.py for schema-model matching verification
This commit is contained in:
@@ -1 +1,133 @@
|
||||
# Schemas package
|
||||
"""Schemas package initialization."""
|
||||
from app.schemas.schemas import (
|
||||
LoginRequest, LoginResponse, RefreshTokenRequest, TokenResponse,
|
||||
UserBase, UserCreate, UserUpdate, UserResponse,
|
||||
DeckCreate, DeckUpdate, DeckResponse,
|
||||
FolderCreate, FolderResponse,
|
||||
GameCreate, GameResponse,
|
||||
RoomResponse,
|
||||
BanCreate, BanResponse,
|
||||
ErrorResponse, ValidationErrorResponse,
|
||||
PaginationParams, PaginatedResponse,
|
||||
CardMirrorResponse, DeckCardLinkResponse, DeckWithCardsResponse,
|
||||
)
|
||||
from app.schemas.user_data_schemas import (
|
||||
DeckVersionStatus, GameReplayStatus, GameOutcomeType,
|
||||
GroupMemberRole, NetworkMemberRole, UserPreferenceTheme, ActivityType,
|
||||
SessionResponse, SessionCleanupResponse,
|
||||
DeckVersionCreate, DeckVersionUpdate, DeckVersionResponse, DeckVersionListResponse,
|
||||
GameReplayCreate, GameReplayUpdate, GameReplayResponse, GameReplayListResponse,
|
||||
GameOutcomeCreate, GameOutcomeResponse, GameOutcomeListResponse,
|
||||
UserStatisticsResponse, StatisticsUpdateResponse,
|
||||
CardCollectionCreate, CardCollectionUpdate, CardCollectionResponse, CardCollectionListResponse,
|
||||
WishlistCreate, WishlistUpdate, WishlistResponse, WishlistListResponse,
|
||||
GroupCreate, GroupUpdate, GroupMemberCreate, GroupMemberUpdate, GroupMemberRemove,
|
||||
GroupResponse, GroupListResponse, GroupChatMessageCreate, GroupChatMessageResponse, GroupChatMessageListResponse,
|
||||
NetworkCreate, NetworkUpdate, NetworkMemberCreate,
|
||||
NetworkResponse, NetworkListResponse,
|
||||
UserPreferenceUpdate, UserPreferenceResponse,
|
||||
ActivityLogEntry, ActivityLogListResponse,
|
||||
MessageResponse, CountResponse, ErrorDetail,
|
||||
)
|
||||
from app.schemas.user_deck_schemas import (
|
||||
DeckStatus, DeckZone, SuggestionType,
|
||||
UserDeckCreate, UserDeckUpdate, UserDeckResponse, UserDeckListResponse,
|
||||
DeckCardCreate, DeckCardUpdate, DeckCardResponse, DeckCardWithDetailsResponse, DeckCardListResponse,
|
||||
PrecedentCreate, PrecedentUpdate, PrecedentResponse, PrecedentListResponse,
|
||||
SuggestionCreate, SuggestionResponse, SuggestionListResponse,
|
||||
DeckFinalizeRequest, DeckFinalizeResponse, DeckDeleteResponse,
|
||||
CardSearchRequest, CardSearchResponse,
|
||||
)
|
||||
from app.schemas.user_card_collection import (
|
||||
CardCondition, AcquisitionMethod,
|
||||
CollectionStatistics, CollectionSummaryResponse,
|
||||
)
|
||||
from app.schemas.card_import_schemas import (
|
||||
CardImportRequest, CardImportResponse, CardImportStatusResponse,
|
||||
CardMatchResult, CardImportSummary,
|
||||
CardImportBatchCreate, CardImportBatchResponse,
|
||||
UserCardImportCreate, UserCardImportResponse, UserCardImportRecordResponse,
|
||||
)
|
||||
from app.schemas.card_search_schemas import (
|
||||
CardResponse, SetResponse, CardTypeResponse,
|
||||
)
|
||||
from app.schemas.proto_messages import (
|
||||
ProtoMessageBase, SessionCommand, GameCommand, GameEvent, Response,
|
||||
ServerInfoUser, ServerInfoDeckStorageFile, ServerInfoDeckStorageFolder,
|
||||
ServerInfoDeckStorageTreeItem, ServerInfoCard, ServerInfoZone, ServerInfoGame,
|
||||
)
|
||||
from app.schemas.protocol_constants import (
|
||||
SessionCommandType, GameCommandType, GameEventType, ResponseCode,
|
||||
ZoneType, UserLevelFlag,
|
||||
)
|
||||
from app.schemas.game_schemas import (
|
||||
GameCreate, GameResponse, GameJoinRequest, GameLeaveRequest,
|
||||
GameListResponse, GamePlayerResponse, GameStateResponse,
|
||||
)
|
||||
from app.schemas.mtg_card_schemas import (
|
||||
MtgCardResponse, MtgCardSearchRequest, MtgCardSearchResponse,
|
||||
MtgSetResponse, MtgCardMirrorResponse, DeckCardLinkResponse, DeckWithCardsResponse,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
# Auth
|
||||
"LoginRequest", "LoginResponse", "RefreshTokenRequest", "TokenResponse",
|
||||
# User
|
||||
"UserBase", "UserCreate", "UserUpdate", "UserResponse",
|
||||
# Deck
|
||||
"DeckCreate", "DeckUpdate", "DeckResponse",
|
||||
"FolderCreate", "FolderResponse",
|
||||
# Game
|
||||
"GameCreate", "GameResponse", "RoomResponse",
|
||||
"GameJoinRequest", "GameLeaveRequest", "GameListResponse", "GamePlayerResponse", "GameStateResponse",
|
||||
# Ban
|
||||
"BanCreate", "BanResponse",
|
||||
# Error
|
||||
"ErrorResponse", "ValidationErrorResponse",
|
||||
# Pagination
|
||||
"PaginationParams", "PaginatedResponse",
|
||||
# Card Mirror
|
||||
"CardMirrorResponse", "DeckCardLinkResponse", "DeckWithCardsResponse",
|
||||
# User Data
|
||||
"DeckVersionStatus", "GameReplayStatus", "GameOutcomeType",
|
||||
"GroupMemberRole", "NetworkMemberRole", "UserPreferenceTheme", "ActivityType",
|
||||
"SessionResponse", "SessionCleanupResponse",
|
||||
"DeckVersionCreate", "DeckVersionUpdate", "DeckVersionResponse", "DeckVersionListResponse",
|
||||
"GameReplayCreate", "GameReplayUpdate", "GameReplayResponse", "GameReplayListResponse",
|
||||
"GameOutcomeCreate", "GameOutcomeResponse", "GameOutcomeListResponse",
|
||||
"UserStatisticsResponse", "StatisticsUpdateResponse",
|
||||
"CardCollectionCreate", "CardCollectionUpdate", "CardCollectionResponse", "CardCollectionListResponse",
|
||||
"WishlistCreate", "WishlistUpdate", "WishlistResponse", "WishlistListResponse",
|
||||
"GroupCreate", "GroupUpdate", "GroupMemberCreate", "GroupMemberUpdate", "GroupMemberRemove",
|
||||
"GroupResponse", "GroupListResponse", "GroupChatMessageCreate", "GroupChatMessageResponse", "GroupChatMessageListResponse",
|
||||
"NetworkCreate", "NetworkUpdate", "NetworkMemberCreate",
|
||||
"NetworkResponse", "NetworkListResponse",
|
||||
"UserPreferenceUpdate", "UserPreferenceResponse",
|
||||
"ActivityLogEntry", "ActivityLogListResponse",
|
||||
"MessageResponse", "CountResponse", "ErrorDetail",
|
||||
# User Deck
|
||||
"DeckStatus", "DeckZone", "SuggestionType",
|
||||
"UserDeckCreate", "UserDeckUpdate", "UserDeckResponse", "UserDeckListResponse",
|
||||
"DeckCardCreate", "DeckCardUpdate", "DeckCardResponse", "DeckCardWithDetailsResponse", "DeckCardListResponse",
|
||||
"PrecedentCreate", "PrecedentUpdate", "PrecedentResponse", "PrecedentListResponse",
|
||||
"SuggestionCreate", "SuggestionResponse", "SuggestionListResponse",
|
||||
"DeckFinalizeRequest", "DeckFinalizeResponse", "DeckDeleteResponse",
|
||||
"CardSearchRequest", "CardSearchResponse",
|
||||
# Card Collection
|
||||
"CardCondition", "AcquisitionMethod",
|
||||
"CollectionStatistics", "CollectionSummaryResponse",
|
||||
# Card Import
|
||||
"CardImportRequest", "CardImportResponse", "CardImportStatusResponse",
|
||||
"CardMatchResult", "CardImportSummary",
|
||||
"CardImportBatchCreate", "CardImportBatchResponse",
|
||||
"UserCardImportCreate", "UserCardImportResponse", "UserCardImportRecordResponse",
|
||||
# Card Search
|
||||
"CardResponse", "SetResponse", "CardTypeResponse",
|
||||
# Proto Messages
|
||||
"ProtoMessageBase", "SessionCommand", "GameCommand", "GameEvent", "Response",
|
||||
"ServerInfoUser", "ServerInfoDeckStorageFile", "ServerInfoDeckStorageFolder",
|
||||
"ServerInfoDeckStorageTreeItem", "ServerInfoCard", "ServerInfoZone", "ServerInfoGame",
|
||||
# Protocol Constants
|
||||
"SessionCommandType", "GameCommandType", "GameEventType", "ResponseCode",
|
||||
"ZoneType", "UserLevelFlag",
|
||||
]
|
||||
|
||||
@@ -4,7 +4,7 @@ Pydantic schemas for card import feature.
|
||||
Provides request/response models for importing card collections
|
||||
and using them for deckbuilding.
|
||||
"""
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
from typing import List, Optional, Dict, Any
|
||||
from datetime import datetime
|
||||
|
||||
@@ -53,6 +53,65 @@ class CardImportSummary(BaseModel):
|
||||
import_id: Optional[int] = None
|
||||
|
||||
|
||||
# ===== Card Import Batch Schemas =====
|
||||
|
||||
class CardImportBatchCreate(BaseModel):
|
||||
"""Card import batch creation request."""
|
||||
user_id: int
|
||||
card_names: List[str] = Field(..., min_length=1, max_length=10000)
|
||||
source: Optional[str] = None # 'manual', 'mtgjson', 'deck_text'
|
||||
|
||||
|
||||
class CardImportBatchResponse(BaseModel):
|
||||
"""Card import batch response."""
|
||||
id: int
|
||||
user_id: int
|
||||
card_names: List[str]
|
||||
source: Optional[str]
|
||||
status: str # 'pending', 'processing', 'completed', 'failed'
|
||||
total_cards: int
|
||||
matched_cards: int
|
||||
unmatched_cards: int
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class UserCardImportCreate(BaseModel):
|
||||
"""User card import request."""
|
||||
batch_id: int
|
||||
card_id: int
|
||||
quantity: int = Field(1, ge=1)
|
||||
match_confidence: Optional[float] = None
|
||||
|
||||
|
||||
class UserCardImportResponse(BaseModel):
|
||||
"""User card import response."""
|
||||
id: int
|
||||
user_id: int
|
||||
batch_id: int
|
||||
card_id: int
|
||||
quantity: int
|
||||
match_confidence: Optional[float]
|
||||
created_at: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class UserCardImportRecordResponse(BaseModel):
|
||||
"""User card import record response."""
|
||||
id: int
|
||||
user_id: int
|
||||
card_id: int
|
||||
batch_id: int
|
||||
quantity: int
|
||||
source: Optional[str]
|
||||
created_at: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
# Generic response models
|
||||
class MessageResponse(BaseModel):
|
||||
"""Generic message response."""
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
"""Pydantic schemas for game features."""
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
from typing import Optional, List, Dict, Any
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class GameCreate(BaseModel):
|
||||
"""Game creation request."""
|
||||
room_id: int
|
||||
game_type: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
password: Optional[str] = None
|
||||
max_players: int = Field(4, ge=2, le=8)
|
||||
|
||||
|
||||
class GameResponse(BaseModel):
|
||||
"""Game response payload."""
|
||||
id: int
|
||||
room_id: int
|
||||
game_type: Optional[str]
|
||||
description: Optional[str]
|
||||
with_password: bool
|
||||
max_players: int
|
||||
player_count: int
|
||||
started: bool
|
||||
creation_date: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class GameJoinRequest(BaseModel):
|
||||
"""Game join request."""
|
||||
game_id: int
|
||||
password: Optional[str] = None
|
||||
|
||||
|
||||
class GameLeaveRequest(BaseModel):
|
||||
"""Game leave request."""
|
||||
game_id: int
|
||||
|
||||
|
||||
class GameListResponse(BaseModel):
|
||||
"""List of games."""
|
||||
games: List[GameResponse]
|
||||
total: int
|
||||
|
||||
|
||||
class GamePlayerResponse(BaseModel):
|
||||
"""Game player response."""
|
||||
user_id: int
|
||||
username: str
|
||||
deck_id: Optional[int] = None
|
||||
is_ready: bool = False
|
||||
is_host: bool = False
|
||||
|
||||
|
||||
class GameStateResponse(BaseModel):
|
||||
"""Game state response."""
|
||||
game_id: int
|
||||
players: List[GamePlayerResponse]
|
||||
turn: int
|
||||
phase: str
|
||||
zones: Dict[str, Any]
|
||||
updated_at: datetime
|
||||
@@ -0,0 +1,122 @@
|
||||
"""Pydantic schemas for MTG card data."""
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
from typing import Optional, List, Dict, Any
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class MtgCardResponse(BaseModel):
|
||||
"""MTG card response with full details."""
|
||||
id: int
|
||||
source_id: Optional[int] = None
|
||||
name: str
|
||||
mana_cost: Optional[str] = None
|
||||
type_line: Optional[str] = None
|
||||
oracle_text: Optional[str] = None
|
||||
power: Optional[str] = None
|
||||
toughness: Optional[str] = None
|
||||
rarity: Optional[str] = None
|
||||
layout: Optional[str] = None
|
||||
artist: Optional[str] = None
|
||||
flavor_text: Optional[str] = None
|
||||
numbers: Optional[str] = None
|
||||
identifiers: Optional[Dict[str, Any]] = None
|
||||
images: Optional[Dict[str, Any]] = None
|
||||
image: Optional[str] = None
|
||||
card_parts: Optional[List[str]] = None
|
||||
keywords: Optional[List[str]] = None
|
||||
legalities: Optional[Dict[str, str]] = None
|
||||
set_code: Optional[str] = None
|
||||
set_name: Optional[str] = None
|
||||
synced_at: Optional[datetime] = None
|
||||
created_at: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class MtgCardSearchRequest(BaseModel):
|
||||
"""MTG card search request."""
|
||||
query: str = Field(..., min_length=1, max_length=100)
|
||||
set_code: Optional[str] = None
|
||||
rarity: Optional[str] = None
|
||||
type_line: Optional[str] = None
|
||||
limit: int = Field(50, ge=1, le=200)
|
||||
offset: int = Field(0, ge=0)
|
||||
|
||||
|
||||
class MtgCardSearchResponse(BaseModel):
|
||||
"""MTG card search response."""
|
||||
cards: List[MtgCardResponse]
|
||||
total: int
|
||||
page: int
|
||||
page_size: int
|
||||
total_pages: int
|
||||
|
||||
|
||||
class MtgSetResponse(BaseModel):
|
||||
"""MTG set response."""
|
||||
id: int
|
||||
code: str
|
||||
name: str
|
||||
release_date: Optional[datetime] = None
|
||||
card_count: Optional[int] = None
|
||||
type: Optional[str] = None
|
||||
border: Optional[str] = None
|
||||
mcm_id: Optional[int] = None
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class MtgCardMirrorResponse(BaseModel):
|
||||
"""Mirrored card data for user decks."""
|
||||
id: int
|
||||
source_id: Optional[int] = None
|
||||
name: str
|
||||
mana_cost: Optional[str] = None
|
||||
type_line: Optional[str] = None
|
||||
oracle_text: Optional[str] = None
|
||||
power: Optional[str] = None
|
||||
toughness: Optional[str] = None
|
||||
rarity: Optional[str] = None
|
||||
layout: Optional[str] = None
|
||||
artist: Optional[str] = None
|
||||
flavor_text: Optional[str] = None
|
||||
numbers: Optional[str] = None
|
||||
identifiers: Optional[Dict[str, Any]] = None
|
||||
images: Optional[Dict[str, Any]] = None
|
||||
image: Optional[str] = None
|
||||
card_parts: Optional[str] = None
|
||||
keywords: Optional[str] = None
|
||||
legalities: Optional[Dict[str, str]] = None
|
||||
set_code: Optional[str] = None
|
||||
set_name: Optional[str] = None
|
||||
synced_at: Optional[datetime] = None
|
||||
created_at: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class DeckCardLinkResponse(BaseModel):
|
||||
"""Deck-card link response."""
|
||||
id: int
|
||||
deck_id: int
|
||||
card_id: int
|
||||
quantity: int
|
||||
zone: str
|
||||
card: MtgCardMirrorResponse
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class DeckWithCardsResponse(BaseModel):
|
||||
"""Deck response with card links."""
|
||||
id: int
|
||||
name: str
|
||||
content: str
|
||||
format: str
|
||||
status: str
|
||||
folder_id: Optional[int] = None
|
||||
owner_id: int
|
||||
creation_date: datetime
|
||||
card_links: List[DeckCardLinkResponse] = []
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
Reference in New Issue
Block a user