Skip to content

Model.$set will try to set Class getter fields when parsing JSON #432

@skray

Description

@skray

I'm not entirely sure this is a problem that Objection should be handling for me, so please feel free to just let me know if that is the case.

The problem: I have added a getter function to one of my models, and added the getter as a virtual attribute to the model so that it renders out in the JSON, like this:

class MyModel extends Model {

  static get virtualAttributes () {
    return ['virtualValue']
  }
  
  get virtualValue () {
    return this.val1 + this.val2
  }
  
}

The JSON for MyModel will look like this:

{
  "val1": 1,
  "val2": 2,
  "virtualValue": 3
}

The issue is that when I try to use MyModel.fromJson() on this JSON, there is no check in Model.$set() to see if the virtual field is actually writeable (https://github.com/Vincit/objection.js/blob/master/lib/model/modelSet.js#L47..L49), so I get the standard Javascript error: TypeError: Cannot set property virtualValue of #<MyModel> which has only a getter.

I've been able to successfully override MyModel.$parseJson to remove the field, and abstracted the logic to a generic function that I can use to remove any field that has a getter but no setter:

$parseJson(json, options) {
  // delete getters that don't have setters, so Model.fromJson won't try to set the value
  const keys = Object.keys(json)

  for (let i = 0, l = keys.length; i < l; ++i) {
    const key = keys[i]
    const prototype = Object.getPrototypeOf(this)
    const descriptor = Object.getOwnPropertyDescriptor(prototype, key)

    if (descriptor && descriptor.get && !descriptor.set) {
      delete json[key]
    }
  }

  return json
}

Disclaimer: this works for my case, but it might make sense to check if the descriptor is writeable instead, I'm not entirely sure of the most appropriate way to handle all flavors of getters and setters.

So, my question is:

Is there already an option that I missed that will keep Model.fromJson from trying to set unwriteable fields, or possibly to keep it from trying to write virtualAttributes? If not, is this something that would make sense for Objection to handle?

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions