78 lines
2.5 KiB
Python
78 lines
2.5 KiB
Python
from fastapi import FastAPI
|
|
|
|
from .router import router
|
|
from .recipes_router import router as recipes_router
|
|
from .database import engine
|
|
from sqlalchemy import text
|
|
|
|
app = FastAPI(title="FFXI Item Browser API")
|
|
|
|
# Ensure all_items view exists on startup
|
|
@app.on_event("startup")
|
|
async def ensure_view():
|
|
"""Recreate the materialized view `all_items` each startup to ensure schema consistency.
|
|
The view merges all *_items tables and exposes columns: id, name, description, icon_id, type_description.
|
|
Some source tables may lack `description` or `icon_id`; NULLs are substituted in those cases.
|
|
"""
|
|
async with engine.begin() as conn:
|
|
# Drop existing view if present
|
|
await conn.execute(text("DROP VIEW IF EXISTS all_items"))
|
|
|
|
# Discover item tables
|
|
table_rows = await conn.execute(
|
|
text(
|
|
"SELECT tablename FROM pg_tables WHERE schemaname='public'"
|
|
" AND tablename LIKE '%_items' AND tablename NOT IN ('inventory')"
|
|
)
|
|
)
|
|
tables = [r[0] for r in table_rows]
|
|
if not tables:
|
|
return
|
|
|
|
selects = []
|
|
for t in tables:
|
|
desc_exists = await conn.scalar(
|
|
text(
|
|
"""
|
|
SELECT EXISTS (
|
|
SELECT 1 FROM information_schema.columns
|
|
WHERE table_name=:table AND column_name='description'
|
|
)
|
|
"""),
|
|
{"table": t},
|
|
)
|
|
icon_exists = await conn.scalar(
|
|
text(
|
|
"""
|
|
SELECT EXISTS (
|
|
SELECT 1 FROM information_schema.columns
|
|
WHERE table_name=:table AND column_name='icon_id'
|
|
)
|
|
"""),
|
|
{"table": t},
|
|
)
|
|
desc_col = "description" if desc_exists else "NULL"
|
|
icon_col = "icon_id" if icon_exists else "NULL"
|
|
selects.append(
|
|
f"SELECT id, name, {desc_col} AS description, {icon_col} AS icon_id, type_description FROM {t}"
|
|
)
|
|
|
|
union_sql = " UNION ALL ".join(selects)
|
|
await conn.execute(text(f"CREATE VIEW all_items AS {union_sql}"))
|
|
await conn.commit()
|
|
|
|
# Mount API routes
|
|
app.include_router(router, prefix="/api")
|
|
app.include_router(recipes_router, prefix="/api")
|
|
|
|
|
|
@app.get("/health")
|
|
async def health():
|
|
return {"status": "ok"}
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import uvicorn
|
|
|
|
uvicorn.run("app.main:app", host="0.0.0.0", port=8000, reload=True)
|