redis-om-node
redis-om-node copied to clipboard
Transactions & relations
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(...)
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()
.
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.