@autofleet/sadot 0.6.4-beta.1 → 0.6.4
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/dist/scopes/filter.d.ts +7 -2
- package/dist/scopes/filter.js +36 -27
- package/package.json +1 -1
- package/src/scopes/filter.ts +42 -29
package/dist/scopes/filter.d.ts
CHANGED
|
@@ -4,7 +4,11 @@ import { WhereOptions } from 'sequelize';
|
|
|
4
4
|
* Currently supporting strings and arrays of strings.
|
|
5
5
|
* More types to be added (TBA).
|
|
6
6
|
*/
|
|
7
|
-
|
|
7
|
+
type ConditionWithOperator = {
|
|
8
|
+
operator: string;
|
|
9
|
+
value: string;
|
|
10
|
+
};
|
|
11
|
+
export type ConditionValue = ConditionWithOperator | ConditionWithOperator[] | string | string[];
|
|
8
12
|
export type CustomFieldSort = {
|
|
9
13
|
field: string;
|
|
10
14
|
direction: 'ASC' | 'DESC';
|
|
@@ -26,7 +30,8 @@ export declare const customFieldsSortScope: (name: string) => (sort: CustomField
|
|
|
26
30
|
order?: undefined;
|
|
27
31
|
} | {
|
|
28
32
|
attributes: {
|
|
29
|
-
include:
|
|
33
|
+
include: import("sequelize/types/utils").Literal[];
|
|
30
34
|
};
|
|
31
35
|
order: import("sequelize/types/utils").Literal[];
|
|
32
36
|
};
|
|
37
|
+
export {};
|
package/dist/scopes/filter.js
CHANGED
|
@@ -6,6 +6,13 @@ const sequelize_1 = require("sequelize");
|
|
|
6
6
|
const sequelize_typescript_1 = require("sequelize-typescript");
|
|
7
7
|
const common_types_1 = require("@autofleet/common-types");
|
|
8
8
|
const { CUSTOM_FIELDS_FILTER_SCOPE } = common_types_1.customFields;
|
|
9
|
+
const castIfNeeded = (conditionValue) => {
|
|
10
|
+
if (!Number.isNaN(Date.parse(conditionValue))) {
|
|
11
|
+
return '::timestamp';
|
|
12
|
+
}
|
|
13
|
+
return '';
|
|
14
|
+
};
|
|
15
|
+
const AND_DELIMETER = ' AND ';
|
|
9
16
|
/**
|
|
10
17
|
* A Sequelize scope for filtering models by custom fields.
|
|
11
18
|
* This scope builds a WHERE clause to be applied on the main query.
|
|
@@ -19,30 +26,39 @@ const customFieldsFilterScope = (name) => (conditions) => {
|
|
|
19
26
|
}
|
|
20
27
|
// Build the WHERE clause for custom field filtering
|
|
21
28
|
const conditionsStrings = Object.entries(conditions)
|
|
22
|
-
.map(([key,
|
|
23
|
-
if (Array.isArray(
|
|
24
|
-
if (
|
|
29
|
+
.map(([key, condition]) => {
|
|
30
|
+
if (Array.isArray(condition)) {
|
|
31
|
+
if (condition.length === 0) {
|
|
25
32
|
// if empty array, the condition is ignored
|
|
26
33
|
return false;
|
|
27
34
|
}
|
|
28
|
-
|
|
29
|
-
|
|
35
|
+
if (typeof condition[0] === 'string') {
|
|
36
|
+
const values = condition.map((v) => `'${v}'`).join(',');
|
|
37
|
+
return `(custom_fields->>'${key}') IN (${values})`;
|
|
38
|
+
}
|
|
39
|
+
return condition
|
|
40
|
+
.map((c) => `(custom_fields->>'${key}')${castIfNeeded(c.value)} ${c.operator} '${c.value}'`).join(AND_DELIMETER);
|
|
41
|
+
}
|
|
42
|
+
if (typeof condition === 'string') {
|
|
43
|
+
return `(custom_fields->>'${key}')${castIfNeeded(condition)} = '${condition}'`;
|
|
44
|
+
}
|
|
45
|
+
if (condition?.operator) {
|
|
46
|
+
return `(custom_fields->>'${key}')${castIfNeeded(condition.value)} ${condition.operator} '${condition.value}'`;
|
|
30
47
|
}
|
|
31
|
-
return
|
|
48
|
+
return false;
|
|
32
49
|
})
|
|
33
50
|
.filter(Boolean);
|
|
34
51
|
if (conditionsStrings.length === 0) {
|
|
35
52
|
return {};
|
|
36
53
|
}
|
|
37
|
-
const customFieldConditions = conditionsStrings.join(
|
|
54
|
+
const customFieldConditions = conditionsStrings.join(AND_DELIMETER);
|
|
38
55
|
const subQuery = `${'SELECT model_id FROM ('
|
|
39
56
|
+ 'SELECT cv.model_id, jsonb_object_agg(cd.name, cv.value) AS custom_fields '
|
|
40
57
|
+ 'FROM custom_field_values AS cv '
|
|
41
58
|
+ 'INNER JOIN custom_field_definitions AS cd ON cv.custom_field_definition_id = cd.id '
|
|
42
59
|
+ `AND cd.model_type = '${name}' `
|
|
43
60
|
+ 'GROUP BY cv.model_id'
|
|
44
|
-
+ ') AS CustomFieldAggregation '
|
|
45
|
-
+ 'WHERE '}${customFieldConditions}`;
|
|
61
|
+
+ ') AS CustomFieldAggregation WHERE '}${customFieldConditions}`;
|
|
46
62
|
return {
|
|
47
63
|
where: {
|
|
48
64
|
id: {
|
|
@@ -57,24 +73,17 @@ const customFieldsSortScope = (name) => (sort) => {
|
|
|
57
73
|
if (!sort || sort.length === 0) {
|
|
58
74
|
return {};
|
|
59
75
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
WHERE cv.model_id = "${name}"."id"
|
|
72
|
-
GROUP BY cv.model_id
|
|
73
|
-
) AS CustomFieldAggregation
|
|
74
|
-
)`),
|
|
75
|
-
`customFields_${key}`,
|
|
76
|
-
]));
|
|
77
|
-
const orders = Object.entries(sort).map(([key, value]) => sequelize_typescript_1.Sequelize.literal(`"customFields_${key}" ${value}`));
|
|
76
|
+
console.log('sort', sort);
|
|
77
|
+
console.log('name', name);
|
|
78
|
+
console.log('Object.entries(sort)', Object.entries(sort));
|
|
79
|
+
const includes = Object.entries(sort).map(([key]) => sequelize_typescript_1.Sequelize.literal(`(select CustomFieldAggregation.custom_fields->>'${key}'
|
|
80
|
+
from (SELECT cv.model_id, jsonb_object_agg(cd.name, cv.value) AS custom_fields
|
|
81
|
+
FROM custom_field_values AS cv
|
|
82
|
+
INNER JOIN custom_field_definitions AS cd
|
|
83
|
+
ON cv.custom_field_definition_id = cd.id AND cd.model_type = '${name}'
|
|
84
|
+
where cv.model_id = "${name}"."id"
|
|
85
|
+
GROUP BY cv.model_id) AS CustomFieldAggregation) as "customFields.${key}"`));
|
|
86
|
+
const orders = Object.entries(sort).map(([key, value]) => sequelize_typescript_1.Sequelize.literal(`"customFields.${key}" ${value}`));
|
|
78
87
|
return {
|
|
79
88
|
attributes: {
|
|
80
89
|
include: includes,
|
package/package.json
CHANGED
package/src/scopes/filter.ts
CHANGED
|
@@ -10,7 +10,11 @@ const { CUSTOM_FIELDS_FILTER_SCOPE } = customFields;
|
|
|
10
10
|
* Currently supporting strings and arrays of strings.
|
|
11
11
|
* More types to be added (TBA).
|
|
12
12
|
*/
|
|
13
|
-
|
|
13
|
+
type ConditionWithOperator = {
|
|
14
|
+
operator: string;
|
|
15
|
+
value: string;
|
|
16
|
+
};
|
|
17
|
+
export type ConditionValue = ConditionWithOperator | ConditionWithOperator[] | string | string[];
|
|
14
18
|
|
|
15
19
|
export type CustomFieldSort = {
|
|
16
20
|
field: string;
|
|
@@ -21,6 +25,13 @@ export type CustomFieldFilterOptions = {
|
|
|
21
25
|
where?: WhereOptions;
|
|
22
26
|
}
|
|
23
27
|
|
|
28
|
+
const castIfNeeded = (conditionValue: string): string => {
|
|
29
|
+
if (!Number.isNaN(Date.parse(conditionValue))) {
|
|
30
|
+
return '::timestamp';
|
|
31
|
+
}
|
|
32
|
+
return '';
|
|
33
|
+
};
|
|
34
|
+
const AND_DELIMETER = ' AND ';
|
|
24
35
|
/**
|
|
25
36
|
* A Sequelize scope for filtering models by custom fields.
|
|
26
37
|
* This scope builds a WHERE clause to be applied on the main query.
|
|
@@ -37,24 +48,33 @@ export const customFieldsFilterScope = (
|
|
|
37
48
|
// Build the WHERE clause for custom field filtering
|
|
38
49
|
const conditionsStrings = Object.entries(conditions)
|
|
39
50
|
.map(
|
|
40
|
-
([key,
|
|
41
|
-
if (Array.isArray(
|
|
42
|
-
if (
|
|
51
|
+
([key, condition]) => {
|
|
52
|
+
if (Array.isArray(condition)) {
|
|
53
|
+
if (condition.length === 0) {
|
|
43
54
|
// if empty array, the condition is ignored
|
|
44
55
|
return false;
|
|
45
56
|
}
|
|
46
|
-
|
|
47
|
-
|
|
57
|
+
if (typeof condition[0] === 'string') {
|
|
58
|
+
const values = condition.map((v) => `'${v}'`).join(',');
|
|
59
|
+
return `(custom_fields->>'${key}') IN (${values})`;
|
|
60
|
+
}
|
|
61
|
+
return condition
|
|
62
|
+
.map((c) => `(custom_fields->>'${key}')${castIfNeeded(c.value)} ${c.operator} '${c.value}'`).join(AND_DELIMETER);
|
|
48
63
|
}
|
|
49
|
-
|
|
64
|
+
if (typeof condition === 'string') {
|
|
65
|
+
return `(custom_fields->>'${key}')${castIfNeeded(condition)} = '${condition}'`;
|
|
66
|
+
}
|
|
67
|
+
if (condition?.operator) {
|
|
68
|
+
return `(custom_fields->>'${key}')${castIfNeeded(condition.value)} ${condition.operator} '${condition.value}'`;
|
|
69
|
+
}
|
|
70
|
+
return false;
|
|
50
71
|
},
|
|
51
72
|
)
|
|
52
73
|
.filter(Boolean);
|
|
53
|
-
|
|
54
74
|
if (conditionsStrings.length === 0) {
|
|
55
75
|
return {};
|
|
56
76
|
}
|
|
57
|
-
const customFieldConditions = conditionsStrings.join(
|
|
77
|
+
const customFieldConditions = conditionsStrings.join(AND_DELIMETER);
|
|
58
78
|
|
|
59
79
|
const subQuery = `${'SELECT model_id FROM ('
|
|
60
80
|
+ 'SELECT cv.model_id, jsonb_object_agg(cd.name, cv.value) AS custom_fields '
|
|
@@ -62,8 +82,7 @@ export const customFieldsFilterScope = (
|
|
|
62
82
|
+ 'INNER JOIN custom_field_definitions AS cd ON cv.custom_field_definition_id = cd.id '
|
|
63
83
|
+ `AND cd.model_type = '${name}' `
|
|
64
84
|
+ 'GROUP BY cv.model_id'
|
|
65
|
-
+ ') AS CustomFieldAggregation '
|
|
66
|
-
+ 'WHERE '}${customFieldConditions}`;
|
|
85
|
+
+ ') AS CustomFieldAggregation WHERE '}${customFieldConditions}`;
|
|
67
86
|
|
|
68
87
|
return {
|
|
69
88
|
where: {
|
|
@@ -82,26 +101,20 @@ export const customFieldsSortScope = (
|
|
|
82
101
|
if (!sort || sort.length === 0) {
|
|
83
102
|
return {};
|
|
84
103
|
}
|
|
104
|
+
|
|
105
|
+
console.log('sort', sort);
|
|
106
|
+
console.log('name', name);
|
|
107
|
+
console.log('Object.entries(sort)', Object.entries(sort));
|
|
85
108
|
const includes = Object.entries(sort).map(([key]) =>
|
|
86
|
-
(
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
INNER JOIN custom_field_definitions AS cd
|
|
95
|
-
ON cv.custom_field_definition_id = cd.id
|
|
96
|
-
AND cd.model_type = '${name}'
|
|
97
|
-
WHERE cv.model_id = "${name}"."id"
|
|
98
|
-
GROUP BY cv.model_id
|
|
99
|
-
) AS CustomFieldAggregation
|
|
100
|
-
)`),
|
|
101
|
-
`customFields_${key}`,
|
|
102
|
-
]));
|
|
109
|
+
Sequelize.literal(`(select CustomFieldAggregation.custom_fields->>'${key}'
|
|
110
|
+
from (SELECT cv.model_id, jsonb_object_agg(cd.name, cv.value) AS custom_fields
|
|
111
|
+
FROM custom_field_values AS cv
|
|
112
|
+
INNER JOIN custom_field_definitions AS cd
|
|
113
|
+
ON cv.custom_field_definition_id = cd.id AND cd.model_type = '${name}'
|
|
114
|
+
where cv.model_id = "${name}"."id"
|
|
115
|
+
GROUP BY cv.model_id) AS CustomFieldAggregation) as "customFields.${key}"`));
|
|
116
|
+
const orders = Object.entries(sort).map(([key, value]) => Sequelize.literal(`"customFields.${key}" ${value}`));
|
|
103
117
|
|
|
104
|
-
const orders = Object.entries(sort).map(([key, value]) => Sequelize.literal(`"customFields_${key}" ${value}`));
|
|
105
118
|
return {
|
|
106
119
|
attributes: {
|
|
107
120
|
include: includes,
|