realm / realm-js

Realm is a mobile database: an alternative to SQLite & key-value stores
https://realm.io
Apache License 2.0
5.79k stars 577 forks source link

RealmObject cannot be called as a function - Only Android #3876

Closed saravanakumargn closed 3 years ago

saravanakumargn commented 3 years ago

Goals

When I try to use objectForPrimaryKey or objects it's working as expected in Both iOS and Android. like as below:

// Working fine
const categoryData = realmRef.objects<CategorySchema>(CategorySchema).filtered(filterQuery).sorted('name'); 
// Create is not working in Android working fine in iOS
function saveCategory(values: ICategorySchema) {
  try {
    realmRef.write(() => {
      realmRef.create<CategorySchema>(CategorySchema, values, Realm.UpdateMode.Modified);
    });
    setIsCategoryFormModalVisible(false);
  } catch ({message}) {
    // eslint-disable-next-line no-console
    console.error(message);
  }
}
 ERROR  RealmObject cannot be called as a function

Expected Results

No issues while saving in iOS. Should as fine in Android like iOS.

Actual Results

In Android it's throwing {{ ERROR RealmObject cannot be called as a function}} on Create.

Steps to Reproduce

Code Sample

import {UUIDType} from '@src/types';
import Realm from 'realm';
export interface ICategorySchema {
  _id: UUIDType;
  name: string;
  notes?: string;
  categoryType: number; // 0 - Income; 1 - Expenses
}

export class CategorySchema extends Realm.Object implements ICategorySchema {
  public _id: UUIDType;
  public name: string;
  public notes?: string;
  public categoryType: number;

  public static schema: Realm.ObjectSchema = {
    name       : 'Category',
    primaryKey : '_id',
    properties : {
      _id          : 'uuid',
      name         : 'string',
      categoryType : 'int',
      notes        : 'string?'
    }
  };
}
import Realm from 'realm';

import {
  CategorySchema,
} from './schemas';

// prettier-ignore
const realmRef = new Realm(
  {
    schema : [
      CategorySchema, 
    ],
    deleteRealmIfMigrationNeeded : __DEV__
  }
);

export default realmRef;

Version of Realm and Tooling

fronck commented 3 years ago

Hi @saravanakumargn. Thanks for reporting this. We'll look into the issue. Is this a new issue in Realm JS 10.6.1, or have you seen it with previous versions?

takameyer commented 3 years ago

@saravanakumargn I have created a fresh react-native app and implemented the source code you have provided. This works for me without a problem in iOS and Android. The only difference I could see is I am using Realm.BSON.UUID. How are you implementing UUID? Can you provide any other information? Perhaps a sample repository that reproduces this exact issue?

saravanakumargn commented 3 years ago

This is not new code and It was working fine before 10.5.0 and previous versions(My code base was older, and the same implementation I had since v10). Now I changed all my _ids to 'uuid'. So, not able to revert older versions and test the same code.

@takameyer Seems, Declaring schema using const is working fine. Using public static schema not working.

This is my UUID implementation.

const {UUID} = Realm.BSON;

export function getUUID(input?: string | Buffer | undefined): UUIDType {
  if (input) {
    try {
      return new UUID(input);
    } catch ({message}) {
      return new UUID();
    }
  }
  return new UUID();
}
saravanakumargn commented 3 years ago

FYI. This is not because of Reanimated v2 (I had removed and tested). Also, Able to list items using realmRef.objects.

Screenshot_20210728-162847

takameyer commented 3 years ago

@saravanakumargn Ah, are you calling new on your Realm Model class? We do have some known issues involved with making a class extending "Realm.Object". Can you try declaring your class without the extension and doing creates like so: realm.create<ObjectClass>('ObjectClass', value) This may be a workaround until we fix Class Based Models.

saravanakumargn commented 3 years ago

@takameyer

After removing extends Realm.Object able to create the new object and not able to convert results to JSON(). So reverted back I will continue my development in ios.

 WARN  Possible Unhandled Promise Rejection (id: 0):
TypeError: item.toJSON is not a function. (In 'item.toJSON(index.toString(), cache)', 'item.toJSON' is undefined)
takameyer commented 3 years ago

@saravanakumargn the <T> added to any realm query or mutation will add toJSON (among other properties and functions of a realm object) to the return type. What is the line of code providing item in this instance?

saravanakumargn commented 3 years ago

This is my list of objects.

const [listData, setListData] = useState<IBatchSchema[]>();

const batchList: Realm.Results<BatchSchema & Realm.Object> = realmRef
  .objects<BatchSchema>(BatchSchema)
  .filtered(query);

setListData(batchesData.toJSON());
takameyer commented 3 years ago

@saravanakumargn try replacing .objects<BatchSchema>(BatchSchema) with .objects<BatchSchema>('Batch'). If the name of the model is not Batch, then replace it with the correct schema name.

saravanakumargn commented 3 years ago

@takameyer This is working perfectly. Able to create new records using .objects<BatchSchema>('Batch'). But, still toJSON() not working

takameyer commented 3 years ago

@saravanakumargn I can reproduce this. We will check into it and let you know as soon as we find something.

fronck commented 3 years ago

This may be related to #3760.

takameyer commented 3 years ago

