A lightweight, active-record style ORM for PostgreSQL
npm install peculiar-ormA lightweight, transparent, and robust Object-Relational Mapper (ORM) for PostgreSQL, built with TypeScript.
peculiar-orm is designed for applications that need:
- Resilient Connection Management: Built-in pooling, diagnostics, and metrics.
- Explicit Transaction Control: Clean API for handling complex transactions.
- Repository Pattern: A structured way to organize data access logic.
- Observability: Detailed metrics on connection usage, query performance, and transaction history.
- Dependency Injection: First-class support for inversify.
peculiar-orm is built to thrive in distributed environments:pg directly without the overhead of massive ORM frameworks.``bash`
npm install peculiar-orm pg reflect-metadata inversify
npm install --save-dev @types/pg--
Ensure you have experimentalDecorators and emitDecoratorMetadata enabled in your tsconfig.json:
`json`
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
`typescript
import { Column, Index, IndexType } from 'peculiar-orm';
export class User {
@Column('uuid DEFAULT gen_random_uuid() PRIMARY KEY')
id?: string;
@Column('varchar(255) NOT NULL')
@Index({ unique: true })
email!: string;
@Column('varchar(255)')
name?: string;
@Column('timestamp with time zone DEFAULT now()')
createdAt?: Date;
}
`
to implement your data access logic. The base class provides helpers for query building, error handling, and transaction management.`typescript
import { BaseRepository, TransactionManager } from 'peculiar-orm';
import { User } from './User';export class UserRepository extends BaseRepository {
constructor(transactionManager: TransactionManager) {
super(transactionManager, 'users');
}
async create(user: User): Promise {
const { columns, values, placeholders } = this.getEntityColumns(user);
const sql =
;
const result = await this.executeQuery(sql, values);
return result.rows[0];
} async findById(id: string): Promise {
const sql =
SELECT * FROM ${this.tableName} WHERE id = $1;
const result = await this.executeQuery(sql, [id]);
return result.rows[0] || null;
} // ... implement other abstract methods (update, delete, etc.)
}
`$3
Configure the ConnectionPoolManager and TransactionManager.`typescript
import { Container } from 'inversify';
import { ConnectionPoolManager, TransactionManager } from 'peculiar-orm';
import { UserRepository } from './UserRepository';const container = new Container();
// 1. Configure the Pool
const poolConfig = {
host: 'localhost',
database: 'my_db',
user: 'postgres',
password: 'password',
max: 20,
idleTimeoutMillis: 30000
};
container.bind(ConnectionPoolManager).toDynamicValue(() => new ConnectionPoolManager(poolConfig)).inSingletonScope();
// 2. Bind TransactionManager
container.bind(TransactionManager).toSelf().inRequestScope();
// Note: InRequestScope is recommended for web apps to isolate transactions per request
// 3. Bind Repository
container.bind(UserRepository).toSelf();
`$3
Execute operations within a transaction.`typescript
const transactionManager = container.get(TransactionManager);
const userRepo = container.get(UserRepository);try {
await transactionManager.beginTransaction();
const newUser = await userRepo.create({
email: 'alice@example.com',
name: 'Alice'
});
console.log('User created:', newUser.id);
await transactionManager.commit();
} catch (error) {
console.error('Operation failed:', error);
await transactionManager.rollback();
}
`Core Components
$3
Manages the pg pool with added reliability features:
- Metrics: Tracks acquired/released connections, leasing durations, and wait times.
- Query Timeouts: Automatically cancels queries that exceed a threshold (default 10s) using pg_cancel_backend.
- Diagnostics: Logs warnings for long-running connections or pool exhaustion.$3
Handles the lifecycle of a database transaction.
- beginTransaction(options): Starts a transaction (supports isolation levels).
- commit(): Commits changes.
- rollback(): Rolls back changes.
- getMetrics(): Returns stats on active/committed/rolled-back transactions.$3
A foundation for your repositories.
- executeQuery: Wraps pg query execution with logging and standardized error handling (maps PG error codes to DatabaseConstraintError, DatabaseConnectionError, etc.).
- Helpers: getEntityColumns, buildWhereClause, buildUpdateSet` help construct SQL dynamically.