@entity-access/entity-access 1.0.111 → 1.0.113

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.
Files changed (37) hide show
  1. package/dist/common/ObjectPool.d.ts +6 -2
  2. package/dist/common/ObjectPool.d.ts.map +1 -1
  3. package/dist/common/ObjectPool.js +33 -27
  4. package/dist/common/ObjectPool.js.map +1 -1
  5. package/dist/common/sleep.d.ts.map +1 -1
  6. package/dist/common/sleep.js +23 -2
  7. package/dist/common/sleep.js.map +1 -1
  8. package/dist/decorators/IColumn.d.ts +1 -0
  9. package/dist/decorators/IColumn.d.ts.map +1 -1
  10. package/dist/decorators/Relate.d.ts +16 -10
  11. package/dist/decorators/Relate.d.ts.map +1 -1
  12. package/dist/decorators/Relate.js +58 -44
  13. package/dist/decorators/Relate.js.map +1 -1
  14. package/dist/entity-query/EntityType.d.ts.map +1 -1
  15. package/dist/entity-query/EntityType.js +5 -0
  16. package/dist/entity-query/EntityType.js.map +1 -1
  17. package/dist/tests/model/ShoppingContext.d.ts +4 -0
  18. package/dist/tests/model/ShoppingContext.d.ts.map +1 -1
  19. package/dist/tests/model/ShoppingContext.js +14 -1
  20. package/dist/tests/model/ShoppingContext.js.map +1 -1
  21. package/dist/tests/model/UseFile.d.ts +8 -0
  22. package/dist/tests/model/UseFile.d.ts.map +1 -0
  23. package/dist/tests/model/UseFile.js +36 -0
  24. package/dist/tests/model/UseFile.js.map +1 -0
  25. package/dist/tests/pool/pool-test.d.ts.map +1 -1
  26. package/dist/tests/pool/pool-test.js +55 -47
  27. package/dist/tests/pool/pool-test.js.map +1 -1
  28. package/dist/tsconfig.tsbuildinfo +1 -1
  29. package/package.json +1 -1
  30. package/src/common/ObjectPool.ts +44 -28
  31. package/src/common/sleep.ts +23 -2
  32. package/src/decorators/IColumn.ts +2 -0
  33. package/src/decorators/Relate.ts +97 -95
  34. package/src/entity-query/EntityType.ts +5 -0
  35. package/src/tests/model/ShoppingContext.ts +14 -2
  36. package/src/tests/model/UseFile.ts +24 -0
  37. package/src/tests/pool/pool-test.ts +58 -51
@@ -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 15 seconds with gap of 1 second each
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 & { [Symbol.asyncDisposable](): Promise<any>; };
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 item = this.free.pop();
98
- if(!item) {
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
- item = this.free.pop();
113
+ existing = this.free.pop();
105
114
  }
106
115
  }
