Skip to content

Add Entity.getOrCreate and Entity.getOrThrow API#567

Merged
DZakh merged 7 commits into
mainfrom
dz/more-get-api
Jun 9, 2025
Merged

Add Entity.getOrCreate and Entity.getOrThrow API#567
DZakh merged 7 commits into
mainfrom
dz/more-get-api

Conversation

@DZakh

@DZakh DZakh commented Jun 4, 2025

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features
    • Introduced methods for guaranteed entity retrieval and conditional creation: getOrThrow (throws an error if the entity is missing) and getOrCreate (creates the entity if it does not exist).
  • Tests
    • Added comprehensive tests to verify the behavior of getOrThrow and getOrCreate methods for entity handling, including error cases and custom error messages.
  • Bug Fixes
    • Enhanced event handling to correctly process and validate entity retrieval and creation scenarios based on event parameters.
  • Refactor
    • Updated event processing to use exception-based error handling for clearer control flow and improved error reporting.
    • Consolidated batch event handling with unified error management and simplified async processing.
  • Chores
    • Removed deprecated error propagation module and unused imports.
    • Added a silent error suppression function for promises to improve error handling flexibility.

@DZakh DZakh requested a review from JonoPrest June 4, 2025 13:23
@coderabbitai

coderabbitai Bot commented Jun 4, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

This change introduces new entity retrieval methods—getOrThrow and getOrCreate—to entity context interfaces and implementations. These methods provide stricter error handling and conditional creation semantics for entities. The update is reflected in both type declarations and runtime logic, and is validated with new event handler logic and targeted tests. Additionally, event processing and batch handling were refactored to use exception-based error handling, removing previous result-based patterns. Some legacy error propagation modules were removed, and silent error suppression was added for promise handling.

Changes

File(s) Change Summary
codegenerator/cli/templates/dynamic/codegen/src/Types.res.hbs,
codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
Added getOrThrow to loader and handler context types; added getOrCreate to handler context types.
codegenerator/cli/templates/static/codegen/src/UserContext.res Implemented getOrThrow and getOrCreate in handler/loader context factories; refactored helper functions.
scenarios/test_codegen/src/EventHandlers.ts Replaced single handler with handlerWithLoader to test new entity retrieval methods and error handling.
scenarios/test_codegen/test/EventHandler_test.ts Added tests for getOrCreate and getOrThrow methods on User entity using mock database.
codegenerator/cli/npm/envio/src/ErrorHandling.res Removed ResultPropogateEnv module with exception-based early return mechanism for async results.
codegenerator/cli/npm/envio/src/bindings/Promise.res Added silentCatch function to suppress promise errors silently without callbacks.
codegenerator/cli/templates/dynamic/codegen/src/TestHelpers.res.hbs Refactored makeEventProcessor to use batch loaders/handlers with exception-based error handling.
codegenerator/cli/templates/static/codegen/src/EventProcessing.res Refactored event processing to use exceptions (ProcessingError) instead of result types; renamed functions.
scenarios/test_codegen/test/Mock_test.res Replaced per-event handler loop with batch handler call using exception-based error handling.

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    participant Handler as EntityHandlerContext
    participant Store as EntityStore

    Caller->>Handler: getOrThrow(id)
    Handler->>Store: get(id)
    alt Entity exists
        Store-->>Handler: entity
        Handler-->>Caller: entity
    else Entity missing
        Handler-->>Caller: throws error
    end

    Caller->>Handler: getOrCreate(entity)
    Handler->>Store: get(entity.id)
    alt Entity exists
        Store-->>Handler: entity
        Handler-->>Caller: entity
    else Entity missing
        Handler->>Store: set(entity)
        Store-->>Handler: entity
        Handler-->>Caller: entity
    end
Loading

Suggested reviewers

  • JasoonS
  • JonoPrest

Poem

In the warren of code, new tunnels appear,
With getOrThrow and getOrCreate—crystal clear!
Now bunnies can fetch, or make with delight,
Entities hop in, no errors in sight.
So nibble these changes, and give them a cheer,
For context is richer, and bugs disappear! 🐇✨


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.
    • Explain this complex logic.
    • 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 explain this code block.
    • @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 explain its main purpose.
    • @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.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

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 generate sequence diagram to generate a sequence diagram of the changes in 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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
codegenerator/cli/templates/static/codegen/src/UserContext.res (2)

