Add backend API for personal finance management application
- Introduced a comprehensive backend API using TypeScript, Fastify, and PostgreSQL. - Added essential files including architecture documentation, environment configuration, and Docker setup. - Implemented RESTful routes for managing assets, liabilities, clients, invoices, and cashflow. - Established a robust database schema with Prisma for data management. - Integrated middleware for authentication and error handling. - Created service and repository layers to adhere to SOLID principles and clean architecture. - Included example environment variables for development, staging, and production setups.
This commit is contained in:
112
backend-api/src/repositories/NetWorthSnapshotRepository.ts
Normal file
112
backend-api/src/repositories/NetWorthSnapshotRepository.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
import {NetWorthSnapshot, Prisma} from '@prisma/client';
|
||||
import {DatabaseConnection} from '../config/database';
|
||||
import {IUserScopedRepository} from './interfaces/IRepository';
|
||||
|
||||
const prisma = DatabaseConnection.getInstance();
|
||||
|
||||
/**
|
||||
* Repository for NetWorthSnapshot data access
|
||||
* Implements Single Responsibility Principle - handles only database operations
|
||||
*/
|
||||
export class NetWorthSnapshotRepository implements IUserScopedRepository<NetWorthSnapshot> {
|
||||
async findById(id: string): Promise<NetWorthSnapshot | null> {
|
||||
return prisma.netWorthSnapshot.findUnique({
|
||||
where: {id},
|
||||
});
|
||||
}
|
||||
|
||||
async findAllByUser(userId: string): Promise<NetWorthSnapshot[]> {
|
||||
return prisma.netWorthSnapshot.findMany({
|
||||
where: {userId},
|
||||
orderBy: {date: 'desc'},
|
||||
});
|
||||
}
|
||||
|
||||
async create(data: Prisma.NetWorthSnapshotCreateInput): Promise<NetWorthSnapshot> {
|
||||
return prisma.netWorthSnapshot.create({
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
async update(id: string, data: Prisma.NetWorthSnapshotUpdateInput): Promise<NetWorthSnapshot> {
|
||||
return prisma.netWorthSnapshot.update({
|
||||
where: {id},
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
async delete(id: string): Promise<void> {
|
||||
await prisma.netWorthSnapshot.delete({
|
||||
where: {id},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the latest snapshot for a user
|
||||
*/
|
||||
async getLatest(userId: string): Promise<NetWorthSnapshot | null> {
|
||||
return prisma.netWorthSnapshot.findFirst({
|
||||
where: {userId},
|
||||
orderBy: {date: 'desc'},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get snapshots within a date range
|
||||
*/
|
||||
async getByDateRange(userId: string, startDate: Date, endDate: Date): Promise<NetWorthSnapshot[]> {
|
||||
return prisma.netWorthSnapshot.findMany({
|
||||
where: {
|
||||
userId,
|
||||
date: {
|
||||
gte: startDate,
|
||||
lte: endDate,
|
||||
},
|
||||
},
|
||||
orderBy: {date: 'asc'},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a snapshot exists for a specific date
|
||||
*/
|
||||
async existsForDate(userId: string, date: Date): Promise<boolean> {
|
||||
const count = await prisma.netWorthSnapshot.count({
|
||||
where: {
|
||||
userId,
|
||||
date,
|
||||
},
|
||||
});
|
||||
|
||||
return count > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get growth over time (percentage change between snapshots)
|
||||
*/
|
||||
async getGrowthStats(userId: string, limit: number = 12): Promise<any[]> {
|
||||
const snapshots = await prisma.netWorthSnapshot.findMany({
|
||||
where: {userId},
|
||||
orderBy: {date: 'desc'},
|
||||
take: limit,
|
||||
});
|
||||
|
||||
const stats = [];
|
||||
for (let i = 0; i < snapshots.length - 1; i++) {
|
||||
const current = snapshots[i];
|
||||
const previous = snapshots[i + 1];
|
||||
const growthAmount = current.netWorth - previous.netWorth;
|
||||
const growthPercent =
|
||||
previous.netWorth !== 0 ? (growthAmount / previous.netWorth) * 100 : 0;
|
||||
|
||||
stats.push({
|
||||
date: current.date,
|
||||
netWorth: current.netWorth,
|
||||
growthAmount,
|
||||
growthPercent: parseFloat(growthPercent.toFixed(2)),
|
||||
});
|
||||
}
|
||||
|
||||
return stats;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user