@biggora/claude-plugins 1.2.2 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -1
- package/package.json +1 -1
- package/registry/registry.json +15 -0
- package/specs/coding.md +11 -0
- package/src/commands/skills/add.js +115 -31
- package/src/commands/skills/list.js +25 -52
- package/src/commands/skills/remove.js +45 -27
- package/src/commands/skills/resolve.js +104 -0
- package/src/commands/skills/update.js +58 -74
- package/src/config.js +5 -0
- package/src/skills/nest-best-practices/SKILL.md +251 -0
- package/src/skills/nest-best-practices/references/best-practices-request-lifecycle.md +158 -0
- package/src/skills/nest-best-practices/references/cli-monorepo.md +106 -0
- package/src/skills/nest-best-practices/references/cli-overview.md +157 -0
- package/src/skills/nest-best-practices/references/core-controllers.md +165 -0
- package/src/skills/nest-best-practices/references/core-dependency-injection.md +179 -0
- package/src/skills/nest-best-practices/references/core-middleware.md +139 -0
- package/src/skills/nest-best-practices/references/core-modules.md +138 -0
- package/src/skills/nest-best-practices/references/core-providers.md +188 -0
- package/src/skills/nest-best-practices/references/faq-raw-body-hybrid.md +122 -0
- package/src/skills/nest-best-practices/references/fundamentals-circular-dependency.md +89 -0
- package/src/skills/nest-best-practices/references/fundamentals-custom-decorators.md +107 -0
- package/src/skills/nest-best-practices/references/fundamentals-dynamic-modules.md +125 -0
- package/src/skills/nest-best-practices/references/fundamentals-exception-filters.md +202 -0
- package/src/skills/nest-best-practices/references/fundamentals-execution-context.md +107 -0
- package/src/skills/nest-best-practices/references/fundamentals-guards.md +136 -0
- package/src/skills/nest-best-practices/references/fundamentals-interceptors.md +187 -0
- package/src/skills/nest-best-practices/references/fundamentals-lazy-loading.md +89 -0
- package/src/skills/nest-best-practices/references/fundamentals-lifecycle-events.md +87 -0
- package/src/skills/nest-best-practices/references/fundamentals-module-reference.md +107 -0
- package/src/skills/nest-best-practices/references/fundamentals-pipes.md +197 -0
- package/src/skills/nest-best-practices/references/fundamentals-provider-scopes.md +92 -0
- package/src/skills/nest-best-practices/references/fundamentals-testing.md +142 -0
- package/src/skills/nest-best-practices/references/graphql-overview.md +233 -0
- package/src/skills/nest-best-practices/references/graphql-resolvers-mutations.md +199 -0
- package/src/skills/nest-best-practices/references/graphql-scalars-unions-enums.md +180 -0
- package/src/skills/nest-best-practices/references/graphql-subscriptions.md +228 -0
- package/src/skills/nest-best-practices/references/microservices-grpc.md +175 -0
- package/src/skills/nest-best-practices/references/microservices-overview.md +221 -0
- package/src/skills/nest-best-practices/references/microservices-transports.md +119 -0
- package/src/skills/nest-best-practices/references/openapi-swagger.md +207 -0
- package/src/skills/nest-best-practices/references/recipes-authentication.md +97 -0
- package/src/skills/nest-best-practices/references/recipes-cqrs.md +176 -0
- package/src/skills/nest-best-practices/references/recipes-crud-generator.md +87 -0
- package/src/skills/nest-best-practices/references/recipes-documentation.md +93 -0
- package/src/skills/nest-best-practices/references/recipes-mongoose.md +153 -0
- package/src/skills/nest-best-practices/references/recipes-prisma.md +98 -0
- package/src/skills/nest-best-practices/references/recipes-terminus.md +148 -0
- package/src/skills/nest-best-practices/references/recipes-typeorm.md +122 -0
- package/src/skills/nest-best-practices/references/security-authorization.md +196 -0
- package/src/skills/nest-best-practices/references/security-cors-helmet-rate-limiting.md +204 -0
- package/src/skills/nest-best-practices/references/security-encryption-hashing.md +93 -0
- package/src/skills/nest-best-practices/references/techniques-caching.md +142 -0
- package/src/skills/nest-best-practices/references/techniques-compression-streaming-sse.md +194 -0
- package/src/skills/nest-best-practices/references/techniques-configuration.md +132 -0
- package/src/skills/nest-best-practices/references/techniques-database.md +153 -0
- package/src/skills/nest-best-practices/references/techniques-events.md +163 -0
- package/src/skills/nest-best-practices/references/techniques-fastify.md +137 -0
- package/src/skills/nest-best-practices/references/techniques-file-upload.md +140 -0
- package/src/skills/nest-best-practices/references/techniques-http-module.md +176 -0
- package/src/skills/nest-best-practices/references/techniques-logging.md +146 -0
- package/src/skills/nest-best-practices/references/techniques-mvc-serve-static.md +132 -0
- package/src/skills/nest-best-practices/references/techniques-queues.md +162 -0
- package/src/skills/nest-best-practices/references/techniques-serialization.md +158 -0
- package/src/skills/nest-best-practices/references/techniques-sessions-cookies.md +167 -0
- package/src/skills/nest-best-practices/references/techniques-task-scheduling.md +166 -0
- package/src/skills/nest-best-practices/references/techniques-validation.md +126 -0
- package/src/skills/nest-best-practices/references/techniques-versioning.md +153 -0
- package/src/skills/nest-best-practices/references/websockets-advanced.md +96 -0
- package/src/skills/nest-best-practices/references/websockets-gateways.md +215 -0
- package/src/skills/typescript-expert/SKILL.md +145 -0
- package/src/skills/typescript-expert/commands/typescript-fix.md +65 -0
- package/src/skills/typescript-expert/references/advanced-conditional-types.md +190 -0
- package/src/skills/typescript-expert/references/advanced-decorators.md +243 -0
- package/src/skills/typescript-expert/references/advanced-mapped-types.md +223 -0
- package/src/skills/typescript-expert/references/advanced-template-literals.md +209 -0
- package/src/skills/typescript-expert/references/advanced-type-guards.md +308 -0
- package/src/skills/typescript-expert/references/best-practices-patterns.md +313 -0
- package/src/skills/typescript-expert/references/best-practices-performance.md +185 -0
- package/src/skills/typescript-expert/references/best-practices-tsconfig.md +242 -0
- package/src/skills/typescript-expert/references/core-generics.md +246 -0
- package/src/skills/typescript-expert/references/core-interfaces-types.md +231 -0
- package/src/skills/typescript-expert/references/core-type-system.md +261 -0
- package/src/skills/typescript-expert/references/core-utility-types.md +235 -0
- package/src/skills/typescript-expert/references/features-ts5x.md +370 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cqrs
|
|
3
|
+
description: Command Query Responsibility Segregation pattern for complex applications
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# CQRS
|
|
7
|
+
|
|
8
|
+
Separate read and write operations for scalability and flexibility.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @nestjs/cqrs
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
@Module({
|
|
18
|
+
imports: [CqrsModule.forRoot()],
|
|
19
|
+
})
|
|
20
|
+
export class AppModule {}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Commands
|
|
24
|
+
|
|
25
|
+
Commands change application state. Use `CommandBus` to dispatch.
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
// kill-dragon.command.ts
|
|
29
|
+
export class KillDragonCommand extends Command<{ actionId: string }> {
|
|
30
|
+
constructor(
|
|
31
|
+
public readonly heroId: string,
|
|
32
|
+
public readonly dragonId: string,
|
|
33
|
+
) {
|
|
34
|
+
super();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// kill-dragon.handler.ts
|
|
39
|
+
@CommandHandler(KillDragonCommand)
|
|
40
|
+
export class KillDragonHandler implements ICommandHandler<KillDragonCommand> {
|
|
41
|
+
constructor(private repository: HeroesRepository) {}
|
|
42
|
+
|
|
43
|
+
async execute(command: KillDragonCommand) {
|
|
44
|
+
const { heroId, dragonId } = command;
|
|
45
|
+
const hero = await this.repository.findOneById(+heroId);
|
|
46
|
+
hero.killEnemy(dragonId);
|
|
47
|
+
await this.repository.persist(hero);
|
|
48
|
+
return { actionId: crypto.randomUUID() };
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
// Usage
|
|
55
|
+
await this.commandBus.execute(
|
|
56
|
+
new KillDragonCommand(heroId, killDragonDto.dragonId)
|
|
57
|
+
);
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Queries
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
export class GetHeroQuery extends Query<Hero> {
|
|
64
|
+
constructor(public readonly heroId: string) {
|
|
65
|
+
super();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
@QueryHandler(GetHeroQuery)
|
|
70
|
+
export class GetHeroHandler implements IQueryHandler<GetHeroQuery> {
|
|
71
|
+
constructor(private repository: HeroesRepository) {}
|
|
72
|
+
|
|
73
|
+
async execute(query: GetHeroQuery) {
|
|
74
|
+
return this.repository.findOneById(query.heroId);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
const hero = await this.queryBus.execute(new GetHeroQuery(heroId));
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Events
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
export class HeroKilledDragonEvent {
|
|
87
|
+
constructor(
|
|
88
|
+
public readonly heroId: string,
|
|
89
|
+
public readonly dragonId: string,
|
|
90
|
+
) {}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
@EventsHandler(HeroKilledDragonEvent)
|
|
94
|
+
export class HeroKilledDragonHandler implements IEventHandler<HeroKilledDragonEvent> {
|
|
95
|
+
handle(event: HeroKilledDragonEvent) {
|
|
96
|
+
// Update read model, send notifications, etc.
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Publish from model with `AggregateRoot`:
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
export class Hero extends AggregateRoot {
|
|
105
|
+
killEnemy(enemyId: string) {
|
|
106
|
+
this.apply(new HeroKilledDragonEvent(this.id, enemyId));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Requires `EventPublisher.mergeObjectContext()` and `hero.commit()`.
|
|
112
|
+
|
|
113
|
+
Or publish manually:
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
this.eventBus.publish(new HeroKilledDragonEvent(heroId, dragonId));
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Sagas
|
|
120
|
+
|
|
121
|
+
Long-running processes that listen to events and dispatch commands.
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
@Injectable()
|
|
125
|
+
export class HeroesGameSagas {
|
|
126
|
+
@Saga()
|
|
127
|
+
dragonKilled = (events$: Observable<any>): Observable<ICommand> => {
|
|
128
|
+
return events$.pipe(
|
|
129
|
+
ofType(HeroKilledDragonEvent),
|
|
130
|
+
map((event) => new DropAncientItemCommand(event.heroId, fakeItemID)),
|
|
131
|
+
);
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Register saga as provider. `ofType` filters events; return command to dispatch.
|
|
137
|
+
|
|
138
|
+
## Request-Scoped Handlers
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
@CommandHandler(KillDragonCommand, { scope: Scope.REQUEST })
|
|
142
|
+
export class KillDragonHandler {
|
|
143
|
+
constructor(@Inject(REQUEST) private request: MyRequest) {}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Pass `AsyncContext` when executing:
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
const myRequest = new MyRequest(user);
|
|
151
|
+
await this.commandBus.execute(command, myRequest);
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Unhandled Exceptions
|
|
155
|
+
|
|
156
|
+
Event handler errors don't reach Exception filters. Subscribe to `UnhandledExceptionBus`:
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
this.unhandledExceptionsBus
|
|
160
|
+
.pipe(takeUntil(this.destroy$))
|
|
161
|
+
.subscribe((exceptionInfo) => {
|
|
162
|
+
// Handle exception
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Key Points
|
|
167
|
+
|
|
168
|
+
- Commands: task-based, change state; Queries: data-centric, read state
|
|
169
|
+
- Register all handlers/sagas as providers
|
|
170
|
+
- Event handlers run asynchronously—no HTTP response
|
|
171
|
+
- Use Redis-backed event store for production sagas
|
|
172
|
+
|
|
173
|
+
<!--
|
|
174
|
+
Source references:
|
|
175
|
+
- https://docs.nestjs.com/recipes/cqrs
|
|
176
|
+
-->
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: recipes-crud-generator
|
|
3
|
+
description: Using Nest CLI to generate CRUD resources
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# CRUD Generator
|
|
7
|
+
|
|
8
|
+
Nest CLI provides a resource generator that automatically creates all boilerplate code for CRUD operations.
|
|
9
|
+
|
|
10
|
+
## Generate Resource
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
nest g resource
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The generator will prompt for:
|
|
17
|
+
- Resource name
|
|
18
|
+
- Transport layer (REST API, GraphQL, Microservice, WebSocket)
|
|
19
|
+
- Whether to generate CRUD entry points
|
|
20
|
+
|
|
21
|
+
## Generated Files
|
|
22
|
+
|
|
23
|
+
For REST API, generates:
|
|
24
|
+
- Module file (`users.module.ts`)
|
|
25
|
+
- Controller file (`users.controller.ts`)
|
|
26
|
+
- Service file (`users.service.ts`)
|
|
27
|
+
- DTO files (`create-user.dto.ts`, `update-user.dto.ts`)
|
|
28
|
+
- Entity file (`user.entity.ts`)
|
|
29
|
+
- Test files (`.spec.ts`)
|
|
30
|
+
|
|
31
|
+
## Generated Controller
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
@Controller('users')
|
|
35
|
+
export class UsersController {
|
|
36
|
+
constructor(private readonly usersService: UsersService) {}
|
|
37
|
+
|
|
38
|
+
@Post()
|
|
39
|
+
create(@Body() createUserDto: CreateUserDto) {
|
|
40
|
+
return this.usersService.create(createUserDto);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@Get()
|
|
44
|
+
findAll() {
|
|
45
|
+
return this.usersService.findAll();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@Get(':id')
|
|
49
|
+
findOne(@Param('id') id: string) {
|
|
50
|
+
return this.usersService.findOne(+id);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@Patch(':id')
|
|
54
|
+
update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
|
|
55
|
+
return this.usersService.update(+id, updateUserDto);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@Delete(':id')
|
|
59
|
+
remove(@Param('id') id: string) {
|
|
60
|
+
return this.usersService.remove(+id);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## GraphQL Support
|
|
66
|
+
|
|
67
|
+
For GraphQL applications, generates resolvers instead of controllers:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
nest g resource users
|
|
71
|
+
# Select: GraphQL (code first)
|
|
72
|
+
# Select: Yes for CRUD entry points
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Key Points
|
|
76
|
+
|
|
77
|
+
- Generates all CRUD boilerplate automatically
|
|
78
|
+
- Supports REST, GraphQL, Microservices, and WebSockets
|
|
79
|
+
- Service methods contain placeholders for implementation
|
|
80
|
+
- Not tied to any specific ORM
|
|
81
|
+
- Includes test files
|
|
82
|
+
- Saves significant development time
|
|
83
|
+
|
|
84
|
+
<!--
|
|
85
|
+
Source references:
|
|
86
|
+
- https://docs.nestjs.com/recipes/crud-generator
|
|
87
|
+
-->
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: recipes-documentation
|
|
3
|
+
description: OpenAPI/Swagger documentation setup in NestJS
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# API Documentation
|
|
7
|
+
|
|
8
|
+
NestJS provides integration with Swagger/OpenAPI for automatic API documentation generation.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install --save @nestjs/swagger
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Basic Setup
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
|
|
20
|
+
|
|
21
|
+
async function bootstrap() {
|
|
22
|
+
const app = await NestFactory.create(AppModule);
|
|
23
|
+
|
|
24
|
+
const config = new DocumentBuilder()
|
|
25
|
+
.setTitle('Cats example')
|
|
26
|
+
.setDescription('The cats API description')
|
|
27
|
+
.setVersion('1.0')
|
|
28
|
+
.addTag('cats')
|
|
29
|
+
.build();
|
|
30
|
+
const document = SwaggerModule.createDocument(app, config);
|
|
31
|
+
SwaggerModule.setup('api', app, document);
|
|
32
|
+
|
|
33
|
+
await app.listen(3000);
|
|
34
|
+
}
|
|
35
|
+
bootstrap();
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## DTO Decorators
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
import { ApiProperty } from '@nestjs/swagger';
|
|
42
|
+
|
|
43
|
+
export class CreateCatDto {
|
|
44
|
+
@ApiProperty()
|
|
45
|
+
name: string;
|
|
46
|
+
|
|
47
|
+
@ApiProperty()
|
|
48
|
+
age: number;
|
|
49
|
+
|
|
50
|
+
@ApiProperty()
|
|
51
|
+
breed: string;
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Controller Decorators
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
|
|
59
|
+
|
|
60
|
+
@ApiTags('cats')
|
|
61
|
+
@Controller('cats')
|
|
62
|
+
export class CatsController {
|
|
63
|
+
@Post()
|
|
64
|
+
@ApiOperation({ summary: 'Create a new cat' })
|
|
65
|
+
@ApiResponse({ status: 201, description: 'The cat has been successfully created.' })
|
|
66
|
+
@ApiResponse({ status: 403, description: 'Forbidden.' })
|
|
67
|
+
create(@Body() createCatDto: CreateCatDto) {
|
|
68
|
+
return this.catsService.create(createCatDto);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Security
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
const config = new DocumentBuilder()
|
|
77
|
+
.addBearerAuth()
|
|
78
|
+
.build();
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Key Points
|
|
82
|
+
|
|
83
|
+
- Use `@nestjs/swagger` for OpenAPI integration
|
|
84
|
+
- Decorate DTOs with `@ApiProperty()`
|
|
85
|
+
- Use `@ApiTags()` to group endpoints
|
|
86
|
+
- Add `@ApiOperation()` and `@ApiResponse()` for documentation
|
|
87
|
+
- Configure security schemes for authentication
|
|
88
|
+
- Access docs at `/api` endpoint
|
|
89
|
+
|
|
90
|
+
<!--
|
|
91
|
+
Source references:
|
|
92
|
+
- https://docs.nestjs.com/openapi/introduction
|
|
93
|
+
-->
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mongoose
|
|
3
|
+
description: MongoDB integration with Mongoose ODM
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Mongoose (MongoDB)
|
|
7
|
+
|
|
8
|
+
Mongoose is the most popular MongoDB object modeling tool for Node.js.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm i @nestjs/mongoose mongoose
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Setup
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
@Module({
|
|
20
|
+
imports: [
|
|
21
|
+
MongooseModule.forRoot('mongodb://localhost/nest'),
|
|
22
|
+
// Or with options
|
|
23
|
+
MongooseModule.forRoot('mongodb://localhost/nest', {
|
|
24
|
+
connectionName: 'cats',
|
|
25
|
+
}),
|
|
26
|
+
],
|
|
27
|
+
})
|
|
28
|
+
export class AppModule {}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Schema Definition
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
|
|
35
|
+
import { HydratedDocument } from 'mongoose';
|
|
36
|
+
|
|
37
|
+
export type CatDocument = HydratedDocument<Cat>;
|
|
38
|
+
|
|
39
|
+
@Schema()
|
|
40
|
+
export class Cat {
|
|
41
|
+
@Prop()
|
|
42
|
+
name: string;
|
|
43
|
+
|
|
44
|
+
@Prop({ required: true })
|
|
45
|
+
age: number;
|
|
46
|
+
|
|
47
|
+
@Prop([String])
|
|
48
|
+
tags: string[];
|
|
49
|
+
|
|
50
|
+
@Prop({ default: Date.now })
|
|
51
|
+
createdAt: Date;
|
|
52
|
+
|
|
53
|
+
@Prop({ type: mongoose.Schema.Types.ObjectId, ref: 'Owner' })
|
|
54
|
+
owner: Owner;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export const CatSchema = SchemaFactory.createForClass(Cat);
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Register Model
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
@Module({
|
|
64
|
+
imports: [
|
|
65
|
+
MongooseModule.forFeature([
|
|
66
|
+
{ name: Cat.name, schema: CatSchema },
|
|
67
|
+
]),
|
|
68
|
+
],
|
|
69
|
+
})
|
|
70
|
+
export class CatsModule {}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Inject and Use
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
@Injectable()
|
|
77
|
+
export class CatsService {
|
|
78
|
+
constructor(
|
|
79
|
+
@InjectModel(Cat.name) private catModel: Model<CatDocument>,
|
|
80
|
+
) {}
|
|
81
|
+
|
|
82
|
+
async create(createCatDto: CreateCatDto) {
|
|
83
|
+
const created = new this.catModel(createCatDto);
|
|
84
|
+
return created.save();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async findAll(): Promise<Cat[]> {
|
|
88
|
+
return this.catModel.find().exec();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async findOne(id: string) {
|
|
92
|
+
return this.catModel.findById(id).populate('owner').exec();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## @Prop Options
|
|
98
|
+
|
|
99
|
+
| Option | Description |
|
|
100
|
+
|--------|-------------|
|
|
101
|
+
| `required` | Required field |
|
|
102
|
+
| `default` | Default value |
|
|
103
|
+
| `unique` | Unique index |
|
|
104
|
+
| `index` | Create index |
|
|
105
|
+
| `type` | Explicit type (e.g., `mongoose.Schema.Types.ObjectId`) |
|
|
106
|
+
| `ref` | Reference to another model |
|
|
107
|
+
|
|
108
|
+
## Relations (Population)
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
@Prop({ type: mongoose.Schema.Types.ObjectId, ref: 'Owner' })
|
|
112
|
+
owner: Owner;
|
|
113
|
+
|
|
114
|
+
// Multiple
|
|
115
|
+
@Prop({ type: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Owner' }] })
|
|
116
|
+
owners: Owner[];
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
return this.catModel.find().populate('owner').exec();
|
|
121
|
+
return this.catModel.find().populate({ path: 'owner', select: 'name' }).exec();
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Plugins
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
CatSchema.plugin(require('mongoose-autopopulate'));
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Async Configuration
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
MongooseModule.forRootAsync({
|
|
134
|
+
imports: [ConfigModule],
|
|
135
|
+
useFactory: (config: ConfigService) => ({
|
|
136
|
+
uri: config.get('MONGODB_URI'),
|
|
137
|
+
}),
|
|
138
|
+
inject: [ConfigService],
|
|
139
|
+
}),
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Key Points
|
|
143
|
+
|
|
144
|
+
- Use `@Schema()` and `@Prop()` decorators
|
|
145
|
+
- `SchemaFactory.createForClass()` generates schema
|
|
146
|
+
- `@InjectModel()` injects Model
|
|
147
|
+
- Use `populate()` for relations
|
|
148
|
+
- `HydratedDocument<Cat>` for typed documents
|
|
149
|
+
|
|
150
|
+
<!--
|
|
151
|
+
Source references:
|
|
152
|
+
- https://docs.nestjs.com/techniques/mongodb
|
|
153
|
+
-->
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: recipes-prisma
|
|
3
|
+
description: Prisma ORM integration in NestJS
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Prisma Integration
|
|
7
|
+
|
|
8
|
+
Prisma is a next-generation ORM that provides type-safe database access.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install --save @prisma/client
|
|
14
|
+
npm install --save-dev prisma
|
|
15
|
+
npx prisma init
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Prisma Service
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
import { Injectable, OnModuleInit } from '@nestjs/common';
|
|
22
|
+
import { PrismaClient } from '@prisma/client';
|
|
23
|
+
|
|
24
|
+
@Injectable()
|
|
25
|
+
export class PrismaService extends PrismaClient implements OnModuleInit {
|
|
26
|
+
async onModuleInit() {
|
|
27
|
+
await this.$connect();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Module Setup
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
import { Module } from '@nestjs/common';
|
|
36
|
+
import { PrismaService } from './prisma.service';
|
|
37
|
+
|
|
38
|
+
@Module({
|
|
39
|
+
providers: [PrismaService],
|
|
40
|
+
exports: [PrismaService],
|
|
41
|
+
})
|
|
42
|
+
export class PrismaModule {}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Using Prisma Service
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import { Injectable } from '@nestjs/common';
|
|
49
|
+
import { PrismaService } from './prisma.service';
|
|
50
|
+
|
|
51
|
+
@Injectable()
|
|
52
|
+
export class UsersService {
|
|
53
|
+
constructor(private prisma: PrismaService) {}
|
|
54
|
+
|
|
55
|
+
async findAll() {
|
|
56
|
+
return this.prisma.user.findMany();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async findOne(id: number) {
|
|
60
|
+
return this.prisma.user.findUnique({
|
|
61
|
+
where: { id },
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async create(data: CreateUserDto) {
|
|
66
|
+
return this.prisma.user.create({
|
|
67
|
+
data,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async update(id: number, data: UpdateUserDto) {
|
|
72
|
+
return this.prisma.user.update({
|
|
73
|
+
where: { id },
|
|
74
|
+
data,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async remove(id: number) {
|
|
79
|
+
return this.prisma.user.delete({
|
|
80
|
+
where: { id },
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Key Points
|
|
87
|
+
|
|
88
|
+
- Prisma provides type-safe database access
|
|
89
|
+
- Extend `PrismaClient` for service
|
|
90
|
+
- Use `$connect()` in `onModuleInit()`
|
|
91
|
+
- Prisma generates types from schema
|
|
92
|
+
- Use Prisma Studio for database management
|
|
93
|
+
- Supports migrations and seeding
|
|
94
|
+
|
|
95
|
+
<!--
|
|
96
|
+
Source references:
|
|
97
|
+
- https://docs.nestjs.com/recipes/prisma
|
|
98
|
+
-->
|