@prestodb/presto-js-client
Version:
This is a Presto JavaScript client that connects to Presto via Presto's REST API to run queries.
285 lines (200 loc) • 8.9 kB
Markdown
# Presto JS Client
This is a Presto JavaScript client that connects to Presto via Presto's REST API to run queries.
## Installation
```sh
npm install @prestodb/presto-js-client
```
## Usage
Import the PrestoClient class from `@prestodb/presto-js-client`.
Create a new instance by passing the connection parameters.
### Example
Import the Client class:
```typescript
import PrestoClient from '@prestodb/presto-js-client'
```
Instantiate a client with connection parameters:
```typescript
const client = PrestoClient({
catalog: 'tpcs',
host: 'localhost',
port: 8080,
schema: 'tiny',
timezone: 'America/Costa_Rica',
user: 'root',
})
```
### Parameters
The Presto client can be configured with the following parameters:
- `host`: The hostname or IP address of the Presto coordinator. (Default: `http://localhost`)
- `port`: The port number of the Presto coordinator. (Default: `8080`)
- `user`: The username to use for authentication. (Default: `undefined`)
- `catalog`: The default catalog to use for queries. (Default: `undefined`)
- `schema`: The default schema to use for queries. (Default: `undefined`)
- `source`: The name of the source you want to use for reporting purposes (Default: `presto-js-client`)
- `timezone`: The timezone to use for queries. (Default: `undefined`)
- `authorizationToken`: The value to send as-is in the Authorization header. _Note_: The `Bearer` scheme is automatically added. (Default: `undefined`)
- `basicAuthentication`: An object with a user and password inside, to be used for basic authentication. (Default: `undefined`)
- `extraHeaders`: An dictionary of key-values to send as extra headers in all requests to the API. (Default: `undefined`)
- `interval`: (DEPRECATED) The interval in milliseconds between checks for the status of a running query. (Default: `100`)
## Querying
The `query` method takes a single `string` parameter, which is the SQL query to be executed. The method returns a PrestoQuery object, which contains the results of the query, including the columns, data, and query ID. If the query fails, the `query` method will throw an error.
The `string` parameter to the `query` method must be a valid SQL query. The query can be any type of SQL query, including `SELECT`, `INSERT`, `UPDATE`, and `DELETE` statements.
### Return data structure (or error state)
The `query` method returns a PrestoQuery object, which contains the results of the query, including the columns, data, and query ID.
If the query succeeds, the PrestoQuery object will have the following properties:
- `columns`: An array of objects that describe the columns in the results.
- `data`: An array of arrays that contain the actual data for the results.
- `queryId`: The ID of the query.
If the query fails, you can catch the error as a PrestoError which contains all information returned by Presto.
### Example usage
The following example shows how to use the query() method to execute a SELECT statement:
```typescript
const client = new PrestoClient({
catalog: 'tpcds',
host: 'http://localhost',
port: 8080,
schema: 'sf1',
user: 'root',
})
const query = `SELECT * FROM my_table`
try {
const prestoQuery = await client.query(query)
const results = prestoQuery.data
} catch (error) {
if (error instanceof PrestoError) {
// Handle the error.
console.error(error.errorCode)
}
}
```
### Additional notes
Additional notes on the `query` method:
- It's asynchronous and will return a promise that resolves to a PrestoQuery object.
- It will automatically retry the query if it fails due to a transient error.
- It will cancel the query if the client is destroyed.
- \*It parses big numbers with the BigInt JavaScript primitive. If your Presto response includes a number bigger than `Number.MAX_SAFE_INTEGER`, it will be parsed into a bigint, so you may need to consider that when handling the response, or serializing it.
\* Only if the current JavaScript environment supports the reviver with context in the JSON.parse callback. Check compatibility here:
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#browser_compatibility
Otherwise, bigger numbers will lose precision due to the default JavaScript JSON parsing.
## Get Query metadata information
### Get Query Information
The `getQueryInfo` method retrieves comprehensive information about a specific query, based on its identifier. It returns metadata including status, execution details, statistics, and more, encapsulated within a `QueryInfo` object or undefined if the query does not exist.
#### Parameters
- `queryId`: The unique identifier string of the query for which information is being retrieved.
#### Example usage
```typescript
const queryInfo = await prestoClient.getQueryInfo('your_query_id')
console.log(queryInfo)
```
## Query catalog, schema, table and column metadata
### Get Catalogs
The `getCatalogs` method retrieves all available database catalogs, returning them as an array of strings.
#### Example usage
```typescript
const catalogs = await prestoClient.getCatalogs()
console.log(catalogs)
```
### Get Schemas
The `getSchemas` method retrieves all schemas within a given catalog. It accepts a catalog parameter, which is a string representing the name of the catalog.
Parameters
- `catalog`: The name of the catalog for which to retrieve schemas.
#### Example usage
```typescript
const schemas = await prestoClient.getSchemas('tpch')
console.log(schemas)
```
### Get Tables
The `getTables` method retrieves a list of tables (of type `Table`) filtered by the given catalog and, optionally, the schema. It accepts an object containing `catalog` and optional `schema` parameters.
Parameters
- `catalog`: The catalog name.
- `schema` (optional): The schema name.
#### Example usage
```typescript
const tables: Table[] = await prestoClient.getTables({ catalog: 'tpch', schema: 'sf100' })
console.log(tables)
```
### Get Columns
The `getColumns` method retrieves a list of columns (of type `Column`) filtered for the given catalog and optional schema and table filters. It accepts an object with `catalog`, and optional `schema` and `table` parameters.
Parameters
- `catalog`: The catalog name.
- `schema` (optional): The schema name.
- `table` (optional): The table name.
#### Example usage
```typescript
const columns: Column[] = await prestoClient.getColumns({
catalog: 'tpch',
schema: 'sf100',
table: 'orders',
})
console.log(columns)
```
## Authentication
When creating the client instance, you optionally pass one of two authentication methods.
### Basic authentication
You can send a basic authorization user and password in this way:
```typescript
const client = new PrestoClient({
basicAuthentication: {
user: 'my-user',
password: 'my-password',
},
catalog: 'tpcds',
host: 'http://localhost',
port: 8080,
schema: 'sf1',
user: 'root',
})
```
### Auth token
You can send an authorization token in the following way:
```typescript
const client = new PrestoClient({
// Do not include `Bearer` here, it is automatically added by the client
authorizationToken: `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c`,
catalog: 'tpcds',
host: 'http://localhost',
port: 8080,
schema: 'sf1',
user: 'root',
})
```
## Extra headers
You can pass any extra custom headers to the Presto client to be send on all requests performed against the host:
```typescript
const client = new PrestoClient({
catalog: 'tpcds',
extraHeaders: {
'X-My-Custom-Header-1': 'value',
'X-My-Custom-Header-2': 'value',
},
host: 'http://localhost',
port: 8080,
schema: 'sf1',
user: 'root',
})
```
## Troubleshooting
### Do not know how to serialize a BigInt
Example error message:
```
Do not know how to serialize a BigInt
TypeError: Do not know how to serialize a BigInt
at JSON.stringify (<anonymous>)
```
Make sure to write a custom replacer and handle the serialization of BigInts if your Presto query returns a number bigger than `Number.MAX_SAFE_INTEGER`.
Example JSON.stringify replacer:
```javascript
const results = await client.query(`SELECT 1234567890123456623`)
return {
columns: results.columns,
rows: JSON.stringify(results.data, (key, value) => {
if (typeof value !== 'bigint') return value
return value.toString()
}),
}
```
### Numbers lose precision
Known issue:
If working with numbers bigger than `Number.MAX_SAFE_INTEGER`, and your environment does not support the `JSON.parse` with the context in the reviver (Node.js > 21.0.0, and certain browser versions), the default JSON.parse will make the number lose precision.
Check compatibility here:
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#browser_compatibility