Migrate transactions to SQLite (self-contained, on the volume)
- txns_db.py: SQLite store with the same list-of-dicts shape, ACID writes (no corruption / no lost-update race), indexes, and a fast unreviewed COUNT. - app.py: get_transactions/save_transactions delegate to txns_db; one-time idempotent migration from transactions.json on startup (JSON kept as backup); nav badge uses count_unreviewed() instead of parsing the whole store (#33). - Verified against the live 265-row dataset: counts, fields, splits, mutation. - Other small JSON files intentionally stay JSON. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
17
app.py
17
app.py
@@ -7,6 +7,7 @@ from datetime import datetime, date
|
||||
import calendar as cal_module
|
||||
from storage import load_json, save_json
|
||||
from settings import load_settings, save_settings, SECRET_KEYS
|
||||
import txns_db
|
||||
from categories import CATEGORIES, CATEGORY_COLORS
|
||||
from bills import load_bills, save_bills, bills_for_month, calendar_grid, get_week_num
|
||||
from sinking import (load_funds, save_funds, FUND_COLORS, monthly_needed,
|
||||
@@ -163,9 +164,8 @@ def compute_tax_estimate(gross_income, rates, se_income=None):
|
||||
|
||||
@app.context_processor
|
||||
def inject_unreviewed_count():
|
||||
transactions = get_transactions()
|
||||
count = sum(1 for t in transactions if not t.get("reviewed"))
|
||||
return dict(unreviewed_count=count)
|
||||
# Fast COUNT query instead of parsing the whole transaction store per request.
|
||||
return dict(unreviewed_count=txns_db.count_unreviewed())
|
||||
|
||||
DATA_DIR = os.environ.get("DATA_DIR", os.path.join(os.path.dirname(__file__), "data"))
|
||||
TRANSACTIONS_FILE = os.path.join(DATA_DIR, "transactions.json")
|
||||
@@ -173,6 +173,13 @@ RULES_FILE = os.path.join(DATA_DIR, "rules.json")
|
||||
BUDGET_FILE = os.path.join(DATA_DIR, "budget.json")
|
||||
NET_WORTH_FILE = os.path.join(DATA_DIR, "net_worth_accounts.json")
|
||||
|
||||
# Transactions live in SQLite (self-contained, on the volume). On first run this
|
||||
# imports any existing transactions.json; it's a no-op once the DB has rows.
|
||||
txns_db.init_db()
|
||||
_migrated = txns_db.migrate_from_json(TRANSACTIONS_FILE)
|
||||
if _migrated:
|
||||
print(f"[startup] migrated {_migrated} transactions from JSON -> SQLite")
|
||||
|
||||
|
||||
def load_nw_accounts():
|
||||
return load_json(NET_WORTH_FILE, [])
|
||||
@@ -183,11 +190,11 @@ def save_nw_accounts(accounts):
|
||||
|
||||
|
||||
def get_transactions():
|
||||
return load_json(TRANSACTIONS_FILE, [])
|
||||
return txns_db.get_transactions()
|
||||
|
||||
|
||||
def save_transactions(transactions):
|
||||
save_json(TRANSACTIONS_FILE, transactions)
|
||||
txns_db.save_transactions(transactions)
|
||||
|
||||
|
||||
def get_rules():
|
||||
|
||||
Reference in New Issue
Block a user