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