Skip to content

Commit 028287d

Browse files
authored
Merge pull request #14 from crashmax-dev/nest-module
feat(package): add `@stenodb/nest`
2 parents 125cc93 + d2b42ea commit 028287d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+8116
-1489
lines changed

.gitignore

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,19 @@
44
.env
55
.DS_Store
66
**/database
7+
**/db
78
**/logs
89
**/temp
10+
11+
# Tests
12+
**/coverage
13+
**/.nyc_output
14+
15+
# Logs
16+
logs
17+
*.log
18+
npm-debug.log*
19+
pnpm-debug.log*
20+
yarn-debug.log*
21+
yarn-error.log*
22+
lerna-debug.log*

.gitmodules

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[submodule "packages/writer"]
2+
path = packages/writer
3+
url = https://github.com/yoloforks/steno
4+
branch = main

README.md

Lines changed: 84 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# stenodb [![](https://img.shields.io/npm/v/stenodb)](https://www.npmjs.org/package/stenodb)
22

3-
> ✍ Easy to use local JSON database. Ready to use in browser (localStorage, sessionStorage) and Node.js.
3+
> ✍ Easy to use local JSON database.
44
55
## Install
66

@@ -16,16 +16,15 @@ yarn add stenodb
1616
pnpm add stenodb
1717
```
1818

19-
| Package | Version | Platform |
19+
| Package | Version | Description |
2020
| ------- | ------ | ----------- |
2121
| [@stenodb/node](./packages/node) | [![](https://img.shields.io/npm/v/@stenodb/node)](https://npm.im/@stenodb/node) | Node.js |
22-
| [@stenodb/browser](./packages/browser) | [![](https://img.shields.io/npm/v/@stenodb/browser)](https://npm.im/@stenodb/browser) | Browser |
22+
| [@stenodb/browser](./packages/browser) | [![](https://img.shields.io/npm/v/@stenodb/browser)](https://npm.im/@stenodb/browser) | Browser (localStorage, sessionStorage) |
23+
| [@stenodb/nest](./packages/nest) | [![](https://img.shields.io/npm/v/@stenodb/nest)](https://npm.im/@stenodb/nest) | Nest.js |
24+
| [@stenodb/logger](./packages/logger) | [![](https://img.shields.io/npm/v/@stenodb/logger)](https://npm.im/@stenodb/logger) | Logger |
2325

2426
## Usage
2527

26-
> **Warning**\
27-
> stenodb is a pure ESM package. If you're having trouble using it in your project, please [read this](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c).
28-
2928
### Database entities
3029
```typescript
3130
// entities.ts
@@ -77,7 +76,7 @@ import { Users, User, Post } from './entities.js'
7776
const path = resolve(dirname(fileURLToPath(import.meta.url)), '..', 'database')
7877
const initialData = new Users(new User('John Doe'))
7978
const adapter = new AsyncAdapter('users', Users, initialData)
80-
const provider = new NodeProvider(path)
79+
const provider = new NodeProvider({ path })
8180
const database = provider.createAsync(adapter)
8281

