Skip to content

Commit

Permalink
Run SQL (#35)
Browse files Browse the repository at this point in the history
  • Loading branch information
bh2smith authored Mar 16, 2024
1 parent 35e7075 commit 5a0cfc3
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 7 deletions.
51 changes: 50 additions & 1 deletion src/api/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
POLL_FREQUENCY_SECONDS,
THREE_MONTHS_IN_HOURS,
} from "../constants";
import { ExecutionParams } from "../types/requestPayload";
import { ExecutionParams, ExecutionPerformance } from "../types/requestPayload";
import { QueryAPI } from "./query";

/// Various states of query execution that are "terminal".
Expand Down Expand Up @@ -183,6 +183,55 @@ export class DuneClient {
log.info(`CSV data has been saved to ${outFile}`);
}

/**
* Allows user to provide execute raw_sql via the CRUD interface
* - create, run, get results with optional archive/delete.
* - Query is by default made private and archived after execution.
* Requires Plus subscription!
* @param query_sql - raw sql of query to run
* @param params - query parameters
* @param isPrivate - whether the created query should be private
* @param archiveAfter - whether the created query should be archived immediately after execution
* @param performance - performance tier of execution engine
* @param batchSize - the page size when retriving results.
* @param pingFrequency - how frequently should we check execution status
* @param name - name of the query
* @returns
*/
public async runSql(
query_sql: string,
params?: QueryParameter[],
isPrivate: boolean = true,
archiveAfter: boolean = true,
performance?: ExecutionPerformance,
batchSize: number = MAX_NUM_ROWS_PER_BATCH,
pingFrequency: number = POLL_FREQUENCY_SECONDS,
name: string = "API Query",
): Promise<ResultsResponse> {
const queryID = await this.query.createQuery({
name,
query_sql,
query_parameters: params,
is_private: isPrivate,
});
let results: ResultsResponse;

try {
results = await this.runQuery(
queryID,
{ query_parameters: params, performance },
batchSize,
pingFrequency,
);
} finally {
if (archiveAfter) {
this.query.archiveQuery(queryID);
}
}

return results;
}

private async _runInner(
queryID: number,
params?: ExecutionParams,
Expand Down
8 changes: 4 additions & 4 deletions src/api/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export class QueryAPI extends Router {
* @returns {boolean} indicating success of request.
*/
public async archiveQuery(queryId: number): Promise<boolean> {
const response = await this._post<EditQueryResponse>(`/query/${queryId}/archive`);
const response = await this._post<EditQueryResponse>(`query/${queryId}/archive`);
const query = await this.readQuery(response.query_id);
return query.is_archived;
}
Expand All @@ -83,7 +83,7 @@ export class QueryAPI extends Router {
* @returns {boolean} indicating success of request.
*/
public async unarchiveQuery(queryId: number): Promise<boolean> {
const response = await this._post<EditQueryResponse>(`/query/${queryId}/unarchive`);
const response = await this._post<EditQueryResponse>(`query/${queryId}/unarchive`);
const query = await this.readQuery(response.query_id);
return query.is_archived;
}
Expand All @@ -96,7 +96,7 @@ export class QueryAPI extends Router {
* @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 response = await this._post<EditQueryResponse>(`query/${queryId}/private`);
const query = await this.readQuery(response.query_id);
if (!query.is_private) {
throw new DuneError("Query was not made private!");
Expand All @@ -111,7 +111,7 @@ export class QueryAPI extends Router {
* @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 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.");
Expand Down
2 changes: 1 addition & 1 deletion src/api/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export class Router {
}
} catch (error) {
log.error(logPrefix, `caught unhandled response error ${JSON.stringify(error)}`);
throw error;
throw new DuneError(`Response ${error}`);
}
return result;
}
Expand Down
11 changes: 10 additions & 1 deletion tests/e2e/client.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { expect } from "chai";
import { DuneClient, QueryParameter } from "../../src/";
import log from "loglevel";
import { BASIC_KEY } from "./util";
import { BASIC_KEY, PLUS_KEY } from "./util";
import * as fs from "fs/promises";

log.setLevel(log.levels.DEBUG, true);
Expand Down Expand Up @@ -89,4 +89,13 @@ describe("DuneClient Extensions", () => {
// Remove the CSV file after the comparison
await fs.unlink("./out.csv");
});

it("runSQL", async () => {
const premiumClient = new DuneClient(PLUS_KEY);
const results = await premiumClient.runSql("select 1", [], true, true);
const queryID = results.query_id;
expect(results.result?.rows).to.be.deep.equal([{ _col0: 1 }]);
const query = await premiumClient.query.readQuery(queryID);
expect(query.is_archived).to.be.equal(true);
});
});
19 changes: 19 additions & 0 deletions tests/e2e/queryAPI.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,25 @@ describe("QueryAPI: Premium - CRUD Operations", () => {
});
expect(updatedQueryId).to.be.equal(recoveredQuery.query_id);
});

it.only("unarchive, make public, make private, rearchive", async () => {
const queryId = 3530410;
let query = await plusClient.readQuery(queryId);
expect(query.is_archived).to.be.equal(true);
expect(query.is_private).to.be.equal(true);

await plusClient.unarchiveQuery(queryId);
await plusClient.makePublic(queryId);
query = await plusClient.readQuery(queryId);
expect(query.is_archived).to.be.equal(false);
expect(query.is_private).to.be.equal(false);

await plusClient.archiveQuery(queryId);
await plusClient.makePrivate(queryId);
query = await plusClient.readQuery(queryId);
expect(query.is_archived).to.be.equal(true);
expect(query.is_private).to.be.equal(true);
});
});

describe("QueryAPI: Errors", () => {
Expand Down

0 comments on commit 5a0cfc3

Please sign in to comment.