Skip to content

Conversation

gfyrag
Copy link
Collaborator

@gfyrag gfyrag commented Apr 22, 2025

No description provided.

@gfyrag gfyrag requested a review from a team as a code owner April 22, 2025 11:33
Copy link

coderabbitai bot commented Apr 22, 2025

Walkthrough

This set of changes introduces a new time.Time parameter to the UpdateTransactionMetadata and DeleteTransactionMetadata methods across the codebase, including interface definitions, implementations, and test mocks. The changes ensure that when transaction metadata is updated or deleted, the operation can be associated with a specific timestamp. SQL migrations are added and updated to enforce and backfill the updated_at field in the transactions table, ensuring its value is never null and accurately reflects the time of the latest update. Tests and migration scripts are updated to align with these changes and verify correctness.

Changes

File(s) Change Summary
internal/controller/ledger/store.go
internal/storage/ledger/transactions.go
internal/storage/ledger/transactions_test.go
internal/controller/ledger/controller_default.go
internal/controller/ledger/controller_default_test.go
internal/controller/ledger/store_generated_test.go
Added a time.Time parameter to UpdateTransactionMetadata and DeleteTransactionMetadata methods, updated all relevant method calls, mocks, and tests to include the new parameter.
internal/storage/bucket/migrations/29-fix-invalid-metadata-on-reverts/up.sql
internal/storage/bucket/migrations/29-fix-invalid-metadata-on-reverts/up_tests_before.sql
Modified migration script to update the updated_at column during metadata corrections; added pre-migration test data insertion.
internal/storage/bucket/migrations/30-transaction-updated-at-trigger/up.sql Added a trigger and function to ensure updated_at is set on insert; added a check constraint to enforce non-null updated_at.
internal/storage/bucket/migrations/31-fix-transaction-updated-at/up.sql Introduced a migration to backfill updated_at with inserted_at for transactions where it is null, processing in batches.
internal/storage/bucket/migrations/31-fix-transaction-updated-at/up_tests_after.sql Added a test to assert that no transaction rows have a null updated_at after migration.
internal/storage/bucket/migrations_test.go Improved error wrapping in migration test error messages using %w for better error context.

Sequence Diagram(s)

sequenceDiagram
    participant Controller
    participant Store
    participant DB

    Controller->>Store: UpdateTransactionMetadata(ctx, id, metadata, at)
    alt at is zero
        Store->>DB: UPDATE transactions SET ... updated_at = transaction_date()
    else at is non-zero
        Store->>DB: UPDATE transactions SET ... updated_at = at
    end
    Store-->>Controller: (*Transaction, bool, error)

    Controller->>Store: DeleteTransactionMetadata(ctx, id, key, at)
    alt at is zero
        Store->>DB: UPDATE transactions SET ... updated_at = transaction_date()
    else at is non-zero
        Store->>DB: UPDATE transactions SET ... updated_at = at
    end
    Store-->>Controller: (*Transaction, bool, error)
Loading

Suggested reviewers

  • Dav-14
  • paul-nicolas

Poem

In the ledger fields where timestamps grow,
Rabbits hop and metadata flows.
Each update now marks its time,
With triggers and checks in SQL rhyme.
No more nulls in updated_at,
Every change wears a time-stamped hat!
🐇⏰

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

codecov bot commented Apr 22, 2025

Codecov Report

Attention: Patch coverage is 94.59459% with 2 lines in your changes missing coverage. Please review.

Project coverage is 82.18%. Comparing base (85d362c) to head (1a48f02).
Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
internal/controller/ledger/controller_default.go 50.00% 0 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #877      +/-   ##
==========================================
- Coverage   82.26%   82.18%   -0.08%     
==========================================
  Files         141      141              
  Lines        7611     7613       +2     
==========================================
- Hits         6261     6257       -4     
- Misses       1035     1039       +4     
- Partials      315      317       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
internal/storage/ledger/transactions.go (1)

250-276: Added timestamp parameter to DeleteTransactionMetadata.

Similar to the UpdateTransactionMetadata method, this method now accepts and uses a timestamp parameter for setting the updated_at field.

Consider extracting the common timestamp handling logic from both methods to reduce code duplication:

