-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathdb.py
More file actions
91 lines (79 loc) · 2.77 KB
/
Copy pathdb.py
File metadata and controls
91 lines (79 loc) · 2.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
"""SQLite persistence for job application tracking."""
import sqlite3
from contextlib import closing
from datetime import datetime, timezone
from pathlib import Path
DB_PATH = Path.home() / ".hiringfunnel" / "hiringfunnel.db"
def _connect() -> sqlite3.Connection:
DB_PATH.parent.mkdir(parents=True, exist_ok=True)
conn = sqlite3.connect(str(DB_PATH))
conn.row_factory = sqlite3.Row
return conn
def init_db() -> None:
"""Create the applications table if it does not exist. Idempotent."""
with closing(_connect()) as conn:
conn.execute("""
CREATE TABLE IF NOT EXISTS applications (
id INTEGER PRIMARY KEY AUTOINCREMENT,
profile_name TEXT NOT NULL,
job_id TEXT,
title TEXT,
company TEXT,
status TEXT NOT NULL,
applied_at TEXT NOT NULL
)
""")
conn.commit()
def record_application(
profile_name: str,
job_id: str,
title: str,
company: str,
status: str,
) -> None:
"""Insert one application row. status should be 'applied' or 'failed'."""
with closing(_connect()) as conn:
conn.execute(
"INSERT INTO applications "
"(profile_name, job_id, title, company, status, applied_at) "
"VALUES (?, ?, ?, ?, ?, ?)",
(
profile_name,
job_id,
title,
company,
status,
datetime.now(timezone.utc).isoformat(),
),
)
conn.commit()
def get_profile_stats(profile_name: str) -> dict:
"""Return {applied: int, failed: int} for a single profile."""
with closing(_connect()) as conn:
row = conn.execute(
"SELECT "
" SUM(CASE WHEN status = 'applied' THEN 1 ELSE 0 END) AS applied, "
" SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END) AS failed "
"FROM applications WHERE profile_name = ?",
(profile_name,),
).fetchone()
return {
"applied": int(row["applied"] or 0),
"failed": int(row["failed"] or 0),
}
def get_all_stats() -> dict:
"""Return {profile_name: {applied: int, failed: int}} for all profiles."""
with closing(_connect()) as conn:
rows = conn.execute(
"SELECT profile_name, status, COUNT(*) AS cnt "
"FROM applications "
"GROUP BY profile_name, status"
).fetchall()
stats: dict = {}
for row in rows:
name = row["profile_name"]
if name not in stats:
stats[name] = {"applied": 0, "failed": 0}
if row["status"] in ("applied", "failed"):
stats[name][row["status"]] = row["cnt"]
return stats