@@ -3,6 +3,20 @@ import { ConstraintMetadata } from './ConstraintMetadata';
33import { ValidationSchema } from '../validation-schema/ValidationSchema' ;
44import { ValidationSchemaToMetadataTransformer } from '../validation-schema/ValidationSchemaToMetadataTransformer' ;
55import { getGlobal } from '../utils' ;
6+ import { ValidationTypes } from '../validation/ValidationTypes' ;
7+
8+ export interface PartitionedPropertyMetadata {
9+ defined : ValidationMetadata [ ] ;
10+ custom : ValidationMetadata [ ] ;
11+ nested : ValidationMetadata [ ] ;
12+ conditional : ValidationMetadata [ ] ;
13+ all : ValidationMetadata [ ] ;
14+ hasPromiseValidation : boolean ;
15+ /** True when only custom validators exist (no defined/nested/conditional) — enables fast path */
16+ customOnly : boolean ;
17+ }
18+
19+ export type PartitionedMetadata = Record < string , PartitionedPropertyMetadata > ;
620
721/**
822 * Storage all metadatas.
@@ -18,6 +32,7 @@ export class MetadataStorage {
1832 private constraintMetadatas : Map < any , ConstraintMetadata [ ] > = new Map ( ) ;
1933 private targetMetadataCache : Map < string , ValidationMetadata [ ] > = new Map ( ) ;
2034 private groupedMetadataCache : Map < string , Record < string , ValidationMetadata [ ] > > = new Map ( ) ;
35+ private partitionedMetadataCache : Map < string , PartitionedMetadata > = new Map ( ) ;
2136
2237 get hasValidationMetaData ( ) : boolean {
2338 return ! ! this . validationMetadatas . size ;
@@ -41,6 +56,7 @@ export class MetadataStorage {
4156 addValidationMetadata ( metadata : ValidationMetadata ) : void {
4257 this . targetMetadataCache . clear ( ) ;
4358 this . groupedMetadataCache . clear ( ) ;
59+ this . partitionedMetadataCache . clear ( ) ;
4460
4561 const existingMetadata = this . validationMetadatas . get ( metadata . target ) ;
4662
@@ -89,6 +105,57 @@ export class MetadataStorage {
89105 return grouped ;
90106 }
91107
108+ /**
109+ * Returns pre-partitioned metadata grouped by property name, with each property's
110+ * metadata split by type. Cached for repeated validations of the same class.
111+ */
112+ getPartitionedMetadata (
113+ groupedMetadatas : Record < string , ValidationMetadata [ ] > ,
114+ cacheKey : string
115+ ) : PartitionedMetadata {
116+ const cached = this . partitionedMetadataCache . get ( cacheKey ) ;
117+ if ( cached ) return cached ;
118+
119+ const result : PartitionedMetadata = { } ;
120+ for ( const propertyName in groupedMetadatas ) {
121+ const allMetadatas = groupedMetadatas [ propertyName ] ;
122+ const defined : ValidationMetadata [ ] = [ ] ;
123+ const custom : ValidationMetadata [ ] = [ ] ;
124+ const nested : ValidationMetadata [ ] = [ ] ;
125+ const conditional : ValidationMetadata [ ] = [ ] ;
126+ const all : ValidationMetadata [ ] = [ ] ;
127+ let hasPromiseValidation = false ;
128+
129+ for ( const metadata of allMetadatas ) {
130+ if ( metadata . type === ValidationTypes . IS_DEFINED ) {
131+ defined . push ( metadata ) ;
132+ } else if ( metadata . type !== ValidationTypes . WHITELIST ) {
133+ all . push ( metadata ) ;
134+ switch ( metadata . type ) {
135+ case ValidationTypes . CUSTOM_VALIDATION :
136+ custom . push ( metadata ) ;
137+ break ;
138+ case ValidationTypes . NESTED_VALIDATION :
139+ nested . push ( metadata ) ;
140+ break ;
141+ case ValidationTypes . CONDITIONAL_VALIDATION :
142+ conditional . push ( metadata ) ;
143+ break ;
144+ case ValidationTypes . PROMISE_VALIDATION :
145+ hasPromiseValidation = true ;
146+ break ;
147+ }
148+ }
149+ }
150+
151+ const customOnly = defined . length === 0 && nested . length === 0 && conditional . length === 0 && ! hasPromiseValidation ;
152+ result [ propertyName ] = { defined, custom, nested, conditional, all, hasPromiseValidation, customOnly } ;
153+ }
154+
155+ this . partitionedMetadataCache . set ( cacheKey , result ) ;
156+ return result ;
157+ }
158+
92159 /**
93160 * Gets all validation metadatas for the given object with the given groups.
94161 */
@@ -109,10 +176,11 @@ export class MetadataStorage {
109176 targetSchema : string ,
110177 always : boolean ,
111178 strictGroups : boolean ,
112- groups ?: string [ ]
179+ groups ?: string [ ] ,
180+ cacheKey ?: string
113181 ) : ValidationMetadata [ ] {
114- const cacheKey = this . buildCacheKey ( targetConstructor , targetSchema , always , strictGroups , groups ) ;
115- const cached = this . targetMetadataCache . get ( cacheKey ) ;
182+ const key = cacheKey ?? this . buildCacheKey ( targetConstructor , targetSchema , always , strictGroups , groups ) ;
183+ const cached = this . targetMetadataCache . get ( key ) ;
116184 if ( cached ) return cached ;
117185
118186 const includeMetadataBecauseOfAlwaysOption = ( metadata : ValidationMetadata ) : boolean => {
@@ -182,7 +250,7 @@ export class MetadataStorage {
182250 } ) ;
183251
184252 const result = originalMetadatas . concat ( uniqueInheritedMetadatas ) ;
185- this . targetMetadataCache . set ( cacheKey , result ) ;
253+ this . targetMetadataCache . set ( key , result ) ;
186254 return result ;
187255 }
188256
0 commit comments