Files
dash-flutter/scripts/seed_dummy_data.py
2026-05-12 10:12:50 -04:00

209 lines
5.7 KiB
Python

#!/usr/bin/env python3
"""Seed the Dash SQLite database with demo garage data.
Usage:
python scripts/seed_dummy_data.py "C:\\path\\to\\cars_sqlite.db"
python scripts/seed_dummy_data.py --reset "C:\\path\\to\\cars_sqlite.db"
If no database path is provided, the script writes to ./cars_sqlite.db.
Use the "sqlite db path:" line printed by the app for the active Windows DB.
"""
from __future__ import annotations
import argparse
import sqlite3
from datetime import datetime, timedelta
from pathlib import Path
CARS = [
{
"vin": "1HGBH41JXMN109186",
"nickname": "Civic Commuter",
"plate": "DASH-101",
"mileage": 84250,
"icon": "images/car_icons/honda.png",
},
{
"vin": "5YJ3E1EA7KF317000",
"nickname": "Model 3",
"plate": "EV-2026",
"mileage": 36640,
"icon": "images/car_icons/tesla.png",
},
{
"vin": "1FTFW1E50NFA00042",
"nickname": "Weekend Truck",
"plate": "HAUL-42",
"mileage": 58910,
"icon": "images/car_icons/ford.png",
},
{
"vin": "WBA8E9G52JNU12345",
"nickname": "Blue Sedan",
"plate": "BLUE-5",
"mileage": 72115,
"icon": "images/car_icons/bmw.png",
},
]
TXN_TEMPLATES = [
("Fuel", 46.82, 120, "Filled tank"),
("Oil Change", 78.40, 420, "Synthetic oil and filter"),
("Tire Rotation", 34.99, 960, "Rotated tires"),
("Repair", 312.65, 1410, "Replaced worn brake pads"),
("Registration", 128.00, 1850, "Annual registration renewal"),
("Wash", 18.00, 2020, "Exterior wash"),
("Insurance", 146.25, 2350, "Monthly premium"),
]
def create_schema(conn: sqlite3.Connection) -> None:
conn.executescript(
"""
PRAGMA foreign_keys=ON;
CREATE TABLE IF NOT EXISTS cars (
id INTEGER PRIMARY KEY,
vin TEXT UNIQUE,
nickname TEXT,
mileage INTEGER,
plate TEXT,
icon TEXT
);
CREATE TABLE IF NOT EXISTS txns (
id INTEGER PRIMARY KEY,
txntype TEXT,
datetime INTEGER,
cost REAL,
mileage INTEGER,
note TEXT,
carid INTEGER,
FOREIGN KEY(carid) REFERENCES cars(id)
);
PRAGMA user_version=1;
"""
)
def table_columns(conn: sqlite3.Connection, table_name: str) -> set[str]:
return {row[1] for row in conn.execute(f"PRAGMA table_info({table_name})")}
def reset_data(conn: sqlite3.Connection) -> None:
conn.execute("DELETE FROM txns")
conn.execute("DELETE FROM cars")
def seed(conn: sqlite3.Connection) -> tuple[int, int]:
car_count = 0
txn_count = 0
today = datetime.now().replace(hour=9, minute=0, second=0, microsecond=0)
car_columns = table_columns(conn, "cars")
has_icon_column = "icon" in car_columns
for car_index, car in enumerate(CARS):
if has_icon_column:
cursor = conn.execute(
"""
INSERT OR IGNORE INTO cars (vin, nickname, mileage, plate, icon)
VALUES (?, ?, ?, ?, ?)
""",
(
car["vin"],
car["nickname"],
car["mileage"],
car["plate"],
car["icon"],
),
)
else:
cursor = conn.execute(
"""
INSERT OR IGNORE INTO cars (vin, nickname, mileage, plate)
VALUES (?, ?, ?, ?)
""",
(
car["vin"],
car["nickname"],
car["mileage"],
car["plate"],
),
)
if cursor.rowcount:
car_count += 1
car_id = conn.execute(
"SELECT id FROM cars WHERE vin = ?",
(car["vin"],),
).fetchone()[0]
existing_txns = conn.execute(
"SELECT COUNT(*) FROM txns WHERE carid = ?",
(car_id,),
).fetchone()[0]
if existing_txns:
continue
base_mileage = int(car["mileage"]) - 3000
for txn_index, (txntype, cost, miles_after, note) in enumerate(TXN_TEMPLATES):
when = today - timedelta(days=(txn_index * 24) + (car_index * 5))
conn.execute(
"""
INSERT INTO txns (txntype, datetime, cost, mileage, note, carid)
VALUES (?, ?, ?, ?, ?, ?)
""",
(
txntype,
int(when.timestamp()),
cost + (car_index * 7.5),
base_mileage + miles_after,
note,
car_id,
),
)
txn_count += 1
return car_count, txn_count
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Seed cars_sqlite.db with demo data for Dash screenshots."
)
parser.add_argument(
"db_path",
nargs="?",
default="cars_sqlite.db",
help="Path to cars_sqlite.db. Defaults to ./cars_sqlite.db.",
)
parser.add_argument(
"--reset",
action="store_true",
help="Delete existing cars and transactions before inserting demo data.",
)
return parser.parse_args()
def main() -> None:
args = parse_args()
db_path = Path(args.db_path).expanduser().resolve()
db_path.parent.mkdir(parents=True, exist_ok=True)
with sqlite3.connect(db_path) as conn:
create_schema(conn)
if args.reset:
reset_data(conn)
car_count, txn_count = seed(conn)
conn.commit()
print(f"Seeded {db_path}")
print(f"Inserted {car_count} cars and {txn_count} transactions")
if __name__ == "__main__":
main()