Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ability to pass custom options to JSON serialization that will be also be passed to children/relations #1374

Closed
seanjrankin opened this issue Jun 13, 2019 · 4 comments

Comments

@seanjrankin
Copy link

seanjrankin commented Jun 13, 2019

Often I find myself needing to alter the JSON results of serialization.

For example:
Perhaps I have a model 'ModelA' with attributes 'name' and 'secret'

I would like to be able to alter the results of toJSON by providing some options:

myModel.toJSON({ isGuest: true })
would yield

{
  "name": "Bob"
} 

But if isGuest was not present or false:

{
  "name": "Bob",
  "secret": "123"
} 

Looking through the API and code, I can't find a proper way to do this. I'm aware of $omitFromJson and objection-visibility, but those don't allow you to provide custom options. I also need this option to propagate down to all children/relations.

Am I missing something?

A relatively simple solution I came up with is like so (I could make a PR):
in objection.js/lib/model/modelToJson.js

function toJson(model, optIn) {
  const modelClass = model.constructor;

  const opt = {
    virtuals: getVirtuals(optIn),
    shallow: isShallow(optIn),
    omit: getOmit(optIn, modelClass),
    pick: null,
    omitFromJson: model.$omitFromJson(optIn.custom) || null,
    cloneObjects: modelClass.cloneObjectAttributes,
    custom: optIn.custom
  };

  let json = toExternalJsonImpl(model, opt);
  json = model.$formatJson(json);

  return json;
}

I simply allow a 'custom' option to be passed into toJSON, and passed along to $omitFromJson

I can then do something like:

export class ModelA extends BaseModel {
    $omitFromJson(options) {
        if (options && options.isGuest) {
            return ['secret'];
        } else {
            return null;
        }
    };
}

Alternatively, this custom option could be passed to $formatJson instead (as a second, optional parameter).

Let me know if this makes sense. I could make a PR that could flexibly handle most inputs to 'custom'. With the exception of promises, which I think should be left out of the serialization flow.

@koskimas
Copy link
Collaborator

koskimas commented Jun 13, 2019

You can override the toJSON method to do whatever you want.

Whoops, I missed the "passing to children" part.

@koskimas koskimas reopened this Jun 13, 2019
@seanjrankin
Copy link
Author

@koskimas

You can override the toJSON method to do whatever you want.

Yes I see that, but I any custom options I provide to super.toJSON will not pass those options to its children/relations. Which is what I need.

@koskimas
Copy link
Collaborator

It would be cool to have some way to pass options to toJSON that would get passed to the whole tree of relations, but your suggestion wouldn't work for couple of reasons.

  1. $omitFromJson is private. You shouldn't be using it. Everything that's not mentioned in the documentation is considered private and can change at any given time. The function may be removed or renamed in any patch version.

  2. $omitFromJson is a getter/setter. Passing values to $omitFromJson sets the omitted values.

  3. Your suggestion would only solve your specific problem, nothing else. It would only allow omitting values based on some options. Not very useful in general. Adding any feature needs to be tested, documented and maintained. Any added feature needs to be generally useful.

We could add a second argument for $formatJson(json, options). Would that work for you?

@seanjrankin
Copy link
Author

Yes I think $formatJson(json, options) would work nicely

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants