@autofleet/sadot 0.7.0-beta.1 → 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/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, scopeValue }: {
|
|
28
|
-
replacementsMap:
|
|
29
|
-
scopeValue:
|
|
27
|
+
export declare const customFieldsFilterScope: (name: string) => ({ replacementsMap: replacements, scopeValue: conditions, }: {
|
|
28
|
+
replacementsMap: Record<string, string>;
|
|
29
|
+
scopeValue: Record<string, ConditionValue>;
|
|
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: Record<string, string>;
|
|
34
|
+
scopeValue: string[];
|
|
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: Record<string, string>;
|
|
45
45
|
};
|
|
46
46
|
export {};
|
package/dist/scopes/filter.js
CHANGED
|
@@ -21,6 +21,36 @@ 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
|
+
};
|
|
24
54
|
/**
|
|
25
55
|
* A Sequelize scope for filtering models by custom fields.
|
|
26
56
|
* This scope builds a WHERE clause to be applied on the main query.
|
|
@@ -28,52 +58,16 @@ const AND_DELIMETER = ' AND ';
|
|
|
28
58
|
* @param name - The model type name used to join custom_field_definitions.
|
|
29
59
|
* @returns A function that takes conditions and returns the Sequelize options object.
|
|
30
60
|
*/
|
|
31
|
-
const customFieldsFilterScope = (name) => ({ replacementsMap, scopeValue }) => {
|
|
32
|
-
const conditions = scopeValue;
|
|
33
|
-
const replacements = replacementsMap;
|
|
34
|
-
console.log('filter replacementsMap:', replacements);
|
|
61
|
+
const customFieldsFilterScope = (name) => ({ replacementsMap: replacements, scopeValue: conditions, }) => {
|
|
35
62
|
if (!conditions || Object.keys(conditions).length === 0) {
|
|
36
63
|
return {};
|
|
37
64
|
}
|
|
38
65
|
// Build the WHERE clause for custom field filtering
|
|
39
66
|
const conditionsStrings = Object.entries(conditions)
|
|
40
|
-
.map(([key, condition]) =>
|
|
41
|
-
const replacemetKey = Object.keys(replacements).find((randomString) => replacements[randomString] === key);
|
|
42
|
-
if (!replacemetKey)
|
|
43
|
-
return false;
|
|
44
|
-
if (Array.isArray(condition)) {
|
|
45
|
-
if (condition.length === 0) {
|
|
46
|
-
// if empty array, the condition is ignored
|
|
47
|
-
return false;
|
|
48
|
-
}
|
|
49
|
-
if (typeof condition[0] === 'string') {
|
|
50
|
-
const values = condition.map((v) => {
|
|
51
|
-
const valRandom = Object.keys(replacements).find((randomString) => replacements[randomString] === v);
|
|
52
|
-
return ` :${valRandom} `;
|
|
53
|
-
}).join(',');
|
|
54
|
-
return `(custom_fields->> :${replacemetKey} ) IN ( ${values} )`;
|
|
55
|
-
}
|
|
56
|
-
return condition
|
|
57
|
-
.map((c) => {
|
|
58
|
-
const valRep = Object.keys(replacements).find((key) => replacements[key] === c.value);
|
|
59
|
-
return `(custom_fields->> :${replacemetKey} )${castIfNeeded(c.value)} ${c.operator} :${valRep}`;
|
|
60
|
-
}).join(AND_DELIMETER);
|
|
61
|
-
}
|
|
62
|
-
if (typeof condition === 'string') {
|
|
63
|
-
const conditionRep = Object.keys(replacements).find((key) => replacements[key] === condition);
|
|
64
|
-
return `(custom_fields->> :${replacemetKey} ) ${castIfNeeded(condition)} = :${conditionRep}`;
|
|
65
|
-
}
|
|
66
|
-
if (condition?.operator) {
|
|
67
|
-
const valueRep = Object.keys(replacements).find((key) => replacements[key] === condition.value);
|
|
68
|
-
return `(custom_fields->> :${replacemetKey} ) ${castIfNeeded(condition.value)} ${condition.operator} :${valueRep}`;
|
|
69
|
-
}
|
|
70
|
-
return false;
|
|
71
|
-
})
|
|
67
|
+
.map(([key, condition]) => buildConditionString(key, condition, replacements))
|
|
72
68
|
.filter(Boolean);
|
|
73
69
|
if (conditionsStrings.length === 0) {
|
|
74
|
-
return {
|
|
75
|
-
replacements,
|
|
76
|
-
};
|
|
70
|
+
return { replacements };
|
|
77
71
|
}
|
|
78
72
|
const customFieldConditions = conditionsStrings.join(AND_DELIMETER);
|
|
79
73
|
const subQuery = `${'SELECT model_id FROM ('
|
|
@@ -100,21 +94,21 @@ const customFieldsSortScope = (name) => ({ replacementsMap, scopeValue: sort })
|
|
|
100
94
|
}
|
|
101
95
|
const randomStr = (0, helpers_1.generateRandomString)();
|
|
102
96
|
const includes = Object.entries(sort).map(([key]) => {
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
return
|
|
97
|
+
const replacementKey = Object.keys(replacementsMap)
|
|
98
|
+
.find((randomString) => replacementsMap[randomString] === key);
|
|
99
|
+
return [
|
|
106
100
|
sequelize_typescript_1.Sequelize.literal(`(
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
]
|
|
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
|
+
];
|
|
118
112
|
});
|
|
119
113
|
const orders = Object.entries(sort).map(([, value]) => sequelize_typescript_1.Sequelize.literal(`"${randomStr}" ${value}`));
|
|
120
114
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@autofleet/sadot",
|
|
3
|
-
"version": "0.7.0-beta.
|
|
3
|
+
"version": "0.7.0-beta.2",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"linter": "./node_modules/.bin/eslint .",
|
|
10
10
|
"test": "jest --forceExit --runInBand",
|
|
11
11
|
"coverage": "jest --coverage --forceExit --runInBand && rm -rf ./coverage",
|
|
12
|
-
"build-to-local-repo": "npm run build && cp -r dist/*
|
|
12
|
+
"build-to-local-repo": "npm run build && cp -r dist/* ../$REPO/node_modules/$npm_package_name/dist",
|
|
13
13
|
"dev": "nodemon",
|
|
14
14
|
"watch": "npm-watch build-to-local-repo",
|
|
15
15
|
"publish-dev": "npm run build && npm publish --tag dev"
|
|
@@ -59,6 +59,9 @@
|
|
|
59
59
|
"typescript": "^5.3.3",
|
|
60
60
|
"typescript-eslint": "^0.0.1-alpha.0"
|
|
61
61
|
},
|
|
62
|
+
"peerDependencies": {
|
|
63
|
+
"@autofleet/sheilta": ">=1.4.0-beta.2"
|
|
64
|
+
},
|
|
62
65
|
"author": "Autofleet",
|
|
63
66
|
"license": "ISC"
|
|
64
67
|
}
|
package/src/scopes/filter.ts
CHANGED
|
@@ -31,13 +31,49 @@ 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
41
|
|
|
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
|
+
|
|
41
77
|
/**
|
|
42
78
|
* A Sequelize scope for filtering models by custom fields.
|
|
43
79
|
* This scope builds a WHERE clause to be applied on the main query.
|
|
@@ -47,55 +83,25 @@ const AND_DELIMETER = ' AND ';
|
|
|
47
83
|
*/
|
|
48
84
|
export const customFieldsFilterScope = (
|
|
49
85
|
name: string,
|
|
50
|
-
) => (
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
86
|
+
) => (
|
|
87
|
+
{
|
|
88
|
+
replacementsMap: replacements,
|
|
89
|
+
scopeValue: conditions,
|
|
90
|
+
}: { replacementsMap: Record<string, string>, scopeValue: Record<string, ConditionValue> },
|
|
91
|
+
): CustomFieldFilterOptions => {
|
|
54
92
|
if (!conditions || Object.keys(conditions).length === 0) {
|
|
55
93
|
return {};
|
|
56
94
|
}
|
|
95
|
+
|
|
57
96
|
// Build the WHERE clause for custom field filtering
|
|
58
97
|
const conditionsStrings = Object.entries(conditions)
|
|
59
|
-
.map(
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (!replacemetKey) return false;
|
|
63
|
-
|
|
64
|
-
if (Array.isArray(condition)) {
|
|
65
|
-
if (condition.length === 0) {
|
|
66
|
-
// if empty array, the condition is ignored
|
|
67
|
-
return false;
|
|
68
|
-
}
|
|
69
|
-
if (typeof condition[0] === 'string') {
|
|
70
|
-
const values = condition.map((v) => {
|
|
71
|
-
const valRandom = Object.keys(replacements).find((randomString) => replacements[randomString] === v);
|
|
72
|
-
return ` :${valRandom} `;
|
|
73
|
-
}).join(',');
|
|
74
|
-
return `(custom_fields->> :${replacemetKey} ) IN ( ${values} )`;
|
|
75
|
-
}
|
|
76
|
-
return condition
|
|
77
|
-
.map((c) => {
|
|
78
|
-
const valRep = Object.keys(replacements).find((key) => replacements[key] === c.value);
|
|
79
|
-
return `(custom_fields->> :${replacemetKey} )${castIfNeeded(c.value)} ${c.operator} :${valRep}`;
|
|
80
|
-
}).join(AND_DELIMETER);
|
|
81
|
-
}
|
|
82
|
-
if (typeof condition === 'string') {
|
|
83
|
-
const conditionRep = Object.keys(replacements).find((key) => replacements[key] === condition);
|
|
84
|
-
return `(custom_fields->> :${replacemetKey} ) ${castIfNeeded(condition)} = :${conditionRep}`;
|
|
85
|
-
}
|
|
86
|
-
if (condition?.operator) {
|
|
87
|
-
const valueRep = Object.keys(replacements).find((key) => replacements[key] === condition.value);
|
|
88
|
-
return `(custom_fields->> :${replacemetKey} ) ${castIfNeeded(condition.value)} ${condition.operator} :${valueRep}`;
|
|
89
|
-
}
|
|
90
|
-
return false;
|
|
91
|
-
},
|
|
92
|
-
)
|
|
93
|
-
.filter(Boolean);
|
|
98
|
+
.map(([key, condition]) => buildConditionString(key, condition, replacements))
|
|
99
|
+
.filter(Boolean) as string[];
|
|
100
|
+
|
|
94
101
|
if (conditionsStrings.length === 0) {
|
|
95
|
-
return {
|
|
96
|
-
replacements,
|
|
97
|
-
};
|
|
102
|
+
return { replacements };
|
|
98
103
|
}
|
|
104
|
+
|
|
99
105
|
const customFieldConditions = conditionsStrings.join(AND_DELIMETER);
|
|
100
106
|
const subQuery = `${'SELECT model_id FROM ('
|
|
101
107
|
+ 'SELECT cv.model_id, jsonb_object_agg(cd.name, cv.value) AS custom_fields '
|
|
@@ -118,27 +124,28 @@ export const scopeName = CUSTOM_FIELDS_FILTER_SCOPE;
|
|
|
118
124
|
|
|
119
125
|
export const customFieldsSortScope = (
|
|
120
126
|
name: string,
|
|
121
|
-
) => ({ replacementsMap, scopeValue: sort }) => {
|
|
127
|
+
) => ({ replacementsMap, scopeValue: sort }: { replacementsMap: Record<string, string>, scopeValue: string[] }) => {
|
|
122
128
|
if (!sort || sort.length === 0) {
|
|
123
129
|
return {};
|
|
124
130
|
}
|
|
131
|
+
|
|
125
132
|
const randomStr = generateRandomString();
|
|
126
133
|
const includes = Object.entries(sort).map(([key]) => {
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
return
|
|
134
|
+
const replacementKey = Object.keys(replacementsMap)
|
|
135
|
+
.find((randomString) => replacementsMap[randomString] === key);
|
|
136
|
+
return [
|
|
130
137
|
Sequelize.literal(`(
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
]
|
|
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
|
+
];
|
|
142
149
|
});
|
|
143
150
|
|
|
144
151
|
const orders = Object.entries(sort).map(([, value]) => Sequelize.literal(`"${randomStr}" ${value}`));
|