Nozbe / WatermelonDB

🍉 Reactive & asynchronous database for powerful React and React Native apps ⚡️
https://watermelondb.dev
MIT License
10.62k stars 600 forks source link

Error: Cannot use 'in' operator to search for 'initializer' in undefined (Model field decorators can only be used for simple properties) #128

Closed bsr203 closed 5 years ago

bsr203 commented 6 years ago

Hi, I was using WatermelonDB for react-native, and trying to setup the same for web. For the same model, schema definition, I am hitting this case https://github.com/Nozbe/WatermelonDB/blob/master/src/decorators/common.js#L21 Model field decorators can only be used for simple properties - method, setter or getter

This is the field definition

...
  @field('text')
  // @ts-ignore
  text;
...

which is not changed from native, and looks similar to other fields. But, I didn't follow changes to the package for a month and uses latest release now.

Also, instead of above error message, it throws error because descriptor is undefined.

TypeError: Cannot use 'in' operator to search for 'initializer' in undefined
ensureDecoratorUsedProperly
node_modules/@nozbe/watermelondb/decorators/common.js:21
  18 | 
  19 | function ensureDecoratorUsedProperly(columnName, target, key, descriptor) {
  20 |   (0, _invariant.default)(columnName, "Pass column name (raw field name) to the decorator - error in ".concat(target.constructor.name, ".prototype.").concat(key, " given."));
> 21 |   (0, _invariant.default)('initializer' in descriptor, "Model field decorators can only be used for simple properties - method, setter or getter ".concat(target.constructor.name, ".prototype.").concat(key, " given."));
  22 |   (0, _invariant.default)(!(0, _is.default)(Function, descriptor.initializer), "Model field decorators must not be used on properties with a default value - error in \"".concat(target.constructor.name, ".prototype.").concat(key, "\"."));
  23 | }
View compiled

thank you.

bsr203 commented 6 years ago

I take it back saying the schema, model definition is not changed. I keep them as a shared local repo to share between web and native, and using the package using yarn link. so using the compiled code now. so, I assume I might be using the transpiled code now, and it is.

    __decorate([
        decorators_1.field('text')
    ], Message.prototype, "text", void 0);

I import the shared lib as

import { dbSchema } from 'xyz-shared/lib/models/schema';
import createDatabase from 'xyz-shared/lib/models/db';

const adapter = new LokiJSAdapter({
  dbName: 'xyz',
  schema: dbSchema
});

...

const database = createDatabase(adapter)
....

is that ok. Or how can I achieve a common schema/model and import as a npm package?

I am not sure how to avoid the usage of decorator and define the fields directly :-(

bsr203 commented 6 years ago

@radex could you please give me some pointers as I am stuck at this. Any help is appreciated.

radex commented 6 years ago

sorry about this! will investigate tomorrow

radex commented 6 years ago

@bsr203 hey, can you show me your babel configuration? Looks like your decorator is misapplied.

PS. You could contribute an improvement to the error message, since I have 'initializer' in descriptor and there should first be an invariant(descriptor,decorator not applied to a property`)

bsr203 commented 6 years ago

@radex Thanks for getting back to me. this is my babelrc

shared

{
  "presets": [
    "@babel/preset-react",
    "@babel/preset-typescript",
    "@babel/preset-env"
  ],
  "plugins": [
    [
      "@babel/plugin-proposal-decorators",
      {
        "legacy": true
      }
    ],
    ["@babel/plugin-proposal-class-properties", { "loose": true }],
    [
      "@babel/plugin-transform-runtime",
      {
        "helpers": true,
        "regenerator": true
      }
    ]
  ]
}

web

{
  "presets": [["react-app", { "flow": false, "typescript": true }]],
  "plugins": [
    [
      "@babel/plugin-proposal-decorators",
      {
        "legacy": true
      }
    ],
    ["@babel/plugin-proposal-class-properties", { "loose": true }],
    [
      "@babel/plugin-transform-runtime",
      {
        "helpers": true,
        "regenerator": true
      }
    ]
  ]
}
bsr203 commented 6 years ago

watermelonissue.zip

Hi @radex please see the attached file, which has 2 folders

  1. shared : shared model, which is compiled to es5/ commonjs.
  2. web : a CRA app, ejected to add watermelonDB config.

to reproduce: on shared:

yarn install
yarn build (the transpiled code is in lib)
yarn link

on web

yarn install
yarn link "shared"
yarn start

please let me know if you need any clarification.

greatly appreciate your time on this. bsr.

stale[bot] commented 5 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

davideweaver commented 5 years ago

I know this has been closed, but has anyone figured out a workaround for this issue?

I get the error Cannot use 'in' operator to search for 'initializer' in undefined when the @field decorator is used because descriptor is undefined.

I'm using React-native with TypeScript

henrymoulton commented 5 years ago

@davideweaver any luck solving this issue?

henrymoulton commented 5 years ago

This is happening during our Jest test run using ts-jest.

TypeError: Cannot use 'in' operator to search for 'initializer' in undefined
  at ensureDecoratorUsedProperly (node_modules/@nozbe/watermelondb/decorators/common.js:17:41)
  at node_modules/@nozbe/watermelondb/decorators/field/index.js:25:45
  at Object.__decorate (node_modules/tslib/tslib.js:90:114)
  at Object.<anonymous> (packages/main/services/transactions/models/Transaction.model.ts:213:9)
  at Object.<anonymous> (packages/main/services/transactions/models/index.ts:6:53)
davideweaver commented 5 years ago

I found out this is happening because the code generated by TypeScript for decorators doesn’t work with the decorator code generated by this project. TypeScript doesn’t pass property descriptors when the decorator is instantiated. I think TypeScript generates older-style decorator code.

vdlindenmark commented 5 years ago

@radex, could you reopen this issue? It's still an issue in the latest version of WatermelonDB. I successfully moved from Realm to WatermelonDB(and I really love it!), only the tests are failing now because of this issue.

radex commented 5 years ago

Sure! Maybe we need to tweak Babel config for Watermelon? Or maybe it's better for TypeScript projects to use 🍉 source code (with babel config to transpile in the project)?

vdlindenmark commented 5 years ago

Did anybody of you found already a fix for this issue? I've struggled with this issue for one hour now but I couldn't solve it :-(

davideweaver commented 5 years ago

Not the ideal solution, but I use patch-package to patch the watermelon-db package after install. I comment out the checks in /node_modules/@nozbe/watermelondb/decorators/common.js. I don't know how to resolve the differences between TypeScript and the code generated in this package.

radex commented 5 years ago

@davideweaver and decorators still work this way?

davideweaver commented 5 years ago

@radex I can't be 100% sure, but it doesn't look like any decorators you are using actually utilize the descriptor argument passed to them. TypeScript doesn't pass descriptor in the code it generates for setting up decorators.

correction @lazy does not work because it depends on descriptor

radex commented 5 years ago

Great! In that case this should be as simple as changing the invariant to only check for initializer if descriptor is present. Can uou send a quick PR?