@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.
- package/DataTable/utils/queryParams.d.ts +3 -8
- package/DataTable/utils/tableQueryParamsToHasuraClauses.d.ts +12 -0
- package/index.cjs.js +161 -27
- package/index.es.js +161 -27
- package/package.json +1 -1
- package/src/DataTable/Columns.js +1 -1
- package/src/DataTable/DisplayOptions.js +1 -1
- package/src/DataTable/index.js +1 -1
- package/src/DataTable/utils/filterLocalEntitiesToHasura.js +6 -0
- package/src/DataTable/utils/filterLocalEntitiesToHasura.test.js +69 -46
- package/src/DataTable/utils/initializeHasuraWhereAndFilter.js +0 -1
- package/src/DataTable/utils/queryParams.js +32 -21
- package/src/DataTable/utils/tableQueryParamsToHasuraClauses.js +154 -17
- package/src/DataTable/utils/tableQueryParamsToHasuraClauses.test.js +8 -21
- package/src/DataTable/utils/withTableParams.js +2 -2
- package/DataTable/utils/simplifyHasuraWhere.d.ts +0 -1
- package/src/DataTable/utils/simplifyHasuraWhere.js +0 -80
- package/src/DataTable/utils/simplifyHasuraWhere.test.js +0 -73
|
@@ -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
|
-
|
|
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 "
|
|
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 "
|
|
114
|
+
case "notContains":
|
|
115
|
+
return { [filterOn]: { _not_ilike: `%${filterValue}%` } };
|
|
116
|
+
case "isExactly":
|
|
69
117
|
return { [filterOn]: { _eq: filterValue } };
|
|
70
|
-
case "
|
|
71
|
-
return {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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 "
|
|
170
|
+
case "lessThan":
|
|
77
171
|
return { [filterOn]: { _lt: parseFloat(filterValue) } };
|
|
78
|
-
case "
|
|
79
|
-
return {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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
|
|
101
|
+
it("should handle contains filter", () => {
|
|
102
102
|
const result = tableQueryParamsToHasuraClauses({
|
|
103
103
|
filters: [
|
|
104
104
|
{
|
|
105
|
-
selectedFilter: "
|
|
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
|
|
119
|
+
it("should handle equalTo filter for number", () => {
|
|
120
120
|
const result = tableQueryParamsToHasuraClauses({
|
|
121
121
|
filters: [
|
|
122
|
-
{ selectedFilter: "
|
|
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: "
|
|
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: "
|
|
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
|
-
});
|