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

Read-only EntityManager forking #2380

Open
parisholley opened this issue Nov 8, 2021 · 6 comments
Open

Read-only EntityManager forking #2380

parisholley opened this issue Nov 8, 2021 · 6 comments
Labels
enhancement New feature or request

Comments

@parisholley
Copy link
Contributor

parisholley commented Nov 8, 2021

In coming up with a solution to flush less (see #2379), i realized one aspect that may help is the ability to access a read-only version of the entity manager that would effectively never flush or write to the database (and perhaps see some performance wins by reducing the about of operations ran during various API calls) and only support select queries (and perhaps throw an error if the user attempts to invoke persist or some other modifying function, though wouldn't protect from raw queries).

example, if a GraphQL request comes in for mutating, it will auto-flush, but if it is a standard query, it will return a version which prevents modifications and disable auto flushing:

  const override = () => {
    throw new Error('Cannot perform write operations in a read-only manager.');
  };

  em.persist = override;
  em.transactional = override;
  em.flush = override;
  em.remove = override;
  em.nativeDelete = override;
  em.nativeInsert = override;
  em.nativeUpdate = override;

  return em;
@parisholley parisholley added the enhancement New feature or request label Nov 8, 2021
@B4nan
Copy link
Member

B4nan commented Nov 9, 2021

This could work only if you handle contexts yourself, so as a parameter of em.fork() (which might be common for GQL users). I am quite sure many people don't do it on their own (especially those using nestjs or some other tool with DIC), as using the RequestContext helper and DI is much more ergonomic.

Not sure if we should throw in such case, maybe a warning + noop might be a better solution? Also not sure about disallowing native* methods, those are just helpers, a readonly EM to me sounds like it should handle only flushing this way (all of persist/remove/transactional will use flush at some point, so it should be enough).

@parisholley
Copy link
Contributor Author

This could work only if you handle contexts yourself

not necessarily, java world introduces this concept via decorators as well (eg: spring's @transactional(readOnly=true). I assume that the RequestContext could have a similar option and simply fork again if the flag is true.

Also not sure about disallowing native* methods

from what i understood, since those methods bypass the identity map, it would execute immediately vs waiting for flush?

sounds like it should handle only flushing this way (all of persist/remove/transactional will use flush at some point, so it should be enough)

the problem with this, is you will only know something is wrong when a flush is attempted. if a developer writes code assuming it will eventually get flushed, it could go to production without any errors if that execution path never flushes (such as depending on web requests to flush at the end).

@B4nan
Copy link
Member

B4nan commented Nov 9, 2021

from what i understood, since those methods bypass the identity map, it would execute immediately vs waiting for flush?

Nope, those are basically shortcuts for QB, would you expect to forbid also query builder?

@parisholley
Copy link
Contributor Author

yep, qb would be limited to select, count, etc

@parisholley
Copy link
Contributor Author

@B4nan i believe this issue is the last thing remaining to get rid of my "EntityManagerWrapper"

Does simply adding a flag to fork() and throwing an exception if flush is ever called internally seem like a good approach?

@B4nan
Copy link
Member

B4nan commented Nov 15, 2022

Yeah, that should cover most of it. I am still not sure about the restrictions around QB/native* methods, so let's keep that for some other time I guess. For flushing it sounds fine - at the same time this flag should set the flushMode to commit, so reads won't produce flushes.

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