NestJS
NestJS Integration
Section titled “NestJS Integration”uql-orm/nestjs ships a minimal dynamic module that registers your querier pool with Nest’s DI container, sets it as UQL’s default pool (so everything else works unchanged: middleware, fetch handler, getQuerier(), @Transactional), and ends the pool on application shutdown.
import { Module } from '@nestjs/common';import { UqlModule } from 'uql-orm/nestjs';import { pool } from './uql.config.js';
@Module({ imports: [UqlModule.forRoot({ pool })], // global by default; pass global: false to scope it})export class AppModule {}To build the pool from other providers (e.g. ConfigService), use forRootAsync:
@Module({ imports: [ UqlModule.forRootAsync({ imports: [ConfigModule], inject: [ConfigService], useFactory: (config: ConfigService) => new PgQuerierPool({ connectionString: config.get('DATABASE_URL') }), }), ],})export class AppModule {}Injecting the pool into services
Section titled “Injecting the pool into services”import { Inject, Injectable } from '@nestjs/common';import { UQL_QUERIER_POOL } from 'uql-orm/nestjs';import type { QuerierPool, Query } from 'uql-orm/type';import { User } from './shared/models/index.js';
@Injectable()export class UsersService { constructor(@Inject(UQL_QUERIER_POOL) private readonly pool: QuerierPool) {}
findMany(q: Query<User>) { return this.pool.findMany(User, q); }
create(user: User) { return this.pool.transaction((querier) => querier.insertOne(User, user)); }}Single reads run directly on the pool (acquire/release per call); withQuerier scopes a multi-statement unit of work and transaction adds begin/commit/rollback. All are built into every QuerierPool.
Multi-tenancy / request context
Section titled “Multi-tenancy / request context”Pass getContext to forRoot and UQL wires a global interceptor that runs every request inside withContext - so security filters (tenant scoping, row-level security) apply automatically to every query in the request, including relations, cascades, and @Transactional services. No querier threading, no per-query $where.
@Module({ imports: [ UqlModule.forRoot({ pool, // derive the tenant/user from the *verified* request (session / JWT) - never trust the client getContext: (req) => ({ tenantId: req.user.tenantId, userId: req.user.id }), }), ],})export class AppModule {}Then any entity with a security filter is scoped automatically, with no tenant plumbing in your services:
@Filter('tenant', { condition: (ctx) => (ctx?.tenantId != null ? { companyId: ctx.tenantId } : undefined), security: true,})@Entity()export class Invoice {}
this.pool.findMany(Invoice, {}); // generates: ... WHERE companyId = <ctx.tenantId>See Multi-tenancy for bypass rules, fail-closed behavior, and HTTP safety.
Auto-generated entity routes
Section titled “Auto-generated entity routes”Nest’s default platform is Express, so the Express middleware mounts directly in main.ts:
import { NestFactory } from '@nestjs/core';import { querierMiddleware } from 'uql-orm/express';import { AppModule } from './app.module.js';import { User, Post } from './shared/models/index.js';
const app = await NestFactory.create(AppModule);app.enableShutdownHooks(); // lets UqlModule end the pool on SIGTERMapp.use('/api', querierMiddleware({ include: [User, Post] }));await app.listen(3000);On the Fastify platform, use createFetchHandler with the bridge recipe instead.