realm-js icon indicating copy to clipboard operation
realm-js copied to clipboard

Cannot index a property using TypeScript

Open thegreatzeus opened this issue 10 months ago • 8 comments

How frequently does the bug occur?

Always

Description

I'm trying to index a string property on a Realm model using TypeScript.

I'm using Realm's React Native SDK with Realm's Expo example app.

Using the same example from Realm's docs:

class Book extends Realm.Object<Book> {
  name!: string;
  price?: number;

  static schema: ObjectSchema = {
    name: 'Book',
    properties: {
      name: {type: 'string', indexed: true},
      price: 'int?',
    },
  };
}

Results in the following error:

Classes extending Realm.Object cannot define their own `schema` static, 
all properties must be defined using TypeScript syntax

Stacktrace & log output

at visitRealmClass (/AtlasDeviceSdkApp/node_modules/@realm/babel-plugin/dist/plugin/index.js:323:15)
    at PluginPass.ClassDeclaration (/AtlasDeviceSdkApp/node_modules/@realm/babel-plugin/dist/plugin/index.js:375:25)
    at newFn (/AtlasDeviceSdkApp/node_modules/@babel/traverse/lib/visitors.js:160:14)
    at NodePath._call (/AtlasDeviceSdkApp/node_modules/@babel/traverse/lib/path/context.js:46:20)
    at NodePath.call (/AtlasDeviceSdkApp/node_modules/@babel/traverse/lib/path/context.js:36:17)
    at NodePath.visit (/AtlasDeviceSdkApp/node_modules/@babel/traverse/lib/path/context.js:82:31)
    at TraversalContext.visitQueue (/AtlasDeviceSdkApp/node_modules/@babel/traverse/lib/context.js:89:16)
    at TraversalContext.visitSingle (/AtlasDeviceSdkApp/node_modules/@babel/traverse/lib/context.js:65:19)
    at TraversalContext.visit (/AtlasDeviceSdkApp/node_modules/@babel/traverse/lib/context.js:112:19)
    at traverseNode (/AtlasDeviceSdkApp/node_modules/@babel/traverse/lib/traverse-node.js:22:17)
    at NodePath.visit (/AtlasDeviceSdkApp/node_modules/@babel/traverse/lib/path/context.js:88:52)
    at TraversalContext.visitQueue (/AtlasDeviceSdkApp/node_modules/@babel/traverse/lib/context.js:89:16)
    at TraversalContext.visitMultiple (/AtlasDeviceSdkApp/node_modules/@babel/traverse/lib/context.js:61:17)
    at TraversalContext.visit (/AtlasDeviceSdkApp/node_modules/@babel/traverse/lib/context.js:110:19)
    at traverseNode (/AtlasDeviceSdkApp/node_modules/@babel/traverse/lib/traverse-node.js:22:17)
    at NodePath.visit (/AtlasDeviceSdkApp/node_modules/@babel/traverse/lib/path/context.js:88:52)
    at TraversalContext.visitQueue (/AtlasDeviceSdkApp/node_modules/@babel/traverse/lib/context.js:89:16)
    at TraversalContext.visitSingle (/AtlasDeviceSdkApp/node_modules/@babel/traverse/lib/context.js:65:19)
    at TraversalContext.visit (/AtlasDeviceSdkApp/node_modules/@babel/traverse/lib/context.js:112:19)
    at traverseNode (/AtlasDeviceSdkApp/node_modules/@babel/traverse/lib/traverse-node.js:22:17)
    at traverse (/AtlasDeviceSdkApp/node_modules/@babel/traverse/lib/index.js:52:34)
    at transformFile (/AtlasDeviceSdkApp/node_modules/@babel/core/lib/transformation/index.js:82:31)
    at transformFile.next (<anonymous>)
    at run (/AtlasDeviceSdkApp/node_modules/@babel/core/lib/transformation/index.js:24:12)
    at run.next (<anonymous>)
    at /AtlasDeviceSdkApp/node_modules/@babel/core/lib/transform-ast.js:23:33
    at Generator.next (<anonymous>)
    at evaluateSync (/AtlasDeviceSdkApp/node_modules/gensync/index.js:251:28)
    at sync (/AtlasDeviceSdkApp/node_modules/gensync/index.js:89:14)
    at stopHiding - secret - don't use this - v1 (/AtlasDeviceSdkApp/node_modules/@babel/core/lib/errors/rewrite-stack-trace.js:47:12)
    at transformFromAstSync (/AtlasDeviceSdkApp/node_modules/@babel/core/lib/transform-ast.js:43:83)
    at Object.transform (/AtlasDeviceSdkApp/node_modules/metro-react-native-babel-transformer/src/index.js:201:20)
    at transformJSWithBabel (/AtlasDeviceSdkApp/node_modules/metro-transform-worker/src/index.js:330:45)
    at Object.transform (/AtlasDeviceSdkApp/node_modules/metro-transform-worker/src/index.js:461:18)
    at transformFile (/AtlasDeviceSdkApp/node_modules/metro/src/DeltaBundler/Worker.flow.js:73:36)
    at Object.transform (/AtlasDeviceSdkApp/node_modules/metro/src/DeltaBundler/Worker.flow.js:48:10)
    at execFunction (/AtlasDeviceSdkApp/node_modules/jest-worker/build/workers/processChild.js:137:17)
    at execHelper (/AtlasDeviceSdkApp/node_modules/jest-worker/build/workers/processChild.js:116:5)
    at execMethod (/AtlasDeviceSdkApp/node_modules/jest-worker/build/workers/processChild.js:120:5)
    at process.messageListener (/AtlasDeviceSdkApp/node_modules/jest-worker/build/workers/processChild.js:38:7)
    at process.emit (node:events:517:28)
    at emit (node:internal/child_process:944:14)


