npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

peculiar-orm

v1.0.1

Published

A lightweight, active-record style ORM for PostgreSQL

Readme

Peculiar ORM

A 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.

Perfect for Microservices

Lightweight and resilient, peculiar-orm is built to thrive in distributed environments:

  • Zero bloat: Wraps pg directly without the overhead of massive ORM frameworks.
  • Resilient: Handles connection drops and query timeouts gracefully, preventing cascading failures.
  • Observable: Exposes internal metrics (pool saturation, transaction durations), making it easy to monitor service health.
  • Stateless-ready: Transaction manager supports request-scoped transactions, ideal for REST/gRPC handlers.

Installation

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
  }
}

Quick Start

1. Define Entities

Use decorators to define your database schema options.

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;
}

2. Create a Repository

Extend BaseRepository to implement your data access logic. The base class provides helpers for query building, error handling, and transaction management.

import { BaseRepository, TransactionManager } from 'peculiar-orm';
import { User } from './User';

export class UserRepository extends BaseRepository<User> {
    constructor(transactionManager: TransactionManager) {
        super(transactionManager, 'users');
    }

    async create(user: User): Promise<User> {
        const { columns, values, placeholders } = this.getEntityColumns(user);
        const sql = `
            INSERT INTO ${this.tableName} (${columns.join(', ')})
            VALUES (${placeholders.join(', ')})
            RETURNING *
        `;
        
        const result = await this.executeQuery<User>(sql, values);
        return result.rows[0];
    }

    async findById(id: string): Promise<User | null> {
        const sql = `SELECT * FROM ${this.tableName} WHERE id = $1`;
        const result = await this.executeQuery<User>(sql, [id]);
        return result.rows[0] || null;
    }

    // ... implement other abstract methods (update, delete, etc.)
}

3. Setup Dependencies

Configure the ConnectionPoolManager and TransactionManager.

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();

4. Use in Application

Execute operations within a transaction.

const transactionManager = container.get(TransactionManager);
const userRepo = container.get(UserRepository);

try {
    await transactionManager.beginTransaction();

    const newUser = await userRepo.create({
        email: '[email protected]',
        name: 'Alice'
    });

    console.log('User created:', newUser.id);

    await transactionManager.commit();
} catch (error) {
    console.error('Operation failed:', error);
    await transactionManager.rollback();
}

Core Components

ConnectionPoolManager

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.

TransactionManager

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.

BaseRepository

A foundation for your repositories.

  • executeQuery<T>(sql, params): 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.

License

ISC