Skip to content

Commit 1751a84

Browse files
committed
✨ First commit
0 parents  commit 1751a84

19 files changed

+824
-0
lines changed

.gitignore

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# compiled output
2+
/dist
3+
/node_modules
4+
5+
# Logs
6+
logs
7+
*.log
8+
npm-debug.log*
9+
yarn-debug.log*
10+
yarn-error.log*
11+
lerna-debug.log*
12+
13+
# OS
14+
.DS_Store
15+
16+
# Tests
17+
/coverage
18+
/.nyc_output
19+
20+
# IDEs and editors
21+
/.idea
22+
.project
23+
.classpath
24+
.c9/
25+
*.launch
26+
.settings/
27+
*.sublime-workspace
28+
29+
# IDE - VSCode
30+
.vscode/*
31+
!.vscode/settings.json
32+
!.vscode/tasks.json
33+
!.vscode/launch.json
34+
!.vscode/extensions.json
35+
36+
# Project
37+
/.env
38+
39+
dump.rdb

README.md

+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
Redisk
2+
=====
3+
[![npm version](https://badge.fury.io/js/redisj.svg)](https://badge.fury.io/js/redisk)
4+
5+
Redisk is a TypeScript ORM library for Redis.
6+
7+
8+
## Features:
9+
10+
* Store entities.
11+
* Single relation support.
12+
* Unique keys support.
13+
* Retrieve entities by his primary keys or his unique keys.
14+
* Indexes support.
15+
* List entities with common filters, like limit, count and sort by.
16+
* Find entities with multiple conditions.
17+
* Search (Similar to LIKE in SQL)
18+
* And much more.
19+
20+
21+
## Getting started
22+
```bash
23+
npm install redisk --save
24+
```
25+
## Examples with a User model
26+
27+
### Model definition
28+
```ts
29+
@Entity('user', { canBeListed: true })
30+
export class User {
31+
32+
@Primary()
33+
@Property()
34+
public readonly id: string;
35+
36+
@Property({sortable: false, searchable: true})
37+
public readonly name: string;
38+
39+
@Unique()
40+
@Property()
41+
public readonly email: string;
42+
43+
@Index()
44+
@Property()
45+
public readonly color: string;
46+
47+
@Property({sortable: true, searchable: false})
48+
public readonly created: Date;
49+
50+
constructor(
51+
id: string,
52+
name: string,
53+
email: string,
54+
color: string,
55+
created: Date,
56+
) {
57+
this.id = id;
58+
this.name = name;
59+
this.email = email;
60+
this.color = color;
61+
this.created = created;
62+
}
63+
}
64+
```
65+
66+
### Init Redisk
67+
68+
```ts
69+
const redisk = new Redisk(new Metadata(), 'redis://127.0.0.1:6379/0');
70+
```
71+
72+
### Store one user
73+
74+
```ts
75+
await redisk.commit<User>(new User(id, name, email, color, created));
76+
```
77+
78+
### Get one user by his primary key
79+
80+
```ts
81+
await redisk.getOne<User>(User, id);
82+
```
83+
84+
### Get one user by his email unique key
85+
86+
```ts
87+
await redisk.getOne<User>(User, '[email protected]', 'email');
88+
```
89+
90+
### Count all users
91+
92+
```ts
93+
await redisk.count<User>(User);
94+
```
95+
96+
### List all users
97+
98+
```ts
99+
await redisk.list<User>(User); // Returns an array of entities
100+
101+
const limit = 10;
102+
const offset = 0;
103+
await redis.list<User>(User, limit, offset); // Returns 10 user entities
104+
105+
await redisk.list<User>(User, undefined, undefined, {
106+
field: 'created',
107+
strategy: 'DESC',
108+
}); // Returns an array of entities sorted by his creation date in descending order
109+
```
110+
111+
### Find all users by one index
112+
```ts
113+
const conditions = [
114+
{
115+
key: 'color',
116+
value: 'red',
117+
},
118+
];
119+
await redisk.find<User>(User, conditions, limit, offset); // Returns an array of entites that match the conditions
120+
```
121+
122+
### Search users by his name
123+
124+
```ts
125+
const condition = {
126+
key: 'color',
127+
value: 'red',
128+
};
129+
const maxNumberOfResults = 10;
130+
await redisk.search<User>(User, condition, maxNumberOfResults);
131+
```
132+
133+
### Delete one user
134+
135+
```ts
136+
await redisk.delete<User>(User, id);
137+
```

package-lock.json

+43
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"name": "redisk",
3+
"version": "1.0.0",
4+
"description": "TypeScript ORM for Redis.",
5+
"main": "index.js",
6+
"directories": {
7+
"test": "test"
8+
},
9+
"scripts": {
10+
"prebuild": "rm -rf dist",
11+
"build": "tsc -p tsconfig.json",
12+
"prepublish:npm": "npm run build",
13+
"publish:npm": "npm publish --access public",
14+
"prepublish:next": "npm run build",
15+
"publish:next": "npm publish --access public --tag next",
16+
"test": "echo \"Error: no test specified\" && exit 1"
17+
},
18+
"dependencies": {
19+
"redis": "^2.8.0",
20+
"bluebird": "^3.7.2",
21+
"reflect-metadata": "^0.1.13"
22+
},
23+
"repository": {
24+
"type": "git",
25+
"url": "git+https://github.com/ArkerLabs/redisk.git"
26+
},
27+
"keywords": [
28+
"typescript",
29+
"redis",
30+
"orm"
31+
],
32+
"author": "ArkerLabs",
33+
"license": "ISC",
34+
"bugs": {
35+
"url": "https://github.com/ArkerLabs/redisk/issues"
36+
},
37+
"homepage": "https://github.com/ArkerLabs/redisk#readme"
38+
}

src/decorators/entity.decorator.ts

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { MetadataStorage } from '../metadata/metadata.storage';
2+
3+
export function Entity(name: string, options?: {canBeListed: boolean}) {
4+
return (target: any) => {
5+
let canBeListed = false;
6+
if (options !== undefined && options.canBeListed === true) {
7+
canBeListed = true;
8+
}
9+
MetadataStorage.getGlobal().canBeListed[target.name] = canBeListed;
10+
MetadataStorage.getGlobal().names[target.name] = name;
11+
};
12+
}

src/decorators/index.decorator.ts

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { MetadataStorage } from '../metadata/metadata.storage';
2+
3+
// tslint:disable-next-line: ban-types
4+
export function Index(): Function {
5+
return (object: object, propertyName: string) => {
6+
if (MetadataStorage.getGlobal().indexes[object.constructor.name] === undefined) {
7+
MetadataStorage.getGlobal().indexes[object.constructor.name] = [];
8+
}
9+
MetadataStorage.getGlobal().indexes[object.constructor.name].push(propertyName);
10+
};
11+
}

src/decorators/primary.decorator.ts

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { MetadataStorage } from '../metadata/metadata.storage';
2+
3+
// tslint:disable-next-line: ban-types
4+
export function Primary(): Function {
5+
return (object: object, propertyName: string) => {
6+
MetadataStorage.getGlobal().primary[object.constructor.name] = propertyName;
7+
};
8+
}

src/decorators/property.decorator.ts

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { MetadataStorage } from '../metadata/metadata.storage';
2+
import 'reflect-metadata';
3+
4+
export function Property(options: {sortable: boolean, searchable: boolean} = {
5+
sortable: false,
6+
searchable: false,
7+
// tslint:disable-next-line: ban-types
8+
}): Function {
9+
return (object: object, propertyName: string) => {
10+
const type = Reflect.getMetadata('design:type', object, propertyName).name;
11+
12+
if (options.sortable && (type !== 'Date' && type !== 'Number')) {
13+
throw new Error('You can only make Dates and numbers sortables');
14+
}
15+
16+
if (MetadataStorage.getGlobal().properties[object.constructor.name] === undefined) {
17+
MetadataStorage.getGlobal().properties[object.constructor.name] = [];
18+
}
19+
MetadataStorage.getGlobal().properties[object.constructor.name].push({
20+
name: propertyName,
21+
sortable: options.sortable,
22+
searchable: options.searchable,
23+
type,
24+
});
25+
};
26+
}

src/decorators/unique.decorator.ts

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { MetadataStorage } from '../metadata/metadata.storage';
2+
3+
// tslint:disable-next-line: ban-types
4+
export function Unique(): Function {
5+
return (object: object, propertyName: string) => {
6+
if (MetadataStorage.getGlobal().uniques[object.constructor.name] === undefined) {
7+
MetadataStorage.getGlobal().uniques[object.constructor.name] = [];
8+
}
9+
MetadataStorage.getGlobal().uniques[object.constructor.name].push(propertyName);
10+
};
11+
}

src/interfaces/condition.ts

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export interface Condition {
2+
key: string;
3+
value: any;
4+
}

src/interfaces/orderby.ts

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export interface OrderBy {
2+
field: string;
3+
strategy: 'ASC' | 'DESC';
4+
}

src/metadata/entity.metadata.ts

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { PropertyMetadata } from './property.metadata';
2+
3+
export interface EntityMetadata {
4+
name: string;
5+
primary: string;
6+
indexes: string[];
7+
uniques: string[];
8+
properties: PropertyMetadata[];
9+
canBeListed: boolean;
10+
}

src/metadata/metadata.storage.ts

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { StateMetadata } from './state.metadata';
2+
3+
export class MetadataStorage {
4+
5+
static global: StateMetadata = {
6+
names: {},
7+
canBeListed: {},
8+
indexes: {},
9+
uniques: {},
10+
properties: {},
11+
primary: {},
12+
};
13+
14+
static getGlobal(): StateMetadata {
15+
return MetadataStorage.global;
16+
}
17+
}

0 commit comments

Comments
 (0)