Skip to content

Commit f8e8718

Browse files
authored
Add Pipeline API support (#85)
1 parent 32c7c08 commit f8e8718

File tree

8 files changed

+153
-1
lines changed

8 files changed

+153
-1
lines changed

src/api/client.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { QueryAPI } from "./query";
2525
import { TableAPI } from "./table";
2626
import { CustomAPI } from "./custom";
2727
import { UsageAPI } from "./usage";
28+
import { PipelineAPI } from "./pipeline";
2829
import { deprecationWarning } from "../deprecation";
2930

3031
/// Various states of query execution that are "terminal".
@@ -50,13 +51,16 @@ export class DuneClient {
5051
custom: CustomAPI;
5152
/// Usage Interface
5253
usage: UsageAPI;
54+
/// Pipeline Interface
55+
pipeline: PipelineAPI;
5356

5457
constructor(apiKey: string) {
5558
this.exec = new ExecutionAPI(apiKey);
5659
this.query = new QueryAPI(apiKey);
5760
this.table = new TableAPI(apiKey);
5861
this.custom = new CustomAPI(apiKey);
5962
this.usage = new UsageAPI(apiKey);
63+
this.pipeline = new PipelineAPI(apiKey);
6064
}
6165

6266
/**

src/api/execution.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import {
1313
GetResultParams,
1414
validateAndBuildGetResultParams,
1515
ExecuteSqlParams,
16+
PipelineExecutionResponse,
17+
PipelineExecutionParams,
1618
} from "../types";
1719
import log from "loglevel";
1820
import { ageInHours, logPrefix } from "../utils";
@@ -69,6 +71,24 @@ export class ExecutionAPI extends Router {
6971
return response as ExecutionResponse;
7072
}
7173

74+
/**
75+
* Executes a query pipeline by query ID according to:
76+
* https://docs.dune.com/api-reference/executions/endpoint/execute-query-pipeline
77+
* @param {number} queryID id of query to execute pipeline for.
78+
* @param {PipelineExecutionParams} params including execution performance.
79+
* @returns {PipelineExecutionResponse} response containing pipeline execution ID.
80+
*/
81+
async executeQueryPipeline(
82+
queryID: number,
83+
params: PipelineExecutionParams = {},
84+
): Promise<PipelineExecutionResponse> {
85+
const { performance = QueryEngine.Medium } = params;
86+
87+
return this.post<PipelineExecutionResponse>(`query/${queryID}/pipeline/execute`, {
88+
performance,
89+
});
90+
}
91+
7292
/**
7393
* Cancels an execution according to:
7494
* https://docs.dune.com/api-reference/executions/endpoint/cancel-execution

src/api/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export * from "./client";
22
export * from "./custom";
33
export * from "./execution";
4+
export * from "./pipeline";
45
export * from "./query";
56
export * from "./router";
67
export * from "./table";

src/api/pipeline.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { PipelineStatusResponse } from "../types";
2+
import { Router } from "./router";
3+
4+
/**
5+
* This class implements all the pipeline routes defined in the Dune API Docs.
6+
*/
7+
export class PipelineAPI extends Router {
8+
/**
9+
* Retrieves the status of a pipeline execution by pipeline execution ID.
10+
* @param {string} pipelineExecutionId string representing ID of pipeline execution.
11+
* @returns {PipelineStatusResponse} status of pipeline execution.
12+
*/
13+
async getPipelineStatus(pipelineExecutionId: string): Promise<PipelineStatusResponse> {
14+
return this._get(`pipelines/executions/${pipelineExecutionId}/status`);
15+
}
16+
}

src/index.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1-
export { DuneClient, QueryAPI, ExecutionAPI, CustomAPI, TableAPI, UsageAPI } from "./api";
1+
export {
2+
DuneClient,
3+
QueryAPI,
4+
ExecutionAPI,
5+
CustomAPI,
6+
TableAPI,
7+
UsageAPI,
8+
PipelineAPI,
9+
} from "./api";
210
export * from "./types";
311
export { Paginator } from "./paginator";

src/types/requestArgs.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,10 @@ export interface ExecuteSqlParams {
212212
performance?: QueryEngine;
213213
}
214214

215+
export interface PipelineExecutionParams {
216+
performance?: QueryEngine;
217+
}
218+
215219
export interface BaseCRUDParams extends BaseParams {
216220
/// Description of the query.
217221
description?: string;

src/types/response.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,22 @@ export interface ExecutionResponse {
4141
state: ExecutionState;
4242
}
4343

44+
export interface PipelineExecutionResponse {
45+
pipeline_execution_id: string;
46+
}
47+
48+
export interface PipelineStatusResponse {
49+
status: string;
50+
node_executions: {
51+
id: number;
52+
query_execution_status: {
53+
status: string;
54+
query_id: number;
55+
execution_id: string;
56+
};
57+
}[];
58+
}
59+
4460
/// Response resturned from query creation request.
4561
export interface CreateQueryResponse {
4662
query_id: number;

tests/e2e/pipeline.spec.ts

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import { PipelineAPI, ExecutionAPI, DuneClient } from "../../src";
2+
import log from "loglevel";
3+
import { QueryEngine } from "../../src/types/requestArgs";
4+
5+
log.setLevel("silent", true);
6+
7+
const API_KEY = process.env.DUNE_API_KEY!;
8+
9+
describe("PipelineAPI: pipeline execution and status", () => {
10+
let client: DuneClient;
11+
let pipelineAPI: PipelineAPI;
12+
let executionAPI: ExecutionAPI;
13+
let testQueryId: number;
14+
15+
beforeAll(() => {
16+
client = new DuneClient(API_KEY);
17+
pipelineAPI = client.pipeline;
18+
executionAPI = client.exec;
19+
testQueryId = 6090403;
20+
});
21+
22+
beforeEach((done) => {
23+
setTimeout(done, 1000);
24+
});
25+
26+
it("executes a query pipeline successfully", async () => {
27+
const response = await executionAPI.executeQueryPipeline(testQueryId, {
28+
performance: QueryEngine.Medium,
29+
});
30+
31+
expect(response.pipeline_execution_id).toBeDefined();
32+
expect(typeof response.pipeline_execution_id).toBe("string");
33+
expect(response.pipeline_execution_id.length).toBeGreaterThan(0);
34+
});
35+
36+
it("executes query pipeline with default performance", async () => {
37+
const response = await executionAPI.executeQueryPipeline(testQueryId);
38+
39+
expect(response.pipeline_execution_id).toBeDefined();
40+
expect(typeof response.pipeline_execution_id).toBe("string");
41+
});
42+
43+
it("gets pipeline status after execution", async () => {
44+
const executionResponse = await executionAPI.executeQueryPipeline(testQueryId, {
45+
performance: QueryEngine.Medium,
46+
});
47+
48+
const pipelineExecutionId = executionResponse.pipeline_execution_id;
49+
expect(pipelineExecutionId).toBeDefined();
50+
51+
const statusResponse = await pipelineAPI.getPipelineStatus(pipelineExecutionId);
52+
53+
expect(statusResponse.status).toBeDefined();
54+
expect(statusResponse.node_executions).toBeDefined();
55+
expect(Array.isArray(statusResponse.node_executions)).toBe(true);
56+
expect(statusResponse.node_executions.length).toBeGreaterThan(0);
57+
58+
const firstNode = statusResponse.node_executions[0];
59+
expect(firstNode.id).toBeDefined();
60+
expect(firstNode.query_execution_status).toBeDefined();
61+
expect(firstNode.query_execution_status.status).toBeDefined();
62+
expect(firstNode.query_execution_status.query_id).toBe(testQueryId);
63+
});
64+
65+
it("verifies pipeline status response structure", async () => {
66+
const executionResponse = await executionAPI.executeQueryPipeline(testQueryId);
67+
const pipelineExecutionId = executionResponse.pipeline_execution_id;
68+
69+
const statusResponse = await pipelineAPI.getPipelineStatus(pipelineExecutionId);
70+
71+
expect(statusResponse).toHaveProperty("status");
72+
expect(statusResponse).toHaveProperty("node_executions");
73+
expect(typeof statusResponse.status).toBe("string");
74+
75+
if (statusResponse.node_executions.length > 0) {
76+
const node = statusResponse.node_executions[0];
77+
expect(node).toHaveProperty("id");
78+
expect(node).toHaveProperty("query_execution_status");
79+
expect(node.query_execution_status).toHaveProperty("status");
80+
expect(node.query_execution_status).toHaveProperty("query_id");
81+
}
82+
});
83+
});

0 commit comments

Comments
 (0)