@gingkoo/pandora-metabase 1.0.26 → 1.0.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/lib/cjs/common/SplitView/index.js +11 -12
  2. package/lib/cjs/components/dialog/custom-column/expression-editor.js +1 -2
  3. package/lib/cjs/components/dialog/custom-column/tokenizedI-input.js +1 -2
  4. package/lib/cjs/components/dialog/expression/index.js +11 -12
  5. package/lib/cjs/components/dialog/formula-list/index.js +53 -43
  6. package/lib/cjs/components/dialog/index.js +2 -2
  7. package/lib/cjs/components/dialog/select-column/index.js +4 -4
  8. package/lib/cjs/components/dialog/select-column-multiple/index.js +7 -7
  9. package/lib/cjs/components/dialog/select-join-column/index.js +4 -0
  10. package/lib/cjs/components/dialog/select-permission-table/index.js +2 -2
  11. package/lib/cjs/components/dialog/select-table/index.js +7 -7
  12. package/lib/cjs/components/icons.js +36 -36
  13. package/lib/cjs/components/metabase/index.js +41 -12
  14. package/lib/cjs/components/metabase/index.less +3 -0
  15. package/lib/cjs/components/modules/components/Wrapper.js +6 -6
  16. package/lib/cjs/components/modules/components/item-name.d.ts +7 -0
  17. package/lib/cjs/components/modules/components/item-name.js +34 -0
  18. package/lib/cjs/components/modules/components/meta-icon.js +6 -0
  19. package/lib/cjs/components/modules/custom-column.js +25 -25
  20. package/lib/cjs/components/modules/filter.js +2 -2
  21. package/lib/cjs/components/modules/join-data.js +206 -80
  22. package/lib/cjs/components/modules/permission-table.js +24 -10
  23. package/lib/cjs/components/modules/sort.js +17 -13
  24. package/lib/cjs/components/modules/summarize/group-by.js +90 -38
  25. package/lib/cjs/components/modules/summarize/select-index.js +84 -38
  26. package/lib/cjs/components/modules/table-data.js +14 -6
  27. package/lib/cjs/components/popup.js +1 -2
  28. package/lib/cjs/hooks/use-state.js +58 -65
  29. package/lib/cjs/index.js +1 -2
  30. package/lib/cjs/locale/en.js +5 -2
  31. package/lib/cjs/locale/zh.js +5 -2
  32. package/lib/cjs/utils/transformSql.d.ts +6 -0
  33. package/lib/cjs/utils/transformSql.js +968 -0
  34. package/lib/cjs/utils.d.ts +7 -1
  35. package/lib/cjs/utils.js +112 -15
  36. package/lib/es/common/SplitView/index.js +10 -10
  37. package/lib/es/components/dialog/expression/index.js +10 -10
  38. package/lib/es/components/dialog/formula-list/index.js +54 -44
  39. package/lib/es/components/dialog/select-column/index.js +4 -4
  40. package/lib/es/components/dialog/select-column-multiple/index.js +7 -7
  41. package/lib/es/components/dialog/select-join-column/index.js +4 -0
  42. package/lib/es/components/dialog/select-permission-table/index.js +2 -2
  43. package/lib/es/components/dialog/select-table/index.js +7 -7
  44. package/lib/es/components/icons.js +36 -36
  45. package/lib/es/components/metabase/index.js +42 -13
  46. package/lib/es/components/metabase/index.less +3 -0
  47. package/lib/es/components/modules/components/Wrapper.js +6 -6
  48. package/lib/es/components/modules/components/item-name.d.ts +7 -0
  49. package/lib/es/components/modules/components/item-name.js +28 -0
  50. package/lib/es/components/modules/components/meta-icon.js +6 -0
  51. package/lib/es/components/modules/custom-column.js +26 -26
  52. package/lib/es/components/modules/filter.js +2 -2
  53. package/lib/es/components/modules/join-data.js +207 -81
  54. package/lib/es/components/modules/permission-table.js +24 -10
  55. package/lib/es/components/modules/sort.js +18 -14
  56. package/lib/es/components/modules/summarize/group-by.js +92 -40
  57. package/lib/es/components/modules/summarize/select-index.js +86 -40
  58. package/lib/es/components/modules/table-data.js +14 -6
  59. package/lib/es/hooks/use-state.js +58 -65
  60. package/lib/es/locale/en.js +5 -2
  61. package/lib/es/locale/zh.js +5 -2
  62. package/lib/es/utils/transformSql.d.ts +6 -0
  63. package/lib/es/utils/transformSql.js +961 -0
  64. package/lib/es/utils.d.ts +7 -1
  65. package/lib/es/utils.js +102 -4
  66. package/package.json +1 -1
