Skip to content

Conversation

@DZakh
Copy link
Member

@DZakh DZakh commented Nov 10, 2025

This PR is a preparation for:

  • ClickHouse sync
  • Fuel & Solana block handler support
  • Better DX on accessing block and transaction fields not specified in field selection
  • It's also an enabler for Hack: createTestIndexer #802

Summary by CodeRabbit

  • New Features

    • Added a Platform abstraction (EVM/Fuel) and expanded storage API with batched writes, deletion/rollback helpers, and utility calls.
  • Refactor

    • Replaced ecosystem usage with platform across runtime and templates; centralized platform-specific access and cleanup. Shifted DB interactions to the storage surface and simplified rollback/data flows.
  • Tests

    • Updated mocks and test helpers to expose new storage methods and platform-based behavior.
  • Chores

    • Removed deprecated batch-delete implementation and unused schema binding.

@moose-code
Copy link
Member

This is cool

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 10, 2025

Walkthrough

Replaces ecosystem with a structured Platform.t and propagates it through Config, templates, and runtime calls. Refactors persistence: removes exposed sql, expands the storage interface with new helpers, centralizes batched writes into writeBatch, and updates many call sites and tests to the new storage API.

Changes

Cohort / File(s) Summary
Platform abstraction
codegenerator/cli/npm/envio/src/Platform.res
Add Platform.name and Platform.t; provide concrete evm/fuel instances, accessors (getNumber, getTimestamp, getId), cleanUpRawEventFieldsInPlace, and fromName.
Config & registration
codegenerator/cli/npm/envio/src/Config.res, codegenerator/cli/npm/envio/src/EventRegister.res, codegenerator/cli/npm/envio/src/EventRegister.resi
Replace ecosystem with platform: Platform.t in types and APIs; Config.make accepts a platform name and derives platform; startRegistration now takes ~platform and registration records use platform.
Persistence surface & PgStorage
codegenerator/cli/npm/envio/src/Persistence.res, codegenerator/cli/npm/envio/src/PgStorage.res
Remove exposed sql from storage public record; add new storage methods (executeUnsafe, hasEntityHistoryRows, setChainMeta, pruneStaleCheckpoints, pruneStaleEntityHistory, getRollbackTargetCheckpoint, getRollbackProgressDiff, getRollbackData, writeBatch) and effectBatchCache type; PgStorage implements delete helpers, writeBatch orchestration, UTF‑8 escape/retry, and maps DB errors to StorageError.
Event processing / write flow
codegenerator/cli/templates/static/codegen/src/EventProcessing.res, codegenerator/cli/templates/static/codegen/src/IO.res
addItemToRawEvents gains ~config: Config.t and uses config.platform for cleanup/IDs; inline multi-step write logic removed in favor of centralized storage.writeBatch; rollback diff sourcing now uses storage.getRollbackData.
Generated templates & tests
codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs, codegenerator/cli/templates/dynamic/codegen/src/TestHelpers_MockDb.res.hbs, codegenerator/cli/templates/dynamic/codegen/src/Types.res.hbs, codegenerator/cli/npm/envio/src/InMemoryStore.gen.ts
Call sites updated to pass ~platform; removed per-ecosystem external getters/cleanup from template Types.Block; added generated TS rawEventsKey type; mock storage expanded with new methods matching Persistence.storage.
Global state / chain manager / helpers
codegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res, codegenerator/cli/templates/static/codegen/src/eventFetching/ChainManager.res, codegenerator/cli/templates/static/codegen/src/db/Migrations.res, codegenerator/cli/templates/static/codegen/src/UserContext.res, codegenerator/cli/templates/static/codegen/src/ink/components/CustomHooks.res
Use config.platform for timestamps and validation; updateProgressedChains now accepts ~indexer and calls storage helpers (setChainMeta, pruneStale*, getRollback*); migration unsafe invocations use storage.executeUnsafe.
DB batch deletion removal / DB functions
codegenerator/cli/templates/static/codegen/src/db/DbFunctionsEntities.res, codegenerator/cli/templates/static/codegen/src/db/DbFunctionsImplementation.js, codegenerator/cli/templates/static/codegen/src/db/Db.res
Removed batchDeleteItemsInTable, related helpers and JS implementation; removed publicSchema top-level binding; deletion responsibilities consolidated into PgStorage.
Test harness updates
scenarios/test_codegen/test/helpers/DbHelpers.res, scenarios/test_codegen/test/helpers/Mock.res, scenarios/test_codegen/test/lib_tests/Persistence_test.res, scenarios/test_codegen/test/schema_types/*.res
Tests updated to stop using Generated.codegenPersistence.sql, create sql via Db.makeClient() where needed, remove sql from Persistence.make calls, and match expanded mock storage API and new persistence call sites.
Templating struct update
codegenerator/cli/src/hbs_templating/codegen_templates.rs
Removed is_fuel: bool field from NetworkConfigTemplate; template generation updated to rely on platform data instead.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant EP as EventProcessing
  participant IM as InMemoryStore
  participant SZ as Persistence.storage
  participant PG as PgStorage
  participant DB as Postgres

  EP->>IM: collect raw events / build batch
  EP->>SZ: writeBatch(~batch, ~inMemoryStore=IM, ~isInReorgThreshold, ~config, ~allEntities, ~batchCache)
  SZ->>PG: delegate writeBatch
  alt normal
    PG->>DB: run deletes / updates / inserts / set raw events / checkpoint / effect cache
    DB-->>PG: success
    PG-->>SZ: ok
    SZ-->>EP: resolves
  else error
    DB-->>PG: error
    PG->>SZ: map to StorageError / retry (maybe PgEncodingError -> escape & retry)
    SZ-->>EP: rejects StorageError
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Areas needing extra attention:
    • PgStorage.writeBatch: orchestration, UTF‑8 escaping retry logic, rollback semantics, exception normalization to Persistence.StorageError.
    • Persistence public type changes: removal of sql and added methods — verify all call sites and tests updated.
    • Template and generated code updates: ensure generated code (Types/Generated/TestHelpers) aligns with runtime Platform API and mock storage.

Possibly related PRs

Suggested reviewers

  • JonoPrest
  • moose-code

Poem

🐰 A little rabbit taps the keys with glee,
Platforms swapped in, now Evm and Fuel agree.
Batches hum together, SQL tucked away,
Tests updated, mocks join the play.
Hoppy commits — a tidy patch for thee! 🎩

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Platform & Storage abstractions' directly reflects the main changes: introducing Platform abstraction (new Platform.res module) and refactoring Storage API surface across multiple files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dz/platform-abstraction

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 189424f and 107f7c4.

📒 Files selected for processing (2)
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs (0 hunks)
  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs (2 hunks)
💤 Files with no reviewable changes (1)
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
🧰 Additional context used
📓 Path-based instructions (3)
codegenerator/cli/**

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

The Rust CLI lives in codegenerator/cli

Files:

  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs
codegenerator/cli/templates/dynamic/**/*.hbs

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Dynamic templates are Handlebars files under codegenerator/cli/templates/dynamic

