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

Entity property config relationship for hiding entity but outputting id #809

Closed
Langstra opened this issue Sep 4, 2020 · 5 comments
Closed
Labels
enhancement New feature or request

Comments

@Langstra
Copy link
Collaborator

Langstra commented Sep 4, 2020

Is your feature request related to a problem? Please describe.
I have a schema where entity A has relationships to B many C's many D's, C has many E's. Now when I return B, it calls toJson function. Since B also has the reverse relation to A, relation A is also outputted, and A then loads B, C and D. This gives me a call stack size exceeded (so maybe I should also file a bug report for this?). However, I'd like to use {hidden: true} on entity B for its relation to A, this hides entity A on B. Now I would like to have property a_id on entitiy B when outputting. This way someone using my API does know that entity B has a relation with entity A.

Describe the solution you'd like
A configuration property like showId: boolean, that when set to true outputs the id of the relationship.

Example:
A book has an author and an author has many books. When outputting with showId true, a book has a property called authorId and when outputting an author it has a property bookIds.

A different approach could be to have a configuration property showId: string which lets the user specify how the property should be named and when being unset/undefined that the id or id array is not outputted.

Describe alternatives you've considered
Currently I am using the hidden property and overriding the toJson method to insert the authorId property myself.

@Langstra Langstra added the enhancement New feature or request label Sep 4, 2020
@B4nan
Copy link
Member

B4nan commented Sep 4, 2020

In general, abstracting the serialization is very complex thing, there is no silver bullet to this other than implementing custom toJSON method.

I don't really understand the problem yet (and I don't think adding another boolean flag would solve it), the PK should always be there on the owning sides, as well as on initialized collections. Can you provide some code that demonstrates the issue?

A book has an author and an author has many books. When outputting with showId true, a book has a property called authorId and when outputting an author it has a property bookIds.

This is already working, Book.author is the owning side (m:1), it will always be part of the output, either the full entity or just the PK.

@Langstra
Copy link
Collaborator Author

Langstra commented Sep 4, 2020

I will try to create an example repository.

I understand that the PK is always there, but there is no option to choose to always output the PK instead of the full entity. I'd like to output always the PK instead of the full entity, even if it is available in the entity map.

@B4nan
Copy link
Member

B4nan commented Sep 4, 2020

There actually is an option for that, not on the entity definition level, it works automatically based on the populate params. Entity can be marked as populated via wrap(e).populated() (and unmarked with a false param).

const a = await em.findOne(Author, 1, ['favouriteBook']);
console.log(a.toJSON()); // favouriteBook was populated explicitly, so will be full entity
wrap(a.favouriteBook).populated(false);
console.log(a.toJSON()); // favouriteBook was unpopulated, so will be just the PK

@Langstra
Copy link
Collaborator Author

Langstra commented Sep 5, 2020

I guess you are right that this type of behavior should be done at controller (output) level. However, maybe you could add support for adding the relation ID as a property on the entity. That way you can either choose to use 'author' or authorId'.

@B4nan
Copy link
Member

B4nan commented Sep 5, 2020

You can already do that via virtual properties, if it's just about controlling the JSON output (but I would still prefer using custom toJSON() method). Something like this should work:

class Book {

  @ManyToOne({ hidden: true })
  author: Author;

  @Property({ name: 'author_id', persist: false })
  get authorId() {
    return this.author.id;
  }

}

But yeah, why not, we can make this easier. Will add serializer and serializedName to PropertyOptions, so you can do this instead:

class Book {

  @ManyToOne({ serializedName: 'author_id', serializer: a => a.id })
  author: Author;

}

@B4nan B4nan closed this as completed in 3d94b93 Sep 6, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants