TypeORM adapter for Universal Inbox-Outbox Pattern (PostgreSQL)
npm install @prodforcode/event-forge-typeormTypeORM adapter for Event-Forge - Universal Inbox-Outbox Pattern implementation for PostgreSQL.
``bash`
npm install @prodforcode/event-forge-typeorm typeorm
- ✅ PostgreSQL 12+ compatible
- ✅ TypeORM entity definitions for outbox and inbox messages
- ✅ Optimized repository implementations with SELECT FOR UPDATE SKIP LOCKED
- ✅ Automatic database migration generation
- ✅ CLI tool for migration management
- ✅ Migration versioning and tracking system
- ✅ Automatic migration discovery and execution
- ✅ Full TypeScript support
Event-Forge provides a CLI tool to generate database migrations without requiring an active TypeORM connection.
#### Generate SQL to stdout
`bash`
npx event-forge migration:generate
#### Generate SQL file
`bash`
npx event-forge migration:generate --format=sql --output=./migrations
#### Generate TypeORM migration class
`bash`
npx event-forge migration:generate --format=typeorm --output=./migrations
#### Custom table names and schema
`bash`
npx event-forge migration:generate \
--format=sql \
--output=./migrations \
--schema=messaging \
--outbox-table=my_outbox \
--inbox-table=my_inbox
After generating the migration, apply it to your database:
#### Using raw SQL
`bash`
psql -d your_database -f migrations/20260109-event-forge-migration.sql
#### Using TypeORM migrations
`bash`
npm run typeorm migration:run
`typescript
import { DataSource } from 'typeorm';
import {
OutboxMessageEntity,
InboxMessageEntity,
TypeORMOutboxRepository,
TypeORMInboxRepository,
} from '@prodforcode/event-forge-typeorm';
import { OutboxService, InboxService } from '@prodforcode/event-forge-core';
// Initialize TypeORM DataSource
const dataSource = new DataSource({
type: 'postgres',
host: 'localhost',
port: 5432,
username: 'postgres',
password: 'postgres',
database: 'myapp',
entities: [OutboxMessageEntity, InboxMessageEntity],
synchronize: false, // Use migrations instead
});
await dataSource.initialize();
// Create repositories
const outboxRepo = new TypeORMOutboxRepository(
dataSource.getRepository(OutboxMessageEntity),
);
const inboxRepo = new TypeORMInboxRepository(
dataSource.getRepository(InboxMessageEntity),
);
// Create services
const outboxService = new OutboxService(outboxRepo, publisher);
const inboxService = new InboxService(inboxRepo);
// Use in your business logic
await dataSource.transaction(async (manager) => {
// Your business logic here
await manager.save(order);
// Create outbox message within same transaction
await outboxService.createMessage(
{
aggregateType: 'Order',
aggregateId: order.id,
eventType: 'OrderCreated',
payload: { orderId: order.id, amount: order.total },
},
manager, // Pass transaction manager for transactional outbox
);
});
`
You can also generate migrations programmatically:
`typescript
import {
getEventForgeUpSQL,
getEventForgeDownSQL,
generateMigrationClass,
generateRawSQLFile,
} from '@prodforcode/event-forge-typeorm';
// Generate UP migration SQL
const upSQL = getEventForgeUpSQL({
schema: 'messaging',
outboxTable: 'outbox_messages',
inboxTable: 'inbox_messages',
});
// Generate DOWN migration SQL
const downSQL = getEventForgeDownSQL({
schema: 'messaging',
outboxTable: 'outbox_messages',
inboxTable: 'inbox_messages',
});
// Generate TypeORM migration class
const migrationClass = generateMigrationClass({
schema: 'messaging',
});
// Generate complete SQL file with comments
const sqlFile = generateRawSQLFile({
schema: 'messaging',
});
// Write to file
import * as fs from 'fs';
fs.writeFileSync('migration.sql', sqlFile);
`
Event-Forge includes a comprehensive migration management system that tracks applied migrations and automatically discovers pending ones when upgrading between versions.
See MIGRATIONS.md for complete documentation.
When upgrading Event-Forge (e.g., 1.0.5 → 1.0.6), the migration system:
1. Tracks which migrations have been applied
2. Discovers new migrations from the package
3. Runs pending migrations automatically or on-demand
4. Supports rollback if needed
`bashList all migrations with status
npx event-forge migration:list --data-source=./src/data-source.ts
CLI Reference
$3
Generate Event-Forge database migration for NEW projects.
Options:
-
-f, --format - Output format: sql, typeorm, or stdout (default: stdout)
- -o, --output - Output directory (required for sql/typeorm formats)
- --filename - Custom output filename (optional)
- --schema - Database schema name (default: public)
- --outbox-table - Outbox table name (default: outbox_messages)
- --inbox-table - Inbox table name (default: inbox_messages)Examples:
`bash
Generate to stdout
npx event-forge migration:generateGenerate SQL file with custom options
npx event-forge migration:generate \
--format=sql \
--output=./migrations \
--schema=events \
--outbox-table=event_outboxGenerate TypeORM migration class
npx event-forge migration:generate \
--format=typeorm \
--output=./src/migrations \
--filename=1704657600000-EventForge.ts
`$3
List all Event-Forge migrations with their status.
Options:
-
-d, --data-source - Path to TypeORM DataSource configuration file (required)
- -m, --migrations-path - Custom migrations directory path (optional)Example:
`bash
npx event-forge migration:list --data-source=./src/data-source.ts
`$3
Run pending Event-Forge migrations.
Options:
-
-d, --data-source - Path to TypeORM DataSource configuration file (required)
- -m, --migrations-path - Custom migrations directory path (optional)Example:
`bash
npx event-forge migration:run --data-source=./src/data-source.ts
`$3
Rollback Event-Forge migrations.
Options:
-
-d, --data-source - Path to TypeORM DataSource configuration file (required)
- -m, --migrations-path - Custom migrations directory path (optional)
- -c, --count - Number of migrations to rollback (default: 1)Examples:
`bash
Rollback last migration
npx event-forge migration:rollback --data-source=./src/data-source.tsRollback last 2 migrations
npx event-forge migration:rollback --data-source=./src/data-source.ts --count=2
`Database Schema
$3
`sql
CREATE TABLE outbox_messages (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
aggregate_type VARCHAR(255) NOT NULL,
aggregate_id VARCHAR(255) NOT NULL,
event_type VARCHAR(255) NOT NULL,
payload JSONB NOT NULL,
metadata JSONB,
status outbox_message_status NOT NULL DEFAULT 'pending',
retry_count INTEGER NOT NULL DEFAULT 0,
max_retries INTEGER NOT NULL DEFAULT 5,
error_message TEXT,
scheduled_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
locked_by VARCHAR(255),
locked_at TIMESTAMP WITH TIME ZONE,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);
`Indexes:
- Partial index on
(status, scheduled_at, created_at) for pending/failed messages
- Index on (aggregate_type, aggregate_id) for aggregate lookups
- Index on (event_type) for event type filtering
- Index on (created_at) for time-based queries$3
`sql
CREATE TABLE inbox_messages (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
message_id VARCHAR(255) NOT NULL,
source VARCHAR(255) NOT NULL,
event_type VARCHAR(255) NOT NULL,
payload JSONB NOT NULL,
status inbox_message_status NOT NULL DEFAULT 'received',
processed_at TIMESTAMP WITH TIME ZONE,
error_message TEXT,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
received_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
UNIQUE(message_id, source)
);
`Indexes:
- Unique constraint on
(message_id, source) for deduplication
- Index on (event_type) for event type filtering
- Index on (status) for status filtering
- Index on (created_at) for time-based queries
- Index on (received_at) for received time queriesAPI Reference
$3
####
getEventForgeUpSQL(options?): stringGenerates complete UP migration SQL (CREATE statements).
Parameters:
-
options.schema - Database schema name (default: 'public')
- options.outboxTable - Outbox table name (default: 'outbox_messages')
- options.inboxTable - Inbox table name (default: 'inbox_messages')Returns: SQL string with CREATE statements for types, tables, and indexes
####
getEventForgeDownSQL(options?): stringGenerates complete DOWN migration SQL (DROP statements).
Parameters: Same as
getEventForgeUpSQLReturns: SQL string with DROP statements for tables and types
####
generateMigrationClass(options?): stringGenerates TypeORM migration class file content.
Parameters: Same as
getEventForgeUpSQLReturns: TypeScript code for TypeORM migration class
####
generateRawSQLFile(options?): stringGenerates raw SQL file content with both UP and DOWN migrations.
Parameters: Same as
getEventForgeUpSQL`Returns: SQL string with commented sections for UP and DOWN migrations
- PostgreSQL 12 or higher
- TypeORM 0.3.0 or higher
- Node.js 18 or higher
MIT
- @prodforcode/event-forge-core - Core interfaces and services
- @prodforcode/event-forge-mongoose - MongoDB adapter
- @prodforcode/event-forge-rabbitmq - RabbitMQ publisher
- @prodforcode/event-forge-nestjs - NestJS integration
For issues and questions, please visit GitHub Issues.