Files:

  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs
{codegenerator/cli/templates/static/codegen/src/**,codegenerator/cli/templates/dynamic/codegen/src/**}

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Template versions of runtime live under templates/{static,dynamic}/codegen/src and are the recommended editing targets

Files:

  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs
🧠 Learnings (1)
📚 Learning: 2025-10-21T16:31:22.127Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2025-10-21T16:31:22.127Z
Learning: Applies to codegenerator/cli/templates/dynamic/**/*.hbs : Dynamic templates are Handlebars files under codegenerator/cli/templates/dynamic

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build_and_test
🔇 Additional comments (4)
codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs (4)

101-101: LGTM: Aligns with platform abstraction.

The parameter change from ~ecosystem to ~platform correctly reflects the new platform abstraction model introduced in this PR.


183-187: LGTM: Storage abstraction properly configured.

The persistence configuration correctly uses the ~storage parameter, which wraps the SQL client through makeStorage. This aligns with the storage interface refactoring mentioned in the PR objectives.


92-92: The parameter naming is intentional and correct for each API.

The review comment misunderstands the design. These are two different APIs with appropriately different parameter names:

  • Config.make accepts ~ecosystem: Platform.name as a builder input (user specifies which ecosystem)
  • Config.make internally converts this to a platform: Platform.t field via Platform.fromName(ecosystem)
  • EventRegister.startRegistration then accepts that constructed ~platform: Platform.t object

This is not an incomplete migration or inconsistency—it's intentional API design where the builder accepts a high-level ecosystem specification and internally constructs the platform abstraction for consumption by EventRegister. The parameter names appropriately reflect their semantic roles.

Likely an incorrect or invalid review comment.


91-93: The scope concern appears unfounded; however, parameter naming inconsistency should be verified.

The is_fuel_ecosystem check at line 91 is appropriately global. This is consistent with the existing pattern: line 36 already accesses is_evm_ecosystem globally from within a nested chain loop (using ../../../ navigation). Since a single configuration aggregates all chains with one shared ecosystem/platform setting, the global scope is correct.

However, there is a potential parameter naming inconsistency: Config.make receives ~ecosystem=Fuel, but EventRegister.startRegistration accesses configWithoutRegistrations.platform. Please verify whether the Config.t type field is named ecosystem or platform—if it's platform, line 92 may need adjustment.


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

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@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: 1

🧹 Nitpick comments (1)
codegenerator/cli/npm/envio/src/PgStorage.res (1)

516-540: Optional guard for empty delete batches

Callers currently filter out empties, but adding an explicit fast-path keeps this helper robust if a future caller forgets. It also avoids issuing ANY($1::text[]) with an empty payload.

 let deleteByIdsOrThrow = async (sql, ~pgSchema, ~ids, ~table: Table.table) => {
-  switch await (
+  if ids->Array.length === 0 {
+    ()
+  } else switch await (
     switch ids {
     | [_] =>
       sql->Postgres.preparedUnsafe(
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1fc77a8 and 22b659e.

⛔ Files ignored due to path filters (1)
  • scenarios/test_codegen/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (16)
  • codegenerator/cli/npm/envio/src/Config.res (3 hunks)
  • codegenerator/cli/npm/envio/src/EventRegister.res (3 hunks)
  • codegenerator/cli/npm/envio/src/EventRegister.resi (1 hunks)
  • codegenerator/cli/npm/envio/src/InMemoryStore.gen.ts (1 hunks)
  • codegenerator/cli/npm/envio/src/PgStorage.res (3 hunks)
  • codegenerator/cli/npm/envio/src/Platform.res (1 hunks)
  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs (1 hunks)
  • codegenerator/cli/templates/dynamic/codegen/src/TestHelpers_MockDb.res.hbs (2 hunks)
  • codegenerator/cli/templates/dynamic/codegen/src/Types.res.hbs (0 hunks)
  • codegenerator/cli/templates/static/codegen/src/EventProcessing.res (5 hunks)
  • codegenerator/cli/templates/static/codegen/src/IO.res (0 hunks)
  • codegenerator/cli/templates/static/codegen/src/UserContext.res (1 hunks)
  • codegenerator/cli/templates/static/codegen/src/db/DbFunctionsEntities.res (0 hunks)
  • codegenerator/cli/templates/static/codegen/src/db/DbFunctionsImplementation.js (0 hunks)
  • codegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res (4 hunks)
  • codegenerator/cli/templates/static/codegen/src/ink/components/CustomHooks.res (1 hunks)
💤 Files with no reviewable changes (4)
  • codegenerator/cli/templates/static/codegen/src/db/DbFunctionsImplementation.js
  • codegenerator/cli/templates/dynamic/codegen/src/Types.res.hbs
  • codegenerator/cli/templates/static/codegen/src/IO.res
  • codegenerator/cli/templates/static/codegen/src/db/DbFunctionsEntities.res
🧰 Additional context used
📓 Path-based instructions (6)
codegenerator/cli/**

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

The Rust CLI lives in codegenerator/cli

Files:

  • codegenerator/cli/npm/envio/src/InMemoryStore.gen.ts
  • codegenerator/cli/templates/static/codegen/src/ink/components/CustomHooks.res
  • codegenerator/cli/npm/envio/src/EventRegister.resi
  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs
  • codegenerator/cli/templates/static/codegen/src/EventProcessing.res
  • codegenerator/cli/templates/dynamic/codegen/src/TestHelpers_MockDb.res.hbs
  • codegenerator/cli/templates/static/codegen/src/UserContext.res
  • codegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res
  • codegenerator/cli/npm/envio/src/PgStorage.res
  • codegenerator/cli/npm/envio/src/Config.res
  • codegenerator/cli/npm/envio/src/Platform.res
  • codegenerator/cli/npm/envio/src/EventRegister.res
codegenerator/cli/npm/envio/**

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Shared library-fied runtime lives in codegenerator/cli/npm/envio

Files:

  • codegenerator/cli/npm/envio/src/InMemoryStore.gen.ts
  • codegenerator/cli/npm/envio/src/EventRegister.resi
  • codegenerator/cli/npm/envio/src/PgStorage.res
  • codegenerator/cli/npm/envio/src/Config.res
  • codegenerator/cli/npm/envio/src/Platform.res
  • codegenerator/cli/npm/envio/src/EventRegister.res
codegenerator/cli/templates/static/**/*.res

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Static templates are raw ReScript files copied verbatim under codegenerator/cli/templates/static

Files:

  • codegenerator/cli/templates/static/codegen/src/ink/components/CustomHooks.res
  • codegenerator/cli/templates/static/codegen/src/EventProcessing.res
  • codegenerator/cli/templates/static/codegen/src/UserContext.res
  • codegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res
{codegenerator/cli/templates/static/codegen/src/**,codegenerator/cli/templates/dynamic/codegen/src/**}

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Template versions of runtime live under templates/{static,dynamic}/codegen/src and are the recommended editing targets

Files:

  • codegenerator/cli/templates/static/codegen/src/ink/components/CustomHooks.res
  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs
  • codegenerator/cli/templates/static/codegen/src/EventProcessing.res
  • codegenerator/cli/templates/dynamic/codegen/src/TestHelpers_MockDb.res.hbs
  • codegenerator/cli/templates/static/codegen/src/UserContext.res
  • codegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res
**/*.res

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Prefer reading ReScript .res modules directly

Files:

  • codegenerator/cli/templates/static/codegen/src/ink/components/CustomHooks.res
  • codegenerator/cli/templates/static/codegen/src/EventProcessing.res
  • codegenerator/cli/templates/static/codegen/src/UserContext.res
  • codegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res
  • codegenerator/cli/npm/envio/src/PgStorage.res
  • codegenerator/cli/npm/envio/src/Config.res
  • codegenerator/cli/npm/envio/src/Platform.res
  • codegenerator/cli/npm/envio/src/EventRegister.res
codegenerator/cli/templates/dynamic/**/*.hbs

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Dynamic templates are Handlebars files under codegenerator/cli/templates/dynamic

Files:

  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs
  • codegenerator/cli/templates/dynamic/codegen/src/TestHelpers_MockDb.res.hbs
🧠 Learnings (5)
📚 Learning: 2025-10-21T16:31:22.127Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2025-10-21T16:31:22.127Z
Learning: Applies to generated/src/EventProcessing.res : In generated runtime, EventProcessing.res handles processing

Applied to files:

  • codegenerator/cli/templates/static/codegen/src/EventProcessing.res
📚 Learning: 2025-10-21T16:31:22.127Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2025-10-21T16:31:22.127Z
Learning: Applies to generated/src/PgStorage.res : In generated runtime, PgStorage.res is part of the persistence stack

Applied to files:

  • codegenerator/cli/npm/envio/src/PgStorage.res
📚 Learning: 2025-05-27T17:07:04.699Z
Learnt from: JonoPrest
Repo: enviodev/hyperindex PR: 555
File: scenarios/test_codegen/test/lib_tests/EntityHistory_test.res:582-629
Timestamp: 2025-05-27T17:07:04.699Z
Learning: In ReScript test files using DbHelpers.resetPostgresClient(), this function is synchronous with signature `unit => unit` and should not be awaited. It performs a raw JavaScript reassignment of the postgres client and does not return a promise.

Applied to files:

  • codegenerator/cli/npm/envio/src/PgStorage.res
📚 Learning: 2025-10-21T16:31:22.127Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2025-10-21T16:31:22.127Z
Learning: Applies to generated/src/Config.res : In generated runtime, Config.res maps env to typed config and sets up persistence

Applied to files:

  • codegenerator/cli/npm/envio/src/Config.res
📚 Learning: 2025-10-21T16:31:22.127Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2025-10-21T16:31:22.127Z
Learning: Applies to codegenerator/cli/npm/envio/** : Shared library-fied runtime lives in codegenerator/cli/npm/envio

Applied to files:

  • codegenerator/cli/npm/envio/src/Config.res
🔇 Additional comments (25)
codegenerator/cli/npm/envio/src/InMemoryStore.gen.ts (1)

1-6: LGTM! Clean type definition for raw events key.

The new rawEventsKey type structure is well-defined with appropriate readonly modifiers and aligns with the platform abstraction changes.

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

100-104: LGTM! Parameter update aligns with platform abstraction.

The renaming from ~ecosystem to ~platform is consistent with the EventRegister.startRegistration signature change and correctly uses configWithoutRegistrations.platform.

codegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res (3)

233-233: LGTM! Platform-specific timestamp accessor correctly implemented.

The change from Types.Block.getTimestamp to indexer.config.platform.getTimestamp properly delegates to platform-specific behavior, improving flexibility across different blockchain platforms.


658-658: LGTM! Call sites correctly updated with indexer parameter.

Both invocations of updateProgressedChains properly pass ~indexer=state.indexer.

Also applies to: 757-757


200-200: All call sites are correctly updated with the new parameter.

Verification confirms both invocations of updateProgressedChains (lines 658 and 757 in GlobalState.res) properly pass the required ~indexer=state.indexer parameter. No other call sites exist in the codebase.

codegenerator/cli/templates/static/codegen/src/ink/components/CustomHooks.res (1)

37-37: LGTM! Clean migration to platform.name accessor.

The change correctly sources the ecosystem value from config.platform.name while maintaining the existing InitApi structure. The type coercion indicates proper variant compatibility.

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

322-322: LGTM! Address validation updated to use platform abstraction.

The condition correctly uses params.config.platform.name === Evm while preserving the existing address validation and lowercasing behavior.

codegenerator/cli/npm/envio/src/EventRegister.resi (1)

6-10: LGTM! Public API signature updated for platform abstraction.

The parameter change from ~ecosystem: Config.ecosystem to ~platform: Platform.t is consistent with the broader refactoring. This is a breaking change to the public API, so ensure any external consumers are aware.

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

46-50: LGTM! Test helper updated with platform parameter.

The EventRegister.startRegistration call correctly uses ~platform=config.platform instead of the previous ~ecosystem parameter.


373-379: LGTM! Event processing updated to use platform-specific accessors.

The changes correctly replace Types.Block getters with config.platform.getTimestamp and config.platform.getNumber, consistently applying the platform abstraction throughout event item creation and block number tracking.

codegenerator/cli/npm/envio/src/Config.res (4)

48-48: LGTM! Config type updated to platform abstraction.

The replacement of ecosystem with platform: Platform.t in the public type t is the foundation of this refactoring and enables platform-specific behavior throughout the system.


63-63: LGTM! Parameter type and default value are appropriate.

The parameter ~ecosystem: Platform.name=Platform.Evm properly defaults to EVM and accepts a platform name that will be converted to a Platform.t instance.


95-108: LGTM! Config construction properly uses platform.

The return object correctly includes the platform field (line 102) derived from the fromName translation, completing the migration from ecosystem to platform abstraction.


93-93: Code is correct—all ecosystem values are properly handled.

The Platform.fromName function correctly handles all ecosystem values. The type system guarantees completeness:

  • The Platform.name type has exactly two variants: Evm and Fuel
  • The fromName function's switch statement covers both variants
  • The ecosystem parameter is typed as Platform.name, ensuring only valid values reach the function
  • ReScript's exhaustive pattern matching enforces completeness at compile time

No additional handling needed.

codegenerator/cli/templates/static/codegen/src/EventProcessing.res (3)

50-50: LGTM! Platform abstraction properly integrated.

The addition of the ~config parameter enables platform-specific block field cleanup and ID retrieval, making the function work correctly across EVM and Fuel platforms.

Also applies to: 64-64, 88-88


223-223: LGTM! Call site correctly updated.

The function call properly passes the config parameter from the indexer.


424-458: LGTM! Error handling properly centralized.

The refactored error handling around the DB write provides better exception management with specific handling for Persistence.StorageError and a fallback for unexpected errors.

codegenerator/cli/npm/envio/src/EventRegister.res (1)

7-7: LGTM! Platform field migration is consistent.

The migration from ecosystem to platform: Platform.t is properly applied across the type definition, function signature, and record construction.

Also applies to: 39-41

codegenerator/cli/npm/envio/src/Platform.res (4)

1-14: LGTM! Well-designed platform abstraction types.

The Platform.t type provides a clean interface for platform-specific behavior, with the name variant enabling type-safe platform identification and accessor functions supporting polymorphic operations.


16-26: LGTM! Platform-specific modules properly implemented.

The Evm and Fuel modules correctly define external bindings for their respective block field names and provide efficient in-place cleanup functions using raw JavaScript.

Also applies to: 103-113


28-101: LGTM! Platform constants comprehensively defined.

The evm and fuel constants provide complete field lists, including EVM's extensive block/transaction fields (with L2-specific additions) and Fuel's simpler structure, properly wired to their respective module implementations.

Also applies to: 115-126


128-133: LGTM! Clean factory function.

The fromName function provides a straightforward way to obtain the appropriate platform instance from a name variant.

codegenerator/cli/npm/envio/src/PgStorage.res (3)

179-185: Delete helpers match existing read helpers

The single- vs multi-id shape mirrors makeLoadById(s) above, so the storage API stays symmetrical and easy to reason about. Nice touch.


953-963: Nice abstraction for conditional batch writes

Wrapping the "only touch SQL when there’s work" pattern keeps Promise plumbing tidy in the transactional path. Reads well.


965-1301: Retry + escape loop looks solid

The targeted PgEncodingError retry with table-scoped UTF-8 cleanup, plus the shared specificError handoff, gives us a predictable path to recovery without double-reporting errors. Thanks for threading the history backfill, deletes, and effect cache in a single transactional view.

switch registration.ecosystem {
| Evm => ()
| Fuel =>
if registration.platform !== Platform.evm {
Copy link
Contributor

@coderabbitai coderabbitai bot Nov 10, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix object reference comparison for platform check.

The comparison registration.platform !== Platform.evm uses reference inequality (!==), which compares object identities rather than values. This is fragile and may fail if Platform.t instances are recreated anywhere in the codebase.

Apply this diff to compare the platform name instead:

-    if registration.platform !== Platform.evm {
+    if registration.platform.name !== Platform.Evm {

This compares the name enum variant, which is the correct semantic check and is robust regardless of how Platform.t instances are constructed.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if registration.platform !== Platform.evm {
if registration.platform.name !== Platform.Evm {
🤖 Prompt for AI Agents
In codegenerator/cli/npm/envio/src/EventRegister.res around line 84, the check
uses reference inequality "registration.platform !== Platform.evm" which
compares object identity; replace it with a value comparison of the enum variant
name, e.g. use "registration.platform.name !== Platform.evm.name" (or
pattern-match on Platform.evm) so the platform comparison is based on the
variant value rather than object identity.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@DZakh I assume this is intended behaviour? They are global objects?

Copy link
Contributor

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Copy link
Member Author

Choose a reason for hiding this comment

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

Eah, it'll be fine in this case, but ideally to do it as rabbit suggests. Although, the code is removed in the next PR, so we are fine.

@DZakh DZakh changed the title Platform abstraction Platform & Storage abstractions Nov 10, 2025
Comment on lines +86 to +126
// Execute raw SQL query
executeUnsafe: string => promise<unknown>,
// Check if entity history has rows
hasEntityHistoryRows: unit => promise<bool>,
// Update chain metadata
setChainMeta: dict<InternalTable.Chains.metaFields> => promise<unknown>,
// Prune old checkpoints
pruneStaleCheckpoints: int => promise<unit>,
// Prune stale entity history
pruneStaleEntityHistory: (
~entityName: string,
~entityIndex: int,
~safeCheckpointId: int,
) => promise<unit>,
// Get rollback target checkpoint
getRollbackTargetCheckpoint: (
~reorgChainId: int,
~lastKnownValidBlockNumber: int,
) => promise<array<{"id": int}>>,
// Get rollback progress diff
getRollbackProgressDiff: int => promise<
array<{
"chain_id": int,
"events_processed_diff": string,
"new_progress_block_number": int,
}>,
>,
// Get rollback data for entity
getRollbackData: (
~entityConfig: Internal.entityConfig,
~rollbackTargetCheckpointId: int,
) => promise<(array<{"id": string}>, array<unknown>)>,
// Write batch to storage
writeBatch: (
~batch: Batch.t,
~inMemoryStore: InMemoryStore.t,
~isInReorgThreshold: bool,
~config: Config.t,
~allEntities: array<Internal.entityConfig>,
~batchCache: array<effectBatchCache>,
) => promise<unit>,
Copy link
Member Author

Choose a reason for hiding this comment

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

This is not very reusable, but we'll be able to clean it up with time

@DZakh DZakh requested a review from JonoPrest November 10, 2025 10:52
Copy link
Contributor

@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 (6)
codegenerator/cli/templates/static/codegen/src/EventProcessing.res (1)

437-468: Consider extracting batchCache construction into a helper function.

The batchCache construction logic is correct but deeply nested, which impacts readability. Consider extracting it into a separate function like buildBatchCacheFromEffects.

For example:

let buildBatchCacheFromEffects = (
  effects: Js.Dict.t<'a>,
  persistence: Persistence.t,
) => {
  effects
  ->Js.Dict.keys
  ->Belt.Array.keepMapU(effectName => {
    let inMemTable = effects->Js.Dict.unsafeGet(effectName)
    let {idsToStore, dict, effect, invalidationsCount} = inMemTable
    switch idsToStore {
    | [] => None
    | ids => {
        let items = Belt.Array.makeUninitializedUnsafe(ids->Belt.Array.length)
        ids->Belt.Array.forEachWithIndex((index, id) => {
          items->Js.Array2.unsafe_set(
            index,
            ({id, output: dict->Js.Dict.unsafeGet(id)}: Internal.effectCacheItem),
          )
        })
        Some(
          persistence->Persistence.getEffectBatchCache(
            ~effect,
            ~items,
            ~invalidationsCount,
          ),
        )
      }
    }
  })
}

Then use it in the writeBatch call:

~batchCache=buildBatchCacheFromEffects(
  inMemoryStore.effects,
  indexer.persistence,
)
scenarios/test_codegen/test/helpers/Mock.res (1)

187-205: Verify test coverage for new storage methods.

The new storage method stubs return empty/default values. While appropriate for basic mocking, ensure that tests requiring realistic behavior from these methods (especially writeBatch, getRollbackData, and getRollbackProgressDiff) have dedicated test implementations or use actual storage.

Consider whether any existing or planned tests need more sophisticated mock implementations for these methods to properly validate rollback and batch-write logic.

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

590-605: Mock storage implementations are minimal.

Similar to the main Mock.res file, these storage method stubs return empty/default values. Ensure tests that exercise batch writing and rollback logic have appropriate mock behavior or use real storage.

codegenerator/cli/npm/envio/src/Persistence.res (1)

86-127: Storage interface significantly expanded.

The addition of executeUnsafe, hasEntityHistoryRows, setChainMeta, pruning methods, and rollback helpers centralizes storage operations. However, some return types use unknown which reduces type safety.

Consider strengthening return types where possible:

  • Line 87: executeUnsafe could return promise<array<unknown>> to indicate it returns rows
  • Line 91: setChainMeta could return promise<unit> instead of promise<unknown>

These changes would improve type safety and documentation.

Also applies to: 142-143

codegenerator/cli/npm/envio/src/PgStorage.res (2)

554-868: Complex batch write implementation with retry logic.

The writeBatch function is comprehensive but very large (~315 lines). Key observations:

Strengths:

  • Proper transaction boundaries with Postgres.beginSql
  • Handles history backfilling before updates (lines 645-654)
  • UTF-8 encoding error retry with targeted escaping (lines 848-867)
  • Normalizes exception types for consistent handling (lines 718-722)
  • Separates effect cache writes from main transaction (lines 824-830)

Complexity concerns:

  • The specificError ref pattern (line 569) for error propagation through nested async operations is intricate
  • Nested try-catch blocks with different error handling strategies
  • The UTF-8 retry mechanism adds another layer of control flow

Consider extracting helper functions for:

  1. History processing (lines 612-688): processEntityHistory
  2. Entity sets and deletes (lines 691-708): processEntityUpdates
  3. Error normalization logic (lines 718-745): normalizeStorageError

This would improve readability and testability without changing functionality. However, given this is a major refactor introducing the new storage API, these improvements can be deferred to a follow-up PR.


1271-1300: Potential edge case in hasEntityHistoryRows.

The implementation checks if any history table has rows, but:

  • Line 1279: Returns false if no history tables exist
  • Lines 1286-1295: Swallows exceptions and returns false for each table check

This might hide legitimate errors (e.g., permission issues). Consider logging exceptions before returning false, or allowing certain exceptions to propagate.

Example improvement:

          } catch {
-         | _ => false
+         | exn => {
+             Logging.warn({
+               "msg": "Failed to check entity history rows",
+               "table": table["table_name"],
+               "error": exn
+             })
+             false
+           }
          }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 22b659e and 189424f.

📒 Files selected for processing (15)
  • codegenerator/cli/npm/envio/src/Persistence.res (5 hunks)
  • codegenerator/cli/npm/envio/src/PgStorage.res (4 hunks)
  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs (1 hunks)
  • codegenerator/cli/templates/dynamic/codegen/src/TestHelpers_MockDb.res.hbs (3 hunks)
  • codegenerator/cli/templates/static/codegen/src/EventProcessing.res (5 hunks)
  • codegenerator/cli/templates/static/codegen/src/IO.res (1 hunks)
  • codegenerator/cli/templates/static/codegen/src/db/Db.res (0 hunks)
  • codegenerator/cli/templates/static/codegen/src/db/Migrations.res (1 hunks)
  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainManager.res (1 hunks)
  • codegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res (8 hunks)
  • scenarios/test_codegen/test/helpers/DbHelpers.res (1 hunks)
  • scenarios/test_codegen/test/helpers/Mock.res (1 hunks)
  • scenarios/test_codegen/test/lib_tests/Persistence_test.res (2 hunks)
  • scenarios/test_codegen/test/schema_types/BigDecimal_test.res (1 hunks)
  • scenarios/test_codegen/test/schema_types/Timestamp_test.res (1 hunks)
💤 Files with no reviewable changes (1)
  • codegenerator/cli/templates/static/codegen/src/db/Db.res
🧰 Additional context used
📓 Path-based instructions (6)
**/*.res

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Prefer reading ReScript .res modules directly

Files:

  • scenarios/test_codegen/test/schema_types/Timestamp_test.res
  • codegenerator/cli/templates/static/codegen/src/db/Migrations.res
  • scenarios/test_codegen/test/helpers/DbHelpers.res
  • codegenerator/cli/templates/static/codegen/src/IO.res
  • codegenerator/cli/templates/static/codegen/src/EventProcessing.res
  • scenarios/test_codegen/test/helpers/Mock.res
  • scenarios/test_codegen/test/schema_types/BigDecimal_test.res
  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainManager.res
  • codegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res
  • scenarios/test_codegen/test/lib_tests/Persistence_test.res
  • codegenerator/cli/npm/envio/src/Persistence.res
  • codegenerator/cli/npm/envio/src/PgStorage.res
codegenerator/cli/**

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

The Rust CLI lives in codegenerator/cli

Files:

  • codegenerator/cli/templates/static/codegen/src/db/Migrations.res
  • codegenerator/cli/templates/static/codegen/src/IO.res
  • codegenerator/cli/templates/static/codegen/src/EventProcessing.res
  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainManager.res
  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs
  • codegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res
  • codegenerator/cli/npm/envio/src/Persistence.res
  • codegenerator/cli/npm/envio/src/PgStorage.res
  • codegenerator/cli/templates/dynamic/codegen/src/TestHelpers_MockDb.res.hbs
codegenerator/cli/templates/static/**/*.res

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Static templates are raw ReScript files copied verbatim under codegenerator/cli/templates/static

Files:

  • codegenerator/cli/templates/static/codegen/src/db/Migrations.res
  • codegenerator/cli/templates/static/codegen/src/IO.res
  • codegenerator/cli/templates/static/codegen/src/EventProcessing.res
  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainManager.res
  • codegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res
{codegenerator/cli/templates/static/codegen/src/**,codegenerator/cli/templates/dynamic/codegen/src/**}

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Template versions of runtime live under templates/{static,dynamic}/codegen/src and are the recommended editing targets

Files:

  • codegenerator/cli/templates/static/codegen/src/db/Migrations.res
  • codegenerator/cli/templates/static/codegen/src/IO.res
  • codegenerator/cli/templates/static/codegen/src/EventProcessing.res
  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainManager.res
  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs
  • codegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res
  • codegenerator/cli/templates/dynamic/codegen/src/TestHelpers_MockDb.res.hbs
codegenerator/cli/templates/dynamic/**/*.hbs

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Dynamic templates are Handlebars files under codegenerator/cli/templates/dynamic

Files:

  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs
  • codegenerator/cli/templates/dynamic/codegen/src/TestHelpers_MockDb.res.hbs
codegenerator/cli/npm/envio/**

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Shared library-fied runtime lives in codegenerator/cli/npm/envio

Files:

  • codegenerator/cli/npm/envio/src/Persistence.res
  • codegenerator/cli/npm/envio/src/PgStorage.res
🧠 Learnings (8)
📚 Learning: 2025-05-27T17:07:04.699Z
Learnt from: JonoPrest
Repo: enviodev/hyperindex PR: 555
File: scenarios/test_codegen/test/lib_tests/EntityHistory_test.res:582-629
Timestamp: 2025-05-27T17:07:04.699Z
Learning: In ReScript test files using DbHelpers.resetPostgresClient(), this function is synchronous with signature `unit => unit` and should not be awaited. It performs a raw JavaScript reassignment of the postgres client and does not return a promise.

Applied to files:

  • scenarios/test_codegen/test/schema_types/Timestamp_test.res
  • codegenerator/cli/templates/static/codegen/src/db/Migrations.res
  • scenarios/test_codegen/test/helpers/DbHelpers.res
  • codegenerator/cli/npm/envio/src/PgStorage.res
📚 Learning: 2025-10-21T16:31:22.127Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2025-10-21T16:31:22.127Z
Learning: Applies to generated/src/PgStorage.res : In generated runtime, PgStorage.res is part of the persistence stack

Applied to files:

  • codegenerator/cli/templates/static/codegen/src/db/Migrations.res
  • scenarios/test_codegen/test/helpers/DbHelpers.res
  • scenarios/test_codegen/test/lib_tests/Persistence_test.res
  • codegenerator/cli/npm/envio/src/Persistence.res
  • codegenerator/cli/npm/envio/src/PgStorage.res
📚 Learning: 2025-10-21T16:31:22.127Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2025-10-21T16:31:22.127Z
Learning: Applies to generated/src/IO.res : In generated runtime, IO.res is used by persistence and processing

Applied to files:

  • codegenerator/cli/templates/static/codegen/src/IO.res
📚 Learning: 2025-05-27T17:07:12.878Z
Learnt from: JonoPrest
Repo: enviodev/hyperindex PR: 555
File: scenarios/test_codegen/test/lib_tests/EntityHistory_test.res:631-659
Timestamp: 2025-05-27T17:07:12.878Z
Learning: In isolated tests for EntityHistory rollbacks with controlled mock data setup, the ordering of getRollbackDiff results is deterministic and doesn't require sorting before comparison with deepStrictEqual.

Applied to files:

  • codegenerator/cli/templates/static/codegen/src/IO.res
  • scenarios/test_codegen/test/helpers/Mock.res
📚 Learning: 2025-10-21T16:31:22.127Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2025-10-21T16:31:22.127Z
Learning: Applies to generated/src/EventProcessing.res : In generated runtime, EventProcessing.res handles processing

Applied to files:

  • codegenerator/cli/templates/static/codegen/src/EventProcessing.res
📚 Learning: 2025-10-21T16:31:22.127Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2025-10-21T16:31:22.127Z
Learning: Applies to generated/src/ChainManager.res : In generated runtime, ChainManager.res is part of the fetch side

Applied to files:

  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainManager.res
📚 Learning: 2025-10-21T16:31:22.127Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2025-10-21T16:31:22.127Z
Learning: Applies to generated/src/Persistence.res : In generated runtime, Persistence.res is part of the persistence stack

Applied to files:

  • scenarios/test_codegen/test/lib_tests/Persistence_test.res
  • codegenerator/cli/npm/envio/src/Persistence.res
📚 Learning: 2025-10-21T16:31:22.127Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2025-10-21T16:31:22.127Z
Learning: Applies to generated/src/Hasura.res : In generated runtime, Hasura.res is part of the persistence stack

Applied to files:

  • scenarios/test_codegen/test/lib_tests/Persistence_test.res
  • codegenerator/cli/npm/envio/src/Persistence.res
🔇 Additional comments (14)
codegenerator/cli/templates/static/codegen/src/EventProcessing.res (3)

50-54: LGTM! Platform abstraction properly integrated.

The addition of the ~config parameter and usage of config.platform.cleanUpRawEventFieldsInPlace (line 68) and config.platform.getId (line 92) correctly implements the platform abstraction pattern described in the PR objectives.

Also applies to: 68-68, 92-92


227-229: LGTM! Call site updated correctly.

The call to addItemToRawEvents now properly passes the ~config=indexer.config parameter, matching the updated function signature.


430-495: LGTM! Unified batch writing with proper error handling.

The refactor successfully centralizes batch writing logic with the new storage.writeBatch call. The error handling appropriately distinguishes between Persistence.StorageError and generic exceptions, and timing metrics are correctly preserved.

scenarios/test_codegen/test/lib_tests/Persistence_test.res (1)

7-7: LGTM! API usage correctly updated.

The removal of the sql parameter aligns with the new persistence API surface where storage methods are accessed through persistence.storage instead of direct SQL access.

Also applies to: 133-133

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

47-47: Platform abstraction correctly applied.

The parameter change from ~ecosystem to ~platform aligns with the PR's platform abstraction goal.


373-379: No compatibility issues found—the code change is correct.

The Platform.t interface properly defines both getTimestamp and getNumber methods with signatures accepting Internal.eventBlock objects:

type t = {
  getNumber: Internal.eventBlock => int,
  getTimestamp: Internal.eventBlock => int,
  // ... other fields
}

Both methods are implemented in platform-specific modules (Evm and Fuel) and return integers as expected. The usage event.block->config.platform.getTimestamp and event.block->config.platform.getNumber is fully compatible with these signatures.

codegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res (3)

198-198: Function signature change propagated correctly.

The addition of ~indexer: Indexer.t parameter to updateProgressedChains and its usage at all call sites (lines 656, 755) maintains consistency. This enables platform-based timestamp access within the function.

Also applies to: 656-656, 755-755


231-231: Platform-based timestamp access.

Accessing block timestamp via indexer.config.platform.getTimestamp(eventItem.event.block) correctly uses the new platform abstraction. This provides better support for different blockchain platforms (EVM, Fuel, etc.).


190-191: Storage API migration completed successfully.

The migration from direct SQL calls to storage-based methods is comprehensive:

  • setChainMeta replaces SQL-based chain metadata updates
  • pruneStaleCheckpoints and pruneStaleEntityHistory replace SQL-based pruning
  • getRollbackTargetCheckpoint and getRollbackProgressDiff replace SQL-based rollback queries

This abstraction improves testability and separates storage concerns from business logic.

Also applies to: 821-821, 833-837, 1020-1037

codegenerator/cli/npm/envio/src/Persistence.res (2)

39-44: Good separation of concerns.

The new effectBatchCache type enables callers to determine cache initialization strategy while keeping the cache metadata management within Persistence. This is a cleaner API than having getEffectBatchCache (formerly setEffectCacheOrThrow) directly call storage.


242-264: API refactoring verified as correct.

The return value from getEffectBatchCache is properly handled throughout the call chain:

  1. EventProcessing.res (line 459) calls getEffectBatchCache and passes the result to writeBatch via the ~batchCache parameter
  2. PgStorage.res (lines 826-830) receives batchCache and correctly delegates persistence by calling setEffectCacheOrThrow for each cache item

The refactoring successfully shifts responsibility to the caller as intended, with no unhandled return values.

codegenerator/cli/npm/envio/src/PgStorage.res (3)

179-185: Delete operations properly implemented.

The delete query builders and deleteByIdsOrThrow correctly handle both single and batch deletions, with appropriate error wrapping in Persistence.StorageError.

Also applies to: 516-540


542-552: Good optimization pattern.

The executeSet helper avoids unnecessary database calls when the items array is empty. This is a useful micro-optimization for batch operations.


1269-1390: Storage method implementations look correct.

All new storage methods are properly implemented:

  • executeUnsafe: Direct SQL passthrough (line 1269)
  • hasEntityHistoryRows: Checks for entity history data (lines 1271-1300)
  • setChainMeta: Wraps chain metadata update (lines 1302-1305)
  • Rollback helpers: Properly delegate to internal modules (lines 1307-1350)
  • writeBatchMethod: Wrapper for internal writeBatch (lines 1352-1371)

let deleteByIdsOrThrow = async (sql, ~pgSchema, ~ids, ~table: Table.table) => {
switch await (
switch ids {
| [_] =>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should we handle the empty case here?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Is there any logic in this file that's changed? Or all just moved from IO.res?

Copy link
Member Author

Choose a reason for hiding this comment

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

All moved from IO + moved pgSchema and all direct access to Db to the storage methods

Comment on lines +30 to +33
blockFields: [
"number",
"timestamp",
"hash",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Haven't found where this is used yet but would love it if this would come from the client.

Copy link
Member Author

Choose a reason for hiding this comment

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

Not used yet, but I plan to use it to create a prototype for the block and transaciton object. What do you mean by client?

"sendRoot",
"mixHash",
],
transactionFields: [
Copy link
Collaborator

Choose a reason for hiding this comment

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

Also just noting, some of these fields are only hypersync transactions. Or otherwise it's a combination of transactions and transactionReceipts on regular RPC

Comment on lines +591 to +605
hasEntityHistoryRows: () => Promise.resolve(false),
setChainMeta: _ => Promise.resolve(%raw(`undefined`)),
pruneStaleCheckpoints: _ => Promise.resolve(),
pruneStaleEntityHistory: (~entityName as _, ~entityIndex as _, ~safeCheckpointId as _) => Promise.resolve(),
getRollbackTargetCheckpoint: (~reorgChainId as _, ~lastKnownValidBlockNumber as _) => Promise.resolve([]),
getRollbackProgressDiff: _ => Promise.resolve([]),
getRollbackData: (~entityConfig as _, ~rollbackTargetCheckpointId as _) => Promise.resolve(([], [])),
writeBatch: (
~batch as _,
~inMemoryStore as _,
~isInReorgThreshold as _,
~config as _,
~allEntities as _,
~batchCache as _,
) => Promise.resolve(),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should these maybe reject? Or do they get called during a test?

Copy link
Member Author

Choose a reason for hiding this comment

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

No, they are not called.

Copy link
Member Author

Choose a reason for hiding this comment

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

Makes sense to make them fail

Comment on lines +438 to +445
inMemoryStore.effects
->Js.Dict.keys
->Belt.Array.keepMapU(effectName => {
let inMemTable = inMemoryStore.effects->Js.Dict.unsafeGet(effectName)
let {idsToStore, dict, effect, invalidationsCount} = inMemTable
switch idsToStore {
| [] => None
| ids => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is this always a function on inMemoryStore? Perhaps this should be done inside of writeBatchFunction since inMemoryStore is passed in

Copy link
Collaborator

Choose a reason for hiding this comment

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

Turn this file into a Rollback module or remove

Copy link
Collaborator

@JonoPrest JonoPrest left a comment

Choose a reason for hiding this comment

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

💪🏼

@DZakh DZakh merged commit 4f34a2b into main Nov 12, 2025
2 checks passed
@DZakh DZakh deleted the dz/platform-abstraction branch November 12, 2025 10:19
This was referenced Nov 12, 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.

4 participants