Declarative Redis - persist structural data with Redis at ease.
npm install --save redis-schema
or
yarn add redis-schema
Define your data model by extending the BaseModel
class and implement the getSchema
method.
(Sample written in Typescript)
import {BaseModel, RedisSchemaType, Types} from 'redis-schema';
interface ITestShape {
shapeNumber: number;
shapeString: string;
nestedShape: {
nestedShapeListOf: Array<number>;
};
}
interface IProps {
listProp: Array<string>;
hashProp: {[key: string]: string};
setProp: Set<string>;
stringProp: string;
numberProp: number;
listOfShapeProp: Array<ITestShape>;
listOfListProp: Array<Array<number>>;
}
class TestModel extends BaseModel<IProps> {
constructor(key: string = 'HTRedisTestModel') {
super(key);
}
getSchema(): RedisSchemaType {
return {
listProp: Types.list,
hashProp: Types.hash,
setProp: Types.set,
stringProp: Types.string,
numberProp: Types.number,
listOfShapeProp: Types.listOf<ITestShape>(
Types.shape({
shapeNumber: Types.number,
shapeString: Types.string,
nestedShape: Types.shape({
nestedShapeListOf: Types.listOf<number>(Types.number),
}),
}),
),
};
}
// This is important and you have to define the default behavior of your
// model so it can be consumed by `Redis` class.
static getInstance(): TestModel {
const instance = new TestModel();
return instance.setTtl({
type: 'expire',
value: 2,
});
}
}
To save and load model data, use the Redis
class:
import {Redis} from 'redis-schema';
const modelData: IProps = {
listProp: ['a', 'b', 'c'],
hashProp: {
a: '1',
b: '2',
},
setProp: new Set(['1', '2', '3']),
stringProp: 'test string',
numberProp: 123,
listOfShapeProp: [
{
shapeNumber: 0,
shapeString: '0',
nestedShape: {
nestedShapeListOf: [0, 1, 2, 3],
}
},
{
shapeNumber: 2,
shapeString: '2',
nestedShape: {
nestedShapeListOf: [2, 3, 4, 5],
},
},
],
listOfListProp: [
[1, 2, 3],
[4, 5, 6],
],
};
async function saveLoad(): Promise<void> {
const model = new Redis(TestModel);
console.log(await model.genSaveModel(modelData));
// => 'OK'
console.log(await model.genLoadModel());
// => modelData will be printed.
}
If you know React's prop-types' syntax, the redis schema's syntax should look very familiar to you. Just replace the prop-types terms with Redis terms. Built-in types include:
-
string
-
number
This is still a string in Redis but conversion is done before saving or after loading
-
list
-
set
-
hash
-
listOf
listOf
accepts a singleIRedisType
implementation. All built-in types areIRedisType
implementations so you can even store a list of lists. -
shape
Similar to
listOf
but the argument should be an object ofIRedisType
implementations. -
instanceOf
Similar to
listOf
but the argument should be an object ofIRedisComposeType
implementation. All subclasses ofBaseModel
areIRedisComposeType
implementations. -
hashOf
Similar to
listOf
but the model needs to be an object whose key is string and value is the given model type that implements theIRedisType
interface.
All built-in types comes with data validation logic. 1 ~ 5 are simple instanceof
checks. 6 and 7 uses their type arguments' validation and only passes when all items are valid. The implication is that all fields in a schema are treated as required fields. Null or undefined values are not acceptable.
You may pass in options to configure the redis
client. redis-schema
uses the redis
package so all options accepted by the redis
package are accepted here, too. Click here for all options.
Essentially, all Redis Schema does is key management. It abstracts away the process to come up with Redis keys, ensuring consistent keys across your Redis server. Thus Redis Schema is not an ORM. If you need to change the structure of persisted data, you'll still need to do it manually. However with the help of a key registry (comiong soon), you are able to perform automated migration by collecting all old data in your migration script. Still, this library will be perfect for you if you only want the ability to persist structural data in Redis.
-
Implement model registry to keep track of top-level model keys.
-
More useful JSON manipulations, to make this more useful than simply storing data structures as JSON strings. For example:
a) Get/set values on a JSON path. With this, things can be done without loading the complete data structure.
b) Get meta data on a JSON path, like
size
orisSet
.