feat: 🎸 Add custom sort support to sql parser (#2959)
* feat: 🎸 Add custom sort support to sql parser * test: 💍 fix column numner * refactor: 💡 apply pr feedback * fix: 🐛 use every method for checking attrs * refactor: 💡 PR feedback + ensure default sort * refactor: 💡 Consolidate attributes field when sorting ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-17441 --------- Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>
This commit is contained in:
1 parent
eab93cf6c5
commit
d414df4ca4
29 files changed
+333
-260
No files matched your search
@@ -33,18 +33,7 @@ export function generateSQLExpressions(
|
||||
addFilterConditions(filters, parameters, conditions);
|
||||
addSearchConditions(search, resource, parameters, conditions);
|
||||
|
||||
const { attribute, direction } = sort;
|
||||
let orderByClause = '';
|
||||
if (attribute) {
|
||||
// We have to check if the attribute is valid for the resource
|
||||
// as we can't use parameterized queries for ORDER BY
|
||||
const validAttributes = Object.keys(modelMapping[resource]);
|
||||
if (validAttributes.includes(attribute)) {
|
||||
orderByClause = `ORDER BY ${attribute} ${direction === 'desc' ? 'DESC' : 'ASC'}`;
|
||||
}
|
||||
} else if (modelMapping[resource]?.created_time) {
|
||||
orderByClause = `ORDER BY created_time DESC`;
|
||||
}
|
||||
const orderByClause = constructOrderByClause(resource, sort);
|
||||
|
||||
const whereClause = conditions.length ? `WHERE ${and(conditions)}` : '';
|
||||
|
||||
@@ -53,7 +42,7 @@ export function generateSQLExpressions(
|
||||
parameters.push(pageSize, (page - 1) * pageSize);
|
||||
}
|
||||
|
||||
const selectClause = `SELECT ${select ? select.join(', ') : '*'} FROM ${resource}`;
|
||||
const selectClause = `SELECT ${select ? select.join(', ') : '*'} FROM "${resource}"`;
|
||||
|
||||
return {
|
||||
// Replace any empty newlines or leading whitespace on each line to be consistent with formatting
|
||||
@@ -145,6 +134,50 @@ function addSearchConditions(search, resource, parameters, conditions) {
|
||||
conditions.push(searchConditions);
|
||||
}
|
||||
|
||||
function constructOrderByClause(resource, sort) {
|
||||
const defaultOrderByClause = 'ORDER BY created_time DESC';
|
||||
|
||||
const { attributes, customSort, direction, isCoalesced } = sort;
|
||||
const sortDirection = direction === 'desc' ? 'DESC' : 'ASC';
|
||||
|
||||
// We have to check if the attributes are valid for the resource
|
||||
// as we can't use parameterized queries for ORDER BY
|
||||
const validAttributes = Object.keys(modelMapping[resource] ?? {});
|
||||
if (attributes?.some((attr) => !validAttributes.includes(attr))) {
|
||||
return modelMapping[resource]?.created_time ? defaultOrderByClause : '';
|
||||
}
|
||||
|
||||
if (customSort?.attributeMap) {
|
||||
const whenClauses = Object.keys(customSort.attributeMap).reduce(
|
||||
(acc, key) => {
|
||||
return acc + `WHEN '${key}' THEN '${customSort.attributeMap[key]}' `;
|
||||
},
|
||||
'',
|
||||
);
|
||||
return `ORDER BY CASE ${attributes.join(', ')} ${whenClauses}END ${sortDirection}`;
|
||||
} else if (attributes?.length > 0) {
|
||||
const commaSeparatedVals = attributes.join(', ');
|
||||
|
||||
// In places where `collate nocase` is used, it is to ensure case is ignored on the initial sort.
|
||||
// Then, a sort on the same condition is performed to ensure upper-case strings are given preference in a tie.
|
||||
if (isCoalesced) {
|
||||
return `ORDER BY COALESCE(${attributes.join(', ')}) COLLATE NOCASE ${sortDirection}, COALESCE(${commaSeparatedVals}) ${sortDirection}`;
|
||||
}
|
||||
|
||||
const attributesWithNoCollate = attributes
|
||||
.map((attr) => `${attr} COLLATE NOCASE ${sortDirection}`)
|
||||
.join(', ');
|
||||
const attributesWithDirection = attributes
|
||||
.map((attr) => `${attr} ${sortDirection}`)
|
||||
.join(', ');
|
||||
return `ORDER BY ${attributesWithNoCollate}, ${attributesWithDirection}`;
|
||||
} else if (modelMapping[resource]?.created_time) {
|
||||
return defaultOrderByClause;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
// Comparison Operators
|
||||
const OPERATORS = {
|
||||
equals: ' = ?',
|
||||
|
||||
Reference in new issue
Block a user