@tanstack/table-core 9.0.0-beta.28 → 9.0.0-beta.30

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 (30) hide show
  1. package/dist/features/column-filtering/columnFilteringFeature.utils.cjs +1 -1
  2. package/dist/features/column-filtering/columnFilteringFeature.utils.cjs.map +1 -1
  3. package/dist/features/column-filtering/columnFilteringFeature.utils.js +1 -1
  4. package/dist/features/column-filtering/columnFilteringFeature.utils.js.map +1 -1
  5. package/dist/features/global-filtering/globalFilteringFeature.utils.d.cts +1 -0
  6. package/dist/features/global-filtering/globalFilteringFeature.utils.d.ts +1 -0
  7. package/dist/features/row-sorting/createSortedRowModel.cjs +41 -34
  8. package/dist/features/row-sorting/createSortedRowModel.cjs.map +1 -1
  9. package/dist/features/row-sorting/createSortedRowModel.js +42 -35
  10. package/dist/features/row-sorting/createSortedRowModel.js.map +1 -1
  11. package/dist/fns/aggregationFns.cjs +21 -19
  12. package/dist/fns/aggregationFns.cjs.map +1 -1
  13. package/dist/fns/aggregationFns.js +21 -19
  14. package/dist/fns/aggregationFns.js.map +1 -1
  15. package/dist/fns/filterFns.cjs +59 -14
  16. package/dist/fns/filterFns.cjs.map +1 -1
  17. package/dist/fns/filterFns.d.cts +11 -4
  18. package/dist/fns/filterFns.d.ts +11 -4
  19. package/dist/fns/filterFns.js +59 -14
  20. package/dist/fns/filterFns.js.map +1 -1
  21. package/dist/fns/sortFns.cjs +77 -28
  22. package/dist/fns/sortFns.cjs.map +1 -1
  23. package/dist/fns/sortFns.js +77 -28
  24. package/dist/fns/sortFns.js.map +1 -1
  25. package/package.json +1 -1
  26. package/src/features/column-filtering/columnFilteringFeature.utils.ts +4 -4
  27. package/src/features/row-sorting/createSortedRowModel.ts +65 -55
  28. package/src/fns/aggregationFns.ts +19 -19
  29. package/src/fns/filterFns.ts +96 -32
  30. package/src/fns/sortFns.ts +158 -46
@@ -59,14 +59,14 @@ export function column_getAutoFilterFn<
59
59
  return filterFns?.equals
60
60
  }
61
61
 
62
- if (value !== null && typeof value === 'object') {
63
- return filterFns?.equals
64
- }
65
-
66
62
  if (Array.isArray(value)) {
67
63
  return filterFns?.arrIncludes
68
64
  }
69
65
 
66
+ if (value !== null && typeof value === 'object') {
67
+ return filterFns?.equals
68
+ }
69
+
70
70
  return filterFns?.weakEquals
71
71
  }
72
72
 
@@ -1,4 +1,4 @@
1
- import { makeObjectMap, tableMemo } from '../../utils'
1
+ import { tableMemo } from '../../utils'
2
2
  import { table_autoResetPageIndex } from '../row-pagination/rowPaginationFeature.utils'
3
3
  import { column_getCanSort, column_getSortFn } from './rowSortingFeature.utils'
4
4
  import type { Column_Internal } from '../../types/Column'
@@ -51,81 +51,91 @@ function _createSortedRowModel<
51
51
  const sortedFlatRows: Array<Row<TFeatures, TData>> = []
52
52
 
53
53
  // Filter out sortings that correspond to non existing columns
54
- const availableSorting = sorting.filter((sort) =>
55
- column_getCanSort(
56
- table.getColumn(sort.id) as Column_Internal<TFeatures, TData>,
57
- ),
58
- )
54
+ const availableSorting = sorting.filter((sort) => {
55
+ const column = table.getColumn(sort.id)
56
+ return column ? column_getCanSort(column) : false
57
+ })
59
58
 
60
- const columnInfoById = makeObjectMap<{
59
+ const resolvedSorting: Array<{
60
+ id: string
61
+ desc?: boolean
61
62
  sortUndefined?: false | -1 | 1 | 'first' | 'last'
62
63
  invertSorting?: boolean
63
64
  sortFn: SortFn<TFeatures, TData>
64
- }>()
65
+ }> = []
65
66
 
66
- availableSorting.forEach((sortEntry) => {
67
+ for (let i = 0; i < availableSorting.length; i++) {
68
+ const sortEntry = availableSorting[i]!
67
69
  const column: Column_Internal<TFeatures, TData> | undefined =
68
70
  table.getColumn(sortEntry.id)
69
- if (!column) return
71
+ if (!column) {
72
+ continue
73
+ }
70
74
 
71
- columnInfoById[sortEntry.id] = {
75
+ resolvedSorting.push({
76
+ id: sortEntry.id,
77
+ desc: sortEntry.desc,
72
78
  sortUndefined: column.columnDef.sortUndefined,
73
79
  invertSorting: column.columnDef.invertSorting,
74
80
  sortFn: column_getSortFn(column),
75
- }
76
- })
81
+ })
82
+ }
77
83
 
78
- const sortData = (rows: Array<Row<TFeatures, TData>>) => {
79
- const sortedData = rows.slice()
84
+ const compareRows = (
85
+ rowA: Row<TFeatures, TData>,
86
+ rowB: Row<TFeatures, TData>,
87
+ ) => {
88
+ for (let i = 0; i < resolvedSorting.length; i++) {
89
+ const sortEntry = resolvedSorting[i]!
90
+ const sortUndefined = sortEntry.sortUndefined
91
+ const isDesc = sortEntry.desc
92
+
93
+ let sortInt = 0
80
94
 
81
- sortedData.sort((rowA, rowB) => {
82
- for (let i = 0; i < availableSorting.length; i++) {
83
- const sortEntry = availableSorting[i]!
84
- const columnInfo = columnInfoById[sortEntry.id]!
85
- const sortUndefined = columnInfo.sortUndefined
86
- const isDesc = sortEntry.desc
87
-
88
- let sortInt = 0
89
-
90
- // All sorting ints should always return in ascending order
91
- if (sortUndefined) {
92
- const aValue = rowA.getValue(sortEntry.id)
93
- const bValue = rowB.getValue(sortEntry.id)
94
-
95
- const aUndefined = aValue === undefined
96
- const bUndefined = bValue === undefined
97
-
98
- if (aUndefined || bUndefined) {
99
- if (sortUndefined === 'first') return aUndefined ? -1 : 1
100
- if (sortUndefined === 'last') return aUndefined ? 1 : -1
101
- sortInt =
102
- aUndefined && bUndefined
103
- ? 0
104
- : aUndefined
105
- ? sortUndefined
106
- : -sortUndefined
107
- }
95
+ // All sorting ints should always return in ascending order
96
+ if (sortUndefined) {
97
+ const aValue = rowA.getValue(sortEntry.id)
98
+ const bValue = rowB.getValue(sortEntry.id)
99
+
100
+ const aUndefined = aValue === undefined
101
+ const bUndefined = bValue === undefined
102
+
103
+ if (aUndefined && bUndefined) {
104
+ continue
108
105
  }
109
106
 
110
- if (sortInt === 0) {
111
- sortInt = columnInfo.sortFn(rowA, rowB, sortEntry.id)
107
+ if (aUndefined || bUndefined) {
108
+ if (sortUndefined === 'first') return aUndefined ? -1 : 1
109
+ if (sortUndefined === 'last') return aUndefined ? 1 : -1
110
+ sortInt = aUndefined ? sortUndefined : -sortUndefined
112
111
  }
112
+ }
113
113
 
114
- // If sorting is non-zero, take care of desc and inversion
115
- if (sortInt !== 0) {
116
- if (isDesc) {
117
- sortInt *= -1
118
- }
114
+ if (sortInt === 0) {
115
+ sortInt = sortEntry.sortFn(rowA, rowB, sortEntry.id)
116
+ }
119
117
 
120
- if (columnInfo.invertSorting) {
121
- sortInt *= -1
122
- }
118
+ // If sorting is non-zero, take care of desc and inversion
119
+ if (sortInt !== 0) {
120
+ if (isDesc) {
121
+ sortInt *= -1
122
+ }
123
123
 
124
- return sortInt
124
+ if (sortEntry.invertSorting) {
125
+ sortInt *= -1
125
126
  }
127
+
128
+ return sortInt
126
129
  }
127
- return rowA.index - rowB.index
128
- })
130
+ }
131
+
132
+ return rowA.index - rowB.index
133
+ }
134
+
135
+ const sortData = (rows: Array<Row<TFeatures, TData>>) => {
136
+ const sortedData = rows.slice()
137
+
138
+ sortedData.sort(compareRows)
129
139
 
130
140
  // If there are sub-rows, sort them. Clone only rows that need mutation
131
141
  // (i.e. have subRows) so we don't corrupt the source row model.
@@ -18,10 +18,12 @@ export function aggregationFn_sum<
18
18
  ) {
19
19
  // It's faster to just add the aggregations together instead of
20
20
  // process leaf nodes individually
21
- return childRows.reduce((sumValue, next) => {
22
- const nextValue = next.getValue(columnId)
23
- return sumValue + (typeof nextValue === 'number' ? nextValue : 0)
24
- }, 0)
21
+ let sumValue = 0
22
+ for (let i = 0; i < childRows.length; i++) {
23
+ const nextValue = childRows[i]!.getValue(columnId)
24
+ sumValue += typeof nextValue === 'number' ? nextValue : 0
25
+ }
26
+ return sumValue
25
27
  }
26
28
 
27
29
  /**
@@ -40,17 +42,16 @@ export function aggregationFn_min<
40
42
  ) {
41
43
  let minValue: number | undefined
42
44
 
43
- childRows.forEach((row) => {
44
- const value = row.getValue(columnId)
45
+ for (let i = 0; i < childRows.length; i++) {
46
+ const value = childRows[i]!.getValue(columnId)
45
47
 
46
48
  if (
47
- value != null &&
48
49
  typeof value === 'number' &&
49
50
  (minValue === undefined || value < minValue)
50
51
  ) {
51
52
  minValue = value
52
53
  }
53
- })
54
+ }
54
55
 
55
56
  return minValue
56
57
  }
@@ -71,16 +72,15 @@ export function aggregationFn_max<
71
72
  ) {
72
73
  let maxValue: number | undefined
73
74
 
74
- childRows.forEach((row) => {
75
- const value = row.getValue(columnId)
75
+ for (let i = 0; i < childRows.length; i++) {
76
+ const value = childRows[i]!.getValue(columnId)
76
77
  if (
77
- value != null &&
78
78
  typeof value === 'number' &&
79
79
  (maxValue === undefined || value > maxValue)
80
80
  ) {
81
81
  maxValue = value
82
82
  }
83
- })
83
+ }
84
84
 
85
85
  return maxValue
86
86
  }
@@ -102,9 +102,9 @@ export function aggregationFn_extent<
102
102
  let minValue: number | undefined
103
103
  let maxValue: number | undefined
104
104
 
105
- childRows.forEach((row) => {
106
- const value = row.getValue(columnId)
107
- if (value != null && typeof value === 'number') {
105
+ for (let i = 0; i < childRows.length; i++) {
106
+ const value = childRows[i]!.getValue(columnId)
107
+ if (typeof value === 'number') {
108
108
  if (minValue === undefined) {
109
109
  minValue = maxValue = value
110
110
  } else {
@@ -112,7 +112,7 @@ export function aggregationFn_extent<
112
112
  if (maxValue! < value) maxValue = value
113
113
  }
114
114
  }
115
- })
115
+ }
116
116
 
117
117
  return [minValue, maxValue]
118
118
  }
@@ -130,8 +130,8 @@ export function aggregationFn_mean<
130
130
  let count = 0
131
131
  let sumValue = 0
132
132
 
133
- leafRows.forEach((row) => {
134
- const value = row.getValue(columnId)
133
+ for (let i = 0; i < leafRows.length; i++) {
134
+ const value = leafRows[i]!.getValue(columnId)
135
135
  if (value != null && typeof value === 'number') {
136
136
  ++count
137
137
  sumValue += value
@@ -142,7 +142,7 @@ export function aggregationFn_mean<
142
142
  sumValue += numValue
143
143
  }
144
144
  }
145
- })
145
+ }
146
146
 
147
147
  if (count) return sumValue / count
148
148
 
@@ -54,7 +54,10 @@ export const filterFn_includesStringSensitive = Object.assign(
54
54
  row.getValue(columnId)?.toString().includes(String(filterValue)),
55
55
  )
56
56
  },
57
- { autoRemove: (val: any) => testFalsy(val) },
57
+ {
58
+ autoRemove: (val: any) => testFalsy(val),
59
+ resolveFilterValue: (val: any) => String(val),
60
+ },
58
61
  )
59
62
 
60
63
  /**
@@ -77,7 +80,10 @@ export const filterFn_includesString = Object.assign(
77
80
  .includes(String(filterValue).toLowerCase()),
78
81
  )
79
82
  },
80
- { autoRemove: (val: any) => testFalsy(val) },
83
+ {
84
+ autoRemove: (val: any) => testFalsy(val),
85
+ resolveFilterValue: (val: any) => String(val).toLowerCase(),
86
+ },
81
87
  )
82
88
 
83
89
  /**
@@ -97,7 +103,10 @@ export const filterFn_equalsString = Object.assign(
97
103
  String(filterValue).toLowerCase()
98
104
  )
99
105
  },
100
- { autoRemove: (val: any) => testFalsy(val) },
106
+ {
107
+ autoRemove: (val: any) => testFalsy(val),
108
+ resolveFilterValue: (val: any) => String(val).toLowerCase(),
109
+ },
101
110
  )
102
111
 
103
112
  /**
@@ -113,7 +122,10 @@ export const filterFn_equalsStringSensitive = Object.assign(
113
122
  ) => {
114
123
  return row.getValue(columnId)?.toString() === String(filterValue)
115
124
  },
116
- { autoRemove: (val: any) => testFalsy(val) },
125
+ {
126
+ autoRemove: (val: any) => testFalsy(val),
127
+ resolveFilterValue: (val: any) => String(val),
128
+ },
117
129
  )
118
130
 
119
131
  // Number filters
@@ -143,7 +155,7 @@ export const filterFn_greaterThan = Object.assign(
143
155
  const stringFilterValue = String(filterValue).toLowerCase().trim()
144
156
  return stringValue > stringFilterValue
145
157
  },
146
- { resolveFilterValue: (val: any) => testFalsy(val) },
158
+ { autoRemove: (val: any) => testFalsy(val) },
147
159
  )
148
160
 
149
161
  /**
@@ -162,7 +174,7 @@ export const filterFn_greaterThanOrEqualTo = Object.assign(
162
174
  filterFn_equals(row, columnId, filterValue)
163
175
  )
164
176
  },
165
- { resolveFilterValue: (val: any) => testFalsy(val) },
177
+ { autoRemove: (val: any) => testFalsy(val) },
166
178
  )
167
179
 
168
180
  /**
@@ -178,7 +190,7 @@ export const filterFn_lessThan = Object.assign(
178
190
  ) => {
179
191
  return !filterFn_greaterThanOrEqualTo(row, columnId, filterValue)
180
192
  },
181
- { resolveFilterValue: (val: any) => testFalsy(val) },
193
+ { autoRemove: (val: any) => testFalsy(val) },
182
194
  )
183
195
 
184
196
  /**
@@ -194,7 +206,7 @@ export const filterFn_lessThanOrEqualTo = Object.assign(
194
206
  ) => {
195
207
  return !filterFn_greaterThan(row, columnId, filterValue)
196
208
  },
197
- { resolveFilterValue: (val: any) => testFalsy(val) },
209
+ { autoRemove: (val: any) => testFalsy(val) },
198
210
  )
199
211
 
200
212
  // Range filters
@@ -209,14 +221,29 @@ const filterFn_between = Object.assign(
209
221
  row: Row<TFeatures, TData>,
210
222
  columnId: string,
211
223
  filterValues: [unknown, unknown],
212
- ): boolean =>
213
- ((['', undefined] as Array<any>).includes(filterValues[0]) ||
214
- filterFn_greaterThan(row, columnId, filterValues[0])) &&
215
- ((!isNaN(Number(filterValues[0])) &&
216
- !isNaN(Number(filterValues[1])) &&
217
- Number(filterValues[0]) > Number(filterValues[1])) ||
218
- (['', undefined] as Array<any>).includes(filterValues[1]) ||
219
- filterFn_lessThan(row, columnId, filterValues[1])),
224
+ ): boolean => {
225
+ const min = filterValues[0]
226
+ if (min !== '' && min !== undefined) {
227
+ if (!filterFn_greaterThan(row, columnId, min)) {
228
+ return false
229
+ }
230
+ }
231
+
232
+ const max = filterValues[1]
233
+ if (max === '' || max === undefined) {
234
+ return true
235
+ }
236
+
237
+ if (min !== '' && min !== undefined) {
238
+ const numericMin = Number(min)
239
+ const numericMax = Number(max)
240
+ if (!isNaN(numericMin) && !isNaN(numericMax) && numericMin > numericMax) {
241
+ return true
242
+ }
243
+ }
244
+
245
+ return filterFn_lessThan(row, columnId, max)
246
+ },
220
247
  {
221
248
  autoRemove: (val: any) =>
222
249
  testFalsy(val) || (testFalsy(val[0]) && testFalsy(val[1])),
@@ -233,14 +260,29 @@ const filterFn_betweenInclusive = Object.assign(
233
260
  row: Row<TFeatures, TData>,
234
261
  columnId: string,
235
262
  filterValues: [unknown, unknown],
236
- ): boolean =>
237
- ((['', undefined] as Array<any>).includes(filterValues[0]) ||
238
- filterFn_greaterThanOrEqualTo(row, columnId, filterValues[0])) &&
239
- ((!isNaN(Number(filterValues[0])) &&
240
- !isNaN(Number(filterValues[1])) &&
241
- Number(filterValues[0]) > Number(filterValues[1])) ||
242
- (['', undefined] as Array<any>).includes(filterValues[1]) ||
243
- filterFn_lessThanOrEqualTo(row, columnId, filterValues[1])),
263
+ ): boolean => {
264
+ const min = filterValues[0]
265
+ if (min !== '' && min !== undefined) {
266
+ if (!filterFn_greaterThanOrEqualTo(row, columnId, min)) {
267
+ return false
268
+ }
269
+ }
270
+
271
+ const max = filterValues[1]
272
+ if (max === '' || max === undefined) {
273
+ return true
274
+ }
275
+
276
+ if (min !== '' && min !== undefined) {
277
+ const numericMin = Number(min)
278
+ const numericMax = Number(max)
279
+ if (!isNaN(numericMin) && !isNaN(numericMax) && numericMin > numericMax) {
280
+ return true
281
+ }
282
+ }
283
+
284
+ return filterFn_lessThanOrEqualTo(row, columnId, max)
285
+ },
244
286
  {
245
287
  autoRemove: (val: any) =>
246
288
  testFalsy(val) || (testFalsy(val[0]) && testFalsy(val[1])),
@@ -302,7 +344,13 @@ export const filterFn_arrHas = Object.assign(
302
344
  columnId: string,
303
345
  filterValue: Array<unknown>,
304
346
  ) => {
305
- return filterValue.some((val) => row.getValue<unknown>(columnId) === val)
347
+ const value = row.getValue<unknown>(columnId)
348
+ for (let i = 0; i < filterValue.length; i++) {
349
+ if (value === filterValue[i]) {
350
+ return true
351
+ }
352
+ }
353
+ return false
306
354
  },
307
355
  { autoRemove: (val: any) => testFalsy(val) || !val?.length },
308
356
  )
@@ -316,11 +364,17 @@ export const filterFn_arrIncludes = Object.assign(
316
364
  columnId: string,
317
365
  filterValue: Array<unknown>,
318
366
  ) => {
319
- return filterValue.some((val) =>
320
- (row.getValue<unknown>(columnId) as Array<unknown> | string).includes(
321
- val as any,
322
- ),
323
- )
367
+ const value = row.getValue<unknown>(columnId)
368
+ if (typeof value !== 'string' && !Array.isArray(value)) {
369
+ return false
370
+ }
371
+
372
+ for (let i = 0; i < filterValue.length; i++) {
373
+ if (value.includes(filterValue[i] as any)) {
374
+ return true
375
+ }
376
+ }
377
+ return false
324
378
  },
325
379
  { autoRemove: (val: any) => testFalsy(val) || !val?.length },
326
380
  )
@@ -336,7 +390,12 @@ export const filterFn_arrIncludesAll = Object.assign(
336
390
  ) => {
337
391
  const value = row.getValue<Array<unknown>>(columnId)
338
392
  if (!Array.isArray(value)) return false
339
- return !filterValue.some((val) => !value.includes(val))
393
+ for (let i = 0; i < filterValue.length; i++) {
394
+ if (!value.includes(filterValue[i])) {
395
+ return false
396
+ }
397
+ }
398
+ return true
340
399
  },
341
400
  { autoRemove: (val: any) => testFalsy(val) || !val?.length },
342
401
  )
@@ -352,7 +411,12 @@ export const filterFn_arrIncludesSome = Object.assign(
352
411
  ) => {
353
412
  const value = row.getValue<Array<unknown>>(columnId)
354
413
  if (!Array.isArray(value)) return false
355
- return filterValue.some((val) => value.includes(val))
414
+ for (let i = 0; i < filterValue.length; i++) {
415
+ if (value.includes(filterValue[i])) {
416
+ return true
417
+ }
418
+ }
419
+ return false
356
420
  },
357
421
  { autoRemove: (val: any) => testFalsy(val) || !val?.length },
358
422
  )