Skip to content

Commit f3e8dc7

Browse files
committed
refactor: propagate structured error fields
1 parent 39b2e96 commit f3e8dc7

File tree

5 files changed

+219
-79
lines changed

5 files changed

+219
-79
lines changed

c/driver/sqlite/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ if(EXISTS "${SQLite3_INCLUDE_DIRS}/sqlite3.h")
3232
ADBC_SQLITE_WITH_LOAD_EXTENSION)
3333
endif()
3434

35-
if(NOT ADBC_SQLITE_WITH_LOAD_EXTENSION)
35+
if(ADBC_SQLITE_WITH_LOAD_EXTENSION EQUAL -1)
3636
set(ADBC_SQLITE_COMPILE_DEFINES "-DADBC_SQLITE_WITH_NO_LOAD_EXTENSION")
3737
endif()
3838

ci/scripts/node_build.sh

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,6 @@ OUT_DIR="$1"
3131
echo "=== Building C++ Drivers ==="
3232
mkdir -p "${OUT_DIR}"
3333

34-
# On macOS, the system sqlite3.h omits sqlite3_load_extension. The cmake
35-
# auto-detection has a bug (string(FIND) returns -1 which is truthy in
36-
# cmake's if(), so the NO_LOAD_EXTENSION guard is never set). Pass it
37-
# explicitly on macOS to avoid a compilation error.
38-
if [[ "$(uname)" == "Darwin" ]]; then
39-
ADBC_CMAKE_ARGS="${ADBC_CMAKE_ARGS} -DADBC_SQLITE_COMPILE_DEFINES=-DADBC_SQLITE_WITH_NO_LOAD_EXTENSION"
40-
fi
41-
4234
cmake -S "${REPO_ROOT}/c" -B "${OUT_DIR}" \
4335
${ADBC_CMAKE_ARGS} \
4436
-DCMAKE_INSTALL_PREFIX="${OUT_DIR}" \

javascript/__test__/error_handling.spec.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,9 @@ after(async () => {
4141
})
4242

4343
test('error: invalid sql syntax', async () => {
44-
await stmt.setSqlQuery('SELECT * FROM') // Syntax error
45-
4644
let error: unknown
4745
try {
46+
await stmt.setSqlQuery('SELECT * FROM') // Syntax error
4847
const reader = await stmt.executeQuery()
4948
for await (const _ of reader) {
5049
}
@@ -54,14 +53,17 @@ test('error: invalid sql syntax', async () => {
5453

5554
assert.ok(error instanceof AdbcError)
5655
assert.match(error.message, /syntax error|incomplete input/i)
57-
assert.ok(error.sqlState)
56+
assert.strictEqual(error.code, 'InvalidArguments')
57+
// SQLite does not expose a numeric vendor code; the ADBC sentinel (INT32_MIN) is filtered to undefined
58+
assert.strictEqual(error.vendorCode, undefined)
59+
// SQLite does not set a SQLSTATE for this error
60+
assert.strictEqual(error.sqlState, undefined)
5861
})
5962

6063
test('error: table not found', async () => {
61-
await stmt.setSqlQuery('SELECT * FROM non_existent_table')
62-
6364
let error: unknown
6465
try {
66+
await stmt.setSqlQuery('SELECT * FROM non_existent_table')
6567
const reader = await stmt.executeQuery()
6668
for await (const _ of reader) {
6769
}
@@ -71,6 +73,9 @@ test('error: table not found', async () => {
7173

7274
assert.ok(error instanceof AdbcError)
7375
assert.match(error.message, /no such table/i)
76+
assert.strictEqual(error.code, 'InvalidArguments')
77+
assert.strictEqual(error.vendorCode, undefined)
78+
assert.strictEqual(error.sqlState, undefined)
7479
})
7580

7681
test('error: constraint violation', async () => {
@@ -91,6 +96,8 @@ test('error: constraint violation', async () => {
9196

9297
assert.ok(error instanceof AdbcError)
9398
assert.match(error.code, /AlreadyExists|Integrity|IO/)
99+
assert.strictEqual(error.vendorCode, undefined)
100+
assert.strictEqual(error.sqlState, undefined)
94101
})
95102

96103
test('error: unsupported option', () => {
@@ -104,4 +111,6 @@ test('error: unsupported option', () => {
104111

105112
assert.ok(error instanceof AdbcError)
106113
assert.strictEqual(error.code, 'NotImplemented')
114+
assert.strictEqual(error.vendorCode, undefined)
115+
assert.strictEqual(error.sqlState, undefined)
107116
})

javascript/lib/error.ts

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,22 +32,14 @@ export class AdbcError extends Error {
3232
}
3333

3434
/**
35-
* Parses a raw error message from the native binding into a structured AdbcError.
36-
* Expected format: "[STATUS] Message (Vendor Code: X, SQL State: Y)"
35+
* Promotes a raw error thrown by the native binding into a structured AdbcError.
3736
*
38-
* If the error does not match this specific format (e.g. it is a standard JS TypeError),
39-
* the original error is returned unmodified.
37+
* Non-ADBC errors (e.g. a standard JS TypeError) are returned unmodified.
4038
*/
4139
static fromError(err: any): any {
42-
if (err instanceof Error) {
43-
// Regex to match: [Status] Message (Vendor Code: 123, SQL State: XYZ)
44-
// Note: Message might contain parentheses, so we match strictly on the suffix.
45-
const match = err.message.trim().match(/^\[(.*?)\] (.*) \(Vendor Code: (-?\d+), SQL State: (.*)\)$/s)
46-
47-
if (match) {
48-
const [, status, msg, vendor, sqlState] = match
49-
return new AdbcError(msg, status, Number(vendor), sqlState)
50-
}
40+
if (err instanceof Error && err.name === 'AdbcError') {
41+
const e = err as any
42+
return new AdbcError(e.message, e.code ?? 'UNKNOWN', e.vendorCode, e.sqlState)
5143
}
5244
return err
5345
}

0 commit comments

Comments
 (0)