Sequelize support getters and setters in a number of interesting ways. I'll be using the classic example of a person model with first name, last name and full name fields. The trouble with this model is that when the first name or the last name columns are updated, the full name should follow suit.
If I need to change the first name on this person instance with the way it's set up right now, I'd have to update both first name and full name manually.
One option is to add a setter to the first name field definition. I'll add a property called "set," and its value will be a function that takes one argument. In this case, I'll call it first.
The first thing I need to do in this setter is ensure the value of first name is set when the setter is called. To do that, I need to use the set data value function that's available on this. I'll parse two arguments, the name of the field I want to set, and the value I want to set it to. It's important that I use set data value here instead of setting the value with a normal assignment to avoid causing issues with the model's change tracking.
To set the full name, I'll first need to get the last name on the model using this dot get data value parsing in the name of the field I want to get the value for. Then, I can use both the first and last variables to get the full name field.
Now, when I change the first name on my person instance, the full name should change, as well. Unfortunately, to get the same effect from last name, I'd have to add nearly the same set function to it. Instead, I'm going to comment out the set method on first name and add a get method to full name.
The get method, we'll use this dot get data value to fetch both first name and last name, and then, return them concatenated together with a space. When I run the script, full name still reflects changes made to first name, and will respect changes made to last name, as well.
What about setting first name and last name from a set method on full name. I'll just write a very naive set method to do that. We'll set the value of full name first, and then, split the value in a space and set first name to value at index zero, and last name to the value at index one. Now, we can set both first name and last name at once using person.set and parsing in full name and my value.
Looking at the full name field a bit more, I'm realizing that I don't really need to persist the value to the database at all, since it can be derived from the first name and last name fields.
To tell Sequelize not to persist it, I can set the field's data type from string to virtual. It will still behave like a normal field in almost every way except that it won't be saved in the database, and the table won't have a full name column either.
Virtual fields can even be validated. Since my full name setter is so naive, I'll add an is validator to validate full name against the regular expression that looks for two words separated by a space. It's worth noting that for validation to work correctly on a virtual column, you must set its value using set data value in the set function, or the validator won't have a value to validate.
If I remove the space from the value I'm setting to full name, I'll see a validation error when the model is saved. When the space is there, it validates and saves without error.
If you don't need validations on a virtual setter or a getter, you can alternatively add them to the model in the options argument parse the defined. Getters can be added to the getters method object, and setters can be added to the setters method object. The key is the name of the field and the value is the getter or the setter function itself.
I'll just copy the getter and setter functions from the full name field above and comment out that full name field and its validation. Running it once more shows that getting and setting the full name still work as expected when using getters and setters from the model.