@autofleet/sadot 0.7.0-beta.2 → 0.7.0-beta.2.2
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/repository/value.js +6 -3
- package/dist/scopes/filter.d.ts +6 -6
- package/dist/scopes/filter.js +52 -47
- package/package.json +4 -1
- package/src/repository/value.ts +6 -3
- package/src/scopes/filter.ts +69 -77
package/dist/repository/value.js
CHANGED
|
@@ -73,8 +73,11 @@ exports.findValuesByModelIds = findValuesByModelIds;
|
|
|
73
73
|
*/
|
|
74
74
|
const updateValues = async (modelType, modelId, identifiers, valuesToUpdate, options = {}) => {
|
|
75
75
|
const names = Object.keys(valuesToUpdate);
|
|
76
|
-
logger_1.default.
|
|
77
|
-
names,
|
|
76
|
+
logger_1.default.debug(`custom-fields: updating values for ${modelType} ${modelId}`, {
|
|
77
|
+
names,
|
|
78
|
+
optionsKeys: options ? Object.keys(options) : null,
|
|
79
|
+
valuesToUpdate,
|
|
80
|
+
identifiers,
|
|
78
81
|
});
|
|
79
82
|
const { modelOptions, transaction } = options;
|
|
80
83
|
const where = {
|
|
@@ -87,7 +90,7 @@ const updateValues = async (modelType, modelId, identifiers, valuesToUpdate, opt
|
|
|
87
90
|
const fieldDefinitions = await DefinitionRepo.findAll(where, { withDisabled: true, transaction, include: modelOptions.include?.(identifiers) }) || [];
|
|
88
91
|
const disabledDefinitions = fieldDefinitions.filter((def) => def.disabled);
|
|
89
92
|
if (fieldDefinitions.length !== names.length) {
|
|
90
|
-
logger_1.default.
|
|
93
|
+
logger_1.default.warn(`custom-fields: missing definitions for ${modelType} ${modelId}`, { names, fieldDefinitions });
|
|
91
94
|
const missingDefinitions = names.filter((name) => !fieldDefinitions.some((def) => def.name === name));
|
|
92
95
|
throw new errors_1.MissingDefinitionError(missingDefinitions);
|
|
93
96
|
}
|
package/dist/scopes/filter.d.ts
CHANGED
|
@@ -24,14 +24,14 @@ export type CustomFieldFilterOptions = {
|
|
|
24
24
|
* @param name - The model type name used to join custom_field_definitions.
|
|
25
25
|
* @returns A function that takes conditions and returns the Sequelize options object.
|
|
26
26
|
*/
|
|
27
|
-
export declare const customFieldsFilterScope: (name: string) => ({ replacementsMap
|
|
28
|
-
replacementsMap:
|
|
29
|
-
scopeValue:
|
|
27
|
+
export declare const customFieldsFilterScope: (name: string) => ({ replacementsMap, scopeValue }: {
|
|
28
|
+
replacementsMap: any;
|
|
29
|
+
scopeValue: any;
|
|
30
30
|
}) => CustomFieldFilterOptions;
|
|
31
31
|
export declare const scopeName = "filterByCustomFields";
|
|
32
32
|
export declare const customFieldsSortScope: (name: string) => ({ replacementsMap, scopeValue: sort }: {
|
|
33
|
-
replacementsMap:
|
|
34
|
-
scopeValue:
|
|
33
|
+
replacementsMap: any;
|
|
34
|
+
scopeValue: any;
|
|
35
35
|
}) => {
|
|
36
36
|
attributes?: undefined;
|
|
37
37
|
order?: undefined;
|
|
@@ -41,6 +41,6 @@ export declare const customFieldsSortScope: (name: string) => ({ replacementsMap
|
|
|
41
41
|
include: (string | import("sequelize/types/utils").Literal)[][];
|
|
42
42
|
};
|
|
43
43
|
order: import("sequelize/types/utils").Literal[];
|
|
44
|
-
replacements:
|
|
44
|
+
replacements: any;
|
|
45
45
|
};
|
|
46
46
|
export {};
|
package/dist/scopes/filter.js
CHANGED
|
@@ -21,36 +21,6 @@ const castIfNeeded = (conditionValue) => {
|
|
|
21
21
|
return '';
|
|
22
22
|
};
|
|
23
23
|
const AND_DELIMETER = ' AND ';
|
|
24
|
-
/**
|
|
25
|
-
* Helper function to build condition strings for the WHERE clause.
|
|
26
|
-
*/
|
|
27
|
-
// eslint-disable-next-line max-len
|
|
28
|
-
const buildConditionString = (key, condition, replacements) => {
|
|
29
|
-
const replacementKey = Object.keys(replacements).find((randomString) => replacements[randomString] === key);
|
|
30
|
-
if (!replacementKey)
|
|
31
|
-
return false;
|
|
32
|
-
if (Array.isArray(condition)) {
|
|
33
|
-
if (condition.length === 0)
|
|
34
|
-
return false;
|
|
35
|
-
if (typeof condition[0] === 'string') {
|
|
36
|
-
const values = condition.map((v) => `:${replacements[v]}`).join(',');
|
|
37
|
-
return `(custom_fields->> :${replacementKey}) IN (${values})`;
|
|
38
|
-
}
|
|
39
|
-
return condition.map((c) => {
|
|
40
|
-
const valRep = replacements[c.value];
|
|
41
|
-
return `(custom_fields->> :${replacementKey})${castIfNeeded(c.value)} ${c.operator} :${valRep}`;
|
|
42
|
-
}).join(AND_DELIMETER);
|
|
43
|
-
}
|
|
44
|
-
if (typeof condition === 'string') {
|
|
45
|
-
const conditionRep = replacements[condition];
|
|
46
|
-
return `(custom_fields->> :${replacementKey}) ${castIfNeeded(condition)} = :${conditionRep}`;
|
|
47
|
-
}
|
|
48
|
-
if (condition?.operator) {
|
|
49
|
-
const valueRep = replacements[condition.value];
|
|
50
|
-
return `(custom_fields->> :${replacementKey}) ${castIfNeeded(condition.value)} ${condition.operator} :${valueRep}`;
|
|
51
|
-
}
|
|
52
|
-
return false;
|
|
53
|
-
};
|
|
54
24
|
/**
|
|
55
25
|
* A Sequelize scope for filtering models by custom fields.
|
|
56
26
|
* This scope builds a WHERE clause to be applied on the main query.
|
|
@@ -58,16 +28,51 @@ const buildConditionString = (key, condition, replacements) => {
|
|
|
58
28
|
* @param name - The model type name used to join custom_field_definitions.
|
|
59
29
|
* @returns A function that takes conditions and returns the Sequelize options object.
|
|
60
30
|
*/
|
|
61
|
-
const customFieldsFilterScope = (name) => ({ replacementsMap
|
|
31
|
+
const customFieldsFilterScope = (name) => ({ replacementsMap, scopeValue }) => {
|
|
32
|
+
const conditions = scopeValue;
|
|
33
|
+
const replacements = replacementsMap;
|
|
62
34
|
if (!conditions || Object.keys(conditions).length === 0) {
|
|
63
35
|
return {};
|
|
64
36
|
}
|
|
65
37
|
// Build the WHERE clause for custom field filtering
|
|
66
38
|
const conditionsStrings = Object.entries(conditions)
|
|
67
|
-
.map(([key, condition]) =>
|
|
39
|
+
.map(([key, condition]) => {
|
|
40
|
+
const replacemetKey = Object.keys(replacements).find((randomString) => replacements[randomString] === key);
|
|
41
|
+
if (!replacemetKey)
|
|
42
|
+
return false;
|
|
43
|
+
if (Array.isArray(condition)) {
|
|
44
|
+
if (condition.length === 0) {
|
|
45
|
+
// if empty array, the condition is ignored
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
if (typeof condition[0] === 'string') {
|
|
49
|
+
const values = condition.map((v) => {
|
|
50
|
+
const valRandom = Object.keys(replacements).find((randomString) => replacements[randomString] === v);
|
|
51
|
+
return ` :${valRandom} `;
|
|
52
|
+
}).join(',');
|
|
53
|
+
return `(custom_fields->> :${replacemetKey} ) IN ( ${values} )`;
|
|
54
|
+
}
|
|
55
|
+
return condition
|
|
56
|
+
.map((c) => {
|
|
57
|
+
const valRep = Object.keys(replacements).find((key) => replacements[key] === c.value);
|
|
58
|
+
return `(custom_fields->> :${replacemetKey} )${castIfNeeded(c.value)} ${c.operator} :${valRep}`;
|
|
59
|
+
}).join(AND_DELIMETER);
|
|
60
|
+
}
|
|
61
|
+
if (typeof condition === 'string') {
|
|
62
|
+
const conditionRep = Object.keys(replacements).find((key) => replacements[key] === condition);
|
|
63
|
+
return `(custom_fields->> :${replacemetKey} ) ${castIfNeeded(condition)} = :${conditionRep}`;
|
|
64
|
+
}
|
|
65
|
+
if (condition?.operator) {
|
|
66
|
+
const valueRep = Object.keys(replacements).find((key) => replacements[key] === condition.value);
|
|
67
|
+
return `(custom_fields->> :${replacemetKey} ) ${castIfNeeded(condition.value)} ${condition.operator} :${valueRep}`;
|
|
68
|
+
}
|
|
69
|
+
return false;
|
|
70
|
+
})
|
|
68
71
|
.filter(Boolean);
|
|
69
72
|
if (conditionsStrings.length === 0) {
|
|
70
|
-
return {
|
|
73
|
+
return {
|
|
74
|
+
replacements,
|
|
75
|
+
};
|
|
71
76
|
}
|
|
72
77
|
const customFieldConditions = conditionsStrings.join(AND_DELIMETER);
|
|
73
78
|
const subQuery = `${'SELECT model_id FROM ('
|
|
@@ -94,21 +99,21 @@ const customFieldsSortScope = (name) => ({ replacementsMap, scopeValue: sort })
|
|
|
94
99
|
}
|
|
95
100
|
const randomStr = (0, helpers_1.generateRandomString)();
|
|
96
101
|
const includes = Object.entries(sort).map(([key]) => {
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
return [
|
|
102
|
+
const replacemetKey = Object.keys(replacementsMap).find((randomString) => replacementsMap[randomString] === key);
|
|
103
|
+
console.log('sort replacemetKey:', replacemetKey);
|
|
104
|
+
return ([
|
|
100
105
|
sequelize_typescript_1.Sequelize.literal(`(
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
];
|
|
106
|
+
SELECT value
|
|
107
|
+
FROM (SELECT cv.model_id, cv.value
|
|
108
|
+
FROM custom_field_values AS cv INNER JOIN custom_field_definitions AS cd
|
|
109
|
+
ON cv.custom_field_definition_id = cd.id
|
|
110
|
+
AND cd.model_type = '${name}'
|
|
111
|
+
WHERE cv.model_id = "${name}"."id"
|
|
112
|
+
AND cd.name = :${replacemetKey}
|
|
113
|
+
) AS CustomFieldAggregation
|
|
114
|
+
)
|
|
115
|
+
`), randomStr,
|
|
116
|
+
]);
|
|
112
117
|
});
|
|
113
118
|
const orders = Object.entries(sort).map(([, value]) => sequelize_typescript_1.Sequelize.literal(`"${randomStr}" ${value}`));
|
|
114
119
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@autofleet/sadot",
|
|
3
|
-
"version": "0.7.0-beta.2",
|
|
3
|
+
"version": "0.7.0-beta.2.2",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -62,6 +62,9 @@
|
|
|
62
62
|
"peerDependencies": {
|
|
63
63
|
"@autofleet/sheilta": ">=1.4.0-beta.2"
|
|
64
64
|
},
|
|
65
|
+
"engines": {
|
|
66
|
+
"node": ">=16.0.0"
|
|
67
|
+
},
|
|
65
68
|
"author": "Autofleet",
|
|
66
69
|
"license": "ISC"
|
|
67
70
|
}
|
package/src/repository/value.ts
CHANGED
|
@@ -55,8 +55,11 @@ export const updateValues = async (
|
|
|
55
55
|
options: FindOptions & { modelOptions?: ModelOptions } = {},
|
|
56
56
|
): Promise<CustomFieldValue[]> => {
|
|
57
57
|
const names = Object.keys(valuesToUpdate);
|
|
58
|
-
logger.
|
|
59
|
-
names,
|
|
58
|
+
logger.debug(`custom-fields: updating values for ${modelType} ${modelId}`, {
|
|
59
|
+
names,
|
|
60
|
+
optionsKeys: options ? Object.keys(options) : null,
|
|
61
|
+
valuesToUpdate,
|
|
62
|
+
identifiers,
|
|
60
63
|
});
|
|
61
64
|
const { modelOptions, transaction } = options;
|
|
62
65
|
|
|
@@ -72,7 +75,7 @@ export const updateValues = async (
|
|
|
72
75
|
|
|
73
76
|
const disabledDefinitions = fieldDefinitions.filter((def) => def.disabled);
|
|
74
77
|
if (fieldDefinitions.length !== names.length) {
|
|
75
|
-
logger.
|
|
78
|
+
logger.warn(`custom-fields: missing definitions for ${modelType} ${modelId}`, { names, fieldDefinitions });
|
|
76
79
|
const missingDefinitions = names.filter((name) => !fieldDefinitions.some((def) => def.name === name));
|
|
77
80
|
throw new MissingDefinitionError(missingDefinitions);
|
|
78
81
|
}
|
package/src/scopes/filter.ts
CHANGED
|
@@ -13,67 +13,31 @@ const { CUSTOM_FIELDS_FILTER_SCOPE } = customFields;
|
|
|
13
13
|
* More types to be added (TBA).
|
|
14
14
|
*/
|
|
15
15
|
type ConditionWithOperator = {
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
operator: string;
|
|
17
|
+
value: string;
|
|
18
18
|
};
|
|
19
19
|
export type ConditionValue = ConditionWithOperator | ConditionWithOperator[] | string | string[];
|
|
20
20
|
|
|
21
21
|
export type CustomFieldSort = {
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
field: string;
|
|
23
|
+
direction: 'ASC' | 'DESC';
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
export type CustomFieldFilterOptions = {
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
where?: WhereOptions;
|
|
28
|
+
replacements?: Record<string, string>;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
const castIfNeeded = (conditionValue: string): string => {
|
|
32
32
|
if (moment.isDate(conditionValue)) {
|
|
33
33
|
return '::timestamp';
|
|
34
|
-
}
|
|
35
|
-
if (!Number.isNaN(Number(conditionValue))) {
|
|
34
|
+
} if (!Number.isNaN(Number(conditionValue))) {
|
|
36
35
|
return '::numeric';
|
|
37
36
|
}
|
|
38
37
|
return '';
|
|
39
38
|
};
|
|
40
39
|
const AND_DELIMETER = ' AND ';
|
|
41
40
|
|
|
42
|
-
/**
|
|
43
|
-
* Helper function to build condition strings for the WHERE clause.
|
|
44
|
-
*/
|
|
45
|
-
// eslint-disable-next-line max-len
|
|
46
|
-
const buildConditionString = (key: string, condition: ConditionValue | ConditionValue[], replacements: Record<string, string>): string | false => {
|
|
47
|
-
const replacementKey = Object.keys(replacements).find((randomString) => replacements[randomString] === key);
|
|
48
|
-
if (!replacementKey) return false;
|
|
49
|
-
|
|
50
|
-
if (Array.isArray(condition)) {
|
|
51
|
-
if (condition.length === 0) return false;
|
|
52
|
-
|
|
53
|
-
if (typeof condition[0] === 'string') {
|
|
54
|
-
const values = condition.map((v) => `:${replacements[v]}`).join(',');
|
|
55
|
-
return `(custom_fields->> :${replacementKey}) IN (${values})`;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return condition.map((c) => {
|
|
59
|
-
const valRep = replacements[c.value];
|
|
60
|
-
return `(custom_fields->> :${replacementKey})${castIfNeeded(c.value)} ${c.operator} :${valRep}`;
|
|
61
|
-
}).join(AND_DELIMETER);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (typeof condition === 'string') {
|
|
65
|
-
const conditionRep = replacements[condition];
|
|
66
|
-
return `(custom_fields->> :${replacementKey}) ${castIfNeeded(condition)} = :${conditionRep}`;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (condition?.operator) {
|
|
70
|
-
const valueRep = replacements[condition.value];
|
|
71
|
-
return `(custom_fields->> :${replacementKey}) ${castIfNeeded(condition.value)} ${condition.operator} :${valueRep}`;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return false;
|
|
75
|
-
};
|
|
76
|
-
|
|
77
41
|
/**
|
|
78
42
|
* A Sequelize scope for filtering models by custom fields.
|
|
79
43
|
* This scope builds a WHERE clause to be applied on the main query.
|
|
@@ -83,33 +47,62 @@ const buildConditionString = (key: string, condition: ConditionValue | Condition
|
|
|
83
47
|
*/
|
|
84
48
|
export const customFieldsFilterScope = (
|
|
85
49
|
name: string,
|
|
86
|
-
) => (
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
scopeValue: conditions,
|
|
90
|
-
}: { replacementsMap: Record<string, string>, scopeValue: Record<string, ConditionValue> },
|
|
91
|
-
): CustomFieldFilterOptions => {
|
|
50
|
+
) => ({ replacementsMap, scopeValue }): CustomFieldFilterOptions => {
|
|
51
|
+
const conditions: Record<string, ConditionValue> = scopeValue;
|
|
52
|
+
const replacements: Record<string, string> = replacementsMap;
|
|
92
53
|
if (!conditions || Object.keys(conditions).length === 0) {
|
|
93
54
|
return {};
|
|
94
55
|
}
|
|
95
|
-
|
|
96
56
|
// Build the WHERE clause for custom field filtering
|
|
97
57
|
const conditionsStrings = Object.entries(conditions)
|
|
98
|
-
.map(
|
|
99
|
-
|
|
100
|
-
|
|
58
|
+
.map(
|
|
59
|
+
([key, condition]) => {
|
|
60
|
+
const replacemetKey = Object.keys(replacements).find((randomString) => replacements[randomString] === key);
|
|
61
|
+
if (!replacemetKey) return false;
|
|
62
|
+
|
|
63
|
+
if (Array.isArray(condition)) {
|
|
64
|
+
if (condition.length === 0) {
|
|
65
|
+
// if empty array, the condition is ignored
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
if (typeof condition[0] === 'string') {
|
|
69
|
+
const values = condition.map((v) => {
|
|
70
|
+
const valRandom = Object.keys(replacements).find((randomString) => replacements[randomString] === v);
|
|
71
|
+
return ` :${valRandom} `;
|
|
72
|
+
}).join(',');
|
|
73
|
+
return `(custom_fields->> :${replacemetKey} ) IN ( ${values} )`;
|
|
74
|
+
}
|
|
75
|
+
return condition
|
|
76
|
+
.map((c) => {
|
|
77
|
+
const valRep = Object.keys(replacements).find((key) => replacements[key] === c.value);
|
|
78
|
+
return `(custom_fields->> :${replacemetKey} )${castIfNeeded(c.value)} ${c.operator} :${valRep}`;
|
|
79
|
+
}).join(AND_DELIMETER);
|
|
80
|
+
}
|
|
81
|
+
if (typeof condition === 'string') {
|
|
82
|
+
const conditionRep = Object.keys(replacements).find((key) => replacements[key] === condition);
|
|
83
|
+
return `(custom_fields->> :${replacemetKey} ) ${castIfNeeded(condition)} = :${conditionRep}`;
|
|
84
|
+
}
|
|
85
|
+
if (condition?.operator) {
|
|
86
|
+
const valueRep = Object.keys(replacements).find((key) => replacements[key] === condition.value);
|
|
87
|
+
return `(custom_fields->> :${replacemetKey} ) ${castIfNeeded(condition.value)} ${condition.operator} :${valueRep}`;
|
|
88
|
+
}
|
|
89
|
+
return false;
|
|
90
|
+
},
|
|
91
|
+
)
|
|
92
|
+
.filter(Boolean);
|
|
101
93
|
if (conditionsStrings.length === 0) {
|
|
102
|
-
return {
|
|
94
|
+
return {
|
|
95
|
+
replacements,
|
|
96
|
+
};
|
|
103
97
|
}
|
|
104
|
-
|
|
105
98
|
const customFieldConditions = conditionsStrings.join(AND_DELIMETER);
|
|
106
99
|
const subQuery = `${'SELECT model_id FROM ('
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
100
|
+
+ 'SELECT cv.model_id, jsonb_object_agg(cd.name, cv.value) AS custom_fields '
|
|
101
|
+
+ 'FROM custom_field_values AS cv '
|
|
102
|
+
+ 'INNER JOIN custom_field_definitions AS cd ON cv.custom_field_definition_id = cd.id '
|
|
103
|
+
+ `AND cd.model_type = '${name}'`
|
|
104
|
+
+ 'GROUP BY cv.model_id'
|
|
105
|
+
+ ') AS CustomFieldAggregation WHERE '} ${customFieldConditions}`;
|
|
113
106
|
return {
|
|
114
107
|
where: {
|
|
115
108
|
id: {
|
|
@@ -124,28 +117,27 @@ export const scopeName = CUSTOM_FIELDS_FILTER_SCOPE;
|
|
|
124
117
|
|
|
125
118
|
export const customFieldsSortScope = (
|
|
126
119
|
name: string,
|
|
127
|
-
) => ({ replacementsMap, scopeValue: sort }
|
|
120
|
+
) => ({ replacementsMap, scopeValue: sort }) => {
|
|
128
121
|
if (!sort || sort.length === 0) {
|
|
129
122
|
return {};
|
|
130
123
|
}
|
|
131
|
-
|
|
132
124
|
const randomStr = generateRandomString();
|
|
133
125
|
const includes = Object.entries(sort).map(([key]) => {
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
return [
|
|
126
|
+
const replacemetKey = Object.keys(replacementsMap).find((randomString) => replacementsMap[randomString] === key);
|
|
127
|
+
console.log('sort replacemetKey:', replacemetKey);
|
|
128
|
+
return ([
|
|
137
129
|
Sequelize.literal(`(
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
];
|
|
130
|
+
SELECT value
|
|
131
|
+
FROM (SELECT cv.model_id, cv.value
|
|
132
|
+
FROM custom_field_values AS cv INNER JOIN custom_field_definitions AS cd
|
|
133
|
+
ON cv.custom_field_definition_id = cd.id
|
|
134
|
+
AND cd.model_type = '${name}'
|
|
135
|
+
WHERE cv.model_id = "${name}"."id"
|
|
136
|
+
AND cd.name = :${replacemetKey}
|
|
137
|
+
) AS CustomFieldAggregation
|
|
138
|
+
)
|
|
139
|
+
`), randomStr,
|
|
140
|
+
]);
|
|
149
141
|
});
|
|
150
142
|
|
|
151
143
|
const orders = Object.entries(sort).map(([, value]) => Sequelize.literal(`"${randomStr}" ${value}`));
|