Skip to content

Commit

Permalink
Add Doc Strings (#32)
Browse files Browse the repository at this point in the history
Adding doc string to all/most public facing methods with updated reference links.
  • Loading branch information
bh2smith authored Mar 8, 2024
1 parent 2a2efd5 commit 3d5d5bb
Show file tree
Hide file tree
Showing 12 changed files with 296 additions and 100 deletions.
30 changes: 29 additions & 1 deletion src/api/client.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/**
* This is the common entry point for end users.
* A class with exhibits all Dune API properties and extensions.
* Specifically, this class is a composition of QueryAPI, ExecutionAPI
* and also contains implementations of runQuery[CSV], getLatestResults[CSV]
*/
import * as fs from "fs/promises";
import {
DuneError,
Expand All @@ -18,23 +24,38 @@ import {
} from "../constants";
import { ExecutionParams } from "../types/requestPayload";
import { QueryAPI } from "./query";
import { join } from "path";

/// Various states of query execution that are "terminal".
const TERMINAL_STATES = [
ExecutionState.CANCELLED,
ExecutionState.COMPLETED,
ExecutionState.FAILED,
ExecutionState.EXPIRED,
];

/**
* The primary interface for devs to utilize
* full functionality of the Dune API.
*/
export class DuneClient {
/// Execution Interface.
exec: ExecutionAPI;
/// Query Management Interface.
query: QueryAPI;

constructor(apiKey: string) {
this.exec = new ExecutionAPI(apiKey);
this.query = new QueryAPI(apiKey);
}

/**
* Runs an existing query by ID via execute, await, return results.
* @param queryID id of the query to be executed
* @param params execution parameters (includes query parameters and execution performance)
* @param batchSize puts a limit on the number of results
* @param pingFrequency how frequently should we check execution status (default: 1s)
* @returns Execution Results
*/
async runQuery(
queryID: number,
params?: ExecutionParams,
Expand Down Expand Up @@ -66,6 +87,13 @@ export class DuneClient {
}
}

/**
* Runs an existing query by ID via execute, await, return Result CSV.
* @param queryID id of the query to be executed
* @param params execution parameters (includes query parameters and execution performance)
* @param pingFrequency how frequently should we check execution status (default: 1s)
* @returns Execution Results as CSV
*/
async runQueryCSV(
queryID: number,
params?: ExecutionParams,
Expand Down
69 changes: 63 additions & 6 deletions src/api/execution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,26 @@ import { Router } from "./router";
import {
ExecutionParams,
ExecutionPerformance,
GetResultPayload,
GetResultParams,
} from "../types/requestPayload";
import {
DEFAULT_GET_PARAMS,
DUNE_CSV_NEXT_OFFSET_HEADER,
DUNE_CSV_NEXT_URI_HEADER,
} from "../constants";

// This class implements all the routes defined in the Dune API Docs: https://dune.com/docs/api/
/**
* This class implements all the routes defined in the Dune API Docs:
* https://docs.dune.com/api-reference/executions/execution-object
*/
export class ExecutionAPI extends Router {
/**
* Executes query by ID according to:
* https://docs.dune.com/api-reference/executions/endpoint/execute-query
* @param {number} queryID id of query to be executed.
* @param {ExecutionParams} params including query parameters and execution performance.
* @returns {ExecutionResponse} response containing execution ID and state.
*/
async executeQuery(
queryID: number,
params?: ExecutionParams,
Expand All @@ -43,13 +53,25 @@ export class ExecutionAPI extends Router {
return response as ExecutionResponse;
}

/**
* Cancels an execution according to:
* https://docs.dune.com/api-reference/executions/endpoint/cancel-execution
* @param {string} executionId string representig ID of query execution.
* @returns {boolean} indicating if success of cancellation request.
*/
async cancelExecution(executionId: string): Promise<boolean> {
const { success }: { success: boolean } = await this._post(
`execution/${executionId}/cancel`,
);
return success;
}

/**
* Retrieve the status of a query execution by executionID:
* https://docs.dune.com/api-reference/executions/endpoint/get-execution-status
* @param {string} executionId string representig ID of query execution.
* @returns {GetStatusResponse} status of query execution.
*/
async getExecutionStatus(executionId: string): Promise<GetStatusResponse> {
const response: GetStatusResponse = await this._get(
`execution/${executionId}/status`,
Expand All @@ -58,9 +80,16 @@ export class ExecutionAPI extends Router {
return response as GetStatusResponse;
}

/**
* Retrieve results of a query execution by executionID:
* https://docs.dune.com/api-reference/executions/endpoint/get-execution-result
* @param {string} executionId string representig ID of query execution
* @param {GetResultParams} params including limit, offset and expectedID.
* @returns {ResultsResponse} response containing execution results.
*/
async getExecutionResults(
executionId: string,
params: GetResultPayload = DEFAULT_GET_PARAMS,
params: GetResultParams = DEFAULT_GET_PARAMS,
): Promise<ResultsResponse> {
const response: ResultsResponse = await this._get(
`execution/${executionId}/results`,
Expand All @@ -70,9 +99,16 @@ export class ExecutionAPI extends Router {
return response as ResultsResponse;
}

/**
* Retrieve results of a query execution (in CSV format) by executionID:
* https://docs.dune.com/api-reference/executions/endpoint/get-execution-result-csv
* @param {string} executionId string representig ID of query execution.
* @param {GetResultParams} params including limit, offset and expectedID.
* @returns {ExecutionResponseCSV} execution results as CSV.
*/
async getResultCSV(
executionId: string,
params: GetResultPayload = DEFAULT_GET_PARAMS,
params: GetResultParams = DEFAULT_GET_PARAMS,
): Promise<ExecutionResponseCSV> {
const response = await this._get<Response>(
`execution/${executionId}/results/csv`,
Expand All @@ -83,18 +119,30 @@ export class ExecutionAPI extends Router {
return this.buildCSVResponse(response);
}

/**
* Retrieves results from query's last execution
* @param {number} queryID id of query to get results for.
* @param {GetResultParams} params parameters for retrieval.
* @returns {ResultsResponse} response containing execution results.
*/
async getLastExecutionResults(
queryId: number,
params: GetResultPayload = DEFAULT_GET_PARAMS,
params: GetResultParams = DEFAULT_GET_PARAMS,
): Promise<ResultsResponse> {
// The first bit might only return a page.
let results = await this._get<ResultsResponse>(`query/${queryId}/results`, params);
return this._fetchEntireResult(results);
}

/**
* Retrieves results from query's last execution (in CSV format)
* @param {number} queryID id of query to get results for.
* @param {GetResultParams} params parameters for retrieval.
* @returns {ExecutionResponseCSV} execution results as CSV.
*/
async getLastResultCSV(
queryId: number,
params: GetResultPayload = DEFAULT_GET_PARAMS,
params: GetResultParams = DEFAULT_GET_PARAMS,
): Promise<ExecutionResponseCSV> {
let response = await this._get<Response>(
`query/${queryId}/results/csv`,
Expand All @@ -104,6 +152,9 @@ export class ExecutionAPI extends Router {
return this._fetchEntireResultCSV(await this.buildCSVResponse(response));
}

/**
* Private method used for building CSV responses.
*/
private async buildCSVResponse(response: Response): Promise<ExecutionResponseCSV> {
const nextOffset = response.headers.get(DUNE_CSV_NEXT_OFFSET_HEADER);
return {
Expand All @@ -113,6 +164,9 @@ export class ExecutionAPI extends Router {
};
}

/**
* Private method used for retrieving entire result via pagination.
*/
private async _fetchEntireResult(results: ResultsResponse): Promise<ResultsResponse> {
let next_uri = results.next_uri;
let batch: ResultsResponse;
Expand All @@ -124,6 +178,9 @@ export class ExecutionAPI extends Router {
return results;
}

/**
* Private method used for retrieving entire result CSV via pagination.
*/
private async _fetchEntireResultCSV(
results: ExecutionResponseCSV,
): Promise<ExecutionResponseCSV> {
Expand Down
136 changes: 76 additions & 60 deletions src/api/query.ts
Original file line number Diff line number Diff line change
@@ -1,105 +1,121 @@
// Assuming the existence of these imports based on your Python code
import { Router } from "./router";
import { DuneQuery, QueryParameter, CreateQueryResponse, DuneError } from "../types";
import { CreateQueryPayload, UpdateQueryPayload } from "../types/requestPayload";
import { DuneQuery, CreateQueryResponse, DuneError } from "../types";
import { CreateQueryParams, UpdateQueryParams } from "../types/requestPayload";
import log from "loglevel";

interface EditQueryResponse {
query_id: number;
}

/**
* Query Management Interface (CRUD operations)
* https://docs.dune.com/api-reference/queries/endpoint/query-object
*/
export class QueryAPI extends Router {
/**
* Creates a Dune Query by ID
* https://dune.com/docs/api/api-reference/edit-queries/create-query/
* Create a query. The owner of the query will be under the context of the API key.
* https://docs.dune.com/api-reference/queries/endpoint/create
* @param {CreateQueryParams} params of query creation.
* @returns {number} the ID of the created query.
*/
async createQuery(
name: string,
querySql: string,
params?: QueryParameter[],
isPrivate: boolean = false,
): Promise<DuneQuery> {
const payload: CreateQueryPayload = {
name,
query_sql: querySql,
is_private: isPrivate,
query_parameters: params ? params : [],
};
const responseJson = await this._post<CreateQueryResponse>("query/", payload);
return this.getQuery(responseJson.query_id);
async createQuery(params: CreateQueryParams): Promise<number> {
if (params.is_private === undefined) {
params.is_private = false;
}
params.query_parameters = params.query_parameters ? params.query_parameters : [];
const responseJson = await this._post<CreateQueryResponse>("query/", params);
return responseJson.query_id;
}

/**
* Retrieves a Dune Query by ID
* https://dune.com/docs/api/api-reference/edit-queries/get-query/
* Read the sql text, parameters, name, tags, and state of a query.
* For private queries, only the API key generated under the context
* of the owner of that query will work:
* https://dune.com/docs/api/api-referenhttps://docs.dune.com/api-reference/queries/endpoint/read
* @param {number} queryId - the ID of the query to be read.
* @returns {DuneQuery} all known data regarding the query with given ID.
*/
async getQuery(queryId: number): Promise<DuneQuery> {
async readQuery(queryId: number): Promise<DuneQuery> {
const responseJson = await this._get(`query/${queryId}`);
return responseJson as DuneQuery;
}

/**
* Updates a Dune Query by ID
* https://dune.com/docs/api/api-reference/edit-queries/update-query/
* Update the sql text, parameters, name, tags, and state of a query.
* Only the API key generated under the context of the owner of that
* query will work.
* https://docs.dune.com/api-reference/queries/endpoint/update
* @param {number} queryId - the ID of the query to be updated.
* @param {UpdateQueryParams} - changes to be made to the query.
* @returns {number} updated query Id
*/
async updateQuery(
queryId: number,
name?: string,
querySql?: string,
params?: QueryParameter[],
description?: string,
tags?: string[],
): Promise<number> {
const parameters: UpdateQueryPayload = {};
if (name !== undefined) parameters.name = name;
if (description !== undefined) parameters.description = description;
if (tags !== undefined) parameters.tags = tags;
if (querySql !== undefined) parameters.query_sql = querySql;
if (params !== undefined) parameters.query_parameters = params;

if (Object.keys(parameters).length === 0) {
async updateQuery(queryId: number, params: UpdateQueryParams): Promise<number> {
if (Object.keys(params).length === 0) {
log.warn("updateQuery: called with no proposed changes.");
return queryId;
}

try {
const responseJson = await this._patch<CreateQueryResponse>(
`query/${queryId}`,
parameters,
);
return responseJson.query_id;
} catch (err: unknown) {
throw new Error(`Fokin Broken: ${err}`);
// throw new DuneError(responseJson, "UpdateQueryResponse", err);
}
const responseJson = await this._patch<CreateQueryResponse>(
`query/${queryId}`,
params,
);
return responseJson.query_id;
}

/**
* Archive a query. Only the API key generated under the context of
* the owner of that query will work. This does not delete the query,
* but will make it uneditable/unexecutable:
* https://docs.dune.com/api-reference/queries/endpoint/archive
* @param {number} queryId ID of the query to be archived.
* @returns {boolean} indicating success of request.
*/
public async archiveQuery(queryId: number): Promise<boolean> {
const response = await this._post<EditQueryResponse>(`/query/${queryId}/archive`);
const query = await this.getQuery(response.query_id);
const query = await this.readQuery(response.query_id);
return query.is_archived;
}

/**
* Unarchive a query. Only the API key generated under the context of
* the owner of that query will work.
* https://docs.dune.com/api-reference/queries/endpoint/unarchive
* @param {number} queryId ID of the query to be unarchived.
* @returns {boolean} indicating success of request.
*/
public async unarchiveQuery(queryId: number): Promise<boolean> {
const response = await this._post<EditQueryResponse>(`/query/${queryId}/unarchive`);
const query = await this.getQuery(response.query_id);
const query = await this.readQuery(response.query_id);
return query.is_archived;
}

public async makePrivate(queryId: number): Promise<void> {
/**
* Make a query private. Only the API key generated under the context of
* the owner of that query will work.
* https://docs.dune.com/api-reference/queries/endpoint/private
* @param {number} queryId - ID of the query to be made private.
* @returns {number} ID of the query made private.
*/
public async makePrivate(queryId: number): Promise<number> {
const response = await this._post<EditQueryResponse>(`/query/${queryId}/private`);
const query = await this.getQuery(response.query_id);
const query = await this.readQuery(response.query_id);
if (!query.is_private) {
throw new DuneError("Query was not made private!");
}
return response.query_id;
}

public async makePublic(queryId: number): Promise<void> {
const responseJson = await this._post<EditQueryResponse>(
`/query/${queryId}/unprivate`,
);
const query = await this.getQuery(responseJson.query_id);
/**
* Make a private query public.
* https://docs.dune.com/api-reference/queries/endpoint/unprivate
* @param {number} queryId - ID of the query to be made public.
* @returns {number} ID of the query made public.
*/
public async makePublic(queryId: number): Promise<number> {
const response = await this._post<EditQueryResponse>(`/query/${queryId}/unprivate`);
const query = await this.readQuery(response.query_id);
if (query.is_private) {
throw new DuneError("Query is still private.");
}
return response.query_id;
}
}
Loading

0 comments on commit 3d5d5bb

Please sign in to comment.