Skip to content

Commit 0ccaf95

Browse files
authored
refactor: move loops out of functions, only loop over transactions for import once (#732)
This reduces the complexity and runtime of the transaction import transformations by only looping over all of them once.
1 parent 0309d7c commit 0ccaf95

File tree

1 file changed

+69
-72
lines changed

1 file changed

+69
-72
lines changed

pkg/controllers/import.go

Lines changed: 69 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,12 @@ func (co Controller) ImportYnabImportPreview(c *gin.Context) {
143143
return
144144
}
145145

146-
transactions = duplicateTransactions(co, transactions, account.BudgetID)
147-
transactions, err = findAccounts(co, transactions, account.BudgetID)
146+
for i, transaction := range transactions {
147+
transaction, err = findAccounts(co, transaction, account.BudgetID)
148+
transaction = duplicateTransactions(co, transaction, account.BudgetID)
149+
transactions[i] = transaction
150+
}
151+
148152
if err != nil {
149153
httperrors.Handler(c, err)
150154
return
@@ -246,89 +250,82 @@ func getUploadedFile(c *gin.Context, suffix string) (multipart.File, bool) {
246250
// duplicateTransactions finds duplicate transactions by their import hash. For all input resources,
247251
// existing resources with the same import hash are searched. If any exist, their IDs are set in the
248252
// DuplicateTransactionIDs field.
249-
func duplicateTransactions(co Controller, transactions []importer.TransactionPreview, budgetID uuid.UUID) []importer.TransactionPreview {
250-
for k, transaction := range transactions {
251-
var duplicates []models.Transaction
252-
co.DB.
253-
Preload("SourceAccount").
254-
Preload("DestinationAccount").
255-
Where(models.Transaction{
256-
TransactionCreate: models.TransactionCreate{
257-
ImportHash: transaction.Transaction.ImportHash,
258-
},
259-
}).
260-
Where(models.Transaction{SourceAccount: models.Account{AccountCreate: models.AccountCreate{BudgetID: budgetID}}}).
261-
Or(models.Transaction{DestinationAccount: models.Account{AccountCreate: models.AccountCreate{BudgetID: budgetID}}}).
262-
Find(&duplicates)
263-
264-
// When there are no resources, we want an empty list, not null
265-
// Therefore, we use make to create a slice with zero elements
266-
// which will be marshalled to an empty JSON array
267-
duplicateIDs := make([]uuid.UUID, 0)
268-
for _, duplicate := range duplicates {
269-
if duplicate.SourceAccount.BudgetID == budgetID || duplicate.DestinationAccount.BudgetID == budgetID {
270-
duplicateIDs = append(duplicateIDs, duplicate.ID)
271-
}
253+
func duplicateTransactions(co Controller, transaction importer.TransactionPreview, budgetID uuid.UUID) importer.TransactionPreview {
254+
var duplicates []models.Transaction
255+
co.DB.
256+
Preload("SourceAccount").
257+
Preload("DestinationAccount").
258+
Where(models.Transaction{
259+
TransactionCreate: models.TransactionCreate{
260+
ImportHash: transaction.Transaction.ImportHash,
261+
},
262+
}).
263+
Where(models.Transaction{SourceAccount: models.Account{AccountCreate: models.AccountCreate{BudgetID: budgetID}}}).
264+
Or(models.Transaction{DestinationAccount: models.Account{AccountCreate: models.AccountCreate{BudgetID: budgetID}}}).
265+
Find(&duplicates)
266+
267+
// When there are no resources, we want an empty list, not null
268+
// Therefore, we use make to create a slice with zero elements
269+
// which will be marshalled to an empty JSON array
270+
duplicateIDs := make([]uuid.UUID, 0)
271+
for _, duplicate := range duplicates {
272+
if duplicate.SourceAccount.BudgetID == budgetID || duplicate.DestinationAccount.BudgetID == budgetID {
273+
duplicateIDs = append(duplicateIDs, duplicate.ID)
272274
}
273-
transaction.DuplicateTransactionIDs = duplicateIDs
274-
transactions[k] = transaction
275275
}
276+
transaction.DuplicateTransactionIDs = duplicateIDs
276277

277-
return transactions
278+
return transaction
278279
}
279280

280281
// findAccounts sets the source or destination account ID for a TransactionPreview resource
281282
// if there is exactly one account with a matching name.
282-
func findAccounts(co Controller, transactions []importer.TransactionPreview, budgetID uuid.UUID) ([]importer.TransactionPreview, error) {
283-
for k, transaction := range transactions {
284-
// Find the right account name
285-
name := transaction.DestinationAccountName
286-
if transaction.SourceAccountName != "" {
287-
name = transaction.SourceAccountName
288-
}
283+
func findAccounts(co Controller, transaction importer.TransactionPreview, budgetID uuid.UUID) (importer.TransactionPreview, error) {
284+
// Find the right account name
285+
name := transaction.DestinationAccountName
286+
if transaction.SourceAccountName != "" {
287+
name = transaction.SourceAccountName
288+
}
289289

290-
var accounts []models.Account
291-
co.DB.Where(models.Account{
292-
AccountCreate: models.AccountCreate{
293-
Name: name,
294-
BudgetID: budgetID,
295-
Hidden: false,
296-
},
290+
var accounts []models.Account
291+
co.DB.Where(models.Account{
292+
AccountCreate: models.AccountCreate{
293+
Name: name,
294+
BudgetID: budgetID,
295+
Hidden: false,
297296
},
298-
// Explicitly specfiy search fields since we use a zero value for Hidden
299-
"Name", "BudgetID", "Hidden").Find(&accounts)
300-
301-
// We cannot determine correctly which account should be used if there are
302-
// multiple accounts, therefore we skip
303-
//
304-
// We also continue if no accounts are found
305-
if len(accounts) != 1 {
306-
continue
297+
},
298+
// Explicitly specfiy search fields since we use a zero value for Hidden
299+
"Name", "BudgetID", "Hidden").Find(&accounts)
300+
301+
// We cannot determine correctly which account should be used if there are
302+
// multiple accounts, therefore we skip
303+
//
304+
// We also continue if no accounts are found
305+
if len(accounts) != 1 {
306+
return transaction, nil
307+
}
308+
309+
// Set source or destination, depending on which one we checked for
310+
if accounts[0].ID != uuid.Nil {
311+
if transaction.SourceAccountName != "" {
312+
transaction.Transaction.SourceAccountID = accounts[0].ID
313+
transaction.SourceAccountName = ""
314+
} else {
315+
transaction.Transaction.DestinationAccountID = accounts[0].ID
316+
transaction.DestinationAccountName = ""
307317
}
308318

309-
// Set source or destination, depending on which one we checked for
310-
if accounts[0].ID != uuid.Nil {
311-
if transaction.SourceAccountName != "" {
312-
transaction.Transaction.SourceAccountID = accounts[0].ID
313-
transaction.SourceAccountName = ""
314-
} else {
315-
transaction.Transaction.DestinationAccountID = accounts[0].ID
316-
transaction.DestinationAccountName = ""
317-
}
318-
319-
// Preset the most popular recent envelope
320-
recentEnvelopes, err := accounts[0].RecentEnvelopes(co.DB)
321-
if err != nil {
322-
return []importer.TransactionPreview{}, err
323-
}
324-
325-
if len(recentEnvelopes) > 0 && recentEnvelopes[0].ID != uuid.Nil {
326-
transaction.Transaction.EnvelopeID = &recentEnvelopes[0].ID
327-
}
319+
// Preset the most popular recent envelope
320+
recentEnvelopes, err := accounts[0].RecentEnvelopes(co.DB)
321+
if err != nil {
322+
return importer.TransactionPreview{}, err
328323
}
329324

330-
transactions[k] = transaction
325+
if len(recentEnvelopes) > 0 && recentEnvelopes[0].ID != uuid.Nil {
326+
transaction.Transaction.EnvelopeID = &recentEnvelopes[0].ID
327+
}
331328
}
332329

333-
return transactions, nil
330+
return transaction, nil
334331
}

0 commit comments

Comments
 (0)