Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/quiet-ways-pick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@aziontech/sql': patch
---

fix surface statement-level query errors
6 changes: 5 additions & 1 deletion packages/sql/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,10 @@ if (result) {
}
```

> **Note:** Statement-level failures reported by the database (for example querying a
> non-existent table, which returns `no such table: ...`) are surfaced through the
> `error` field of the response, not thrown. Always check `error` before using `data`.

#### Use Execute

**JavaScript:**
Expand Down Expand Up @@ -522,7 +526,7 @@ The response object from a database operation.
- `columns: string[]`
- `statement: string`
- `rows: (number | string)[][]`
- `error?: string`
- `error?: string` — set when the individual statement fails (e.g. `no such table: ...`). When present, the operation also resolves with a top-level `error` object.

### `AzionClientOptions`

Expand Down
35 changes: 10 additions & 25 deletions packages/sql/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -448,21 +448,12 @@ describe('SQL Module', () => {
useQuery('test-db', ['pragma table_list', 'select * from main'], {
debug: mockDebug,
}),
).resolves.toEqual(
expect.objectContaining({
data: expect.objectContaining({
state: 'executed',
results: expect.arrayContaining([
expect.anything(),
expect.objectContaining({ error: 'no such table: main' }),
]),
}),
error: expect.objectContaining({
message: 'no such table: main',
operation: 'apiQuery',
}),
).resolves.toEqual({
error: expect.objectContaining({
message: 'no such table: main',
operation: 'apiQuery',
}),
);
});
});

it('should return error if useQuery when last statement is invalid', async () => {
Expand Down Expand Up @@ -526,18 +517,12 @@ describe('SQL Module', () => {
useQuery('test-db', ['pragma table_list', 'select * from sqlite_schema', 'select * from main'], {
debug: mockDebug,
}),
).resolves.toEqual(
expect.objectContaining({
data: expect.objectContaining({
state: 'executed',
results: expect.arrayContaining([
expect.anything(),
expect.anything(),
expect.objectContaining({ error: 'no such table: main' }),
]),
}),
).resolves.toEqual({
error: expect.objectContaining({
message: 'no such table: main',
operation: 'apiQuery',
}),
);
});
});

it('should return error if useQuery when data rows is empty', async () => {
Expand Down
31 changes: 24 additions & 7 deletions packages/sql/src/services/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,18 +184,35 @@ const postQueryDatabase = async (
};
}

// The SQL API reports per-statement failures inside the `data` array
// (e.g. `{ error: 'no such table: ...' }`) rather than in `result.errors`.
const statementError = Array.isArray(result.data)
? result.data.find((statement: any) => statement && statement.error)
: undefined;

if (statementError) {
return {
error: { message: statementError.error, operation: 'post query' },
};
}

const dataResult = result.data;

if (debug) {
const limitedData: ApiQueryExecutionResponse = {
...result,
data: (result as ApiQueryExecutionResponse)?.data?.map((data) => ({
...data,
results: {
...data.results,
rows: limitArraySize(data.results?.rows, 10),
},
})),
data: (result as ApiQueryExecutionResponse)?.data?.map((data) => {
if (!data || !data.results) {
return data;
}
return {
...data,
results: {
...data.results,
rows: limitArraySize(data.results?.rows, 10),
},
};
}),
};
console.log('Response Query:', JSON.stringify(limitedData));
}
Expand Down
Loading