feat(indexer/common): create core ledger cursor table#41
Conversation
…col#24) - Add ledger_cursor SQL migration (0001_create_ledger_cursor.sql) - BIGSERIAL primary key, UNIQUE(source, domain) constraint - CHECK constraints: non-empty source/domain, seq >= 0 - Index on last_ledger_seq for monitoring queries - schema_migrations bookkeeping table for idempotent runs - Add LedgerCursor type and SqlClient type alias (ledger-cursor.ts) - findCursor(sql, source, domain): returns cursor or null - upsertCursor(sql, source, domain, lastLedgerSeq): insert-or-advance with stale-write guard (only advances if new seq > existing) - Add migration runner (migrate.ts) - Reads *.sql files from migrations/ sorted lexicographically - Executes each file idempotently via sql.unsafe() - INDEXER_DATABASE_URL env var; db:migrate npm script - Add @types/node devDependency and node types in tsconfig - Export all public API from index.ts - 16 tests covering findCursor, upsertCursor (in-memory mock) Closes Fundable-Protocol#24
|
@playmaker410 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
📝 WalkthroughWalkthroughAdds a ledger cursor table migration, migration runner wiring, and a new cursor repository with lookup/upsert behavior, tests, exports, and TypeScript settings. ChangesLedger cursor persistence and migration setup
Sequence Diagram(s)sequenceDiagram
participant upsertCursor
participant SqlClient
participant ledger_cursor
participant findCursor
upsertCursor->>SqlClient: INSERT ... ON CONFLICT ... last_ledger_seq
SqlClient->>ledger_cursor: write or advance cursor row
alt no row returned
upsertCursor->>findCursor: re-read source and domain
findCursor->>SqlClient: SELECT cursor row
SqlClient->>ledger_cursor: fetch row
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related issues
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration. 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@indexer/common/src/db/migrate.ts`:
- Around line 45-48: The exported runMigrations helper currently looks for the
migrations directory next to the compiled module, so the SQL files must be
available in the built package. Update the build/package flow for the db
migration path so the src/db/migrations/*.sql assets are copied or otherwise
shipped alongside the emitted JS used by runMigrations, or revert the API to
source-only if that packaging is not intended. Use runMigrations,
listMigrationFiles, and the migrationsDir resolution logic as the main places to
adjust.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 736d7011-eca3-4f7d-81ba-47772b98fe5e
⛔ Files ignored due to path filters (1)
indexer/bun.lockis excluded by!**/*.lock
📒 Files selected for processing (8)
indexer/common/package.jsonindexer/common/src/cursor/ledger-cursor.test.tsindexer/common/src/cursor/ledger-cursor.tsindexer/common/src/db/migrate.tsindexer/common/src/db/migrations/0001_create_ledger_cursor.sqlindexer/common/src/index.tsindexer/common/tsconfig.jsonpackage.json
| export async function runMigrations(databaseUrl: string): Promise<void> { | ||
| const migrationsDir = join(fileURLToPath(import.meta.url), "..", "migrations"); | ||
|
|
||
| const files = await listMigrationFiles(migrationsDir); |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift
Package the SQL migrations alongside runMigrations.
Line 46 resolves migrations/ next to the executing module, but this PR only shows source-time execution for the CLI. I don't see a matching step that makes src/db/migrations/*.sql available beside the compiled JS, so the newly exported runMigrations API can fail with ENOENT when invoked from the built package. Either ship the SQL assets with the build or keep this runner source-only.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@indexer/common/src/db/migrate.ts` around lines 45 - 48, The exported
runMigrations helper currently looks for the migrations directory next to the
compiled module, so the SQL files must be available in the built package. Update
the build/package flow for the db migration path so the src/db/migrations/*.sql
assets are copied or otherwise shipped alongside the emitted JS used by
runMigrations, or revert the API to source-only if that packaging is not
intended. Use runMigrations, listMigrationFiles, and the migrationsDir
resolution logic as the main places to adjust.
Summary
Implements issue #24 — durable progress tracking for the Soroban event poller.
Changes
Migration —
0001_create_ledger_cursor.sqlschema_migrationsbookkeeping table (idempotent, guarded run)ledger_cursortable:BIGSERIALsurrogate PKUNIQUE(source, domain)— the natural identity for a cursorCHECKconstraints: non-empty source/domain,last_ledger_seq >= 0last_ledger_seq WHERE NOT NULLfor monitoring/backfill queriesCursor repository —
ledger-cursor.tsLedgerCursorinterface:id,source,domain,last_ledger_seq,created_at,updated_atSqlClienttype alias: minimal tagged-template signature; nopostgresimport needed in callers/testsfindCursor(sql, source, domain)— SELECT by(source, domain), returnsLedgerCursor | nullupsertCursor(sql, source, domain, lastLedgerSeq)— INSERT … ON CONFLICT DO UPDATE with stale-write guard; falls back tofindCursorif the WHERE suppresses the updateMigration runner —
migrate.ts*.sqlfiles frommigrations/lexicographicallysql.unsafe()(idempotency enforced inside SQL)INDEXER_DATABASE_URLenv var;db:migratescript in package.jsonindexer:db:migrateconvenience script addedPackage config
@types/nodedevDependency added toindexer/commontsconfig.jsonupdated withtypes: ["node", "vitest/globals"]index.tsTests
16 tests covering
findCursorandupsertCursorusing an in-memorySqlClientmock (no database required):Acceptance criteria checklist
bun run indexer:type-checkpassesbun run indexer:testpassesbun run indexer:lintpassesCloses #24
Summary by CodeRabbit
New Features
Bug Fixes
Tests