Redis ORM for TypeScript
Features:
- Modern ORM based on decorators & datamapper pattern
- Type binding for numbers, booleans, strings, dates. Objects/arrays are being converted to json strings
- Native support for ES2015 Maps and Sets (Stored as separated hashes/sets in Redis)
- Single field relation support
- Multiple relations support for Maps and Sets
- Relations cascade inserting/updating (But not deleting)
- Entity subscriber support & built-in pubsub subscriber
- Operation optimized - writes to redis only changed values
- Lazy maps/sets support
- Optimistic locking (WIP)
Requirments
- TypeScript 2.3 or greater
- Node 7.*
- Symbol.asyncIterator polyfill to iterate over lazy maps/sets
Setup
Enable emitDecoratorMetadata
and experimentalDecorators
in your tsconfig.json
Install reflect-metadata
library and import it somewhere in your project:
npm install reflect-metadata --save
// in index.ts
import "reflect-metadata";
If you're going to use lazy maps/sets then you need Symbol.asyncIterator
polyfill. This can be easily achived by writing this somewhere in app:
Symbol as any.asyncIterator = Symbol as any.asyncIterator || Symbol.for"Symbol.asyncIterator";
Examples
Basic example
; createConnection.then.catchconsole.error;
Relations
ORM supports both single relations (linked to a single property) and multiple relations (linked to Set/Map)
; rel1.id = 1; ; rel2.id = 2; ; owner.id = "test"; owner.rel = rel1; owner.relationSet.addrel1; owner.relationMap.set10, rel1; owner.relationMap.set12, rel2; // Cascading insert will save all relations too in object await manager.saveowner; // Get and eager load all relations, including all inner relations (if presented) ; loaded.rel.relProp = "test"; // If cascadeUpdate was set then will trigger update operation for Relation entity await manager.saveloaded; // Don't load relations for properties rel and relationMap ;
NOTE: ORM DOESN'T support cascade delete operation now, you must delete your relations manually
// To clean owner object with all linked relations: ; for of owner.setRel await manager.deleteowner;
Lazy collections
By default all sets/maps are being loaded eagerly. If your map/set in redis is very big, it can take some time to load, especially for relation sets/maps. You can use lazy sets/maps in this case:
; ; ent.id = 1; // Won't be saved until calling manager.save() for new entities await ent.set.add1; await ent.map.set1, true; await manager.saveent; // Immediately saved to set in redis now await ent.set.add2; // Use asyncronyous iterator available in TS 2.3+ for await of ent.set.values console.logawait ent.set.size; // 2 ; for await of anotherEnt.map.keysAndValues ; rel.id = 1; ; anotherEnt.id = 1; anotherEnt.map.set1, rel; await manager.saveanotherEnt; ; await savedEnt.map.get1; // Rel { id: 1 }
Asyncronyous iterators are using SCAN
redis command so they suitable for iterating over big collections.
LazyMap/LazySet after saving entity/loading entity are being converted to specialized RedisLazyMap/RedisLazySet.
Also it's possible to use RedisLazyMap/RedisLazySet directly:
; await map.set1, true; await map.set2, false; for await of map.keysAndValues