Skip to content

Commit 9089203

Browse files
committed
feat: 🎸 Use subqueries
1 parent d91ebce commit 9089203

File tree

3 files changed

+111
-33
lines changed

3 files changed

+111
-33
lines changed

‎addons/api/addon/utils/sqlite-query.js‎

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ function addFilterConditions({ filters, parameters, conditions }) {
6969
? filterArrayOrObject
7070
: filterArrayOrObject.values;
7171

72-
if (!filterValueArray || !filterValueArray.length) {
72+
if (!filterValueArray || !filterValueArray.length || key === 'subqueries') {
7373
continue;
7474
}
7575

@@ -131,6 +131,22 @@ function addFilterConditions({ filters, parameters, conditions }) {
131131
),
132132
);
133133
}
134+
135+
if (filters.subqueries?.length > 0) {
136+
filters.subqueries.forEach((subquery) => {
137+
const { resource, query, select } = subquery;
138+
const { sql, parameters: subqueryParams } = generateSQLExpressions(
139+
resource,
140+
query,
141+
{
142+
select,
143+
},
144+
);
145+
146+
conditions.push(`id IN (${sql})`);
147+
parameters.push(...subqueryParams);
148+
});
149+
}
134150
}
135151

136152
function addSearchConditions({

‎addons/api/tests/unit/utils/sqlite-query-test.js‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,48 @@ module('Unit | Utility | sqlite-query', function (hooks) {
410410
]);
411411
});
412412

413+
test('it generates subqueries with filters', function (assert) {
414+
const query = {
415+
filters: {
416+
type: [{ equals: 'ssh' }],
417+
subqueries: [
418+
{
419+
resource: 'session',
420+
query: {
421+
filters: {
422+
status: [{ equals: 'active' }],
423+
},
424+
},
425+
select: [{ field: 'target_id' }],
426+
},
427+
{
428+
resource: 'session-recording',
429+
query: {
430+
filters: {
431+
state: [{ equals: 'available' }],
432+
},
433+
},
434+
select: [{ field: 'target_id' }],
435+
},
436+
],
437+
},
438+
};
439+
440+
const { sql, parameters } = generateSQLExpressions('target', query);
441+
assert.strictEqual(
442+
sql,
443+
`
444+
SELECT * FROM "target"
445+
WHERE (type = ?) AND id IN (SELECT target_id FROM "session"
446+
WHERE (status = ?)
447+
ORDER BY created_time DESC) AND id IN (SELECT target_id FROM "session_recording"
448+
WHERE (state = ?)
449+
ORDER BY created_time DESC)
450+
ORDER BY created_time DESC`.removeExtraWhiteSpace(),
451+
);
452+
assert.deepEqual(parameters, ['ssh', 'active', 'available']);
453+
});
454+
413455
test('it generates SQL with all clauses combined', function (assert) {
414456
const query = {
415457
search: 'favorite',

‎ui/admin/app/routes/scopes/scope/targets/index.js‎

Lines changed: 52 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -92,19 +92,25 @@ export default class ScopesScopeTargetsIndexRoute extends Route {
9292
});
9393

9494
if (this.can.can('list model', scope, { collection: 'sessions' })) {
95-
const sessions = await this.store.query('session', {
96-
scope_id,
97-
query: {
98-
filters: {
99-
scope_id: [{ equals: scope_id }],
100-
status: [
101-
{ equals: STATUS_SESSION_ACTIVE },
102-
{ equals: STATUS_SESSION_PENDING },
103-
],
95+
await this.store.query(
96+
'session',
97+
{
98+
scope_id,
99+
query: {
100+
filters: {
101+
scope_id: [{ equals: scope_id }],
102+
status: [
103+
{ equals: STATUS_SESSION_ACTIVE },
104+
{ equals: STATUS_SESSION_PENDING },
105+
],
106+
},
104107
},
108+
page: 1,
109+
pageSize: 1,
105110
},
106-
});
107-
this.addActiveSessionFilters(filters, availableSessions, sessions);
111+
{ pushToStore: false },
112+
);
113+
this.addActiveSessionFilters(filters, availableSessions);
108114
}
109115

110116
const typeMap = {
@@ -186,38 +192,52 @@ export default class ScopesScopeTargetsIndexRoute extends Route {
186192
* Add the filters for active sessions to the filter object.
187193
* @param filters
188194
* @param availableSessions
189-
* @param sessions
190195
*/
191-
addActiveSessionFilters = (filters, availableSessions, sessions) => {
192-
const uniqueTargetIdsWithSessions = new Set(
193-
sessions.map((session) => session.target_id),
194-
);
195-
196+
addActiveSessionFilters = (filters, availableSessions) => {
196197
// Don't add any filtering if the user selects both which is equivalent to no filters
197198
if (availableSessions.length === 2) {
198199
return;
199200
}
200201

201202
availableSessions.forEach((availability) => {
202203
if (availability === 'yes') {
203-
filters.id.logicalOperator = 'or';
204-
uniqueTargetIdsWithSessions.forEach((targetId) => {
205-
filters.id.values.push({ equals: targetId });
206-
});
207-
208-
// If there's no sessions just set it to a dummy value
209-
// so the search returns no results
210-
if (uniqueTargetIdsWithSessions.size === 0) {
211-
filters.id.values.push({ equals: 'none' });
212-
}
204+
filters.subqueries = [
205+
{
206+
resource: 'session',
207+
query: {
208+
filters: {
209+
status: {
210+
logicalOperator: 'or',
211+
values: [
212+
{ equals: STATUS_SESSION_ACTIVE },
213+
{ equals: STATUS_SESSION_PENDING },
214+
],
215+
},
216+
},
217+
},
218+
select: [{ field: 'target_id' }],
219+
},
220+
];
213221
}
214222

215223
if (availability === 'no') {
216-
filters.id.logicalOperator = 'and';
217-
218-
uniqueTargetIdsWithSessions.forEach((targetId) => {
219-
filters.id.values.push({ notEquals: targetId });
220-
});
224+
filters.subqueries = [
225+
{
226+
resource: 'session',
227+
query: {
228+
filters: {
229+
status: {
230+
logicalOperator: 'and',
231+
values: [
232+
{ notEquals: STATUS_SESSION_ACTIVE },
233+
{ notEquals: STATUS_SESSION_PENDING },
234+
],
235+
},
236+
},
237+
},
238+
select: [{ field: 'target_id' }],
239+
},
240+
];
221241
}
222242
});
223243
};

0 commit comments

Comments
 (0)