11

Can I define a getter of a property as an asyc function in Sequelize?
In the getter I should retrieve a value from another table and I've tried this in the model definition:

...
bio: {
    type: Sequelize.STRING,
    get: async function() {
        let bio = this.getDataValue('bio');
        if (bio) {
            let bestFriend = await db.models.User.findById(this.getDataValue('BestFriendId'))
            if(bestFriend){
                bio += ` Best friend: ${bestFriend.name}.`;
            }
            console.log(bio)
            return bio;
        } else {
            return '';
        }
    }
},
...

Logging I can read the correct bio with something like:
Born yesterday. Love to read Best friend: Markus

But the object I retrieve has an empty object in the bio attribute.
I suppose that is because the async function is not supported, am I wrong?

How can I achieve this without using an async function?

lellefood
  • 1,885
  • 3
  • 18
  • 40

2 Answers2

17

According to the documentation getters and setters do not support any form of asynchrony. They are sync. So there is no way to use async functions (as we'd need a promise support).

Also here is a thread with a discussion on this subject. And it's confirmed that this feature is not going to be added in future.

You could extend the model instead and add the instance level method. The doc calls it a virtual getter. Please see this article.

You can also make it async and access the model data.

BioModel.prototype.getBio = async function() {
    let bio = this.getDataValue('bio');
    if (bio) {
        let bestFriend = await db.models.User.findById(this.getDataValue('BestFriendId'))
        if(bestFriend){
            bio += ` Best friend: ${bestFriend.name}.`;
        }
        return bio;
    } else {
        return '';
    }
}
Antonio Narkevich
  • 4,206
  • 18
  • 28
0

In Sequelize, you can define delayed virtual fields, that you write and read from strategical positions in code, instead of from the model schema. If you store your virtual values alongside with persisted values, then they are automatically managed by collective operations like model.get(), model.toJSON(), ...

Setup

myVirtualField: {
  type: new DataTypes.VIRTUAL(DataTypes.STRING),
  get() {
    return this.getDataValue("myVirtualField")
  },
  set(value) {
    this.setDataValue("myVirtualField", value)
  },
},

Usage

// before writing anything into myVirtualField, `item.getDataValues()` has no entry for it
if (item.myVirtualField === undefined) { // <- true

// set myVirtualField
item.myVirtualField = await getHelloWorldAsync() // this resolves to "Hello, World!"

// after writing anything into myVirtualField, `item.getDataValues()` has an entry for it
if (item.myVirtualField === "Hello, World!") { // <- true
aercolino
  • 2,193
  • 1
  • 22
  • 20