Skip to content

Commit 5e8e966

Browse files
address CR and add tests
1 parent 3162e31 commit 5e8e966

File tree

5 files changed

+648
-108
lines changed

5 files changed

+648
-108
lines changed

src/connection/base.ts

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -179,10 +179,10 @@ export abstract class Connection {
179179

180180
abstract cancelAsyncQuery(token: string): Promise<void>;
181181

182-
protected async prepareAndExecuteQuery(
182+
protected prepareQuery(
183183
query: string,
184184
executeQueryOptions: ExecuteQueryOptions
185-
): Promise<{ formattedQuery: string; response: Response }> {
185+
): { formattedQuery: string; setKey: string } {
186186
executeQueryOptions.response = {
187187
...defaultResponseSettings,
188188
...(executeQueryOptions.response ?? {})
@@ -205,13 +205,14 @@ export abstract class Connection {
205205
);
206206
}
207207

208-
return await this.executeQuery(formattedQuery, executeQueryOptions, setKey);
208+
return { formattedQuery, setKey };
209209
}
210210

211211
protected async executeQuery(
212212
formattedQuery: string,
213213
executeQueryOptions: ExecuteQueryOptions,
214-
setKey = ""
214+
setKey = "",
215+
returnResponse = false
215216
) {
216217
const { httpClient } = this.context;
217218

@@ -229,7 +230,14 @@ export abstract class Connection {
229230
try {
230231
const response = await request.ready();
231232
await this.processHeaders(response.headers);
232-
return { formattedQuery, response };
233+
if (returnResponse) {
234+
return { response, text: "" };
235+
}
236+
237+
const text = await response.text();
238+
await this.throwErrorIfErrorBody(text, response);
239+
240+
return { response, text };
233241
} catch (error) {
234242
// In case it was a set query, remove set parameter if query fails
235243
if (setKey.length > 0) {
@@ -241,17 +249,42 @@ export abstract class Connection {
241249
}
242250
}
243251

252+
protected async prepareAndExecuteQuery(
253+
query: string,
254+
executeQueryOptions: ExecuteQueryOptions,
255+
returnResponse = false
256+
): Promise<{
257+
formattedQuery: string;
258+
response: Response;
259+
text: string;
260+
}> {
261+
const { formattedQuery, setKey } = this.prepareQuery(
262+
query,
263+
executeQueryOptions
264+
);
265+
const { response, text } = await this.executeQuery(
266+
formattedQuery,
267+
executeQueryOptions,
268+
setKey,
269+
returnResponse
270+
);
271+
272+
return {
273+
formattedQuery,
274+
response,
275+
text
276+
};
277+
}
278+
244279
async execute(
245280
query: string,
246281
executeQueryOptions: ExecuteQueryOptions = {}
247282
): Promise<Statement> {
248-
const { formattedQuery, response } = await this.prepareAndExecuteQuery(
283+
const { formattedQuery, text } = await this.prepareAndExecuteQuery(
249284
query,
250285
executeQueryOptions
251286
);
252287

253-
const text = await response.text();
254-
await this.throwErrorIfErrorBody(text, response);
255288
return new Statement(this.context, {
256289
query: formattedQuery,
257290
text,

src/connection/connection_v2.ts

Lines changed: 28 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,11 @@ export class ConnectionV2 extends BaseConnection {
9191
// can't have an async set query
9292
throw new Error("SET statements cannot be executed asynchronously.");
9393
}
94-
const { formattedQuery, response } = await this.prepareAndExecuteQuery(
94+
const { formattedQuery, text } = await this.prepareAndExecuteQuery(
9595
query,
9696
asyncExecuteQueryOptions
9797
);
9898

99-
const text = await response.text();
100-
await this.throwErrorIfErrorBody(text, response);
10199
return new AsyncStatement(this.context, {
102100
query: formattedQuery,
103101
text,
@@ -109,13 +107,17 @@ export class ConnectionV2 extends BaseConnection {
109107
query: string,
110108
executeQueryOptions: ExecuteQueryOptions = {}
111109
): Promise<StreamStatement> {
112-
const { response } = await this.prepareAndExecuteQuery(query, {
113-
...executeQueryOptions,
114-
settings: {
115-
...executeQueryOptions?.settings,
116-
output_format: OutputFormat.JSON_LINES
117-
}
118-
});
110+
const { response } = await this.prepareAndExecuteQuery(
111+
query,
112+
{
113+
...executeQueryOptions,
114+
settings: {
115+
...executeQueryOptions?.settings,
116+
output_format: OutputFormat.JSON_LINES
117+
}
118+
},
119+
true
120+
);
119121

120122
return new StreamStatement({
121123
response,
@@ -137,48 +139,36 @@ export class ConnectionV2 extends BaseConnection {
137139
query: string,
138140
executeQueryOptions: ExecuteQueryOptions
139141
): Promise<Statement> {
140-
this.checkParameters(query, executeQueryOptions.namedParameters);
141-
const { response } = await this.executeQuery(
142+
const { text } = await this.executeQuery(
142143
query,
143144
this.getExecuteQueryOptionsForPreparedStatement(executeQueryOptions)
144145
);
145146

146-
const text = await response.text();
147-
await this.throwErrorIfErrorBody(text, response);
148147
return new Statement(this.context, {
149148
query: query,
150149
text,
151150
executeQueryOptions
152151
});
153152
}
154153

155-
private checkParameters(
156-
query: string,
157-
namedParameters: Record<string, unknown> | undefined
158-
) {
159-
const fireboltNumericParameters =
160-
this.queryFormatter.getFireboltNumericParameters(query);
161-
const providedParameters = Object.keys(namedParameters || {});
162-
if (fireboltNumericParameters.length != providedParameters.length) {
163-
throw new Error(
164-
`Number of parameters in the query (${fireboltNumericParameters.length}) does not match the number of named parameters provided (${providedParameters.length}).`
165-
);
166-
}
167-
fireboltNumericParameters.forEach(param => {
168-
if (!providedParameters.includes(param)) {
169-
throw new Error(
170-
`Parameter "${param}" is missing from the named parameters.`
171-
);
172-
}
173-
});
174-
}
175-
176154
private getExecuteQueryOptionsForPreparedStatement(
177155
executeQueryOptions: ExecuteQueryOptions
178156
): ExecuteQueryOptions {
179-
const queryParameters = Object.entries(
180-
executeQueryOptions.namedParameters || {}
181-
).map(([key, value]) => ({ name: key, value }));
157+
let queryParameters;
158+
if (!executeQueryOptions.parameters) {
159+
queryParameters = Object.entries(
160+
executeQueryOptions.namedParameters || {}
161+
).map(([key, value]) => ({ name: key, value }));
162+
} else if (!executeQueryOptions.namedParameters) {
163+
queryParameters = executeQueryOptions.parameters.map((value, index) => ({
164+
name: `$${index + 1}`,
165+
value
166+
}));
167+
} else {
168+
throw new Error(
169+
"Server-side prepared statement can only use either parameters or namedParameters"
170+
);
171+
}
182172

183173
return {
184174
settings: {

src/formatter/base.ts

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -220,20 +220,6 @@ export abstract class QueryFormatter {
220220
return query;
221221
}
222222

223-
getFireboltNumericParameters(query: string): string[] {
224-
const regex = /'[^']*'|"[^"]*"|\/\*[\s\S]*?\*\/|--.*|(\$[0-9]+)/g;
225-
226-
let match;
227-
const params = [];
228-
229-
while ((match = regex.exec(query)) !== null) {
230-
if (match[1]) {
231-
params.push(match[1]);
232-
}
233-
}
234-
return params;
235-
}
236-
237223
isSetStatement(query: string): boolean {
238224
return query.trim().toLowerCase().startsWith(SET_PREFIX);
239225
}

0 commit comments

Comments
 (0)