Browse Source

add query

czhen 3 years ago
parent
commit
2b9aed5868

+ 6 - 0
client/src/http/BaseModel.ts

@@ -84,4 +84,10 @@ export default class BaseModel {
     const res = await http.post(path, data);
     return res.data.data;
   }
+
+  static async query(options: updateParamsType) {
+    const { path, data } = options;
+    const res = await http.post(path, data);
+    return res.data.data;
+  }
 }

+ 8 - 0
client/src/http/Collection.ts

@@ -2,6 +2,7 @@ import { ChildrenStatusType } from '../components/status/Types';
 import { CollectionView, InsertDataParam } from '../pages/collections/Types';
 import { Field } from '../pages/schema/Types';
 import { VectorSearchParam } from '../pages/seach/Types';
+import { QueryParam } from '../pages/query/Types';
 import { IndexState, ShowCollectionsType } from '../types/Milvus';
 import { formatNumber } from '../utils/Common';
 import BaseModel from './BaseModel';
@@ -98,6 +99,13 @@ export class CollectionHttp extends BaseModel implements CollectionView {
     });
   }
 
+  static queryData(collectionName: string, params: QueryParam) {
+    return super.query({
+      path: `${this.COLLECTIONS_URL}/${collectionName}/query`,
+      data: params,
+    });
+  }
+
   get _autoId() {
     return this.autoID;
   }

+ 1 - 0
client/src/i18n/cn/button.ts

@@ -16,6 +16,7 @@ const btnTrans = {
   previous: 'Previous',
   done: 'Done',
   vectorSearch: 'Vector search',
+  query: 'Query',
 };
 
 export default btnTrans;

+ 2 - 0
client/src/i18n/cn/collection.ts

@@ -58,6 +58,8 @@ const collectionTrans = {
   // collection tabs
   partitionTab: 'Partitions',
   schemaTab: 'Schema',
+  queryTab: 'Data Query',
+  startTip: 'Start your data query',
 };
 
 export default collectionTrans;

+ 1 - 0
client/src/i18n/en/button.ts

@@ -16,6 +16,7 @@ const btnTrans = {
   previous: 'Previous',
   done: 'Done',
   vectorSearch: 'Vector search',
+  query: 'Query',
 };
 
 export default btnTrans;

+ 2 - 0
client/src/i18n/en/collection.ts

@@ -58,6 +58,8 @@ const collectionTrans = {
   // collection tabs
   partitionTab: 'Partitions',
   schemaTab: 'Schema',
+  queryTab: 'Data Query',
+  startTip: 'Start your data query'
 };
 
 export default collectionTrans;

+ 5 - 0
client/src/pages/collections/Collection.tsx

@@ -8,6 +8,7 @@ import { useHistory, useLocation, useParams } from 'react-router-dom';
 import { useMemo } from 'react';
 import { parseLocationSearch } from '../../utils/Format';
 import Schema from '../schema/Schema';
