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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@easysofts/id-logic

v1.0.3

Published

Dynamic unique ID generation module for NestJS with Sequelize

Downloads

179

Readme

🧩 @easysofts/id-logic — ID Logic Module for NestJS

A flexible, database-driven ID generation system for NestJS using Sequelize and PostgreSQL/MySQL.

This module allows you to define custom ID formats, supports daily/monthly/yearly resets, and can include dynamic placeholders such as date and contextual fields (like company code, prefix, etc.).


🚀 Features

  • 🎯 Dynamic ID format using placeholders ({YYYY}, {MM}, {DD}, {KEY}, {#####})
  • 🔁 Reset sequence daily, monthly, yearly, or by custom token logic
  • 📜 Logs every generated ID for tracking
  • 🔢 Supports batch generation (multiple IDs at once)
  • 🧱 Fully transactional — ensures atomicity
  • 🧩 Reusable DynamicModule for easy integration

📦 Installation

Install the published package:

npm i @easysofts/id-logic
# or with yarn
yarn add @easysofts/id-logic

Peer / supporting packages (install these if your project doesn't already have them):

npm i sequelize sequelize-typescript luxon
# If using PostgreSQL
npm i pg
# If using MySQL
npm i mysql2

⚠️ @easysofts/id-logic is a NestJS module and expects Sequelize + sequelize-typescript configured in your Nest app.

🛠️ Quick usage (NestJS)

Add IdLogicModule to your AppModule (module exported from the package):

// app.module.ts
import { Module } from '@nestjs/common';
import { SequelizeModule } from '@nestjs/sequelize';
import { IdLogicModule } from '@easysofts/id-logic'; // <- package import

@Module({
  imports: [
    SequelizeModule.forRoot({
      dialect: 'postgres',
      host: process.env.DB_HOST,
      port: Number(process.env.DB_PORT),
      username: process.env.DB_USERNAME,
      password: process.env.DB_PASSWORD,
      database: process.env.DB_DATABASE,
      autoLoadModels: true,
      synchronize: true, // dev only
      logging: false,
    }),

    // register the id-logic module from the package
    IdLogicModule.register(),
  ],
})
export class AppModule {}

Then inject the service where needed:

import { Injectable } from '@nestjs/common';
import { IdLogicService } from '@easysofts/id-logic'; // service export from package

@Injectable()
export class EmployeeService {
  constructor(private readonly idLogicService: IdLogicService) {}

  async createEmployee() {
    const id = await this.idLogicService.generateId({
      slug: 'employee',
      data: { PREFIX: 'EMP', DEPT: 'HR' },
    });
    // use `id`
  }
}

⚙️ Environment Configuration

1️⃣ Create a .env file in your project root:

# .env
APP_PORT=5000
NODE_ENV=development

DB_DIALECT=postgres
DB_HOST=localhost
DB_PORT=5432
DB_USERNAME=your_db_user
DB_PASSWORD=your_db_password
DB_DATABASE=your_db_name

DB_LOGGING=false
DB_SYNC=true

🛠️ Database Configuration (Sequelize)

Use the .env variables in your app.module.ts configuration:

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { SequelizeModule } from '@nestjs/sequelize';
import { IdLogicModule } from './id-logic/id-logic.module';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
    }),

    SequelizeModule.forRoot({
      dialect: process.env.DB_DIALECT as any,
      host: process.env.DB_HOST,
      port: Number(process.env.DB_PORT),
      username: process.env.DB_USERNAME,
      password: process.env.DB_PASSWORD,
      database: process.env.DB_DATABASE,
      autoLoadModels: true,
      synchronize: process.env.DB_SYNC === 'true',
      logging: process.env.DB_LOGGING === 'true',
    }),

    // Import the dynamic ID logic module
    IdLogicModule.register(),
  ],
})
export class AppModule {}

🧩 Model Structure

sys_unique_id_logics

Defines the logic and format for generating IDs.

