Skip to content

Commit

Permalink
Merge pull request #200 from zilliztech/fixQuery
Browse files Browse the repository at this point in the history
Allow user to type query expression on query page
  • Loading branch information
shanghaikid authored Jun 16, 2023
2 parents bfe975a + 6ae771e commit af3607e
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 84 deletions.
4 changes: 2 additions & 2 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"private": true,
"dependencies": {
"@date-io/dayjs": "1.x",
"@loadable/component": "^5.15.0",
"@json2csv/plainjs": "^7.0.1",
"@material-ui/core": "4.11.4",
"@material-ui/icons": "^4.11.3",
"@material-ui/lab": "4.0.0-alpha.58",
Expand All @@ -26,7 +26,6 @@
"react-router-dom": "^6.4.3",
"react-syntax-highlighter": "^15.4.4",
"socket.io-client": "^4.1.3",
"typescript": "^4.1.2",
"vite": "^3.2.2",
"vite-plugin-svgr": "^0.3.0",
"web-vitals": "^1.0.1"
Expand All @@ -52,6 +51,7 @@
"@vitest/coverage-c8": "^0.25.0",
"jsdom": "^20.0.2",
"prettier": "2.3.2",
"typescript": "^4.1.2",
"vitest": "^0.24.5"
},
"homepage": "./",
Expand Down
16 changes: 8 additions & 8 deletions client/src/consts/Util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,6 @@ export const BYTE_UNITS: { [x: string]: number } = {
};