### Can you reproduce the bug?

Always

### Reproduction Steps

Use the Expo template app and try to define a new model using TypeScript such as [the example](https://www.mongodb.com/docs/realm/sdk/react-native/model-data/define-a-realm-object-model/#index-a-property):

```ts
class Book extends Realm.Object<Book> {
  name!: string;
  price?: number;

  static schema: ObjectSchema = {
    name: 'Book',
    properties: {
      name: {type: 'string', indexed: true},
      price: 'int?',
    },
  };
}

Version

"realm": "12.0.0", "@realm/react": "^0.6.0",

What services are you using?

Local Database only

Are you using encryption?

No

Platform OS and version(s)

Android 14

Build environment

Node v18.19.1

package.json contents:

{
  "name": "atlasdevicesdkapp",
  "version": "1.0.0",
  "scripts": {
    "start": "expo start --dev-client",
    "android": "expo run:android",
    "ios": "expo run:ios"
  },
  "dependencies": {
    "@realm/react": "^0.6.0",
    "expo": "^49.0.8",
    "expo-dev-client": "~2.4.8",
    "expo-splash-screen": "~0.20.5",
    "expo-status-bar": "~1.6.0",
    "react": "18.2.0",
    "react-native": "0.72.4",
    "react-native-get-random-values": "~1.9.0",
    "realm": "12.0.0"
  },
  "devDependencies": {
    "@babel/core": "^7.22.5",
    "@babel/plugin-proposal-decorators": "^7.22.5",
    "@realm/babel-plugin": "^0.1.1",
    "@types/react": "~18.2.13",
    "typescript": "^5.1.3"
  },
  "license": "Apache-2.0",
  "private": true
}

Cocoapods version

No response

thegreatzeus avatar Apr 11 '24 15:04 thegreatzeus

➤ PM Bot commented:

Jira ticket: RJS-2799

sync-by-unito[bot] avatar Apr 11 '24 15:04 sync-by-unito[bot]

@thegreatzeus Thank you for reporting. We need to investigate.

kneth avatar Apr 12 '24 11:04 kneth

I've literally been having same issue! well, same error message Classes extending Realm.Object cannot define their own schema static, all properties must be defined using TypeScript syntax

in my case I'm just trying to create a basic model like so

class Book extends Realm.Object<Book> {
  name!: string;
  price?: number;
  static schema: ObjectSchema = {
    name: 'Book',
    properties: {
      name: 'string',
      price: 'int?',
    },
  };
}

favourwright avatar Apr 12 '24 16:04 favourwright

@thegreatzeus any leads yet?

favourwright avatar Apr 12 '24 16:04 favourwright

Same issue here. Using @thegreatzeus class as example, if I just define my scheme as the following, it works fine

class Book extends Realm.Object<Book> {
  name?: string;
  price?: number;
}

If I add the static scheme: ObjectSchema { ... } code it always throw the error mentioned here. It seems the only way to set a primaryKey is through this ObjectSchema but with this error going on it's impossible.

Is there any work around so far?

jpbast avatar Apr 15 '24 13:04 jpbast

import { Realm } from '@realm/react'
import { BeneficiaryType } from '...'

export class Beneficiary extends Realm.Object {
  _id!: Realm.BSON.ObjectId;
  name!: string;
  ...

  static generate(payload: BeneficiaryType) {
    return {
      _id: new Realm.BSON.ObjectId(),
      name: payload.name,
      ....
    };
  }
}

Object.defineProperty(Beneficiary, 'schema', {
  value: {
    name: 'Beneficiary',
    primaryKey: '_id',
    properties: {
      _id: 'objectId',
      name: 'string',
      ...
    },
  },
});

this is what I ended up using @jpbast

favourwright avatar Apr 15 '24 13:04 favourwright

@favourwright it worked for me! Thanks for your quick reply

jpbast avatar Apr 15 '24 13:04 jpbast

@thegreatzeus, it looks like you're using the @realm/babel-plugin. The idea of that plugin is to simplify some of the model/schema creation by removing the need for the explicit static schema field.

You can either remove the plugin and use the schema as you have defined it, or use the plugin and remove the static schema.

To index a property using the babel-plugin, use the @index annotation. To declare a primary key, use static primaryKey = _id (or whichever key is the pk).

The following is a similar example as the @realm/babel-plugin README:

class Task extends Realm.Object<Task, "description"> {
  _id = new Realm.BSON.ObjectId();
  description!: string;
  @index
  isComplete = false;

  static primaryKey = "_id";
}

elle-j avatar Apr 22 '24 09:04 elle-j