| Field | Type | Description | | ------------------- | ------ | ---------------------------------------------------------- | | slug | string | Unique key identifying the logic | | format | string | Format pattern, e.g. {PREFIX}-{YYYY}-{MM}-{#####} | | reset_type | string | 'none', 'yearly', 'monthly', 'daily', or 'token' | | token_reset_logic | string | Comma-separated tokens (YYYY,MM,DD) | | starting_id | number | Starting value (default: 1) | | pad_length | number | Length of numeric ID padding (default: 5) |

sys_generated_ids

Stores every generated ID along with metadata.

| Field | Type | Description | | ----------------- | ------ | ----------------------------------- | | slug | string | Logic slug | | id_token | string | Reset token (combination of fields) | | generated_code | string | Final generated ID | | sequence_number | number | Sequential ID number |

🧰 Example Interface

// id-logic.interface.ts
export interface IdLogicInterface {
  slug: string;
  data?: Record<string, any>;
  date?: string; // optional ISO date for testing resets
  multiple?: number; // for batch generation
}

⚙️ Example Service Usage

import { Injectable } from '@nestjs/common';
import { IdLogicService } from './id-logic/id-logic.service';

@Injectable()
export class EmployeeService {
  constructor(private readonly idLogicService: IdLogicService) {}

  async createEmployee() {
    const generatedId = await this.idLogicService.generateId({
      slug: 'employee',
      data: {
        PREFIX: 'EMP',
        DEPT: 'HR',
      },
    });

    console.log('Generated Employee ID:', generatedId);
  }
}

🧮 Example Logic Configuration

Insert your logic configuration record in the sys_unique_id_logics table:

| Field | Example Value | | ----------------- | ------------------------------ | | slug | employee | | format | {PREFIX}-{YYYY}-{MM}-{#####} | | reset_type | monthly | | token_reset_logic | YYYY,MM | | starting_id | 1 | | pad_length | 5 | | active | true |

🧩 More Advance Configurations for sys_unique_id_logics table:

| ID | Slug | Format | Reset Type | Token Reset Logic | Next Number | Starting ID | Pad Length | Active | Description | | -- | ---------- | ---------------------------------------------- | ---------- | --------------------- | ----------- | ----------- | ---------- | ------ | -------------------------------------------------------------------------------------------- | | 1 | employee | {PREFIX}{CODE}{YYYY}-{MM}-{#####} | monthly | PREFIX,CODE,YYYY,MM | 1 | 1 | 5 | true | Employee IDs include a prefix + internal code, reset monthly. Example: EMP0012025-11-00001 | | 2 | challan | {PREFIX}-{WAREHOUSE}-{YYYY}-{MM}-{#####} | monthly | YYYY,MM | 1 | 1 | 5 | true | Warehouse challans reset monthly. Example: CH-WH01-2025-11-00001 | | 3 | order | {PREFIX}-{DEPT}-{YYYY}-{MM}-{DD}-{#####} | daily | YYYY,MM,DD | 1 | 1 | 6 | true | Daily order IDs per department. Example: ORD-HR-2025-11-04-000001 | | 4 | invoice | {PREFIX}-{CUSTOMER}-{YYYY}-{MM}-{#####} | monthly | CUSTOMER,YYYY,MM | 1 | 1 | 5 | true | Invoices reset per customer every month. Example: INV-ACME-2025-11-00001 | | 5 | shipment | {PREFIX}-{REGION}-{YYYY}-{MM}-{DD}-{#####} | daily | REGION,YYYY,MM,DD | 1 | 1 | 5 | true | Daily shipments per region. Example: SHIP-NE-2025-11-04-00001 | | 6 | project | {PREFIX}-{CLIENT}-{YYYY}-{#####} | yearly | CLIENT,YYYY | 1 | 1 | 4 | true | Projects reset yearly per client. Example: PRJ-ACME-2025-0001 | | 7 | ticket | {PREFIX}-{CATEGORY}-{YYYY}-{MM}-{DD}-{#####} | daily | CATEGORY,YYYY,MM,DD | 1 | 1 | 5 | true | Support tickets reset daily per category. Example: TCK-BUG-2025-11-04-00001 | | 8 | asset | {PREFIX}-{TYPE}-{YYYY}-{MM}-{#####} | monthly | TYPE,YYYY,MM | 1 | 1 | 5 | true | Assets reset monthly per type. Example: AST-LAP-2025-11-00001 |

🧩 Example Generated IDs

| Slug | Format | Reset Type | Token | Sequence | Generated ID | | ---------- | ---------------------------------------------- | ---------- | -------------------- | -------- | -------------------------- | | employee | {PREFIX}{CODE}{YYYY}-{MM}-{#####} | monthly | EMP001-2025-11 | 1 | EMP0012025-11-00001 | | employee | {PREFIX}{CODE}{YYYY}-{MM}-{#####} | monthly | EMP001-2025-11 | 2 | EMP0012025-11-00002 | | employee | {PREFIX}{CODE}{YYYY}-{MM}-{#####} | monthly | EMP001-2025-12 | 1 | EMP0012025-12-00001 | | challan | {PREFIX}-{WAREHOUSE}-{YYYY}-{MM}-{#####} | monthly | CH-WH01-2025-11 | 1 | CH-WH01-2025-11-00001 | | challan | {PREFIX}-{WAREHOUSE}-{YYYY}-{MM}-{#####} | monthly | CH-WH01-2025-11 | 2 | CH-WH01-2025-11-00002 | | order | {PREFIX}-{DEPT}-{YYYY}-{MM}-{DD}-{#####} | daily | ORD-HR-2025-11-04 | 1 | ORD-HR-2025-11-04-000001 | | order | {PREFIX}-{DEPT}-{YYYY}-{MM}-{DD}-{#####} | daily | ORD-HR-2025-11-04 | 2 | ORD-HR-2025-11-04-000002 | | order | {PREFIX}-{DEPT}-{YYYY}-{MM}-{DD}-{#####} | daily | ORD-HR-2025-11-05 | 1 | ORD-HR-2025-11-05-000001 | | invoice | {PREFIX}-{CUSTOMER}-{YYYY}-{MM}-{#####} | monthly | INV-ACME-2025-11 | 1 | INV-ACME-2025-11-00001 | | invoice | {PREFIX}-{CUSTOMER}-{YYYY}-{MM}-{#####} | monthly | INV-ACME-2025-11 | 2 | INV-ACME-2025-11-00002 | | shipment | {PREFIX}-{REGION}-{YYYY}-{MM}-{DD}-{#####} | daily | SHIP-NE-2025-11-04 | 1 | SHIP-NE-2025-11-04-00001 | | shipment | {PREFIX}-{REGION}-{YYYY}-{MM}-{DD}-{#####} | daily | SHIP-NE-2025-11-04 | 2 | SHIP-NE-2025-11-04-00002 | | project | {PREFIX}-{CLIENT}-{YYYY}-{#####} | yearly | PRJ-ACME-2025 | 1 | PRJ-ACME-2025-0001 | | project | {PREFIX}-{CLIENT}-{YYYY}-{#####} | yearly | PRJ-ACME-2025 | 2 | PRJ-ACME-2025-0002 | | ticket | {PREFIX}-{CATEGORY}-{YYYY}-{MM}-{DD}-{#####} | daily | TCK-BUG-2025-11-04 | 1 | TCK-BUG-2025-11-04-00001 | | ticket | {PREFIX}-{CATEGORY}-{YYYY}-{MM}-{DD}-{#####} | daily | TCK-BUG-2025-11-04 | 2 | TCK-BUG-2025-11-04-00002 | | asset | {PREFIX}-{TYPE}-{YYYY}-{MM}-{#####} | monthly | AST-LAP-2025-11 | 1 | AST-LAP-2025-11-00001 | | asset | {PREFIX}-{TYPE}-{YYYY}-{MM}-{#####} | monthly | AST-LAP-2025-11 | 2 | AST-LAP-2025-11-00002 |

🔹 Explanation of fields

- slug → Unique identifier for the ID type
- format → Template string; placeholders:
    - {PREFIX} → any custom prefix
    - {CODE} → internal code
    - {YYYY}, {YY}, {MM}, {DD} → date parts
    - {#####} → padded sequence number
    - {KEY} → any dynamic key from data object
- reset_type → Determines how the sequence resets (none, daily, monthly, yearly)
- token_reset_logic → Fields used to calculate id_token for resets (comma-separated)
- pad_length → Number of digits in the sequence part
- next_number / starting_id → Defaults for the sequence counter
- active → Whether this logic is enabled 

🧠 How It Works

1. The service looks up the logic record by slug.
2. It builds a token using the data and token_reset_logic (e.g., EMP-HR-2025-11).
3. It checks sys_generated_ids for the last sequence under that token.
4. Based on reset_type, it determines if the sequence should restart.
5. It generates the formatted ID (e.g., EMP-2025-11-00001).
6. It logs the generated ID in the database.

🧪 Example Outputs

| Configuration | Output Example | | ----------------------------------- | ---------------------- | | {PREFIX}-{YYYY}-{#####} | EMP-2025-00001 | | {DEPT}-{YY}-{MM}-{#####} | HR-25-11-00001 | | {PREFIX}-{YYYY}-{MM}-{DD}-{#####} | ORD-2025-11-04-00001 |

🧱 Example Folder Structure

src/
 └── id-logic/
      ├── id-logic.module.ts
      ├── id-logic.service.ts
      ├── id-logic.interface.ts
      └── models/
          ├── id-logic.model.ts
          └── generated-id.model.ts

🧩 DynamicModule Pattern

The IdLogicModule is implemented as a dynamic module for reusability:

@Module({})
export class IdLogicModule {
  static register(): DynamicModule {
    return {
      module: IdLogicModule,
      imports: [SequelizeModule.forFeature([IdLogic, SysGeneratedId])],
      providers: [IdLogicService],
      exports: [IdLogicService],
    };
  }
}

You can import IdLogicModule.register() into any other module or microservice.

🧰 Example SQL (PostgreSQL)

CREATE TABLE sys_unique_id_logics (
  id BIGSERIAL PRIMARY KEY,
  slug VARCHAR(255) UNIQUE NOT NULL,
  format VARCHAR(255) NOT NULL,
  reset_type VARCHAR(50) DEFAULT 'none',
  token_reset_logic VARCHAR(255),
  next_number INT DEFAULT 1,
  starting_id INT DEFAULT 1,
  pad_length INT DEFAULT 5,
  active BOOLEAN DEFAULT TRUE,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  deleted_at TIMESTAMP NULL
);

CREATE TABLE sys_generated_ids (
  id BIGSERIAL PRIMARY KEY,
  slug VARCHAR(255) NOT NULL,
  id_token VARCHAR(255),
  generated_code VARCHAR(255),
  sequence_number INT,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  deleted_at TIMESTAMP NULL
);

📚 Example Generated IDs

| Date | Token | Sequence | Generated Code | | ---------- | ------------- | -------- | ------------------- | | 2025-11-04 | EMP-2025-11 | 1 | EMP-2025-11-00001 | | 2025-11-04 | EMP-2025-11 | 2 | EMP-2025-11-00002 | | 2025-12-01 | EMP-2025-12 | 1 | EMP-2025-12-00001 |

💡 Tips

- Use {#####} or any number of #s to define padding length (auto-detected from your config).
- Keep format flexible — any {KEY} in your data object will be replaced dynamically.
- token_reset_logic helps reset sequences for unique tokens (like per-month or per-branch).
- Always wrap generateId() inside transactions if combining with your own DB logic.

🧑‍💻 Author

Abu Bakar Siddique
📧 [email protected]