111-121: Consider potential race condition in getOrCreate.

The implementation is functionally correct, but there's a theoretical race condition between checking entity existence and creating it. In concurrent scenarios, multiple calls could attempt to create the same entity simultaneously.

This might be acceptable depending on your system's concurrency model and whether the underlying storage layer handles duplicate creation gracefully. Consider documenting this behavior or implementing atomic upsert semantics if needed.


215-236: Consider reducing code duplication between contexts.

The getOrThrow implementation is duplicated between handler and loader contexts. While the logic is correct, you could extract this into a shared helper function to improve maintainability.

+let makeGetOrThrow = (get, entityName) => (entityId, ~message=?) =>
+  get(entityId)->Promise.thenResolve(entity => {
+    switch entity {
+    | Some(entity) => entity
+    | None =>
+      Js.Exn.raiseError(
+        message->Belt.Option.getWithDefault(
+          `Entity '${entityName}' with ID '${entityId}' is expected to exist.`,
+        ),
+      )
+    }
+  })

Then use this helper in both contexts:

-    getOrThrow: (entityId, ~message=?) =>
-      get(entityId)->Promise.thenResolve(entity => {
-        switch entity {
-        | Some(entity) => entity
-        | None =>
-          Js.Exn.raiseError(
-            message->Belt.Option.getWithDefault(
-              `Entity '${entityConfig.name}' with ID '${entityId}' is expected to exist.`,
-            ),
-          )
-        }
-      }),
+    getOrThrow: makeGetOrThrow(get, entityConfig.name),
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 5a1cbe0 and 4690af8.

