Skip to main content

@deco.Virtual

The @deco.Virtual decorator enables setting of fields as if they corresponded to columns in the model's table so they can be passed to new, create, and update. It requires an OpenAPI type argument that defines both the serializer OpenAPI shape and the request body OpenAPI shape (in Psychic).

For example, in the first example below, one could call await bodyMeasurement.update({ lbs: 180.1 }), and 180.1 will be passed into the lbs setter, which then translates lbs to grams to be stored in the grams column in the metrics table.

And in the second example below, one could call await user.update({ password }), and, in the BeforeSave lifecycle hook, the password would be hashed into hashedPassword. (This is just an example to illustrate using the Virtual decorator on a simple field; it might be better design to use the getter/setter pattern for password, with the getter simply returning undefined.)

class BodyMeasurement extends ApplicationModel {
@deco.Virtual('number')
public get lbs() {
const self: BodyMeasurement = this
return gramsToLbs(self.getAttribute('grams') ?? 0)
}

public set lbs(lbs: number) {
const self: BodyMeasurement = this
self.setAttribute('grams', lbsToGrams(lbs))
}

@deco.Virtual('number')
public get kilograms() {
const self: BodyMeasurement = this
return gramsToKilograms(self.getAttribute('grams') ?? 0)
}

public set kilograms(kg: number) {
const self: BodyMeasurement = this
self.setAttribute('grams', kilogramsToGrams(kg))
}
}
import argon2 from 'argon2'

class User extends ApplicationModel {
@deco.Virtual('string')
public password: string | undefined

@deco.BeforeSave()
public async hashPassword(this: User) {
if (this.password) {
this.setAttribute(
'passwordDigest',
await argon2.hash(this.password)
)
this.password = undefined
}
}
}

The type argument accepts any OpenAPI shorthand primitive type (like 'string', 'number', 'integer', 'boolean') or a more complex OpenAPI schema body shorthand for representing objects and arrays.