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

Transactions & relations #28

Open
gothy opened this issue Jan 12, 2022 · 2 comments
Open

Transactions & relations #28

gothy opened this issue Jan 12, 2022 · 2 comments
Labels
enhancement New feature or request

Comments

@gothy
Copy link

gothy commented Jan 12, 2022

First of all, let me thank you for this cool library :)
Now, I'm really considering using Redis Enterprise as a primary DB in the future projects!

So, my question arises from this section in the readme https://github.com/redis/redis-om-node#-embedding-your-own-logic-into-entities
We can fetch "relations" in our entities, but I'm more interested in updating those relations as a part of a transaction. I can see that currently, saving an entity requires you to call repository.save(entity), but what about related entries? What if I need to update an entity, some sub-entity and commit or discard all of the changes?

It would be cool to have something like

getCurrentClient().startTransaction(() => {
  repository1.save(entity);
  repository2.save(subentity);
}).then(...).catch(...)
@HeyItsBATMAN
Copy link

HeyItsBATMAN commented Jan 13, 2022

This could be achieved by exposing/using .multi() from the @node-redis Client used in RedisShim.
Then, instead of saving the data using the .save() method from a Repository one could prepare the data like it is prepared in the .save(), skip the saving, and instead appending it to the exposed .multi().

I threw together a proof of concept

Preparing the data for transaction in the repository could look like:

prepareForTransaction(entity: Entity) {
  const key = this.makeKey(entity.entityId);
  const {dataStructure} = this.schema;

  const data = dataStructure === 'JSON'
    ? this.jsonConverter.toJsonData(entity.entityData)
    : this.hashConverter.toHashData(entity.entityData);

  return {key, data, dataStructure};
}

This data could then be used in some kind of Transaction class like:

export default class Transaction {
  private multi;

  constructor(client: Client) {
    this.multi = client.multi();
  }

  add(repository: Repository<Entity>, entity: Entity) {
    const { key, data, dataStructure } = repository.prepareForTransaction(entity);
    dataStructure === 'JSON' ? this.multi.jsonset(key, data) : this.multi.hSet(key, data);
    return this;
  }

  exec() {
    return this.multi.exec();
  }
}

And finally, a transaction could be created and executed with as many steps as needed:

new Transaction(client)
  .add(fooRepo, fooEntity)
  .add(barRepo, barEntity)
  .exec();

It's probably better to execute this inside of an isolated Client though, like RedisShim is doing for .hsetall().

@guyroyse
Copy link
Contributor

Regarding transactions, I think this is an interesting idea. I'll consider it in the future.

Regarding nesting objects and relationships, this has been asked a couple of different times by a couple of different people with different flavors. It's something that's on the roadmap but not in the backlog. It'll happen. Not sure exactly what it will look like yet.

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

3 participants