Skip to content

Commit 3958c75

Browse files
committed
feat(helpers): add toError
1 parent 07628b3 commit 3958c75

File tree

3 files changed

+218
-0
lines changed

3 files changed

+218
-0
lines changed

__tests__/to-error.spec.ts

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
import { describe, it, expect } from "vitest";
2+
import { toError } from "../src/helpers";
3+
import { MongoError } from "../src/types";
4+
5+
describe("toError", () => {
6+
it("converts MongoDB error with all properties to JavaScript Error", () => {
7+
const mongoError: MongoError = {
8+
code: 11000,
9+
name: "DuplicateKey",
10+
description: "Duplicate key error collection",
11+
categories: ["RetriableError"]
12+
};
13+
14+
const result = toError(mongoError);
15+
16+
expect(result).toBeInstanceOf(Error);
17+
expect(result.message).toBe("[11000] DuplicateKey: Duplicate key error collection | RetriableError");
18+
expect(result.cause).toBe(mongoError);
19+
});
20+
21+
it("converts MongoDB error without description", () => {
22+
const mongoError: MongoError = {
23+
code: 10,
24+
name: "CannotMutateObject",
25+
categories: ["ValidationError"]
26+
};
27+
28+
const result = toError(mongoError);
29+
30+
expect(result.message).toBe("[10] CannotMutateObject | ValidationError");
31+
expect(result.cause).toBe(mongoError);
32+
});
33+
34+
it("converts MongoDB error without categories", () => {
35+
const mongoError: MongoError = {
36+
code: 1,
37+
name: "InternalError",
38+
description: "An unspecified internal error occurred."
39+
};
40+
41+
const result = toError(mongoError);
42+
43+
expect(result.message).toBe("[1] InternalError: An unspecified internal error occurred.");
44+
expect(result.cause).toBe(mongoError);
45+
});
46+
47+
it("converts minimal MongoDB error with only code and name", () => {
48+
const mongoError: MongoError = {
49+
code: 999,
50+
name: "CustomError"
51+
};
52+
53+
const result = toError(mongoError);
54+
55+
expect(result.message).toBe("[999] CustomError");
56+
expect(result.cause).toBe(mongoError);
57+
});
58+
59+
it("handles multiple categories", () => {
60+
const mongoError: MongoError = {
61+
code: 6,
62+
name: "HostUnreachable",
63+
description: "The host is unreachable.",
64+
categories: ["NetworkError", "RetriableError"]
65+
};
66+
67+
const result = toError(mongoError);
68+
69+
expect(result.message).toBe("[6] HostUnreachable: The host is unreachable. | NetworkError, RetriableError");
70+
expect(result.cause).toBe(mongoError);
71+
});
72+
73+
it("handles empty categories array", () => {
74+
const mongoError: MongoError = {
75+
code: 2,
76+
name: "BadValue",
77+
description: "The value provided is invalid.",
78+
categories: []
79+
};
80+
81+
const result = toError(mongoError);
82+
83+
expect(result.message).toBe("[2] BadValue: The value provided is invalid.");
84+
expect(result.cause).toBe(mongoError);
85+
});
86+
87+
it("uses custom formatter when provided", () => {
88+
const mongoError: MongoError = {
89+
code: 11000,
90+
name: "DuplicateKey",
91+
description: "Duplicate key error collection",
92+
categories: ["RetriableError"]
93+
};
94+
95+
const customFormatter = (error: MongoError) =>
96+
`MongoDB Error ${error.code}: ${error.name}`;
97+
98+
const result = toError(mongoError, customFormatter);
99+
100+
expect(result.message).toBe("MongoDB Error 11000: DuplicateKey");
101+
expect(result.cause).toBe(mongoError);
102+
});
103+
104+
it("custom formatter receives complete MongoError object", () => {
105+
const mongoError: MongoError = {
106+
code: 6,
107+
name: "HostUnreachable",
108+
description: "The host is unreachable.",
109+
categories: ["NetworkError", "RetriableError"]
110+
};
111+
112+
const customFormatter = (error: MongoError) => {
113+
return `${error.name} (${error.code}): ${error.description} [${error.categories?.join(", ")}]`;
114+
};
115+
116+
const result = toError(mongoError, customFormatter);
117+
118+
expect(result.message).toBe("HostUnreachable (6): The host is unreachable. [NetworkError, RetriableError]");
119+
expect(result.cause).toBe(mongoError);
120+
});
121+
122+
it("custom formatter can return simple string", () => {
123+
const mongoError: MongoError = {
124+
code: 1,
125+
name: "InternalError"
126+
};
127+
128+
const customFormatter = () => "Custom error message";
129+
130+
const result = toError(mongoError, customFormatter);
131+
132+
expect(result.message).toBe("Custom error message");
133+
expect(result.cause).toBe(mongoError);
134+
});
135+
});

