feat: support full click gap history generation
This commit is contained in:
@@ -103,21 +103,33 @@ def validate_existing_schema(path: str) -> None:
|
||||
raise RuntimeError("click_gap 主键必须为 (pid, dt, pkg_name)")
|
||||
|
||||
|
||||
def read_rows(path: str, start: str, end: str, pid: str = PID) -> list[dict[str, Any]]:
|
||||
def read_rows(path: str, start: str | None, end: str | None, pid: str = PID) -> list[dict[str, Any]]:
|
||||
validate_existing_schema(path)
|
||||
try:
|
||||
with sqlite3.connect(f"file:{path}?mode=ro", uri=True) as conn:
|
||||
conn.row_factory = sqlite3.Row
|
||||
result = conn.execute(
|
||||
query = (
|
||||
"SELECT dt, attr_platform, pkg_name, shareit_clicks, af_clicks, installs_ua, clicks_diff, clicks_diff_rate "
|
||||
"FROM click_gap WHERE pid=? AND dt BETWEEN ? AND ? ORDER BY dt DESC, shareit_clicks DESC, pkg_name",
|
||||
(pid, start, end),
|
||||
"FROM click_gap WHERE pid=?"
|
||||
)
|
||||
parameters: list[str] = [pid]
|
||||
if start is not None and end is not None:
|
||||
query += " AND dt BETWEEN ? AND ?"
|
||||
parameters.extend((start, end))
|
||||
query += " ORDER BY dt DESC, shareit_clicks DESC, pkg_name"
|
||||
result = conn.execute(query, parameters)
|
||||
return [dict(row) for row in result]
|
||||
except sqlite3.Error as exc:
|
||||
raise RuntimeError(f"SQLite 查询失败: {exc}") from exc
|
||||
|
||||
|
||||
def available_dates(rows: list[dict[str, Any]]) -> list[str]:
|
||||
dates = set()
|
||||
for row in rows:
|
||||
dates.add(date8(str(row["dt"])))
|
||||
return sorted(dates, reverse=True)
|
||||
|
||||
|
||||
def validate_rows(rows: list[dict[str, Any]], start: str, end: str) -> list[dict[str, Any]]:
|
||||
normalized = []
|
||||
for row in rows:
|
||||
@@ -213,6 +225,7 @@ def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description="Read SQLite click-gap data and publish JSON")
|
||||
parser.add_argument("--start-date", help="读取开始日期 YYYY-MM-DD")
|
||||
parser.add_argument("--end-date", help="读取结束日期 YYYY-MM-DD")
|
||||
parser.add_argument("--all", action="store_true", help="读取数据库中所有实际有数据的日期")
|
||||
parser.add_argument("--dry-run", action="store_true", help="只读取、校验并生成临时 JSON,不写文件或 Git")
|
||||
group = parser.add_mutually_exclusive_group()
|
||||
group.add_argument("--no-push", action="store_true", help="写文件但不 push")
|
||||
@@ -226,11 +239,19 @@ def main() -> int:
|
||||
try:
|
||||
if args.dry_run and (args.no_push or args.push):
|
||||
raise ValueError("--dry-run 不可与 --push/--no-push 同时使用")
|
||||
start, end = window(args.start_date, args.end_date)
|
||||
rows = validate_rows(read_rows(args.db_path, start, end), start, end)
|
||||
first = dt.datetime.strptime(start, "%Y%m%d").date()
|
||||
last = dt.datetime.strptime(end, "%Y%m%d").date()
|
||||
dates = [(first + dt.timedelta(days=i)).strftime("%Y%m%d") for i in range((last - first).days + 1)]
|
||||
if args.all and (args.start_date or args.end_date):
|
||||
raise ValueError("--all 不可与 --start-date/--end-date 同时使用")
|
||||
if args.all:
|
||||
rows = validate_rows(read_rows(args.db_path, None, None), "00010101", "99991231")
|
||||
dates = available_dates(rows)
|
||||
start = dates[-1] if dates else "无日期"
|
||||
end = dates[0] if dates else "无日期"
|
||||
else:
|
||||
start, end = window(args.start_date, args.end_date)
|
||||
rows = validate_rows(read_rows(args.db_path, start, end), start, end)
|
||||
first = dt.datetime.strptime(start, "%Y%m%d").date()
|
||||
last = dt.datetime.strptime(end, "%Y%m%d").date()
|
||||
dates = [(first + dt.timedelta(days=i)).strftime("%Y%m%d") for i in range((last - first).days + 1)]
|
||||
repo = Path(__file__).resolve().parents[1]
|
||||
with tempfile.TemporaryDirectory(prefix="af-click-gap-") as temp:
|
||||
generated = Path(temp) / "data"
|
||||
|
||||
Reference in New Issue
Block a user