export const LOGICAL_OPERATORS = [
{
value: '<',
label: '<',
},
{
value: '<=',
label: '<=',
},
{
value: '>',
label: '>',
Expand All @@ -30,6 +22,14 @@ export const LOGICAL_OPERATORS = [
value: '!=',
label: '!=',
},
{
value: '<',
label: '<',
},
{
value: '<=',
label: '<=',
},
{
value: 'in',
label: 'in',
Expand Down
8 changes: 4 additions & 4 deletions client/src/i18n/en/collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ const collectionTrans = {
alias: 'Alias',
aliasTooltip: 'Please select one collection to create alias',
download: 'Download',
downloadTooltip: 'Download all query results',
downloadTooltip: 'Export all query results to CSV file',
downloadDisabledTooltip: 'Please query data before exporting',

collection: 'Collection',
entites: 'entites',
Expand Down Expand Up @@ -84,15 +85,14 @@ const collectionTrans = {
queryTab: 'Data Query',
previewTab: 'Data Preview',
startTip: 'Start your data query',
exprPlaceHolder: 'Please enter your query by using advanced filter ->',
exprPlaceHolder: 'Please enter your data query, for example id > 0',

// alias dialog
aliasCreatePlaceholder: 'Alias name',

// rename dialog
newColNamePlaceholder: 'New Collection Name',
newNameInfo:
'Only numbers, letters, and underscores are allowed.',
newNameInfo: 'Only numbers, letters, and underscores are allowed.',
};

export default collectionTrans;
80 changes: 50 additions & 30 deletions client/src/pages/query/Query.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { FC, useEffect, useState, useRef, useMemo, useContext } from 'react';
import { TextField } from '@material-ui/core';
import { useTranslation } from 'react-i18next';

import { Parser } from '@json2csv/plainjs';
import { rootContext } from '../../context/Root';

import EmptyCard from '../../components/cards/EmptyCard';
import icons from '../../components/icons/Icons';
import CustomButton from '../../components/customButton/CustomButton';
Expand All @@ -14,13 +14,11 @@ import { CollectionHttp } from '../../http/Collection';
import { FieldHttp } from '../../http/Field';
import { usePaginationHook } from '../../hooks/Pagination';
// import { useTimeTravelHook } from '../../hooks/TimeTravel';

import CopyButton from '../../components/advancedSearch/CopyButton';
import DeleteTemplate from '../../components/customDialog/DeleteDialogTemplate';
import CustomToolBar from '../../components/grid/ToolBar';
// import { CustomDatePicker } from '../../components/customDatePicker/CustomDatePicker';
import { saveAs } from 'file-saver';
import { generateCsvData } from '../../utils/Format';
import { DataTypeStringEnum } from '../collections/Types';

const Query: FC<{
Expand All @@ -32,7 +30,6 @@ const Query: FC<{
const [queryResult, setQueryResult] = useState<any>();
const [selectedData, setSelectedData] = useState<any[]>([]);
const [primaryKey, setPrimaryKey] = useState<string>('');

const { setDialog, handleCloseDialog, openSnackBar } =
useContext(rootContext);
const VectorSearchIcon = icons.vectorSearch;
Expand All @@ -48,9 +45,6 @@ const Query: FC<{

const classes = getQueryStyles();

// const { timeTravel, setTimeTravel, timeTravelInfo, handleDateTimeChange } =
// useTimeTravelHook();

// Format result list
const queryResultMemo = useMemo(
() =>
Expand Down Expand Up @@ -88,14 +82,6 @@ const Query: FC<{
[queryResult, classes.vectorTableCell, classes.copyBtn, copyTrans.label]
);

const csvDataMemo = useMemo(() => {
const headers: string[] = fields?.map(i => i.name);
if (headers?.length && queryResult?.length) {
return generateCsvData(headers, queryResult);
}
return '';
}, [fields, queryResult]);

const {
pageSize,
handlePageSize,
Expand Down Expand Up @@ -142,14 +128,18 @@ const Query: FC<{

const handleFilterSubmit = (expression: string) => {
setExpression(expression);
setQueryResult(null);
handleQuery(expression);
};

const handleQuery = async () => {
const handleQuery = async (expr: string = '') => {
setTableLoading(true);
if (expr === '') {
handleFilterReset();
return;
}
try {
const res = await CollectionHttp.queryData(collectionName, {
expr: expression,
expr: expr,
output_fields: fields.map(i => i.name),
// travel_timestamp: timeTravelInfo.timestamp,
});
Expand Down Expand Up @@ -207,15 +197,22 @@ const Query: FC<{
{
type: 'iconBtn',
onClick: () => {
const csvData = new Blob([csvDataMemo.toString()], {
type: 'text/csv;charset=utf-8',
});
saveAs(csvData, 'query_result.csv');
try {
const opts = {};
const parser = new Parser(opts);
const csv = parser.parse(queryResult);
const csvData = new Blob([csv], {
type: 'text/csv;charset=utf-8',
});
saveAs(csvData, 'milvus_query_result.csv');
} catch (err) {
console.error(err);
}
},
label: collectionTrans('delete'),
label: '',
icon: 'download',
tooltip: collectionTrans('download'),
disabledTooltip: collectionTrans('downloadTooltip'),
tooltip: collectionTrans('downloadTooltip'),
disabledTooltip: collectionTrans('downloadDisabledTooltip'),
disabled: () => !queryResult?.length,
},
];
Expand All @@ -225,8 +222,27 @@ const Query: FC<{
<CustomToolBar toolbarConfigs={toolbarConfigs} />
<div className={classes.toolbar}>
<div className="left">
{/* <div className="expression"> */}
<div>{`${expression || collectionTrans('exprPlaceHolder')}`}</div>
<TextField
className="textarea"
InputProps={{
classes: {
root: 'textfield',
multiline: 'multiline',
},
}}
placeholder={collectionTrans('exprPlaceHolder')}
value={expression}
onChange={(e: React.ChangeEvent<{ value: unknown }>) => {
setExpression(e.target.value as string);
}}
onKeyDown={e => {
if (e.key === 'Enter') {
// Do code here
handleQuery(expression);
e.preventDefault();
}
}}
/>
<Filter
ref={filterRef}
title="Advanced Filter"
Expand All @@ -250,14 +266,18 @@ const Query: FC<{
/> */}
</div>
<div className="right">
<CustomButton className="btn" onClick={handleFilterReset}>
<CustomButton
className="btn"
onClick={handleFilterReset}
disabled={!expression}
>
<ResetIcon classes={{ root: 'icon' }} />
{btnTrans('reset')}
</CustomButton>
<CustomButton
variant="contained"
disabled={!expression}
onClick={() => handleQuery()}
onClick={() => handleQuery(expression)}
>
{btnTrans('query')}
</CustomButton>
Expand Down
12 changes: 11 additions & 1 deletion client/src/pages/query/Styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@ export const getQueryStyles = makeStyles((theme: Theme) => ({
padding: theme.spacing(0, 1.5),
backgroundColor: '#F9F9F9',
},
'& .textarea': {
width: '100%',
'& .MuiInput-underline:before': {
borderWidth: 1,
borderColor: '#F9F9F9',
},
'& .MuiInput-underline:after': {
borderWidth: 1,
},
},
},

'& .right': {
Expand All @@ -61,6 +71,6 @@ export const getQueryStyles = makeStyles((theme: Theme) => ({
width: '16px',
height: '16px',
position: 'relative',
top: '-3px'
top: '-3px',
},
}));
29 changes: 0 additions & 29 deletions client/src/utils/Format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,32 +225,3 @@ export const formatUtcToMilvus = (bigNumber: number) => {
const milvusTimeStamp = BigInt(bigNumber) << BigInt(18);
return milvusTimeStamp.toString();
};

/**
* Convert headers and rows to csv string.
* @param headers csv headers: string[]
* @param rows csv data rows: {[key in headers]: any}[]
* @returns csv string
*/
export const generateCsvData = (headers: string[], rows: any[]) => {
const rowsData = rows.reduce((prev, item: any[]) => {
headers.forEach((colName: any, idx: number) => {
const val = item[colName];
if (typeof val === 'string') {
prev += val;
} else if (typeof val === 'object') {
// Use double quote to ensure csv display correctly
prev += `"${JSON.stringify(val)}"`;
} else {
prev += `${val}`;
}
if (idx === headers.length - 1) {
prev += '\n';
} else {
prev += ',';
}
});
return prev;
}, '');
return headers.join(',') + '\n' + rowsData;
};
35 changes: 25 additions & 10 deletions client/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@
"@babel/plugin-syntax-jsx" "^7.18.6"
"@babel/types" "^7.19.0"

"@babel/runtime@^7.12.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.8", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.7", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.7":
"@babel/runtime@^7.12.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.8", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.7":
version "7.16.0"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.16.0.tgz#e27b977f2e2088ba24748bf99b5e1dece64e4f0b"
integrity sha512-Nht8L0O8YCktmsDV6FqFue7vQLRx3Hb0B37lS5y0jDRqRxlBG4wIJHnf9/bgSE2UyipKFA01YtS+npRdTWBUyw==
Expand Down Expand Up @@ -568,14 +568,19 @@
"@jridgewell/resolve-uri" "3.1.0"
"@jridgewell/sourcemap-codec" "1.4.14"

"@loadable/component@^5.15.0":
version "5.15.0"
resolved "https://registry.yarnpkg.com/@loadable/component/-/component-5.15.0.tgz#48b9524237be553f48b158f8c9152593f3f3fded"
integrity sha512-g63rQzypPOZi0BeGsK4ST2MYhsFR+i7bhL8k/McUoWDNMDuTTdUlQ2GACKxqh5sI/dNC/6nVoPrycMnSylnAgQ==
"@json2csv/formatters@^7.0.1":
version "7.0.1"
resolved "https://registry.yarnpkg.com/@json2csv/formatters/-/formatters-7.0.1.tgz#c025f0795f9bbab480de77e2248ab593987296b9"
integrity sha512-eCmYKIIoFDXUB0Fotet2RmcoFTtNLXLmSV7j6aEQH/D2GiO749Uan3ts03PtAhXpE11QghxBjS0toXom8VQNBw==

"@json2csv/plainjs@^7.0.1":
version "7.0.1"
resolved "https://registry.yarnpkg.com/@json2csv/plainjs/-/plainjs-7.0.1.tgz#361d849f04a2a5013c7880738f08b6bc193c24eb"
integrity sha512-UAdaZwahrUeYhMYYilJwDsRfE7wDRsmGMsszYH67j8FLD5gZitqG38RXpUgHEH0s6YjsY8iKYWeEQ19WILncFA==
dependencies:
"@babel/runtime" "^7.7.7"
hoist-non-react-statics "^3.3.1"
react-is "^16.12.0"
"@json2csv/formatters" "^7.0.1"
"@streamparser/json" "^0.0.15"
lodash.get "^4.4.2"

"@material-ui/core@4.11.4":
version "4.11.4"
Expand Down Expand Up @@ -715,6 +720,11 @@
resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.0.0.tgz#8863915676f837d9dad7b76f50cb500c1e9422e9"
integrity sha512-2pTGuibAXJswAPJjaKisthqS/NOK5ypG4LYT6tEAV0S/mxW0zOIvYvGK0V8w8+SHxAm6vRMSjqSalFXeBAqs+Q==

"@streamparser/json@^0.0.15":
version "0.0.15"
resolved "https://registry.yarnpkg.com/@streamparser/json/-/json-0.0.15.tgz#405fbe94877ce0cbd3cf650b4d9186a0ec6acd0a"
integrity sha512-6oikjkMTYAHGqKmcC9leE4+kY4Ch4eiTImXUN/N4d2bNGBYs0LJ/tfxmpvF5eExSU7iiPlV9jYlADqvj3NWA3Q==

"@svgr/babel-plugin-add-jsx-attribute@^5.4.0":
version "5.4.0"
resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-5.4.0.tgz#81ef61947bb268eb9d50523446f9c638fb355906"
Expand Down Expand Up @@ -2527,7 +2537,7 @@ highlight.js@^10.4.1, highlight.js@~10.7.0:
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531"
integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==

hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2:
hoist-non-react-statics@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
Expand Down Expand Up @@ -3011,6 +3021,11 @@ locate-path@^6.0.0:
dependencies:
p-locate "^5.0.0"

lodash.get@^4.4.2:
version "4.4.2"
resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==

lodash@^4.17.15:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
Expand Down Expand Up @@ -3391,7 +3406,7 @@ react-i18next@^12.0.0:
"@babel/runtime" "^7.14.5"
html-parse-stringify "^3.0.1"

react-is@^16.12.0, react-is@^16.7.0, react-is@^16.8.1:
react-is@^16.7.0, react-is@^16.8.1:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
Expand Down

0 comments on commit af3607e

Please sign in to comment.