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

@nest-yalc-2/ag-grid

v2.2.18

Published

<div align="center"> <h1>@nest-yalc-2/ag-grid</h1> <p><em>Core enterprise module for the @nest-yalc-2/ag-grid integration within the Ferrox/YALC ecosystem.</em></p>

Readme

npm version License

🚀 Installation

npm install @nest-yalc-2/ag-grid
# or
yarn add @nest-yalc-2/ag-grid
# or
pnpm add @nest-yalc-2/ag-grid

AG-Grid Server-Side Integration & Query Transformers

The @nestjs-yalc/ag-grid package provides enterprise-grade, server-side data grid processing for NestJS applications. It automatically translates frontend AG-Grid request payloads (containing complex filtering rules, multi-column sorting, pagination limits, and grouping expressions) into optimized TypeORM SelectQueryBuilder execution plans with parameterized SQL generation.


1. What It Is & Architectural Purpose

Modern enterprise applications require rendering massive datasets (millions of rows) with real-time grid capabilities - such as column searching, multi-level sorting, dynamic range filtering, and server-side pagination - without overwhelming client-side memory or making un-indexed database calls.

@nestjs-yalc/ag-grid acts as the bridge between frontend AG-Grid Enterprise implementations and backend TypeORM ORM layers. It eliminates hand-written SQL search parsers by consuming standard AG-Grid IServerSideGetRowsRequest structures and applying exact column-mapping logic, type-safe conversions, and automated security sanitization before database execution.

┌────────────────────────┐      AG-Grid JSON Payload      ┌─────────────────────────────┐
│                        │ ─────────────────────────────> │                             │
│  Frontend AG-Grid      │                                │  AG-Grid Transformer        │
│  (Server-Side Model)   │ <───────────────────────────── │  (@nestjs-yalc/ag-grid)     │
└────────────────────────┘      Row Data + Total Count    └──────────────┬──────────────┘
                                                                         │
                                                                         │ TypeORM SQL Builder
                                                                         ▼
                                                          ┌─────────────────────────────┐
                                                          │  PostgreSQL / MySQL / SQLite │
                                                          └─────────────────────────────┘

2. What It Does & Key Capabilities

  • Automated Filter Translation: Converts AG-Grid text, number, date, set, and boolean filter models into parameterized SQL WHERE clauses.
  • Multi-Column Sorting: Translates nested sortModel arrays into SQL ORDER BY statements with null-sorting safety.
  • Dynamic Pagination: Calculates offset-based (SKIP / TAKE) parameters directly from startRow and endRow.
  • Column Mapping & Security Sanitization: Maps grid field keys to actual entity properties or joined table aliases while stripping SQL injection vectors.
  • Relational Field Resolution: Supports deeply nested column paths (e.g., user.profile.firstName) across TypeORM LEFT JOIN aliases.

3. How It Works Under the Hood

Execution Flow Sequence

sequenceDiagram
    autonumber
    participant Client as AG-Grid Client
    participant Controller as NestJS Controller
    participant Service as Grid Service
    participant Transformer as AgGridQueryTransformer
    participant DB as TypeORM QueryBuilder

    Client->>Controller: POST /api/users/grid (IServerSideGetRowsRequest)
    Controller->>Service: getUsersGrid(gridRequest)
    Service->>Transformer: applyAgGridToQueryBuilder(queryBuilder, gridRequest, entityMapping)
    Transformer->>Transformer: Validate & Sanitize Field Names
    Transformer->>Transformer: Build Filter Expressions (SQL WHERE)
    Transformer->>Transformer: Apply Multi-Column Sort (SQL ORDER BY)
    Transformer->>Transformer: Set Pagination Window (LIMIT / OFFSET)
    Transformer->>DB: Execute GetManyAndCount()
    DB-->>Transformer: Returns [entities, totalCount]
    Transformer-->>Service: Formatted Grid Result { rowData, totalCount }
    Service-->>Controller: DTO Response
    Controller-->>Client: JSON Response { rows: [...], lastRow: totalCount }

