-
Notifications
You must be signed in to change notification settings - Fork 3.8k
/
Copy pathsqlApi.ts
138 lines (123 loc) · 3.89 KB
/
sqlApi.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Copyright 2022 The Cockroach Authors.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
import { fetchDataJSON } from "./fetchData";
export type SqlExecutionRequest = {
statements: SqlStatement[];
execute?: boolean;
timeout?: string; // Default 5s
application_name?: string; // Defaults to '$ api-v2-sql'
database?: string; // Defaults to defaultDb
max_result_size?: number; // Default 10kib
};
export type SqlStatement = {
sql: string;
arguments?: unknown[];
};
export type SqlExecutionResponse<T> = {
num_statements?: number;
execution?: SqlExecutionExecResult<T>;
error?: SqlExecutionErrorMessage;
request?: SqlExecutionRequest;
};
export interface SqlExecutionExecResult<T> {
retries: number;
txn_results: SqlTxnResult<T>[];
}
export type SqlTxnResult<RowType> = {
statement: number; // Statement index from input array
tag: string; // Short stmt tag
start: string; // Start timestamp, encoded as RFC3339
end: string; // End timestamp, encoded as RFC3339
rows_affected: number;
columns?: SqlResultColumn[];
rows?: RowType[];
error?: Error;
};
export type SqlResultColumn = {
name: string;
type: string;
oid: number;
};
export type SqlExecutionErrorMessage = {
message: string;
code: string;
severity: string;
source: { file: string; line: number; function: "string" };
};
export const SQL_API_PATH = "/api/v2/sql/";
/**
* executeSql executes the provided SQL statements in a single transaction
* over HTTP.
*
* @param req execution request details
*/
export function executeSql<RowType>(
req: SqlExecutionRequest,
): Promise<SqlExecutionResponse<RowType>> {
return fetchDataJSON<SqlExecutionResponse<RowType>, SqlExecutionRequest>(
SQL_API_PATH,
req,
);
}
export const INTERNAL_SQL_API_APP = "$ internal-console";
export const LONG_TIMEOUT = "300s";
export const LARGE_RESULT_SIZE = 50000; // 50 kib
/**
* executeInternalSql executes the provided SQL statements with
* the app name set to the internal sql api app name above.
* Note that technically all SQL executed over this API are
* executed as internal, but we make this distinction using the
* function name for when we want to execute user queries in the
* future, where such queries should not have an internal app name.
*
* @param req execution request details
*/
export function executeInternalSql<RowType>(
req: SqlExecutionRequest,
): Promise<SqlExecutionResponse<RowType>> {
if (!req.application_name) {
req.application_name = INTERNAL_SQL_API_APP;
} else {
req.application_name = `$ internal-${req.application_name}`;
}
return executeSql(req);
}
/**
* sqlResultsAreEmpty returns true if the provided result
* does not contain any rows.
* @param result the sql execution result returned by the server
* @returns
*/
export function sqlResultsAreEmpty(
result: SqlExecutionResponse<unknown>,
): boolean {
return (
!result.execution?.txn_results?.length ||
result.execution.txn_results.every(
txn => !txn.rows || txn.rows.length === 0,
)
);
}
/**
* errorMessage cleans the error message returned by the sqlApi,
* removing information not useful for the user.
* e.g. "$executing stmt 1: run-query-via-api: only users with either MODIFYCLUSTERSETTING
* or VIEWCLUSTERSETTING privileges are allowed to show cluster settings"
* became
* "only users with either MODIFYCLUSTERSETTING or VIEWCLUSTERSETTING privileges are allowed to show cluster settings"
* @param message
*/
export function sqlApiErrorMessage(message: string) {
const runQueryInfo = "run-query-via-api: ";
if (message.includes(runQueryInfo)) {
return message.split(runQueryInfo)[1];
}
return message;
}