@teselagen/ui 0.8.6-beta.2 → 0.8.6-beta.20

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.
@@ -9,7 +9,10 @@ import {
9
9
  includes,
10
10
  isObject,
11
11
  has,
12
- orderBy
12
+ orderBy,
13
+ endsWith,
14
+ get,
15
+ forEach
13
16
  } from "lodash-es";
14
17
 
15
18
  export function filterLocalEntitiesToHasura(
@@ -27,6 +30,7 @@ export function filterLocalEntitiesToHasura(
27
30
  if (order_by) {
28
31
  filteredRecords = applyOrderBy(filteredRecords, order_by);
29
32
  }
33
+ filteredRecords = restoreEntitiesFromLocalFilter(filteredRecords);
30
34
 
31
35
  // Store the complete filtered and ordered records for pagination info
32
36
  const allFilteredRecords = [...filteredRecords];
@@ -74,7 +78,7 @@ function applyWhereClause(records, where) {
74
78
  return false;
75
79
  }
76
80
  } else {
77
- const value = record[key];
81
+ const value = get(record, key);
78
82
  const conditions = filter[key];
79
83
 
80
84
  // Handle nested object properties
@@ -225,12 +229,127 @@ function applyWhereClause(records, where) {
225
229
  return records.filter(record => applyFilter(record, where));
226
230
  }
227
231
 
228
- function applyOrderBy(records, order_by) {
229
- const keys = Object.keys(order_by);
230
- if (keys.length > 0) {
231
- const field = keys[0];
232
- const direction = order_by[field] === "asc" ? "asc" : "desc";
233
- return orderBy(records, [field], [direction]);
232
+ // takes in an array of records and an order_by clause
233
+ // order_by looks like this: [{ some_field: "asc" }, { some_other_field: "desc" }] or {some_field: "asc"}
234
+ // returns the records sorted by the order_by clause
235
+ function applyOrderBy(records, _order_by) {
236
+ const order_by = isArray(_order_by)
237
+ ? _order_by
238
+ : isEmpty(_order_by)
239
+ ? []
240
+ : [_order_by];
241
+
242
+ if (order_by.length > 0) {
243
+ const orderFuncs = [];
244
+ const ascOrDescArray = [];
245
+
246
+ order_by.forEach(
247
+ ({ path, direction, type, sortFn, getValueToFilterOn, ownProps }) => {
248
+ // Default direction is "desc" if not specified
249
+ direction = direction || "desc";
250
+
251
+ if (sortFn) {
252
+ // Handle specifically custom sort functions
253
+ // First make sure we have an array of sort functions
254
+ const sortFnArray = Array.isArray(sortFn) ? sortFn : [sortFn];
255
+
256
+ // For each sort function
257
+ sortFnArray.forEach(fn => {
258
+ // First handle null check for this function's values
259
+ orderFuncs.push(r => {
260
+ const val = fn(r);
261
+ return val !== null && val !== undefined ? 1 : 0;
262
+ });
263
+ ascOrDescArray.push("desc"); // Always push nulls to the bottom
264
+
265
+ // Then the actual sort function
266
+ orderFuncs.push(fn);
267
+ ascOrDescArray.push(direction);
268
+ });
269
+ } else if (getValueToFilterOn) {
270
+ // Custom getValue function
271
+ // First handle null check
272
+ orderFuncs.push(r => {
273
+ const val = getValueToFilterOn(r, ownProps);
274
+ return val !== null && val !== undefined ? 1 : 0;
275
+ });
276
+ ascOrDescArray.push("desc"); // Always push nulls to the bottom
277
+
278
+ // Then the actual value getter function
279
+ orderFuncs.push(r => getValueToFilterOn(r, ownProps));
280
+ ascOrDescArray.push(direction);
281
+ } else if (type === "timestamp") {
282
+ // Sort nulls/undefined to the bottom regardless of sort direction
283
+ orderFuncs.push(r => {
284
+ const val = get(r, path);
285
+ // First check if value exists, this ensures nulls go to the bottom
286
+ return val ? 1 : 0;
287
+ });
288
+ ascOrDescArray.push("desc"); // always put nulls at the bottom
289
+
290
+ // Then actual timestamp sorting
291
+ orderFuncs.push(r => {
292
+ const val = get(r, path);
293
+ return val ? new Date(val).getTime() : -Infinity;
294
+ });
295
+ ascOrDescArray.push(direction);
296
+ } else if (path && endsWith(path.toLowerCase(), "id")) {
297
+ // Handle ID fields - sort numerically
298
+ // First handle null check
299
+ orderFuncs.push(r => {
300
+ const val = get(r, path);
301
+ return val !== null && val !== undefined ? 1 : 0;
302
+ });
303
+ ascOrDescArray.push("desc"); // Always push nulls to the bottom
304
+
305
+ // Then the actual ID parsing
306
+ orderFuncs.push(o => {
307
+ const val = get(o, path);
308
+ if (val === null || val === undefined) return -Infinity;
309
+ return parseInt(val, 10) || 0;
310
+ });
311
+ ascOrDescArray.push(direction);
312
+ } else {
313
+ // Default sorting
314
+ // First sort by existence (non-nulls first)
315
+ orderFuncs.push(r => {
316
+ const val = get(r, path);
317
+ return val !== null && val !== undefined ? 1 : 0;
318
+ });
319
+ ascOrDescArray.push("desc"); // Always put nulls at the bottom
320
+
321
+ // Then sort by actual value
322
+ orderFuncs.push(r => {
323
+ const val = get(r, path);
324
+ if (val === null || val === undefined) return -Infinity;
325
+
326
+ // For string sorting, implement natural sort
327
+ if (isString(val)) {
328
+ return val.toLowerCase().replace(/(\d+)/g, num =>
329
+ // Pad numbers with leading zeros for proper natural sort
330
+ num.padStart(10, "0")
331
+ );
332
+ }
333
+ return val;
334
+ });
335
+ ascOrDescArray.push(direction);
336
+ }
337
+ }
338
+ );
339
+
340
+ records = orderBy(records, orderFuncs, ascOrDescArray);
234
341
  }
235
342
  return records;
236
343
  }
344
+
345
+ function restoreEntitiesFromLocalFilter(ents) {
346
+ return ents.map(entity => {
347
+ forEach(entity, (val, key) => {
348
+ if (key.startsWith?.("___original___")) {
349
+ entity[key.slice("___original___".length)] = val;
350
+ delete entity[key];
351
+ }
352
+ });
353
+ return entity;
354
+ });
355
+ }