Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ _fresh/
node_modules/

sqlite*
.serena
26 changes: 19 additions & 7 deletions db/models/expense.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,8 @@ export default class ExpenseService {
});
}

// TODO make this more atomic. if one fails, all should fail
expensesToUpdate.forEach(async (expense) => {
// Update all expenses atomically - if one fails, all fail
const updatePromises = expensesToUpdate.map(async (expense) => {
const expenseKey = [Keys.EXPENSES, userId, expense.id];
const correlationKey = [
Keys.EXPENSES_BY_CORRELATION,
Expand All @@ -206,15 +206,17 @@ export default class ExpenseService {
expense.id,
];

// keep the original date, only update the day
expense.payment.date.setDate(input.payment.date.getDate());
// keep the original date, only update the day (create new Date to avoid mutation)
const updatedDate = new Date(expense.payment.date);
updatedDate.setDate(input.payment.date.getDate());

const updatedExpense = {
...expense,
...payload,
payment: {
...expense.payment,
...payload.payment,
date: expense.payment.date,
date: updatedDate,
},
};

Expand All @@ -228,8 +230,13 @@ export default class ExpenseService {
if (!res.ok) {
throw new Deno.errors.Interrupted("Failed to update expense");
}

return updatedExpense;
});

// Wait for all updates to complete
await Promise.all(updatePromises);

const updatedExpense = {
...rawExpense.value,
...input,
Expand Down Expand Up @@ -321,8 +328,8 @@ export default class ExpenseService {
(e) => e.payment.date.getMonth() + 1 >= initialMonth,
);
}
// TODO make this more atomic. if one fails, all should fail
expensesToDelete.forEach(async (expense) => {
// Delete all expenses atomically - if one fails, all fail
const deletePromises = expensesToDelete.map(async (expense) => {
const expenseKey = [Keys.EXPENSES, userId, expense.id];
const correlationKey = [
Keys.EXPENSES_BY_CORRELATION,
Expand Down Expand Up @@ -352,8 +359,13 @@ export default class ExpenseService {
`Failed to delete expense. Expense ID: ${expense.id}`,
);
}

return expense;
});

// Wait for all deletes to complete
await Promise.all(deletePromises);

return rawExpense.value;
}
}
14 changes: 8 additions & 6 deletions utils/expenses/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,13 @@ export default class ExpenseInputFactory {
}
}

private getInstallmentDate(installment: number) {
return installment === 1 ? new Date(this.data.paymentDate) : new Date(
new Date(this.data.paymentDate).setMonth(
new Date(this.data.paymentDate).getMonth() + installment - 1,
),
);
private getInstallmentDate(installment: number): Date {
if (installment === 1) {
return new Date(this.data.paymentDate);
}

const date = new Date(this.data.paymentDate);
date.setMonth(date.getMonth() + installment - 1);
return date;
}
}