📒 Files selected for processing (5)
  • codegenerator/cli/templates/dynamic/codegen/src/Types.res.hbs (2 hunks)
  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs (2 hunks)
  • codegenerator/cli/templates/static/codegen/src/UserContext.res (3 hunks)
  • scenarios/test_codegen/src/EventHandlers.ts (2 hunks)
  • scenarios/test_codegen/test/EventHandler_test.ts (2 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
scenarios/test_codegen/test/EventHandler_test.ts

[error] 104-104: Don't focus the test.

The 'only' method is often used for debugging or during implementation. It should be removed before deploying to production.
Consider removing 'only' to ensure all tests are executed.
Unsafe fix: Remove focus from test.

(lint/suspicious/noFocusedTests)


[error] 131-131: Don't focus the test.

The 'only' method is often used for debugging or during implementation. It should be removed before deploying to production.
Consider removing 'only' to ensure all tests are executed.
Unsafe fix: Remove focus from test.

(lint/suspicious/noFocusedTests)


[error] 159-159: Don't focus the test.

The 'only' method is often used for debugging or during implementation. It should be removed before deploying to production.
Consider removing 'only' to ensure all tests are executed.
Unsafe fix: Remove focus from test.

(lint/suspicious/noFocusedTests)


[error] 187-187: Don't focus the test.

The 'only' method is often used for debugging or during implementation. It should be removed before deploying to production.
Consider removing 'only' to ensure all tests are executed.
Unsafe fix: Remove focus from test.

(lint/suspicious/noFocusedTests)


[error] 209-209: Don't focus the test.

The 'only' method is often used for debugging or during implementation. It should be removed before deploying to production.
Consider removing 'only' to ensure all tests are executed.
Unsafe fix: Remove focus from test.

(lint/suspicious/noFocusedTests)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build_and_test
🔇 Additional comments (8)
codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs (1)

26-30: LGTM! Clean and well-designed API additions.

The new getOrThrow and getOrCreate methods are properly documented with clear JSDoc comments and follow consistent TypeScript patterns. The design decision to restrict getOrCreate to HandlerContext only makes sense since loaders should not perform mutations.

Also applies to: 54-63

codegenerator/cli/templates/dynamic/codegen/src/Types.res.hbs (1)

18-18: LGTM! Consistent type definitions across language bindings.

The ReScript type definitions properly mirror the TypeScript interface with correct syntax for labeled arguments (~message: string=?). The API consistency between TypeScript and ReScript ensures proper interoperability.

Also applies to: 34-35

scenarios/test_codegen/test/EventHandler_test.ts (1)

104-229: Excellent test coverage for new entity methods.

The test suite comprehensively covers all scenarios for the new getOrCreate and getOrThrow methods:

  • Entity creation when missing
  • Entity loading when existing
  • Successful retrieval with getOrThrow
  • Error handling with default and custom messages

The test setup with mock database and entity assertions using deepEqual is well-structured and validates the expected behavior correctly.

🧰 Tools
🪛 Biome (1.9.4)

[error] 104-104: Don't focus the test.

The 'only' method is often used for debugging or during implementation. It should be removed before deploying to production.
Consider removing 'only' to ensure all tests are executed.
Unsafe fix: Remove focus from test.

(lint/suspicious/noFocusedTests)


[error] 131-131: Don't focus the test.

The 'only' method is often used for debugging or during implementation. It should be removed before deploying to production.
Consider removing 'only' to ensure all tests are executed.
Unsafe fix: Remove focus from test.

(lint/suspicious/noFocusedTests)


[error] 159-159: Don't focus the test.

The 'only' method is often used for debugging or during implementation. It should be removed before deploying to production.
Consider removing 'only' to ensure all tests are executed.
Unsafe fix: Remove focus from test.

(lint/suspicious/noFocusedTests)


[error] 187-187: Don't focus the test.

The 'only' method is often used for debugging or during implementation. It should be removed before deploying to production.
Consider removing 'only' to ensure all tests are executed.
Unsafe fix: Remove focus from test.

(lint/suspicious/noFocusedTests)


[error] 209-209: Don't focus the test.

The 'only' method is often used for debugging or during implementation. It should be removed before deploying to production.
Consider removing 'only' to ensure all tests are executed.
Unsafe fix: Remove focus from test.

(lint/suspicious/noFocusedTests)

scenarios/test_codegen/src/EventHandlers.ts (3)

1-1: Good addition of required import.

Adding deepEqual import supports the assertion logic used in the new event handler test cases.


431-438: Clean and focused helper functions.

The notify and isLiveEvent helper functions are simple, well-named, and serve clear purposes in the event handling logic.


440-506: Excellent implementation testing the new entity methods.

The event handler systematically tests all scenarios for the new getOrCreate and getOrThrow methods:

  • Proper type checking with expectType
  • Data validation using deepEqual assertions
  • Comprehensive coverage of success and error cases
  • Clean switch statement structure that corresponds to test cases

The implementation demonstrates the intended usage patterns and validates the API behavior correctly.

codegenerator/cli/templates/static/codegen/src/UserContext.res (2)

67-85: LGTM: Good refactoring with helper functions.

The extraction of get and set helper functions improves code organization and reduces duplication. The logic is correct and maintains the same functionality as before.


99-110: LGTM: getOrThrow implementation is correct.

The getOrThrow method properly handles the error case with a customizable error message and follows the expected semantics for this type of operation.

Comment thread scenarios/test_codegen/test/EventHandler_test.ts Outdated
| None =>
Js.Exn.raiseError(
message->Belt.Option.getWithDefault(
`Entity '${params.entityConfig.name}' with ID '${entityId}' is expected to exist.`,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think regardless of the message we should add entity name and id as a context.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

No easy way to pass it from here

Comment on lines +225 to +229
getOrThrow: (entityId, ~message=?) =>
get(entityId)->Promise.thenResolve(entity => {
switch entity {
| Some(entity) => entity
| None =>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

How does this implementation account for the entity not existing on the first run of the loader?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@JonoPrest I updated the PR to silently ignore the first loader run errors. I don't know why we didn't do it before. I firmly believe that the previous behavior is wrong, so I'll merge the PR without a rereview, but I'm open to feedback when you're back on Monday.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Ok, something is wrong with thests, so you'll have a chance to review :)

@JonoPrest JonoPrest left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Looks great but please let me know if its handled that loader runs for the first time without the entity existing yet or if it will crash.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 (2)
codegenerator/cli/npm/envio/src/bindings/Promise.res (1)

40-43: Consider the implications of silent error suppression.

The silentCatch function suppresses promise rejections without any logging or handling, which could make debugging difficult if errors are inadvertently swallowed. While this appears intentional for the new batch processing flow, ensure this is only used where errors are definitively handled elsewhere.

The use of Obj.magic is inherently unsafe but appears necessary for the no-op function.

Consider adding a comment explaining when silentCatch should be used:

+// Only use silentCatch when errors are handled elsewhere in the pipeline
 let silentCatch = (promise: promise<'a>): promise<'a> => {
   catch(promise, noop)
 }
scenarios/test_codegen/src/EventHandlers.ts (1)

431-431: Consider test isolation for the module-level counter.

While this approach works for sequential test execution, consider resetting this counter before each test or using a more isolated approach to avoid potential issues with parallel test execution.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 2252dee and 74b8471.

📒 Files selected for processing (7)
  • codegenerator/cli/npm/envio/src/ErrorHandling.res (0 hunks)
  • codegenerator/cli/npm/envio/src/bindings/Promise.res (1 hunks)
  • codegenerator/cli/templates/dynamic/codegen/src/TestHelpers.res.hbs (4 hunks)
  • codegenerator/cli/templates/static/codegen/src/EventProcessing.res (4 hunks)
  • scenarios/test_codegen/src/EventHandlers.ts (2 hunks)
  • scenarios/test_codegen/test/EventHandler_test.ts (2 hunks)
  • scenarios/test_codegen/test/Mock_test.res (1 hunks)
💤 Files with no reviewable changes (1)
  • codegenerator/cli/npm/envio/src/ErrorHandling.res
🧰 Additional context used
🧬 Code Graph Analysis (1)
scenarios/test_codegen/src/EventHandlers.ts (1)
codegenerator/cli/templates/static/codegen/index.js (1)
  • BigDecimal (7-7)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build_and_test
🔇 Additional comments (15)
scenarios/test_codegen/test/Mock_test.res (1)

13-26: Excellent refactor to batch processing with proper error handling.

The consolidation from manual event iteration to runBatchHandlersOrThrow aligns well with the new exception-based error handling pattern. The try-catch block properly handles ProcessingError exceptions while maintaining consistent error logging and propagation.

codegenerator/cli/templates/dynamic/codegen/src/TestHelpers.res.hbs (2)

143-158: Well-designed refactor to exception-based batch processing.

The transformation from conditional handler invocation to batch processing with exception handling significantly improves the code:

  1. Cleaner control flow: Exception-based error handling is more readable than nested conditionals
  2. Consistent error handling: ProcessingError exceptions provide structured error information
  3. Better performance: Batch processing is more efficient than individual event handling
  4. Improved maintainability: Unified error handling path reduces code duplication

The proper contextual logging with event-specific loggers ensures good debugging capabilities.


129-132:

Details

✅ Verification successful

Verify the contract register function signature.

Ensure that runContractRegistersOrThrow accepts the expected parameter format with ~reversedWithContractRegister.


🏁 Script executed:

#!/bin/bash
# Verify the ChainFetcher.runContractRegistersOrThrow function signature
ast-grep --pattern 'let runContractRegistersOrThrow = $$$'

Length of output: 60


To locate the definition of runContractRegistersOrThrow, let’s search across all Rescript source files:


🏁 Script executed:

#!/bin/bash
# Search for runContractRegistersOrThrow in .res files to find its signature
rg "runContractRegistersOrThrow" -n --glob "*.res"

Length of output: 340


To confirm the exact parameters of runContractRegistersOrThrow, let’s inspect its definition in ChainFetcher.res around line 311:


🏁 Script executed:

#!/bin/bash
# Extract the function signature and surrounding context
sed -n '300,330p' codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res

Length of output: 1258


Signature Verified

The runContractRegistersOrThrow function in
codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res
is declared as:

let runContractRegistersOrThrow = async (
  ~reversedWithContractRegister: array<Internal.eventItem>,
) => { … }

This matches the call in your template (~reversedWithContractRegister=[eventItem]). No changes required.

scenarios/test_codegen/test/EventHandler_test.ts (6)

105-130: Excellent test coverage for getOrCreate functionality.

The test properly verifies entity creation when the entity doesn't exist, with appropriate assertions on all expected fields including the default values for updatesCountOnUserForTesting and accountType.


132-158: Good isolation and verification of getOrCreate loading behavior.

The test correctly:

  1. Pre-populates the mock database with an existing entity
  2. Verifies that getOrCreate loads rather than creates
  3. Ensures no modification of the existing entity

This validates the conditional logic in the getOrCreate implementation.


160-186: Solid verification of getOrThrow success path.

The test appropriately validates that getOrThrow returns existing entities without modification, confirming the method works as expected when entities exist.


188-208: Proper error handling validation for getOrThrow.

The test correctly uses assert.rejects to verify that getOrThrow throws the expected error message when entities don't exist. This ensures the error handling semantics are working properly.


210-230: Good validation of custom error messaging.

Testing custom error messages ensures the getOrThrow method properly supports user-defined error messages, which is important for debugging and user experience.


232-252: Comprehensive edge case testing for loader failure scenarios.

This test validates complex error handling where the first loader failure is ignored but subsequent failures abort processing. This ensures the robustness of the error handling pipeline in real-world scenarios.

scenarios/test_codegen/src/EventHandlers.ts (2)

1-1: LGTM! Good choice for deep equality assertions.

Using deepEqual from the assert module is appropriate for verifying entity data in tests.


433-566: Well-structured test implementation for the new entity retrieval methods.

The test cases comprehensively cover the new getOrCreate and getOrThrow functionality:

  • Loader failure handling is properly tested
  • Type safety is verified with expectType
  • Data integrity is checked with deepEqual
  • All test scenarios are clearly separated and documented
codegenerator/cli/templates/static/codegen/src/EventProcessing.res (4)

95-95: Good error structure for event processing failures.

The ProcessingError exception provides excellent context for debugging by including the error message, original exception, and the event item that caused the failure.


97-166: Clean refactoring to exception-based error handling.

The error handling provides clear, actionable messages that guide users to handle errors properly. The preservation of benchmarking logic and proper propagation of loader returns to handlers is well implemented.


196-227: Intentional error suppression is well-documented.

The comments clearly explain why errors are silently caught during the first loader run. This design prevents stale data by re-running loaders before handlers, aligning with the test behavior in EventHandlers.ts.


275-349: Excellent simplification of error handling flow.

The refactoring from result-based to exception-based error handling significantly improves readability while maintaining all functionality. The centralized error handling with proper context preservation makes debugging easier.

@DZakh DZakh enabled auto-merge (squash) June 6, 2025 15:02
Comment on lines +209 to +220
try {
Some(
loader(
UserContext.getLoaderArgs({
eventItem,
inMemoryStore,
loadLayer,
shouldGroup: true,
}),
)->Promise.silentCatch,
)
} catch {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Do you need to try catch if you're running silent catch?

Or vice versa

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yes, because if it throws before await, it'll be immediately thrown without creating a rejected promise.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 74b8471 and 63a2812.

⛔ Files ignored due to path filters (1)
  • scenarios/erc20_multichain_factory/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (1)
  • codegenerator/cli/templates/static/codegen/src/EventProcessing.res (4 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build_and_test
🔇 Additional comments (5)
codegenerator/cli/templates/static/codegen/src/EventProcessing.res (5)

95-95: Well-structured exception type for debugging.

The ProcessingError exception includes comprehensive context (message, original exception, and event item) which will be valuable for error tracking and debugging.


97-166: Solid exception-based refactor with proper benchmarking.

The refactored function correctly:

  • Wraps async operations in try-catch blocks
  • Provides descriptive error messages for debugging
  • Preserves benchmarking logic after successful execution
  • Maintains the same logical flow as the previous result-based approach

168-194: Consistent refactor maintaining original logic.

The function correctly adapts to the new exception-based pattern while preserving all original functionality including sync state updates and raw event handling.


232-251: Appropriate sequential processing for handlers.

Sequential handler execution ensures proper event ordering and allows exceptions to properly propagate, which is correct for the exception-based error handling pattern.


278-352:

Details

❌ Incorrect review comment

Mixed error handling patterns need consistency.

The function mixes exception-based processing with result-based database operations, creating inconsistency:

  1. Lines 301-345: ProcessingError exceptions from event processing
  2. Lines 320-321: Database exceptions converted to Error results
  3. Lines 347-350: ProcessingError converted back to Error results

Consider standardizing the error handling approach - either handle database exceptions as ProcessingError or convert all exceptions to results at the same level.

Additionally, verify that all metrics and benchmarking data is properly preserved in both success and error scenarios.


No changes needed to error‐handling here

Both event‐processing errors and database exceptions are already converted into Error results before the function returns—

  • The switch … | exception exn => … block around executeBatch catches and wraps DB errors.
  • The outer catch ProcessingError block wraps any processing exceptions.

Since every failure path yields an Error and every success path yields Ok(), the error‐handling pattern is consistent.

Likely an incorrect or invalid review comment.

Comment on lines +196 to 230
let runBatchLoadersOrThrow = async (
eventBatch: array<Internal.eventItem>,
~loadLayer,
~inMemoryStore,
) => {
// On the first run of loaders, we don't care about the result,
// whether it's an error or a return type.
// We'll rerun the loader again right before the handler run,
// to avoid having a stale data returned from the loader.
let _ = await Promise.all(
eventBatch->Array.keepMap(eventItem => {
switch eventItem.eventConfig {
| {loader: Some(loader)} =>
try {
Some(
loader(
UserContext.getLoaderArgs({
eventItem,
inMemoryStore,
loadLayer,
shouldGroup: true,
}),
// Must have Promise.catch as well as normal catch,
// because if user throws an error before await in the handler,
// it won't create a rejected promise
)->Promise.silentCatch,
)
} catch {
| _ => None
}
})
->Promise.all
Ok()
})
| _ => None
}
}),
)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify the silent error suppression approach in batch loaders.

The dual error handling (try-catch + silentCatch) correctly addresses synchronous vs asynchronous errors. However, the silent suppression of all loader errors on the first run could mask important issues.

Consider logging suppressed errors for debugging purposes, even if they don't fail the batch processing.


🏁 Script executed:

#!/bin/bash
# Verify that Promise.silentCatch is properly implemented and doesn't completely hide errors
ast-grep --pattern 'silentCatch'

Length of output: 32


I couldn’t locate any silentCatch definitions with the first AST query. Let’s try a broader grep search:

If this still returns nothing, please verify manually that Promise.silentCatch is implemented (and how it handles/logs errors), as we need confidence it won’t fully swallow critical loader failures.


🏁 Script executed:

#!/bin/bash
# Search for any usage or definition of silentCatch
rg -n 'Promise\.silentCatch'
rg -n 'silentCatch'

Length of output: 379


Log suppressed errors in Promise.silentCatch for better visibility

Currently the first‐run loader errors are completely swallowed by silentCatch, making it hard to debug latent loader failures. To retain silent failure but still capture these errors:

• In codegenerator/cli/npm/envio/src/bindings/Promise.res (around line 41), enhance silentCatch to emit a log:

 let silentCatch = (promise: promise<'a>): promise<'a> =>
-  promise->Js.Promise.catch(_ => Js.Promise.resolve())
+  promise->Js.Promise.catch(err => {
+    /* debug: record suppressed error */
+    Js.log2("silentCatch suppressed error:", err);
+    Js.Promise.resolve()
+  })

• Or, wrap the loader invocation in codegenerator/cli/templates/static/codegen/src/EventProcessing.res (line 221) to log per‐loader errors:

     )->Promise.silentCatch,

becomes

     )->Promise.silentCatch
+      |> Js.Promise.tapError(err => {
+           Js.log2("First‐run loader error (suppressed):", err);
+           Js.Promise.resolve(None)
+         }),

This preserves the intentional “ignore first run” semantics while surfacing suppressed errors for later troubleshooting.

🤖 Prompt for AI Agents
In codegenerator/cli/templates/static/codegen/src/EventProcessing.res around
lines 196 to 230, the current use of Promise.silentCatch in the first-run batch
loaders completely suppresses errors, which can hide important issues. To fix
this, modify the silentCatch implementation in
codegenerator/cli/npm/envio/src/bindings/Promise.res near line 41 to log
suppressed errors for visibility, or alternatively, wrap the loader invocation
at line 221 in EventProcessing.res with additional error logging that captures
and logs errors while still allowing the batch to continue silently. This
ensures errors are not lost but the first-run silent failure behavior is
preserved.

@DZakh DZakh merged commit 275b871 into main Jun 9, 2025
2 of 3 checks passed
@DZakh DZakh deleted the dz/more-get-api branch June 9, 2025 14:29
@coderabbitai coderabbitai Bot mentioned this pull request Jun 18, 2025
@coderabbitai coderabbitai Bot mentioned this pull request Aug 6, 2025
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