-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathquery.ts
More file actions
92 lines (78 loc) · 2.77 KB
/
query.ts
File metadata and controls
92 lines (78 loc) · 2.77 KB
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
import { createHash } from "node:crypto";
import type { sql } from "@databricks/sdk-experimental";
import { isSQLTypeMarker, type SQLTypeMarker, sql as sqlHelpers } from "shared";
import { getWorkspaceId } from "../context";
import { ValidationError } from "../errors";
type SQLParameterValue = SQLTypeMarker | null | undefined;
export class QueryProcessor {
async processQueryParams(
query: string,
parameters?: Record<string, SQLParameterValue>,
): Promise<Record<string, SQLParameterValue>> {
const processed = { ...parameters };
// extract all params from the query
const paramMatches = query.matchAll(/:([a-zA-Z_]\w*)/g);
const queryParams = new Set(Array.from(paramMatches, (m) => m[1]));
// auto-inject workspaceId if needed and not provided
if (queryParams.has("workspaceId") && !processed.workspaceId) {
const workspaceId = await getWorkspaceId();
if (workspaceId) {
processed.workspaceId = sqlHelpers.string(workspaceId);
}
}
return processed;
}
hashQuery(query: string): string {
return createHash("md5").update(query).digest("hex");
}
convertToSQLParameters(
query: string,
parameters?: Record<string, SQLParameterValue>,
): { statement: string; parameters: sql.StatementParameterListItem[] } {
const sqlParameters: sql.StatementParameterListItem[] = [];
if (parameters) {
// extract all params from the query
const queryParamMatches = query.matchAll(/:([a-zA-Z_]\w*)/g);
const queryParams = new Set(Array.from(queryParamMatches, (m) => m[1]));
// only allow parameters that exist in the query
for (const key of Object.keys(parameters)) {
if (!queryParams.has(key)) {
const validParams = Array.from(queryParams).join(", ") || "none";
throw ValidationError.invalidValue(
key,
parameters[key],
`a parameter defined in the query (valid: ${validParams})`,
);
}
}
// convert parameters to SQL parameters
for (const [key, value] of Object.entries(parameters)) {
const parameter = this._createParameter(key, value);
if (parameter) {
sqlParameters.push(parameter);
}
}
}
return { statement: query, parameters: sqlParameters };
}
private _createParameter(
key: string,
value: SQLParameterValue,
): sql.StatementParameterListItem | null {
if (value === null || value === undefined) {
return null;
}
if (!isSQLTypeMarker(value)) {
throw ValidationError.invalidValue(
key,
value,
"SQL type (use sql.string(), sql.number(), sql.date(), sql.timestamp(), or sql.boolean())",
);
}
return {
name: key,
value: value.value,
type: value.__sql_type,
};
}
}