Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Class constructor Model cannot be invoked without 'new' and how getter v4 work? #7840

Closed
zonorion opened this issue Jun 25, 2017 · 30 comments
Closed

Comments

@zonorion
Copy link

zonorion commented Jun 25, 2017

Hi all,
I using v4 to defined my model as:

@Options({
    sequelize,
    tableName: 'V2_category',
    timestamps: false
})
@Attributes({
    id: {
        type: DataTypes.INTEGER,
        allowNull: false,
        primaryKey: true,
        autoIncrement: true
    },
    name: DataTypes.STRING,
    name_vi: DataTypes.STRING,
    code: DataTypes.STRING,
    type: DataTypes.STRING,
    created_at: DataTypes.DATE,
    updated_at: DataTypes.DATE,
})
export class V2Category extends Model {
    get fullName() {
        return this.name + '-' + this.name_vi;
    }

    set fullName(fullName) {
        const names = fullName.split(' ');
        this.name = names.pop();
        this.name_vi = names.join(' ');
    }
}

and i import in others:
import {V2Category as category} from '../models/V2_category';

my query :
findCategoryById (id) { return category.findOne({ where: { 'id': id } }); }

When run i got an error:

Unhandled rejection TypeError: Class constructor Model cannot be invoked without 'new'

However, i add { where: { 'id': id }, raw: true } my code working but i can't use getter function fullName. Could you tell me where my mistake and how to fix it? Thanks

@felixfbecker
Copy link
Contributor

Please post the whole stack trace

@kalyuk
Copy link

kalyuk commented Jun 29, 2017

I had the same problem

During debugging I found out that the Model constructor returns a class instead of a function

I have a suspicion that the problem arises at the moment of inheritance

@felixfbecker
Copy link
Contributor

In JavaScript, a class is a function.

@kalyuk
Copy link

kalyuk commented Jun 29, 2017

