bups and readme cleanup
This commit is contained in:
208
scripts/seed_dummy_data.py
Normal file
208
scripts/seed_dummy_data.py
Normal file
@@ -0,0 +1,208 @@
|
||||
#!/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()
|
||||
Reference in New Issue
Block a user