Add lock files for package management and update architecture documentation
- Introduced bun.lock and package-lock.json to manage dependencies for the project. - Enhanced backend API architecture documentation with additional security and documentation guidelines. - Made minor formatting adjustments across various files for consistency and clarity.
This commit is contained in:
@@ -12,14 +12,14 @@ export class AssetRepository {
|
||||
|
||||
async findByIdAndUser(id: string, userId: string): Promise<Asset | null> {
|
||||
return prisma.asset.findFirst({
|
||||
where: {id, userId},
|
||||
where: {id, userId}
|
||||
});
|
||||
}
|
||||
|
||||
async findAllByUser(userId: string, filters?: Record<string, any>): Promise<Asset[]> {
|
||||
return prisma.asset.findMany({
|
||||
where: {userId, ...filters},
|
||||
orderBy: {createdAt: 'desc'},
|
||||
orderBy: {createdAt: 'desc'}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ export class AssetRepository {
|
||||
async update(id: string, data: Prisma.AssetUpdateInput): Promise<Asset> {
|
||||
return prisma.asset.update({
|
||||
where: {id},
|
||||
data,
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ export class AssetRepository {
|
||||
async getTotalValue(userId: string): Promise<number> {
|
||||
const result = await prisma.asset.aggregate({
|
||||
where: {userId},
|
||||
_sum: {value: true},
|
||||
_sum: {value: true}
|
||||
});
|
||||
return result._sum.value || 0;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ export class IncomeSourceRepository {
|
||||
async findAllByUser(userId: string): Promise<IncomeSource[]> {
|
||||
return prisma.incomeSource.findMany({
|
||||
where: {userId},
|
||||
orderBy: {createdAt: 'desc'},
|
||||
orderBy: {createdAt: 'desc'}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ export class IncomeSourceRepository {
|
||||
async getTotalMonthlyIncome(userId: string): Promise<number> {
|
||||
const result = await prisma.incomeSource.aggregate({
|
||||
where: {userId},
|
||||
_sum: {amount: true},
|
||||
_sum: {amount: true}
|
||||
});
|
||||
return result._sum.amount || 0;
|
||||
}
|
||||
@@ -58,7 +58,7 @@ export class ExpenseRepository {
|
||||
async findAllByUser(userId: string): Promise<Expense[]> {
|
||||
return prisma.expense.findMany({
|
||||
where: {userId},
|
||||
orderBy: {createdAt: 'desc'},
|
||||
orderBy: {createdAt: 'desc'}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -77,18 +77,21 @@ export class ExpenseRepository {
|
||||
async getTotalMonthlyExpenses(userId: string): Promise<number> {
|
||||
const result = await prisma.expense.aggregate({
|
||||
where: {userId},
|
||||
_sum: {amount: true},
|
||||
_sum: {amount: true}
|
||||
});
|
||||
return result._sum.amount || 0;
|
||||
}
|
||||
|
||||
async getByCategory(userId: string): Promise<Record<string, Expense[]>> {
|
||||
const expenses = await this.findAllByUser(userId);
|
||||
return expenses.reduce((acc, expense) => {
|
||||
if (!acc[expense.category]) acc[expense.category] = [];
|
||||
acc[expense.category].push(expense);
|
||||
return acc;
|
||||
}, {} as Record<string, Expense[]>);
|
||||
return expenses.reduce(
|
||||
(acc, expense) => {
|
||||
if (!acc[expense.category]) acc[expense.category] = [];
|
||||
acc[expense.category].push(expense);
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, Expense[]>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +110,7 @@ export class TransactionRepository {
|
||||
async findAllByUser(userId: string): Promise<Transaction[]> {
|
||||
return prisma.transaction.findMany({
|
||||
where: {userId},
|
||||
orderBy: {date: 'desc'},
|
||||
orderBy: {date: 'desc'}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -127,38 +130,38 @@ export class TransactionRepository {
|
||||
return prisma.transaction.findMany({
|
||||
where: {
|
||||
userId,
|
||||
date: {gte: startDate, lte: endDate},
|
||||
date: {gte: startDate, lte: endDate}
|
||||
},
|
||||
orderBy: {date: 'desc'},
|
||||
orderBy: {date: 'desc'}
|
||||
});
|
||||
}
|
||||
|
||||
async getByType(userId: string, type: string): Promise<Transaction[]> {
|
||||
return prisma.transaction.findMany({
|
||||
where: {userId, type},
|
||||
orderBy: {date: 'desc'},
|
||||
orderBy: {date: 'desc'}
|
||||
});
|
||||
}
|
||||
|
||||
async getCashflowSummary(userId: string, startDate: Date, endDate: Date): Promise<{
|
||||
async getCashflowSummary(
|
||||
userId: string,
|
||||
startDate: Date,
|
||||
endDate: Date
|
||||
): Promise<{
|
||||
totalIncome: number;
|
||||
totalExpenses: number;
|
||||
netCashflow: number;
|
||||
}> {
|
||||
const transactions = await this.getByDateRange(userId, startDate, endDate);
|
||||
|
||||
const totalIncome = transactions
|
||||
.filter(t => t.type === 'income')
|
||||
.reduce((sum, t) => sum + t.amount, 0);
|
||||
const totalIncome = transactions.filter(t => t.type === 'income').reduce((sum, t) => sum + t.amount, 0);
|
||||
|
||||
const totalExpenses = transactions
|
||||
.filter(t => t.type === 'expense')
|
||||
.reduce((sum, t) => sum + t.amount, 0);
|
||||
const totalExpenses = transactions.filter(t => t.type === 'expense').reduce((sum, t) => sum + t.amount, 0);
|
||||
|
||||
return {
|
||||
totalIncome,
|
||||
totalExpenses,
|
||||
netCashflow: totalIncome - totalExpenses,
|
||||
netCashflow: totalIncome - totalExpenses
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@ export class ClientRepository {
|
||||
return prisma.client.findUnique({
|
||||
where: {id},
|
||||
include: {
|
||||
invoices: true,
|
||||
},
|
||||
invoices: true
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ export class ClientRepository {
|
||||
return prisma.client.findFirst({
|
||||
where: {id, userId},
|
||||
include: {
|
||||
invoices: true,
|
||||
},
|
||||
invoices: true
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -31,10 +31,10 @@ export class ClientRepository {
|
||||
where: {userId},
|
||||
include: {
|
||||
invoices: {
|
||||
orderBy: {createdAt: 'desc'},
|
||||
},
|
||||
orderBy: {createdAt: 'desc'}
|
||||
}
|
||||
},
|
||||
orderBy: {createdAt: 'desc'},
|
||||
orderBy: {createdAt: 'desc'}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -42,8 +42,8 @@ export class ClientRepository {
|
||||
return prisma.client.create({
|
||||
data,
|
||||
include: {
|
||||
invoices: true,
|
||||
},
|
||||
invoices: true
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -52,14 +52,14 @@ export class ClientRepository {
|
||||
where: {id},
|
||||
data,
|
||||
include: {
|
||||
invoices: true,
|
||||
},
|
||||
invoices: true
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async delete(id: string): Promise<void> {
|
||||
await prisma.client.delete({
|
||||
where: {id},
|
||||
where: {id}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -70,8 +70,8 @@ export class ClientRepository {
|
||||
return prisma.client.findFirst({
|
||||
where: {
|
||||
userId,
|
||||
email,
|
||||
},
|
||||
email
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -82,13 +82,13 @@ export class ClientRepository {
|
||||
const result = await prisma.invoice.aggregate({
|
||||
where: {
|
||||
client: {
|
||||
userId,
|
||||
userId
|
||||
},
|
||||
status: 'paid',
|
||||
status: 'paid'
|
||||
},
|
||||
_sum: {
|
||||
total: true,
|
||||
},
|
||||
total: true
|
||||
}
|
||||
});
|
||||
|
||||
return result._sum.total || 0;
|
||||
@@ -105,11 +105,11 @@ export class ClientRepository {
|
||||
select: {
|
||||
id: true,
|
||||
total: true,
|
||||
status: true,
|
||||
},
|
||||
},
|
||||
status: true
|
||||
}
|
||||
}
|
||||
},
|
||||
orderBy: {createdAt: 'desc'},
|
||||
orderBy: {createdAt: 'desc'}
|
||||
});
|
||||
|
||||
return clients.map(client => ({
|
||||
@@ -117,13 +117,9 @@ export class ClientRepository {
|
||||
stats: {
|
||||
totalInvoices: client.invoices.length,
|
||||
paidInvoices: client.invoices.filter(inv => inv.status === 'paid').length,
|
||||
totalRevenue: client.invoices
|
||||
.filter(inv => inv.status === 'paid')
|
||||
.reduce((sum, inv) => sum + inv.total, 0),
|
||||
outstandingAmount: client.invoices
|
||||
.filter(inv => inv.status !== 'paid')
|
||||
.reduce((sum, inv) => sum + inv.total, 0),
|
||||
},
|
||||
totalRevenue: client.invoices.filter(inv => inv.status === 'paid').reduce((sum, inv) => sum + inv.total, 0),
|
||||
outstandingAmount: client.invoices.filter(inv => inv.status !== 'paid').reduce((sum, inv) => sum + inv.total, 0)
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,9 +14,9 @@ export class DebtAccountRepository {
|
||||
include: {
|
||||
category: true,
|
||||
payments: {
|
||||
orderBy: {date: 'desc'},
|
||||
},
|
||||
},
|
||||
orderBy: {date: 'desc'}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -26,9 +26,9 @@ export class DebtAccountRepository {
|
||||
include: {
|
||||
category: true,
|
||||
payments: {
|
||||
orderBy: {date: 'desc'},
|
||||
},
|
||||
},
|
||||
orderBy: {date: 'desc'}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -38,10 +38,10 @@ export class DebtAccountRepository {
|
||||
include: {
|
||||
category: true,
|
||||
payments: {
|
||||
orderBy: {date: 'desc'},
|
||||
},
|
||||
orderBy: {date: 'desc'}
|
||||
}
|
||||
},
|
||||
orderBy: {createdAt: 'desc'},
|
||||
orderBy: {createdAt: 'desc'}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -50,10 +50,10 @@ export class DebtAccountRepository {
|
||||
where: {categoryId},
|
||||
include: {
|
||||
payments: {
|
||||
orderBy: {date: 'desc'},
|
||||
},
|
||||
orderBy: {date: 'desc'}
|
||||
}
|
||||
},
|
||||
orderBy: {createdAt: 'desc'},
|
||||
orderBy: {createdAt: 'desc'}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -62,8 +62,8 @@ export class DebtAccountRepository {
|
||||
data,
|
||||
include: {
|
||||
category: true,
|
||||
payments: true,
|
||||
},
|
||||
payments: true
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -73,14 +73,14 @@ export class DebtAccountRepository {
|
||||
data,
|
||||
include: {
|
||||
category: true,
|
||||
payments: true,
|
||||
},
|
||||
payments: true
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async delete(id: string): Promise<void> {
|
||||
await prisma.debtAccount.delete({
|
||||
where: {id},
|
||||
where: {id}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -91,8 +91,8 @@ export class DebtAccountRepository {
|
||||
const result = await prisma.debtAccount.aggregate({
|
||||
where: {userId},
|
||||
_sum: {
|
||||
currentBalance: true,
|
||||
},
|
||||
currentBalance: true
|
||||
}
|
||||
});
|
||||
|
||||
return result._sum.currentBalance || 0;
|
||||
@@ -107,9 +107,9 @@ export class DebtAccountRepository {
|
||||
include: {
|
||||
category: true,
|
||||
payments: {
|
||||
orderBy: {date: 'desc'},
|
||||
},
|
||||
},
|
||||
orderBy: {date: 'desc'}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return accounts.map(account => {
|
||||
@@ -122,8 +122,8 @@ export class DebtAccountRepository {
|
||||
totalPaid,
|
||||
numberOfPayments: account.payments.length,
|
||||
lastPaymentDate: lastPayment?.date || null,
|
||||
lastPaymentAmount: lastPayment?.amount || null,
|
||||
},
|
||||
lastPaymentAmount: lastPayment?.amount || null
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -15,10 +15,10 @@ export class DebtCategoryRepository implements IUserScopedRepository<DebtCategor
|
||||
include: {
|
||||
accounts: {
|
||||
include: {
|
||||
payments: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
payments: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -28,12 +28,12 @@ export class DebtCategoryRepository implements IUserScopedRepository<DebtCategor
|
||||
include: {
|
||||
accounts: {
|
||||
include: {
|
||||
payments: true,
|
||||
payments: true
|
||||
},
|
||||
orderBy: {createdAt: 'desc'},
|
||||
},
|
||||
orderBy: {createdAt: 'desc'}
|
||||
}
|
||||
},
|
||||
orderBy: {createdAt: 'desc'},
|
||||
orderBy: {createdAt: 'desc'}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -41,8 +41,8 @@ export class DebtCategoryRepository implements IUserScopedRepository<DebtCategor
|
||||
return prisma.debtCategory.create({
|
||||
data,
|
||||
include: {
|
||||
accounts: true,
|
||||
},
|
||||
accounts: true
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -51,14 +51,14 @@ export class DebtCategoryRepository implements IUserScopedRepository<DebtCategor
|
||||
where: {id},
|
||||
data,
|
||||
include: {
|
||||
accounts: true,
|
||||
},
|
||||
accounts: true
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async delete(id: string): Promise<void> {
|
||||
await prisma.debtCategory.delete({
|
||||
where: {id},
|
||||
where: {id}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -69,8 +69,8 @@ export class DebtCategoryRepository implements IUserScopedRepository<DebtCategor
|
||||
return prisma.debtCategory.findFirst({
|
||||
where: {
|
||||
userId,
|
||||
name,
|
||||
},
|
||||
name
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -81,8 +81,8 @@ export class DebtCategoryRepository implements IUserScopedRepository<DebtCategor
|
||||
const result = await prisma.debtAccount.aggregate({
|
||||
where: {categoryId},
|
||||
_sum: {
|
||||
currentBalance: true,
|
||||
},
|
||||
currentBalance: true
|
||||
}
|
||||
});
|
||||
|
||||
return result._sum.currentBalance || 0;
|
||||
@@ -97,19 +97,15 @@ export class DebtCategoryRepository implements IUserScopedRepository<DebtCategor
|
||||
return Promise.all(
|
||||
categories.map(async category => {
|
||||
const totalDebt = await this.getTotalDebt(category.id);
|
||||
const totalPayments = category.accounts.reduce(
|
||||
(sum, account) =>
|
||||
sum + account.payments.reduce((pSum, payment) => pSum + payment.amount, 0),
|
||||
0
|
||||
);
|
||||
const totalPayments = category.accounts.reduce((sum, account) => sum + account.payments.reduce((pSum, payment) => pSum + payment.amount, 0), 0);
|
||||
|
||||
return {
|
||||
...category,
|
||||
stats: {
|
||||
totalAccounts: category.accounts.length,
|
||||
totalDebt,
|
||||
totalPayments,
|
||||
},
|
||||
totalPayments
|
||||
}
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
@@ -14,17 +14,17 @@ export class DebtPaymentRepository {
|
||||
include: {
|
||||
account: {
|
||||
include: {
|
||||
category: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
category: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async findByAccount(accountId: string): Promise<DebtPayment[]> {
|
||||
return prisma.debtPayment.findMany({
|
||||
where: {accountId},
|
||||
orderBy: {date: 'desc'},
|
||||
orderBy: {date: 'desc'}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -33,18 +33,18 @@ export class DebtPaymentRepository {
|
||||
where: {
|
||||
account: {
|
||||
category: {
|
||||
userId,
|
||||
},
|
||||
},
|
||||
userId
|
||||
}
|
||||
}
|
||||
},
|
||||
include: {
|
||||
account: {
|
||||
include: {
|
||||
category: true,
|
||||
},
|
||||
},
|
||||
category: true
|
||||
}
|
||||
}
|
||||
},
|
||||
orderBy: {date: 'desc'},
|
||||
orderBy: {date: 'desc'}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -54,16 +54,16 @@ export class DebtPaymentRepository {
|
||||
include: {
|
||||
account: {
|
||||
include: {
|
||||
category: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
category: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async delete(id: string): Promise<void> {
|
||||
await prisma.debtPayment.delete({
|
||||
where: {id},
|
||||
where: {id}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -74,8 +74,8 @@ export class DebtPaymentRepository {
|
||||
const result = await prisma.debtPayment.aggregate({
|
||||
where: {accountId},
|
||||
_sum: {
|
||||
amount: true,
|
||||
},
|
||||
amount: true
|
||||
}
|
||||
});
|
||||
|
||||
return result._sum.amount || 0;
|
||||
@@ -89,13 +89,13 @@ export class DebtPaymentRepository {
|
||||
where: {
|
||||
account: {
|
||||
category: {
|
||||
userId,
|
||||
},
|
||||
},
|
||||
userId
|
||||
}
|
||||
}
|
||||
},
|
||||
_sum: {
|
||||
amount: true,
|
||||
},
|
||||
amount: true
|
||||
}
|
||||
});
|
||||
|
||||
return result._sum.amount || 0;
|
||||
@@ -109,22 +109,22 @@ export class DebtPaymentRepository {
|
||||
where: {
|
||||
account: {
|
||||
category: {
|
||||
userId,
|
||||
},
|
||||
userId
|
||||
}
|
||||
},
|
||||
date: {
|
||||
gte: startDate,
|
||||
lte: endDate,
|
||||
},
|
||||
lte: endDate
|
||||
}
|
||||
},
|
||||
include: {
|
||||
account: {
|
||||
include: {
|
||||
category: true,
|
||||
},
|
||||
},
|
||||
category: true
|
||||
}
|
||||
}
|
||||
},
|
||||
orderBy: {date: 'desc'},
|
||||
orderBy: {date: 'desc'}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,14 +15,14 @@ export class InvoiceRepository implements IUserScopedRepository<Invoice> {
|
||||
async findById(id: string): Promise<Invoice | null> {
|
||||
return prisma.invoice.findUnique({
|
||||
where: {id},
|
||||
include: {lineItems: true, client: true},
|
||||
include: {lineItems: true, client: true}
|
||||
}) as unknown as Invoice;
|
||||
}
|
||||
|
||||
async findByIdAndUser(id: string, userId: string): Promise<InvoiceWithLineItems | null> {
|
||||
return prisma.invoice.findFirst({
|
||||
where: {id, userId},
|
||||
include: {lineItems: true, client: true},
|
||||
include: {lineItems: true, client: true}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -30,14 +30,14 @@ export class InvoiceRepository implements IUserScopedRepository<Invoice> {
|
||||
return prisma.invoice.findMany({
|
||||
where: {userId, ...filters},
|
||||
include: {lineItems: true, client: true},
|
||||
orderBy: {createdAt: 'desc'},
|
||||
orderBy: {createdAt: 'desc'}
|
||||
});
|
||||
}
|
||||
|
||||
async create(data: Prisma.InvoiceCreateInput): Promise<Invoice> {
|
||||
return prisma.invoice.create({
|
||||
data,
|
||||
include: {lineItems: true, client: true},
|
||||
include: {lineItems: true, client: true}
|
||||
}) as unknown as Invoice;
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ export class InvoiceRepository implements IUserScopedRepository<Invoice> {
|
||||
return prisma.invoice.update({
|
||||
where: {id},
|
||||
data,
|
||||
include: {lineItems: true, client: true},
|
||||
include: {lineItems: true, client: true}
|
||||
}) as unknown as Invoice;
|
||||
}
|
||||
|
||||
@@ -58,8 +58,8 @@ export class InvoiceRepository implements IUserScopedRepository<Invoice> {
|
||||
where: {
|
||||
userId,
|
||||
invoiceNumber,
|
||||
...(excludeId && {id: {not: excludeId}}),
|
||||
},
|
||||
...(excludeId && {id: {not: excludeId}})
|
||||
}
|
||||
});
|
||||
return count > 0;
|
||||
}
|
||||
@@ -69,8 +69,8 @@ export class InvoiceRepository implements IUserScopedRepository<Invoice> {
|
||||
const count = await prisma.invoice.count({
|
||||
where: {
|
||||
userId,
|
||||
invoiceNumber: {startsWith: `INV-${year}-`},
|
||||
},
|
||||
invoiceNumber: {startsWith: `INV-${year}-`}
|
||||
}
|
||||
});
|
||||
return `INV-${year}-${String(count + 1).padStart(3, '0')}`;
|
||||
}
|
||||
|
||||
@@ -10,39 +10,39 @@ const prisma = DatabaseConnection.getInstance();
|
||||
export class LiabilityRepository {
|
||||
async findById(id: string): Promise<Liability | null> {
|
||||
return prisma.liability.findUnique({
|
||||
where: {id},
|
||||
where: {id}
|
||||
});
|
||||
}
|
||||
|
||||
async findByIdAndUser(id: string, userId: string): Promise<Liability | null> {
|
||||
return prisma.liability.findFirst({
|
||||
where: {id, userId},
|
||||
where: {id, userId}
|
||||
});
|
||||
}
|
||||
|
||||
async findAllByUser(userId: string): Promise<Liability[]> {
|
||||
return prisma.liability.findMany({
|
||||
where: {userId},
|
||||
orderBy: {createdAt: 'desc'},
|
||||
orderBy: {createdAt: 'desc'}
|
||||
});
|
||||
}
|
||||
|
||||
async create(data: Prisma.LiabilityCreateInput): Promise<Liability> {
|
||||
return prisma.liability.create({
|
||||
data,
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
async update(id: string, data: Prisma.LiabilityUpdateInput): Promise<Liability> {
|
||||
return prisma.liability.update({
|
||||
where: {id},
|
||||
data,
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
async delete(id: string): Promise<void> {
|
||||
await prisma.liability.delete({
|
||||
where: {id},
|
||||
where: {id}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -53,8 +53,8 @@ export class LiabilityRepository {
|
||||
const result = await prisma.liability.aggregate({
|
||||
where: {userId},
|
||||
_sum: {
|
||||
balance: true,
|
||||
},
|
||||
balance: true
|
||||
}
|
||||
});
|
||||
|
||||
return result._sum.balance || 0;
|
||||
@@ -66,13 +66,16 @@ export class LiabilityRepository {
|
||||
async getByType(userId: string): Promise<Record<string, Liability[]>> {
|
||||
const liabilities = await this.findAllByUser(userId);
|
||||
|
||||
return liabilities.reduce((acc, liability) => {
|
||||
const type = liability.type;
|
||||
if (!acc[type]) {
|
||||
acc[type] = [];
|
||||
}
|
||||
acc[type].push(liability);
|
||||
return acc;
|
||||
}, {} as Record<string, Liability[]>);
|
||||
return liabilities.reduce(
|
||||
(acc, liability) => {
|
||||
const type = liability.type;
|
||||
if (!acc[type]) {
|
||||
acc[type] = [];
|
||||
}
|
||||
acc[type].push(liability);
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, Liability[]>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,33 +11,33 @@ const prisma = DatabaseConnection.getInstance();
|
||||
export class NetWorthSnapshotRepository implements IUserScopedRepository<NetWorthSnapshot> {
|
||||
async findById(id: string): Promise<NetWorthSnapshot | null> {
|
||||
return prisma.netWorthSnapshot.findUnique({
|
||||
where: {id},
|
||||
where: {id}
|
||||
});
|
||||
}
|
||||
|
||||
async findAllByUser(userId: string): Promise<NetWorthSnapshot[]> {
|
||||
return prisma.netWorthSnapshot.findMany({
|
||||
where: {userId},
|
||||
orderBy: {date: 'desc'},
|
||||
orderBy: {date: 'desc'}
|
||||
});
|
||||
}
|
||||
|
||||
async create(data: Prisma.NetWorthSnapshotCreateInput): Promise<NetWorthSnapshot> {
|
||||
return prisma.netWorthSnapshot.create({
|
||||
data,
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
async update(id: string, data: Prisma.NetWorthSnapshotUpdateInput): Promise<NetWorthSnapshot> {
|
||||
return prisma.netWorthSnapshot.update({
|
||||
where: {id},
|
||||
data,
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
async delete(id: string): Promise<void> {
|
||||
await prisma.netWorthSnapshot.delete({
|
||||
where: {id},
|
||||
where: {id}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ export class NetWorthSnapshotRepository implements IUserScopedRepository<NetWort
|
||||
async getLatest(userId: string): Promise<NetWorthSnapshot | null> {
|
||||
return prisma.netWorthSnapshot.findFirst({
|
||||
where: {userId},
|
||||
orderBy: {date: 'desc'},
|
||||
orderBy: {date: 'desc'}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -60,10 +60,10 @@ export class NetWorthSnapshotRepository implements IUserScopedRepository<NetWort
|
||||
userId,
|
||||
date: {
|
||||
gte: startDate,
|
||||
lte: endDate,
|
||||
},
|
||||
lte: endDate
|
||||
}
|
||||
},
|
||||
orderBy: {date: 'asc'},
|
||||
orderBy: {date: 'asc'}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -74,8 +74,8 @@ export class NetWorthSnapshotRepository implements IUserScopedRepository<NetWort
|
||||
const count = await prisma.netWorthSnapshot.count({
|
||||
where: {
|
||||
userId,
|
||||
date,
|
||||
},
|
||||
date
|
||||
}
|
||||
});
|
||||
|
||||
return count > 0;
|
||||
@@ -88,7 +88,7 @@ export class NetWorthSnapshotRepository implements IUserScopedRepository<NetWort
|
||||
const snapshots = await prisma.netWorthSnapshot.findMany({
|
||||
where: {userId},
|
||||
orderBy: {date: 'desc'},
|
||||
take: limit,
|
||||
take: limit
|
||||
});
|
||||
|
||||
const stats = [];
|
||||
@@ -96,14 +96,13 @@ export class NetWorthSnapshotRepository implements IUserScopedRepository<NetWort
|
||||
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;
|
||||
const growthPercent = previous.netWorth !== 0 ? (growthAmount / previous.netWorth) * 100 : 0;
|
||||
|
||||
stats.push({
|
||||
date: current.date,
|
||||
netWorth: current.netWorth,
|
||||
growthAmount,
|
||||
growthPercent: parseFloat(growthPercent.toFixed(2)),
|
||||
growthPercent: parseFloat(growthPercent.toFixed(2))
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -24,8 +24,8 @@ export class UserRepository implements IRepository<User> {
|
||||
name: true,
|
||||
createdAt: true,
|
||||
updatedAt: true,
|
||||
password: false, // Never return password
|
||||
},
|
||||
password: false // Never return password
|
||||
}
|
||||
}) as unknown as User[];
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ export class UserRepository implements IRepository<User> {
|
||||
async update(id: string, data: Prisma.UserUpdateInput): Promise<User> {
|
||||
return prisma.user.update({
|
||||
where: {id},
|
||||
data,
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,7 @@ export interface IRepository<T, CreateInput = unknown, UpdateInput = unknown> {
|
||||
* User-scoped repository interface
|
||||
* For entities that belong to a specific user
|
||||
*/
|
||||
export interface IUserScopedRepository<T, CreateInput = unknown, UpdateInput = unknown>
|
||||
extends Omit<IRepository<T, CreateInput, UpdateInput>, 'findAll'> {
|
||||
export interface IUserScopedRepository<T, CreateInput = unknown, UpdateInput = unknown> extends Omit<IRepository<T, CreateInput, UpdateInput>, 'findAll'> {
|
||||
findAllByUser(userId: string, filters?: Record<string, unknown>): Promise<T[]>;
|
||||
findByIdAndUser(id: string, userId: string): Promise<T | null>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user