@felixfbecker nice joke, I'm very familiar with JS
I could not understand why he inherited this error when he inherited
But if you go the old way and use define, the error disappears
static build(values, options) {
if (Array.isArray(values)){
return this.bulkBuild(values, options);
}
return new this(values, options); }`

@HriBB
Copy link

HriBB commented Jul 5, 2017

I have the same problem.

@HriBB
Copy link

HriBB commented Jul 16, 2017

I think it has something to do with the way babel transpiles the code. After I changed my .babelrc file to this:

{
  "presets": [
    ["env", {
      "targets": {
        "node": "current"
      }
    }]
  ]
}

it works as expected.

@felixfbecker
Copy link
Contributor

Yes, that is very likely.
@zonorion could you post the transpiled JS of that model?

@SuperPaintman
Copy link

Intypescript case, my solution was to change target from es5 to es6

{
  "compilerOptions": {
    "target": "es6", // <=
    // ...
  }
}

@tybro0103
Copy link

I'm getting this as well. Just upgraded from 3 to 4.4.2, and when I change my model definitions to:

const attributes = {/*...*/};
const options = {
  sequelize,
};
class User extends Sequelize.Model {
  someInstanceMethod() {}
}
User.someStaticMethod = () => {};
User.init(attributes, options);

I started seeing the error anytime Sequelize attempted to create an instance of User (such as User.findOne()).

My .babelrc:

{
  "presets": ["es2015", "react", "stage-0"]
}

Switching to this for now:

const User = sequelize.define('User', attributes, options);
User.prototype.someInstanceMethod = function() {}; // function can't be () => {}
User.someClassMethod = () => {};

@cinic
Copy link

cinic commented Aug 17, 2017

@juhaelee says:

You just need to use the env preset package instead of es2015

  "presets": [
    ["env", {
      "targets": {
        "node": "current"
      }
      }],
    "stage-1"
  ],
  "plugins": []
}

@zonorion
Copy link
Author

Sr, i missed any notifications
I used:
{ "presets": [ "es2015-node6", "stage-3" ], "plugins": [ ["transform-decorators-legacy"], [ "transform-runtime", { "polyfill": false, "regenerator": true } ], [ "istanbul", { "exclude": [ "test/*.js" ] } ] ] }

sequelize woking fine!

@BjarkeNL
Copy link

BjarkeNL commented Sep 14, 2017

It turns out that an ES6-class transpiled by babel can't extend a real ES6 class (The Sequelize.Model ES6-class for example).

So class MyEntity extends Sequelize.Model { ... } won't work if MyEntity is transpiled into ES5.

See https://stackoverflow.com/questions/36577683/babel-error-class-constructor-foo-cannot-be-invoked-without-new

The solution i used, was to use es2015-node5 instead of es2015. But ONLY on the server, of course, not on the client - i.e. not when transpiling for the browser. So i didn't put this in my .babelrc, but added it to the "build-server" command-line scripts in package.json instead: babel .... --no-babelrc --presets=es2015-node5,stage-0,react.

@corneliouzbett
Copy link

have almost the same problem how do i solve it ... looking for a solution

@kalyuk
Copy link

kalyuk commented Nov 2, 2018

@corneliouzbett

have almost the same problem how do i solve it ... looking for a solution

do you found solution ?

@christopher4lis
Copy link
Contributor

I'm getting this error as well when using some of the example code listed within Express / Sequelize setup. Seems the the offending line of code is within the cli's default generated models/index.js

const model = sequelize['import'](path.join(__dirname, file))

Altered things with babel and so forth, but haven't gotten it working just yet.

@christopher4lis
Copy link
Contributor

Turns out in my case, I had a previously created model in the models folder that was causing things to break:

const Sequelize = require('sequelize')
const db = require('../sequelize')

const Post = db.define('post', {
    title: Sequelize.STRING(255),
    body: Sequelize.TEXT('long'),
    excerpt: Sequelize.STRING(500),
    tags: Sequelize.STRING(500),
    slug: Sequelize.STRING(255),
    thumbnail_path: Sequelize.STRING(255),
    hero_path: Sequelize.STRING(255),
    updatedAt: Sequelize.DATE
})

module.exports = Post

This was preventing the file from being read correctly by sequelize and causing the error listed in this thread. Advice for others: Make sure all of your code inside of your models folder is valid and from examples.

@mschipperheyn
Copy link

For those running into this, this is a bug in babel. I haven't been able to solve it on my end using the suggested solutions likely because I use babel runtime transformations. There is a PR open @babel to resolve this. Hopefully it will be merged soon. babel/babel#8656

@cpkenn09y
Copy link

Mine got solved via:

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": {
          "node": true
        }
      }
    ]
  ]
}

@jcfinnerup
Copy link

jcfinnerup commented Apr 17, 2019

Im not using a transpiler and i have this error as well

@TidyIQ
Copy link

TidyIQ commented Apr 27, 2019

Same issue here and my .babelrc is:

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": {
          "node": "current"
        }
      }
    ]
  ]
}

Any other suggestions to solve this?

@damien-git
Copy link

Just in case it helps someone else: in my case the issue was that I was using --presets @babel/preset-env with the babel command, so my babel.config.js file with presets: [['@babel/preset-env', {targets: {node: 'current'}}]] was being ignored...

@duckbrain
Copy link

For anyone having trouble with this using Jest and Expo (React Native), you may need to add sequelize to to the transformIgnorePatterns in the jest config.

My jest.config.js
module.exports = {
  preset: "jest-expo",
  reporters: [
    "default",
    [
      "./node_modules/jest-html-reporters",
      {
        filename: "./public/test-report.html",
        pageTitle: "BioPointe: Unit Tests",
      },
    ],
  ],
  coverageDirectory: "./public/coverage",
  snapshotSerializers: ["./src/BioPointe.serializer.js"],
  transformIgnorePatterns: [
    "node_modules/(?!((jest-)?" +
      // If having issues with complation/runtime in tests regarding language
      // features, you may want to add entries to this array for the relevant
      // modules.
      [
        "react-native",
        "react-clone-referenced-element",
        "expo(nent)?",
        "@unimodules/.*",
        "jest-expo/.*",
        "@expo(nent)?/.*",
        "react-navigation",
        "@react-navigation/.*",
        "sentry-expo",
        "sequelize",
        "native-base",
        "@sentry/.*",
        "unimodules-.*",
      ].join("|") +
      "))",
  ],
};

@acharb
Copy link

acharb commented Apr 18, 2020

For anyone who comes to this and the reason was not transpiling. For me it was because I was exporting my models as classes, and the line from the generated models/index.js :

const model = sequelize['import'](path.join(__dirname, file))

was causing the error. Once I changed that line to:

let model = require(path.join(__dirname, file));

It was fixed

@cuongndc
Copy link

cuongndc commented May 17, 2020

Hi guys, I have the same issue with tsc (TypeScript compiler).

tscconfig.json

{
  "compilerOptions": {
    "target": "ES6",
    "module": "CommonJS",
    "moduleResolution": "node",
    "lib": ["ES5", "ES6"],
    "declaration": true,
    "outDir": "./build",
    "strict": true,
    "esModuleInterop": true,
    "allowJs": false,
    "allowSyntheticDefaultImports": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "strictPropertyInitialization": false,
    "sourceMap": true
  },
  "include": ["src"],
  "exclude": ["node_modules"]
}

version

{
  "sequelize": "^5.21.6",
  "ts-node": "^8.10.1",
  "typescript": "^3.7.2"
}

model

import { Model, DataTypes } from 'sequelize';
import sequelize from './';
import { OrderStatus } from '../components/constants';

class Order extends Model {
  public id!: number;
  public total!: number;
  public finalTotal!: number;
  public status: OrderStatus;
  public start_date: Date;
  public end_date: Date;
  public created_at: Date;
  public updated_at: Date;
}

Order.init({
  id: {
    type: DataTypes.UUID,
    primaryKey: true,
    defaultValue: DataTypes.UUIDV4
  },
  total: {
    type: DataTypes.INTEGER,
    allowNull: true,
  },
  finalTotal: {
    type: DataTypes.INTEGER,
    allowNull: true,
    validate: {
      len: {
        args: [2, 5],
        msg: 'Name must be from 2 to 5 characters in length'
      },
    }
  },
  status: {
    type: DataTypes.ENUM(OrderStatus.InProcess, OrderStatus.Done)
  },
}, {
  sequelize,
  tableName: 'orders',
})

export default Order;

sequelize.import

const modelsPath = `${__dirname}/../src/models`;
  const models = fs
    .readdirSync(modelsPath)
    .filter((filename: string) => /model.ts$/.test(filename))
    .reduce((total: any, filename: string) => {
      const model = sequelize.import(path.join(modelsPath, filename));
      total[capitalize(model.name)] = model;
      return total;
    }, {});

  // Sets up the associations for each model.
  Object.keys(models).forEach((modelName: string) => {
    if ('associate' in models[modelName]) {
      models[modelName].associate(models);
    }
  });

error

TypeError: Class constructor Order cannot be invoked without 'new'
      at Sequelize.import (node_modules/sequelize/lib/sequelize.js:486:38)
      at /home/cuongw/Workspace/SaveMoney/service-template/test/utils.ts:18:37
      at Array.reduce (<anonymous>)
      at Object.exports.prepareModels (test/utils.ts:17:6)
      at Object.exports.loadFixtures (test/utils.ts:35:18)
      at Context.<anonymous> (test/order.test.ts:16:11)
      at processImmediate (internal/timers.js:456:21)

Please tell me a solution. Thank all.

@svfreitas
Copy link

svfreitas commented May 18, 2020

I had the same error with typescript and it was fixed when I updated the tsconfig.json changing the es5 for es6

"compilerOptions": {
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. /
"module": "commonjs", /
Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */

@cuongndc
Copy link

I had the same error with typescript and it was fixed when I updated the tsconfig.json changing the es5 for es6

"compilerOptions": {
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. / "module": "commonjs", / Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */

Thank for your reply. I used ES6 for target but it doesn't work.

@cuongndc
Copy link

Hi guys, I have the same issue with tsc (TypeScript compiler).

tscconfig.json

{
  "compilerOptions": {
    "target": "ES6",
    "module": "CommonJS",
    "moduleResolution": "node",
    "lib": ["ES5", "ES6"],
    "declaration": true,
    "outDir": "./build",
    "strict": true,
    "esModuleInterop": true,
    "allowJs": false,
    "allowSyntheticDefaultImports": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "strictPropertyInitialization": false,
    "sourceMap": true
  },
  "include": ["src"],
  "exclude": ["node_modules"]
}

version

{
  "sequelize": "^5.21.6",
  "ts-node": "^8.10.1",
  "typescript": "^3.7.2"
}

model

import { Model, DataTypes } from 'sequelize';
import sequelize from './';
import { OrderStatus } from '../components/constants';

class Order extends Model {
  public id!: number;
  public total!: number;
  public finalTotal!: number;
  public status: OrderStatus;
  public start_date: Date;
  public end_date: Date;
  public created_at: Date;
  public updated_at: Date;
}

Order.init({
  id: {
    type: DataTypes.UUID,
    primaryKey: true,
    defaultValue: DataTypes.UUIDV4
  },
  total: {
    type: DataTypes.INTEGER,
    allowNull: true,
  },
  finalTotal: {
    type: DataTypes.INTEGER,
    allowNull: true,
    validate: {
      len: {
        args: [2, 5],
        msg: 'Name must be from 2 to 5 characters in length'
      },
    }
  },
  status: {
    type: DataTypes.ENUM(OrderStatus.InProcess, OrderStatus.Done)
  },
}, {
  sequelize,
  tableName: 'orders',
})

export default Order;

sequelize.import

const modelsPath = `${__dirname}/../src/models`;
  const models = fs
    .readdirSync(modelsPath)
    .filter((filename: string) => /model.ts$/.test(filename))
    .reduce((total: any, filename: string) => {
      const model = sequelize.import(path.join(modelsPath, filename));
      total[capitalize(model.name)] = model;
      return total;
    }, {});

  // Sets up the associations for each model.
  Object.keys(models).forEach((modelName: string) => {
    if ('associate' in models[modelName]) {
      models[modelName].associate(models);
    }
  });

error

TypeError: Class constructor Order cannot be invoked without 'new'
      at Sequelize.import (node_modules/sequelize/lib/sequelize.js:486:38)
      at /home/cuongw/Workspace/SaveMoney/service-template/test/utils.ts:18:37
      at Array.reduce (<anonymous>)
      at Object.exports.prepareModels (test/utils.ts:17:6)
      at Object.exports.loadFixtures (test/utils.ts:35:18)
      at Context.<anonymous> (test/order.test.ts:16:11)
      at processImmediate (internal/timers.js:456:21)

Please tell me a solution. Thank all.

I resolved my issue. I used require instead of sequelize.import. 😓

Smarthard added a commit to Palus-Somni-Team/shikicinema-server that referenced this issue Jul 30, 2020
@marcosAJS
Copy link

Intypescript case, my solution was to change target from es5 to es6

{
  "compilerOptions": {
    "target": "es6", // <=
    // ...
  }
}

Works for me! Thanks

@yungnoey
Copy link

let model = require(path.join(__dirname, file))

I am having the same issue, changed the appropriate line, still no luck.

@AlexStiyer
Copy link

After much searching I found that this error does sometimes occur when the entity column type cannot be inferred.

These are the only values that can automap:
string | STRING
boolean | BOOLEAN
number | INTEGER
bigint | BIGINT
Date | DATE
Buffer | BLOB

If you are using any other value, for example a UUID you need to set that in the column annotation
@column({type: DataType.UUIDV4})

Hope that helps anyone else going down this rabbit hole.

LuckyWindsck added a commit to LuckyWindsck/myfontsns-backend that referenced this issue May 3, 2021
Code is executed in nodeJS, so we can raise the target version.

Also, this patch prevent the sequelize error below:
  `Class constructor Model cannot be invoked without 'new'`

Solution:
  sequelize/sequelize#7840 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests