Skip to content

Commit ccccbf1

Browse files
fabioh8010claude
andcommitted
refactor: extract key utilities into centralized OnyxKeys module
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 434871e commit ccccbf1

13 files changed

Lines changed: 389 additions & 324 deletions

lib/Onyx.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import type {
2323
SetOptions,
2424
} from './types';
2525
import OnyxUtils from './OnyxUtils';
26+
import OnyxKeys from './OnyxKeys';
2627
import logMessages from './logMessages';
2728
import type {Connection} from './OnyxConnectionManager';
2829
import connectionManager from './OnyxConnectionManager';
@@ -55,13 +56,13 @@ function init({
5556
OnyxUtils.setSkippableCollectionMemberIDs(new Set(skippableCollectionMemberIDs));
5657
OnyxUtils.setSnapshotMergeKeys(new Set(snapshotMergeKeys));
5758

58-
cache.setRamOnlyKeys(new Set<OnyxKey>(ramOnlyKeys));
59+
OnyxKeys.setRamOnlyKeys(new Set<OnyxKey>(ramOnlyKeys));
5960

6061
if (shouldSyncMultipleInstances) {
6162
Storage.keepInstancesSync?.((key, value) => {
6263
// RAM-only keys should never sync from storage as they may have stale persisted data
6364
// from before the key was migrated to RAM-only.
64-
if (OnyxUtils.isRamOnlyKey(key)) {
65+
if (OnyxKeys.isRamOnlyKey(key)) {
6566
return;
6667
}
6768

@@ -70,7 +71,7 @@ function init({
7071
// Check if this is a collection member key to prevent duplicate callbacks
7172
// When a collection is updated, individual members sync separately to other tabs
7273
// Setting isProcessingCollectionUpdate=true prevents triggering collection callbacks for each individual update
73-
const isKeyCollectionMember = OnyxUtils.isCollectionMember(key);
74+
const isKeyCollectionMember = OnyxKeys.isCollectionMember(key);
7475

7576
OnyxUtils.keyChanged(key, value as OnyxValue<typeof key>, undefined, isKeyCollectionMember);
7677
});
@@ -83,7 +84,7 @@ function init({
8384
OnyxUtils.initStoreValues(keys, initialKeyStates, evictableKeys);
8485

8586
// Initialize all of our keys with data provided then give green light to any pending connections
86-
Promise.all([cache.addEvictableKeysToRecentlyAccessedList(OnyxUtils.isCollectionKey, OnyxUtils.getAllKeys), OnyxUtils.initializeWithDefaultKeyStates()]).then(
87+
Promise.all([cache.addEvictableKeysToRecentlyAccessedList(OnyxKeys.isCollectionKey, OnyxUtils.getAllKeys), OnyxUtils.initializeWithDefaultKeyStates()]).then(
8788
OnyxUtils.getDeferredInitTask().resolve,
8889
);
8990
}
@@ -201,7 +202,7 @@ function merge<TKey extends OnyxKey>(key: TKey, changes: OnyxMergeInput<TKey>):
201202
const skippableCollectionMemberIDs = OnyxUtils.getSkippableCollectionMemberIDs();
202203
if (skippableCollectionMemberIDs.size) {
203204
try {
204-
const [, collectionMemberID] = OnyxUtils.splitCollectionMemberKey(key);
205+
const [, collectionMemberID] = OnyxKeys.splitCollectionMemberKey(key);
205206
if (skippableCollectionMemberIDs.has(collectionMemberID)) {
206207
// The key is a skippable one, so we set the new changes to undefined.
207208
// eslint-disable-next-line no-param-reassign
@@ -351,7 +352,7 @@ function clear(keysToPreserve: OnyxKey[] = []): Promise<void> {
351352
if (newValue !== oldValue) {
352353
cache.set(key, newValue);
353354

354-
const collectionKey = OnyxUtils.getCollectionKey(key);
355+
const collectionKey = OnyxKeys.getCollectionKey(key);
355356

356357
if (collectionKey) {
357358
if (!keyValuesToResetAsCollection[collectionKey]) {
@@ -376,7 +377,7 @@ function clear(keysToPreserve: OnyxKey[] = []): Promise<void> {
376377
// Exclude RAM-only keys to prevent them from being saved to storage
377378
const defaultKeyValuePairs = Object.entries(
378379
Object.keys(defaultKeyStates)
379-
.filter((key) => !keysToPreserve.includes(key) && !OnyxUtils.isRamOnlyKey(key))
380+
.filter((key) => !keysToPreserve.includes(key) && !OnyxKeys.isRamOnlyKey(key))
380381
.reduce((obj: KeyValueMapping, key) => {
381382
// eslint-disable-next-line no-param-reassign
382383
obj[key] = defaultKeyStates[key];
@@ -486,8 +487,8 @@ function update<TKey extends OnyxKey>(data: Array<OnyxUpdate<TKey>>): Promise<vo
486487
// Group all the collection-related keys and update each collection in a single `mergeCollection` call.
487488
// This is needed to prevent multiple `mergeCollection` calls for the same collection and `merge` calls for the individual items of the said collection.
488489
// This way, we ensure there is no race condition in the queued updates of the same key.
489-
for (const collectionKey of OnyxUtils.getCollectionKeys()) {
490-
const collectionItemKeys = Object.keys(updateQueue).filter((key) => OnyxUtils.isKeyMatch(collectionKey, key));
490+
for (const collectionKey of OnyxKeys.getCollectionKeys()) {
491+
const collectionItemKeys = Object.keys(updateQueue).filter((key) => OnyxKeys.isKeyMatch(collectionKey, key));
491492
if (collectionItemKeys.length <= 1) {
492493
// If there are no items of this collection in the updateQueue, we should skip it.
493494
// If there is only one item, we should update it individually, therefore retain it in the updateQueue.

lib/OnyxCache.ts

Lines changed: 18 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import bindAll from 'lodash/bindAll';
33
import type {ValueOf} from 'type-fest';
44
import utils from './utils';
55
import type {OnyxKey, OnyxValue} from './types';
6-
import * as Str from './Str';
6+
import OnyxKeys from './OnyxKeys';
77

88
// Task constants
99
const TASK = {
@@ -52,12 +52,6 @@ class OnyxCache {
5252
/** List of keys that have been directly subscribed to or recently modified from least to most recent */
5353
private recentlyAccessedKeys = new Set<OnyxKey>();
5454

55-
/** Set of collection keys for fast lookup */
56-
private collectionKeys = new Set<OnyxKey>();
57-
58-
/** Set of RAM-only keys for fast lookup */
59-
private ramOnlyKeys = new Set<OnyxKey>();
60-
6155
constructor() {
6256
this.storageKeys = new Set();
6357
this.nullishStorageKeys = new Set();
@@ -94,11 +88,8 @@ class OnyxCache {
9488
'addEvictableKeysToRecentlyAccessedList',
9589
'getKeyForEviction',
9690
'setCollectionKeys',
97-
'isCollectionKey',
98-
'getCollectionKey',
9991
'getCollectionData',
100-
'setRamOnlyKeys',
101-
'isRamOnlyKey',
92+
'hasValueChanged',
10293
);
10394
}
10495

@@ -120,13 +111,17 @@ class OnyxCache {
120111
*/
121112
setAllKeys(keys: OnyxKey[]) {
122113
this.storageKeys = new Set(keys);
114+
for (const key of keys) {
115+
OnyxKeys.registerMemberKey(key);
116+
}
123117
}
124118

125119
/** Saves a key in the storage keys list
126120
* Serves to keep the result of `getAllKeys` up to date
127121
*/
128122
addKey(key: OnyxKey): void {
129123
this.storageKeys.add(key);
124+
OnyxKeys.registerMemberKey(key);
130125
}
131126

132127
/** Used to set keys that are null/undefined in storage without adding null to the storage map */
@@ -172,7 +167,7 @@ class OnyxCache {
172167
// since it will either be set to a non nullish value or removed from the cache completely.
173168
this.nullishStorageKeys.delete(key);
174169

175-
const collectionKey = this.getCollectionKey(key);
170+
const collectionKey = OnyxKeys.getCollectionKey(key);
176171
if (value === null || value === undefined) {
177172
delete this.storageMap[key];
178173

@@ -201,18 +196,19 @@ class OnyxCache {
201196
delete this.storageMap[key];
202197

203198
// Remove from collection data cache if this is a collection member
204-
const collectionKey = this.getCollectionKey(key);
199+
const collectionKey = OnyxKeys.getCollectionKey(key);
205200
if (collectionKey && this.collectionData[collectionKey]) {
206201
delete this.collectionData[collectionKey][key];
207202
}
208203

209204
// If this is a collection key, clear its data
210-
if (this.isCollectionKey(key)) {
205+
if (OnyxKeys.isCollectionKey(key)) {
211206
delete this.collectionData[key];
212207
}
213208

214209
this.storageKeys.delete(key);
215210
this.recentKeys.delete(key);
211+
OnyxKeys.deregisterMemberKey(key);
216212
}
217213

218214
/**
@@ -235,7 +231,7 @@ class OnyxCache {
235231
this.addKey(key);
236232
this.addToAccessedKeys(key);
237233

238-
const collectionKey = this.getCollectionKey(key);
234+
const collectionKey = OnyxKeys.getCollectionKey(key);
239235

240236
if (value === null || value === undefined) {
241237
this.addNullishStorageKey(key);
@@ -325,7 +321,7 @@ class OnyxCache {
325321
delete this.storageMap[key];
326322

327323
// Remove from collection data cache if this is a collection member
328-
const collectionKey = this.getCollectionKey(key);
324+
const collectionKey = OnyxKeys.getCollectionKey(key);
329325
if (collectionKey && this.collectionData[collectionKey]) {
330326
delete this.collectionData[collectionKey][key];
331327
}
@@ -364,17 +360,7 @@ class OnyxCache {
364360
* @param testKey - Key to check
365361
*/
366362
isEvictableKey(testKey: OnyxKey): boolean {
367-
return this.evictionAllowList.some((key) => this.isKeyMatch(key, testKey));
368-
}
369-
370-
/**
371-
* Check if a given key matches a pattern key
372-
* @param configKey - Pattern that may contain a wildcard
373-
* @param key - Key to test against the pattern
374-
*/
375-
private isKeyMatch(configKey: OnyxKey, key: OnyxKey): boolean {
376-
const isCollectionKey = configKey.endsWith('_');
377-
return isCollectionKey ? Str.startsWith(key, configKey) : configKey === key;
363+
return this.evictionAllowList.some((key) => OnyxKeys.isKeyMatch(key, testKey));
378364
}
379365

380366
/**
@@ -411,7 +397,7 @@ class OnyxCache {
411397
return getAllKeysFn().then((keys: Set<OnyxKey>) => {
412398
for (const evictableKey of this.evictionAllowList) {
413399
for (const key of keys) {
414-
if (!this.isKeyMatch(evictableKey, key)) {
400+
if (!OnyxKeys.isKeyMatch(evictableKey, key)) {
415401
continue;
416402
}
417403

@@ -437,7 +423,7 @@ class OnyxCache {
437423
* Set the collection keys for optimized storage
438424
*/
439425
setCollectionKeys(collectionKeys: Set<OnyxKey>): void {
440-
this.collectionKeys = collectionKeys;
426+
OnyxKeys.setCollectionKeys(collectionKeys);
441427

442428
// Initialize collection data for existing collection keys
443429
for (const collectionKey of collectionKeys) {
@@ -446,25 +432,11 @@ class OnyxCache {
446432
}
447433
this.collectionData[collectionKey] = {};
448434
}
449-
}
450-
451-
/**
452-
* Check if a key is a collection key
453-
*/
454-
isCollectionKey(key: OnyxKey): boolean {
455-
return this.collectionKeys.has(key);
456-
}
457435

458-
/**
459-
* Get the collection key for a given member key
460-
*/
461-
getCollectionKey(key: OnyxKey): OnyxKey | undefined {
462-
for (const collectionKey of this.collectionKeys) {
463-
if (key.startsWith(collectionKey) && key.length > collectionKey.length) {
464-
return collectionKey;
465-
}
436+
// Register existing storageKeys with OnyxKeys
437+
for (const key of this.storageKeys) {
438+
OnyxKeys.registerMemberKey(key);
466439
}
467-
return undefined;
468440
}
469441

470442
/**
@@ -480,19 +452,6 @@ class OnyxCache {
480452
return {...cachedCollection};
481453
}
482454

483-
/**
484-
* Set the RAM-only keys for optimized storage
485-
*/
486-
setRamOnlyKeys(ramOnlyKeys: Set<OnyxKey>): void {
487-
this.ramOnlyKeys = ramOnlyKeys;
488-
}
489-
490-
/**
491-
* Check if a key is a RAM-only key
492-
*/
493-
isRamOnlyKey(key: OnyxKey): boolean {
494-
return this.ramOnlyKeys.has(key);
495-
}
496455
}
497456

498457
const instance = new OnyxCache();

lib/OnyxConnectionManager.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import bindAll from 'lodash/bindAll';
22
import * as Logger from './Logger';
33
import type {ConnectOptions} from './Onyx';
44
import OnyxUtils from './OnyxUtils';
5+
import OnyxKeys from './OnyxKeys';
56
import * as Str from './Str';
67
import type {CollectionConnectCallback, DefaultConnectCallback, DefaultConnectOptions, OnyxKey, OnyxValue} from './types';
78
import cache from './OnyxCache';
@@ -129,7 +130,7 @@ class OnyxConnectionManager {
129130
if (
130131
reuseConnection === false ||
131132
initWithStoredValues === false ||
132-
(OnyxUtils.isCollectionKey(key) && (waitForCollectionCallback === undefined || waitForCollectionCallback === false))
133+
(OnyxKeys.isCollectionKey(key) && (waitForCollectionCallback === undefined || waitForCollectionCallback === false))
133134
) {
134135
suffix += `,uniqueID=${Str.guid()}`;
135136
}

0 commit comments

Comments
 (0)