Skip to content

Commit 095dcca

Browse files
committed
feat: 🎸 Add optimization for caching sqlite data
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-18506
1 parent d1aeac5 commit 095dcca

2 files changed

Lines changed: 84 additions & 7 deletions

File tree

‎addons/api/addon/handlers/sqlite-handler.js‎

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,35 @@ export default class SqliteHandler {
6262
totalInsert = 0;
6363

6464
if (!peekDb) {
65-
const tokenKey = `${type}-${hashCode(remainingQuery)}`;
65+
let tokenKey = `${type}-${hashCode(remainingQuery)}`;
66+
// The global token key represents a recursive query from global scope,
67+
// which pulls back every resource of this type.
68+
const globalTokenKey = `${type}-${hashCode({ scope_id: 'global', recursive: true })}`;
6669
if (storeToken) {
67-
const [tokenObj] = await this.sqlite.fetchResource({
68-
...generateSQLExpressions('token', {
69-
filters: { id: [{ equals: tokenKey }] },
70-
}),
71-
});
72-
listToken = tokenObj?.token;
70+
// Always prefer the global token when it exists for
71+
// any more fine-grained query. The global query already fetched every
72+
// item for this resource type, so we should just re-use it.
73+
if (tokenKey !== globalTokenKey) {
74+
const [globalTokenObj] = await this.sqlite.fetchResource({
75+
...generateSQLExpressions('token', {
76+
filters: { id: [{ equals: globalTokenKey }] },
77+
}),
78+
});
79+
if (globalTokenObj?.token) {
80+
tokenKey = globalTokenKey;
81+
listToken = globalTokenObj.token;
82+
}
83+
}
84+
85+
// Only look up the specific token if no global token was found.
86+
if (!listToken) {
87+
const [tokenObj] = await this.sqlite.fetchResource({
88+
...generateSQLExpressions('token', {
89+
filters: { id: [{ equals: tokenKey }] },
90+
}),
91+
});
92+
listToken = tokenObj?.token;
93+
}
7394
} else {
7495
// This is a temporary fix of clearing the DB (specifically for auth-methods)
7596
// since we are not storing the token we do not get back a list of removed_ids

‎addons/api/tests/unit/handlers/sqlite-handler-test.js‎

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,62 @@ module('Unit | Handler | sqlite-handler', function (hooks) {
470470
assert.strictEqual(results[0].name, 'specific-target');
471471
});
472472

473+
test('it reuses the global token for a more specific query when the global token exists', async function (assert) {
474+
const targets = this.server.createList('target', 3, { scope });
475+
let capturedListToken;
476+
let responseToken = 'specific-list-token';
477+
478+
this.server.get('targets', (_schema, request) => {
479+
capturedListToken = request.queryParams.list_token;
480+
return {
481+
items: targets.map((t) =>
482+
this.server.serializerOrRegistry.serialize(t),
483+
),
484+
list_token: responseToken,
485+
response_type: 'complete',
486+
};
487+
});
488+
489+
// Run the specific query first
490+
await store.query('target', { scope_id: 'some-specific-scope' });
491+
492+
// Switch the response token and run the global query
493+
responseToken = 'global-list-token';
494+
await store.query('target', { scope_id: 'global', recursive: true });
495+
496+
capturedListToken = undefined;
497+
498+
// Re-run the specific query which has a cached token but should prefer the global token since it exists
499+
await store.query('target', { scope_id: 'some-specific-scope' });
500+
501+
assert.strictEqual(capturedListToken, 'global-list-token');
502+
});
503+
504+
test('it uses the specific token when no global token exists', async function (assert) {
505+
const targets = this.server.createList('target', 3, { scope });
506+
let capturedListToken;
507+
508+
this.server.get('targets', (_schema, request) => {
509+
capturedListToken = request.queryParams.list_token;
510+
return {
511+
items: targets.map((t) =>
512+
this.server.serializerOrRegistry.serialize(t),
513+
),
514+
list_token: 'specific-list-token',
515+
response_type: 'complete',
516+
};
517+
});
518+
519+
await store.query('target', { scope_id: 'some-specific-scope' });
520+
521+
capturedListToken = undefined;
522+
523+
// Re-run the specific query which should just use the normal specific token since no global token exists
524+
await store.query('target', { scope_id: 'some-specific-scope' });
525+
526+
assert.strictEqual(capturedListToken, 'specific-list-token');
527+
});
528+
473529
test('it retries query when invalid list token error occurs', async function (assert) {
474530
let targets = this.server.createList('target', 5, { scope });
475531

0 commit comments

Comments
 (0)