initial: blog-app snapshot
This commit is contained in:
3
repositories/__init__.py
Normal file
3
repositories/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from . import project_repo, release_repo, issue_repo, watchdog_repo
|
||||
|
||||
__all__ = ["project_repo", "release_repo", "issue_repo", "watchdog_repo"]
|
||||
46
repositories/issue_repo.py
Normal file
46
repositories/issue_repo.py
Normal file
@@ -0,0 +1,46 @@
|
||||
"""Issue queries. No Flask imports; take an explicit sqlite3 connection.
|
||||
|
||||
Queries filter on `issues.project_id`, which is backed by the
|
||||
`idx_issues_project_id` index (Stage 4.2; docs/analysis/optional-indexes.sql).
|
||||
"""
|
||||
|
||||
ISSUE_COLUMNS = "id, project_id, title, state, created_at, html_url, user"
|
||||
|
||||
|
||||
def _rows(cur):
|
||||
return [dict(row) for row in cur.fetchall()]
|
||||
|
||||
|
||||
def list_recent_issues(db, limit=10):
|
||||
return _rows(
|
||||
db.execute(
|
||||
f"SELECT {ISSUE_COLUMNS} FROM issues "
|
||||
"ORDER BY created_at DESC LIMIT ?",
|
||||
(limit,),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def list_issues_for_project(db, project_id, limit=None):
|
||||
sql = (
|
||||
f"SELECT {ISSUE_COLUMNS} FROM issues "
|
||||
"WHERE project_id = ? ORDER BY created_at DESC"
|
||||
)
|
||||
params = (project_id,)
|
||||
if limit is not None:
|
||||
sql += " LIMIT ?"
|
||||
params = (project_id, limit)
|
||||
return _rows(db.execute(sql, params))
|
||||
|
||||
|
||||
def search_issues(db, keyword, limit=None):
|
||||
like = f"%{keyword}%"
|
||||
sql = (
|
||||
f"SELECT {ISSUE_COLUMNS} FROM issues "
|
||||
"WHERE title LIKE ? ORDER BY created_at DESC"
|
||||
)
|
||||
params = (like,)
|
||||
if limit is not None:
|
||||
sql += " LIMIT ?"
|
||||
params = (like, limit)
|
||||
return _rows(db.execute(sql, params))
|
||||
80
repositories/project_repo.py
Normal file
80
repositories/project_repo.py
Normal file
@@ -0,0 +1,80 @@
|
||||
"""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,
|
||||
}
|
||||
94
repositories/release_repo.py
Normal file
94
repositories/release_repo.py
Normal file
@@ -0,0 +1,94 @@
|
||||
"""Release queries. No Flask imports; take an explicit sqlite3 connection.
|
||||
|
||||
Queries filter on `releases.project_id`, which is backed by the
|
||||
`idx_releases_project_id` index (Stage 4.2; docs/analysis/optional-indexes.sql).
|
||||
"""
|
||||
|
||||
import config
|
||||
|
||||
RELEASE_COLUMNS = (
|
||||
"id, project_id, tag_name, name, body, published_at, html_url"
|
||||
)
|
||||
|
||||
# LLM context rows never need more than LLM_BODY_LIMIT body chars, so the
|
||||
# body is truncated in SQL and the full body never leaves the database.
|
||||
SLIM_RELEASE_COLUMNS = (
|
||||
f"id, project_id, tag_name, name, "
|
||||
f"substr(body, 1, {config.LLM_BODY_LIMIT}) AS body, published_at, html_url"
|
||||
)
|
||||
|
||||
|
||||
def _rows(cur):
|
||||
return [dict(row) for row in cur.fetchall()]
|
||||
|
||||
|
||||
def list_recent_releases(db, limit=5):
|
||||
return _rows(
|
||||
db.execute(
|
||||
f"SELECT {RELEASE_COLUMNS} FROM releases "
|
||||
"ORDER BY published_at DESC LIMIT ?",
|
||||
(limit,),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def list_recent_releases_slim(db, limit=5):
|
||||
return _rows(
|
||||
db.execute(
|
||||
f"SELECT {SLIM_RELEASE_COLUMNS} FROM releases "
|
||||
"ORDER BY published_at DESC LIMIT ?",
|
||||
(limit,),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def list_releases_for_project(db, project_id, limit=None):
|
||||
sql = (
|
||||
f"SELECT {RELEASE_COLUMNS} FROM releases "
|
||||
"WHERE project_id = ? ORDER BY published_at DESC"
|
||||
)
|
||||
params = (project_id,)
|
||||
if limit is not None:
|
||||
sql += " LIMIT ?"
|
||||
params = (project_id, limit)
|
||||
return _rows(db.execute(sql, params))
|
||||
|
||||
|
||||
def list_releases_for_project_slim(db, project_id, limit=None):
|
||||
sql = (
|
||||
f"SELECT {SLIM_RELEASE_COLUMNS} FROM releases "
|
||||
"WHERE project_id = ? ORDER BY published_at DESC"
|
||||
)
|
||||
params = (project_id,)
|
||||
if limit is not None:
|
||||
sql += " LIMIT ?"
|
||||
params = (project_id, limit)
|
||||
return _rows(db.execute(sql, params))
|
||||
|
||||
|
||||
def search_releases(db, keyword, limit=None):
|
||||
like = f"%{keyword}%"
|
||||
sql = (
|
||||
f"SELECT {RELEASE_COLUMNS} FROM releases "
|
||||
"WHERE tag_name LIKE ? OR name LIKE ? "
|
||||
"ORDER BY published_at DESC"
|
||||
)
|
||||
params = (like, like)
|
||||
if limit is not None:
|
||||
sql += " LIMIT ?"
|
||||
params = (like, like, limit)
|
||||
return _rows(db.execute(sql, params))
|
||||
|
||||
|
||||
def search_releases_slim(db, keyword, limit=None):
|
||||
like = f"%{keyword}%"
|
||||
sql = (
|
||||
f"SELECT {SLIM_RELEASE_COLUMNS} FROM releases "
|
||||
"WHERE tag_name LIKE ? OR name LIKE ? "
|
||||
"ORDER BY published_at DESC"
|
||||
)
|
||||
params = (like, like)
|
||||
if limit is not None:
|
||||
sql += " LIMIT ?"
|
||||
params = (like, like, limit)
|
||||
return _rows(db.execute(sql, params))
|
||||
29
repositories/watchdog_repo.py
Normal file
29
repositories/watchdog_repo.py
Normal file
@@ -0,0 +1,29 @@
|
||||
"""Watchdog report queries (read against watchdog.db). No Flask imports."""
|
||||
|
||||
import json
|
||||
import logging
|
||||
import sqlite3
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def list_reports(watchdog_conn, days=7):
|
||||
"""Return recent watchdog reports; rows include parsed `meta` dict.
|
||||
|
||||
Raises sqlite3.Error on read failure — the caller (service layer) decides
|
||||
how to degrade.
|
||||
"""
|
||||
cur = watchdog_conn.execute(
|
||||
"SELECT date, markdown, meta_json, created_at FROM reports "
|
||||
"ORDER BY date DESC LIMIT ?",
|
||||
(days,),
|
||||
)
|
||||
reports = []
|
||||
for row in cur.fetchall():
|
||||
item = dict(row)
|
||||
try:
|
||||
item["meta"] = json.loads(item.get("meta_json") or "{}")
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
item["meta"] = {}
|
||||
reports.append(item)
|
||||
return reports
|
||||
Reference in New Issue
Block a user