Daedalus and Talos integration test
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
"""add moves and abilities tables
|
||||
|
||||
Revision ID: j1e2f3a4b5c6
|
||||
Revises: i0d1e2f3a4b5
|
||||
Create Date: 2026-03-20 12:00:00.000000
|
||||
|
||||
"""
|
||||
|
||||
from collections.abc import Sequence
|
||||
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = "j1e2f3a4b5c6"
|
||||
down_revision: str | Sequence[str] | None = "i0d1e2f3a4b5"
|
||||
branch_labels: str | Sequence[str] | None = None
|
||||
depends_on: str | Sequence[str] | None = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# Create moves table
|
||||
op.create_table(
|
||||
"moves",
|
||||
sa.Column("id", sa.Integer(), primary_key=True),
|
||||
sa.Column("name", sa.String(50), nullable=False, unique=True),
|
||||
sa.Column("introduced_gen", sa.SmallInteger(), nullable=False),
|
||||
sa.Column("type", sa.String(20), nullable=True),
|
||||
)
|
||||
op.create_index("ix_moves_introduced_gen", "moves", ["introduced_gen"])
|
||||
|
||||
# Create abilities table
|
||||
op.create_table(
|
||||
"abilities",
|
||||
sa.Column("id", sa.Integer(), primary_key=True),
|
||||
sa.Column("name", sa.String(50), nullable=False, unique=True),
|
||||
sa.Column("introduced_gen", sa.SmallInteger(), nullable=False),
|
||||
)
|
||||
op.create_index("ix_abilities_introduced_gen", "abilities", ["introduced_gen"])
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_index("ix_abilities_introduced_gen", "abilities")
|
||||
op.drop_table("abilities")
|
||||
op.drop_index("ix_moves_introduced_gen", "moves")
|
||||
op.drop_table("moves")
|
||||
@@ -0,0 +1,63 @@
|
||||
"""add journal entries table
|
||||
|
||||
Revision ID: k2f3a4b5c6d7
|
||||
Revises: j1e2f3a4b5c6
|
||||
Create Date: 2026-03-20 12:00:00.000000
|
||||
|
||||
"""
|
||||
|
||||
from collections.abc import Sequence
|
||||
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = "k2f3a4b5c6d7"
|
||||
down_revision: str | Sequence[str] | None = "j1e2f3a4b5c6"
|
||||
branch_labels: str | Sequence[str] | None = None
|
||||
depends_on: str | Sequence[str] | None = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.create_table(
|
||||
"journal_entries",
|
||||
sa.Column(
|
||||
"id",
|
||||
sa.UUID(),
|
||||
primary_key=True,
|
||||
server_default=sa.text("gen_random_uuid()"),
|
||||
),
|
||||
sa.Column(
|
||||
"run_id",
|
||||
sa.Integer(),
|
||||
sa.ForeignKey("nuzlocke_runs.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
index=True,
|
||||
),
|
||||
sa.Column(
|
||||
"boss_result_id",
|
||||
sa.Integer(),
|
||||
sa.ForeignKey("boss_results.id", ondelete="SET NULL"),
|
||||
nullable=True,
|
||||
index=True,
|
||||
),
|
||||
sa.Column("title", sa.String(200), nullable=False),
|
||||
sa.Column("body", sa.Text(), nullable=False),
|
||||
sa.Column(
|
||||
"created_at",
|
||||
sa.DateTime(timezone=True),
|
||||
nullable=False,
|
||||
server_default=sa.func.now(),
|
||||
),
|
||||
sa.Column(
|
||||
"updated_at",
|
||||
sa.DateTime(timezone=True),
|
||||
nullable=False,
|
||||
server_default=sa.func.now(),
|
||||
onupdate=sa.func.now(),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_table("journal_entries")
|
||||
151
backend/src/app/api/journal_entries.py
Normal file
151
backend/src/app/api/journal_entries.py
Normal file
@@ -0,0 +1,151 @@
|
||||
from datetime import UTC, datetime
|
||||
from uuid import UUID
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Response
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.core.database import get_session
|
||||
from app.models.boss_result import BossResult
|
||||
from app.models.journal_entry import JournalEntry
|
||||
from app.models.nuzlocke_run import NuzlockeRun
|
||||
from app.schemas.journal_entry import (
|
||||
JournalEntryCreate,
|
||||
JournalEntryResponse,
|
||||
JournalEntryUpdate,
|
||||
)
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/{run_id}/journal", response_model=list[JournalEntryResponse])
|
||||
async def list_journal_entries(
|
||||
run_id: int,
|
||||
boss_result_id: int | None = None,
|
||||
session: AsyncSession = Depends(get_session),
|
||||
):
|
||||
# Validate run exists
|
||||
run = await session.get(NuzlockeRun, run_id)
|
||||
if run is None:
|
||||
raise HTTPException(status_code=404, detail="Run not found")
|
||||
|
||||
query = select(JournalEntry).where(JournalEntry.run_id == run_id)
|
||||
|
||||
if boss_result_id is not None:
|
||||
query = query.where(JournalEntry.boss_result_id == boss_result_id)
|
||||
|
||||
query = query.order_by(JournalEntry.created_at.desc())
|
||||
|
||||
result = await session.execute(query)
|
||||
return result.scalars().all()
|
||||
|
||||
|
||||
@router.post("/{run_id}/journal", response_model=JournalEntryResponse, status_code=201)
|
||||
async def create_journal_entry(
|
||||
run_id: int,
|
||||
data: JournalEntryCreate,
|
||||
session: AsyncSession = Depends(get_session),
|
||||
):
|
||||
# Validate run exists
|
||||
run = await session.get(NuzlockeRun, run_id)
|
||||
if run is None:
|
||||
raise HTTPException(status_code=404, detail="Run not found")
|
||||
|
||||
# Validate boss_result_id if provided
|
||||
if data.boss_result_id is not None:
|
||||
boss_result = await session.get(BossResult, data.boss_result_id)
|
||||
if boss_result is None:
|
||||
raise HTTPException(status_code=404, detail="Boss result not found")
|
||||
if boss_result.run_id != run_id:
|
||||
raise HTTPException(
|
||||
status_code=400, detail="Boss result does not belong to this run"
|
||||
)
|
||||
|
||||
entry = JournalEntry(
|
||||
run_id=run_id,
|
||||
boss_result_id=data.boss_result_id,
|
||||
title=data.title,
|
||||
body=data.body,
|
||||
)
|
||||
session.add(entry)
|
||||
await session.commit()
|
||||
await session.refresh(entry)
|
||||
return entry
|
||||
|
||||
|
||||
@router.get("/{run_id}/journal/{entry_id}", response_model=JournalEntryResponse)
|
||||
async def get_journal_entry(
|
||||
run_id: int,
|
||||
entry_id: UUID,
|
||||
session: AsyncSession = Depends(get_session),
|
||||
):
|
||||
result = await session.execute(
|
||||
select(JournalEntry).where(
|
||||
JournalEntry.id == entry_id,
|
||||
JournalEntry.run_id == run_id,
|
||||
)
|
||||
)
|
||||
entry = result.scalar_one_or_none()
|
||||
if entry is None:
|
||||
raise HTTPException(status_code=404, detail="Journal entry not found")
|
||||
return entry
|
||||
|
||||
|
||||
@router.put("/{run_id}/journal/{entry_id}", response_model=JournalEntryResponse)
|
||||
async def update_journal_entry(
|
||||
run_id: int,
|
||||
entry_id: UUID,
|
||||
data: JournalEntryUpdate,
|
||||
session: AsyncSession = Depends(get_session),
|
||||
):
|
||||
result = await session.execute(
|
||||
select(JournalEntry).where(
|
||||
JournalEntry.id == entry_id,
|
||||
JournalEntry.run_id == run_id,
|
||||
)
|
||||
)
|
||||
entry = result.scalar_one_or_none()
|
||||
if entry is None:
|
||||
raise HTTPException(status_code=404, detail="Journal entry not found")
|
||||
|
||||
update_data = data.model_dump(exclude_unset=True)
|
||||
|
||||
# Validate boss_result_id if provided
|
||||
if "boss_result_id" in update_data and update_data["boss_result_id"] is not None:
|
||||
boss_result = await session.get(BossResult, update_data["boss_result_id"])
|
||||
if boss_result is None:
|
||||
raise HTTPException(status_code=404, detail="Boss result not found")
|
||||
if boss_result.run_id != run_id:
|
||||
raise HTTPException(
|
||||
status_code=400, detail="Boss result does not belong to this run"
|
||||
)
|
||||
|
||||
for field, value in update_data.items():
|
||||
setattr(entry, field, value)
|
||||
|
||||
entry.updated_at = datetime.now(UTC)
|
||||
|
||||
await session.commit()
|
||||
await session.refresh(entry)
|
||||
return entry
|
||||
|
||||
|
||||
@router.delete("/{run_id}/journal/{entry_id}", status_code=204)
|
||||
async def delete_journal_entry(
|
||||
run_id: int,
|
||||
entry_id: UUID,
|
||||
session: AsyncSession = Depends(get_session),
|
||||
):
|
||||
result = await session.execute(
|
||||
select(JournalEntry).where(
|
||||
JournalEntry.id == entry_id,
|
||||
JournalEntry.run_id == run_id,
|
||||
)
|
||||
)
|
||||
entry = result.scalar_one_or_none()
|
||||
if entry is None:
|
||||
raise HTTPException(status_code=404, detail="Journal entry not found")
|
||||
|
||||
await session.delete(entry)
|
||||
await session.commit()
|
||||
return Response(status_code=204)
|
||||
@@ -8,6 +8,7 @@ from app.api import (
|
||||
games,
|
||||
genlockes,
|
||||
health,
|
||||
journal_entries,
|
||||
pokemon,
|
||||
runs,
|
||||
stats,
|
||||
@@ -19,6 +20,7 @@ api_router.include_router(games.router, prefix="/games", tags=["games"])
|
||||
api_router.include_router(pokemon.router, tags=["pokemon"])
|
||||
api_router.include_router(evolutions.router, tags=["evolutions"])
|
||||
api_router.include_router(runs.router, prefix="/runs", tags=["runs"])
|
||||
api_router.include_router(journal_entries.router, prefix="/runs", tags=["journal"])
|
||||
api_router.include_router(genlockes.router, prefix="/genlockes", tags=["genlockes"])
|
||||
api_router.include_router(encounters.router, tags=["encounters"])
|
||||
api_router.include_router(stats.router, prefix="/stats", tags=["stats"])
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from app.models.ability import Ability
|
||||
from app.models.boss_battle import BossBattle
|
||||
from app.models.boss_pokemon import BossPokemon
|
||||
from app.models.boss_result import BossResult
|
||||
@@ -6,6 +7,8 @@ from app.models.evolution import Evolution
|
||||
from app.models.game import Game
|
||||
from app.models.genlocke import Genlocke, GenlockeLeg
|
||||
from app.models.genlocke_transfer import GenlockeTransfer
|
||||
from app.models.journal_entry import JournalEntry
|
||||
from app.models.move import Move
|
||||
from app.models.nuzlocke_run import NuzlockeRun
|
||||
from app.models.pokemon import Pokemon
|
||||
from app.models.route import Route
|
||||
@@ -13,6 +16,7 @@ from app.models.route_encounter import RouteEncounter
|
||||
from app.models.version_group import VersionGroup
|
||||
|
||||
__all__ = [
|
||||
"Ability",
|
||||
"BossBattle",
|
||||
"BossPokemon",
|
||||
"BossResult",
|
||||
@@ -22,6 +26,8 @@ __all__ = [
|
||||
"Genlocke",
|
||||
"GenlockeLeg",
|
||||
"GenlockeTransfer",
|
||||
"JournalEntry",
|
||||
"Move",
|
||||
"NuzlockeRun",
|
||||
"Pokemon",
|
||||
"Route",
|
||||
|
||||
15
backend/src/app/models/ability.py
Normal file
15
backend/src/app/models/ability.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from sqlalchemy import SmallInteger, String
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.core.database import Base
|
||||
|
||||
|
||||
class Ability(Base):
|
||||
__tablename__ = "abilities"
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
name: Mapped[str] = mapped_column(String(50), unique=True)
|
||||
introduced_gen: Mapped[int] = mapped_column(SmallInteger)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<Ability(id={self.id}, name='{self.name}', gen={self.introduced_gen})>"
|
||||
37
backend/src/app/models/journal_entry.py
Normal file
37
backend/src/app/models/journal_entry.py
Normal file
@@ -0,0 +1,37 @@
|
||||
from datetime import datetime
|
||||
from uuid import UUID
|
||||
|
||||
from sqlalchemy import DateTime, ForeignKey, String, Text, func
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from app.core.database import Base
|
||||
|
||||
|
||||
class JournalEntry(Base):
|
||||
__tablename__ = "journal_entries"
|
||||
|
||||
id: Mapped[UUID] = mapped_column(
|
||||
primary_key=True, server_default=func.gen_random_uuid()
|
||||
)
|
||||
run_id: Mapped[int] = mapped_column(
|
||||
ForeignKey("nuzlocke_runs.id", ondelete="CASCADE"), index=True
|
||||
)
|
||||
boss_result_id: Mapped[int | None] = mapped_column(
|
||||
ForeignKey("boss_results.id", ondelete="SET NULL"), index=True
|
||||
)
|
||||
title: Mapped[str] = mapped_column(String(200))
|
||||
body: Mapped[str] = mapped_column(Text)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), server_default=func.now()
|
||||
)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
|
||||
)
|
||||
|
||||
run: Mapped[NuzlockeRun] = relationship(back_populates="journal_entries")
|
||||
boss_result: Mapped[BossResult | None] = relationship()
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f"<JournalEntry(id={self.id}, run_id={self.run_id}, title='{self.title}')>"
|
||||
)
|
||||
16
backend/src/app/models/move.py
Normal file
16
backend/src/app/models/move.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from sqlalchemy import SmallInteger, String
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.core.database import Base
|
||||
|
||||
|
||||
class Move(Base):
|
||||
__tablename__ = "moves"
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
name: Mapped[str] = mapped_column(String(50), unique=True)
|
||||
introduced_gen: Mapped[int] = mapped_column(SmallInteger)
|
||||
type: Mapped[str | None] = mapped_column(String(20))
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<Move(id={self.id}, name='{self.name}', gen={self.introduced_gen})>"
|
||||
@@ -27,6 +27,7 @@ class NuzlockeRun(Base):
|
||||
game: Mapped[Game] = relationship(back_populates="runs")
|
||||
encounters: Mapped[list[Encounter]] = relationship(back_populates="run")
|
||||
boss_results: Mapped[list[BossResult]] = relationship(back_populates="run")
|
||||
journal_entries: Mapped[list[JournalEntry]] = relationship(back_populates="run")
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
|
||||
@@ -25,6 +25,17 @@ from app.schemas.game import (
|
||||
RouteUpdate,
|
||||
)
|
||||
from app.schemas.genlocke import GenlockeCreate, GenlockeLegResponse, GenlockeResponse
|
||||
from app.schemas.journal_entry import (
|
||||
JournalEntryCreate,
|
||||
JournalEntryResponse,
|
||||
JournalEntryUpdate,
|
||||
)
|
||||
from app.schemas.move import (
|
||||
AbilityResponse,
|
||||
MoveResponse,
|
||||
PaginatedAbilityResponse,
|
||||
PaginatedMoveResponse,
|
||||
)
|
||||
from app.schemas.pokemon import (
|
||||
BulkImportItem,
|
||||
BulkImportResult,
|
||||
@@ -46,6 +57,7 @@ from app.schemas.run import (
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"AbilityResponse",
|
||||
"BossBattleCreate",
|
||||
"BossBattleResponse",
|
||||
"BossBattleUpdate",
|
||||
@@ -68,6 +80,12 @@ __all__ = [
|
||||
"GameDetailResponse",
|
||||
"GameResponse",
|
||||
"GameUpdate",
|
||||
"JournalEntryCreate",
|
||||
"JournalEntryResponse",
|
||||
"JournalEntryUpdate",
|
||||
"MoveResponse",
|
||||
"PaginatedAbilityResponse",
|
||||
"PaginatedMoveResponse",
|
||||
"PokemonCreate",
|
||||
"PokemonResponse",
|
||||
"PokemonUpdate",
|
||||
|
||||
26
backend/src/app/schemas/journal_entry.py
Normal file
26
backend/src/app/schemas/journal_entry.py
Normal file
@@ -0,0 +1,26 @@
|
||||
from datetime import datetime
|
||||
from uuid import UUID
|
||||
|
||||
from app.schemas.base import CamelModel
|
||||
|
||||
|
||||
class JournalEntryCreate(CamelModel):
|
||||
boss_result_id: int | None = None
|
||||
title: str
|
||||
body: str
|
||||
|
||||
|
||||
class JournalEntryUpdate(CamelModel):
|
||||
boss_result_id: int | None = None
|
||||
title: str | None = None
|
||||
body: str | None = None
|
||||
|
||||
|
||||
class JournalEntryResponse(CamelModel):
|
||||
id: UUID
|
||||
run_id: int
|
||||
boss_result_id: int | None
|
||||
title: str
|
||||
body: str
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
28
backend/src/app/schemas/move.py
Normal file
28
backend/src/app/schemas/move.py
Normal file
@@ -0,0 +1,28 @@
|
||||
from app.schemas.base import CamelModel
|
||||
|
||||
|
||||
class MoveResponse(CamelModel):
|
||||
id: int
|
||||
name: str
|
||||
introduced_gen: int
|
||||
type: str | None
|
||||
|
||||
|
||||
class PaginatedMoveResponse(CamelModel):
|
||||
items: list[MoveResponse]
|
||||
total: int
|
||||
limit: int
|
||||
offset: int
|
||||
|
||||
|
||||
class AbilityResponse(CamelModel):
|
||||
id: int
|
||||
name: str
|
||||
introduced_gen: int
|
||||
|
||||
|
||||
class PaginatedAbilityResponse(CamelModel):
|
||||
items: list[AbilityResponse]
|
||||
total: int
|
||||
limit: int
|
||||
offset: int
|
||||
1470
backend/src/app/seeds/data/abilities.json
Normal file
1470
backend/src/app/seeds/data/abilities.json
Normal file
File diff suppressed because it is too large
Load Diff
4687
backend/src/app/seeds/data/moves.json
Normal file
4687
backend/src/app/seeds/data/moves.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -4,11 +4,13 @@ from sqlalchemy import delete, select, update
|
||||
from sqlalchemy.dialects.postgresql import insert
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.models.ability import Ability
|
||||
from app.models.boss_battle import BossBattle
|
||||
from app.models.boss_pokemon import BossPokemon
|
||||
from app.models.encounter import Encounter
|
||||
from app.models.evolution import Evolution
|
||||
from app.models.game import Game
|
||||
from app.models.move import Move
|
||||
from app.models.pokemon import Pokemon
|
||||
from app.models.route import Route
|
||||
from app.models.route_encounter import RouteEncounter
|
||||
@@ -484,3 +486,59 @@ async def upsert_evolutions(
|
||||
|
||||
await session.flush()
|
||||
return count
|
||||
|
||||
|
||||
async def upsert_moves(
|
||||
session: AsyncSession,
|
||||
moves: list[dict],
|
||||
) -> int:
|
||||
"""Upsert move records, return count of upserted rows."""
|
||||
count = 0
|
||||
for move in moves:
|
||||
stmt = (
|
||||
insert(Move)
|
||||
.values(
|
||||
name=move["name"],
|
||||
introduced_gen=move["introduced_gen"],
|
||||
type=move.get("type"),
|
||||
)
|
||||
.on_conflict_do_update(
|
||||
index_elements=["name"],
|
||||
set_={
|
||||
"introduced_gen": move["introduced_gen"],
|
||||
"type": move.get("type"),
|
||||
},
|
||||
)
|
||||
)
|
||||
await session.execute(stmt)
|
||||
count += 1
|
||||
|
||||
await session.flush()
|
||||
return count
|
||||
|
||||
|
||||
async def upsert_abilities(
|
||||
session: AsyncSession,
|
||||
abilities: list[dict],
|
||||
) -> int:
|
||||
"""Upsert ability records, return count of upserted rows."""
|
||||
count = 0
|
||||
for ability in abilities:
|
||||
stmt = (
|
||||
insert(Ability)
|
||||
.values(
|
||||
name=ability["name"],
|
||||
introduced_gen=ability["introduced_gen"],
|
||||
)
|
||||
.on_conflict_do_update(
|
||||
index_elements=["name"],
|
||||
set_={
|
||||
"introduced_gen": ability["introduced_gen"],
|
||||
},
|
||||
)
|
||||
)
|
||||
await session.execute(stmt)
|
||||
count += 1
|
||||
|
||||
await session.flush()
|
||||
return count
|
||||
|
||||
@@ -10,18 +10,22 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import selectinload
|
||||
|
||||
from app.core.database import async_session
|
||||
from app.models.ability import Ability
|
||||
from app.models.boss_battle import BossBattle
|
||||
from app.models.boss_pokemon import BossPokemon
|
||||
from app.models.evolution import Evolution
|
||||
from app.models.game import Game
|
||||
from app.models.move import Move
|
||||
from app.models.pokemon import Pokemon
|
||||
from app.models.route import Route
|
||||
from app.models.route_encounter import RouteEncounter
|
||||
from app.models.version_group import VersionGroup
|
||||
from app.seeds.loader import (
|
||||
upsert_abilities,
|
||||
upsert_bosses,
|
||||
upsert_evolutions,
|
||||
upsert_games,
|
||||
upsert_moves,
|
||||
upsert_pokemon,
|
||||
upsert_route_encounters,
|
||||
upsert_routes,
|
||||
@@ -69,6 +73,24 @@ async def seed(*, prune: bool = False):
|
||||
dex_to_id = await upsert_pokemon(session, pokemon_data)
|
||||
print(f"Pokemon: {len(dex_to_id)} upserted")
|
||||
|
||||
# 3a. Upsert Moves
|
||||
moves_path = DATA_DIR / "moves.json"
|
||||
if moves_path.exists():
|
||||
moves_data = load_json("moves.json")
|
||||
moves_count = await upsert_moves(session, moves_data)
|
||||
print(f"Moves: {moves_count} upserted")
|
||||
else:
|
||||
print("No moves.json found, skipping moves")
|
||||
|
||||
# 3b. Upsert Abilities
|
||||
abilities_path = DATA_DIR / "abilities.json"
|
||||
if abilities_path.exists():
|
||||
abilities_data = load_json("abilities.json")
|
||||
abilities_count = await upsert_abilities(session, abilities_data)
|
||||
print(f"Abilities: {abilities_count} upserted")
|
||||
else:
|
||||
print("No abilities.json found, skipping abilities")
|
||||
|
||||
# 4. Per version group: upsert routes once, then encounters per game
|
||||
total_routes = 0
|
||||
total_encounters = 0
|
||||
@@ -199,6 +221,10 @@ async def verify():
|
||||
vg_count = (await session.execute(select(func.count(VersionGroup.id)))).scalar()
|
||||
games_count = (await session.execute(select(func.count(Game.id)))).scalar()
|
||||
pokemon_count = (await session.execute(select(func.count(Pokemon.id)))).scalar()
|
||||
moves_count = (await session.execute(select(func.count(Move.id)))).scalar()
|
||||
abilities_count = (
|
||||
await session.execute(select(func.count(Ability.id)))
|
||||
).scalar()
|
||||
routes_count = (await session.execute(select(func.count(Route.id)))).scalar()
|
||||
enc_count = (
|
||||
await session.execute(select(func.count(RouteEncounter.id)))
|
||||
@@ -208,6 +234,8 @@ async def verify():
|
||||
print(f"Version Groups: {vg_count}")
|
||||
print(f"Games: {games_count}")
|
||||
print(f"Pokemon: {pokemon_count}")
|
||||
print(f"Moves: {moves_count}")
|
||||
print(f"Abilities: {abilities_count}")
|
||||
print(f"Routes: {routes_count}")
|
||||
print(f"Route Encounters: {enc_count}")
|
||||
print(f"Boss Battles: {boss_count}")
|
||||
|
||||
Reference in New Issue
Block a user