Skip to content

Commit

Permalink
Add a workaround for React Native Proxy objects pre-JSI not working…
Browse files Browse the repository at this point in the history
… properly with JSC. (#4541)

* Add a workaround for React Native `Proxy` objects pre-JSI not working properly with JSC.

This change can be reverted once we go to v11. Fixes #4507
  • Loading branch information
Tom Duncalf committed May 26, 2022
1 parent 7a6beca commit 34a8807
Show file tree
Hide file tree
Showing 10 changed files with 1,955 additions and 650 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ x.x.x Release notes (yyyy-MM-dd)
### Fixed
* Flexible sync would not correctly resume syncing if a bootstrap was interrupted. ([realm/realm-core#5466](https://github.com/realm/realm-core/pull/5466), since v10.12.0)
* The sync client may upload corrupted internal data leading to a fatal error from the sync server. ([realm/realm-core#5460](https://github.com/realm/realm-core/pull/5460), since v10.16.0)
* Proxied `Realm.Results` (e.g. as returned from `useQuery` in `@realm/react`) could not be used with `MutableSubscriptionSet.add`/`remove` ([#4507](https://github.com/realm/realm-js/issues/4507), since v10.12.0)

### Compatibility
* MongoDB Realm Cloud.
Expand Down
10 changes: 9 additions & 1 deletion lib/extensions.js
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,6 @@ module.exports = function (realmConstructor) {
Object.defineProperties(realmConstructor.User.prototype, getOwnPropertyDescriptors(userMethods.instance));

let subscriptionSetMethods = require("./subscription-set");

Object.defineProperties(
realmConstructor.App.Sync.SubscriptionSet,
getOwnPropertyDescriptors(subscriptionSetMethods.static),
Expand All @@ -376,6 +375,15 @@ module.exports = function (realmConstructor) {
...require("./collection-methods")(realmConstructor),
});

let mutableSubscriptionSetMethods = require("./mutable-subscription-set");
Object.defineProperties(
realmConstructor.App.Sync.MutableSubscriptionSet,
getOwnPropertyDescriptors(mutableSubscriptionSetMethods.static),
);
Object.defineProperties(realmConstructor.App.Sync.MutableSubscriptionSet.prototype, {
...getOwnPropertyDescriptors(mutableSubscriptionSetMethods.instance),
});

let sessionMethods = require("./session");
Object.defineProperties(realmConstructor.App.Sync.Session, getOwnPropertyDescriptors(sessionMethods.static));
Object.defineProperties(
Expand Down
50 changes: 50 additions & 0 deletions lib/mutable-subscription-set.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2022 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////

const { symbols } = require("@realm.io/common");

// React Native `Proxy` objects when not using JSI are not compatible with
// `JSValueIsObjectOfClass`, because it seems JSC is not able to "unwrap"
// the proxy - see https://github.com/realm/realm-js/issues/4507#issuecomment-1112237740.
//
// In order to enable the return value of Realm React's `useQuery` (which are wrapped
// in a proxy) to be passed to the subscription mutation methods, we need to store
// the unproxied results on the proxy object as a non-enumerable field with a symbol key
// (see `useQuery.ts` in @realm/react), then in here, we check if that field exists, and
// if so we pass the original unproxied results to C++.
//
// Once our v11 branch is merged, we can revert this change as JSI React Native `Proxy`s
// work fine, by reverting PR #4541.
const instanceMethods = {
add(query, options) {
return this._add(query[symbols.PROXY_TARGET] || query, options);
},

remove(query) {
return this._remove(query[symbols.PROXY_TARGET] || query);
},
};

const staticMethods = {
// none
};

module.exports = {
static: staticMethods,
instance: instanceMethods,
};
1 change: 1 addition & 0 deletions packages/realm-common/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@
////////////////////////////////////////////////////////////////////////////

export { deprecationWarning, handleDeprecatedPositionalArgs } from "./deprecation";
export * as symbols from "./symbols";
21 changes: 21 additions & 0 deletions packages/realm-common/src/symbols.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2022 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////

// Used as a key by Realm React in `useQuery`, to store the original object
// which is being proxied, for compatibility with JSC pre-v11 (#4541)
export const PROXY_TARGET = Symbol("PROXY_TARGET");
3 changes: 1 addition & 2 deletions packages/realm-react/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ x.x.x Release notes (yyyy-MM-dd)
* Additionally appRef on `AppProvider` was added to provide access to `Realm.App` from outside the provider component

### Fixed
* <How to hit and notice issue? what was the impact?> ([#????](https://github.com/realm/realm-js/issues/????), since v?.?.?)
* None.
* Results from `useQuery` could not be passed to `MutableSubscriptionSet.add`/`remove` ([#4507](https://github.com/realm/realm-js/issues/4507), since v0.1.0)

### Compatibility
* MongoDB Realm Cloud.
Expand Down
Loading

0 comments on commit 34a8807

Please sign in to comment.