Skip to content

Commit

Permalink
Fix toJSON behaviour for Dictionary on JSC pre-v11 (fixes #4658)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tom Duncalf committed Jun 24, 2022
1 parent 893b32e commit 0546806
Show file tree
Hide file tree
Showing 9 changed files with 50 additions and 7 deletions.
24 changes: 24 additions & 0 deletions integration-tests/tests/src/tests/dictionary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,30 @@ describe("Dictionary", () => {
});
});

describe("toJSON", function () {
openRealmBefore({
schema: [
{
name: "Item",
properties: { dict: "{}" },
},
],
});

it("calling toJSON on an object with a Dictionary field removes the Proxy from the Dictionary", function (this: RealmContext) {
const object = this.realm.write(() => {
return this.realm.create<Item>("Item", { dict: { something: "test" } });
});
const jsonObject = object.toJSON();

// Previously this would throw on JSC, because the Dictionary was still a Proxy,
// so modifying it tried to write to the Realm outside of a write transaction
expect(() => {
jsonObject.dict.something = "test2";
}).to.not.throw();
});
});

type ValueGenerator = (realm: Realm) => DictValues;

type TypedDictionarySuite = {
Expand Down
7 changes: 7 additions & 0 deletions lib/dictionary.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,15 @@
//
////////////////////////////////////////////////////////////////////////////

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

const dictionaryHandler = {
get(target, key) {
// Allows us to detect if this is a proxied Dictionary on JSC pre-v11. See realm-common/symbols.ts for details.
if (key === symbols.IS_PROXIED_DICTIONARY) {
return true;
}

if (key === "toJSON") {
return function () {
const keys = target._keys();
Expand Down
8 changes: 7 additions & 1 deletion lib/extensions.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
//
////////////////////////////////////////////////////////////////////////////

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

let getOwnPropertyDescriptors =
Object.getOwnPropertyDescriptors ||
function (obj) {
Expand Down Expand Up @@ -109,7 +111,11 @@ module.exports = function (realmConstructor) {
// recursively trigger `toJSON` for Realm instances with the same cache.
if (value instanceof realmConstructor.Object || value instanceof realmConstructor.Collection) {
result[key] = value.toJSON(key, cache);
} else if (value instanceof realmConstructor.Dictionary) {
} else if (
value instanceof realmConstructor.Dictionary ||
// Allows us to detect if this is a proxied Dictionary on JSC pre-v11. See realm-common/symbols.ts for details.
value[symbols.IS_PROXIED_DICTIONARY]
) {
// Dictionary special case to share the "cache" for dictionary-values,
// in case of circular structures involving links.
result[key] = Object.fromEntries(
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
"postinstall": "node scripts/submit-analytics.js"
},
"dependencies": {
"@realm.io/common": "^0.1.3",
"@realm.io/common": "^0.1.4",
"bindings": "^1.5.0",
"bson": "4.4.1",
"clang-format": "^1.6.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/realm-common/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@realm.io/common",
"version": "0.1.3",
"version": "0.1.4",
"description": "Cross-product common code used by Realm",
"main": "./dist/bundle.cjs.js",
"module": "./dist/bundle.es.js",
Expand Down
8 changes: 7 additions & 1 deletion packages/realm-common/src/symbols.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,11 @@
////////////////////////////////////////////////////////////////////////////

// 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)
// which is being proxied, for compatibility when using JSC pre-v11 (#4541)
export const PROXY_TARGET = Symbol("PROXY_TARGET");

// Used to indicate that an object is a proxied Realm.Dictionary, to allow us
// to correctly detect Dictionaries in toJSON when using JSC pre-v11 (#4674)
export const IS_PROXIED_DICTIONARY = Symbol("IS_PROXIED_DICTIONARY");

// todo add test for dict to json in jsc?
2 changes: 1 addition & 1 deletion packages/realm-network-transport/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
},
"license": "SEE LICENSE IN LICENSE",
"dependencies": {
"@realm.io/common": "^0.1.3",
"@realm.io/common": "^0.1.4",
"abort-controller": "^3.0.0",
"node-fetch": "^2.6.0"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/realm-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
},
"dependencies": {
"lodash": "^4.17.21",
"@realm.io/common": "^0.1.2"
"@realm.io/common": "^0.1.4"
},
"devDependencies": {
"@babel/core": "^7.15.5",
Expand Down
2 changes: 1 addition & 1 deletion packages/realm-web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
},
"license": "SEE LICENSE IN LICENSE",
"dependencies": {
"@realm.io/common": "^0.1.3",
"@realm.io/common": "^0.1.4",
"bson": "^4.5.4",
"detect-browser": "^5.2.1",
"js-base64": "^3.7.2"
Expand Down

0 comments on commit 0546806

Please sign in to comment.