@entity-access/entity-access 1.0.110 → 1.0.112
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/common/ObjectPool.d.ts +6 -2
- package/dist/common/ObjectPool.d.ts.map +1 -1
- package/dist/common/ObjectPool.js +33 -27
- package/dist/common/ObjectPool.js.map +1 -1
- package/dist/common/sleep.d.ts.map +1 -1
- package/dist/common/sleep.js +23 -2
- package/dist/common/sleep.js.map +1 -1
- package/dist/decorators/Relate.d.ts +16 -10
- package/dist/decorators/Relate.d.ts.map +1 -1
- package/dist/decorators/Relate.js +52 -46
- package/dist/decorators/Relate.js.map +1 -1
- package/dist/model/changes/ChangeEntry.d.ts.map +1 -1
- package/dist/model/changes/ChangeEntry.js +4 -3
- package/dist/model/changes/ChangeEntry.js.map +1 -1
- package/dist/tests/model/ShoppingContext.d.ts.map +1 -1
- package/dist/tests/model/ShoppingContext.js +2 -1
- package/dist/tests/model/ShoppingContext.js.map +1 -1
- package/dist/tests/pool/pool-test.d.ts.map +1 -1
- package/dist/tests/pool/pool-test.js +55 -47
- package/dist/tests/pool/pool-test.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/common/ObjectPool.ts +44 -28
- package/src/common/sleep.ts +23 -2
- package/src/decorators/Relate.ts +91 -97
- package/src/model/changes/ChangeEntry.ts +4 -3
- package/src/tests/model/ShoppingContext.ts +3 -2
- package/src/tests/pool/pool-test.ts +58 -51
package/src/common/ObjectPool.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import EntityAccessError from "./EntityAccessError.js";
|
|
3
3
|
import TimedCache from "./cache/TimedCache.js";
|
|
4
4
|
import sleep from "./sleep.js";
|
|
5
|
+
import "./IDisposable.js";
|
|
5
6
|
|
|
6
7
|
interface IObjectPool<T> {
|
|
7
8
|
factory?: () => T;
|
|
@@ -22,12 +23,16 @@ interface IObjectPool<T> {
|
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
25
|
* Max wait in milliseconds before creating
|
|
25
|
-
* new object, default is
|
|
26
|
+
* new object, default is 5 seconds
|
|
26
27
|
*/
|
|
27
28
|
maxWait?: number;
|
|
29
|
+
|
|
30
|
+
logger?: (text: string) => void;
|
|
28
31
|
}
|
|
29
32
|
|
|
30
|
-
export type IPooledObject<T> = T & {
|
|
33
|
+
export type IPooledObject<T> = T & {
|
|
34
|
+
[Symbol.asyncDisposable](): Promise<any>;
|
|
35
|
+
};
|
|
31
36
|
|
|
32
37
|
/**
|
|
33
38
|
* Most pool implementations are poor and are having too many errors.
|
|
@@ -63,10 +68,13 @@ export default class ObjectPool<T> {
|
|
|
63
68
|
|
|
64
69
|
private awaited: Set<AbortController> = new Set();
|
|
65
70
|
|
|
71
|
+
private logger: (text: string) => void;
|
|
72
|
+
|
|
66
73
|
constructor({
|
|
67
74
|
maxSize = 40,
|
|
68
75
|
maxWait = 5000,
|
|
69
76
|
poolSize = 20,
|
|
77
|
+
logger,
|
|
70
78
|
asyncFactory,
|
|
71
79
|
factory,
|
|
72
80
|
destroy,
|
|
@@ -79,6 +87,7 @@ export default class ObjectPool<T> {
|
|
|
79
87
|
this.factory = factory;
|
|
80
88
|
this.destroy = destroy;
|
|
81
89
|
this.subscribeForRemoval = subscribeForRemoval;
|
|
90
|
+
this.logger = logger;
|
|
82
91
|
}
|
|
83
92
|
|
|
84
93
|
public async dispose() {
|
|
@@ -94,51 +103,58 @@ export default class ObjectPool<T> {
|
|
|
94
103
|
}
|
|
95
104
|
|
|
96
105
|
public async acquire(): Promise<IPooledObject<T>> {
|
|
97
|
-
let
|
|
98
|
-
if(!
|
|
106
|
+
let existing = this.free.pop();
|
|
107
|
+
if(!existing) {
|
|
99
108
|
if (this.total >= this.poolSize) {
|
|
100
109
|
const a = new AbortController();
|
|
101
110
|
this.awaited.add(a);
|
|
102
111
|
await sleep(this.maxWait, a.signal);
|
|
103
112
|
this.awaited.delete(a);
|
|
104
|
-
|
|
113
|
+
existing = this.free.pop();
|
|
105
114
|
}
|
|
106
115
|
}
|
|
107
|
-
if(
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
throw new EntityAccessError(`Maximum size of pool reached. Retry after sometime.`);
|
|
111
|
-
}
|
|
112
|
-
this.total++;
|
|
116
|
+
if(existing) {
|
|
117
|
+
return existing as IPooledObject<T>;
|
|
118
|
+
}
|
|
113
119
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
item = this.factory();
|
|
117
|
-
} else {
|
|
118
|
-
item = await this.asyncFactory();
|
|
119
|
-
}
|
|
120
|
-
this.subscribeForRemoval(item as unknown as any, () => {
|
|
121
|
-
const index = this.free.indexOf(item);
|
|
122
|
-
this.free.splice(index, 1);
|
|
123
|
-
});
|
|
120
|
+
if (this.total >= this.maxSize) {
|
|
121
|
+
throw new EntityAccessError(`Maximum size of pool reached. Retry after sometime.`);
|
|
124
122
|
}
|
|
123
|
+
this.total++;
|
|
124
|
+
|
|
125
|
+
// create new..
|
|
126
|
+
const item = this.factory?.() ?? (await this.asyncFactory());
|
|
127
|
+
this.subscribeForRemoval(item as unknown as any, () => {
|
|
128
|
+
const index = this.free.indexOf(item);
|
|
129
|
+
this.free.splice(index, 1);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
return this.setupItem(item);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
private setupItem(item: T) {
|
|
125
137
|
const pooledItem = item as IPooledObject<T>;
|
|
126
138
|
pooledItem[Symbol.asyncDisposable] = async () => {
|
|
139
|
+
delete this[Symbol.asyncDisposable];
|
|
127
140
|
if (this.free.length < this.poolSize) {
|
|
128
|
-
this.
|
|
129
|
-
|
|
141
|
+
this.logger?.(`Pooled item ${pooledItem} freed.`);
|
|
142
|
+
this.free.push(pooledItem);
|
|
143
|
+
for (const [iterator] of this.awaited.entries()) {
|
|
130
144
|
this.awaited.delete(iterator);
|
|
131
145
|
iterator.abort();
|
|
132
|
-
|
|
146
|
+
return;
|
|
133
147
|
}
|
|
134
|
-
|
|
135
|
-
await this.destroy(item);
|
|
136
|
-
this.total--;
|
|
148
|
+
return;
|
|
137
149
|
}
|
|
150
|
+
this.total--;
|
|
151
|
+
this.logger?.(`Pooled item ${pooledItem} destoryed.`);
|
|
152
|
+
void this.destroy(pooledItem)?.catch(console.error);
|
|
138
153
|
};
|
|
154
|
+
this.logger?.(`Pooled item ${pooledItem} acquired.`);
|
|
155
|
+
this.logger?.(`Item ${pooledItem} has disposable ${typeof pooledItem[Symbol.asyncDisposable]}`);
|
|
139
156
|
return item as IPooledObject<T>;
|
|
140
157
|
}
|
|
141
|
-
|
|
142
158
|
}
|
|
143
159
|
|
|
144
160
|
export class NamedObjectPool<T> {
|
package/src/common/sleep.ts
CHANGED
|
@@ -3,14 +3,35 @@ export default async function sleep(n: number, signal?: AbortSignal, throwOnAbor
|
|
|
3
3
|
return;
|
|
4
4
|
}
|
|
5
5
|
return new Promise<void>((resolve, reject) => {
|
|
6
|
+
if (!signal) {
|
|
7
|
+
setTimeout(resolve, n);
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
let resolved = false;
|
|
11
|
+
const old = resolve;
|
|
12
|
+
resolve = () => {
|
|
13
|
+
if (resolved) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
resolved = true;
|
|
17
|
+
old();
|
|
18
|
+
};
|
|
19
|
+
const oldReject = reject;
|
|
20
|
+
reject = (r) => {
|
|
21
|
+
if (resolved) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
resolved = true;
|
|
25
|
+
oldReject(r);
|
|
26
|
+
};
|
|
6
27
|
const id = setTimeout(resolve, n);
|
|
7
|
-
signal
|
|
28
|
+
signal.onabort = () => {
|
|
8
29
|
clearTimeout(id);
|
|
9
30
|
if (throwOnAbort) {
|
|
10
31
|
reject("cancelled");
|
|
11
32
|
return;
|
|
12
33
|
}
|
|
13
34
|
resolve();
|
|
14
|
-
}
|
|
35
|
+
};
|
|
15
36
|
});
|
|
16
37
|
}
|
package/src/decorators/Relate.ts
CHANGED
|
@@ -2,95 +2,58 @@ import type { IClassOf } from "./IClassOf.js";
|
|
|
2
2
|
import SchemaRegistry from "./SchemaRegistry.js";
|
|
3
3
|
import NameParser from "./parser/NameParser.js";
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}: {
|
|
11
|
-
|
|
12
|
-
foreignKey: (item: T) => any;
|
|
13
|
-
|
|
14
|
-
inverseProperty: (item: TRelated) => T[];
|
|
15
|
-
|
|
16
|
-
inverseKey?: (item: TRelated) => any;
|
|
17
|
-
dotNotCreateIndex?: boolean;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
) {
|
|
21
|
-
return (target: T, key: string): any => {
|
|
22
|
-
|
|
23
|
-
const cn = target.constructor ?? target;
|
|
24
|
-
const type = SchemaRegistry.model(cn);
|
|
25
|
-
|
|
26
|
-
type.addRelation({
|
|
27
|
-
type,
|
|
28
|
-
name: key,
|
|
29
|
-
foreignKey: NameParser.parseMember(name),
|
|
30
|
-
relatedTypeClass: c,
|
|
31
|
-
relatedName: NameParser.parseMember(inv),
|
|
32
|
-
relatedKey: invKey ? NameParser.parseMember(invKey) : void 0,
|
|
33
|
-
dotNotCreateIndex
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
};
|
|
5
|
+
export interface IRelatedType<T, TRelated> {
|
|
6
|
+
property: (item: T) => TRelated;
|
|
7
|
+
inverseProperty: (item: TRelated) => T[];
|
|
8
|
+
inverseKey?: (item: TRelated) => any;
|
|
9
|
+
dotNotCreateIndex?: boolean;
|
|
37
10
|
}
|
|
38
11
|
|
|
39
|
-
export
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
inverseProperty: (item: TRelated) => T;
|
|
47
|
-
|
|
48
|
-
inverseKey?: (item: TRelated) => any;
|
|
49
|
-
dotNotCreateIndex?: boolean;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
) {
|
|
53
|
-
return (target: T, key: string): any => {
|
|
12
|
+
export interface IRelatedTypeOne<T, TRelated> {
|
|
13
|
+
property: (item: T) => TRelated;
|
|
14
|
+
inverseProperty: (item: TRelated) => T;
|
|
15
|
+
inverseKey?: (item: TRelated) => any;
|
|
16
|
+
dotNotCreateIndex?: boolean;
|
|
17
|
+
}
|
|
54
18
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
foreignKey: NameParser.parseMember(name),
|
|
62
|
-
relatedTypeClass: c,
|
|
63
|
-
relatedName: NameParser.parseMember(inv),
|
|
64
|
-
relatedKey: invKey ? NameParser.parseMember(invKey) : void 0,
|
|
65
|
-
dotNotCreateIndex
|
|
66
|
-
});
|
|
67
|
-
r.relatedRelation.isCollection = false;
|
|
68
|
-
};
|
|
19
|
+
export interface IRelatedTypeWithType<T, TRelated> {
|
|
20
|
+
type: () => IClassOf<TRelated>,
|
|
21
|
+
property: (item: T) => TRelated;
|
|
22
|
+
inverseProperty: (item: TRelated) => T[];
|
|
23
|
+
inverseKey?: (item: TRelated) => any;
|
|
24
|
+
dotNotCreateIndex?: boolean;
|
|
69
25
|
}
|
|
70
26
|
|
|
71
|
-
export
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
27
|
+
export interface IRelatedTypeOneWithType<T, TRelated> {
|
|
28
|
+
type: () => IClassOf<TRelated>,
|
|
29
|
+
property: (item: T) => TRelated;
|
|
30
|
+
inverseProperty: (item: TRelated) => T;
|
|
31
|
+
inverseKey?: (item: TRelated) => any;
|
|
32
|
+
dotNotCreateIndex?: boolean;
|
|
33
|
+
}
|
|
34
|
+
export function RelateTo<T, TRelated>(p: IRelatedTypeWithType<T, TRelated>): (target: T, key: string) => any;
|
|
35
|
+
export function RelateTo<T, TRelated>(c: IClassOf<TRelated>, p: IRelatedType<T, TRelated>): (target: T, key: string) => any;
|
|
36
|
+
export function RelateTo(c, p?): any {
|
|
76
37
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
dotNotCreateIndex?: boolean;
|
|
38
|
+
if (p === void 0) {
|
|
39
|
+
p = c;
|
|
40
|
+
c = p.type?.();
|
|
81
41
|
}
|
|
82
42
|
|
|
83
|
-
|
|
84
|
-
|
|
43
|
+
const { property, inverseKey: invKey, inverseProperty, dotNotCreateIndex } = p;
|
|
44
|
+
|
|
45
|
+
return (target: any, foreignKey: string): any => {
|
|
85
46
|
|
|
86
47
|
const cn = target.constructor ?? target;
|
|
87
|
-
const
|
|
48
|
+
const entityType = SchemaRegistry.model(cn);
|
|
49
|
+
|
|
50
|
+
const name = NameParser.parseMember(property);
|
|
88
51
|
|
|
89
|
-
|
|
90
|
-
type,
|
|
91
|
-
name
|
|
52
|
+
entityType.addRelation({
|
|
53
|
+
type: entityType,
|
|
54
|
+
name,
|
|
92
55
|
foreignKey,
|
|
93
|
-
relatedTypeClass: c,
|
|
56
|
+
relatedTypeClass: c ?? (Reflect as any).getMetadata("design:type", target, name),
|
|
94
57
|
relatedName: NameParser.parseMember(inverseProperty),
|
|
95
58
|
relatedKey: invKey ? NameParser.parseMember(invKey) : void 0,
|
|
96
59
|
dotNotCreateIndex
|
|
@@ -99,34 +62,65 @@ export function RelateTo<T, TRelated>(c: IClassOf<TRelated>,
|
|
|
99
62
|
};
|
|
100
63
|
}
|
|
101
64
|
|
|
65
|
+
export function RelateToOne<T, TRelated>(p: IRelatedTypeOneWithType<T, TRelated>): (target: T, key: string) => any;
|
|
66
|
+
export function RelateToOne<T, TRelated>(c: IClassOf<TRelated>, p: IRelatedTypeOne<T, TRelated>): (target: T, key: string) => any;
|
|
67
|
+
export function RelateToOne(c, p?): any {
|
|
102
68
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}: {
|
|
107
|
-
|
|
108
|
-
property: (item: T) => TRelated;
|
|
109
|
-
inverseProperty: (item: TRelated) => T;
|
|
110
|
-
|
|
111
|
-
inverseKey?: (item: TRelated) => any;
|
|
112
|
-
dotNotCreateIndex?: boolean;
|
|
69
|
+
if (p === void 0) {
|
|
70
|
+
p = c;
|
|
71
|
+
c = p.type?.();
|
|
113
72
|
}
|
|
114
73
|
|
|
115
|
-
|
|
116
|
-
|
|
74
|
+
const { property, inverseKey: invKey, inverseProperty, dotNotCreateIndex } = p;
|
|
75
|
+
|
|
76
|
+
return (target: any, foreignKey: string): any => {
|
|
117
77
|
|
|
118
78
|
const cn = target.constructor ?? target;
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
79
|
+
const entityType = SchemaRegistry.model(cn);
|
|
80
|
+
|
|
81
|
+
const name = NameParser.parseMember(property);
|
|
82
|
+
|
|
83
|
+
entityType.addRelation({
|
|
84
|
+
type: entityType,
|
|
85
|
+
name,
|
|
86
|
+
foreignKey,
|
|
87
|
+
relatedTypeClass: c ?? (Reflect as any).getMetadata("design:type", target, name),
|
|
88
|
+
relatedName: NameParser.parseMember(inverseProperty),
|
|
127
89
|
relatedKey: invKey ? NameParser.parseMember(invKey) : void 0,
|
|
128
90
|
dotNotCreateIndex,
|
|
129
91
|
singleInverseRelation: true
|
|
130
92
|
});
|
|
93
|
+
|
|
131
94
|
};
|
|
132
95
|
}
|
|
96
|
+
|
|
97
|
+
// export function RelateToOne<T, TRelated>(c: IClassOf<TRelated>,
|
|
98
|
+
// {
|
|
99
|
+
// property: name, inverseProperty: inv, inverseKey: invKey, dotNotCreateIndex
|
|
100
|
+
// }: {
|
|
101
|
+
|
|
102
|
+
// property: (item: T) => TRelated;
|
|
103
|
+
// inverseProperty: (item: TRelated) => T;
|
|
104
|
+
|
|
105
|
+
// inverseKey?: (item: TRelated) => any;
|
|
106
|
+
// dotNotCreateIndex?: boolean;
|
|
107
|
+
// }
|
|
108
|
+
|
|
109
|
+
// ) {
|
|
110
|
+
// return (target: T, key: string): any => {
|
|
111
|
+
|
|
112
|
+
// const cn = target.constructor ?? target;
|
|
113
|
+
// const type = SchemaRegistry.model(cn);
|
|
114
|
+
|
|
115
|
+
// const r = type.addRelation({
|
|
116
|
+
// type,
|
|
117
|
+
// name: NameParser.parseMember(name),
|
|
118
|
+
// foreignKey: key,
|
|
119
|
+
// relatedTypeClass: c,
|
|
120
|
+
// relatedName: NameParser.parseMember(inv),
|
|
121
|
+
// relatedKey: invKey ? NameParser.parseMember(invKey) : void 0,
|
|
122
|
+
// dotNotCreateIndex,
|
|
123
|
+
// singleInverseRelation: true
|
|
124
|
+
// });
|
|
125
|
+
// };
|
|
126
|
+
// }
|
|
@@ -116,11 +116,12 @@ export default class ChangeEntry<T = any> implements IChanges {
|
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
+
if (this.status === "inserted") {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
119
122
|
|
|
120
123
|
if (this.modified.size > 0) {
|
|
121
|
-
|
|
122
|
-
this.status = "modified";
|
|
123
|
-
}
|
|
124
|
+
this.status = "modified";
|
|
124
125
|
} else {
|
|
125
126
|
this.status = "unchanged";
|
|
126
127
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import EntityContext from "../../model/EntityContext.js";
|
|
2
2
|
import Column from "../../decorators/Column.js";
|
|
3
|
-
import
|
|
3
|
+
import { RelateTo, RelateToOne } from "../../decorators/Relate.js";
|
|
4
4
|
import Table from "../../decorators/Table.js";
|
|
5
5
|
import Index from "../../decorators/Index.js";
|
|
6
6
|
import DateTime from "../../types/DateTime.js";
|
|
@@ -263,7 +263,8 @@ export class OrderItem {
|
|
|
263
263
|
public orderItemID: number;
|
|
264
264
|
|
|
265
265
|
@Column()
|
|
266
|
-
@RelateTo(
|
|
266
|
+
@RelateTo({
|
|
267
|
+
type: () => Order,
|
|
267
268
|
property: (orderItem) => orderItem.order,
|
|
268
269
|
inverseProperty: (order) => order.orderItems
|
|
269
270
|
})
|
|
@@ -3,70 +3,77 @@ import assert from "assert";
|
|
|
3
3
|
import ObjectPool from "../../common/ObjectPool.js";
|
|
4
4
|
import sleep from "../../common/sleep.js";
|
|
5
5
|
|
|
6
|
-
export default async function () {
|
|
7
|
-
const pool = new ObjectPool({
|
|
8
|
-
asyncFactory: async () => {
|
|
9
|
-
await sleep(10);
|
|
10
|
-
return Promise.resolve({});
|
|
11
|
-
},
|
|
12
|
-
subscribeForRemoval: (po, clear) => void 0,
|
|
13
|
-
destroy(item) {
|
|
14
|
-
return sleep(10);
|
|
15
|
-
},
|
|
16
|
-
maxSize: 5,
|
|
17
|
-
poolSize: 2,
|
|
18
|
-
maxWait: 100
|
|
19
|
-
});
|
|
20
6
|
|
|
21
|
-
|
|
22
|
-
|
|
7
|
+
export default async function () {
|
|
8
|
+
let id = 1;
|
|
9
|
+
const logs = [] as string[];
|
|
10
|
+
try {
|
|
11
|
+
const pool = new ObjectPool({
|
|
12
|
+
asyncFactory: async () => {
|
|
13
|
+
await sleep(1);
|
|
14
|
+
return Promise.resolve({ id: id++, toString() { return `item-${this.id}`; } });
|
|
15
|
+
},
|
|
16
|
+
subscribeForRemoval: (po, clear) => void 0,
|
|
17
|
+
destroy(item) {
|
|
18
|
+
return Promise.resolve();
|
|
19
|
+
},
|
|
20
|
+
maxSize: 5,
|
|
21
|
+
poolSize: 2,
|
|
22
|
+
maxWait: 5000,
|
|
23
|
+
logger: (t) => logs.push(t)
|
|
24
|
+
});
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
const c1 = await pool.acquire();
|
|
27
|
+
const c2 = await pool.acquire();
|
|
25
28
|
|
|
26
|
-
|
|
29
|
+
assert.equal(2, c2.id);
|
|
27
30
|
|
|
28
|
-
|
|
29
|
-
assert.equal(c1, c3);
|
|
31
|
+
assert.notStrictEqual(c1, c2);
|
|
30
32
|
|
|
31
|
-
|
|
33
|
+
await c1[Symbol.asyncDisposable]();
|
|
32
34
|
|
|
33
|
-
|
|
34
|
-
assert.notEqual(c4, c1);
|
|
35
|
-
assert.notEqual(c4, c2);
|
|
35
|
+
assert.equal(pool.freeSize, 1);
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
const c3 = await pool.acquire();
|
|
38
|
+
assert.strictEqual(c1, c3);
|
|
39
|
+
assert.notStrictEqual(c2, c3);
|
|
40
|
+
assert.strictEqual(pool.freeSize, 0);
|
|
38
41
|
|
|
39
|
-
|
|
42
|
+
const c4 = await pool.acquire();
|
|
43
|
+
assert.notStrictEqual(c4, c1);
|
|
44
|
+
assert.notStrictEqual(c4, c2);
|
|
40
45
|
|
|
41
|
-
|
|
46
|
+
assert.strictEqual(pool.currentSize, 3);
|
|
42
47
|
|
|
43
|
-
|
|
44
|
-
|
|
48
|
+
await c4[Symbol.asyncDisposable]();
|
|
49
|
+
await c2[Symbol.asyncDisposable]();
|
|
45
50
|
|
|
46
|
-
|
|
51
|
+
assert.equal(pool.currentSize, 3);
|
|
47
52
|
|
|
48
|
-
|
|
53
|
+
assert.equal(pool.freeSize, 2);
|
|
49
54
|
|
|
50
|
-
await pool.acquire();
|
|
51
|
-
await pool.acquire();
|
|
52
|
-
await pool.acquire();
|
|
53
|
-
await pool.acquire();
|
|
54
|
-
const last = await pool.acquire();
|
|
55
|
-
let lastError;
|
|
56
|
-
try {
|
|
57
55
|
await pool.acquire();
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
56
|
+
await pool.acquire();
|
|
57
|
+
await pool.acquire();
|
|
58
|
+
const last = await pool.acquire();
|
|
59
|
+
let lastError;
|
|
60
|
+
try {
|
|
61
|
+
await pool.acquire();
|
|
62
|
+
} catch (error) {
|
|
63
|
+
lastError = error;
|
|
64
|
+
}
|
|
65
|
+
if (!lastError) {
|
|
66
|
+
assert.fail("Failed");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// free last after few milliseconds
|
|
70
|
+
setTimeout(() => {
|
|
71
|
+
last[Symbol.asyncDisposable]().catch(console.error);
|
|
72
|
+
}, 10);
|
|
73
|
+
|
|
74
|
+
// this should not fail
|
|
75
|
+
await pool.acquire();
|
|
76
|
+
} finally {
|
|
77
|
+
console.log(logs.join("\n"));
|
|
63
78
|
}
|
|
64
|
-
|
|
65
|
-
// free last after few milliseconds
|
|
66
|
-
setTimeout(() => {
|
|
67
|
-
last[Symbol.asyncDisposable]().catch(console.error);
|
|
68
|
-
}, 10);
|
|
69
|
-
|
|
70
|
-
// this should not fail
|
|
71
|
-
await pool.acquire();
|
|
72
79
|
}
|