+import Query from '../query/Query';
 
 enum TAB_EMUM {
   'schema',
@@ -47,6 +48,10 @@ const Collection = () => {
       label: collectionTrans('partitionTab'),
       component: <Partitions collectionName={collectionName} />,
     },
+    {
+      label: collectionTrans('queryTab'),
+      component: <Query collectionName={collectionName} />,
+    },
   ];
 
   return (

+ 178 - 0
client/src/pages/query/Query.tsx

@@ -0,0 +1,178 @@
+import {
+  FC,
+  useCallback,
+  useContext,
+  useEffect,
+  useState,
+  useRef,
+} from 'react';
+import { useTranslation } from 'react-i18next';
+
+import EmptyCard from '../../components/cards/EmptyCard';
+import icons from '../../components/icons/Icons';
+import CustomButton from '../../components/customButton/CustomButton';
+import MilvusGrid from '../../components/grid/Grid';
+import { getQueryStyles } from './Styles';
+import CustomToolBar from '../../components/grid/ToolBar';
+import { ColDefinitionsType, ToolBarConfig } from '../../components/grid/Types';
+import Filter from '../../components/advancedSearch';
+import { CollectionHttp } from '../../http/Collection';
+import { FieldHttp } from '../../http/Field';
+import { usePaginationHook } from '../../hooks/Pagination';
+
+const Query: FC<{
+  collectionName: string;
+}> = ({ collectionName }) => {
+  const [fields, setFields] = useState<any[]>([]);
+  const [expression, setExpression] = useState('');
+  const [tableLoading, setTableLoading] = useState<any>();
+  const [queryResult, setQueryResult] = useState<any>();
+
+  const VectorSearchIcon = icons.vectorSearch;
+  const ResetIcon = icons.refresh;
+
+  const { t: searchTrans } = useTranslation('search');
+  const { t: collectionTrans } = useTranslation('collection');
+  const { t: btnTrans } = useTranslation('btn');
+  const classes = getQueryStyles();
+
+  const {
+    pageSize,
+    handlePageSize,
+    currentPage,
+    handleCurrentPage,
+    total,
+    data: result,
+    order,
+    orderBy,
+    handleGridSort,
+  } = usePaginationHook(queryResult || []);
+  const handlePageChange = (e: any, page: number) => {
+    handleCurrentPage(page);
+  };
+
+  const getFields = async (collectionName: string) => {
+    const schemaList = await FieldHttp.getFields(collectionName);
+    const nameList = schemaList.map(i => ({
+      name: i.name,
+      type: i.data_type.includes('Int') ? 'int' : 'float',
+    }));
+    console.log(schemaList);
+    setFields(nameList);
+  };
+
+  useEffect(() => {
+    collectionName && getFields(collectionName);
+  }, [collectionName]);
+
+  const filterRef = useRef();
+  const resetFilter = () => {
+    const currentFilter: any = filterRef.current;
+    currentFilter?.getReset();
+    setExpression('');
+    setTableLoading(null);
+    setQueryResult(null);
+  };
+
+  const handleFilterSubmit = (expression: string) => {
+    setExpression(expression);
+  };
+  const handleQuery = async () => {
+    setTableLoading(true);
+    try {
+      const res = await CollectionHttp.queryData(collectionName, {
+        expr: expression,
+        output_fields: fields.map(i => i.name),
+      });
+      setTableLoading(false);
+      console.log(res);
+      const result = res.data;
+      // const result = transferSearchResult(res.results);
+      setQueryResult(result);
+    } catch (err) {
+      setTableLoading(false);
+    }
+  };
+
+  return (
+    <>
+      <div className={classes.toolbar}>
+        <div className="left">
+          <div>{`${
+            expression || 'Please enter your query or use advanced filter ->'
+          }`}</div>
+          <Filter
+            ref={filterRef}
+            title="Advanced Filter"
+            fields={fields}
+            filterDisabled={false}
+            onSubmit={handleFilterSubmit}
+            showTitle={false}
+            showTooltip={false}
+          />
+        </div>
+        <div className="right">
+          <CustomButton className="btn" onClick={resetFilter}>
+            <ResetIcon classes={{ root: 'icon' }} />
+            {btnTrans('reset')}
+          </CustomButton>
+          <CustomButton
+            variant="contained"
+            disabled={!expression}
+            onClick={() => handleQuery()}
+          >
+            {btnTrans('query')}
+          </CustomButton>
+        </div>
+      </div>
+      {tableLoading || queryResult ? (
+        <MilvusGrid
+          toolbarConfigs={[]}
+          colDefinitions={fields.map(i => ({
+            id: i.name,
+            align: 'left',
+            disablePadding: false,
+            label: i.name,
+          }))}
+          // rows={queryResult || []}
+          // rowCount={queryResult?.length || 0}
+          primaryKey={fields.find(i => i.is_primary_key)?.name}
+          // page={1}
+          // onChangePage={() => {}}
+          // rowsPerPage={1000}
+          // setRowsPerPage={() => {}}
+          openCheckBox={false}
+          // isLoading={tableLoading}
+          isLoading={!!tableLoading}
+          // orderBy={fields.find(i => i.is_primary_key)?.name}
+          // order={''}
+          // handleSort={() => {}}
+          rows={result}
+          rowCount={total}
+          // primaryKey="rank"
+          page={currentPage}
+          onChangePage={handlePageChange}
+          rowsPerPage={pageSize}
+          setRowsPerPage={handlePageSize}
+          // openCheckBox={false}
+          // isLoading={tableLoading}
+          orderBy={orderBy}
+          order={order}
+          handleSort={handleGridSort}
+        />
+      ) : (
+        <EmptyCard
+          wrapperClass={`page-empty-card ${classes.emptyCard}`}
+          icon={<VectorSearchIcon />}
+          text={
+            queryResult !== null
+              ? searchTrans('empty')
+              : collectionTrans('startTip')
+          }
+        />
+      )}
+    </>
+  );
+};
+
+export default Query;

+ 34 - 0
client/src/pages/query/Styles.ts

@@ -0,0 +1,34 @@
+import { makeStyles, Theme } from '@material-ui/core';
+
+export const getQueryStyles = makeStyles((theme: Theme) => ({
+  root: {},
+  emptyCard: {
+    height: '100%',
+  },
+  toolbar: {
+    display: 'flex',
+    justifyContent: 'space-between',
+    alignItems: 'center',
+    backgroundColor: 'white',
+    padding: theme.spacing(1, 2),
+    gap: theme.spacing(2),
+    borderRadius: theme.spacing(0.5, 0.5, 0, 0),
+
+    '& .left': {
+      display: 'flex',
+      justifyContent: 'space-between',
+      alignItems: 'center',
+      width: 'calc(100% - 206px)',
+      padding: theme.spacing(0, 0, 0, 2),
+      fontSize: theme.spacing(2),
+      backgroundColor: '#F9F9F9',
+    },
+
+    '& .right': {
+      display: 'flex',
+      justifyContent: 'space-between',
+      alignItems: 'center',
+      gap: theme.spacing(2),
+    },
+  },
+}));

+ 5 - 0
client/src/pages/query/Types.ts

@@ -0,0 +1,5 @@
+export interface QueryParam {
+  expr: string;
+  partitions_names?: string[];
+  output_fields?: string[];
+}