+func (store *Store) buildMetadataUpdateQuery(query *bun.UpdateQuery, at time.Time) *bun.UpdateQuery {
+    if at.IsZero() {
+        return query.Set("updated_at = " + store.GetPrefixedRelationName("transaction_date") + "()")
+    } else {
+        return query.Set("updated_at = ?", at)
+    }
+}

 func (store *Store) UpdateTransactionMetadata(ctx context.Context, id int, m metadata.Metadata, at time.Time) (tx *ledger.Transaction, modified bool, err error) {
     _, err = tracing.TraceWithMetric(
         ctx,
         "UpdateTransactionMetadata",
         store.tracer,
         store.updateTransactionMetadataHistogram,
         func(ctx context.Context) (*ledger.Transaction, error) {
-            updateQuery := store.db.NewUpdate().
+            updateQuery := store.buildMetadataUpdateQuery(store.db.NewUpdate().
                 Model(&ledger.Transaction{}).
                 ModelTableExpr(store.GetPrefixedRelationName("transactions")).
                 Where("id = ?", id).
                 Where("ledger = ?", store.ledger.Name).
                 Set("metadata = metadata || ?", m).
                 Where("not (metadata @> ?)", m).
-                Returning("*")
-            if at.IsZero() {
-                updateQuery = updateQuery.Set("updated_at = " + store.GetPrefixedRelationName("transaction_date") + "()")
-            } else {
-                updateQuery = updateQuery.Set("updated_at = ?", at)
-            }
+                Returning("*"), at)

             tx, modified, err = store.updateTxWithRetrieve(ctx, id, updateQuery)

             return nil, postgres.ResolveError(err)
         },
     )
     return tx, modified, err
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dd37d3e and 1a48f02.

⛔ Files ignored due to path filters (5)
  • internal/storage/bucket/migrations/30-transaction-updated-at-trigger/notes.yaml is excluded by !**/*.yaml
  • internal/storage/bucket/migrations/31-fix-transaction-updated-at/notes.yaml is excluded by !**/*.yaml
  • internal/storage/bucket/migrations/32-accounts-recreate-unique-index/notes.yaml is excluded by !**/*.yaml
  • internal/storage/bucket/migrations/33-clean-database/notes.yaml is excluded by !**/*.yaml
  • internal/storage/bucket/migrations/34-logs-async-hash-procedure/notes.yaml is excluded by !**/*.yaml
📒 Files selected for processing (12)
  • internal/controller/ledger/controller_default.go (4 hunks)
  • internal/controller/ledger/controller_default_test.go (2 hunks)
  • internal/controller/ledger/store.go (1 hunks)
  • internal/controller/ledger/store_generated_test.go (2 hunks)
  • internal/storage/bucket/migrations/29-fix-invalid-metadata-on-reverts/up.sql (2 hunks)
  • internal/storage/bucket/migrations/29-fix-invalid-metadata-on-reverts/up_tests_before.sql (1 hunks)
  • internal/storage/bucket/migrations/30-transaction-updated-at-trigger/up.sql (1 hunks)
  • internal/storage/bucket/migrations/31-fix-transaction-updated-at/up.sql (1 hunks)
  • internal/storage/bucket/migrations/31-fix-transaction-updated-at/up_tests_after.sql (1 hunks)
  • internal/storage/bucket/migrations_test.go (2 hunks)
  • internal/storage/ledger/transactions.go (2 hunks)
  • internal/storage/ledger/transactions_test.go (7 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
internal/controller/ledger/store.go (2)
internal/transaction.go (2)
  • Transaction (38-50)
  • Transaction (52-59)
internal/controller/ledger/controller.go (1)
  • DeleteTransactionMetadata (105-108)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Tests
  • GitHub Check: Dirty
🔇 Additional comments (21)
internal/storage/bucket/migrations/31-fix-transaction-updated-at/up_tests_after.sql (1)

1-6: Effective post-migration validation test

This SQL test script correctly verifies that after the migration runs, there are no rows with null updated_at values in the transactions table. It's a good practice to include such validation to ensure the migration successfully fixed all affected records.

internal/storage/bucket/migrations_test.go (2)

55-55: Good use of error wrapping with %w

This change improves error handling by using Go's error wrapping feature with %w instead of string formatting with %s. This approach preserves the original error's type and context, enabling proper error inspection with errors.Is and errors.As up the call stack.


75-75: Good use of error wrapping with %w

Same as above, this change correctly updates error handling to use Go's error wrapping instead of string formatting, preserving the error chain for better error inspection and debugging.

internal/storage/bucket/migrations/29-fix-invalid-metadata-on-reverts/up_tests_before.sql (1)

6-20: LGTM: Appropriate test data setup

This addition properly sets up the test data required for the assertion on line 21. Inserting a transaction before checking metadata properties ensures the test environment has the necessary data for meaningful validation.

internal/controller/ledger/controller_default_test.go (2)

152-152: Correctly updated test to match new method signature

This change adds the required time.Time{} parameter to the mock expectation, matching the updated method signature that now accepts a timestamp parameter for setting the updated_at field.


193-193: Correctly updated test to match new method signature

Similar to line 152, this change properly adds the time.Time{} parameter to the DeleteTransactionMetadata mock expectation, ensuring the test remains compatible with the updated method signature.

internal/storage/bucket/migrations/29-fix-invalid-metadata-on-reverts/up.sql (3)

14-16: Improved data extraction from memento field

The change from using the data JSON field to extracting information from the memento field (converted from UTF-8 to JSONB) provides a more reliable way to access transaction data. This is a good approach as the memento field likely contains a more complete snapshot of the transaction state.


20-21: Enhanced selection with revert timestamp

Adding reversed.revertedAt to the selected fields ensures the revert timestamp is available for subsequent operations, aligning with the PR objective to properly set the updated_at field.


45-47: Fixed missing updated_at timestamp for reverted transactions

This change addresses the core issue described in the PR title. By setting updated_at = data.revertedAt, reverted transactions now correctly track when they were modified. This ensures consistency in the transaction history and fixes the issue where the updated_at field was not being set properly.

internal/controller/ledger/controller_default.go (4)

224-224: Passing log timestamp for transaction metadata updates

Updating the method call to include log.Date as the timestamp parameter ensures that when transaction metadata is updated during log import, the operation will be timestamped with the actual event time rather than the current time. This maintains historical accuracy.


239-239: Passing log timestamp for transaction metadata deletions

Similar to the update operation, this change ensures that metadata deletions during log import are timestamped with the log's event time. This maintains consistency with the actual sequence of events.


432-432: Using zero time for direct metadata updates

When metadata is updated directly (not as part of log import), a zero time value is passed. This indicates that the storage layer should use a different mechanism (likely current time) for setting the updated_at field. This approach maintains a clear distinction between importing historical events and creating new ones.


470-470: Using zero time for direct metadata deletions

Consistent with the pattern for updates, metadata deletions that aren't part of log imports use a zero time value. This maintains consistency in how timestamps are handled across the codebase.

internal/controller/ledger/store.go (1)

45-46:

✅ Verification successful

Updated interface to support timestamped metadata operations

The Store interface has been updated to include a time.Time parameter in both metadata methods, allowing implementations to use the provided timestamp when updating the updated_at field. This change is essential for propagating the correct timestamp through the system layers.

You should verify that all implementations of this interface have been updated to accept this new parameter. Run this script to check for any missed implementations:


🏁 Script executed:

#!/bin/bash
# Find all implementations of UpdateTransactionMetadata and DeleteTransactionMetadata
# to ensure they've been updated with the new parameter

echo "Checking for UpdateTransactionMetadata implementations:"
rg "func \(.+\) UpdateTransactionMetadata\(" --type go

echo -e "\nChecking for DeleteTransactionMetadata implementations:"
rg "func \(.+\) DeleteTransactionMetadata\(" --type go

Length of output: 4590


All Store interface implementations now include the time.Time parameter

I’ve verified that every implementation of both UpdateTransactionMetadata and DeleteTransactionMetadata has been updated to accept the new at time.Time argument:

  • internal/storage/ledger/transactions.go
  • internal/controller/ledger/store_generated_test.go (mocks and mock recorder)

No remaining action required here.

internal/storage/bucket/migrations/31-fix-transaction-updated-at/up.sql (1)

1-46:

❓ Verification inconclusive

Data migration to backfill missing updated_at values

This migration script addresses existing transactions with null updated_at values by setting them to match their inserted_at values. The script:

  1. Uses batched updates for performance (1000 rows per batch)
  2. Reports progress through notifications
  3. Includes proper error handling and early exit when no rows need updating
  4. Cleans up temporary tables

This is a well-structured migration that ensures data consistency without locking the entire table at once.

Run this verification script to check if there are any transactions with null updated_at values after the migration:


🏁 Script executed:

#!/bin/bash
# Verify the effectiveness of the migration by checking if any transactions 
# still have null updated_at values in test databases

fd --type file "up_tests_after.sql" --exec cat {} \; | grep -i "updated_at is null"

Length of output: 194


Verify that no updated_at values remain null

Please connect to your test database (using the same schema) and run:

SELECT count(*) AS null_updated_ats
FROM transactions
WHERE updated_at IS NULL;

Ensure this returns 0 before approving the migration.

internal/storage/ledger/transactions_test.go (2)

146-147: Method calls updated to include new timestamp parameter.

The UpdateTransactionMetadata, DeleteTransactionMetadata, and RevertTransaction method calls have been updated to include a new zero timestamp parameter (time.Time{}). This change correctly adapts the test to the updated interface methods.

Also applies to: 150-150, 169-169, 174-174, 204-204, 215-215, 220-220, 564-564, 576-576, 581-581, 719-719


646-647: Model struct updated to include UpdatedAt field.

The UpdatedAt field has been added to the test model structure to correctly verify that the transaction's updated_at timestamp is being set. The test also properly verifies that this field matches the current time (now).

Also applies to: 669-670

internal/storage/bucket/migrations/30-transaction-updated-at-trigger/up.sql (1)

1-24:

❓ Verification inconclusive

Well-designed migration for handling transaction updated_at values.

This migration addresses the issue mentioned in the PR title by:

  1. Creating a trigger function that automatically sets updated_at to match inserted_at for new transactions
  2. Adding a NOT NULL constraint (marked as not valid to avoid validation on existing rows)

The approach is solid, handling both new insertions and providing a path to fixing existing data.

Verify that there's a subsequent migration that validates the constraint after fixing existing data:


🏁 Script executed:

#!/bin/bash
# Look for a migration that validates the constraint or updates existing rows
fd -e sql -e SQL -p "transactions.*updated_at" internal/storage/bucket/migrations

Length of output: 83


Please add or confirm a follow‑up migration to backfill and validate the new constraint.

I didn’t find any migration that:

  • Updates existing transactions rows to populate updated_at
  • Runs
    ALTER TABLE transactions VALIDATE CONSTRAINT transactions_updated_at_not_null;

Without that step, the NOT NULL constraint can never be marked valid.
Please verify (or add) a migration under internal/storage/bucket/migrations/ to backfill old data and validate the constraint.

internal/storage/ledger/transactions.go (2)

123-123: Updated return columns to include updated_at.

The InsertTransaction method now correctly returns the updated_at column along with other fields, ensuring this new field is properly populated in the returned transaction.


220-248: Added timestamp parameter to UpdateTransactionMetadata.

The method now accepts an at time.Time parameter and conditionally sets the updated_at field:

  • If at is zero, it uses the database's transaction date function
  • Otherwise, it uses the provided timestamp

This change ensures proper tracking of when transaction metadata was last updated.

internal/controller/ledger/store_generated_test.go (1)

135-148: Updated mock implementation with new timestamp parameter.

The mock implementations for DeleteTransactionMetadata and UpdateTransactionMetadata have been correctly updated to include the new at time.Time parameter, ensuring test coverage for the interface changes.

Also applies to: 325-338

@gfyrag gfyrag added this pull request to the merge queue Apr 22, 2025
Merged via the queue into main with commit 3b718a3 Apr 22, 2025
9 of 10 checks passed
@gfyrag gfyrag deleted the fix/updated-at branch April 22, 2025 13:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants