Basic Usage #
The query method executes a SQL statement and automatically follows Trino's nextUri pagination links until all result pages have been collected.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { TrinoClient } from "@lakeql/trino-client"
const client = new TrinoClient({
host: "https://trino.example.com",
port: 8443,
auth: { type: "basic", username: "analyst", password: "secret" },
catalog: "hive",
schema: "sales",
})
const rows = await client.query<[string, string, number]>({
sql: "SELECT id, region, amount FROM orders WHERE status = 'shipped'",
})
for (const [id, region, amount] of rows) {
console.log(`Order ${id}: ${region} - $${amount}`)
}
Row Transforms #
Use the transform option to map raw row arrays into typed objects:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29import { TrinoClient } from "@lakeql/trino-client"
import type { Column } from "@lakeql/trino-client"
const client = new TrinoClient({
host: "https://trino.example.com",
port: 8443,
auth: { type: "basic", username: "analyst", password: "secret" },
catalog: "hive",
schema: "sales",
})
interface Order {
id: string
region: string
amount: number
}
const orders = await client.query<Order>({
sql: "SELECT id, region, amount FROM orders",
transform: (row: unknown[], columns: Column[]) => ({
id: row[0] as string,
region: row[1] as string,
amount: row[2] as number,
}),
})
// orders: Order[]
console.log(orders[0].region)
The transform function receives the raw row array and the column metadata, and returns the desired shape.
User Impersonation #
Pass impersonateAs to execute the query as a different Trino user. This sets the X-Trino-User header for that request only:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { TrinoClient } from "@lakeql/trino-client"
const client = new TrinoClient({
host: "https://trino.example.com",
port: 8443,
auth: { type: "basic", username: "analyst", password: "secret" },
catalog: "hive",
})
const rows = await client.query<[string]>({
sql: "SELECT current_user",
impersonateAs: "data-team-service",
})
// rows: [["data-team-service"]]
Query Cancellation #
Cancel a running query using an AbortSignal:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25import { TrinoClient, TrinoCancellationError } from "@lakeql/trino-client"
const client = new TrinoClient({
host: "https://trino.example.com",
port: 8443,
auth: { type: "basic", username: "analyst", password: "secret" },
catalog: "hive",
})
const controller = new AbortController()
// Cancel after 10 seconds
setTimeout(() => controller.abort(), 10_000)
try {
const rows = await client.query({
sql: "SELECT * FROM very_large_table",
signal: controller.signal,
})
} catch (error) {
if (error instanceof TrinoCancellationError) {
console.log("Query was cancelled")
}
}
You can also cancel queries by ID:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { TrinoClient } from "@lakeql/trino-client"
const client = new TrinoClient({
host: "https://trino.example.com",
port: 8443,
auth: { type: "basic", username: "analyst", password: "secret" },
catalog: "hive",
})
// Cancel a specific query
await client.cancelQuery("20240101_123456_00001_abcde")
// Cancel all active queries
await client.cancelAllQueries()
// Check what's currently running
const active = client.getActiveQueries()
Error Handling #
The client throws typed errors depending on the failure:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32import {
TrinoClient,
TrinoClientError,
TrinoQueryError,
TrinoCancellationError,
} from "@lakeql/trino-client"
const client = new TrinoClient({
host: "https://trino.example.com",
port: 8443,
auth: { type: "basic", username: "analyst", password: "secret" },
catalog: "hive",
})
try {
const rows = await client.query({ sql: "SELECT * FROM nonexistent_table" })
} catch (error) {
if (error instanceof TrinoQueryError) {
// Trino returned an error in the response body
console.error(error.errorName) // e.g. "TABLE_NOT_FOUND"
console.error(error.errorType) // e.g. "USER_ERROR"
console.error(error.queryId)
} else if (error instanceof TrinoClientError) {
// HTTP-level error (non-2xx status)
console.error(error.statusCode) // e.g. 503
console.error(error.message)
} else if (error instanceof TrinoCancellationError) {
// Query was cancelled via AbortSignal
console.log("Cancelled:", error.queryId)
}
}
How Pagination Works #
-
A
POSTis sent to/v1/statementwith the SQL body -
Trino returns an initial response with (optionally) data and a
nextUri -
The client follows
nextUriwithGETrequests, collectingdataarrays -
When no
nextUriis returned, all pages have been fetched - The concatenated result array is returned
This is entirely transparent — you call query() and get the complete result regardless of how many pages Trino needed internally.
QueryProps Reference #
| Property | Type |
|---|---|
| sql | string |
The SQL statement to execute. | |
| impersonateAs? | string |
Optional Trino user to impersonate via | |
| signal? | AbortSignal |
Abort signal for cancelling the query. | |
| transform? | (row: unknown[], columns: Column[]) => T |
Optional transform function to map raw row arrays to typed objects. | |