feat: add SQLAlchemy database models and tests
Add the data layer for the spending analysis app including models for household members, accounts, categories, transactions, categorization rules, and CSV import mappings. All models use SQLAlchemy 2.0 mapped columns with proper foreign key relationships. Includes db.py with Base class, engine/session factories, and 6 passing tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
112
tests/models/test_models.py
Normal file
112
tests/models/test_models.py
Normal file
@@ -0,0 +1,112 @@
|
||||
import datetime
|
||||
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from src.db import Base
|
||||
from src.models.household import HouseholdMember
|
||||
from src.models.account import Account
|
||||
from src.models.category import Category
|
||||
from src.models.transaction import Transaction
|
||||
from src.models.rule import CategorizationRule
|
||||
from src.models.csv_mapping import CsvMapping
|
||||
|
||||
|
||||
def make_session():
|
||||
engine = create_engine("sqlite:///:memory:")
|
||||
Base.metadata.create_all(engine)
|
||||
return Session(engine)
|
||||
|
||||
|
||||
def test_create_household_member():
|
||||
session = make_session()
|
||||
member = HouseholdMember(name="Andrew", relationship="self")
|
||||
session.add(member)
|
||||
session.commit()
|
||||
assert member.id is not None
|
||||
assert member.name == "Andrew"
|
||||
|
||||
|
||||
def test_create_account_with_owner():
|
||||
session = make_session()
|
||||
member = HouseholdMember(name="Andrew", relationship="self")
|
||||
session.add(member)
|
||||
session.flush()
|
||||
account = Account(
|
||||
name="Chase Freedom",
|
||||
institution="Chase",
|
||||
account_type="credit",
|
||||
owner_id=member.id,
|
||||
)
|
||||
session.add(account)
|
||||
session.commit()
|
||||
assert account.owner.name == "Andrew"
|
||||
|
||||
|
||||
def test_create_category():
|
||||
session = make_session()
|
||||
cat = Category(name="Groceries", default_tag="needs")
|
||||
session.add(cat)
|
||||
session.commit()
|
||||
assert cat.id is not None
|
||||
|
||||
|
||||
def test_create_transaction():
|
||||
session = make_session()
|
||||
member = HouseholdMember(name="Andrew", relationship="self")
|
||||
session.add(member)
|
||||
session.flush()
|
||||
account = Account(name="Checking", institution="Wells Fargo", account_type="checking", owner_id=member.id)
|
||||
cat = Category(name="Groceries", default_tag="needs")
|
||||
session.add_all([account, cat])
|
||||
session.flush()
|
||||
txn = Transaction(
|
||||
date=datetime.date(2026, 1, 15),
|
||||
amount=-48.52,
|
||||
description="WAL-MART #7181",
|
||||
raw_description="PURCHASE AUTHORIZED ON 01/14 WAL-MART #7181 BEAUFORT SC CARD 5360",
|
||||
account_id=account.id,
|
||||
category_id=cat.id,
|
||||
attributed_to_id=member.id,
|
||||
tag="needs",
|
||||
)
|
||||
session.add(txn)
|
||||
session.commit()
|
||||
assert txn.id is not None
|
||||
assert txn.account.name == "Checking"
|
||||
assert txn.category.name == "Groceries"
|
||||
|
||||
|
||||
def test_create_categorization_rule():
|
||||
session = make_session()
|
||||
cat = Category(name="Groceries", default_tag="needs")
|
||||
session.add(cat)
|
||||
session.flush()
|
||||
rule = CategorizationRule(
|
||||
pattern="WAL-MART",
|
||||
category_id=cat.id,
|
||||
priority=10,
|
||||
)
|
||||
session.add(rule)
|
||||
session.commit()
|
||||
assert rule.id is not None
|
||||
|
||||
|
||||
def test_create_csv_mapping():
|
||||
session = make_session()
|
||||
member = HouseholdMember(name="Andrew", relationship="self")
|
||||
session.add(member)
|
||||
session.flush()
|
||||
account = Account(name="Chase", institution="Chase", account_type="credit", owner_id=member.id)
|
||||
session.add(account)
|
||||
session.flush()
|
||||
mapping = CsvMapping(
|
||||
name="Chase Credit Card",
|
||||
fingerprint="Transaction Date,Post Date,Description,Category,Type,Amount,Memo",
|
||||
column_map='{"date": "Transaction Date", "amount": "Amount", "description": "Description"}',
|
||||
amount_logic="signed",
|
||||
account_id=account.id,
|
||||
)
|
||||
session.add(mapping)
|
||||
session.commit()
|
||||
assert mapping.id is not None
|
||||
Reference in New Issue
Block a user