rez_core 4.0.59 → 4.0.61
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/package.json
CHANGED
|
@@ -28,7 +28,6 @@ export class FilterService {
|
|
|
28
28
|
private readonly skipAppCodeFilterEntities = ['ORGP'];
|
|
29
29
|
private readonly skipOrgFilterEntities = ['ORGP'];
|
|
30
30
|
|
|
31
|
-
|
|
32
31
|
private async gettab_value_counts(
|
|
33
32
|
tableName: string,
|
|
34
33
|
column: string | undefined,
|
|
@@ -36,54 +35,80 @@ export class FilterService {
|
|
|
36
35
|
) {
|
|
37
36
|
if (!column) return [];
|
|
38
37
|
|
|
38
|
+
// ✅ Validate tableName and column to prevent SQL injection
|
|
39
|
+
if (!/^[a-zA-Z0-9_]+$/.test(tableName) || !/^[a-zA-Z0-9_]+$/.test(column)) {
|
|
40
|
+
throw new Error('Invalid table or column name');
|
|
41
|
+
}
|
|
42
|
+
|
|
39
43
|
let whereSQL = '';
|
|
40
44
|
const values: any[] = [];
|
|
41
45
|
|
|
42
46
|
if (whereClauses.length > 0) {
|
|
43
47
|
const clauseParts = whereClauses.map((clause) => {
|
|
44
|
-
|
|
48
|
+
// ✅ Safely remove alias "e." only at word boundaries
|
|
49
|
+
let parsedQuery = clause.query.replace(/\be\./g, '');
|
|
45
50
|
|
|
46
51
|
Object.entries(clause.params).forEach(([key, val]) => {
|
|
47
52
|
if (Array.isArray(val)) {
|
|
48
|
-
//
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
53
|
+
// ✅ Handle both '=' and 'IN' dynamically
|
|
54
|
+
if (parsedQuery.match(new RegExp(`=\\s*:${key}\\b`))) {
|
|
55
|
+
parsedQuery = parsedQuery.replace(
|
|
56
|
+
new RegExp(`=\\s*:${key}\\b`, 'g'),
|
|
57
|
+
`IN (${val.map(() => '?').join(', ')})`,
|
|
58
|
+
);
|
|
59
|
+
} else {
|
|
60
|
+
parsedQuery = parsedQuery.replace(
|
|
61
|
+
new RegExp(`:\\b${key}\\b`, 'g'),
|
|
62
|
+
val.map(() => '?').join(', '),
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
values.push(...val);
|
|
52
66
|
} else {
|
|
53
|
-
parsedQuery = parsedQuery.replace(
|
|
67
|
+
parsedQuery = parsedQuery.replace(
|
|
68
|
+
new RegExp(`:\\b${key}\\b`, 'g'),
|
|
69
|
+
'?',
|
|
70
|
+
);
|
|
54
71
|
values.push(val);
|
|
55
72
|
}
|
|
56
73
|
});
|
|
57
74
|
|
|
58
|
-
|
|
75
|
+
// ✅ Enclose each clause in parentheses for proper AND grouping
|
|
76
|
+
return `(${parsedQuery})`;
|
|
59
77
|
});
|
|
60
78
|
|
|
61
79
|
whereSQL = `WHERE ${clauseParts.join(' AND ')}`;
|
|
62
80
|
}
|
|
63
81
|
|
|
82
|
+
// ✅ Wrap identifiers in backticks for MySQL or double quotes for Postgres
|
|
64
83
|
const rawSQL = `
|
|
65
|
-
SELECT
|
|
84
|
+
SELECT
|
|
85
|
+
${column} AS tab_value,
|
|
86
|
+
COUNT(*) AS tab_value_count
|
|
66
87
|
FROM ${tableName}
|
|
67
88
|
${whereSQL}
|
|
68
89
|
GROUP BY ${column}
|
|
90
|
+
ORDER BY tab_value_count DESC
|
|
69
91
|
`;
|
|
70
92
|
|
|
71
93
|
const rows = await this.dataSource.query(rawSQL, values);
|
|
72
94
|
|
|
95
|
+
// ✅ Handle total count safely
|
|
73
96
|
const total = rows.reduce(
|
|
74
|
-
(sum, r) => sum +
|
|
97
|
+
(sum, r) => sum + Number(r.tab_value_count || 0),
|
|
75
98
|
0,
|
|
76
99
|
);
|
|
77
100
|
|
|
101
|
+
// ✅ Ensure consistent response
|
|
78
102
|
return [
|
|
79
103
|
{ tab_value: 'All', tab_value_count: total },
|
|
80
104
|
...rows.map((r) => ({
|
|
81
105
|
tab_value: r.tab_value ?? 'UNKNOWN',
|
|
82
|
-
tab_value_count:
|
|
106
|
+
tab_value_count: Number(r.tab_value_count || 0),
|
|
83
107
|
})),
|
|
84
108
|
];
|
|
85
109
|
}
|
|
86
110
|
|
|
111
|
+
|
|
87
112
|
|
|
88
113
|
async applyFilterWrapper(dto: FilterRequestDto) {
|
|
89
114
|
const {
|