@vritti/api-sdk 0.0.9 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/drizzle-orm.cjs +25 -0
- package/dist/drizzle-orm.cjs.map +1 -0
- package/dist/drizzle-orm.d.cts +2 -0
- package/dist/drizzle-orm.d.ts +2 -0
- package/dist/drizzle-orm.js +3 -0
- package/dist/drizzle-orm.js.map +1 -0
- package/dist/drizzle-pg-core.cjs +25 -0
- package/dist/drizzle-pg-core.cjs.map +1 -0
- package/dist/drizzle-pg-core.d.cts +1 -0
- package/dist/drizzle-pg-core.d.ts +1 -0
- package/dist/drizzle-pg-core.js +3 -0
- package/dist/drizzle-pg-core.js.map +1 -0
- package/dist/index.cjs +317 -279
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +318 -215
- package/dist/index.d.ts +318 -215
- package/dist/index.js +317 -279
- package/dist/index.js.map +1 -1
- package/package.json +33 -10
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import * as _nestjs_common from '@nestjs/common';
|
|
2
2
|
import { DynamicModule, OnModuleDestroy, OnModuleInit, Logger, CanActivate, ExecutionContext, ExceptionFilter, ArgumentsHost, HttpException, HttpStatus, ModuleMetadata, Type, NestModule, MiddlewareConsumer, LoggerService as LoggerService$1, NestMiddleware, NestInterceptor, CallHandler } from '@nestjs/common';
|
|
3
|
+
import { NodePgDatabase } from 'drizzle-orm/node-postgres';
|
|
4
|
+
import { InferInsertModel, InferSelectModel, SQL } from 'drizzle-orm';
|
|
5
|
+
import { PgTable } from 'drizzle-orm/pg-core';
|
|
3
6
|
import { ConfigService } from '@nestjs/config';
|
|
4
7
|
import { Reflector } from '@nestjs/core';
|
|
5
8
|
import { JwtService } from '@nestjs/jwt';
|
|
@@ -81,6 +84,34 @@ declare class AuthConfigModule {
|
|
|
81
84
|
static forRootAsync(): DynamicModule;
|
|
82
85
|
}
|
|
83
86
|
|
|
87
|
+
/**
|
|
88
|
+
* Schema Registry Interface
|
|
89
|
+
*
|
|
90
|
+
* Projects augment this interface to register their Drizzle schema.
|
|
91
|
+
* This enables type-safe db.query access without passing schema types everywhere.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* // In your project's schema.registry.ts:
|
|
95
|
+
* declare module '@vritti/api-sdk' {
|
|
96
|
+
* interface SchemaRegistry {
|
|
97
|
+
* schema: typeof import('./schema');
|
|
98
|
+
* }
|
|
99
|
+
* }
|
|
100
|
+
*/
|
|
101
|
+
interface SchemaRegistry {
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Extracts the registered schema type.
|
|
105
|
+
* Falls back to Record<string, unknown> if no schema is registered.
|
|
106
|
+
*/
|
|
107
|
+
type RegisteredSchema = SchemaRegistry extends {
|
|
108
|
+
schema: infer S;
|
|
109
|
+
} ? S : Record<string, unknown>;
|
|
110
|
+
/**
|
|
111
|
+
* Type alias for the Drizzle database client with registered schema
|
|
112
|
+
*/
|
|
113
|
+
type TypedDrizzleClient = NodePgDatabase<RegisteredSchema>;
|
|
114
|
+
|
|
84
115
|
/**
|
|
85
116
|
* Primary database connection configuration
|
|
86
117
|
*/
|
|
@@ -97,8 +128,8 @@ interface PrimaryDbConfig {
|
|
|
97
128
|
database: string;
|
|
98
129
|
/** Default schema (default: 'public') */
|
|
99
130
|
schema?: string;
|
|
100
|
-
/** SSL mode: 'require' | 'prefer' | 'disable' (default: 'require') */
|
|
101
|
-
sslMode?: 'require' | 'prefer' | 'disable';
|
|
131
|
+
/** SSL mode: 'require' | 'prefer' | 'disable' | 'no-verify' (default: 'require') */
|
|
132
|
+
sslMode?: 'require' | 'prefer' | 'disable' | 'no-verify';
|
|
102
133
|
}
|
|
103
134
|
/**
|
|
104
135
|
* Configuration options for DatabaseModule
|
|
@@ -120,11 +151,11 @@ interface DatabaseModuleOptions {
|
|
|
120
151
|
*/
|
|
121
152
|
primaryDb: PrimaryDbConfig;
|
|
122
153
|
/**
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
* @example import
|
|
154
|
+
* Drizzle schema object containing all tables and relations
|
|
155
|
+
* Import your schema from db/schema/index.ts and pass it here
|
|
156
|
+
* @example import * as schema from '@/db/schema'
|
|
126
157
|
*/
|
|
127
|
-
|
|
158
|
+
drizzleSchema: RegisteredSchema;
|
|
128
159
|
/**
|
|
129
160
|
* Connection cache TTL in milliseconds
|
|
130
161
|
* Idle connections will be closed after this period
|
|
@@ -356,7 +387,7 @@ declare class TenantContextService {
|
|
|
356
387
|
* Service responsible for managing tenant-scoped database connections
|
|
357
388
|
*
|
|
358
389
|
* This service:
|
|
359
|
-
* - Maintains a connection pool (Map<cacheKey,
|
|
390
|
+
* - Maintains a connection pool (Map<cacheKey, TenantConnection>)
|
|
360
391
|
* - Creates new connections dynamically based on tenant context
|
|
361
392
|
* - Reuses existing connections for the same tenant
|
|
362
393
|
* - Supports both cloud schemas and enterprise databases
|
|
@@ -364,14 +395,14 @@ declare class TenantContextService {
|
|
|
364
395
|
*
|
|
365
396
|
* @example
|
|
366
397
|
* // In a controller or service
|
|
367
|
-
* const
|
|
368
|
-
* const users = await
|
|
398
|
+
* const db = this.tenantDatabase.drizzleClient;
|
|
399
|
+
* const users = await db.select().from(usersTable);
|
|
369
400
|
*/
|
|
370
401
|
declare class TenantDatabaseService implements OnModuleDestroy {
|
|
371
402
|
private readonly options;
|
|
372
403
|
private readonly tenantContext;
|
|
373
404
|
private readonly logger;
|
|
374
|
-
/** Connection pool: Map<cacheKey,
|
|
405
|
+
/** Connection pool: Map<cacheKey, TenantConnection> */
|
|
375
406
|
private readonly clients;
|
|
376
407
|
/** Track last usage time for idle connection cleanup */
|
|
377
408
|
private readonly clientLastUsed;
|
|
@@ -379,14 +410,18 @@ declare class TenantDatabaseService implements OnModuleDestroy {
|
|
|
379
410
|
private cleanupInterval?;
|
|
380
411
|
constructor(options: DatabaseModuleOptions, tenantContext: TenantContextService);
|
|
381
412
|
/**
|
|
382
|
-
* Get the
|
|
413
|
+
* Get the Drizzle client for the current tenant's database.
|
|
383
414
|
* This returns the tenant-scoped database client.
|
|
384
415
|
*
|
|
385
|
-
* @returns Tenant-scoped database
|
|
416
|
+
* @returns Tenant-scoped Drizzle database instance
|
|
386
417
|
* @throws UnauthorizedException if tenant context not set
|
|
387
418
|
* @throws InternalServerErrorException if connection fails
|
|
388
419
|
*/
|
|
389
|
-
get
|
|
420
|
+
get drizzleClient(): TypedDrizzleClient;
|
|
421
|
+
/**
|
|
422
|
+
* Get the Drizzle schema
|
|
423
|
+
*/
|
|
424
|
+
get schema(): Record<string, unknown>;
|
|
390
425
|
/**
|
|
391
426
|
* Get tenant-scoped database client for the current request/message
|
|
392
427
|
*
|
|
@@ -395,21 +430,17 @@ declare class TenantDatabaseService implements OnModuleDestroy {
|
|
|
395
430
|
* 2. Builds a connection URL based on tenant type
|
|
396
431
|
* 3. Returns cached client if exists, otherwise creates new one
|
|
397
432
|
*
|
|
398
|
-
* @returns
|
|
433
|
+
* @returns Drizzle database instance
|
|
399
434
|
* @throws UnauthorizedException if tenant context not set
|
|
400
435
|
* @throws InternalServerErrorException if connection fails
|
|
401
|
-
*
|
|
402
|
-
* @example
|
|
403
|
-
* const dbClient = await tenantDatabase.getDbClient<PrismaClient>();
|
|
404
|
-
* const users = await dbClient.user.findMany();
|
|
405
436
|
*/
|
|
406
437
|
private getDbClient;
|
|
407
438
|
/**
|
|
408
|
-
* Create a new database client for the given tenant
|
|
439
|
+
* Create a new database client for the given tenant (synchronous)
|
|
409
440
|
*/
|
|
410
|
-
private
|
|
441
|
+
private createDbClientSync;
|
|
411
442
|
/**
|
|
412
|
-
* Build connection URL for
|
|
443
|
+
* Build connection URL for tenant (dedicated database)
|
|
413
444
|
*/
|
|
414
445
|
private buildTenantDbUrl;
|
|
415
446
|
/**
|
|
@@ -455,8 +486,10 @@ declare class TenantDatabaseService implements OnModuleDestroy {
|
|
|
455
486
|
declare class PrimaryDatabaseService implements OnModuleInit, OnModuleDestroy {
|
|
456
487
|
private readonly options;
|
|
457
488
|
private readonly logger;
|
|
458
|
-
/**
|
|
459
|
-
private
|
|
489
|
+
/** PostgreSQL connection pool */
|
|
490
|
+
private pool;
|
|
491
|
+
/** Drizzle database instance */
|
|
492
|
+
private db;
|
|
460
493
|
/** In-memory cache: Map<tenantIdentifier, TenantConfig> */
|
|
461
494
|
private readonly tenantConfigCache;
|
|
462
495
|
/** Cache TTL in milliseconds */
|
|
@@ -464,9 +497,9 @@ declare class PrimaryDatabaseService implements OnModuleInit, OnModuleDestroy {
|
|
|
464
497
|
constructor(options: DatabaseModuleOptions);
|
|
465
498
|
onModuleInit(): Promise<void>;
|
|
466
499
|
/**
|
|
467
|
-
* Initialize connection to primary database
|
|
500
|
+
* Initialize connection to primary database using Drizzle
|
|
468
501
|
*/
|
|
469
|
-
private
|
|
502
|
+
private initializeDrizzleClient;
|
|
470
503
|
/**
|
|
471
504
|
* Build connection URL from primary database properties
|
|
472
505
|
*/
|
|
@@ -476,9 +509,9 @@ declare class PrimaryDatabaseService implements OnModuleInit, OnModuleDestroy {
|
|
|
476
509
|
*/
|
|
477
510
|
private maskPassword;
|
|
478
511
|
/**
|
|
479
|
-
* Get tenant configuration by identifier (ID or
|
|
512
|
+
* Get tenant configuration by identifier (ID or subdomain)
|
|
480
513
|
*
|
|
481
|
-
* @param tenantIdentifier Tenant ID or
|
|
514
|
+
* @param tenantIdentifier Tenant ID or subdomain
|
|
482
515
|
* @returns Tenant configuration or null if not found
|
|
483
516
|
*/
|
|
484
517
|
getTenantInfo(tenantIdentifier: string): Promise<TenantInfo | null>;
|
|
@@ -491,7 +524,7 @@ declare class PrimaryDatabaseService implements OnModuleInit, OnModuleDestroy {
|
|
|
491
524
|
*
|
|
492
525
|
* Useful when tenant settings are updated and cache needs to be invalidated
|
|
493
526
|
*
|
|
494
|
-
* @param tenantIdentifier Tenant ID or
|
|
527
|
+
* @param tenantIdentifier Tenant ID or subdomain
|
|
495
528
|
*/
|
|
496
529
|
clearTenantCache(tenantIdentifier: string): void;
|
|
497
530
|
/**
|
|
@@ -499,13 +532,17 @@ declare class PrimaryDatabaseService implements OnModuleInit, OnModuleDestroy {
|
|
|
499
532
|
*/
|
|
500
533
|
clearAllCaches(): void;
|
|
501
534
|
/**
|
|
502
|
-
* Get the
|
|
503
|
-
* This is a synchronous property that returns the initialized
|
|
535
|
+
* Get the Drizzle database instance for the primary database.
|
|
536
|
+
* This is a synchronous property that returns the initialized Drizzle client.
|
|
504
537
|
*
|
|
505
|
-
* @returns Primary database
|
|
538
|
+
* @returns Primary database Drizzle instance
|
|
506
539
|
* @throws Error if primary database client is not initialized
|
|
507
540
|
*/
|
|
508
|
-
get
|
|
541
|
+
get drizzleClient(): TypedDrizzleClient;
|
|
542
|
+
/**
|
|
543
|
+
* Get the Drizzle schema
|
|
544
|
+
*/
|
|
545
|
+
get schema(): typeof this$1.options.drizzleSchema;
|
|
509
546
|
/**
|
|
510
547
|
* Decrypt database credentials
|
|
511
548
|
*
|
|
@@ -519,90 +556,123 @@ declare class PrimaryDatabaseService implements OnModuleInit, OnModuleDestroy {
|
|
|
519
556
|
}
|
|
520
557
|
|
|
521
558
|
/**
|
|
522
|
-
*
|
|
559
|
+
* Type-safe wrapper for Drizzle's RelationalQueryBuilder.
|
|
560
|
+
* This interface matches the method signatures of RelationalQueryBuilder
|
|
561
|
+
* but properly binds the TSelect generic for type safety.
|
|
562
|
+
*
|
|
563
|
+
* We use this instead of RelationalQueryBuilder directly because
|
|
564
|
+
* TypeScript cannot infer TSelect from the generic base repository context.
|
|
565
|
+
*/
|
|
566
|
+
interface TypedRelationalQueryBuilder<TSelect> {
|
|
567
|
+
findFirst(config?: {
|
|
568
|
+
where?: SQL;
|
|
569
|
+
with?: Record<string, unknown>;
|
|
570
|
+
columns?: Record<string, boolean>;
|
|
571
|
+
}): Promise<TSelect | undefined>;
|
|
572
|
+
findMany(config?: {
|
|
573
|
+
where?: SQL;
|
|
574
|
+
orderBy?: SQL;
|
|
575
|
+
limit?: number;
|
|
576
|
+
offset?: number;
|
|
577
|
+
with?: Record<string, unknown>;
|
|
578
|
+
columns?: Record<string, boolean>;
|
|
579
|
+
}): Promise<TSelect[]>;
|
|
580
|
+
}
|
|
581
|
+
/**
|
|
582
|
+
* Abstract base repository for primary database operations using Drizzle ORM.
|
|
523
583
|
* Provides common CRUD operations with automatic logging.
|
|
524
584
|
*
|
|
525
|
-
* @template
|
|
526
|
-
* @template
|
|
527
|
-
* @template
|
|
585
|
+
* @template TTable - The Drizzle table type (must be registered in SchemaRegistry)
|
|
586
|
+
* @template TInsert - Type for insert operations (inferred from table.$inferInsert)
|
|
587
|
+
* @template TSelect - Type for select operations (inferred from table.$inferSelect)
|
|
588
|
+
*
|
|
589
|
+
* @remarks
|
|
590
|
+
* **Type Assertion Pattern:** This repository uses `as any` casts when passing
|
|
591
|
+
* the generic table to Drizzle methods. This is necessary because TypeScript
|
|
592
|
+
* cannot prove that a generic `TTable extends PgTable` satisfies Drizzle's
|
|
593
|
+
* stricter internal type requirements for `insert()`, `update()`, and `delete()`.
|
|
594
|
+
*
|
|
595
|
+
* The public API maintains full type safety:
|
|
596
|
+
* - Input parameters are typed as `TInsert` (inferred from table)
|
|
597
|
+
* - Return values are typed as `TSelect` (inferred from table)
|
|
598
|
+
* - The casts are implementation details that don't leak to consumers
|
|
528
599
|
*
|
|
529
600
|
* @example
|
|
530
601
|
* ```typescript
|
|
531
|
-
*
|
|
532
|
-
* // Type-safe, IDE autocomplete, refactor-friendly
|
|
533
|
-
* @Injectable()
|
|
534
|
-
* export class UserRepository extends PrimaryBaseRepository<
|
|
535
|
-
* User,
|
|
536
|
-
* CreateUserDto,
|
|
537
|
-
* UpdateUserDto
|
|
538
|
-
* > {
|
|
539
|
-
* constructor(database: PrimaryDatabaseService) {
|
|
540
|
-
* super(database, (prisma) => prisma.user); // ✅ Type-safe with autocomplete!
|
|
541
|
-
* }
|
|
602
|
+
* import { users } from '@/db/schema';
|
|
542
603
|
*
|
|
543
|
-
*
|
|
544
|
-
*
|
|
545
|
-
* return this.model.findUnique({ where: { email } });
|
|
546
|
-
* }
|
|
547
|
-
* }
|
|
604
|
+
* type User = typeof users.$inferSelect;
|
|
605
|
+
* type NewUser = typeof users.$inferInsert;
|
|
548
606
|
*
|
|
549
|
-
* // Short syntax is also supported
|
|
550
607
|
* @Injectable()
|
|
551
|
-
* export class
|
|
608
|
+
* export class UserRepository extends PrimaryBaseRepository<typeof users> {
|
|
552
609
|
* constructor(database: PrimaryDatabaseService) {
|
|
553
|
-
* super(database,
|
|
610
|
+
* super(database, users);
|
|
554
611
|
* }
|
|
555
|
-
* }
|
|
556
612
|
*
|
|
557
|
-
*
|
|
558
|
-
*
|
|
559
|
-
*
|
|
560
|
-
*
|
|
561
|
-
*
|
|
613
|
+
* // Use Prisma-like relational query syntax (recommended)
|
|
614
|
+
* async findByEmail(email: string): Promise<User | undefined> {
|
|
615
|
+
* return this.model.findFirst({
|
|
616
|
+
* where: eq(users.email, email),
|
|
617
|
+
* });
|
|
618
|
+
* }
|
|
619
|
+
*
|
|
620
|
+
* // Use Prisma-like with relations
|
|
621
|
+
* async findWithRelations(id: string): Promise<User | undefined> {
|
|
622
|
+
* return this.model.findFirst({
|
|
623
|
+
* where: eq(users.id, id),
|
|
624
|
+
* with: { posts: true, profile: true }
|
|
625
|
+
* });
|
|
562
626
|
* }
|
|
563
627
|
* }
|
|
564
628
|
* ```
|
|
565
629
|
*/
|
|
566
|
-
declare abstract class PrimaryBaseRepository<
|
|
630
|
+
declare abstract class PrimaryBaseRepository<TTable extends PgTable, TInsert = InferInsertModel<TTable>, TSelect = InferSelectModel<TTable>> {
|
|
567
631
|
protected readonly database: PrimaryDatabaseService;
|
|
632
|
+
protected readonly table: TTable;
|
|
568
633
|
protected readonly logger: Logger;
|
|
569
|
-
private readonly modelGetter;
|
|
570
634
|
/**
|
|
571
|
-
*
|
|
635
|
+
* The table name extracted from the Drizzle table at runtime.
|
|
636
|
+
* Used to access the query API for this repository's table.
|
|
637
|
+
*/
|
|
638
|
+
private readonly tableName;
|
|
639
|
+
/**
|
|
640
|
+
* Lazy getter for Drizzle client.
|
|
572
641
|
* Accesses the client from the database service only when needed,
|
|
573
642
|
* avoiding initialization timing issues with NestJS lifecycle.
|
|
574
643
|
*/
|
|
575
|
-
protected get
|
|
644
|
+
protected get db(): TypedDrizzleClient;
|
|
576
645
|
/**
|
|
577
|
-
*
|
|
578
|
-
*
|
|
646
|
+
* Model query API for THIS repository's table (Prisma-like syntax)
|
|
647
|
+
* Scoped to only the table this repository manages.
|
|
648
|
+
* Returns a type-safe wrapper around Drizzle's RelationalQueryBuilder.
|
|
649
|
+
*
|
|
650
|
+
* @example
|
|
651
|
+
* ```typescript
|
|
652
|
+
* // Use relational queries with type safety
|
|
653
|
+
* const user = await this.model.findFirst({
|
|
654
|
+
* where: eq(users.id, id),
|
|
655
|
+
* with: { posts: true, profile: true }
|
|
656
|
+
* });
|
|
657
|
+
* ```
|
|
579
658
|
*/
|
|
580
|
-
protected get model():
|
|
659
|
+
protected get model(): TypedRelationalQueryBuilder<TSelect>;
|
|
581
660
|
/**
|
|
582
661
|
* Create a new repository instance
|
|
583
662
|
*
|
|
584
663
|
* @param database - The primary database service
|
|
585
|
-
* @param
|
|
664
|
+
* @param table - The Drizzle table schema object
|
|
586
665
|
*
|
|
587
666
|
* @example
|
|
588
667
|
* ```typescript
|
|
589
|
-
*
|
|
590
|
-
* constructor(database: PrimaryDatabaseService) {
|
|
591
|
-
* super(database, (prisma) => prisma.user);
|
|
592
|
-
* }
|
|
668
|
+
* import { users } from '@/db/schema';
|
|
593
669
|
*
|
|
594
|
-
* // Short syntax
|
|
595
670
|
* constructor(database: PrimaryDatabaseService) {
|
|
596
|
-
* super(database,
|
|
597
|
-
* }
|
|
598
|
-
*
|
|
599
|
-
* // Complex model names
|
|
600
|
-
* constructor(database: PrimaryDatabaseService) {
|
|
601
|
-
* super(database, (p) => p.emailVerification);
|
|
671
|
+
* super(database, users);
|
|
602
672
|
* }
|
|
603
673
|
* ```
|
|
604
674
|
*/
|
|
605
|
-
constructor(database: PrimaryDatabaseService,
|
|
675
|
+
constructor(database: PrimaryDatabaseService, table: TTable);
|
|
606
676
|
/**
|
|
607
677
|
* Create a new record
|
|
608
678
|
*
|
|
@@ -613,63 +683,64 @@ declare abstract class PrimaryBaseRepository<TModel, TCreateDTO = any, TUpdateDT
|
|
|
613
683
|
* ```typescript
|
|
614
684
|
* const user = await userRepository.create({
|
|
615
685
|
* email: 'user@example.com',
|
|
616
|
-
*
|
|
686
|
+
* firstName: 'John'
|
|
617
687
|
* });
|
|
618
688
|
* ```
|
|
619
689
|
*/
|
|
620
|
-
create(data:
|
|
690
|
+
create(data: TInsert): Promise<TSelect>;
|
|
621
691
|
/**
|
|
622
692
|
* Find a single record by ID
|
|
623
693
|
*
|
|
624
694
|
* @param id - The record ID
|
|
625
|
-
* @returns Promise resolving to the record or
|
|
695
|
+
* @returns Promise resolving to the record or undefined if not found
|
|
626
696
|
*
|
|
627
697
|
* @example
|
|
628
698
|
* ```typescript
|
|
629
699
|
* const user = await userRepository.findById('user-id-123');
|
|
630
700
|
* ```
|
|
631
701
|
*/
|
|
632
|
-
findById(id: string): Promise<
|
|
702
|
+
findById(id: string): Promise<TSelect | undefined>;
|
|
633
703
|
/**
|
|
634
704
|
* Find a single record with custom where clause
|
|
635
705
|
*
|
|
636
|
-
* @param where -
|
|
637
|
-
* @returns Promise resolving to the record or
|
|
706
|
+
* @param where - SQL condition
|
|
707
|
+
* @returns Promise resolving to the record or undefined if not found
|
|
638
708
|
*
|
|
639
709
|
* @example
|
|
640
710
|
* ```typescript
|
|
641
|
-
*
|
|
642
|
-
* const user = await userRepository.findOne(
|
|
643
|
-
*
|
|
644
|
-
* // With include
|
|
645
|
-
* const user = await userRepository.findOne({
|
|
646
|
-
* where: { email: 'user@example.com' },
|
|
647
|
-
* include: { posts: true }
|
|
648
|
-
* });
|
|
711
|
+
* import { eq } from 'drizzle-orm';
|
|
712
|
+
* const user = await userRepository.findOne(eq(users.email, 'user@example.com'));
|
|
649
713
|
* ```
|
|
650
714
|
*/
|
|
651
|
-
findOne(where:
|
|
715
|
+
findOne(where: SQL): Promise<TSelect | undefined>;
|
|
652
716
|
/**
|
|
653
717
|
* Find multiple records
|
|
654
718
|
*
|
|
655
|
-
* @param
|
|
719
|
+
* @param options - Query options (where, orderBy, limit, offset)
|
|
656
720
|
* @returns Promise resolving to an array of records
|
|
657
721
|
*
|
|
658
722
|
* @example
|
|
659
723
|
* ```typescript
|
|
724
|
+
* import { eq, desc } from 'drizzle-orm';
|
|
725
|
+
*
|
|
660
726
|
* // Find all users
|
|
661
727
|
* const users = await userRepository.findMany();
|
|
662
728
|
*
|
|
663
729
|
* // Find with filtering and pagination
|
|
664
730
|
* const users = await userRepository.findMany({
|
|
665
|
-
* where:
|
|
666
|
-
* orderBy:
|
|
667
|
-
*
|
|
668
|
-
*
|
|
731
|
+
* where: eq(users.accountStatus, 'ACTIVE'),
|
|
732
|
+
* orderBy: desc(users.createdAt),
|
|
733
|
+
* limit: 10,
|
|
734
|
+
* offset: 0
|
|
669
735
|
* });
|
|
670
736
|
* ```
|
|
671
737
|
*/
|
|
672
|
-
findMany(
|
|
738
|
+
findMany(options?: {
|
|
739
|
+
where?: SQL;
|
|
740
|
+
orderBy?: SQL;
|
|
741
|
+
limit?: number;
|
|
742
|
+
offset?: number;
|
|
743
|
+
}): Promise<TSelect[]>;
|
|
673
744
|
/**
|
|
674
745
|
* Update a record by ID
|
|
675
746
|
*
|
|
@@ -680,28 +751,30 @@ declare abstract class PrimaryBaseRepository<TModel, TCreateDTO = any, TUpdateDT
|
|
|
680
751
|
* @example
|
|
681
752
|
* ```typescript
|
|
682
753
|
* const user = await userRepository.update('user-id-123', {
|
|
683
|
-
*
|
|
754
|
+
* firstName: 'Jane'
|
|
684
755
|
* });
|
|
685
756
|
* ```
|
|
686
757
|
*/
|
|
687
|
-
update(id: string, data:
|
|
758
|
+
update(id: string, data: Partial<TInsert>): Promise<TSelect>;
|
|
688
759
|
/**
|
|
689
760
|
* Update multiple records
|
|
690
761
|
*
|
|
691
|
-
* @param where -
|
|
762
|
+
* @param where - SQL condition to match records
|
|
692
763
|
* @param data - The data to update
|
|
693
764
|
* @returns Promise resolving to the count of updated records
|
|
694
765
|
*
|
|
695
766
|
* @example
|
|
696
767
|
* ```typescript
|
|
768
|
+
* import { eq } from 'drizzle-orm';
|
|
769
|
+
*
|
|
697
770
|
* const result = await userRepository.updateMany(
|
|
698
|
-
*
|
|
699
|
-
* {
|
|
771
|
+
* eq(users.accountStatus, 'PENDING'),
|
|
772
|
+
* { accountStatus: 'ACTIVE' }
|
|
700
773
|
* );
|
|
701
774
|
* console.log(`Updated ${result.count} users`);
|
|
702
775
|
* ```
|
|
703
776
|
*/
|
|
704
|
-
updateMany(where:
|
|
777
|
+
updateMany(where: SQL, data: Partial<TInsert>): Promise<{
|
|
705
778
|
count: number;
|
|
706
779
|
}>;
|
|
707
780
|
/**
|
|
@@ -715,142 +788,166 @@ declare abstract class PrimaryBaseRepository<TModel, TCreateDTO = any, TUpdateDT
|
|
|
715
788
|
* const user = await userRepository.delete('user-id-123');
|
|
716
789
|
* ```
|
|
717
790
|
*/
|
|
718
|
-
delete(id: string): Promise<
|
|
791
|
+
delete(id: string): Promise<TSelect>;
|
|
719
792
|
/**
|
|
720
793
|
* Delete multiple records
|
|
721
794
|
*
|
|
722
|
-
* @param where -
|
|
795
|
+
* @param where - SQL condition to match records
|
|
723
796
|
* @returns Promise resolving to the count of deleted records
|
|
724
797
|
*
|
|
725
798
|
* @example
|
|
726
799
|
* ```typescript
|
|
727
|
-
*
|
|
728
|
-
*
|
|
729
|
-
*
|
|
730
|
-
*
|
|
800
|
+
* import { lt } from 'drizzle-orm';
|
|
801
|
+
*
|
|
802
|
+
* const result = await userRepository.deleteMany(
|
|
803
|
+
* lt(users.createdAt, new Date('2020-01-01'))
|
|
804
|
+
* );
|
|
731
805
|
* console.log(`Deleted ${result.count} users`);
|
|
732
806
|
* ```
|
|
733
807
|
*/
|
|
734
|
-
deleteMany(where:
|
|
808
|
+
deleteMany(where: SQL): Promise<{
|
|
735
809
|
count: number;
|
|
736
810
|
}>;
|
|
737
811
|
/**
|
|
738
812
|
* Count records
|
|
739
813
|
*
|
|
740
|
-
* @param where - Optional
|
|
814
|
+
* @param where - Optional SQL condition to filter records
|
|
741
815
|
* @returns Promise resolving to the count of records
|
|
742
816
|
*
|
|
743
817
|
* @example
|
|
744
818
|
* ```typescript
|
|
819
|
+
* import { eq } from 'drizzle-orm';
|
|
820
|
+
*
|
|
745
821
|
* // Count all users
|
|
746
822
|
* const total = await userRepository.count();
|
|
747
823
|
*
|
|
748
824
|
* // Count active users
|
|
749
|
-
* const activeCount = await userRepository.count(
|
|
825
|
+
* const activeCount = await userRepository.count(
|
|
826
|
+
* eq(users.accountStatus, 'ACTIVE')
|
|
827
|
+
* );
|
|
750
828
|
* ```
|
|
751
829
|
*/
|
|
752
|
-
count(where?:
|
|
830
|
+
count(where?: SQL): Promise<number>;
|
|
753
831
|
/**
|
|
754
832
|
* Check if a record exists
|
|
755
833
|
*
|
|
756
|
-
* @param where -
|
|
834
|
+
* @param where - SQL condition to match records
|
|
757
835
|
* @returns Promise resolving to true if at least one record exists, false otherwise
|
|
758
836
|
*
|
|
759
837
|
* @example
|
|
760
838
|
* ```typescript
|
|
761
|
-
*
|
|
762
|
-
*
|
|
763
|
-
*
|
|
839
|
+
* import { eq } from 'drizzle-orm';
|
|
840
|
+
*
|
|
841
|
+
* const emailExists = await userRepository.exists(
|
|
842
|
+
* eq(users.email, 'user@example.com')
|
|
843
|
+
* );
|
|
764
844
|
* ```
|
|
765
845
|
*/
|
|
766
|
-
exists(where:
|
|
846
|
+
exists(where: SQL): Promise<boolean>;
|
|
767
847
|
}
|
|
768
848
|
|
|
769
849
|
/**
|
|
770
|
-
*
|
|
850
|
+
* Type helper to extract table name from Drizzle table.
|
|
851
|
+
* TTable['_']['name'] gives us the string literal type (e.g., 'products')
|
|
852
|
+
*/
|
|
853
|
+
type ExtractTableName<TTable extends PgTable> = TTable['_']['name'];
|
|
854
|
+
/**
|
|
855
|
+
* Abstract base repository for tenant-scoped database operations using Drizzle ORM.
|
|
771
856
|
* All operations are automatically scoped to the current tenant.
|
|
772
857
|
*
|
|
773
|
-
* @template
|
|
774
|
-
* @template
|
|
775
|
-
* @template
|
|
858
|
+
* @template TTable - The Drizzle table type (must be registered in SchemaRegistry)
|
|
859
|
+
* @template TInsert - Type for insert operations (inferred from table.$inferInsert)
|
|
860
|
+
* @template TSelect - Type for select operations (inferred from table.$inferSelect)
|
|
861
|
+
*
|
|
862
|
+
* @remarks
|
|
863
|
+
* **Type Assertion Pattern:** This repository uses `as any` casts when passing
|
|
864
|
+
* the generic table to Drizzle methods. This is necessary because TypeScript
|
|
865
|
+
* cannot prove that a generic `TTable extends PgTable` satisfies Drizzle's
|
|
866
|
+
* stricter internal type requirements for `insert()`, `update()`, and `delete()`.
|
|
867
|
+
*
|
|
868
|
+
* The public API maintains full type safety:
|
|
869
|
+
* - Input parameters are typed as `TInsert` (inferred from table)
|
|
870
|
+
* - Return values are typed as `TSelect` (inferred from table)
|
|
871
|
+
* - The casts are implementation details that don't leak to consumers
|
|
776
872
|
*
|
|
777
873
|
* @example
|
|
778
874
|
* ```typescript
|
|
779
|
-
*
|
|
780
|
-
*
|
|
875
|
+
* import { products } from '@/db/schema';
|
|
876
|
+
*
|
|
877
|
+
* type Product = typeof products.$inferSelect;
|
|
878
|
+
* type NewProduct = typeof products.$inferInsert;
|
|
879
|
+
*
|
|
781
880
|
* @Injectable()
|
|
782
|
-
* export class ProductRepository extends TenantBaseRepository<
|
|
783
|
-
* Product,
|
|
784
|
-
* CreateProductDto,
|
|
785
|
-
* UpdateProductDto
|
|
786
|
-
* > {
|
|
881
|
+
* export class ProductRepository extends TenantBaseRepository<typeof products> {
|
|
787
882
|
* constructor(database: TenantDatabaseService) {
|
|
788
|
-
* super(database,
|
|
883
|
+
* super(database, products);
|
|
789
884
|
* }
|
|
790
885
|
*
|
|
791
|
-
* //
|
|
886
|
+
* // Use SQL-builder syntax
|
|
792
887
|
* async findBySku(sku: string): Promise<Product | null> {
|
|
793
|
-
*
|
|
888
|
+
* const [result] = await this.db
|
|
889
|
+
* .select()
|
|
890
|
+
* .from(this.table)
|
|
891
|
+
* .where(eq(products.sku, sku))
|
|
892
|
+
* .limit(1);
|
|
893
|
+
* return result ?? null;
|
|
794
894
|
* }
|
|
795
|
-
* }
|
|
796
895
|
*
|
|
797
|
-
*
|
|
798
|
-
*
|
|
799
|
-
*
|
|
800
|
-
*
|
|
801
|
-
*
|
|
802
|
-
*
|
|
803
|
-
* }
|
|
804
|
-
*
|
|
805
|
-
* // Works with complex model names
|
|
806
|
-
* @Injectable()
|
|
807
|
-
* export class InventoryItemRepository extends TenantBaseRepository<InventoryItem> {
|
|
808
|
-
* constructor(database: TenantDatabaseService) {
|
|
809
|
-
* super(database, (p) => p.inventoryItem); // ✅ Matches Prisma naming
|
|
896
|
+
* // Use Prisma-like relational query syntax
|
|
897
|
+
* async findWithRelations(id: string): Promise<Product | null> {
|
|
898
|
+
* return await this.model.findFirst({
|
|
899
|
+
* where: eq(products.id, id),
|
|
900
|
+
* with: { category: true, variants: true }
|
|
901
|
+
* });
|
|
810
902
|
* }
|
|
811
903
|
* }
|
|
812
904
|
* ```
|
|
813
905
|
*/
|
|
814
|
-
declare abstract class TenantBaseRepository<
|
|
906
|
+
declare abstract class TenantBaseRepository<TTable extends PgTable, TInsert = InferInsertModel<TTable>, TSelect = InferSelectModel<TTable>> {
|
|
815
907
|
protected readonly database: TenantDatabaseService;
|
|
908
|
+
protected readonly table: TTable;
|
|
816
909
|
protected readonly logger: Logger;
|
|
817
|
-
private readonly modelGetter;
|
|
818
910
|
/**
|
|
819
|
-
*
|
|
911
|
+
* The table name extracted from the Drizzle table at runtime.
|
|
912
|
+
* Used to access the query API for this repository's table.
|
|
913
|
+
*/
|
|
914
|
+
private readonly tableName;
|
|
915
|
+
/**
|
|
916
|
+
* Lazy getter for Drizzle client.
|
|
820
917
|
* Accesses the client from the database service only when needed,
|
|
821
918
|
* avoiding initialization timing issues with NestJS lifecycle.
|
|
822
919
|
*/
|
|
823
|
-
protected get
|
|
920
|
+
protected get db(): TypedDrizzleClient;
|
|
824
921
|
/**
|
|
825
|
-
*
|
|
826
|
-
*
|
|
922
|
+
* Model query API for THIS repository's table (Prisma-like syntax)
|
|
923
|
+
* Scoped to only the table this repository manages
|
|
924
|
+
*
|
|
925
|
+
* @example
|
|
926
|
+
* ```typescript
|
|
927
|
+
* // Use relational queries with type safety
|
|
928
|
+
* const product = await this.model.findFirst({
|
|
929
|
+
* where: eq(products.id, id),
|
|
930
|
+
* with: { category: true, variants: true }
|
|
931
|
+
* });
|
|
932
|
+
* ```
|
|
827
933
|
*/
|
|
828
|
-
protected get model():
|
|
934
|
+
protected get model(): TypedDrizzleClient['query'][ExtractTableName<TTable> & keyof TypedDrizzleClient['query']];
|
|
829
935
|
/**
|
|
830
936
|
* Create a new repository instance
|
|
831
937
|
*
|
|
832
938
|
* @param database - The tenant database service
|
|
833
|
-
* @param
|
|
939
|
+
* @param table - The Drizzle table schema object
|
|
834
940
|
*
|
|
835
941
|
* @example
|
|
836
942
|
* ```typescript
|
|
837
|
-
*
|
|
838
|
-
* constructor(database: TenantDatabaseService) {
|
|
839
|
-
* super(database, (prisma) => prisma.product);
|
|
840
|
-
* }
|
|
943
|
+
* import { products } from '@/db/schema';
|
|
841
944
|
*
|
|
842
|
-
* // Short syntax
|
|
843
945
|
* constructor(database: TenantDatabaseService) {
|
|
844
|
-
* super(database,
|
|
845
|
-
* }
|
|
846
|
-
*
|
|
847
|
-
* // Complex model names
|
|
848
|
-
* constructor(database: TenantDatabaseService) {
|
|
849
|
-
* super(database, (p) => p.inventoryItem);
|
|
946
|
+
* super(database, products);
|
|
850
947
|
* }
|
|
851
948
|
* ```
|
|
852
949
|
*/
|
|
853
|
-
constructor(database: TenantDatabaseService,
|
|
950
|
+
constructor(database: TenantDatabaseService, table: TTable);
|
|
854
951
|
/**
|
|
855
952
|
* Create a new record
|
|
856
953
|
*
|
|
@@ -866,7 +963,7 @@ declare abstract class TenantBaseRepository<TModel, TCreateDTO = any, TUpdateDTO
|
|
|
866
963
|
* });
|
|
867
964
|
* ```
|
|
868
965
|
*/
|
|
869
|
-
create(data:
|
|
966
|
+
create(data: TInsert): Promise<TSelect>;
|
|
870
967
|
/**
|
|
871
968
|
* Find a single record by ID
|
|
872
969
|
*
|
|
@@ -878,47 +975,48 @@ declare abstract class TenantBaseRepository<TModel, TCreateDTO = any, TUpdateDTO
|
|
|
878
975
|
* const product = await productRepository.findById('product-id-123');
|
|
879
976
|
* ```
|
|
880
977
|
*/
|
|
881
|
-
findById(id: string): Promise<
|
|
978
|
+
findById(id: string): Promise<TSelect | null>;
|
|
882
979
|
/**
|
|
883
980
|
* Find a single record with custom where clause
|
|
884
981
|
*
|
|
885
|
-
* @param where -
|
|
982
|
+
* @param where - SQL condition
|
|
886
983
|
* @returns Promise resolving to the record or null if not found
|
|
887
984
|
*
|
|
888
985
|
* @example
|
|
889
986
|
* ```typescript
|
|
890
|
-
*
|
|
891
|
-
* const product = await productRepository.findOne(
|
|
892
|
-
*
|
|
893
|
-
* // With include
|
|
894
|
-
* const product = await productRepository.findOne({
|
|
895
|
-
* where: { sku: 'WDG-001' },
|
|
896
|
-
* include: { category: true }
|
|
897
|
-
* });
|
|
987
|
+
* import { eq } from 'drizzle-orm';
|
|
988
|
+
* const product = await productRepository.findOne(eq(products.sku, 'WDG-001'));
|
|
898
989
|
* ```
|
|
899
990
|
*/
|
|
900
|
-
findOne(where:
|
|
991
|
+
findOne(where: SQL): Promise<TSelect | null>;
|
|
901
992
|
/**
|
|
902
993
|
* Find multiple records
|
|
903
994
|
*
|
|
904
|
-
* @param
|
|
995
|
+
* @param options - Query options (where, orderBy, limit, offset)
|
|
905
996
|
* @returns Promise resolving to an array of records
|
|
906
997
|
*
|
|
907
998
|
* @example
|
|
908
999
|
* ```typescript
|
|
1000
|
+
* import { eq, desc } from 'drizzle-orm';
|
|
1001
|
+
*
|
|
909
1002
|
* // Find all products
|
|
910
1003
|
* const products = await productRepository.findMany();
|
|
911
1004
|
*
|
|
912
1005
|
* // Find with filtering and pagination
|
|
913
1006
|
* const products = await productRepository.findMany({
|
|
914
|
-
* where:
|
|
915
|
-
* orderBy:
|
|
916
|
-
*
|
|
917
|
-
*
|
|
1007
|
+
* where: eq(products.status, 'ACTIVE'),
|
|
1008
|
+
* orderBy: desc(products.createdAt),
|
|
1009
|
+
* limit: 10,
|
|
1010
|
+
* offset: 0
|
|
918
1011
|
* });
|
|
919
1012
|
* ```
|
|
920
1013
|
*/
|
|
921
|
-
findMany(
|
|
1014
|
+
findMany(options?: {
|
|
1015
|
+
where?: SQL;
|
|
1016
|
+
orderBy?: SQL;
|
|
1017
|
+
limit?: number;
|
|
1018
|
+
offset?: number;
|
|
1019
|
+
}): Promise<TSelect[]>;
|
|
922
1020
|
/**
|
|
923
1021
|
* Update a record by ID
|
|
924
1022
|
*
|
|
@@ -933,24 +1031,26 @@ declare abstract class TenantBaseRepository<TModel, TCreateDTO = any, TUpdateDTO
|
|
|
933
1031
|
* });
|
|
934
1032
|
* ```
|
|
935
1033
|
*/
|
|
936
|
-
update(id: string, data:
|
|
1034
|
+
update(id: string, data: Partial<TInsert>): Promise<TSelect>;
|
|
937
1035
|
/**
|
|
938
1036
|
* Update multiple records
|
|
939
1037
|
*
|
|
940
|
-
* @param where -
|
|
1038
|
+
* @param where - SQL condition to match records
|
|
941
1039
|
* @param data - The data to update
|
|
942
1040
|
* @returns Promise resolving to the count of updated records
|
|
943
1041
|
*
|
|
944
1042
|
* @example
|
|
945
1043
|
* ```typescript
|
|
1044
|
+
* import { eq } from 'drizzle-orm';
|
|
1045
|
+
*
|
|
946
1046
|
* const result = await productRepository.updateMany(
|
|
947
|
-
*
|
|
1047
|
+
* eq(products.status, 'PENDING'),
|
|
948
1048
|
* { status: 'ACTIVE' }
|
|
949
1049
|
* );
|
|
950
1050
|
* console.log(`Updated ${result.count} products`);
|
|
951
1051
|
* ```
|
|
952
1052
|
*/
|
|
953
|
-
updateMany(where:
|
|
1053
|
+
updateMany(where: SQL, data: Partial<TInsert>): Promise<{
|
|
954
1054
|
count: number;
|
|
955
1055
|
}>;
|
|
956
1056
|
/**
|
|
@@ -964,55 +1064,62 @@ declare abstract class TenantBaseRepository<TModel, TCreateDTO = any, TUpdateDTO
|
|
|
964
1064
|
* const product = await productRepository.delete('product-id-123');
|
|
965
1065
|
* ```
|
|
966
1066
|
*/
|
|
967
|
-
delete(id: string): Promise<
|
|
1067
|
+
delete(id: string): Promise<TSelect>;
|
|
968
1068
|
/**
|
|
969
1069
|
* Delete multiple records
|
|
970
1070
|
*
|
|
971
|
-
* @param where -
|
|
1071
|
+
* @param where - SQL condition to match records
|
|
972
1072
|
* @returns Promise resolving to the count of deleted records
|
|
973
1073
|
*
|
|
974
1074
|
* @example
|
|
975
1075
|
* ```typescript
|
|
976
|
-
*
|
|
977
|
-
*
|
|
978
|
-
*
|
|
979
|
-
*
|
|
1076
|
+
* import { lt } from 'drizzle-orm';
|
|
1077
|
+
*
|
|
1078
|
+
* const result = await productRepository.deleteMany(
|
|
1079
|
+
* lt(products.createdAt, new Date('2020-01-01'))
|
|
1080
|
+
* );
|
|
980
1081
|
* console.log(`Deleted ${result.count} products`);
|
|
981
1082
|
* ```
|
|
982
1083
|
*/
|
|
983
|
-
deleteMany(where:
|
|
1084
|
+
deleteMany(where: SQL): Promise<{
|
|
984
1085
|
count: number;
|
|
985
1086
|
}>;
|
|
986
1087
|
/**
|
|
987
1088
|
* Count records
|
|
988
1089
|
*
|
|
989
|
-
* @param where - Optional
|
|
1090
|
+
* @param where - Optional SQL condition to filter records
|
|
990
1091
|
* @returns Promise resolving to the count of records
|
|
991
1092
|
*
|
|
992
1093
|
* @example
|
|
993
1094
|
* ```typescript
|
|
1095
|
+
* import { eq } from 'drizzle-orm';
|
|
1096
|
+
*
|
|
994
1097
|
* // Count all products
|
|
995
1098
|
* const total = await productRepository.count();
|
|
996
1099
|
*
|
|
997
1100
|
* // Count active products
|
|
998
|
-
* const activeCount = await productRepository.count(
|
|
1101
|
+
* const activeCount = await productRepository.count(
|
|
1102
|
+
* eq(products.status, 'ACTIVE')
|
|
1103
|
+
* );
|
|
999
1104
|
* ```
|
|
1000
1105
|
*/
|
|
1001
|
-
count(where?:
|
|
1106
|
+
count(where?: SQL): Promise<number>;
|
|
1002
1107
|
/**
|
|
1003
1108
|
* Check if a record exists
|
|
1004
1109
|
*
|
|
1005
|
-
* @param where -
|
|
1110
|
+
* @param where - SQL condition to match records
|
|
1006
1111
|
* @returns Promise resolving to true if at least one record exists, false otherwise
|
|
1007
1112
|
*
|
|
1008
1113
|
* @example
|
|
1009
1114
|
* ```typescript
|
|
1010
|
-
*
|
|
1011
|
-
*
|
|
1012
|
-
*
|
|
1115
|
+
* import { eq } from 'drizzle-orm';
|
|
1116
|
+
*
|
|
1117
|
+
* const skuExists = await productRepository.exists(
|
|
1118
|
+
* eq(products.sku, 'WDG-001')
|
|
1119
|
+
* );
|
|
1013
1120
|
* ```
|
|
1014
1121
|
*/
|
|
1015
|
-
exists(where:
|
|
1122
|
+
exists(where: SQL): Promise<boolean>;
|
|
1016
1123
|
}
|
|
1017
1124
|
|
|
1018
1125
|
declare class RequestService {
|
|
@@ -1336,7 +1443,7 @@ declare class HttpExceptionFilter implements ExceptionFilter {
|
|
|
1336
1443
|
catch(exception: unknown, host: ArgumentsHost): void;
|
|
1337
1444
|
}
|
|
1338
1445
|
|
|
1339
|
-
interface FieldError
|
|
1446
|
+
interface FieldError {
|
|
1340
1447
|
field?: string;
|
|
1341
1448
|
message: string;
|
|
1342
1449
|
}
|
|
@@ -1346,13 +1453,9 @@ interface ProblemDetails {
|
|
|
1346
1453
|
detail: string;
|
|
1347
1454
|
}
|
|
1348
1455
|
interface ApiErrorResponse extends ProblemDetails {
|
|
1349
|
-
errors: FieldError
|
|
1456
|
+
errors: FieldError[];
|
|
1350
1457
|
}
|
|
1351
1458
|
|
|
1352
|
-
interface FieldError {
|
|
1353
|
-
field?: string;
|
|
1354
|
-
message: string;
|
|
1355
|
-
}
|
|
1356
1459
|
declare abstract class BaseFieldException extends HttpException {
|
|
1357
1460
|
constructor(statusOrMessageOrErrors: HttpStatus | string | FieldError[], messageOrStatus?: string | HttpStatus, statusOrDetail?: HttpStatus | string, detail?: string);
|
|
1358
1461
|
}
|
|
@@ -2167,4 +2270,4 @@ declare function generateCorrelationId(): string;
|
|
|
2167
2270
|
*/
|
|
2168
2271
|
declare function addCorrelationIdToResponse(reply: FastifyReply, correlationId: string, headerName?: string): void;
|
|
2169
2272
|
|
|
2170
|
-
export { type ApiErrorResponse, AuthConfigModule, BadGatewayException, BadRequestException, BaseFieldException, ConflictException, type CorrelationContext, CorrelationIdMiddleware, CsrfGuard, DEFAULT_CORRELATION_HEADER, DatabaseModule, type DatabaseModuleOptions, type FieldError, ForbiddenException, GoneException, HttpExceptionFilter, HttpLoggerInterceptor, type HttpLoggerOptions, HttpModule, InternalServerErrorException, LOGGER_MODULE_OPTIONS, type LogFormat, type LogLevel, type LogMetadata, LoggerModule, type LoggerModuleAsyncOptions, type LoggerModuleOptions, type LoggerOptionsFactory, LoggerService, MethodNotAllowedException, NotAcceptableException, NotFoundException, NotImplementedException, Onboarding, PayloadTooLargeException, PrimaryBaseRepository, PrimaryDatabaseService, type PrimaryDbConfig, type ProblemDetails, Public, RequestTimeoutException, ServiceUnavailableException, Tenant, TenantBaseRepository, TenantContextService, TenantDatabaseService, type TenantInfo, TooManyRequestsException, UnauthorizedException, UnprocessableEntityException, UnsupportedMediaTypeException, ValidationException, VrittiAuthGuard, addCorrelationIdToResponse, correlationStorage, generateCorrelationId, getCorrelationContext, getHttpStatusTitle, runWithCorrelationContext, updateCorrelationContext };
|
|
2273
|
+
export { type ApiErrorResponse, AuthConfigModule, BadGatewayException, BadRequestException, BaseFieldException, ConflictException, type CorrelationContext, CorrelationIdMiddleware, CsrfGuard, DEFAULT_CORRELATION_HEADER, DatabaseModule, type DatabaseModuleOptions, type FieldError, ForbiddenException, GoneException, HttpExceptionFilter, HttpLoggerInterceptor, type HttpLoggerOptions, HttpModule, InternalServerErrorException, LOGGER_MODULE_OPTIONS, type LogFormat, type LogLevel, type LogMetadata, LoggerModule, type LoggerModuleAsyncOptions, type LoggerModuleOptions, type LoggerOptionsFactory, LoggerService, MethodNotAllowedException, NotAcceptableException, NotFoundException, NotImplementedException, Onboarding, PayloadTooLargeException, PrimaryBaseRepository, PrimaryDatabaseService, type PrimaryDbConfig, type ProblemDetails, Public, type RegisteredSchema, RequestTimeoutException, type SchemaRegistry, ServiceUnavailableException, Tenant, TenantBaseRepository, TenantContextService, TenantDatabaseService, type TenantInfo, TooManyRequestsException, type TypedDrizzleClient, UnauthorizedException, UnprocessableEntityException, UnsupportedMediaTypeException, ValidationException, VrittiAuthGuard, addCorrelationIdToResponse, correlationStorage, generateCorrelationId, getCorrelationContext, getHttpStatusTitle, runWithCorrelationContext, updateCorrelationContext };
|