-
-
Notifications
You must be signed in to change notification settings - Fork 496
/
Reference.ts
113 lines (89 loc) · 3.06 KB
/
Reference.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import { AnyEntity, Dictionary, EntityProperty, Primary } from '../typings';
import { wrap } from './wrap';
export type IdentifiedReference<T, PK extends keyof T = 'id' & keyof T> = { [K in PK]: T[K] } & Reference<T>;
export class Reference<T> {
constructor(private entity: T) {
this.set(entity);
const wrapped = wrap(this.entity, true);
Object.defineProperty(this, '__reference', { value: true });
wrapped.__meta.primaryKeys.forEach(primaryKey => {
Object.defineProperty(this, primaryKey, {
get() {
return this.entity[primaryKey];
},
});
});
if (wrapped.__meta.serializedPrimaryKey && wrapped.__meta.primaryKeys[0] !== wrapped.__meta.serializedPrimaryKey) {
Object.defineProperty(this, wrapped.__meta.serializedPrimaryKey, {
get() {
return wrap(this.entity, true).__serializedPrimaryKey;
},
});
}
}
static create<T, PK extends keyof T>(entity: T | IdentifiedReference<T, PK>): IdentifiedReference<T, PK> {
if (Reference.isReference(entity)) {
return entity as IdentifiedReference<T, PK>;
}
return new Reference(entity) as IdentifiedReference<T, PK>;
}
/**
* Checks whether the argument is instance or `Reference` wrapper.
*/
static isReference<T extends AnyEntity<T>>(data: any): data is Reference<T> {
return data && !!data.__reference;
}
/**
* Wraps the entity in a `Reference` wrapper if the property is defined as `wrappedReference`.
*/
static wrapReference<T extends AnyEntity<T>>(entity: T | Reference<T>, prop: EntityProperty<T>): Reference<T> | T {
if (entity && prop.wrappedReference && !Reference.isReference(entity)) {
return Reference.create(entity as T);
}
return entity;
}
/**
* Returns wrapped entity.
*/
static unwrapReference<T extends AnyEntity<T>>(ref: T | Reference<T>): T {
return Reference.isReference<T>(ref) ? (ref as Reference<T>).unwrap() : ref;
}
async load(): Promise<T> {
if (this.isInitialized()) {
return this.entity;
}
return wrap(this.entity, true).init();
}
async get<K extends keyof T>(prop: K): Promise<T[K]> {
await this.load();
return this.entity[prop];
}
set(entity: T | IdentifiedReference<T>): void {
if (entity instanceof Reference) {
entity = entity.unwrap();
}
this.entity = entity;
Object.defineProperty(this, '__helper', { value: wrap(this.entity, true), writable: true });
}
unwrap(): T {
return this.entity;
}
getEntity(): T {
if (!this.isInitialized()) {
throw new Error(`Reference<${wrap(this, true).__meta.name}> ${(wrap(this.entity, true).__primaryKey as Primary<T>)} not initialized`);
}
return this.entity;
}
getProperty<K extends keyof T>(prop: K): T[K] {
return this.getEntity()[prop];
}
isInitialized(): boolean {
return wrap(this.entity, true).isInitialized();
}
populated(populated?: boolean): void {
wrap(this.entity, true).populated!(populated);
}
toJSON(...args: any[]): Dictionary {
return wrap(this.entity).toJSON!(...args);
}
}