sequelize-typescript
sequelize-typescript copied to clipboard
Intance model properties are undefined
Versions
- sequelize: 5.21.7
- sequelize-typescript: 1.1.0
- typescript: 3.8.3
I'm submitting a ...
[ x ] bug report [ ] feature request
Actual behavior:
I execute a findOne
function to get a model instance, but the properties are undefined
Expected behavior: I would like to get the properties values
Steps to reproduce:
const city = await CityModel.findOne({ where: { name: 'example' } })
console.log(city.name);
Related code:
If I execute the city.getDataValue('name')
I see the right value, but simply running city.name
I get undefined
.
If I execute console.log(city)
all works well:
CityModel {
dataValues: {
id: 'fb73e40a-9055-42b8-9a21-d8368ef13222',
name: 'Example',
createdAt: 2020-04-27,
updatedAt: 2020-04-27
},
_previousDataValues: {
id: 'fb73e40a-9055-42b8-9a21-d8368ef13222',
name: 'Example',
createdAt: 2020-04-27,
updatedAt: 2020-04-27
},
...
},
My model:
import {
Model,
Table,
DataType,
Column,
PrimaryKey,
Default,
HasMany,
} from 'sequelize-typescript';
import UserModel from './user.model';
@Table({ tableName: 'Cities', timestamps: true })
class CityModel extends Model<CityModel> {
@PrimaryKey
@Default(DataType.UUIDV4)
@Column(DataType.UUIDV4)
id!: string;
@Column(DataType.STRING)
name!: string;
@Column(DataType.STRING)
initials!: string;
@Column(DataType.STRING)
status!: string;
@HasMany(() => UserModel, 'cityId')
users!: UserModel[];
}
export default CityModel;
Same problem. It seems like I need to call getDataValue
.
I created a quick repo here showing the issue: https://github.com/jrm2k6/laughing-octo-enigma
When running the command to execute a findAll this is what I get back:
Executing (default): SELECT "uuid", "name", "createdAt", "updatedAt", "deletedAt" FROM "users" AS "users" WHERE ("users"."deletedAt" IS NULL);
[
users {
dataValues: {
uuid: '36497139-77d2-4edb-ba49-481a589f2f8c',
name: 'John Smith',
createdAt: 2021-02-22T01:15:35.993Z,
updatedAt: null,
deletedAt: null
},
_previousDataValues: {
uuid: '36497139-77d2-4edb-ba49-481a589f2f8c',
name: 'John Smith',
createdAt: 2021-02-22T01:15:35.993Z,
updatedAt: null,
deletedAt: null
},
_changed: {},
_modelOptions: {
timestamps: true,
validate: {},
freezeTableName: false,
underscored: false,
paranoid: true,
rejectOnEmpty: false,
whereCollection: null,
schema: null,
schemaDelimiter: '',
defaultScope: {},
scopes: {},
indexes: [],
name: [Object],
omitNull: false,
sequelize: [Sequelize],
hooks: {}
},
_options: {
isNewRecord: false,
_schema: null,
_schemaDelimiter: '',
raw: true,
1 node_modules/
attributes: [Array]
},
isNewRecord: false,
uuid: undefined,
name: undefined
}
]
I also use sequelize-typescript with nestjs and I am not having the same issue but haven't found out if it does something different.
Hope that helps so that we can figure out if we are doing something wrong or not.
Thanks!
@jrm2k6 The problem is I can not get the value just using user.name
, but if I use user.getDataValue('name')
works fine.
I tested it with your github project and the result was the same.
@gideaoms Yes, this is why I added a way for anybody to get the same results as we have and see if it is something wrong with our setup or not. Makes it easier for a maintainer to understand the issue and be able to debug if needed.
Ok I did some more investigating and I think in my example, it boils down to using babel-node vs ts-node. In here: https://github.com/jrm2k6/laughing-octo-enigma/commit/e745244c1b995f174adf2d48263b30ac52c49e3c I changed my tsconfig to use commonjs instead of esnext, and use ts-node instead of babel-node.
When I run node -r ts-node/register index.ts
it lets me access the model properties directly. I am not 100% sure yet but I think with the way my babel-node config is set up, it will generate model properties automatically initialized with undefined, overriding what sequelize-typescript might be doing when it comes to accessing model properties. Still a guess though.
Here we go: https://github.com/RobinBuschmann/sequelize-typescript/issues/612
Yep, it makes sense.
Encountered this issue when upgrading typescript from 3 to 4. Data was only in dataValues but not in the class fields. Setting useDefineForClassFields to true in my tsconfig seems to have fixed it.
That's weird. For me doing the exact opposite (setting useDefineForClassFields to false) fixed it. I'm targeting ESNext on Node 14.
I had actually set it to false but just wrote the wrong value in the comment. Thanks.
For me, it had nothing to do with babel (which I wasn't using to begin with).
The solution was entirely to add "useDefineForClassFields": "false"
to my tsconfig.json.
Thanks, @triesmon!
This appears to be the change (and some surrounding discussion) in babel that breaks this behavior:
https://github.com/babel/babel/pull/11747
Take a look at the updated sequelize documentation regarding the issue with class fields: https://sequelize.org/v6/manual/model-basics.html#caveat-with-public-class-fields
The new documentation is a big improvement over where we were at a week ago, unfortunately the declare
keyword trick only works with tsc
tooling and not with babel due to the above linked PR.
The fact that babel still emits public class fields tagged with declare
when using decorators is problematic. Makes sequelize/sequelize#14300 all the more pressing.
I have worked around this in my project with a model class decorator – it's very ugly, but the approach could be used as another way to fix the issue more formally in sequelize by applying the getter/setters after the model constructor.
https://github.com/outline/outline/blob/main/server/models/decorators/Fix.ts
I had this problem as well in Deno 1.32 which doesn't support useDefineForClassFields
. I fixed it by just declare
-ing all my fields:
...
@Column({
allowNull: false,
defaultValue: "",
})
declare myField: string
First of all great project! Strange that README.md not updated with 'declare' workaround, as well as with ReturnType<() => Model>; for associated fields. To prepare PR with "declare" column attributes and "ReturnType" associated attributes?