Skip to content

Commit 5b24aae

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 5aaefdb commit 5b24aae

11 files changed

+257
-238
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
export class ArrayCollection<T> extends Array<T> {
2+
constructor(private globalArray: Array<T>) {
3+
super();
4+
}
5+
6+
push(...items): number {
7+
this.globalArray.push(...items);
8+
return super.push(...items);
9+
}
10+
11+
unshift(...items): number {
12+
this.globalArray.unshift(...items);
13+
return super.unshift(...items);
14+
}
15+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { MetadataListByNameCollection } from './metadata.list.by.name.collection';
2+
import { PropertyDirectiveMetadata } from '../metadata';
3+
4+
export class FieldDirectiveCollection extends MetadataListByNameCollection<PropertyDirectiveMetadata> {
5+
sdls = new Set<string>();
6+
fieldNames = new Set<string>();
7+
8+
add(value: PropertyDirectiveMetadata) {
9+
if (this.sdls.has(value.sdl) && this.fieldNames.has(value.fieldName))
10+
return;
11+
12+
super.add(value, value.fieldName);
13+
14+
this.sdls.add(value.sdl);
15+
this.fieldNames.add(value.fieldName);
16+
this.globalArray && this.globalArray.push(value);
17+
}
18+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export * from './metadata.storage.collection.list';
2+
export * from './field.directive.collection';
3+
export * from './array.collection';
4+
export * from './metada.collection.model.interface';
5+
export * from './metadata.by.name.collection';
6+
export * from './metadata.list.by.name.collection';
7+
export * from './metadata.storage.collection';
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { ClassMetadata, ResolverClassMetadata } from '../metadata';
2+
import { ObjectTypeMetadata } from '../metadata/object-type.metadata';
3+
4+
export interface MetadataCollectionModelInterface {
5+
argumentType: ClassMetadata[];
6+
interface: ClassMetadata[];
7+
inputType: ClassMetadata[];
8+
objectType: ObjectTypeMetadata[];
9+
resolver: ResolverClassMetadata[];
10+
classDirectives: [];
11+
classExtensions: [];
12+
fieldDirectives: [];
13+
fieldExtensions: [];
14+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
export class MetadataByNameCollection<T> {
2+
protected map = new Map<string, T>();
3+
protected all: (T extends any[] ? T[number] : T)[] = [];
4+
5+
getAll() {
6+
return this.all;
7+
}
8+
9+
getByName(name: string) {
10+
return this.map.get(name);
11+
}
12+
13+
add(value: T extends any[] ? T[number] : T, name: string) {
14+
if (this.map.has(name)) return;
15+
16+
this.map.set(name, value);
17+
this.all.push(value);
18+
}
19+
20+
unshift(value: T extends any[] ? T[number] : T, name: string) {
21+
if (this.map.has(name)) return;
22+
23+
this.map.set(name, value);
24+
this.all.unshift(value);
25+
}
26+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { MetadataByNameCollection } from './metadata.by.name.collection';
2+
3+
export class MetadataListByNameCollection<T> extends MetadataByNameCollection<
4+
T[]
5+
> {
6+
constructor(protected globalArray: Array<T> = null) {
7+
super();
8+
}
9+
10+
getByName(name: string): T[] {
11+
return super.getByName(name) || [];
12+
}
13+
14+
add(value: T, name: string) {
15+
let arrayResult = super.getByName(name);
16+
if (!arrayResult) {
17+
arrayResult = [];
18+
this.map.set(name, arrayResult);
19+
}
20+
21+
arrayResult.push(value);
22+
this.all.push(value);
23+
this.globalArray && this.globalArray.push(value);
24+
}
25+
26+
unshift(value: T, name: string) {
27+
let arrayResult = super.getByName(name);
28+
if (!arrayResult) {
29+
arrayResult = [];
30+
this.map.set(name, arrayResult);
31+
}
32+
33+
arrayResult.unshift(value);
34+
this.all.push(value);
35+
this.globalArray && this.globalArray.unshift(value);
36+
}
37+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { MetadataStorageCollection } from './metadata.storage.collection';
2+
import { MetadataCollectionModelInterface } from './metada.collection.model.interface';
3+
4+
export class MetadataStorageCollectionList {
5+
private storageMap = new Map<Function, MetadataStorageCollection>();
6+
private storageList = new Array<MetadataStorageCollection>();
7+
8+
public all: MetadataCollectionModelInterface = {
9+
argumentType: [],
10+
interface: [],
11+
inputType: [],
12+
objectType: [],
13+
resolver: [],
14+
classDirectives: [],
15+
classExtensions: [],
16+
fieldDirectives: [],
17+
fieldExtensions: [],
18+
};
19+
20+
get(target: Function) {
21+
let metadata = this.storageMap.get(target);
22+
23+
if (!metadata) {
24+
metadata = new MetadataStorageCollection(this.all);
25+
this.storageMap.set(target, metadata);
26+
this.storageList.push(metadata);
27+
}
28+
29+
return metadata;
30+
}
31+
32+
compile() {
33+
this.reversePredicate((t) => t.classDirectives);
34+
this.reversePredicate((t) => t.classExtensions);
35+
this.reversePredicate((t) => t.fieldDirectives.getAll());
36+
this.reversePredicate((t) => t.fieldExtensions.getAll());
37+
}
38+
39+
private reversePredicate<V>(
40+
predicate: (t: MetadataStorageCollection) => Array<V>,
41+
) {
42+
this.storageList.forEach((t) => predicate(t).reverse());
43+
}
44+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { MetadataByNameCollection } from './metadata.by.name.collection';
2+
import {
3+
ClassDirectiveMetadata,
4+
ClassExtensionsMetadata,
5+
ClassMetadata,
6+
MethodArgsMetadata,
7+
PropertyExtensionsMetadata,
8+
PropertyMetadata,
9+
ResolverClassMetadata,
10+
} from '../metadata';
11+
import { MetadataListByNameCollection } from './metadata.list.by.name.collection';
12+
import { FieldDirectiveCollection } from './field.directive.collection';
13+
import { ObjectTypeMetadata } from '../metadata/object-type.metadata';
14+
import { ArrayCollection } from './array.collection';
15+
import { MetadataCollectionModelInterface } from './metada.collection.model.interface';
16+
17+
export class MetadataStorageCollection {
18+
constructor(private all: MetadataCollectionModelInterface) {}
19+
20+
fields = new MetadataByNameCollection<PropertyMetadata>();
21+
params = new MetadataListByNameCollection<MethodArgsMetadata>();
22+
fieldDirectives = new FieldDirectiveCollection(this.all.fieldDirectives);
23+
fieldExtensions =
24+
new MetadataListByNameCollection<PropertyExtensionsMetadata>(
25+
this.all.fieldExtensions,
26+
);
27+
classDirectives = new ArrayCollection<ClassDirectiveMetadata>(
28+
this.all.classDirectives,
29+
);
30+
classExtensions = new ArrayCollection<ClassExtensionsMetadata>(
31+
this.all.classExtensions,
32+
);
33+
34+
set argumentType(val: ClassMetadata) {
35+
this._argumentType = val;
36+
this.all.argumentType.push(val);
37+
}
38+
get argumentType() {
39+
return this._argumentType;
40+
}
41+
42+
set interface(val: ClassMetadata) {
43+
this._interface = val;
44+
this.all.interface.push(val);
45+
}
46+
get interface() {
47+
return this._interface;
48+
}
49+
50+
set inputType(val: ClassMetadata) {
51+
this._inputType = val;
52+
this.all.inputType.push(val);
53+
}
54+
get inputType() {
55+
return this._inputType;
56+
}
57+
58+
set objectType(val: ObjectTypeMetadata) {
59+
this._objectType = val;
60+
this.all.objectType.push(val);
61+
}
62+
get objectType() {
63+
return this._objectType;
64+
}
65+
66+
set resolver(val: ResolverClassMetadata) {
67+
this._resolver = val;
68+
this.all.resolver.push(val);
69+
}
70+
get resolver() {
71+
return this._resolver;
72+
}
73+
74+
_argumentType: ClassMetadata;
75+
_interface: ClassMetadata;
76+
_inputType: ClassMetadata;
77+
_objectType: ObjectTypeMetadata;
78+
_resolver: ResolverClassMetadata;
79+
}

0 commit comments

Comments
 (0)