@teselagen/ui 0.7.33-beta.4 → 0.7.33-beta.5

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.
@@ -1,3 +1,5 @@
1
+ import { camelCase } from "lodash-es";
2
+
1
3
  export function tableQueryParamsToHasuraClauses({
2
4
  page,
3
5
  pageSize,
@@ -7,6 +9,7 @@ export function tableQueryParamsToHasuraClauses({
7
9
  schema, // Add schema as a parameter
8
10
  additionalFilter
9
11
  }) {
12
+ const ccFields = getFieldsMappedByCCDisplayName(schema);
10
13
  let where = {};
11
14
  const order_by = {};
12
15
  const limit = pageSize || 25;
@@ -61,28 +64,137 @@ export function tableQueryParamsToHasuraClauses({
61
64
 
62
65
  if (filters && filters.length > 0) {
63
66
  const filterClauses = filters.map(filter => {
64
- const { selectedFilter, filterOn, filterValue } = filter;
67
+ let { selectedFilter, filterOn, filterValue } = filter;
68
+ const fieldSchema = ccFields[filterOn] || {};
69
+
70
+ const { path, reference, type } = fieldSchema;
71
+ let stringFilterValue =
72
+ filterValue && filterValue.toString
73
+ ? filterValue.toString()
74
+ : filterValue;
75
+ if (stringFilterValue === false) {
76
+ // we still want to be able to search for the string "false" which will get parsed to false
77
+ stringFilterValue = "false";
78
+ } else {
79
+ stringFilterValue = stringFilterValue || "";
80
+ }
81
+ const arrayFilterValue = Array.isArray(filterValue)
82
+ ? filterValue
83
+ : stringFilterValue.split(";");
84
+
85
+ if (type === "number" || type === "integer") {
86
+ filterValue = Array.isArray(filterValue)
87
+ ? filterValue.map(val => Number(val))
88
+ : Number(filterValue);
89
+ }
90
+
91
+ if (fieldSchema.normalizeFilter) {
92
+ filterValue = fieldSchema.normalizeFilter(
93
+ filterValue,
94
+ selectedFilter,
95
+ filterOn
96
+ );
97
+ }
98
+
99
+ if (reference) {
100
+ filterOn = reference.sourceField;
101
+ } else {
102
+ filterOn = path || filterOn;
103
+ }
104
+
65
105
  switch (selectedFilter) {
66
- case "textContains":
106
+ case "none":
107
+ return {};
108
+ case "startsWith":
109
+ return { [filterOn]: { _ilike: `${filterValue}%` } };
110
+ case "endsWith":
111
+ return { [filterOn]: { _ilike: `%${filterValue}` } };
112
+ case "contains":
67
113
  return { [filterOn]: { _ilike: `%${filterValue}%` } };
68
- case "textEquals":
114
+ case "notContains":
115
+ return { [filterOn]: { _not_ilike: `%${filterValue}%` } };
116
+ case "isExactly":
69
117
  return { [filterOn]: { _eq: filterValue } };
70
- case "textNotEquals":
71
- return { [filterOn]: { _neq: filterValue } };
72
- case "numberEquals":
73
- return { [filterOn]: { _eq: parseFloat(filterValue) } };
74
- case "numberGreaterThan":
118
+ case "isEmpty":
119
+ return {
120
+ _or: [
121
+ { [filterOn]: { _eq: "" } },
122
+ { [filterOn]: { _is_null: true } }
123
+ ]
124
+ };
125
+ case "notEmpty":
126
+ return {
127
+ _and: [
128
+ { [filterOn]: { _neq: "" } },
129
+ { [filterOn]: { _is_null: false } }
130
+ ]
131
+ };
132
+ case "inList":
133
+ return { [filterOn]: { _in: filterValue } };
134
+ case "notInList":
135
+ return { [filterOn]: { _nin: filterValue } };
136
+ case "true":
137
+ return { [filterOn]: { _eq: true } };
138
+ case "false":
139
+ return { [filterOn]: { _eq: false } };
140
+ case "dateIs":
141
+ return { [filterOn]: { _eq: filterValue } };
142
+ case "notBetween":
143
+ return {
144
+ _or: [
145
+ {
146
+ [filterOn]: {
147
+ _lt: new Date(arrayFilterValue[0])
148
+ }
149
+ },
150
+ {
151
+ [filterOn]: {
152
+ _gt: new Date(new Date(arrayFilterValue[1]).setHours(23, 59))
153
+ }
154
+ }
155
+ ]
156
+ };
157
+ case "isBetween":
158
+ return {
159
+ [filterOn]: {
160
+ _gte: new Date(arrayFilterValue[0]),
161
+ _lte: new Date(new Date(arrayFilterValue[1]).setHours(23, 59))
162
+ }
163
+ };
164
+ case "isBefore":
165
+ return { [filterOn]: { _lt: new Date(filterValue) } };
166
+ case "isAfter":
167
+ return { [filterOn]: { _gt: new Date(filterValue) } };
168
+ case "greaterThan":
75
169
  return { [filterOn]: { _gt: parseFloat(filterValue) } };
76
- case "numberLessThan":
170
+ case "lessThan":
77
171
  return { [filterOn]: { _lt: parseFloat(filterValue) } };
78
- case "numberGreaterThanEquals":
79
- return { [filterOn]: { _gte: parseFloat(filterValue) } };
80
- case "numberLessThanEquals":
81
- return { [filterOn]: { _lte: parseFloat(filterValue) } };
82
- case "isNull":
83
- return { [filterOn]: { _is_null: true } };
84
- case "isNotNull":
85
- return { [filterOn]: { _is_null: false } };
172
+ case "inRange":
173
+ return {
174
+ [filterOn]: {
175
+ _gte: parseFloat(arrayFilterValue[0]),
176
+ _lte: parseFloat(arrayFilterValue[1])
177
+ }
178
+ };
179
+ case "outsideRange":
180
+ return {
181
+ _or: [
182
+ {
183
+ [filterOn]: {
184
+ _lt: parseFloat(arrayFilterValue[0])
185
+ }
186
+ },
187
+ {
188
+ [filterOn]: {
189
+ _gt: parseFloat(arrayFilterValue[1])
190
+ }
191
+ }
192
+ ]
193
+ };
194
+ case "equalTo":
195
+ return { [filterOn]: { _eq: parseFloat(filterValue) } };
196
+ case "regex":
197
+ return { [filterOn]: { _regex: filterValue } };
86
198
  default:
87
199
  console.warn(`Unsupported filter type: ${selectedFilter}`);
88
200
  return {};
@@ -111,3 +223,28 @@ export function tableQueryParamsToHasuraClauses({
111
223
  }
112
224
  return { where, order_by, limit, offset };
113
225
  }
226
+
227
+ /**
228
+ * Takes a schema and returns an object with the fields mapped by their camelCased display name.
229
+ * If the displayName is not set or is a jsx element, the path is used instead.
230
+ * The same conversion must be done when using the result of this method
231
+ */
232
+ export function getFieldsMappedByCCDisplayName(schema) {
233
+ if (!schema || !schema.fields) return {};
234
+ return schema.fields.reduce((acc, field) => {
235
+ const ccDisplayName = getCCDisplayName(field);
236
+ acc[ccDisplayName] = field;
237
+ return acc;
238
+ }, {});
239
+ }
240
+
241
+ /**
242
+ *
243
+ * @param {object} field
244
+ * @returns the camelCase display name of the field, to be used for filters, sorting, etc
245
+ */
246
+ export function getCCDisplayName(field) {
247
+ return camelCase(
248
+ typeof field.displayName === "string" ? field.displayName : field.path
249
+ );
250
+ }
@@ -98,11 +98,11 @@ describe("tableQueryParamsToHasuraClauses", () => {
98
98
  });
99
99
  });
100
100
 
101
- it("should handle textContains filter", () => {
101
+ it("should handle contains filter", () => {
102
102
  const result = tableQueryParamsToHasuraClauses({
103
103
  filters: [
104
104
  {
105
- selectedFilter: "textContains",
105
+ selectedFilter: "contains",
106
106
  filterOn: "name",
107
107
  filterValue: "test"
108
108
  }
@@ -116,25 +116,12 @@ describe("tableQueryParamsToHasuraClauses", () => {
116
116
  });
117
117
  });
118
118
 
119
- it("should handle textEquals filter", () => {
119
+ it("should handle equalTo filter for number", () => {
120
120
  const result = tableQueryParamsToHasuraClauses({
121
121
  filters: [
122
- { selectedFilter: "textEquals", filterOn: "name", filterValue: "test" }
123
- ]
124
- });
125
- expect(result).toEqual({
126
- where: { _and: [{ name: { _eq: "test" } }] },
127
- order_by: {},
128
- limit: 25,
129
- offset: 0
130
- });
131
- });
132
-
133
- it("should handle numberEquals filter", () => {
134
- const result = tableQueryParamsToHasuraClauses({
135
- filters: [
136
- { selectedFilter: "numberEquals", filterOn: "age", filterValue: "30" }
137
- ]
122
+ { selectedFilter: "equalTo", filterOn: "age", filterValue: "30" }
123
+ ],
124
+ schema
138
125
  });
139
126
  expect(result).toEqual({
140
127
  where: { _and: [{ age: { _eq: 30 } }] },
@@ -161,7 +148,7 @@ describe("tableQueryParamsToHasuraClauses", () => {
161
148
  searchTerm: "test",
162
149
  filters: [
163
150
  {
164
- selectedFilter: "numberGreaterThan",
151
+ selectedFilter: "greaterThan",
165
152
  filterOn: "age",
166
153
  filterValue: "30"
167
154
  }
@@ -192,7 +179,7 @@ describe("tableQueryParamsToHasuraClauses", () => {
192
179
  searchTerm: "test",
193
180
  filters: [
194
181
  {
195
- selectedFilter: "numberGreaterThan",
182
+ selectedFilter: "greaterThan",
196
183
  filterOn: "age",
197
184
  filterValue: "30"
198
185
  }
@@ -6,13 +6,13 @@ import {
6
6
  makeDataTableHandlers,
7
7
  getQueryParams,
8
8
  setCurrentParamsOnUrl,
9
- getCurrentParamsFromUrl,
10
- getCCDisplayName
9
+ getCurrentParamsFromUrl
11
10
  } from "./queryParams";
12
11
  import { withRouter } from "react-router-dom";
13
12
  import getTableConfigFromStorage from "./getTableConfigFromStorage";
14
13
  import { useDeepEqualMemo } from "../../utils/hooks/useDeepEqualMemo";
15
14
  import { branch, compose } from "recompose";
15
+ import { getCCDisplayName } from "./tableQueryParamsToHasuraClauses";
16
16
 
17
17
  /**
18
18
  * Note all these options can be passed at Design Time or at Runtime (like reduxForm())
@@ -1 +0,0 @@
1
- export function simplifyHasuraWhere(whereClause: any): {};
@@ -1,80 +0,0 @@
1
- export function simplifyHasuraWhere(whereClause) {
2
- const simplifiedWhere = {};
3
-
4
- for (const key in whereClause) {
5
- // eslint-disable-next-line no-prototype-builtins
6
- if (whereClause.hasOwnProperty(key)) {
7
- const value = whereClause[key];
8
-
9
- if (
10
- typeof value === "object" &&
11
- value !== null &&
12
- !Array.isArray(value)
13
- ) {
14
- if (key.includes(".")) {
15
- // Handle dot-nested where clauses
16
- const keys = key.split(".");
17
- let currentObj = simplifiedWhere;
18
- for (let i = 0; i < keys.length - 1; i++) {
19
- const nestedKey = keys[i];
20
- if (!currentObj[nestedKey]) {
21
- currentObj[nestedKey] = {};
22
- }
23
- currentObj = currentObj[nestedKey];
24
- }
25
- if (typeof value === "object" && value !== null && "_eq" in value) {
26
- currentObj[keys[keys.length - 1]] = value;
27
- } else {
28
- currentObj[keys[keys.length - 1]] = { _eq: value };
29
- }
30
- } else {
31
- // Handle regular Hasura operators or already nested objects.
32
- if (
33
- typeof value === "object" &&
34
- value !== null &&
35
- !("_eq" in value) &&
36
- !("_gt" in value) &&
37
- !("_lt" in value) &&
38
- !("_gte" in value) &&
39
- !("_lte" in value) &&
40
- !("_in" in value) &&
41
- !("_nin" in value) &&
42
- !("_neq" in value) &&
43
- !("_like" in value) &&
44
- !("_nlike" in value) &&
45
- !("_ilike" in value) &&
46
- !("_nilike" in value) &&
47
- !("_similar" in value) &&
48
- !("_nsimilar" in value) &&
49
- !("_regex" in value) &&
50
- !("_nregex" in value) &&
51
- !("_iregex" in value) &&
52
- !("_niregex" in value)
53
- ) {
54
- simplifiedWhere[key] = simplifyHasuraWhere(value);
55
- } else {
56
- simplifiedWhere[key] = value;
57
- }
58
- }
59
- } else {
60
- // Handle simplified _eq where clauses
61
- if (key.includes(".")) {
62
- const keys = key.split(".");
63
- let currentObj = simplifiedWhere;
64
- for (let i = 0; i < keys.length - 1; i++) {
65
- const nestedKey = keys[i];
66
- if (!currentObj[nestedKey]) {
67
- currentObj[nestedKey] = {};
68
- }
69
- currentObj = currentObj[nestedKey];
70
- }
71
- currentObj[keys[keys.length - 1]] = { _eq: value };
72
- } else {
73
- simplifiedWhere[key] = { _eq: value };
74
- }
75
- }
76
- }
77
- }
78
-
79
- return simplifiedWhere;
80
- }
@@ -1,73 +0,0 @@
1
- import { simplifyHasuraWhere } from "./simplifyHasuraWhere";
2
-
3
- describe("simplifyHasuraWhere", () => {
4
- it("should handle empty where clause", () => {
5
- expect(simplifyHasuraWhere({})).toEqual({});
6
- });
7
-
8
- it("should simplify simple _eq where clauses", () => {
9
- const input = { id: 123, name: "John Doe" };
10
- const expected = { id: { _eq: 123 }, name: { _eq: "John Doe" } };
11
- expect(simplifyHasuraWhere(input)).toEqual(expected);
12
- });
13
-
14
- it("should handle existing _eq where clauses without simplification", () => {
15
- const input = { id: { _eq: 123 }, name: { _eq: "John Doe" } };
16
- const expected = { id: { _eq: 123 }, name: { _eq: "John Doe" } };
17
- expect(simplifyHasuraWhere(input)).toEqual(expected);
18
- });
19
-
20
- it("should handle other Hasura operators", () => {
21
- const input = { age: { _gt: 30 }, isActive: { _eq: true } };
22
- const expected = { age: { _gt: 30 }, isActive: { _eq: true } };
23
- expect(simplifyHasuraWhere(input)).toEqual(expected);
24
- });
25
-
26
- it("should handle dot-nested where clauses", () => {
27
- const input = { "address.city": { _eq: "New York" }, "address.zip": 10001 };
28
- const expected = {
29
- address: { city: { _eq: "New York" }, zip: { _eq: 10001 } }
30
- };
31
- expect(simplifyHasuraWhere(input)).toEqual(expected);
32
- });
33
-
34
- it("should handle deeply nested dot-nested where clauses", () => {
35
- const input = { "nested.prop.value": { _eq: "test" } };
36
- const expected = { nested: { prop: { value: { _eq: "test" } } } };
37
- expect(simplifyHasuraWhere(input)).toEqual(expected);
38
- });
39
-
40
- it("should handle a mix of simple, nested, and operator clauses", () => {
41
- const input = {
42
- id: 123,
43
- name: "John Doe",
44
- "address.city": { _eq: "New York" },
45
- age: { _gt: 30 },
46
- "nested.prop.value": { _eq: "test" }
47
- };
48
- const expected = {
49
- id: { _eq: 123 },
50
- name: { _eq: "John Doe" },
51
- address: { city: { _eq: "New York" } },
52
- age: { _gt: 30 },
53
- nested: { prop: { value: { _eq: "test" } } }
54
- };
55
- expect(simplifyHasuraWhere(input)).toEqual(expected);
56
- });
57
-
58
- it("should handle already nested objects with operators", () => {
59
- const input = {
60
- address: {
61
- city: { _eq: "London" },
62
- country: "UK"
63
- }
64
- };
65
- const expected = {
66
- address: {
67
- city: { _eq: "London" },
68
- country: { _eq: "UK" }
69
- }
70
- };
71
- expect(simplifyHasuraWhere(input)).toEqual(expected);
72
- });
73
- });