Query.ts 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. import { useState, useRef, useEffect } from 'react';
  2. import {
  3. DataTypeStringEnum,
  4. DYNAMIC_FIELD,
  5. LOAD_STATE,
  6. MIN_INT64,
  7. } from '@/consts';
  8. import { Collection } from '@/http';
  9. export const useQuery = (params: {
  10. onQueryStart: Function;
  11. onQueryEnd?: Function;
  12. onQueryFinally?: Function;
  13. collectionName: string;
  14. }) => {
  15. // state
  16. const [collection, setCollection] = useState<any>({
  17. fields: [],
  18. primaryKey: { value: '', type: DataTypeStringEnum.Int64 },
  19. loaded: false,
  20. data: null,
  21. });
  22. const [consistencyLevel, setConsistencyLevel] = useState<string>('Bounded');
  23. const [currentPage, setCurrentPage] = useState<number>(0);
  24. const [pageSize, setPageSize] = useState<number>(0);
  25. const [total, setTotal] = useState<number>(0);
  26. const [expr, setExpr] = useState<string>('');
  27. const [queryResult, setQueryResult] = useState<any>({ data: [], latency: 0 });
  28. const lastQuery = useRef<any>();
  29. // build local cache for pk ids
  30. const pageCache = useRef(new Map());
  31. // get next/previous expression
  32. const getPageExpr = (page: number) => {
  33. const cache = pageCache.current.get(
  34. page > currentPage ? currentPage : page
  35. );
  36. const primaryKey = collection.primaryKey;
  37. const formatPKValue = (pkId: string | number) =>
  38. primaryKey.type === DataTypeStringEnum.VarChar ? `'${pkId}'` : pkId;
  39. // If cache does not exist, return expression based on primaryKey type
  40. let condition = '';
  41. if (!cache) {
  42. const defaultValue =
  43. primaryKey.type === DataTypeStringEnum.VarChar ? "''" : `${MIN_INT64}`;
  44. condition = `${primaryKey.value} > ${defaultValue}`;
  45. } else {
  46. const { firstPKId, lastPKId } = cache;
  47. const lastPKValue = formatPKValue(lastPKId);
  48. const firstPKValue = formatPKValue(firstPKId);
  49. condition =
  50. page > currentPage
  51. ? `(${primaryKey.value} > ${lastPKValue})`
  52. : `((${primaryKey.value} <= ${lastPKValue}) && (${primaryKey.value} >= ${firstPKValue}))`;
  53. }
  54. return expr ? `${expr} && ${condition}` : condition;
  55. };
  56. // query function
  57. const query = async (
  58. page: number = currentPage,
  59. consistency_level = consistencyLevel
  60. ) => {
  61. const _expr = getPageExpr(page);
  62. // console.log('query expr', _expr);
  63. params.onQueryStart(_expr);
  64. try {
  65. const queryParams = {
  66. expr: _expr,
  67. output_fields: collection.fields.map((i: any) => i.name),
  68. limit: pageSize || 10,
  69. consistency_level,
  70. // travel_timestamp: timeTravelInfo.timestamp,
  71. };
  72. // cache last query
  73. lastQuery.current = queryParams;
  74. // execute query
  75. const res = await Collection.queryData(
  76. params.collectionName,
  77. queryParams
  78. );
  79. // get last item of the data
  80. const lastItem = res.data[res.data.length - 1];
  81. // get first item of the data
  82. const firstItem = res.data[0];
  83. // get last pk id
  84. const lastPKId: string | number =
  85. lastItem && lastItem[collection.primaryKey.value];
  86. // get first pk id
  87. const firstPKId: string | number =
  88. firstItem && firstItem[collection.primaryKey.value];
  89. // store pk id in the cache with the page number
  90. if (lastItem) {
  91. pageCache.current.set(page, {
  92. firstPKId,
  93. lastPKId,
  94. });
  95. }
  96. // console.log('query result page', page, pageCache.current);
  97. // update query result
  98. setQueryResult(res);
  99. params.onQueryEnd?.(res);
  100. } catch (e: any) {
  101. reset();
  102. } finally {
  103. params.onQueryFinally?.();
  104. }
  105. };
  106. // get collection info
  107. const prepare = async (collectionName: string) => {
  108. const collection = await Collection.getCollectionInfo(collectionName);
  109. const schemaList = collection.fields;
  110. const nameList = schemaList.map(v => ({
  111. name: v.name,
  112. type: v.fieldType,
  113. }));
  114. // if the dynamic field is enabled, we add $meta column in the grid
  115. if (collection.enableDynamicField) {
  116. nameList.push({
  117. name: DYNAMIC_FIELD,
  118. type: DataTypeStringEnum.JSON,
  119. });
  120. }
  121. const primaryKey = schemaList.find(v => v.isPrimaryKey === true)!;
  122. setConsistencyLevel(collection.consistency_level);
  123. setCollection({
  124. fields: nameList as any[],
  125. primaryKey: { value: primaryKey['name'], type: primaryKey['fieldType'] },
  126. loaded: collection.state === LOAD_STATE.LoadStateLoaded,
  127. data: collection,
  128. });
  129. };
  130. const count = async (consistency_level = consistencyLevel) => {
  131. const count = 'count(*)';
  132. const res = await Collection.queryData(params.collectionName, {
  133. expr: expr,
  134. output_fields: [count],
  135. consistency_level,
  136. // travel_timestamp: timeTravelInfo.timestamp,
  137. });
  138. setTotal(Number(res.data[0][count]));
  139. };
  140. // reset
  141. const reset = () => {
  142. setCurrentPage(0);
  143. setQueryResult({ data: [] });
  144. pageCache.current.clear();
  145. };
  146. // Get fields at first or collection name changed.
  147. useEffect(() => {
  148. params.collectionName && prepare(params.collectionName);
  149. }, [params.collectionName]);
  150. // query if expr is changed
  151. useEffect(() => {
  152. if (!collection.primaryKey.value || !collection.loaded) {
  153. // console.info('[skip running query]: no key yet');
  154. return;
  155. } // reset
  156. reset();
  157. // get count;
  158. count();
  159. // do the query
  160. query();
  161. }, [expr]);
  162. // query if collection is changed
  163. useEffect(() => {
  164. if (!collection.primaryKey.value || !collection.loaded) {
  165. // console.info('[skip running query]: no key yet');
  166. return;
  167. }
  168. // reset
  169. reset();
  170. // get count;
  171. count();
  172. // do the query
  173. query();
  174. }, [collection]);
  175. // query if page size is changed
  176. useEffect(() => {
  177. if (!collection.primaryKey.value || !collection.loaded) {
  178. // console.info('[skip running query]: no key yet');
  179. return;
  180. }
  181. // reset
  182. reset();
  183. // do the query
  184. query();
  185. }, [pageSize]);
  186. return {
  187. // collection info(primaryKey, consistency level, fields)
  188. collection,
  189. // total query count
  190. total,
  191. // page size
  192. pageSize,
  193. // update page size
  194. setPageSize,
  195. // consistency level
  196. consistencyLevel,
  197. // update consistency level
  198. setConsistencyLevel,
  199. // current page
  200. currentPage,
  201. // query current data page
  202. setCurrentPage,
  203. // expression to query
  204. expr,
  205. // expression updater
  206. setExpr,
  207. // query result
  208. queryResult,
  209. // query
  210. query,
  211. // reset
  212. reset,
  213. // count
  214. count,
  215. // get expression
  216. getPageExpr,
  217. };
  218. };