8382
await database.read()
@@ -86,6 +85,7 @@ await database.write()
8685
```
8786

8887
### `@stenodb/browser`
88+
8989
```typescript
9090
import 'reflect-metadata'
9191
import { LocalStorage, BrowserProvider } from '@stenodb/browser'
@@ -101,6 +101,83 @@ storage.data?.users[0]?.addPost(new Post('Lorem ipsum'))
101101
storage.write()
102102
```
103103

104+
### `@stenodb/nest`
105+
106+
```typescript
107+
// users.dto.ts
108+
import { Exclude, Type } from 'class-transformer'
109+
import { Length, Max, Min } from 'class-validator'
110+
111+
export class Users {
112+
@Type(() => CreateUserDto)
113+
users: CreateUserDto[] = []
114+
115+
constructor(...users: CreateUserDto[]) {
116+
this.users = users
117+
}
118+
}
119+
120+
export class CreateUserDto {
121+
@Exclude({ toPlainOnly: true })
122+
id: number
123+
124+
@Length(1, 20)
125+
name: string
126+
127+
@Min(12)
128+
@Max(100)
129+
age: number
130+
131+
constructor(id: number, name: string, age: number) {
132+
this.id = id
133+
this.name = name
134+
this.age = age
135+
}
136+
}
137+
138+
// app.module.ts
139+
import { resolve } from 'node:path'
140+
import { Module } from '@nestjs/common'
141+
import { StenoModule } from '@stenodb/nest'
142+
143+
@Module({
144+
imports: [
145+
StenoModule.register({
146+
path: resolve(process.cwd(), 'db')
147+
})
148+
]
149+
})
150+
export class AppModule {}
151+
152+
// users.service.ts
153+
import { Injectable, OnModuleInit } from '@nestjs/common'
154+
import { Steno, StenoService } from '@stenodb/nest'
155+
import { Users, CreateUserDto } from './users.dto'
156+
157+
@Injectable()
158+
export class UsersService implements OnModuleInit {
159+
private usersProvider: Steno.NodeProvider<Users>
160+
161+
constructor(private readonly stenoService: StenoService) {}
162+
163+
async onModuleInit(): Promise<void> {
164+
this.usersProvider = await this.stenoService.create(
165+
'users',
166+
Users,
167+
new Users(
168+
new CreateUserDto(1, 'John', 22)
169+
)
170+
)
171+
172+
await this.usersProvider.read()
173+
}
174+
175+
get users(): CreateUserDto[] {
176+
return this.usersProvider.data.users
177+
}
178+
}
179+
```
180+
104181
## Credits
105182

106183
- [steno](https://github.com/typicode/steno) - Specialized fast async file writer.

examples/with-browser-lodash/src/storage.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { BrowserProvider, LocalStorage } from '@stenodb/browser'
2-
import { Steno } from '@stenodb/browser/types'
32
import lodash from 'lodash'
43
import { User, Users } from './entities.js'
4+
import type { Steno } from '@stenodb/browser'
55

66
export class BrowserWithLodash<T> {
77
chain: lodash.ExpChain<T>

examples/with-nest/nest-cli.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"$schema": "https://json.schemastore.org/nest-cli",
3+
"collection": "@nestjs/schematics",
4+
"sourceRoot": "src"
5+
}

examples/with-nest/package.json

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
{
2+
"name": "with-nest",
3+
"version": "0.0.1",
4+
"description": "",
5+
"author": "",
6+
"private": true,
7+
"license": "UNLICENSED",
8+
"scripts": {
9+
"prebuild": "rimraf dist",
10+
"build": "nest build",
11+
"start": "nest start",
12+
"start:dev": "nest start --watch",
13+
"start:debug": "nest start --debug --watch",
14+
"start:prod": "node dist/main",
15+
"test": "jest",
16+
"test:watch": "jest --watch",
17+
"test:cov": "jest --coverage",
18+
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
19+
"test:e2e": "jest --config ./test/jest-e2e.json"
20+
},
21+
"dependencies": {
22+
"@nestjs/common": "^9.0.0",
23+
"@nestjs/core": "^9.0.0",
24+
"@nestjs/platform-express": "^9.0.0",
25+
"@stenodb/nest": "workspace:*",
26+
"class-transformer": "0.5.1",
27+
"class-validator": "^0.14.0",
28+
"reflect-metadata": "^0.1.13",
29+
"rimraf": "^3.0.2",
30+
"rxjs": "^7.2.0"
31+
},
32+
"devDependencies": {
33+
"@nestjs/cli": "^9.0.0",
34+
"@nestjs/schematics": "^9.0.0",
35+
"@nestjs/testing": "^9.0.0",
36+
"@types/express": "^4.17.13",
37+
"@types/jest": "28.1.8",
38+
"@types/node": "^16.0.0",
39+
"@types/supertest": "^2.0.11",
40+
"jest": "28.1.3",
41+
"source-map-support": "^0.5.20",
42+
"supertest": "^6.1.3",
43+
"ts-jest": "28.0.8",
44+
"ts-loader": "^9.2.3",
45+
"ts-node": "^10.0.0",
46+
"tsconfig-paths": "4.1.0",
47+
"typescript": "^4.7.4"
48+
},
49+
"jest": {
50+
"moduleFileExtensions": [
51+
"js",
52+
"json",
53+
"ts"
54+
],
55+
"rootDir": "src",
56+
"testRegex": ".*\\.spec\\.ts$",
57+
"transform": {
58+
"^.+\\.(t|j)s$": "ts-jest"
59+
},
60+
"collectCoverageFrom": [
61+
"**/*.(t|j)s"
62+
],
63+
"coverageDirectory": "../coverage",
64+
"testEnvironment": "node"
65+
}
66+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { Test, TestingModule } from '@nestjs/testing'
2+
import { StenoModule } from '@stenodb/nest'
3+
import { resolve } from 'path'
4+
import { UsersController } from './app.controller'
5+
import { UsersService } from './app.service'
6+
import { initialUsersData } from './dto/users.dto'
7+
8+
describe('UsersController', () => {
9+
let usersController: UsersController
10+
11+
beforeEach(async () => {
12+
const app: TestingModule = await Test.createTestingModule({
13+
imports: [
14+
StenoModule.register({
15+
path: resolve(process.cwd(), 'db', 'users')
16+
})
17+
],
18+
controllers: [UsersController],
19+
providers: [UsersService]
20+
}).compile()
21+
22+
await app.init()
23+
24+
usersController = app.get<UsersController>(UsersController)
25+
})
26+
27+
describe('root', () => {
28+
it('should return initialUsersData', () => {
29+
expect(usersController.getUsers()).toEqual(initialUsersData.users)
30+
})
31+
})
32+
})
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { Body, Controller, Get, Param, Post } from '@nestjs/common'
2+
import { UsersService } from './app.service'
3+
import { CreateUserDto } from './dto/users.dto'
4+
5+
@Controller('users')
6+
export class UsersController {
7+
constructor(private readonly usersService: UsersService) {}
8+
9+
@Get()
10+
getUsers() {
11+
return this.usersService.users
12+
}
13+
14+
@Get(':id')
15+
getUserById(@Param('id') id: string) {
16+
return this.usersService.findById(Number(id)) ?? {}
17+
}
18+
19+
@Post()
20+
async addUser(@Body() user: CreateUserDto) {
21+
await this.usersService.add(user)
22+
}
23+
24+
@Post('reset')
25+
async resetUsers() {
26+
await this.usersService.reset()
27+
}
28+
29+
@Post('remove/:id')
30+
async removeUser(@Param('id') id: string) {
31+
await this.usersService.remove(Number(id))
32+
}
33+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { Module } from '@nestjs/common'
2+
import { StenoModule } from '@stenodb/nest'
3+
import { resolve } from 'path'
4+
import { UsersController } from './app.controller'
5+
import { UsersService } from './app.service'
6+
7+
@Module({
8+
imports: [
9+
StenoModule.register({
10+
path: resolve(process.cwd(), 'db')
11+
})
12+
],
13+
controllers: [UsersController],
14+
providers: [UsersService]
15+
})
16+
export class AppModule {}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { Injectable, OnModuleInit } from '@nestjs/common'
2+
import { Steno, StenoService } from '@stenodb/nest'
3+
import { CreateUserDto, initialUsersData, Users } from './dto/users.dto'
4+
5+
@Injectable()
6+
export class UsersService implements OnModuleInit {
7+
private usersProvider: Steno.NodeProvider<Users>
8+
9+
constructor(private readonly stenoService: StenoService) {}
10+
11+
async onModuleInit(): Promise<void> {
12+
this.usersProvider = await this.stenoService.create(
13+
'users',
14+
Users,
15+
initialUsersData
16+
)
17+
18+
await this.usersProvider.read()
19+
}
20+
21+
get users(): CreateUserDto[] {
22+
return this.usersProvider.data.users
23+
}
24+
25+
set users(users: CreateUserDto[]) {
26+
this.usersProvider.data.users = users
27+
}
28+
29+
async reset(): Promise<void> {
30+
await this.usersProvider.reset()
31+
}
32+
33+
findById(id: number): CreateUserDto {
34+
return this.users.find((user) => user.id === id)
35+
}
36+
37+
async add(user: CreateUserDto): Promise<void> {
38+
user.id = this.users.at(-1).id + 1
39+
this.users.push(user)
40+
await this.usersProvider.write()
41+
}
42+
43+
async remove(id: number): Promise<void> {
44+
this.users = this.users.filter((user) => user.id !== id)
45+
await this.usersProvider.write()
46+
}
47+
}

0 commit comments

Comments
 (0)