Internal Engine Mechanics

  1. Filter Model Parsing: When a filter request arrives (e.g., filterType: 'number', type: 'greaterThan', filter: 100), the AgGridQueryTransformer inspects the registered entity metadata. It converts the operator into parameterized SQL (field > :param_1) to prevent SQL injection.
  2. Date Range Normalization: Date filters automatically cast ISO-8601 strings into database-compatible timestamps and apply boundary ranges (BETWEEN or >= and <=).
  3. Set Filters (IN Clauses): Multi-selection set filters convert array values into parameterized IN (:...setValues) conditions.

4. Why It Was Designed This Way

| Design Aspect | Traditional Hand-Coded Approach | @nestjs-yalc/ag-grid Approach | | :--- | :--- | :--- | | Maintenance | Writing manual SQL WHERE parsers for every API endpoint. | Single decorator / service call handles any complex grid query. | | Security | High risk of SQL injection via unescaped search string concatenation. | 100% Parameterized queries with column-name whitelist validation. | | Performance | Inefficient table scans from non-indexed dynamic joins. | Strict relation aliasing with indexed column mapping rules. | | Type Safety | Loose any typing for grid filter parameters. | Strictly typed DTO wrappers for IServerSideGetRowsRequest. |


5. Practical Usage Guide & Extended Code Examples

5.1 Basic Controller & Service Setup

import { Controller, Post, Body } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { AgGridQueryTransformer, IServerSideGetRowsRequest } from '@nestjs-yalc/ag-grid';
import { UserEntity } from './user.entity';

@Controller('users')
export class UserController {
  constructor(
    @InjectRepository(UserEntity)
    private readonly userRepository: Repository<UserEntity>,
  ) {}

  @Post('grid')
  async getUsersGrid(@Body() gridRequest: IServerSideGetRowsRequest) {
    const queryBuilder = this.userRepository.createQueryBuilder('user');

    // Apply AG-Grid filters, sorting, and pagination
    const transformer = new AgGridQueryTransformer<UserEntity>(queryBuilder, gridRequest, {
      id: 'user.id',
      email: 'user.email',
      role: 'user.role',
      createdAt: 'user.createdAt',
      'department.name': 'department.name', // Relational field mapping
    });

    // Automatically adds LEFT JOIN if relational fields are filtered/sorted
    transformer.applyJoins([
      { property: 'user.department', alias: 'department' }
    ]);

    const [rows, totalCount] = await transformer.execute();

    return {
      rows,
      lastRow: totalCount,
    };
  }
}

5.2 Advanced Custom Filter Handling

import { AgGridQueryTransformer, FilterCondition } from '@nestjs-yalc/ag-grid';

const transformer = new AgGridQueryTransformer(queryBuilder, gridRequest, fieldMap);

// Register custom filter evaluator for complex JSONB or GEO columns
transformer.registerCustomFilter('metadata', (qb, filterModel: FilterCondition) => {
  qb.andWhere("user.metadata ->> 'status' = :status", { status: filterModel.filter });
});

const result = await transformer.execute();

6. Anti-Patterns: How NOT to Use It

[!CAUTION] Anti-Pattern 1: Passing Raw Unmapped Frontend Fields Never pass client-provided field names directly into the QueryBuilder without validating them against an explicit field mapping object. Doing so allows malicious clients to probe private database columns.

// ❌ WRONG: Passing unmapped grid field directly
queryBuilder.orderBy(gridRequest.sortModel[0].colId);

// ✅ CORRECT: Use AgGridQueryTransformer field map
const transformer = new AgGridQueryTransformer(queryBuilder, gridRequest, {
  allowedField: 'entity.actualColumn',
});

[!WARNING] Anti-Pattern 2: Unbounded Count Queries on Large Tables Calling getManyAndCount() on tables with tens of millions of rows without indexes can freeze database workers. Always pass pre-filtered indexing constraints or set maximum take limits.


7. Pro-Tips & Best Practices

[!TIP] Optimization 1: Indexing Strategy Create composite indexes on frequently filtered and sorted column combinations (e.g., (department_id, created_at DESC)).

[!NOTE] Optimization 2: Default Sort Order Always provide a fallback default sort order (e.g., user.id DESC) in case the user clears all grid sorts, ensuring deterministic SQL pagination results.


🔗 Cross-References

To see how this module integrates with the rest of the Ferrox architecture, refer to the following documentation:


📚 Ecosystem Documentation

This module is a core component of the Ferrox enterprise microservice architecture.

👉 Read the Full Documentation on Ferrox-Rust.dev