Skip to content

Commit

Permalink
Type resolution fix for Set and friends (#4109)
Browse files Browse the repository at this point in the history
Fixed inconsistent `Realm not defined` errors on types with iterators.
  • Loading branch information
fronck committed Dec 16, 2021
1 parent 77337a6 commit b9f9f92
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 69 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ x.x.x Release notes (yyyy-MM-dd)
* If the option `user` in a sync configuration was not a `Realm.User` object could lead to a crash. ([#1348](https://github.com/realm/realm-js/issues/1348), since v10.0.0)
* `@sum` and `@avg` queries on Dictionaries of floats or doubles used too much precision for intermediates, resulting in incorrect rounding. (since v10.3.0-rc.1)
* Queries of the form `link.collection.@sum = 0` where `link` is `null` matched when `collection` was a List or Set, but not a Dictionary ([realm/realm-core#5080](https://github.com/realm/realm-core/pull/5080), since v10.5.0)
* Type methods defined in `collection-methods.js` no longer throw `Realm not defined` errors in some environments ([#4029](https://github.com/realm/realm-js/issues/4029), [#3991](https://github.com/realm/realm-js/issues/3991), since v10.5.0)
* Fixed a bug in `Realm.App.emailPasswordAuth.callResetPasswordFunction()` which could lead to the error `Error: Error: resetDetails must be of type 'object', got (user@example.com)`. ([#4143](https://github.com/realm/realm-js/issues/4143), since v10.10.0)

### Compatibility
Expand Down
136 changes: 68 additions & 68 deletions lib/collection-methods.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,80 +16,80 @@
//
////////////////////////////////////////////////////////////////////////////

/* global Realm */
module.exports = function (realmConstructor) {
const exportedFunctions = {};
var arrayPrototype = Array.prototype;
// eslint-disable-next-line no-undef
var iteratorPrototype = {};

var arrayPrototype = Array.prototype;
// These iterators should themselves be iterable.
Object.defineProperty(iteratorPrototype, Symbol.iterator, {
value: function () {
return this;
},
});

// eslint-disable-next-line no-undef
var iteratorPrototype = {};
[
"toString",
"toLocaleString",
"concat",
"join",
"slice",
"lastIndexOf",
"every",
"some",
"forEach",
"find",
"findIndex",
"map",
"filter",
"reduce",
"reduceRight",
].forEach(function (methodName) {
var method = arrayPrototype[methodName];
if (method) {
exportedFunctions[methodName] = { value: method, configurable: true, writable: true };
}
});

// These iterators should themselves be iterable.
Object.defineProperty(iteratorPrototype, Symbol.iterator, {
value: function () {
return this;
},
});
["entries", "keys", "values"].forEach(function (methodName) {
var method = function () {
const isSet = this instanceof realmConstructor.Set;
var self = this.type === "object" || isSet ? this.snapshot() : this;
var index = 0;

[
"toString",
"toLocaleString",
"concat",
"join",
"slice",
"lastIndexOf",
"every",
"some",
"forEach",
"find",
"findIndex",
"map",
"filter",
"reduce",
"reduceRight",
].forEach(function (methodName) {
var method = arrayPrototype[methodName];
if (method) {
exports[methodName] = { value: method, configurable: true, writable: true };
}
});
return Object.create(iteratorPrototype, {
next: {
value: function () {
if (!self || index >= self.length) {
self = null;
return { done: true, value: undefined };
}

["entries", "keys", "values"].forEach(function (methodName) {
var method = function () {
// checks for Set datatype. Required for compatibility with node.js, Jest, and RN
// instanceof Set is not performing correctly in Jest tests, so we need to use an alternate method
const isSet = (this.constructor && this.constructor.name === "Set") || this instanceof Realm.Set;
var self = this.type === "object" || isSet ? this.snapshot() : this;
var index = 0;
var value;
switch (methodName) {
case "entries":
value = isSet ? [self[index], self[index]] : [index, self[index]];
break;
case "keys":
value = isSet ? undefined : index;
break;
default:
value = self[index];
break;
}

return Object.create(iteratorPrototype, {
next: {
value: function () {
if (!self || index >= self.length) {
self = null;
return { done: true, value: undefined };
}

var value;
switch (methodName) {
case "entries":
value = isSet ? [self[index], self[index]] : [index, self[index]];
break;
case "keys":
value = isSet ? undefined : index;
break;
default:
value = self[index];
break;
}

index++;
return { done: false, value: value };
index++;
return { done: false, value: value };
},
},
},
});
};
});
};

exportedFunctions[methodName] = { value: method, configurable: true, writable: true };
});

exports[methodName] = { value: method, configurable: true, writable: true };
});
exportedFunctions[Symbol.iterator] = exportedFunctions.values;

exports[Symbol.iterator] = exports.values;
return exportedFunctions;
};
2 changes: 1 addition & 1 deletion lib/extensions.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ function openLocalRealm(realmConstructor, config) {

module.exports = function (realmConstructor) {
// Add the specified Array methods to the Collection prototype.
Object.defineProperties(realmConstructor.Collection.prototype, require("./collection-methods"));
Object.defineProperties(realmConstructor.Set.prototype, require("./set-methods")(realmConstructor));
Object.defineProperties(realmConstructor.Collection.prototype, require("./collection-methods")(realmConstructor));
realmConstructor.DictionaryProxy = require("./dictionary").DictionaryProxy;

setConstructorOnPrototype(realmConstructor.Collection);
Expand Down

0 comments on commit b9f9f92

Please sign in to comment.