"""Project-related queries. Organized by business scenario (project browsing / search / stats), not one-repo-per-table. Functions take an explicit sqlite3 connection with row_factory=sqlite3.Row and return plain dicts. No Flask imports. """ import logging logger = logging.getLogger(__name__) PROJECT_COLUMNS = ( "id, name, full_name, description, stars, forks, language, html_url, " "created_at, updated_at, source" ) def _rows(cur): return [dict(row) for row in cur.fetchall()] def list_projects(db): """All projects ordered by stars desc.""" return _rows( db.execute(f"SELECT {PROJECT_COLUMNS} FROM projects ORDER BY stars DESC") ) def get_project(db, project_id): """Single project row as dict, or None.""" row = db.execute( f"SELECT {PROJECT_COLUMNS} FROM projects WHERE id = ?", (project_id,) ).fetchone() return dict(row) if row is not None else None # Backward-compatible alias for the pre-refactor name. get_all_projects = list_projects def list_project_summaries(db): """Slim project list (id/name/full_name/stars/forks/language) for selectors.""" return _rows( db.execute( "SELECT id, name, full_name, stars, forks, language " "FROM projects ORDER BY stars DESC" ) ) def search_projects(db, keyword): like = f"%{keyword}%" return _rows( db.execute( f"SELECT {PROJECT_COLUMNS} FROM projects WHERE name LIKE ? OR full_name LIKE ? " "ORDER BY stars DESC", (like, like), ) ) def get_starred_names(db): """Return the set of project names flagged `starred = 1` (Stage 4.1).""" cur = db.execute("SELECT name FROM projects WHERE starred = 1") return {row["name"] for row in cur.fetchall()} def get_stats(db): """Single-row aggregate stats across projects/releases/issues.""" total_projects = db.execute("SELECT COUNT(*) FROM projects").fetchone()[0] total_releases = db.execute("SELECT COUNT(*) FROM releases").fetchone()[0] total_issues = db.execute("SELECT COUNT(*) FROM issues").fetchone()[0] total_stars = db.execute("SELECT COALESCE(SUM(stars), 0) FROM projects").fetchone()[0] return { "total_projects": total_projects, "total_releases": total_releases, "total_issues": total_issues, "total_stars": total_stars, }