@@ -169,12 +169,12 @@ export var LeftJoinIcon = function LeftJoinIcon(_ref9) {
169
169
  })
170
170
  });
171
171
  };
172
- export var InnerJoinIcon = function InnerJoinIcon(_ref10) {
173
- var _ref10$width = _ref10.width,
174
- width = _ref10$width === void 0 ? 32 : _ref10$width,
175
- _ref10$height = _ref10.height,
176
- height = _ref10$height === void 0 ? 32 : _ref10$height,
177
- style = _ref10.style;
172
+ export var InnerJoinIcon = function InnerJoinIcon(_ref0) {
173
+ var _ref0$width = _ref0.width,
174
+ width = _ref0$width === void 0 ? 32 : _ref0$width,
175
+ _ref0$height = _ref0.height,
176
+ height = _ref0$height === void 0 ? 32 : _ref0$height,
177
+ style = _ref0.style;
178
178
  return _jsx("svg", {
179
179
  viewBox: '0 0 32 32',
180
180
  width: width,
@@ -188,11 +188,11 @@ export var InnerJoinIcon = function InnerJoinIcon(_ref10) {
188
188
  })
189
189
  });
190
190
  };
191
- export var UpArrowIcon = function UpArrowIcon(_ref11) {
192
- var _ref11$width = _ref11.width,
193
- width = _ref11$width === void 0 ? 16 : _ref11$width,
194
- _ref11$height = _ref11.height,
195
- height = _ref11$height === void 0 ? 17 : _ref11$height;
191
+ export var UpArrowIcon = function UpArrowIcon(_ref1) {
192
+ var _ref1$width = _ref1.width,
193
+ width = _ref1$width === void 0 ? 16 : _ref1$width,
194
+ _ref1$height = _ref1.height,
195
+ height = _ref1$height === void 0 ? 17 : _ref1$height;
196
196
  return _jsx("svg", {
197
197
  className: 'sort-arrow',
198
198
  viewBox: '0 0 32 34',
@@ -206,11 +206,11 @@ export var UpArrowIcon = function UpArrowIcon(_ref11) {
206
206
  })
207
207
  });
208
208
  };
209
- export var DownArrowIcon = function DownArrowIcon(_ref12) {
210
- var _ref12$width = _ref12.width,
211
- width = _ref12$width === void 0 ? 16 : _ref12$width,
212
- _ref12$height = _ref12.height,
213
- height = _ref12$height === void 0 ? 17 : _ref12$height;
209
+ export var DownArrowIcon = function DownArrowIcon(_ref10) {
210
+ var _ref10$width = _ref10.width,
211
+ width = _ref10$width === void 0 ? 16 : _ref10$width,
212
+ _ref10$height = _ref10.height,
213
+ height = _ref10$height === void 0 ? 17 : _ref10$height;
214
214
  return _jsx("svg", {
215
215
  className: 'sort-arrow',
216
216
  viewBox: '0 0 32 34',
@@ -224,11 +224,11 @@ export var DownArrowIcon = function DownArrowIcon(_ref12) {
224
224
  })
225
225
  });
226
226
  };
