Skip to content

Commit 7b0626c

Browse files
committed
feat: add better error handling
1 parent fba906b commit 7b0626c

File tree

6 files changed

+122
-49
lines changed

6 files changed

+122
-49
lines changed

package/cpp/NitroSQLiteException.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
#include <iostream>
55
#include <string>
66

7+
const std::string NITRO_SQLITE_EXCEPTION_PREFIX = "[NitroSQLiteException]";
8+
79
enum NitroSQLiteExceptionType {
810
UnknownError,
911
DatabaseCannotBeOpened,
@@ -33,7 +35,7 @@ class NitroSQLiteException : public std::exception {
3335
explicit NitroSQLiteException(const std::string& message) : NitroSQLiteException(NitroSQLiteExceptionType::UnknownError, message) {}
3436
NitroSQLiteException(const NitroSQLiteExceptionType& type, const char* message) : NitroSQLiteException(type, std::string(message)) {}
3537
NitroSQLiteException(const NitroSQLiteExceptionType& type, const std::string& message)
36-
: _exceptionString("[" + typeToString(type) + "] " + message) {}
38+
: _exceptionString(NITRO_SQLITE_EXCEPTION_PREFIX + " [" + typeToString(type) + "] " + message) {}
3739

3840
private:
3941
const std::string _exceptionString;

package/src/NitroSQLiteError.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
const NITRO_SQLITE_ERROR_NAME = 'NitroSQLiteError' as const
2+
const NITRO_SQLITE_ERROR_PREFIX = '[NitroSQLite] ' as const
3+
4+
/**
5+
* Custom error class for NitroSQLite operations
6+
* Extends the native Error class with proper prototype chain and error handling
7+
*/
8+
export default class NitroSQLiteError extends Error {
9+
constructor(message: string, options?: ErrorOptions) {
10+
super(message, options)
11+
this.name = NITRO_SQLITE_ERROR_NAME
12+
this.message = NITRO_SQLITE_ERROR_PREFIX + message
13+
14+
// Maintains proper prototype chain for instanceof checks
15+
Object.setPrototypeOf(this, NitroSQLiteError.prototype)
16+
}
17+
18+
/**
19+
* Converts an unknown error to a NitroSQLiteError
20+
* Preserves stack traces and error causes when available
21+
*/
22+
static fromError(error: unknown): NitroSQLiteError {
23+
if (error instanceof NitroSQLiteError) {
24+
return error
25+
}
26+
27+
if (error instanceof Error) {
28+
const nitroSQLiteError = new NitroSQLiteError(error.message, {
29+
cause: error.cause,
30+
})
31+
// Preserve original stack trace if available
32+
if (error.stack) {
33+
nitroSQLiteError.stack = error.stack
34+
}
35+
return nitroSQLiteError
36+
}
37+
38+
if (typeof error === 'string') {
39+
return new NitroSQLiteError(error)
40+
}
41+
42+
return new NitroSQLiteError('Unknown error occurred', {
43+
cause: error,
44+
})
45+
}
46+
}

package/src/operations/execute.ts

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type {
88
SQLiteQueryParams,
99
QueryResultRow,
1010
} from '../types'
11+
import NitroSQLiteError from '../NitroSQLiteError'
1112

1213
export function execute<Row extends QueryResultRow = never>(
1314
dbName: string,
@@ -18,13 +19,17 @@ export function execute<Row extends QueryResultRow = never>(
1819
? toNativeQueryParams(params)
1920
: (params as NativeSQLiteQueryParams)
2021

21-
const nativeResult = HybridNitroSQLite.execute(
22-
dbName,
23-
query,
24-
transformedParams,
25-
)
26-
const result = buildJsQueryResult<Row>(nativeResult)
27-
return result
22+
try {
23+
const nativeResult = HybridNitroSQLite.execute(
24+
dbName,
25+
query,
26+
transformedParams,
27+
)
28+
29+
return buildJsQueryResult<Row>(nativeResult)
30+
} catch (error) {
31+
throw NitroSQLiteError.fromError(error)
32+
}
2833
}
2934

3035
export async function executeAsync<Row extends QueryResultRow = never>(
@@ -36,13 +41,16 @@ export async function executeAsync<Row extends QueryResultRow = never>(
3641
? toNativeQueryParams(params)
3742
: (params as NativeSQLiteQueryParams)
3843

39-
const nativeResult = await HybridNitroSQLite.executeAsync(
40-
dbName,
41-
query,
42-
transformedParams,
43-
)
44-
const result = buildJsQueryResult<Row>(nativeResult)
45-
return result
44+
try {
45+
const nativeResult = await HybridNitroSQLite.executeAsync(
46+
dbName,
47+
query,
48+
transformedParams,
49+
)
50+
return buildJsQueryResult<Row>(nativeResult)
51+
} catch (error) {
52+
throw NitroSQLiteError.fromError(error)
53+
}
4654
}
4755

4856
function toNativeQueryParams(

package/src/operations/executeBatch.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import type {
99
BatchQueryCommand,
1010
NativeBatchQueryCommand,
1111
} from '../types'
12+
import NitroSQLiteError from '../NitroSQLiteError'
1213

1314
export function executeBatch(
1415
dbName: string,
@@ -18,8 +19,11 @@ export function executeBatch(
1819
? toNativeBatchQueryCommands(commands)
1920
: (commands as NativeBatchQueryCommand[])
2021

21-
const result = HybridNitroSQLite.executeBatch(dbName, transformedCommands)
22-
return result
22+
try {
23+
return HybridNitroSQLite.executeBatch(dbName, transformedCommands)
24+
} catch (error) {
25+
throw NitroSQLiteError.fromError(error)
26+
}
2327
}
2428

2529
export async function executeBatchAsync(
@@ -30,11 +34,14 @@ export async function executeBatchAsync(
3034
? toNativeBatchQueryCommands(commands)
3135
: (commands as NativeBatchQueryCommand[])
3236

33-
const result = await HybridNitroSQLite.executeBatchAsync(
34-
dbName,
35-
transformedCommands,
36-
)
37-
return result
37+
try {
38+
return await HybridNitroSQLite.executeBatchAsync(
39+
dbName,
40+
transformedCommands,
41+
)
42+
} catch (error) {
43+
throw NitroSQLiteError.fromError(error)
44+
}
3845
}
3946

4047
function toNativeBatchQueryCommands(

package/src/operations/session.ts

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,30 @@ import type {
1111
} from '../types'
1212
import { execute, executeAsync } from './execute'
1313
import { executeBatch, executeBatchAsync } from './executeBatch'
14+
import NitroSQLiteError from '../NitroSQLiteError'
1415

1516
export function open(
1617
options: NitroSQLiteConnectionOptions,
1718
): NitroSQLiteConnection {
18-
openDb(options.name, options.location)
19+
try {
20+
HybridNitroSQLite.open(options.name, options.location)
21+
locks[options.name] = {
22+
queue: [],
23+
inProgress: false,
24+
}
25+
} catch (error) {
26+
throw NitroSQLiteError.fromError(error)
27+
}
1928

2029
return {
21-
close: () => close(options.name),
30+
close: () => {
31+
try {
32+
HybridNitroSQLite.close(options.name)
33+
delete locks[options.name]
34+
} catch (error) {
35+
throw NitroSQLiteError.fromError(error)
36+
}
37+
},
2238
delete: () => HybridNitroSQLite.drop(options.name, options.location),
2339
attach: (dbNameToAttach: string, alias: string, location?: string) =>
2440
HybridNitroSQLite.attach(options.name, dbNameToAttach, alias, location),
@@ -43,17 +59,3 @@ export function open(
4359
HybridNitroSQLite.loadFileAsync(options.name, location),
4460
}
4561
}
46-
47-
export function openDb(dbName: string, location?: string) {
48-
HybridNitroSQLite.open(dbName, location)
49-
50-
locks[dbName] = {
51-
queue: [],
52-
inProgress: false,
53-
}
54-
}
55-
56-
export function close(dbName: string) {
57-
HybridNitroSQLite.close(dbName)
58-
delete locks[dbName]
59-
}

package/src/operations/transaction.ts

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { locks, HybridNitroSQLite } from '../nitro'
2+
import NitroSQLiteError from '../NitroSQLiteError'
23
import type {
34
QueryResult,
45
Transaction,
@@ -25,7 +26,7 @@ export const transaction = (
2526
fn: (tx: Transaction) => Promise<void> | void,
2627
): Promise<void> => {
2728
if (locks[dbName] == null)
28-
throw Error(`Nitro SQLite Error: No lock found on db: ${dbName}`)
29+
throw new NitroSQLiteError(`No lock found on db: ${dbName}`)
2930

3031
let isFinalized = false
3132

@@ -35,8 +36,10 @@ export const transaction = (
3536
params?: SQLiteQueryParams,
3637
): QueryResult<Data> => {
3738
if (isFinalized) {
38-
throw Error(
39-
`Nitro SQLite Error: Cannot execute query on finalized transaction: ${dbName}`,
39+
throw NitroSQLiteError.fromError(
40+
new NitroSQLiteError(
41+
`Cannot execute query on finalized transaction: ${dbName}`,
42+
),
4043
)
4144
}
4245
return execute(dbName, query, params)
@@ -47,17 +50,17 @@ export const transaction = (
4750
params?: SQLiteQueryParams,
4851
): Promise<QueryResult<Data>> => {
4952
if (isFinalized) {
50-
throw Error(
51-
`Nitro SQLite Error: Cannot execute query on finalized transaction: ${dbName}`,
53+
throw new NitroSQLiteError(
54+
`Cannot execute query on finalized transaction: ${dbName}`,
5255
)
5356
}
5457
return executeAsync(dbName, query, params)
5558
}
5659

5760
const commit = () => {
5861
if (isFinalized) {
59-
throw Error(
60-
`Nitro SQLite Error: Cannot execute commit on finalized transaction: ${dbName}`,
62+
throw new NitroSQLiteError(
63+
`Cannot execute commit on finalized transaction: ${dbName}`,
6164
)
6265
}
6366
const result = HybridNitroSQLite.execute(dbName, 'COMMIT')
@@ -67,8 +70,8 @@ export const transaction = (
6770

6871
const rollback = () => {
6972
if (isFinalized) {
70-
throw Error(
71-
`Nitro SQLite Error: Cannot execute rollback on finalized transaction: ${dbName}`,
73+
throw new NitroSQLiteError(
74+
`Cannot execute rollback on finalized transaction: ${dbName}`,
7275
)
7376
}
7477
const result = HybridNitroSQLite.execute(dbName, 'ROLLBACK')
@@ -108,7 +111,11 @@ export const transaction = (
108111
return new Promise((resolve, reject) => {
109112
const tx: PendingTransaction = {
110113
start: () => {
111-
run().then(resolve).catch(reject)
114+
try {
115+
run().then(resolve)
116+
} catch (error) {
117+
reject(NitroSQLiteError.fromError(error))
118+
}
112119
},
113120
}
114121

@@ -118,7 +125,8 @@ export const transaction = (
118125
}
119126

120127
function startNextTransaction(dbName: string) {
121-
if (locks[dbName] == null) throw Error(`Lock not found for db: ${dbName}`)
128+
if (locks[dbName] == null)
129+
throw new NitroSQLiteError(`Lock not found for db: ${dbName}`)
122130

123131
if (locks[dbName].inProgress) {
124132
// Transaction is already in process bail out

0 commit comments

Comments
 (0)