diff --git a/CHANGELOG.md b/CHANGELOG.md index cafecff61a..d4d733e066 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ NOTE: This version bumps the Realm file format to version 11. It is not possible ### Fixed * Fixed a crash when calling `user.apiKeys.fetchAll()`. ([#3067](https://github.com/realm/realm-js/pull/3067)) * Fixed calling `app.emailPasswordAuth.resetPassword` and `app.emailPasswordAuth.callResetPasswordFunction`, which would throw an error of mismatch in count of arguments. ([#3079](https://github.com/realm/realm-js/pull/3079)) +* realm.delete throws an exception `Argument to 'delete' must be a Realm object or a collection of Realm objects.` for schema objects defined with JS class syntax and not inheriting from RealmObject [2848](https://github.com/realm/realm-js/issues/2848). ### Compatibility * MongoDB Realm Cloud. diff --git a/src/jsc/jsc_class.hpp b/src/jsc/jsc_class.hpp index 36b5754cf8..a8b51c0368 100644 --- a/src/jsc/jsc_class.hpp +++ b/src/jsc/jsc_class.hpp @@ -600,6 +600,7 @@ bool ObjectWrap::has_instance(JSContextRef ctx, JSValueRef value) { return false; } + //search for RealmObjectClassConstructor on the prototype chain of the object JSObjectRef proto = try_get_prototype(ctx, object); while (proto != nullptr && !JSValueIsNull(ctx, proto)) { if (JSValueIsStrictEqual(ctx, proto, RealmObjectClassConstructorPrototype)) { @@ -609,6 +610,14 @@ bool ObjectWrap::has_instance(JSContextRef ctx, JSValueRef value) { proto = try_get_prototype(ctx, proto); } + //handle RealmObjects using user defined ctors without extending RealmObject. + //In this case we just check for existing internal value to identify RealmObject instances + auto internal = ObjectWrap::get_internal(ctx, object); + if (internal != nullptr) { + return true; + } + + //if there is no RealmObjectClass on the prototype chain and the object does not have existing internal value then this is not an RealmObject instance return false; } diff --git a/src/node/node_class.hpp b/src/node/node_class.hpp index 1782a21cd4..f46b0bc547 100644 --- a/src/node/node_class.hpp +++ b/src/node/node_class.hpp @@ -490,6 +490,18 @@ inline bool WrappedObject::is_instance(Napi::Env env, const Napi::Obj isInstanceOf = instance.InstanceOf(ctor); } + //handle RealmObjects with user defined ctors without extending RealmObject + //In this case we just check for existing internal value to identify RealmObject instances + if (!isInstanceOf) { + bool isRealmObjectClass = std::is_same>::value; + if (isRealmObjectClass) { + Napi::External external = object.Get(ExternalSymbol).As>(); + if (!external.IsUndefined()) { + return true; + } + } + } + return isInstanceOf; } diff --git a/tests/js/realm-tests.js b/tests/js/realm-tests.js index c96d377b86..134bbe304e 100644 --- a/tests/js/realm-tests.js +++ b/tests/js/realm-tests.js @@ -131,7 +131,7 @@ module.exports = { Object.setPrototypeOf(Car2, Realm.Object); //test class syntax support without extending Realm.Object - let car3ConstructorCalled = true; + let car3ConstructorCalled = false; class Car3 { constructor() { car3ConstructorCalled = true; @@ -155,7 +155,7 @@ module.exports = { TestCase.assertEqual(car.make, "Audi"); TestCase.assertEqual(car.model, "A4"); TestCase.assertEqual(car.kilometers, 24); - TestCase.assertTrue(car instanceof Realm.Object); + TestCase.assertInstanceOf(car, Realm.Object, "car not an instance of Realm.Object"); let cars = realm.objects("Car"); TestCase.assertUndefined(cars[""]); @@ -163,7 +163,7 @@ module.exports = { TestCase.assertEqual(carZero.make, "Audi"); TestCase.assertEqual(carZero.model, "A4"); TestCase.assertEqual(carZero.kilometers, 24); - TestCase.assertTrue(carZero instanceof Realm.Object); + TestCase.assertInstanceOf(carZero, Realm.Object, "carZero not an instance of Realm.Object"); constructorCalled = false; let car1 = realm.create('Car', { make: 'VW', model: 'Touareg', kilometers: 13 }); @@ -171,28 +171,27 @@ module.exports = { TestCase.assertEqual(car1.make, "VW"); TestCase.assertEqual(car1.model, "Touareg"); TestCase.assertEqual(car1.kilometers, 13); - TestCase.assertTrue(car1 instanceof Realm.Object); + TestCase.assertInstanceOf(car1, Realm.Object, "car1 not an instance of Realm.Object"); let car2 = realm.create('Car2', { make: 'Audi', model: 'A4', kilometers: 24 }); TestCase.assertTrue(calledAsConstructor); TestCase.assertEqual(car2.make, "Audi"); TestCase.assertEqual(car2.model, "A4"); TestCase.assertEqual(car2.kilometers, 24); - TestCase.assertTrue(car2 instanceof Realm.Object); + TestCase.assertInstanceOf(car2, Realm.Object, "car2 not an instance of Realm.Object"); let car2_1 = realm.create('Car2', { make: 'VW', model: 'Touareg', kilometers: 13 }); TestCase.assertTrue(calledAsConstructor); TestCase.assertEqual(car2_1.make, "VW"); TestCase.assertEqual(car2_1.model, "Touareg"); TestCase.assertEqual(car2_1.kilometers, 13); - TestCase.assertTrue(car2_1 instanceof Realm.Object); + TestCase.assertInstanceOf(car2_1, Realm.Object, "car2_1 not an instance of Realm.Object"); let car3 = realm.create('Car3', { make: 'Audi', model: 'A4', kilometers: 24 }); TestCase.assertTrue(car3ConstructorCalled); TestCase.assertEqual(car3.make, "Audi"); TestCase.assertEqual(car3.model, "A4"); TestCase.assertEqual(car3.kilometers, 24); - TestCase.assertFalse(car3 instanceof Realm.Object); //methods from Realm.Objects should be present TestCase.assertDefined(car3.addListener);