227
- export var CloseIcon = function CloseIcon(_ref13) {
228
- var _ref13$width = _ref13.width,
229
- width = _ref13$width === void 0 ? 16 : _ref13$width,
230
- _ref13$height = _ref13.height,
231
- height = _ref13$height === void 0 ? 16 : _ref13$height;
227
+ export var CloseIcon = function CloseIcon(_ref11) {
228
+ var _ref11$width = _ref11.width,
229
+ width = _ref11$width === void 0 ? 16 : _ref11$width,
230
+ _ref11$height = _ref11.height,
231
+ height = _ref11$height === void 0 ? 16 : _ref11$height;
232
232
  return _jsx("svg", {
233
233
  className: 'closeIcon',
234
234
  viewBox: '0 0 32 32',
@@ -242,11 +242,11 @@ export var CloseIcon = function CloseIcon(_ref13) {
242
242
  })
243
243
  });
244
244
  };
245
- export var AddIcon = function AddIcon(_ref14) {
246
- var _ref14$width = _ref14.width,
247
- width = _ref14$width === void 0 ? 16 : _ref14$width,
248
- _ref14$height = _ref14.height,
249
- height = _ref14$height === void 0 ? 16 : _ref14$height;
245
+ export var AddIcon = function AddIcon(_ref12) {
246
+ var _ref12$width = _ref12.width,
247
+ width = _ref12$width === void 0 ? 16 : _ref12$width,
248
+ _ref12$height = _ref12.height,
249
+ height = _ref12$height === void 0 ? 16 : _ref12$height;
250
250
  return _jsx("svg", {
251
251
  viewBox: '0 0 32 32',
252
252
  width: width,
@@ -259,11 +259,11 @@ export var AddIcon = function AddIcon(_ref14) {
259
259
  })
260
260
  });
261
261
  };
262
- export var TableIcon = function TableIcon(_ref15) {
263
- var _ref15$width = _ref15.width,
264
- width = _ref15$width === void 0 ? 18 : _ref15$width,
265
- _ref15$height = _ref15.height,
266
- height = _ref15$height === void 0 ? 18 : _ref15$height;
262
+ export var TableIcon = function TableIcon(_ref13) {
263
+ var _ref13$width = _ref13.width,
264
+ width = _ref13$width === void 0 ? 18 : _ref13$width,
265
+ _ref13$height = _ref13.height,
266
+ height = _ref13$height === void 0 ? 18 : _ref13$height;
267
267
  return _jsx("svg", {
268
268
  viewBox: '0 0 32 32',
269
269
  width: width,
@@ -276,11 +276,11 @@ export var TableIcon = function TableIcon(_ref15) {
276
276
  })
277
277
  });
278
278
  };