107
- if(!item) {
108
-
109
- if (this.total >= this.maxSize) {
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
- // create new..
115
- if (this.factory) {
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.free.push(item);
129
- for (const iterator of this.awaited) {
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
- break;
146
+ return;
133
147
  }
134
- } else {
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> {
@@ -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?.addEventListener("abort", () => {
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
  }
@@ -86,6 +86,8 @@ export interface IEntityRelation {
86
86
 
87
87
  relatedTypeClass: IClassOf<any>;
88
88
 
89
+ relatedTypeClassFactory?: () => IClassOf<any>;
90
+
89
91
  fkColumn?: IColumn;
90
92
 
91
93
 
@@ -2,95 +2,62 @@ 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
- export default function Relate<T, TRelated>(c: IClassOf<TRelated>,
8
- {
9
- foreignKey: name, inverseProperty: inv, inverseKey: invKey, dotNotCreateIndex
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 function RelateOne<T, TRelated>(c: IClassOf<TRelated>,
40
- {
41
- foreignKey: name, inverseProperty: inv, inverseKey: invKey, dotNotCreateIndex
42
- }: {
43
-
44
- foreignKey: (item: T) => any;
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 => {
54
-
55
- const cn = target.constructor ?? target;
56
- const type = SchemaRegistry.model(cn);
57
-
58
- const r = type.addRelation({
59
- type,
60
- name: key,
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
- };
12
+ export interface IRelatedTypeOne<T, TRelated> {
13
+ property: (item: T) => TRelated;
14
+ inverseProperty: (item: TRelated) => T;
15
+ inverseKey?: (item: TRelated) => any;
16
+ dotNotCreateIndex?: boolean;
69
17
  }
70
18
 
71
- export function RelateTo<T, TRelated>(c: IClassOf<TRelated>,
72
- {
73
- property,
74
- inverseProperty, inverseKey: invKey, dotNotCreateIndex
75
- }: {
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;
25
+ }
76
26
 
77
- property: (item: T) => TRelated;
78
- inverseProperty: (item: TRelated) => T[];
79
- inverseKey?: (item: TRelated) => any;
80
- dotNotCreateIndex?: boolean;
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 {
37
+
38
+ if (p === void 0) {
39
+ p = c;
40
+ // c = p.type?.();
41
+ if (p.type) {
42
+ c = void 0;
43
+ }
81
44
  }
82
45
 
83
- ) {
84
- return (target: T, foreignKey: string): any => {
46
+ const { property, inverseKey: invKey, inverseProperty, dotNotCreateIndex } = p;
47
+
48
+ return (target: any, foreignKey: string): any => {
85
49
 
86
50
  const cn = target.constructor ?? target;
87
- const type = SchemaRegistry.model(cn);
51
+ const entityType = SchemaRegistry.model(cn);
52
+
53
+ const name = NameParser.parseMember(property);
88
54
 
89
- type.addRelation({
90
- type,
91
- name: NameParser.parseMember(property),
55
+ entityType.addRelation({
56
+ type: entityType,
57
+ name,
92
58
  foreignKey,
93
59
  relatedTypeClass: c,
60
+ relatedTypeClassFactory: p.type,
94
61
  relatedName: NameParser.parseMember(inverseProperty),
95
62
  relatedKey: invKey ? NameParser.parseMember(invKey) : void 0,
96
63
  dotNotCreateIndex
@@ -99,34 +66,69 @@ export function RelateTo<T, TRelated>(c: IClassOf<TRelated>,
99
66
  };
100
67
  }
101
68
 
69
+ export function RelateToOne<T, TRelated>(p: IRelatedTypeOneWithType<T, TRelated>): (target: T, key: string) => any;
70
+ export function RelateToOne<T, TRelated>(c: IClassOf<TRelated>, p: IRelatedTypeOne<T, TRelated>): (target: T, key: string) => any;
71
+ export function RelateToOne(c, p?): any {
102
72
 
103
- export function RelateToOne<T, TRelated>(c: IClassOf<TRelated>,
104
- {
105
- property: name, inverseProperty: inv, inverseKey: invKey, dotNotCreateIndex
106
- }: {
107
-
108
- property: (item: T) => TRelated;
109
- inverseProperty: (item: TRelated) => T;
110
-
111
- inverseKey?: (item: TRelated) => any;
112
- dotNotCreateIndex?: boolean;
73
+ if (p === void 0) {
74
+ p = c;
75
+ // c = p.type?.();
76
+ if (p.type) {
77
+ c = void 0;
78
+ }
113
79
  }
114
80
 
115
- ) {
116
- return (target: T, key: string): any => {
81
+ const { property, inverseKey: invKey, inverseProperty, dotNotCreateIndex } = p;
82
+
83
+ return (target: any, foreignKey: string): any => {
117
84
 
118
85
  const cn = target.constructor ?? target;
119
- const type = SchemaRegistry.model(cn);
86
+ const entityType = SchemaRegistry.model(cn);
120
87
 
121
- const r = type.addRelation({
122
- type,
123
- name: NameParser.parseMember(name),
124
- foreignKey: key,
88
+ const name = NameParser.parseMember(property);
89
+
90
+ entityType.addRelation({
91
+ type: entityType,
92
+ name,
93
+ foreignKey,
125
94
  relatedTypeClass: c,
126
- relatedName: NameParser.parseMember(inv),
95
+ relatedTypeClassFactory: p.type,
96
+ relatedName: NameParser.parseMember(inverseProperty),
127
97
  relatedKey: invKey ? NameParser.parseMember(invKey) : void 0,
128
98
  dotNotCreateIndex,
129
99
  singleInverseRelation: true
130
100
  });
101
+
131
102
  };
132
103
  }
104
+
105
+ // export function RelateToOne<T, TRelated>(c: IClassOf<TRelated>,
106
+ // {
107
+ // property: name, inverseProperty: inv, inverseKey: invKey, dotNotCreateIndex
108
+ // }: {
109
+
110
+ // property: (item: T) => TRelated;
111
+ // inverseProperty: (item: TRelated) => T;
112
+
113
+ // inverseKey?: (item: TRelated) => any;
114
+ // dotNotCreateIndex?: boolean;
115
+ // }
116
+
117
+ // ) {
118
+ // return (target: T, key: string): any => {
119
+
120
+ // const cn = target.constructor ?? target;
121
+ // const type = SchemaRegistry.model(cn);
122
+
123
+ // const r = type.addRelation({
124
+ // type,
125
+ // name: NameParser.parseMember(name),
126
+ // foreignKey: key,
127
+ // relatedTypeClass: c,
128
+ // relatedName: NameParser.parseMember(inv),
129
+ // relatedKey: invKey ? NameParser.parseMember(invKey) : void 0,
130
+ // dotNotCreateIndex,
131
+ // singleInverseRelation: true
132
+ // });
133
+ // };
134
+ // }
@@ -106,6 +106,11 @@ export default class EntityType {
106
106
  // we will also set fk to the corresponding column
107
107
  this.relations.push(relation);
108
108
  this.relationMap.set(relation.name, relation);
109
+ if (getInverseModel) {
110
+ if (!relation.relatedTypeClass) {
111
+ relation.relatedTypeClass = relation.relatedTypeClassFactory();
112
+ }
113
+ }
109
114
 
110
115
  // find fk...
111
116
  let fkColumn = this.fieldMap.get(relation.foreignKey);
@@ -1,9 +1,10 @@
1
1
  import EntityContext from "../../model/EntityContext.js";
2
2
  import Column from "../../decorators/Column.js";
3
- import Relate, { RelateTo, RelateToOne } from "../../decorators/Relate.js";
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";
7
+ import { UserFile } from "./UseFile.js";
7
8
 
8
9
  export const statusPublished = "published";
9
10
 
@@ -47,6 +48,13 @@ export class User {
47
48
  @Column({ dataType: "Char", length: 200 })
48
49
  public userName: string;
49
50
 
51
+ @RelateTo({
52
+ type: () => UserFile,
53
+ property: (u) => u.photo,
54
+ inverseProperty: (uf) => uf.photoUsers
55
+ })
56
+ public photoID: number;
57
+
50
58
  public profile: UserProfile;
51
59
 
52
60
  public ownedProducts: Product[];
@@ -55,6 +63,9 @@ export class User {
55
63
 
56
64
  public categories: UserCategory[];
57
65
 
66
+ public files: UserFile[];
67
+
68
+ public photo: UserFile;
58
69
  }
59
70
 
60
71
  @Table("Categories")
@@ -263,7 +274,8 @@ export class OrderItem {
263
274
  public orderItemID: number;
264
275
 
265
276
  @Column()
266
- @RelateTo(Order, {
277
+ @RelateTo({
278
+ type: () => Order,
267
279
  property: (orderItem) => orderItem.order,
268
280
  inverseProperty: (order) => order.orderItems
269
281
  })
@@ -0,0 +1,24 @@
1
+ import Column from "../../decorators/Column.js";
2
+ import { RelateTo } from "../../decorators/Relate.js";
3
+ import Table from "../../decorators/Table.js";
4
+ import { User } from "./ShoppingContext.js";
5
+
6
+ @Table("UserFiles")
7
+ export class UserFile {
8
+
9
+ @Column({ dataType: "BigInt", key: true, autoGenerate: true })
10
+ public fileID: number;
11
+
12
+ @Column({ dataType: "BigInt"})
13
+ @RelateTo({
14
+ type: () => User,
15
+ property: (uf) => uf.user,
16
+ inverseProperty: (u) => u.files
17
+ })
18
+ public userID: number;
19
+
20
+ public user: User;
21
+
22
+ public photoUsers: User[];
23
+
24
+ }
@@ -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
- const c1 = await pool.acquire();
22
- const c2 = await pool.acquire();
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
- await c1[Symbol.asyncDisposable]();
26
+ const c1 = await pool.acquire();
27
+ const c2 = await pool.acquire();
25
28
 
26
- assert.equal(pool.freeSize, 1);
29
+ assert.equal(2, c2.id);
27
30
 
28
- const c3 = await pool.acquire();
29
- assert.equal(c1, c3);
31
+ assert.notStrictEqual(c1, c2);
30
32
 
31
- assert.equal(pool.freeSize, 0);
33
+ await c1[Symbol.asyncDisposable]();
32
34
 
33
- const c4 = await pool.acquire();
34
- assert.notEqual(c4, c1);
35
- assert.notEqual(c4, c2);
35
+ assert.equal(pool.freeSize, 1);
36
36
 
37
- assert.equal(pool.currentSize, 3);
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
- await c3[Symbol.asyncDisposable]();
42
+ const c4 = await pool.acquire();
43
+ assert.notStrictEqual(c4, c1);
44
+ assert.notStrictEqual(c4, c2);
40
45
 
41
- assert.equal(pool.currentSize, 3);
46
+ assert.strictEqual(pool.currentSize, 3);
42
47
 
43
- await c4[Symbol.asyncDisposable]();
44
- await c2[Symbol.asyncDisposable]();
48
+ await c4[Symbol.asyncDisposable]();
49
+ await c2[Symbol.asyncDisposable]();
45
50
 
46
- assert.equal(pool.currentSize, 2);
51
+ assert.equal(pool.currentSize, 3);
47
52
 
48
- assert.equal(pool.freeSize, 2);
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
- } catch (error) {
59
- lastError = error;
60
- }
61
- if (!lastError) {
62
- assert.fail("Failed");
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
  }