Skip to content

Commit fd060a8

Browse files
committed
fix: made type-metadata.storage.ts much faster
Changed the data modeling of type-metadata storage to store the data in maps instead of arrays. This results in a dramatic improvement of application startup time since many of the lookups for metadata are now in O(1) instead of O(n)
1 parent 7b96060 commit fd060a8

File tree

4 files changed

+407
-174
lines changed

4 files changed

+407
-174
lines changed
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import {
2+
ClassDirectiveMetadata,
3+
ClassExtensionsMetadata,
4+
ClassMetadata,
5+
MethodArgsMetadata,
6+
PropertyDirectiveMetadata,
7+
PropertyExtensionsMetadata,
8+
PropertyMetadata,
9+
ResolverClassMetadata,
10+
} from '../metadata';
11+
import { InterfaceMetadata } from '../metadata/interface.metadata';
12+
import { ObjectTypeMetadata } from '../metadata/object-type.metadata';
13+
14+
export class MapByName<T> {
15+
protected map = new Map<string, T>();
16+
protected all: T[] = [];
17+
18+
getAll() {
19+
return this.all;
20+
}
21+
22+
getByName(name: string) {
23+
return this.map.get(name);
24+
}
25+
26+
add(value: T extends any[] ? T[number] : T, name: string) {
27+
if (this.map.has(name)) return;
28+
29+
this.map.set(name, value);
30+
this.all.push(value);
31+
}
32+
33+
unshift(value: T extends any[] ? T[number] : T, name: string) {
34+
if (this.map.has(name)) return;
35+
36+
this.map.set(name, value);
37+
this.all.unshift(value);
38+
}
39+
}
40+
41+
export class MapArrayByName<T> extends MapByName<T[]> {
42+
getByName(name: string): T[] {
43+
return super.getByName(name) || [];
44+
}
45+
46+
add(value: T[] extends any[] ? T[][number] : T[], name: string) {
47+
let arrayResult = this.map.get(name);
48+
if (!arrayResult) {
49+
arrayResult = [];
50+
this.map.set(name, arrayResult);
51+
}
52+
53+
arrayResult.push(value);
54+
this.all.push(value);
55+
}
56+
}
57+
58+
export class FieldDirectiveMap extends MapArrayByName<PropertyDirectiveMetadata> {
59+
sdls = new Set<string>();
60+
fieldNames = new Set<string>();
61+
62+
add(value: PropertyDirectiveMetadata) {
63+
if (this.sdls.has(value.sdl) && this.fieldNames.has(value.fieldName))
64+
return;
65+
66+
super.add(value, value.fieldName);
67+
68+
this.sdls.add(value.sdl);
69+
this.fieldNames.add(value.fieldName);
70+
}
71+
}
72+
73+
export class TypeMetadataStorageModel {
74+
fieldDirectives = new FieldDirectiveMap();
75+
fieldExtensions = new MapArrayByName<PropertyExtensionsMetadata>();
76+
fields = new MapByName<PropertyMetadata>();
77+
params = new MapArrayByName<MethodArgsMetadata>();
78+
classDirectives = new Array<ClassDirectiveMetadata>();
79+
classExtensions = new Array<ClassExtensionsMetadata>();
80+
argumentType: ClassMetadata;
81+
interface: InterfaceMetadata;
82+
inputType: ClassMetadata;
83+
objectType: ObjectTypeMetadata;
84+
resolver: ResolverClassMetadata;
85+
}
86+
87+
export class TypeMetadataStorageModelList {
88+
private map = new Map<Function, TypeMetadataStorageModel>();
89+
private array = new Array<TypeMetadataStorageModel>();
90+
91+
get(target: Function) {
92+
let metadata = this.map.get(target);
93+
94+
if (!metadata) {
95+
metadata = new TypeMetadataStorageModel();
96+
this.map.set(target, metadata);
97+
this.array.push(metadata);
98+
}
99+
100+
return metadata;
101+
}
102+
103+
private getAllWithoutNullsByPredicate<V>(
104+
predicate: (t: TypeMetadataStorageModel) => V,
105+
) {
106+
return this.array.reduce((prev, curr) => {
107+
const val = predicate(curr);
108+
if (val) prev.push(val);
109+
return prev;
110+
}, new Array<V>());
111+
}
112+
113+
getAll() {
114+
return {
115+
argumentType: () =>
116+
this.getAllWithoutNullsByPredicate((t) => t.argumentType),
117+
interface: () => this.getAllWithoutNullsByPredicate((t) => t.interface),
118+
inputType: () => this.getAllWithoutNullsByPredicate((t) => t.inputType),
119+
objectType: () => this.getAllWithoutNullsByPredicate((t) => t.objectType),
120+
resolver: () => this.getAllWithoutNullsByPredicate((t) => t.resolver),
121+
classDirectives: () => this.array.flatMap((t) => t.classDirectives),
122+
classExtensions: () => this.array.flatMap((t) => t.classExtensions),
123+
fieldDirectives: () =>
124+
this.array.flatMap((t) => t.fieldDirectives.getAll()),
125+
fieldExtensions: () =>
126+
this.array.flatMap((t) => t.fieldExtensions.getAll()),
127+
};
128+
}
129+
}

0 commit comments

Comments
 (0)