279
- export var SearchIcon = function SearchIcon(_ref16) {
280
- var _ref16$width = _ref16.width,
281
- width = _ref16$width === void 0 ? 16 : _ref16$width,
282
- _ref16$height = _ref16.height,
283
- height = _ref16$height === void 0 ? 16 : _ref16$height;
279
+ export var SearchIcon = function SearchIcon(_ref14) {
280
+ var _ref14$width = _ref14.width,
281
+ width = _ref14$width === void 0 ? 16 : _ref14$width,
282
+ _ref14$height = _ref14.height,
283
+ height = _ref14$height === void 0 ? 16 : _ref14$height;
284
284
  return _jsx("svg", {
285
285
  viewBox: '0 0 32 32',
286
286
  width: width,
@@ -7,7 +7,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
7
7
  import './index.less';
8
8
  import { useMemo, useState } from 'react';
9
9
  import cx from 'classnames';
10
- import { Button, Toast } from '@gingkoo/pandora';
10
+ import { Button, Modal, Toast } from '@gingkoo/pandora';
11
11
  // import { toJS } from 'mobx';
12
12
  import Styled from 'styled-components';
13
13
  import Union from '../modules/union';
@@ -46,11 +46,40 @@ var Metabase = function Metabase(props) {
46
46
  if (!visible) return null;
47
47
  return content;
48
48
  }, [store.popupData2]);
49
+ var onCheck = function onCheck() {
50
+ var doms = store.popupContainer.current.querySelectorAll('.isError');
51
+ if (doms.length) {
52
+ Modal.confirm({
53
+ title: __('metabase.prompt'),
54
+ content: __('metabase.validationFailed'),
55
+ onOk: function () {
56
+ var _onOk = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
57
+ return _regeneratorRuntime.wrap(function (_context) {
58
+ while (1) switch (_context.prev = _context.next) {
59
+ case 0:
60
+ _context.next = 1;
61
+ return onSave();
62
+ case 1:
63
+ case "end":
64
+ return _context.stop();
65
+ }
66
+ }, _callee);
67
+ }));
68
+ function onOk() {
69
+ return _onOk.apply(this, arguments);
70
+ }
71
+ return onOk;
72
+ }()
73
+ });
74
+ } else {
75
+ onSave();
76
+ }
77
+ };
49
78
  var onSave = /*#__PURE__*/function () {
50
- var _ref = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
79
+ var _ref = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
51
80
  var intercept, _metaList;
52
- return _regeneratorRuntime.wrap(function _callee$(_context) {
53
- while (1) switch (_context.prev = _context.next) {
81
+ return _regeneratorRuntime.wrap(function (_context2) {
82
+ while (1) switch (_context2.prev = _context2.next) {
54
83
  case 0:
55
84
  intercept = false; // 是否返回
56
85
  _metaList = splitByUnion(store.metaList);
@@ -63,21 +92,21 @@ var Metabase = function Metabase(props) {
63
92
  }
64
93
  });
65
94
  if (!(saveLoading || intercept)) {
66
- _context.next = 6;
95
+ _context2.next = 1;
67
96
  break;
68
97
  }
69
- return _context.abrupt("return", null);
70
- case 6:
98
+ return _context2.abrupt("return", null);
99
+ case 1:
71
100
  setSaveLoading(true);
72
- _context.next = 9;
101
+ _context2.next = 2;
73
102
  return onOk === null || onOk === void 0 ? void 0 : onOk(_metaList);
74
- case 9:
103
+ case 2:
75
104
  setSaveLoading(false);
76
- case 10:
105
+ case 3:
77
106
  case "end":
78
- return _context.stop();
107
+ return _context2.stop();
79
108
  }
80
- }, _callee);
109
+ }, _callee2);
81
110
  }));
82
111
  return function onSave() {
83
112
  return _ref.apply(this, arguments);
@@ -120,7 +149,7 @@ var Metabase = function Metabase(props) {
120
149
  className: ":Sqb-btn",
121
150
  loading: saveLoading,
122
151
  disabled: saveLoading,
123
- onClick: onSave,
152
+ onClick: onCheck,
124
153
  children: btnText || __('SqlQueryBuilder.visualize')
125
154
  }) : null, store.popupContainer.current && _jsx(Popup, {
126
155
  container: store.popupData.container || store.popupContainer.current,
@@ -259,6 +259,9 @@
259
259
  }
260
260
  }
261
261
  }
262
+ &.isError {
263
+ background-color: red;
264
+ }
262
265
  }
263
266
 