readme.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ import {
3737
getErrorCode,
3838
getErrorDescription,
3939
isKnownErrorCode,
40+
getErrorDetails,
41+
toError,
4042
MongoErrorList,
4143
} from "mongo-error-codes";
4244

@@ -45,6 +47,16 @@ console.log(getErrorCode("DuplicateKey")); // 11000
4547
console.log(getErrorDescription(11000)); // description or undefined
4648
console.log(isKnownErrorCode(11000)); // true
4749

50+
// Get full error details
51+
const errorDetails = getErrorDetails(11000);
52+
console.log(errorDetails); // { code: 11000, name: "DuplicateKey", ... }
53+
54+
// Convert to JavaScript Error
55+
if (errorDetails) {
56+
const jsError = toError(errorDetails);
57+
console.log(jsError.message); // "[11000] DuplicateKey: Duplicate key error collection"
58+
}
59+
4860
// List all error codes
4961
console.log(MongoErrorList);
5062
```
@@ -101,6 +113,44 @@ console.log(getErrorDetails("DuplicateKey"));
101113
// { code: 11000, name: "DuplicateKey", description: "Duplicate key error collection" }
102114
```
103115

116+
#### `toError(mongoError: MongoError, formatter?: (error: MongoError) => string): Error`
117+
118+
Converts a MongoDB error object to a JavaScript Error with a formatted message. Optionally accepts a custom formatter function.
119+
120+
```ts
121+
import { toError, getErrorDetails } from "mongo-error-codes";
122+
123+
const mongoError = getErrorDetails(11000);
124+
if (mongoError) {
125+
// Default formatting
126+
const jsError = toError(mongoError);
127+
console.log(jsError.message); // "[11000] DuplicateKey: Duplicate key error collection"
128+
console.log(jsError.cause); // Original MongoError object
129+
}
130+
131+
// With categories
132+
const errorWithCategories = {
133+
code: 6,
134+
name: "HostUnreachable",
135+
description: "The host is unreachable.",
136+
categories: ["NetworkError", "RetriableError"]
137+
};
138+
const jsError = toError(errorWithCategories);
139+
console.log(jsError.message);
140+
// "[6] HostUnreachable: The host is unreachable. | NetworkError, RetriableError"
141+
142+
// Custom formatter
143+
const customError = toError(errorWithCategories, (error) =>
144+
`MongoDB ${error.name} (${error.code}): ${error.description}`
145+
);
146+
console.log(customError.message);
147+
// "MongoDB HostUnreachable (6): The host is unreachable."
148+
149+
// Simple custom formatter
150+
const simpleError = toError(mongoError, (error) => `Error ${error.code}`);
151+
console.log(simpleError.message); // "Error 11000"
152+
```
153+
104154
### Data Structures
105155

106156
#### `MongoErrorCodes` (enum)

src/helpers/helpers.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { MongoCodeErrorMap, MongoNameErrorMap } from "../data/map";
2+
import { MongoError } from "../types";
23

34
/**
45
* Get the name of the error code.
@@ -58,3 +59,35 @@ export function getErrorDetails(
5859
return MongoNameErrorMap.get(input);
5960
}
6061
}
62+
63+
/**
64+
* Convert a MongoDB error to a JavaScript error.
65+
*
66+
* @param mongoError - The MongoDB error.
67+
* @param formatter - Optional custom formatter function that takes a MongoError and returns a string.
68+
* @returns The JavaScript error.
69+
*/
70+
export function toError(
71+
mongoError: MongoError,
72+
formatter?: (error: MongoError) => string
73+
): Error {
74+
let message: string;
75+
76+
if (formatter) {
77+
message = formatter(mongoError);
78+
} else {
79+
message = `[${mongoError.code}] ${mongoError.name}`;
80+
81+
if (mongoError.description) {
82+
message += `: ${mongoError.description}`;
83+
}
84+
85+
if (mongoError.categories?.length) {
86+
message += ` | ${mongoError.categories.join(", ")}`;
87+
}
88+
}
89+
90+
return new Error(message, {
91+
cause: mongoError,
92+
});
93+
}

0 commit comments

Comments
 (0)