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:
Lisbet AlvarezandZhihe Li authored and Zhihe Li committed 2025-09-03 11:41:41 -04:00
1 parent eab93cf6c5
commit d414df4ca4
29 files changed
+333 -260

No files matched your search

@@ -28,7 +28,7 @@ module('Unit | Utility | sqlite-query', function (hooks) {
assert.strictEqual(
sql,
`
SELECT * FROM target
SELECT * FROM "target"
WHERE rowid IN (SELECT rowid FROM target_fts WHERE target_fts MATCH ?)
ORDER BY created_time DESC`.removeExtraWhiteSpace(),
);
@@ -44,7 +44,7 @@ module('Unit | Utility | sqlite-query', function (hooks) {
assert.strictEqual(
sql,
`
SELECT * FROM token
SELECT * FROM "token"
WHERE (id = ?)`.removeExtraWhiteSpace(),
);
assert.deepEqual(parameters, ['tokenKey']);
@@ -59,8 +59,8 @@ module('Unit | Utility | sqlite-query', function (hooks) {
assert.strictEqual(
sql,
`
SELECT count(*) as total FROM target
ORDER BY created_time DESC`.removeExtraWhiteSpace(),
SELECT count(*) as total FROM "target"
ORDER BY created_time DESC`.removeExtraWhiteSpace(),
);
assert.deepEqual(parameters, []);
});
@@ -160,7 +160,7 @@ module('Unit | Utility | sqlite-query', function (hooks) {
assert.strictEqual(
sql,
`
SELECT * FROM target
SELECT * FROM "target"
${expectedWhereClause}
ORDER BY created_time DESC`.removeExtraWhiteSpace(),
);
@@ -176,15 +176,55 @@ module('Unit | Utility | sqlite-query', function (hooks) {
],
function (assert, [direction, expectedDirection]) {
const query = {
sort: { attribute: 'name', direction },
sort: { attributes: ['name'], direction },
};
const { sql, parameters } = generateSQLExpressions('target', query);
assert.strictEqual(
sql,
`
SELECT * FROM target
ORDER BY name ${expectedDirection}`.removeExtraWhiteSpace(),
SELECT * FROM "target"
ORDER BY name COLLATE NOCASE ${expectedDirection}, name ${expectedDirection}`.removeExtraWhiteSpace(),
);
assert.deepEqual(parameters, []);
},
);
test.each(
'it generates sort order clause correctly',
{
'sort on multiple attributes and coalesced': {
sort: {
attributes: ['name', 'id'],
isCoalesced: true,
},
expectedOrderByClause: `ORDER BY COALESCE(name, id) COLLATE NOCASE DESC, COALESCE(name, id) DESC`,
},
'sort on multiple attributes': {
sort: {
attributes: ['name', 'id'],
},
expectedOrderByClause: `ORDER BY name COLLATE NOCASE DESC, id COLLATE NOCASE DESC, name DESC, id DESC`,
},
'sort on mapped attributes': {
sort: {
attributes: ['type'],
customSort: { attributeMap: { ssh: 'SSH', tcp: 'Generic TCP' } },
},
expectedOrderByClause: `ORDER BY CASE type WHEN 'ssh' THEN 'SSH' WHEN 'tcp' THEN 'Generic TCP' END DESC`,
},
},
function (assert, { sort, expectedOrderByClause }) {
const query = {
sort: { ...sort, direction: 'desc' },
};
const { sql, parameters } = generateSQLExpressions('target', query);
assert.strictEqual(
sql,
`
SELECT * FROM "target"
${expectedOrderByClause}`.removeExtraWhiteSpace(),
);
assert.deepEqual(parameters, []);
},
@@ -206,7 +246,7 @@ module('Unit | Utility | sqlite-query', function (hooks) {
assert.strictEqual(
sql,
`
SELECT * FROM target
SELECT * FROM "target"
ORDER BY created_time DESC
LIMIT ? OFFSET ?`.removeExtraWhiteSpace(),
);
@@ -230,7 +270,7 @@ module('Unit | Utility | sqlite-query', function (hooks) {
assert.strictEqual(
sql,
`
SELECT * FROM target
SELECT * FROM "target"
WHERE (id != ? AND id != ?) AND (status = ? OR status = ?) AND rowid IN (SELECT rowid FROM target_fts WHERE target_fts MATCH ?)
ORDER BY created_time DESC`.removeExtraWhiteSpace(),
);
@@ -254,7 +294,7 @@ module('Unit | Utility | sqlite-query', function (hooks) {
},
created_time: [{ gte: date }],
},
sort: { attribute: 'name', direction: 'desc' },
sort: { attributes: ['name'], direction: 'desc' },
};
const { sql, parameters } = generateSQLExpressions('target', query, {
@@ -266,9 +306,9 @@ module('Unit | Utility | sqlite-query', function (hooks) {
assert.strictEqual(
sql,
`
SELECT data FROM target
SELECT data FROM "target"
WHERE (type = ?) AND (status = ? OR status = ?) AND (created_time >= ?) AND rowid IN (SELECT rowid FROM target_fts WHERE target_fts MATCH ?)
ORDER BY name DESC
ORDER BY name COLLATE NOCASE DESC, name DESC
LIMIT ? OFFSET ?`.removeExtraWhiteSpace(),
);
@@ -290,19 +330,38 @@ module('Unit | Utility | sqlite-query', function (hooks) {
emptySearch: { search: '' },
emptyFilter: { filters: {} },
emptyFilterAttributes: { filters: { type: [] } },
invalidSortAttribute: { attribute: 'test', direction: 'asc' },
invalidSortAttribute: {
sort: { attributes: ['test'], direction: 'asc' },
},
invalidCoalescedSortAttribute: {
sort: {
attributes: ['id', 'test'],
direction: 'asc',
isCoalesced: true,
},
},
onlyPage: { page: 10 },
onlyPageSize: { pageSize: 5 },
},
function (assert, query) {
const { sql, parameters } = generateSQLExpressions('target', query);
const { sql: targetSql, parameters: targetParameters } =
generateSQLExpressions('target', query);
assert.strictEqual(
sql,
targetSql,
`
SELECT * FROM target
SELECT * FROM "target"
ORDER BY created_time DESC`.removeExtraWhiteSpace(),
);
assert.deepEqual(parameters, []);
assert.deepEqual(targetParameters, []);
const { sql: resourceSql, parameters: resourceParameters } =
generateSQLExpressions('resource', query);
assert.strictEqual(
resourceSql,
`
SELECT * FROM "resource"`.removeExtraWhiteSpace(),
);
assert.deepEqual(resourceParameters, []);
},
);
});