264
267
  .ant-input-number {
@@ -25,19 +25,19 @@ var Wrapper = function Wrapper(_ref) {
25
25
  function _animation() {
26
26
  _animation = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
27
27
  var _couterRef$current;
28
- return _regeneratorRuntime.wrap(function _callee$(_context) {
28
+ return _regeneratorRuntime.wrap(function (_context) {
29
29
  while (1) switch (_context.prev = _context.next) {
30
30
  case 0:
31
- _context.next = 2;
31
+ _context.next = 1;
32
32
  return sleep(10);
33
- case 2:
33
+ case 1:
34
34
  setOpacity(1);
35
35
  ((_couterRef$current = couterRef.current) === null || _couterRef$current === void 0 || (_couterRef$current = _couterRef$current.childNodes) === null || _couterRef$current === void 0 ? void 0 : _couterRef$current.length) && setMaxHeight(couterRef.current.childNodes[0].clientHeight + 16);
36
- _context.next = 6;
36
+ _context.next = 2;
37
37
  return sleep(500);
38
- case 6:
38
+ case 2:
39
39
  setMaxHeight('auto');
40
- case 7:
40
+ case 3:
41
41
  case "end":
42
42
  return _context.stop();
43
43
  }
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ interface HeaderProps {
3
+ children: React.ReactNode;
4
+ isError: boolean;
5
+ }
6
+ declare const ItemName: (props: HeaderProps) => import("react/jsx-runtime").JSX.Element;
7
+ export default ItemName;
@@ -0,0 +1,28 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Badge, Button, Tooltip } from '@gingkoo/pandora';
3
+ import { ExclamationCircleFill } from '@gingkoo/pandora-icons';
4
+ import { __ } from '../../../locale';
5
+ var ItemName = function ItemName(props) {
6
+ var children = props.children,
7
+ isError = props.isError;
8
+ return _jsx(Badge, {
9
+ offset: [-8, 0],
10
+ count: isError ? _jsx(Tooltip, {
11
+ title: __('metabase.verify'),
12
+ children: _jsx(Button, {
13
+ className: 'isError',
14
+ style: {
15
+ width: '100%',
16
+ height: '100%',
17
+ fontSize: 18
18
+ },
19
+ danger: true,
20
+ size: 'small',
21
+ icon: _jsx(ExclamationCircleFill, {}),
22
+ iconOnly: true
23
+ })
24
+ }) : '',
25
+ children: children
26
+ });
27
+ };
28
+ export default ItemName;
@@ -145,6 +145,9 @@ var findNextIcon = function findNextIcon(store, props) {
145
145
  } else {
146
146
  available = OrderType.slice(curLocation + 1, nextLocation);
147
147
  }
148
+ if (nextType === TypeEnum.joinData) {
149
+ available = [TypeEnum.joinData];
150
+ }
148
151
  }
149
152
  if (type === TypeEnum.joinData) {
150
153
  if (ExistAboveGroupBy && isLast) {
@@ -165,6 +168,9 @@ var findNextIcon = function findNextIcon(store, props) {
165
168
  if (nextType !== TypeEnum.joinData && meta.table2.name) {
166
169
  available.unshift(TypeEnum.joinData);
167
170
  }
171
+ if (nextType === TypeEnum.joinData) {
172
+ available = [TypeEnum.joinData];
173
+ }
168
174
  }
169
175
  if (type === TypeEnum.customColumn) {
170
176
  if (ExistAboveGroupBy && isLast) {
@@ -5,8 +5,9 @@ import _regeneratorRuntime from "@babel/runtime/regenerator";
5
5
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
6
6
  import { Modal2 } from '@gingkoo/pandora';
7
7
  import { Provider } from '../../hooks/use-provider';
8
+ import cx from 'classnames';
8
9
  import { __ } from '../../locale';
9
- import { findIndex } from '../../utils';
10
+ import { findIndex, isError } from '../../utils';
10
11
  import { sleep, flatArray } from '../../utils/helper';
11
12
  import { getHelper } from '../../utils';
12
13
  import { TypeEnum, SQL_COLUMN_TYPE } from '../../store/enum';
@@ -17,6 +18,7 @@ import { CustomColumnPopup } from '../dialog';
17
18
  import Wrapper from './components/Wrapper';
18
19
  import NextDom from './components/meta-icon';
19
20
  import Header from './components/header';
21
+ import ItemName from './components/item-name';
20
22
  import { useStore } from '../../hooks/use-provider';
21
23
  var CustomColumn = function CustomColumn(props) {
22
24
  var meta = props.meta,
@@ -69,14 +71,14 @@ var CustomColumn = function CustomColumn(props) {
69
71
  function _handleUpdate() {
70
72
  _handleUpdate = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee(e, i) {
71
73
  var node, newMeta, value, columns;
72
- return _regeneratorRuntime.wrap(function _callee$(_context) {
74
+ return _regeneratorRuntime.wrap(function (_context) {
73
75
  while (1) switch (_context.prev = _context.next) {
74
76
  case 0:
75
77
  node = e.currentTarget;
76
78
  closePopup();
77
- _context.next = 4;
79
+ _context.next = 1;
78
80
  return sleep(100);
79
- case 4:
81
+ case 1:
80
82
  newMeta = store.metaList[groupIndex].list.slice();
81
83
  value = customColumn[i];
82
84
  columns = getAvailableColumns();
@@ -98,7 +100,7 @@ var CustomColumn = function CustomColumn(props) {
98
100
  onClose: closePopup
99
101
  })
100
102
  });
101
- case 8:
103
+ case 2:
102
104
  case "end":
103
105
  return _context.stop();
104
106
  }
@@ -124,8 +126,8 @@ var CustomColumn = function CustomColumn(props) {
124
126
  tableId: prevGroupBy.alias,
125
127
  tableUuid: prevGroupBy.tableUuid || uuidv4('table'),
126
128
  alias: prevGroupBy.alias,
127
- datasourceId: mainTable.table.datasourceId,
128
- datasourceName: mainTable.table.datasourceName,
129
+ datasourceId: '',
130
+ datasourceName: '',
129
131
  columns: []
130
132
  };
131
133
  if (prevGroupBy !== null && prevGroupBy !== void 0 && (_prevGroupBy$group = prevGroupBy.group) !== null && _prevGroupBy$group !== void 0 && _prevGroupBy$group.length) {
@@ -157,15 +159,11 @@ var CustomColumn = function CustomColumn(props) {
157
159
  data = [_data];
158
160
  var joinData = prevList.filter(function (v) {
159
161
  return v.type === TypeEnum.joinData;
160
- })
161
- // @ts-ignore
162
- .filter(function (v) {
162
+ }).filter(function (v) {
163
163
  return v && v.table2.name;
164
164
  });
165
165
  if (joinData.length) {
166
- data = data.concat(
167
- // @ts-ignore
168
- joinData.map(function (v) {
166
+ data = data.concat(joinData.map(function (v) {
169
167
  return _objectSpread(_objectSpread({}, v.table2), {}, {
170
168
  alias: v.table2.alias,
171
169
  table: v.table2.name,
@@ -178,7 +176,6 @@ var CustomColumn = function CustomColumn(props) {
178
176
  }));
179
177
  }
180
178
  } else {
181
- // @ts-ignore
182
179
  data = store.metaList[groupIndex].list.slice(0, index).map(function (v) {
183
180
  if (v.type === TypeEnum.data) {
184
181
  return _objectSpread(_objectSpread({}, v.table), {}, {
@@ -299,20 +296,23 @@ var CustomColumn = function CustomColumn(props) {
299
296
  children: _jsxs("div", {
300
297
  className: "Sqb-NotebookCell gray-bg",
301
298
  children: [meta.customColumn.map(function (v, i) {
302
- return _jsxs("div", {
303
- className: "Sqb-TableName gray-name",
304
- onClick: function onClick(e) {
305
- return showSubQuery(e, i);
306
- },
307
- children: [v.name, _jsx("span", {
308
- style: {
309
- fontSize: 0
310
- },
299
+ return _jsx(ItemName, {
300
+ isError: isError(v.formulaList, getColumns()),
301
+ children: _jsxs("div", {
302
+ className: cx("Sqb-TableName gray-name"),
311
303
  onClick: function onClick(e) {
312
- return handleDel(e, i);
304
+ return showSubQuery(e, i);
313
305
  },
314
- children: _jsx(CloseIcon, {})
315
- })]
306
+ children: [v.name, _jsx("span", {
307
+ style: {
308
+ fontSize: 0
309
+ },
310
+ onClick: function onClick(e) {
311
+ return handleDel(e, i);
312
+ },
313
+ children: _jsx(CloseIcon, {})
314
+ })]
315
+ })
316
316
  }, i);
317
317
  }), _jsx("div", {
318
318
  className: "Sqb-TableName gray-name",
@@ -40,8 +40,8 @@ var Filter = function Filter(props) {
40
40
  id: prevGroupBy.alias,
41
41
  tableUuid: prevGroupBy.tableUuid,
42
42
  // alias: (prevGroupBy as MetaSummarize).alias,
43
- datasourceId: mainTable.table.datasourceId,
44
- datasourceName: mainTable.table.datasourceName,
43
+ // datasourceId: mainTable.table.datasourceId,
44
+ // datasourceName: mainTable.table.datasourceName,
45
45
  columns: []
46
46
  };
47
47
  if (prevGroupBy !== null && prevGroupBy !== void 0 && (_prevGroupBy$group = prevGroupBy.group) !== null && _prevGroupBy$group !== void 0 && _prevGroupBy$group.length) {