Skip to content

Commit 8cdce6a

Browse files
Keimenosdepold
andauthored
feat(types): transition lib/errors (#13710)
* feat(types): transition lib/errors * feat(types): importing model type from existing types * feat(types): don't export AsyncQueueError from lib/errors * feat(types): storing key not value of enum in class * feat(types): migrate async-queue to typescript * fix(tests): adjust tests for typescript migration * feat(types): using inline export for named exports * feat(types): rework type definitions * feat(types): export AsyncQueueError from errors/index Co-authored-by: Sascha Depold <[email protected]>
1 parent b0865ec commit 8cdce6a

41 files changed

Lines changed: 731 additions & 616 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

lib/dialects/mssql/async-queue.js

Lines changed: 0 additions & 46 deletions
This file was deleted.

lib/dialects/mssql/async-queue.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { BaseError, ConnectionError } from '../../errors';
2+
3+
/**
4+
* Thrown when a connection to a database is closed while an operation is in progress
5+
*/
6+
export class AsyncQueueError extends BaseError {
7+
constructor(message: string) {
8+
super(message);
9+
this.name = 'SequelizeAsyncQueueError';
10+
}
11+
}
12+
13+
class AsyncQueue {
14+
previous: Promise<unknown>;
15+
closed: boolean;
16+
rejectCurrent: (reason?: any) => void;
17+
18+
constructor() {
19+
this.previous = Promise.resolve();
20+
this.closed = false;
21+
this.rejectCurrent = () => {
22+
/** do nothing */
23+
};
24+
}
25+
26+
close() {
27+
this.closed = true;
28+
this.rejectCurrent(
29+
new ConnectionError(
30+
new AsyncQueueError(
31+
'the connection was closed before this query could finish executing'
32+
)
33+
)
34+
);
35+
}
36+
37+
enqueue(asyncFunction: (...args: any[]) => Promise<unknown>) {
38+
// This outer promise might seems superflous since down below we return asyncFunction().then(resolve, reject).
39+
// However, this ensures that this.previous will never be a rejected promise so the queue will
40+
// always keep going, while still communicating rejection from asyncFunction to the user.
41+
return new Promise((resolve, reject) => {
42+
this.previous = this.previous.then(() => {
43+
this.rejectCurrent = reject;
44+
if (this.closed) {
45+
return reject(
46+
new ConnectionError(
47+
new AsyncQueueError(
48+
'the connection was closed before this query could be executed'
49+
)
50+
)
51+
);
52+
}
53+
return asyncFunction().then(resolve, reject);
54+
});
55+
});
56+
}
57+
}
58+
59+
export default AsyncQueue;

lib/errors/aggregate-error.js

Lines changed: 0 additions & 34 deletions
This file was deleted.

lib/errors/aggregate-error.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import BaseError from './base-error';
2+
3+
/**
4+
* A wrapper for multiple Errors
5+
*
6+
* @param errors Array of errors
7+
*/
8+
class AggregateError extends BaseError {
9+
errors: Array<AggregateError | Error>;
10+
11+
constructor(errors: Array<AggregateError | Error>) {
12+
super();
13+
this.errors = errors;
14+
this.name = 'AggregateError';
15+
}
16+
17+
toString(): string {
18+
const message = `AggregateError of:\n${this.errors
19+
.map((error: Error | AggregateError) =>
20+
error === this
21+
? '[Circular AggregateError]'
22+
: error instanceof AggregateError
23+
? String(error).replace(/\n$/, '').replace(/^/gm, ' ')
24+
: String(error).replace(/^/gm, ' ').substring(2)
25+
)
26+
.join('\n')}\n`;
27+
return message;
28+
}
29+
}
30+
31+
export default AggregateError;
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
1-
'use strict';
2-
3-
const BaseError = require('./base-error');
1+
import BaseError from './base-error';
42

53
/**
64
* Thrown when an association is improperly constructed (see message for details)
75
*/
86
class AssociationError extends BaseError {
9-
constructor(message) {
7+
constructor(message: string) {
108
super(message);
119
this.name = 'SequelizeAssociationError';
1210
}
1311
}
1412

15-
module.exports = AssociationError;
13+
export default AssociationError;
Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,17 @@
1-
'use strict';
1+
export interface ErrorOptions {
2+
stack?: string;
3+
}
4+
5+
export interface CommonErrorProperties {
6+
/** The database specific error which triggered this one */
7+
readonly parent: Error;
8+
9+
/** The database specific error which triggered this one */
10+
readonly original: Error;
11+
12+
/** The SQL that triggered the error */
13+
readonly sql: string;
14+
}
215

316
/**
417
* Sequelize provides a host of custom error classes, to allow you to do easier debugging. All of these errors are exposed on the sequelize object and the sequelize constructor.
@@ -7,11 +20,11 @@
720
* This means that errors can be accessed using `Sequelize.ValidationError`
821
* The Base Error all Sequelize Errors inherit from.
922
*/
10-
class BaseError extends Error {
11-
constructor(message) {
23+
abstract class BaseError extends Error {
24+
constructor(message?: string) {
1225
super(message);
1326
this.name = 'SequelizeBaseError';
1427
}
1528
}
1629

17-
module.exports = BaseError;
30+
export default BaseError;

lib/errors/bulk-record-error.js

Lines changed: 0 additions & 21 deletions
This file was deleted.

lib/errors/bulk-record-error.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import BaseError from './base-error';
2+
import type { Model } from '../../types/lib/model';
3+
4+
/**
5+
* Thrown when bulk operation fails, it represent per record level error.
6+
* Used with AggregateError
7+
*
8+
* @param error Error for a given record/instance
9+
* @param record DAO instance that error belongs to
10+
*/
11+
class BulkRecordError extends BaseError {
12+
errors: Error;
13+
record: Model;
14+
15+
constructor(error: Error, record: Model) {
16+
super(error.message);
17+
this.name = 'SequelizeBulkRecordError';
18+
this.errors = error;
19+
this.record = record;
20+
}
21+
}
22+
23+
export default BulkRecordError;
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,19 @@
1-
'use strict';
2-
3-
const BaseError = require('./base-error');
1+
import BaseError from './base-error';
42

53
/**
64
* A base class for all connection related errors.
75
*/
86
class ConnectionError extends BaseError {
9-
constructor(parent) {
7+
/** The connection specific error which triggered this one */
8+
parent: Error;
9+
original: Error;
10+
11+
constructor(parent: Error) {
1012
super(parent ? parent.message : '');
1113
this.name = 'SequelizeConnectionError';
12-
/**
13-
* The connection specific error which triggered this one
14-
*
15-
* @type {Error}
16-
*/
1714
this.parent = parent;
1815
this.original = parent;
1916
}
2017
}
2118

22-
module.exports = ConnectionError;
19+
export default ConnectionError;
Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
1-
'use strict';
2-
3-
const ConnectionError = require('./../connection-error');
1+
import ConnectionError from './../connection-error';
42

53
/**
64
* Thrown when a connection to a database is refused due to insufficient privileges
75
*/
86
class AccessDeniedError extends ConnectionError {
9-
constructor(parent) {
7+
constructor(parent: Error) {
108
super(parent);
119
this.name = 'SequelizeAccessDeniedError';
1210
}
1311
}
1412

15-
module.exports = AccessDeniedError;
13+
export default AccessDeniedError;

0 commit comments

Comments
 (0)