-
Notifications
You must be signed in to change notification settings - Fork 83
feat(webui): Add support for submitting Presto SQL queries. #1127
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
fbc0fb4
73d41d5
767dcf5
879941e
b2c8614
257a901
c740212
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| import { | ||
| Static, | ||
| Type, | ||
| } from "@sinclair/typebox"; | ||
| import {Value} from "@sinclair/typebox/value"; | ||
| import axios from "axios"; | ||
|
|
||
|
|
||
| // eslint-disable-next-line no-warning-comments | ||
| // TODO: Replace with shared type from the `@common` directory once refactoring is completed. | ||
| // Currently, server schema types require typebox dependency so they cannot be moved to the | ||
| // `@common` directory with current implementation. | ||
| const StringSchema = Type.String({ | ||
hoophalab marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| minLength: 1, | ||
| }); | ||
hoophalab marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
| const PrestoSearchJobCreationSchema = Type.Object({ | ||
| queryString: StringSchema, | ||
| }); | ||
hoophalab marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| type PrestoSearchJobCreation = Static<typeof PrestoSearchJobCreationSchema>; | ||
|
|
||
| const PrestoJobSchema = Type.Object( | ||
| { | ||
| searchJobId: StringSchema, | ||
| } | ||
| ); | ||
|
|
||
| type PrestoJob = Static<typeof PrestoJobSchema>; | ||
|
|
||
| /** | ||
| * Sends post request to server tosubmit presto query. | ||
hoophalab marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| * | ||
| * @param payload | ||
| * @return | ||
| */ | ||
| const submitQuery = async (payload: PrestoSearchJobCreation): Promise<PrestoJob> => { | ||
| const ret = await axios.post<PrestoJob>("/api/presto-search/query", payload); | ||
| return Value.Parse(PrestoJobSchema, ret.data); | ||
| }; | ||
|
|
||
| export {submitQuery}; | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,89 @@ | ||||||||||||||||||||||||||||||||||||||
| import {FastifyPluginAsyncTypebox} from "@fastify/type-provider-typebox"; | ||||||||||||||||||||||||||||||||||||||
| import {StatusCodes} from "http-status-codes"; | ||||||||||||||||||||||||||||||||||||||
| import {Client} from "presto-client"; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| import settings from "../../../../settings.json" with {type: "json"}; | ||||||||||||||||||||||||||||||||||||||
| import {ErrorSchema} from "../../../schemas/error.js"; | ||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||
| PrestoJobSchema, | ||||||||||||||||||||||||||||||||||||||
| PrestoSearchJobCreationSchema, | ||||||||||||||||||||||||||||||||||||||
| } from "../../../schemas/presto-search.js"; | ||||||||||||||||||||||||||||||||||||||
| import {Nullable} from "../../../typings/common.js"; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||
| * Presto search API routes. | ||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||
| * @param fastify | ||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||
| const plugin: FastifyPluginAsyncTypebox = async (fastify) => { | ||||||||||||||||||||||||||||||||||||||
| if (false === settings.EnablePresto) { | ||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| const client = new Client({host: settings.PrestoHost, port: settings.PrestoPort}); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
| const plugin: FastifyPluginAsyncTypebox = async (fastify) => { | |
| if (false === settings.EnablePresto) { | |
| return; | |
| } | |
| const client = new Client({host: settings.PrestoHost, port: settings.PrestoPort}); | |
| const plugin: FastifyPluginAsyncTypebox = async (fastify) => { | |
| if (false === settings.EnablePresto) { | |
| return; | |
| } | |
| if (!settings.PrestoHost || !settings.PrestoPort) { | |
| throw new Error("Presto is enabled but PrestoHost or PrestoPort is not configured"); | |
| } | |
| const client = new Client({host: settings.PrestoHost, port: settings.PrestoPort}); | |
| // …rest of plugin implementation… | |
| } |
🤖 Prompt for AI Agents
In components/webui/server/src/routes/api/presto-search/index.ts around lines 19
to 25, the code creates a Presto client without validating the configuration
settings. Add validation checks to ensure that settings.PrestoHost is a
non-empty string and settings.PrestoPort is a valid number before creating the
client. If either setting is missing or invalid, log an error or return early to
prevent creating the client with invalid configuration.
davemarco marked this conversation as resolved.
Show resolved
Hide resolved
hoophalab marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
hoophalab marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Critical: Improve error handling and async flow in Presto callbacks.
The current implementation has several issues:
- The error thrown in the error callback (line 60) won't be caught by the Promise
- The Promise resolves immediately when state is updated, not when the query completes
- No handling for the case where the query completes without calling the state callback
Consider refactoring to properly handle all callback scenarios:
- searchJobId = await new Promise((resolve) => {
+ searchJobId = await new Promise((resolve, reject) => {
client.execute({
data: (error, data, columns) => {
+ if (error) {
+ request.log.error({error}, "Error in data callback");
+ return;
+ }
if (null === searchJobId) {
request.log.error("Data arrived from Presto before the search job id.");
}
request.log.info({error, searchJobId, columns, data}, "Presto data");
},
error: (error) => {
request.log.info(error, "Presto search failed");
-
- // The `/query` endpoint will catch this error if `resolve` hasn't
- // been called.
- throw new Error("Presto search failed.");
+ reject(new Error("Presto search failed."));
},
query: queryString,
state: (error, newSearchJobId, stats) => {
+ if (error) {
+ request.log.error({error}, "Error in state callback");
+ reject(error);
+ return;
+ }
request.log.info({
error: error,
searchJobId: newSearchJobId,
state: stats.state,
}, "Presto search state updated");
- resolve(newSearchJobId);
+ // Only set searchJobId once
+ if (null === searchJobId && newSearchJobId) {
+ searchJobId = newSearchJobId;
+ }
+
+ // Don't resolve here - wait for success or error
},
success: () => {
request.log.info("Presto search succeeded");
+ resolve(searchJobId);
},
});
});🤖 Prompt for AI Agents
In components/webui/server/src/routes/api/presto-search/index.ts between lines
47 and 76, the Promise handling Presto client callbacks has issues: throwing an
error inside the error callback does not reject the Promise, the Promise
resolves prematurely on state update instead of query completion, and there is
no handling for query completion without state callback. To fix this, refactor
the Promise to reject on error by calling reject with the error, resolve only
when the success callback is invoked indicating query completion, and ensure all
possible callback scenarios (error, state, success) properly trigger resolve or
reject to maintain correct async flow.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| import {Type} from "@sinclair/typebox"; | ||
|
|
||
| import {StringSchema} from "./common.js"; | ||
|
|
||
|
|
||
| /** | ||
| * Schema for request to create a new query job. | ||
| */ | ||
| const PrestoSearchJobCreationSchema = Type.Object({ | ||
| queryString: StringSchema, | ||
| }); | ||
|
|
||
| const PrestoJobSchema = Type.Object({ | ||
| searchJobId: StringSchema, | ||
| }); | ||
|
|
||
| export { | ||
| PrestoJobSchema, | ||
| PrestoSearchJobCreationSchema, | ||
| }; |
Uh oh!
There was an error while loading. Please reload this page.