Skip to content

Commit

Permalink
Fix crash when accessing out of bounds index of a collection (realm#4416
Browse files Browse the repository at this point in the history
)

* Fix crash when accessing out of bounds index of a collection

Collection will now return `undefined` for out of bound indexes.
Added a test to cover this.
  • Loading branch information
takameyer committed Mar 15, 2022
1 parent 4aba151 commit 3c78c7b
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 10 deletions.
14 changes: 14 additions & 0 deletions packages/realm-react/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
x.x.x Release notes (yyyy-MM-dd)
=============================================================
### Enhancements
* None.

### Fixed
* Fixed bug when trying to access a collection result with an out of bounds index.

### Compatibility
* None

### Internal
* None

0.2.0 Release notes (2022-03-07)
=============================================================
### Enhancements
Expand Down
8 changes: 7 additions & 1 deletion packages/realm-react/src/__tests__/useQueryHook.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ const testDataSet = [
{ _id: 6, name: "Sadie", color: "gold", gender: "female", age: 5 },
];

describe("useQuery", () => {
describe("useQueryHook", () => {
beforeEach(() => {
const realm = new Realm(configuration);
realm.write(() => {
Expand Down Expand Up @@ -101,4 +101,10 @@ describe("useQuery", () => {
expect(collection.length).toBe(6);
expect(collection[0]).toEqual(collection?.[0]);
});
it("should return undefined indexes that are out of bounds", () => {
const { result } = renderHook(() => useQuery<IDog>("dog"));
const collection = result.current;

expect(collection[99]).toBe(undefined);
});
});
24 changes: 15 additions & 9 deletions packages/realm-react/src/cachedCollection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ function getCacheKey(id: string) {
}

/**
* Arguments object for {@link cachedCollection}.
*/
* Arguments object for {@link cachedCollection}.
*/
type CachedCollectionArgs<T> = {
/**
* The {@link Realm.Collection} to proxy
Expand All @@ -40,7 +40,7 @@ type CachedCollectionArgs<T> = {
* (derived) version of the collection to reuse the same cache, preventing excess new object
* references being created.
*/
collectionCache?: Map<string, T>;
objectCache?: Map<string, T>;
/**
* Optional flag specifying that this is a derived (`sorted` or `filtered`) version of
* an existing collection, so we should not create or remove listeners or clear the cache
Expand All @@ -66,12 +66,7 @@ export function createCachedCollection<T extends Realm.Object>({
updateCallback,
objectCache = new Map(),
isDerived = false,
}: {
collection: Realm.Collection<T>;
updateCallback: () => void;
objectCache?: Map<string, T>;
isDerived?: boolean;
}): { collection: Realm.Collection<T>; tearDown: () => void } {
}: CachedCollectionArgs<T>): { collection: Realm.Collection<T>; tearDown: () => void } {
const cachedCollectionHandler: ProxyHandler<Realm.Collection<T & Realm.Object>> = {
get: function (target, key) {
// Pass functions through
Expand Down Expand Up @@ -100,6 +95,17 @@ export function createCachedCollection<T extends Realm.Object>({
// If the key is numeric, check if we have a cached object for this key
const index = Number(key);
const object = target[index];

// If the collection is modeled in a way that objects can be null
// then we should return null instead of undefined to stay semantically
// correct
if (object === null) {
return null;
} else if (typeof object === "undefined") {
// If there is no object at this index, return undefined
return undefined;
}

const objectId = object._objectId();
const cacheKey = getCacheKey(objectId);

Expand Down

0 comments on commit 3c78c7b

Please sign in to comment.