Skip to content

Commit 4e2a06f

Browse files
authored
Merge branch 'y-scope:main' into graceful-shutdown
2 parents 0bdf6b8 + 06f5fe5 commit 4e2a06f

4 files changed

Lines changed: 100 additions & 6 deletions

File tree

  • components/webui

components/webui/client/src/components/QueryBox/InputWithCaseSensitive/index.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
22
Input,
33
InputProps,
4+
InputRef,
45
} from "antd";
56

67
import CaseSensitiveToggle, {CaseSensitiveToggleProps} from "./CaseSenstiveToggle";
@@ -9,7 +10,8 @@ import CaseSensitiveToggle, {CaseSensitiveToggleProps} from "./CaseSenstiveToggl
910
/**
1011
* Antd Input props and case sensitive toggle props with suffix omitted since set by component.
1112
*/
12-
type InputWithCaseSensitiveProps = Omit<InputProps, "suffix"> & CaseSensitiveToggleProps;
13+
type InputWithCaseSensitiveProps =
14+
Omit<InputProps, "suffix"> & CaseSensitiveToggleProps & React.RefAttributes<InputRef>;
1315

1416
/**
1517
* Antd Input with a built-in case sensitivity toggle.

components/webui/client/src/pages/SearchPage/SearchControls/QueryInput/index.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
useState,
77
} from "react";
88

9+
import type {InputRef} from "antd";
910
import {Nullable} from "src/typings/common";
1011

1112
import QueryBox from "../../../../components/QueryBox";
@@ -28,6 +29,7 @@ const QueryInput = () => {
2829
const searchUiState = useSearchStore((state) => state.searchUiState);
2930
const [pseudoProgress, setPseudoProgress] = useState<Nullable<number>>(null);
3031
const intervalIdRef = useRef<number>(0);
32+
const inputRef = useRef<InputRef>(null);
3133

3234
const handleCaseSensitiveChange = useCallback((newValue: boolean) => {
3335
const {updateQueryIsCaseSensitive} = useSearchStore.getState();
@@ -67,11 +69,21 @@ const QueryInput = () => {
6769
clearInterval(intervalIdRef.current);
6870
}, []);
6971

72+
useEffect(() => {
73+
if (
74+
searchUiState === SEARCH_UI_STATE.DEFAULT ||
75+
searchUiState === SEARCH_UI_STATE.DONE
76+
) {
77+
inputRef.current?.focus();
78+
}
79+
}, [searchUiState]);
80+
7081
return (
7182
<QueryBox
7283
isCaseSensitive={queryIsCaseSensitive}
7384
placeholder={"Enter your query"}
7485
progress={pseudoProgress}
86+
ref={inputRef}
7587
size={"large"}
7688
value={queryString}
7789
disabled={

components/webui/server/src/routes/api/presto-search/index.ts

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,28 @@ import {
66
PrestoQueryJobCreationSchema,
77
PrestoQueryJobSchema,
88
} from "../../../schemas/presto-search.js";
9+
import {insertPrestoRowsToMongo} from "./utils.js";
910

1011

1112
/**
1213
* Presto search API routes.
1314
*
1415
* @param fastify
1516
*/
17+
// eslint-disable-next-line max-lines-per-function
1618
const plugin: FastifyPluginAsyncTypebox = async (fastify) => {
17-
const {Presto} = fastify;
19+
const {Presto, mongo} = fastify;
20+
const mongoDb = mongo.db;
1821

1922
if ("undefined" === typeof Presto) {
2023
// If Presto client is not available, skip the plugin registration.
2124
return;
2225
}
2326

27+
if ("undefined" === typeof mongoDb) {
28+
throw new Error("MongoDB database not found");
29+
}
30+
2431
/**
2532
* Submits a search query.
2633
*/
@@ -36,7 +43,7 @@ const plugin: FastifyPluginAsyncTypebox = async (fastify) => {
3643
tags: ["Presto Search"],
3744
},
3845
},
39-
46+
// eslint-disable-next-line max-lines-per-function
4047
async (request, reply) => {
4148
const {queryString} = request.body;
4249

@@ -45,13 +52,39 @@ const plugin: FastifyPluginAsyncTypebox = async (fastify) => {
4552
try {
4653
searchJobId = await new Promise<string>((resolve, reject) => {
4754
let isResolved = false;
48-
4955
Presto.client.execute({
5056
// eslint-disable-next-line no-warning-comments
51-
// TODO: Data, error, and success handlers are dummy implementations
57+
// TODO: Error, and success handlers are dummy implementations
5258
// and will be replaced with proper implementations.
5359
data: (_, data, columns) => {
54-
request.log.info({columns, data}, "Presto data");
60+
request.log.info(
61+
`Received ${data.length} rows from Presto query`
62+
);
63+
64+
if (false === isResolved) {
65+
request.log.error(
66+
"Presto data received before searchJobId was resolved; " +
67+
"skipping insert."
68+
);
69+
70+
return;
71+
}
72+
73+
if (0 === data.length) {
74+
return;
75+
}
76+
77+
insertPrestoRowsToMongo(
78+
data,
79+
columns,
80+
searchJobId,
81+
mongoDb
82+
).catch((err: unknown) => {
83+
request.log.error(
84+
err,
85+
"Failed to insert Presto results into MongoDB"
86+
);
87+
});
5588
},
5689
error: (error) => {
5790
request.log.info(error, "Presto search failed");
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import type {
2+
Db,
3+
InsertManyResult,
4+
} from "mongodb";
5+
6+
7+
/**
8+
* Converts a Presto result row (array of values) into an object, using the provided column
9+
* definitions to assign property names.
10+
*
11+
* @param row Array of values representing a single Presto result row.
12+
* @param columns Array of column definitions, each containing a `name` property.
13+
* @return An object mapping each column name to its corresponding value from the row.
14+
*/
15+
const prestoRowToObject = (
16+
row: unknown[],
17+
columns: {name: string}[]
18+
): Record<string, unknown> => {
19+
const obj: Record<string, unknown> = {};
20+
columns.forEach((col, idx) => {
21+
obj[col.name] = row[idx];
22+
});
23+
24+
return obj;
25+
};
26+
27+
/**
28+
* Inserts Presto rows into a MongoDB collection for a given search job.
29+
*
30+
* @param data Array of Presto result rows
31+
* @param columns Array of column definitions
32+
* @param searchJobId
33+
* @param mongoDb
34+
* @return Promise that resolves when the insertion is complete
35+
*/
36+
const insertPrestoRowsToMongo = (
37+
data: unknown[][],
38+
columns: {name: string}[],
39+
searchJobId: string,
40+
mongoDb: Db
41+
): Promise<InsertManyResult<Document>> => {
42+
const collection = mongoDb.collection(searchJobId);
43+
const resultDocs = data.map((row) => prestoRowToObject(row, columns));
44+
return collection.insertMany(resultDocs);
45+
};
46+
47+
export {insertPrestoRowsToMongo};

0 commit comments

Comments
 (0)