-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.ts
126 lines (104 loc) · 2.88 KB
/
index.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
114
115
116
117
118
119
120
121
122
123
124
125
126
export interface UnitOfWork {
beginWork (): void
commitWork (): Promise<void>
}
export interface UowObject<Tx> {
createByTx (tx: Tx): Promise<void>
updateByTx (tx: Tx): Promise<void>
deleteByTx (tx: Tx): Promise<void>
}
export abstract class Uow<Tx> implements UnitOfWork {
private creates: UowObject<Tx>[] = []
private updates: UowObject<Tx>[] = []
private deletes: UowObject<Tx>[] = []
private isActive: boolean = false
/* abstract */
/**
* begin begins a new transaction
*/
protected abstract begin (): Promise<Tx>
/**
* commit commits a transaction
*/
protected abstract commit (tx: Tx): Promise<void>
/**
* rollback rollbacks a transaction
*/
protected abstract rollback (tx: Tx): Promise<void>
/**
* release releases a transaction (should be overridden if needed)
*/
protected release (tx: Tx): Promise<void> {
return Promise.resolve()
}
/**
* beginWork begins a transaction in this unit of work
*/
public beginWork (): void {
this.isActive = true
}
/**
* commitWork commits all actions in this unit of work
*/
public commitWork (): Promise<void> {
return this.commitChanges()
}
/* protected */
/**
* markCreate caches object which is going to be created
*/
protected markCreate (uowObj: UowObject<Tx>): Promise<void> {
return this.mark(() => this.creates.push(uowObj))
}
/**
* markUpdate caches object which is going to be updated
*/
protected markUpdate (uowObj: UowObject<Tx>): Promise<void> {
return this.mark(() => this.updates.push(uowObj))
}
/**
* markDelete caches object which is going to be deleted
*/
protected markDelete (uowObj: UowObject<Tx>): Promise<void> {
return this.mark(() => this.deletes.push(uowObj))
}
/* private */
private async mark (mark: () => void): Promise<void> {
mark()
if (!this.isActive) {
await this.commitChanges()
}
}
private async commitChanges (): Promise<void> {
const tx = await this.begin()
try {
// for the possibility of multiple db manipulations in each commit,
// commits should wait for others to finish before continuing
await this.commitCreates(tx)
await this.commitUpdates(tx)
await this.commitDeletes(tx)
await this.commit(tx)
} catch (e) {
await this.rollback(tx)
throw e
} finally {
await this.release(tx)
this.dispose()
}
}
private async commitCreates (tx: Tx): Promise<void> {
await Promise.all(this.creates.map(m => m.createByTx(tx)))
}
private async commitUpdates (tx: Tx): Promise<void> {
await Promise.all(this.updates.map(m => m.updateByTx(tx)))
}
private async commitDeletes (tx: Tx): Promise<void> {
await Promise.all(this.deletes.map(m => m.deleteByTx(tx)))
}
private dispose () {
this.creates = []
this.updates = []
this.deletes = []
this.isActive = false
}
}