Realm-js: "realm.objectForPrimaryKey" result missing `addListener` function

Created on 2 Jul 2019  路  15Comments  路  Source: realm/realm-js

Bug

For React Native, the result from realm.objectForPrimaryKey should have the addListener function present, but it is missing from the resulting object if the schema is defined using classes.

Expected Results

When I do the below, I expect the addListener function to be present, and log true.

const person = realm.objectForPrimaryKey('Person', id);
console.log(person.addListener != null);

Actual Results

person.addListener is undefined, so it logs false.

Steps to Reproduce

Please note I have used __classes__ with static schema properties to define the models. I have read the docs, and am aware that there is a large warning that says classes are not fully supported, but should work in react-native, so I used them anyways.

Code Sample

// App.js - Created from an ejected expo app
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import Realm from 'realm';

const DogSchema = {
  name: 'Dog',
  primaryKey: 'id',
  properties: {
    id: 'int',
    name: 'string',
  },
}
class Cat { }
Cat.schema = {
  name: 'Cat',
  primaryKey: 'id',
  properties: {
    id: 'int',
    name: 'string',
  },
}

const schema = [
  DogSchema, // This works
  Cat        // This doesn't
]

export default class App extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      realm: null,
      dog: undefined,
      cat: undefined,
    };
  }

  componentWillMount() {
    Realm.open({ schema }).then(realm => {
      realm.write(() => {
        realm.create('Dog', { name: 'Rex', id: 0 }, true);
        realm.create('Cat', { name: 'Tilly', id: 0 }, true);
      });
      this.setState({ 
        realm,
        dog: realm.objectForPrimaryKey('Dog', 0),
        cat: realm.objectForPrimaryKey('Cat', 0),
      });
    });
  }

  render() {
    let dogInfo = 'Loading...';
    let catInfo = '';
    if (this.state.realm) {
      dogInfo = `dog.addListener exist? ${this.state.dog.addListener != null}`;
      catInfo = `cat.addListener exist? ${this.state.cat.addListener != null}`;
    }

    return (
      <View style={styles.container}>
        <Text>{dogInfo}</Text>
        <Text>{catInfo}</Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
});

This results in:

Version of Realm and Tooling

  • Realm JS SDK Version: 3.0.0-beta.1
  • Node: 10.15.3
  • React Native: 0.57.8
  • Client OS & Version: Android 9
  • Which debugger for React Native: None
O-Community T-Doc

Most helpful comment

@Fawxy I've made a npm library to better support TypeScript class based models, including the addition of decorators. This should be easier than me posting all my setup, interfaces, and classes.

Check it out here: __realm-ts-class-decorators__

@model("Cat")
export default class Cat extends RealmModel {
  @property({ type: "int", primaryKey: true }) public id!: number;
  @property("string") public name!: string;
}

All 15 comments

@aklinker1 I believe that the isse is that you use the Cat class and not Cat.schema when opening the Realm. It looks like a regression on our side. We have made some changes in that area of the code recently. As a workaround, I suggest that you use Cat.schema.

Yeah, I could just switch over to the schema object, but there are a lot of benefits to using classes instead. For example we have a lot of helper functions on our model classes for computing values or doing more complex updates. They could be switch from something like person.fullname() to PersonUtils.fullname(person), but I'd like to avoid any unnecessary refactoring if possible.

If it is a regression issue, do you think going back a few versions would make it work, and if so, would you have a version you would suggest? I have tried 2.26.1 (I used to use that), but after trying it out, the same issue happens on that version as well.

Hopefully this will be fixed by the time 3.0.0 comes out! For now, I'm probably just going to forgo the listener but if I really need it, I'll switch to using just the schema objects as you suggested.

@aklinker1 I fully understand why it can be convient to use classes. Unfortunately, RN and node.js differ a bit when it comes to classes.

I can't tell you when we introduced the regression and we need to investigate it.

@kneth Thanks for the help, I'll go with just using the schema object for now.

The documentation should be changed then, shouldn't it? I believe many people just as myself built pretty much everything using classes in RN and when you find out this issue you have to manually go through the entire code to change from class methods to custom helpers... I'm not blaming Realm or anything, just pointing something that should be mentioned in the Docs.

@vinicarra Maybe the explanation can be better at https://realm.io/docs/javascript/latest#models (see section "Classes") but it is mentioned in the documentation.

So... Making the class extend RealmObject makes it work.

class Cat extends Realm.Object {} // <- This line
Cat.schema = {
  name: 'Cat',
  primaryKey: 'id',
  properties: {
    id: 'int',
    name: 'string',
  },
}

Another issue from 11 days ago, #2494, also had this problem, and someone suggested extending Realm.Object as I have above.

The main issue now is that it does not support typescript, which I also happen to use. So closing this here because the solution was found to this problem.

___This should definitely be in the docs___

Reopening to enhance docs.

Have just run into typescript support issues, I was hoping to be able to use classes in this new RN project.

Yeah, @Fawxy we also have a typescript project, and had to do some funky typing to get around that. I'll try and post our setup later.

That would be super helpful! Trying to make typescript understand this stuff is a bit of a challenge 馃槵

@Fawxy I've made a npm library to better support TypeScript class based models, including the addition of decorators. This should be easier than me posting all my setup, interfaces, and classes.

Check it out here: __realm-ts-class-decorators__

@model("Cat")
export default class Cat extends RealmModel {
  @property({ type: "int", primaryKey: true }) public id!: number;
  @property("string") public name!: string;
}

@aklinker1 FYI looks like the Typescript bug was fixed in https://github.com/realm/realm-js/pull/3103 by @steffenagger (was back ported to 6.0.4 from v10)

@hudon this was not a TS bug, it was a JS one. The function didn't exist when the types said it did.

Sorry I should've been more specific: extending Object.realm works now, and this in turn prevents the "missing method" issue. Extending Object.realm used to throw TS errors.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

CrystalRanita picture CrystalRanita  路  3Comments

emrehayirci picture emrehayirci  路  3Comments

jmartindivmedianet picture jmartindivmedianet  路  3Comments

max-zu picture max-zu  路  3Comments

kevinnguy picture kevinnguy  路  3Comments