@saravanakumargn So I have dug into this deeper. Are you opening your realm with your class or with your schema? If you are using the class, try changing to schema and that should fix the toJSON issue. For example: new Realm({schemas: [CategorySchema.schema]});

umarpazir11 commented 3 years ago

@takameyer

After removing extends Realm.Object able to create the new object and not able to convert results to JSON(). So reverted back I will continue my development in ios.

 WARN  Possible Unhandled Promise Rejection (id: 0):
TypeError: item.toJSON is not a function. (In 'item.toJSON(index.toString(), cache)', 'item.toJSON' is undefined)

I am facing exactly same issue.

saravanakumargn commented 3 years ago

@takameyer Do you have any idea/ETA about this fix in Android?

takameyer commented 3 years ago

@saravanakumargn I cannot say for sure when we will have these classes refactored. Have you tried opening your Realm using the schema object instead of the class? This should be a workaround to fix the TypeError.

saravanakumargn commented 3 years ago

@takameyer EDIT: I was able to create in Both Android and IOS when I used the schema object instead of the class as below code. But when I use toJSON() i am getting below error.

TypeError: item.toJSON is not a function. (In 'item.toJSON(index.toString(), cache)', 'item.toJSON' is undefined)

@takameyer Still I am facing the error only in Android. I have modified my code as below. Please help me to fix this and check is anything I missed?.

Error: Constructor was not registered in the schema for this Realm

My Code:

import Realm from 'realm';

import {
  SettingsSchema,
  ProfileSchema,
} from './schemas';

// prettier-ignore
const realmRef = new Realm(
  {
    schema : [
      SettingsSchema.schema,
      ProfileSchema.schema,
    ],
    deleteRealmIfMigrationNeeded : __DEV__
  }
);

export default realmRef;
import Realm from 'realm';

import {UUIDType} from '@src/types';

export interface ISettingsSchema {
  languageCode: string;
  isRTL?: Boolean;
}

export class SettingsSchema extends Realm.Object implements ISettingsSchema {
  public _id: UUIDType;
  public languageCode: string;
  public isRTL?: Boolean;

  public static schema: Realm.ObjectSchema = {
    name       : 'Settings',
    primaryKey : '_id',
    properties : {
      _id          : 'uuid',
      languageCode : 'string',
      isRTL        : {
        type    : 'bool?',
        default : false
      }
    }
  };
}

Reading from SettingsSchema. Working fine in Android & iOS

const settings = realmRef.objects<SettingsSchema>('Settings')[0];
  function saveProfile(values: ISettingsSchema) {
    try {
      realmRef.write(() => {
        realmRef.create<SettingsSchema>('Settings', values, Realm.UpdateMode.Modified);
      });
      navigation.goBack();
    } catch ({message}) {
      // eslint-disable-next-line no-console
      console.error(message);
    }
  }

Screenshot_20210831-124516 Screenshot_20210831-124507

takameyer commented 3 years ago

I think your non-optional class members should be declared using !. For example:

  public _id!: UUIDType;
  public languageCode!: string;

Other than that, the code looks correct and should be able to use toJSON. What is your implementation of toJSON? If you are querying realm using a string instead of the model class, than toJSON should be defined.

saravanakumargn commented 3 years ago

@takameyer

My issue got resolved. This is because of react-native-animatable v2. I didn't enable enableHermes, in my build.gradle still enableHermes: false. After downgraded react-native-animatable to v1, this undefined issue got resolved with your solution.

Thanks for your all support. really appreciate it.

Android getting an empty object, where iOS getting results of the first object. Because of empty object toJSON() is failing.

function loadProfile() {
    const profileResults = realmRef.objects<ProfileSchema>('Profile').sorted('fullName');
    console.log(profileResults?.length) // 1
    console.log(profileResults?.[0]) // {}
    // setListData(profileResults.toJSON());
  }
takameyer commented 3 years ago

@saravanakumargn Thanks for following up on this. Happy that you were able to get further along. I will now close this issue

tejasNix commented 2 years ago

Still facing the same issue, with @realm/react and the hooks useRealm, useQuery.

image

saravanakumargn commented 2 years ago

@tejasNix without @realm/react is this working fine?

theBeesAtWork commented 2 years ago

@takameyer

The problem still persists on Android because of react-native-reanimatedV2

"react-native": "^0.70.0", "realm": "^10.21.1", "react-native-reanimated": "^2.10.0", "@realm/react": "^0.3.2",

takameyer commented 2 years ago

@theBeesAtWork This should work with:

"realm": "11.0.0-rc.2"
theBeesAtWork commented 2 years ago

Thank you so much. You saved my life @takameyer. It works now with "realm": "11.0.0-rc.2"

ismailsemihsenturk commented 2 years ago

Still having the same error. I just used this template : npx expo-cli init ReactRealmJSTemplateApp -t @realm/expo-template-js photo_2022-09-24_02-45-10

image

ismailsemihsenturk commented 2 years ago

I updated my package.json file to be able to use realm": "11.0.0-rc.2 image

Now it's even worse image

First Error: android/app/build.gradle: image image

kneth commented 2 years ago

@ismailsemihsenturk Please check your dependencies against https://github.com/realm/realm-js/blob/master/COMPATIBILITY.md