Files
threshold-ui/addons/api/tests/unit/utils/sqlite-query-test.js
T

308 lines
8.3 KiB
JavaScript
Raw Normal View History

2025-08-06 11:09:14 -04:00
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import { generateSQLExpressions } from 'api/utils/sqlite-query';
import { module, test } from 'qunit';
module('Unit | Utility | sqlite-query', function (hooks) {
const date = new Date(2025, 1, 1);
const isoDateString = date.toISOString();
hooks.beforeEach(function () {
String.prototype.removeExtraWhiteSpace = function () {
return this.replace(/^\s+/gm, '').trim();
};
});
hooks.afterEach(function () {
delete String.prototype.removeExtraWhiteSpace;
});
// TODO: Add a normal LIKE search when we add a resource that uses it
test('it generates search correctly with FTS5', function (assert) {
const query = { search: 'favorite' };
const { sql, parameters } = generateSQLExpressions('target', query);
assert.strictEqual(
sql,
`
SELECT * FROM target
WHERE rowid IN (SELECT rowid FROM target_fts WHERE target_fts MATCH ?)
ORDER BY created_time DESC`.removeExtraWhiteSpace(),
);
assert.deepEqual(parameters, ['"favorite"*']);
});
test('it grabs resources not in the model mapping', function (assert) {
const query = {
filters: { id: [{ equals: 'tokenKey' }] },
};
const { sql, parameters } = generateSQLExpressions('token', query);
assert.strictEqual(
sql,
`
SELECT * FROM token
WHERE (id = ?)`.removeExtraWhiteSpace(),
);
assert.deepEqual(parameters, ['tokenKey']);
});
test('it executes count queries correctly', function (assert) {
const select = {
select: ['count(*) as total'],
};
const { sql, parameters } = generateSQLExpressions('target', {}, select);
assert.strictEqual(
sql,
`
SELECT count(*) as total FROM target
ORDER BY created_time DESC`.removeExtraWhiteSpace(),
);
assert.deepEqual(parameters, []);
});
test.each(
'it generates filters correctly',
{
equals: {
query: {
filters: {
type: [{ equals: 'ssh' }],
},
},
expectedWhereClause: 'WHERE (type = ?)',
expectedParams: ['ssh'],
},
notEquals: {
query: {
filters: {
type: [{ notEquals: 'ssh' }],
},
},
expectedWhereClause: 'WHERE (type != ?)',
expectedParams: ['ssh'],
},
contains: {
query: {
filters: {
type: [{ contains: 'ssh' }],
},
},
expectedWhereClause: 'WHERE (type LIKE ?)',
expectedParams: ['%ssh%'],
},
greaterThan: {
query: {
filters: {
created_time: [{ gt: date }],
numberField: [{ gt: 10 }],
},
},
expectedWhereClause: 'WHERE (created_time > ?) AND (numberField > ?)',
expectedParams: [isoDateString, 10],
},
lessThan: {
query: {
filters: {
created_time: [{ lt: date }],
numberField: [{ lt: 10 }],
},
},
expectedWhereClause: 'WHERE (created_time < ?) AND (numberField < ?)',
expectedParams: [isoDateString, 10],
},
greaterThanOrEqual: {
query: {
filters: {
created_time: [{ gte: date }],
numberField: [{ gte: 10 }],
},
},
expectedWhereClause: 'WHERE (created_time >= ?) AND (numberField >= ?)',
expectedParams: [isoDateString, 10],
},
lessThanOrEqual: {
query: {
filters: {
created_time: [{ lte: date }],
numberField: [{ lte: 10 }],
},
},
expectedWhereClause: 'WHERE (created_time <= ?) AND (numberField <= ?)',
expectedParams: [isoDateString, 10],
},
logicalOperators: {
query: {
filters: {
id: {
logicalOperator: 'and',
values: [{ notEquals: 'id1' }, { notEquals: 'id2' }],
},
status: {
logicalOperator: 'or',
values: [{ equals: 'active' }, { equals: 'pending' }],
},
type: [{ equals: 'ssh' }],
},
},
expectedWhereClause:
'WHERE (id != ? AND id != ?) AND (status = ? OR status = ?) AND (type = ?)',
expectedParams: ['id1', 'id2', 'active', 'pending', 'ssh'],
},
},
function (assert, { query, expectedWhereClause, expectedParams }) {
const { sql, parameters } = generateSQLExpressions('target', query);
assert.strictEqual(
sql,
`
SELECT * FROM target
${expectedWhereClause}
ORDER BY created_time DESC`.removeExtraWhiteSpace(),
);
assert.deepEqual(parameters, expectedParams);
},
);
test.each(
'it generates sort direction correctly',
[
['asc', 'ASC'],
['desc', 'DESC'],
],
function (assert, [direction, expectedDirection]) {
const query = {
sort: { attribute: 'name', direction },
};
const { sql, parameters } = generateSQLExpressions('target', query);
assert.strictEqual(
sql,
`
SELECT * FROM target
ORDER BY name ${expectedDirection}`.removeExtraWhiteSpace(),
);
assert.deepEqual(parameters, []);
},
);
test.each(
'it generates pagination clause',
[
{ page: 1, pageSize: 10, expectedParams: [10, 0] },
{ page: 3, pageSize: 10, expectedParams: [10, 20] },
{ page: 7, pageSize: 50, expectedParams: [50, 300] },
],
function (assert, { page, pageSize, expectedParams }) {
const { sql, parameters } = generateSQLExpressions(
'target',
{},
{ page, pageSize },
);
assert.strictEqual(
sql,
`
SELECT * FROM target
ORDER BY created_time DESC
LIMIT ? OFFSET ?`.removeExtraWhiteSpace(),
);
assert.deepEqual(parameters, expectedParams);
},
);
test('it generates FTS5 search with filters', function (assert) {
const query = {
search: 'favorite',
filters: {
id: {
logicalOperator: 'and',
values: [{ notEquals: 'id1' }, { notEquals: 'id2' }],
},
status: [{ equals: 'active' }, { equals: 'pending' }],
},
};
const { sql, parameters } = generateSQLExpressions('target', query);
assert.strictEqual(
sql,
`
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(),
);
assert.deepEqual(parameters, [
'id1',
'id2',
'active',
'pending',
'"favorite"*',
]);
});
test('it generates SQL with all clauses combined', function (assert) {
const query = {
search: 'favorite',
filters: {
type: [{ equals: 'ssh' }],
status: {
logicalOperator: 'or',
values: [{ equals: 'active' }, { equals: 'pending' }],
},
created_time: [{ gte: date }],
},
sort: { attribute: 'name', direction: 'desc' },
};
const { sql, parameters } = generateSQLExpressions('target', query, {
page: 2,
pageSize: 15,
select: ['data'],
});
assert.strictEqual(
sql,
`
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
LIMIT ? OFFSET ?`.removeExtraWhiteSpace(),
);
assert.deepEqual(parameters, [
'ssh',
'active',
'pending',
isoDateString,
'"favorite"*',
15,
15,
]);
});
test.each(
'it handles empty and invalid fields',
{
emptyObject: {},
emptySearch: { search: '' },
emptyFilter: { filters: {} },
emptyFilterAttributes: { filters: { type: [] } },
invalidSortAttribute: { attribute: 'test', direction: 'asc' },
onlyPage: { page: 10 },
onlyPageSize: { pageSize: 5 },
},
function (assert, query) {
const { sql, parameters } = generateSQLExpressions('target', query);
assert.strictEqual(
sql,
`
SELECT * FROM target
ORDER BY created_time DESC`.removeExtraWhiteSpace(),
);
assert.deepEqual(parameters, []);
},
);
});