Using NPM:
npm install aws-athena-node-client @aws-sdk/client-athenaUsing yarn:
yarn add aws-athena-node-client @aws-sdk/client-athenaUsing pnpm:
pnpm add aws-athena-node-client @aws-sdk/client-athenaconst athenaNodeClient = new AthenaNodeClient({
bucketUri: "s3://athena-query-results-eu-west-1/",
database: "default",
waitTime: 0.5,
workGroup: "my-work-group",
});const query = `SELECT 1`;
try {
const results = await athenaNodeClient.executeQuery<T>(query);
console.log(results);
} catch (error) {
console.error(error);
}If you want to use AWS Athena cache, you can specify that cache in minutes. If you don't provide this query configuration, Athena doesn't use this cache.
const results = await athenaNodeClient.executeQuery<T>(query, {
cacheInMinutes: 60,
});This project doesn't support native query parameters becase I consider that are very simple and useless, then this project use pg-promise package to format the SQL with parameters to prevent SQL Injection attacks. You can visit https://github.com/vitaly-t/pg-promise?tab=readme-ov-file#named-parameters for more info.
const query =
"SELECT name, surname, age FROM users WHERE name = $(name) AND surname = $(surname)";
const results = await athenaNodeClient.executeQuery<T>(query, {
parameters: {
name: "John",
surname: "Doe",
},
});You need to install @aws-sdk/client-s3 and @aws-sdk/s3-request-presigner
pnpm add @aws-sdk/client-s3 @aws-sdk/s3-request-presignerconst query = `SELECT 1`;
try {
const results = await athenaNodeClient.executeQueryAndGetS3Url(query);
console.log(results); // Print s3://S3_BUCKET_NAME/QUERY_ID.csv
} catch (error) {
console.error(error);
}const query = `SELECT 1`;
try {
const results = await athenaNodeClient.executeQuery<T>(query, {
parameters,
id: "hdaiuh33r8uyjdkas",
});
console.log(results);
} catch (error) {
if (!(error instanceof QueryCanceledException)) {
console.error(error);
}
}You must run this code in a distinct thread than the query execution thread.
try {
await athenaNodeClient.cancelQuery("hdaiuh33r8uyjdkas");
} catch (error) {
console.error(error);
}- Client class renamed to
AthenaNodeClientto prevent issues with@aws-sdk/client-athenaclasses naming. - Now you must instance
AthenaClientfrom@aws-sdk/client-athenapackage. This is to optimize support for AWS Lambda functions (@aws-sdk/*packages are included in AWS Lambda runtime), use the most updated version of this package in your project and you can use more custom configurations in the AWS SDK client, like roles. You need to execute:
pnpm add @aws-sdk/client-athenaBefore
const athenaClient = new AthenaClient({
awsConfig: {
accessKeyId: "DASCDAS82941",
apiVersion: "2017-05-18",
region: "eu-west-1",
secretAccessKey: "CJDADDHDASIUOHADS/3123DASE12",
},
bucketUri: "s3://athena-query-results-eu-west-1/",
database: "default",
waitTime: 0.5,
workGroup: "my-work-group",
});After
import { AthenaClient } from "@aws-sdk/client-athena";
const athena = new AthenaClient({});
const athenaNodeClient = new AthenaNodeClient(athena, {
bucketUri: "s3://athena-query-results-eu-west-1/",
database: "default",
waitTime: 0.5,
workGroup: "my-work-group",
});- If you use methods
executeQueryAndGetS3KeyexecuteQueryAndGetDownloadSignedUrlnow you must create your S3 client before. The reason is the same with the Athena client. You need to execute:
pnpm add @aws-sdk/client-s3 @aws-sdk/s3-request-presignerBefore
const athenaClient = new AthenaClient({
awsConfig: {
accessKeyId: "DASCDAS82941",
apiVersion: "2017-05-18",
region: "eu-west-1",
secretAccessKey: "CJDADDHDASIUOHADS/3123DASE12",
},
bucketUri: "s3://athena-query-results-eu-west-1/",
database: "default",
waitTime: 0.5,
workGroup: "my-work-group",
});After
import { AthenaClient } from "@aws-sdk/client-athena";
import { S3 } from "@aws-sdk/client-s3";
const athena = new AthenaClient({});
const s3 = new S3({
useDualstackEndpoint: true, // recommended to support IPv6
});
const athenaNodeClient = new AthenaNodeClient(athena, {
bucketUri: "s3://athena-query-results-eu-west-1/",
database: "default",
waitTime: 0.5,
workGroup: "my-work-group",
s3Client: s3,
});-
Method
executeQueryAndGetS3Urlis renamed toexecuteQueryAndGetS3Keyand now returns and object with the S3 bucket and key of the object generated by Athena instead of returns an S3 schema url. If you want a direct URL to download the results, you must useexecuteQueryAndGetDownloadSignedUrlmethod. -
All query related method, now have 2 parameters, sql and query config. The query parameters and query id, must be inside this second parameter:
Before
const results = await athenaClient.executeQuery<T>(query, parameters, queryId);After
const results = await athenaNodeClient.executeQuery<T>(query, {
parameters: {
name: "John",
surname: "Doe",
},
id: "abcd",
cacheInMinutes: 60,
});- There is a new statistics parameter in QueryConfig. Now the executeQuery methods will also return a statistics object if the stats parameter is true. By default stats value is false.
Before
const results = await athenaNodeClient.executeQuery<T>(query);- V2 Response example:
[
{
"result": "1"
},
{
"result": "2"
}
]After
- If the statistics parameter is true, the method returns an object with results and statistics, otherwise it will return an array of objects.
const result = await athenaNodeClient.executeQuery<T>(query, {
stats: false,
});
// OR
const { results, statistics } = await athenaNodeClient.executeQuery<T>(query, {
stats: true,
});- V3 response example with stats false or without stats param:
{
"id": "id",
"results": [
{
"result": "1"
},
{
"result": "2"
}
]
}- V3 response example with stats true:
{
"id": "id",
"results": [
{
"result": "1"
},
{
"result": "2"
}
],
"statistics": {
"dataScannedInBytes": 26376236,
"executionTimeInSeconds": 2.703
}
}Before
const { bucket, key } = await athenaNodeClient.executeQueryAndGetS3Key<T>(
query
);- V2 Response example:
{
"bucket": "bucket-test",
"key": "123-key.csv"
}After
If the statistics parameter is true, the method returns an object with bucket, key and statistics, otherwise it will return an object with bucket and key.
const { bucket, key, statistics } =
await athenaNodeClient.executeQueryAndGetS3Key<T>(query, {
stats: true | false,
});- V3 response example with stats false or without stats param:
{
"id": "id",
"bucket": "bucket-test",
"key": "123-key.csv"
}- V3 response example with stats true:
{
"id": "id",
"bucket": "bucket-test",
"key": "123-key.csv",
"statistics": {
"dataScannedInBytes": 26376236,
"executionTimeInSeconds": 2.703
}
}Before
const url = await athenaNodeClient.executeQueryAndGetDownloadSignedUrl<T>(
query
);- V2 response example:
"https://bucket-test..."After
If the statistics parameter is true, the method returns an object with url and statistics, otherwise it will return an object with url.
const { url, statistics } =
await athenaNodeClient.executeQueryAndGetDownloadSignedUrl<T>(query, {
stats: true | false,
});- V3 response example with stats false or without stats param:
{
"id": "id",
"url": "https://bucket-test..."
}- V3 response example with stats true:
{
"id": "id",
"url": "https://bucket-test...",
"statistics": {
"dataScannedInBytes": 26376236,
"executionTimeInSeconds": 2.362
}
}