Security News
The Unpaid Backbone of Open Source: Solo Maintainers Face Increasing Security Demands
Solo open source maintainers face burnout and security challenges, with 60% unpaid and 60% considering quitting.
ts-redis-orm
Advanced tools
ts-redis-orm targets to provide relational DB features to Redis Lover.
It is designed to preserve the performance of Redis, but extending all the useful features that you found useful in relational DB such as (multiple index, primary keys, unique keys, auto increment, aggregate, etc.)
Due to design limitation, the package doesn't work with Redis Cluster.
This package mainly build on top of ioredis and tested with Redis 3, 4 and 5.
const [entity, performanceResult] = await Entity.create({}).save();
console.log(performanceResult);
// This will print:
{
executionTime: number;
commandStats: object;
diffCommandStats: object;
usedCpuSys: number;
diffUsedCpuSys: number;
usedCpuUser: number;
diffUsedCpuUser: number;
usedMemory: number;
diffUsedMemory: number;
}
import {BaseEntity, Column, Entity} from "ts-redis-orm";
@Entity({connection: "default", table: "Entity"})
class MyEntity extends BaseEntity {
@Column({autoIncrement: true})
public id: number = 0;
}
// usage
const entity1 = new MyEntity();
await entity1.save();
const [entity2] = await MyEntity.create({string: "value", number: 0}).save();
import {
BaseEntity,
Column,
Entity,
RedisOrmDecoratorError,
RedisOrmOperationError,
RedisOrmQueryError,
RedisOrmSchemaError,
redisOrm,
} from "ts-redis-orm";
@Entity({connection: "default", table: "Entity", tablePrefix: "Prefix"})
class MyEntity extends BaseEntity {
@Column({autoIncrement: true})
public id: number = 0;
@Column({unique: true})
public string: string = "";
@Column({unique: true, index: true})
public number: number = 0;
@Column({index: true})
public date: Date = new Date();
@Column({index: true})
public boolean: boolean = false;
@Column()
public array: number[] = [];
@Column()
public object1: any;
@Column()
public object2: null | string = null;
@Column()
public object3: {name?: string, value?: number} = {};
}
const main = async () => {
// init the connection to redis, you don't need to call this. it will be done internally
// for some scenarios, you can put this at the bootstrap of your project ot make sure everything is all right
await MyEntity.connect();
// get the redis instance
const redis = await MyEntity.getRedis();
// we have an internal schema protection
// if we encounter a schema error, you can try to resync it once
try {
const [entity, performanceResult1] = await MyEntity.create({}).save();
} catch (err) {
if (err instanceof RedisOrmSchemaError) {
const [hasResync, performanceResult2] = await MyEntity.resyncDb();
}
}
// truncate the DB, need to provide class name for protection
const [totalDeleted, performanceResult3] = await MyEntity.truncate("MyEntity");
// create entity
const entity1 = new MyEntity();
const entity2 = entity1.clone();
const entity3 = MyEntity.create({id: 1});
const createdAt = entity1.createdAt; // create time of entity (the moment u create the object, not the time u save it to Redis).
// set values
entity1.id = 1;
entity1.setValues({id: 1});
entity1.increment("number", 10);
entity1.createdAt = new Date(); // auto added into entity
// get values
const id1 = entity1.id;
const values1 = entity1.getValues();
const entityId = entity1.getEntityId(); // internal identifier for the entity
// save
const [entity1a, performanceResult4] = await entity1.save();
const [entity1b, performanceResult5] = await entity1.delete(); // soft delete
// simple query
const [total] = await MyEntity.count();
const [all] = await MyEntity.all();
const [entity4] = await MyEntity.find(1);
const [entities5] = await MyEntity.findMany([1, 2, 3]);
// complex query
const [entity6] = await MyEntity.query().findUnique("string", "string");
const [entities7] = await MyEntity.query().findUniqueMany("string", ["string1", "string2"]);
const [entities8] = await MyEntity.query().where("number", "=", 5).runOnce();
const [entities9] = await MyEntity
.query()
// if column is indexed
.where("number", "=", 5)
.where("number", ">", 5)
.where("number", ">=", 5)
.where("number", "<", 5)
.where("number", "<=", 5)
// if column is not indexed
.where("string", "=", "value")
.where("string", "!=", "value")
.where("string", "like", "value")
.sortBy("number", "desc")
.offset(10)
.limit(10)
.run();
// aggregate query
const [count] = await MyEntity.query().count();
const [sum] = await MyEntity.query().sum("number");
const [min] = await MyEntity.query().min("number");
const [max] = await MyEntity.query().max("number");
const [avg] = await MyEntity.query().avg("number");
const [countGroup] = await MyEntity.query().count("string");
// rank (get the ordering of an entity from index, useful for doing ranking)
const id = 1;
const [rank] = await MyEntity.query().rank("number", id);
const [reversedRank] = await MyEntity.query().rank("number", id, true);
// export / import
await MyEntity.export("path");
await MyEntity.import("path");
await MyEntity.import("path", true); // skip schemas check
// events
const events = MyEntity.getEvents();
events.on("create", (entity) => { /* */ });
events.on("update", (entity) => { /* */ });
events.on("delete", (entity) => { /* */ });
// dynamic tables
const table = "another-table";
await MyEntity.connect(table);
await MyEntity.truncate("MyEntity", table);
await MyEntity.export("./file.txt", table);
await MyEntity.import("./file.txt", false, table);
const entity10 = new MyEntity();
entity10.setTable(table);
const currentTable = entity10.getTable();
entity10.id = 10;
await entity10.save();
const [entity10a] = await MyEntity.query().setTable(table).find(10);
// others
const removeSchemasList = redisOrm.getRemoteSchemasList("connectionKey");
const allEntityTypes = redisOrm.getEntityTypes();
// errors
try {
await MyEntity.create({}).save();
} catch (err) {
if (err instanceof RedisOrmSchemaError) {
// error related to entity schema, throw at first connection to Redis
} else if (err instanceof RedisOrmDecoratorError) {
// error related to decorator, only throw at compile time
} else if (err instanceof RedisOrmOperationError) {
// error related to entity operation
} else if (err instanceof RedisOrmQueryError) {
// error related to entity query
} else {
// ioredis error or other unkonw errors
}
}
}
{
// If you didn't set any connection in Entity, it will use the default connection.
// The connection config are the same as in ioredis, pleases visit https://github.com/luin/ioredis/blob/master/API.md for more details.
"default": {
"host": "127.0.0.1",
"port": 6379,
"connectTimeout": 1000,
"db": 0,
"showFriendlyErrorStack": false,
// report more detailed report on redis for every operations
"trackRedisInfo": false,
// this is an extra feature supported by ts-redis-orm, if redis suddenly go offline, the entity can prompt for an connection error.
"maxConnectRetry": 5
}
}
FAQs
A full functional Redis Orm library written in Typescript.
The npm package ts-redis-orm receives a total of 110 weekly downloads. As such, ts-redis-orm popularity was classified as not popular.
We found that ts-redis-orm demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Solo open source maintainers face burnout and security challenges, with 60% unpaid and 60% considering quitting.
Security News
License exceptions modify the terms of open source licenses, impacting how software can be used, modified, and distributed. Developers should be aware of the legal implications of these exceptions.
Security News
A developer is accusing Tencent of violating the GPL by modifying a Python utility and changing its license to BSD, highlighting the importance of copyleft compliance.