├── .editorconfig
├── .eslintrc.js
├── .gitignore
├── .prettierrc
├── README.md
├── docker-compose.yml
├── nest-cli.json
├── package-lock.json
├── package.json
├── src
├── app.controller.spec.ts
├── app.controller.ts
├── app.module.ts
├── app.service.ts
├── common
│ ├── mongo-id.pipe.spec.ts
│ ├── mongo-id.pipe.ts
│ ├── parse-int.pipe.spec.ts
│ └── parse-int.pipe.ts
├── config.ts
├── database
│ └── database.module.ts
├── enviroments.ts
├── main.ts
├── products
│ ├── controllers
│ │ ├── brands.controller.ts
│ │ ├── categories.controller.ts
│ │ └── products.controller.ts
│ ├── dtos
│ │ ├── brand.dtos.ts
│ │ ├── category.dtos.ts
│ │ └── products.dtos.ts
│ ├── entities
│ │ ├── brand.entity.ts
│ │ ├── category.entity.ts
│ │ └── product.entity.ts
│ ├── products.module.ts
│ └── services
│ │ ├── brands.service.ts
│ │ ├── categories.service.ts
│ │ └── products.service.ts
├── recap.ts
└── users
│ ├── controllers
│ ├── customers.controller.ts
│ ├── orders.controller.ts
│ └── users.controller.ts
│ ├── dtos
│ ├── customer.dto.ts
│ ├── order.dto.ts
│ └── user.dto.ts
│ ├── entities
│ ├── customer.entity.ts
│ ├── order.entity.ts
│ └── user.entity.ts
│ ├── services
│ ├── customers.service.ts
│ ├── orders.service.ts
│ └── users.service.ts
│ └── users.module.ts
├── test
├── app.e2e-spec.ts
└── jest-e2e.json
├── tsconfig.build.json
└── tsconfig.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.ts]
12 | quote_type = single
13 |
14 | [*.md]
15 | max_line_length = off
16 | trim_trailing_whitespace = false
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | parser: '@typescript-eslint/parser',
3 | parserOptions: {
4 | project: 'tsconfig.json',
5 | sourceType: 'module',
6 | },
7 | plugins: ['@typescript-eslint/eslint-plugin'],
8 | extends: [
9 | 'plugin:@typescript-eslint/recommended',
10 | 'plugin:prettier/recommended',
11 | ],
12 | root: true,
13 | env: {
14 | node: true,
15 | jest: true,
16 | },
17 | ignorePatterns: ['.eslintrc.js'],
18 | rules: {
19 | '@typescript-eslint/interface-name-prefix': 'off',
20 | '@typescript-eslint/explicit-function-return-type': 'off',
21 | '@typescript-eslint/explicit-module-boundary-types': 'off',
22 | '@typescript-eslint/no-explicit-any': 'off',
23 | },
24 | };
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
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 | *.env
37 | /mongo_data
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "all"
4 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | [circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
6 | [circleci-url]: https://circleci.com/gh/nestjs/nest
7 |
8 | A progressive Node.js framework for building efficient and scalable server-side applications.
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
24 |
25 | ## Description
26 |
27 | [Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.
28 |
29 | ## Installation
30 |
31 | ```bash
32 | $ npm install
33 | ```
34 |
35 | ## Running the app
36 |
37 | ```bash
38 | # development
39 | $ npm run start
40 |
41 | # watch mode
42 | $ npm run start:dev
43 |
44 | # production mode
45 | $ npm run start:prod
46 | ```
47 |
48 | ## Test
49 |
50 | ```bash
51 | # unit tests
52 | $ npm run test
53 |
54 | # e2e tests
55 | $ npm run test:e2e
56 |
57 | # test coverage
58 | $ npm run test:cov
59 | ```
60 |
61 | ## Support
62 |
63 | Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
64 |
65 | ## Stay in touch
66 |
67 | - Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)
68 | - Website - [https://nestjs.com](https://nestjs.com/)
69 | - Twitter - [@nestframework](https://twitter.com/nestframework)
70 |
71 | ## License
72 |
73 | Nest is [MIT licensed](LICENSE).
74 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3.3'
2 |
3 | services:
4 | mongo:
5 | image: mongo:4.4
6 | environment:
7 | MONGO_INITDB_ROOT_USERNAME: root
8 | MONGO_INITDB_ROOT_PASSWORD: root
9 | ports:
10 | - 27017:27017
11 | volumes:
12 | - ./mongo_data:/data/db
--------------------------------------------------------------------------------
/nest-cli.json:
--------------------------------------------------------------------------------
1 | {
2 | "collection": "@nestjs/schematics",
3 | "sourceRoot": "src",
4 | "compilerOptions": {
5 | "plugins": ["@nestjs/swagger/plugin"]
6 | }
7 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "platzi-store",
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 | "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
12 | "start": "nest start",
13 | "start:dev": "nest start --watch",
14 | "start:debug": "nest start --debug --watch",
15 | "start:prod": "node dist/main",
16 | "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
17 | "test": "jest",
18 | "test:watch": "jest --watch",
19 | "test:cov": "jest --coverage",
20 | "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
21 | "test:e2e": "jest --config ./test/jest-e2e.json"
22 | },
23 | "dependencies": {
24 | "@nestjs/common": "^7.6.13",
25 | "@nestjs/config": "^0.6.3",
26 | "@nestjs/core": "^7.6.13",
27 | "@nestjs/mapped-types": "^0.3.0",
28 | "@nestjs/mongoose": "^7.2.4",
29 | "@nestjs/platform-express": "^7.6.13",
30 | "@nestjs/swagger": "^4.7.16",
31 | "class-transformer": "^0.4.0",
32 | "class-validator": "^0.13.1",
33 | "joi": "^17.4.0",
34 | "mongodb": "^3.6.4",
35 | "mongoose": "^5.11.20",
36 | "reflect-metadata": "^0.1.13",
37 | "rimraf": "^3.0.2",
38 | "rxjs": "^6.6.6",
39 | "swagger-ui-express": "^4.1.6"
40 | },
41 | "devDependencies": {
42 | "@nestjs/cli": "^7.5.6",
43 | "@nestjs/schematics": "^7.2.7",
44 | "@nestjs/testing": "^7.6.13",
45 | "@types/express": "^4.17.11",
46 | "@types/jest": "^26.0.20",
47 | "@types/mongodb": "^3.6.9",
48 | "@types/node": "^14.14.31",
49 | "@types/supertest": "^2.0.10",
50 | "@typescript-eslint/eslint-plugin": "^4.15.2",
51 | "@typescript-eslint/parser": "^4.15.2",
52 | "eslint": "^7.20.0",
53 | "eslint-config-prettier": "^8.1.0",
54 | "eslint-plugin-prettier": "^3.3.1",
55 | "jest": "^26.6.3",
56 | "prettier": "^2.2.1",
57 | "supertest": "^6.1.3",
58 | "ts-jest": "^26.5.2",
59 | "ts-loader": "^8.0.17",
60 | "ts-node": "^9.1.1",
61 | "tsconfig-paths": "^3.9.0",
62 | "typescript": "^4.1.5"
63 | },
64 | "jest": {
65 | "moduleFileExtensions": [
66 | "js",
67 | "json",
68 | "ts"
69 | ],
70 | "rootDir": "src",
71 | "testRegex": ".*\\.spec\\.ts$",
72 | "transform": {
73 | "^.+\\.(t|j)s$": "ts-jest"
74 | },
75 | "collectCoverageFrom": [
76 | "**/*.(t|j)s"
77 | ],
78 | "coverageDirectory": "../coverage",
79 | "testEnvironment": "node"
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/app.controller.spec.ts:
--------------------------------------------------------------------------------
1 | import { Test, TestingModule } from '@nestjs/testing';
2 | import { AppController } from './app.controller';
3 | import { AppService } from './app.service';
4 |
5 | describe('AppController', () => {
6 | let appController: AppController;
7 |
8 | beforeEach(async () => {
9 | const app: TestingModule = await Test.createTestingModule({
10 | controllers: [AppController],
11 | providers: [AppService],
12 | }).compile();
13 |
14 | appController = app.get(AppController);
15 | });
16 |
17 | describe('root', () => {
18 | it('should return "Hello World!"', () => {
19 | expect(appController.getHello()).toBe('Hello World!');
20 | });
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/src/app.controller.ts:
--------------------------------------------------------------------------------
1 | import { Controller, Get, Param, Query } from '@nestjs/common';
2 | import { AppService } from './app.service';
3 |
4 | @Controller()
5 | export class AppController {
6 | constructor(private readonly appService: AppService) {}
7 |
8 | @Get()
9 | getHello(): string {
10 | return this.appService.getHello();
11 | }
12 |
13 | @Get('nuevo')
14 | newEndpoint() {
15 | return 'yo soy nuevo';
16 | }
17 |
18 | @Get('/ruta/')
19 | hello() {
20 | return 'con /sas/';
21 | }
22 |
23 | @Get('/tasks/')
24 | getTasks() {
25 | return this.appService.getTasks();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/app.module.ts:
--------------------------------------------------------------------------------
1 | import { Module, HttpModule, HttpService } from '@nestjs/common';
2 | import { ConfigModule } from '@nestjs/config';
3 | import * as Joi from 'joi';
4 |
5 |
6 | import { AppController } from './app.controller';
7 | import { AppService } from './app.service';
8 | import { UsersModule } from './users/users.module';
9 | import { ProductsModule } from './products/products.module';
10 | import { DatabaseModule } from './database/database.module';
11 | import { enviroments } from './enviroments';
12 | import config from './config';
13 |
14 |
15 |
16 | @Module({
17 | imports: [
18 | ConfigModule.forRoot({
19 | envFilePath: enviroments[process.env.NODE_ENV] || '.env',
20 | load: [config],
21 | isGlobal: true,
22 | validationSchema: Joi.object({
23 | API_KEY: Joi.number().required(),
24 | DATABASE_NAME: Joi.string().required(),
25 | DATABASE_PORT: Joi.number().required(),
26 | }),
27 | }),
28 | HttpModule,
29 | UsersModule,
30 | ProductsModule,
31 | DatabaseModule,
32 | ],
33 | controllers: [AppController],
34 | providers: [
35 | AppService,
36 | {
37 | provide: 'TASKS',
38 | useFactory: async (http: HttpService) => {
39 | const tasks = await http
40 | .get('https://jsonplaceholder.typicode.com/todos')
41 | .toPromise();
42 | return tasks.data;
43 | },
44 | inject: [HttpService],
45 | },
46 | ],
47 | })
48 | export class AppModule {}
49 |
--------------------------------------------------------------------------------
/src/app.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable, Inject } from '@nestjs/common';
2 | import { ConfigType } from '@nestjs/config';
3 | import { Db } from 'mongodb';
4 |
5 | import config from './config';
6 |
7 | @Injectable()
8 | export class AppService {
9 | constructor(
10 | // @Inject('API_KEY') private apiKey: string,
11 | @Inject('TASKS') private tasks: any[],
12 | @Inject('MONGO') private database: Db,
13 | @Inject(config.KEY) private configService: ConfigType,
14 | ) {}
15 | getHello(): string {
16 | const apiKey = this.configService.apiKey;
17 | const name = this.configService.database.name;
18 | return `Hello World! ${apiKey} ${name}`;
19 | }
20 | getTasks() {
21 | const tasksCollection = this.database.collection('tasks');
22 | return tasksCollection.find().toArray();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/common/mongo-id.pipe.spec.ts:
--------------------------------------------------------------------------------
1 | import { MongoIdPipe } from './mongo-id.pipe';
2 |
3 | describe('MongoIdPipe', () => {
4 | it('should be defined', () => {
5 | expect(new MongoIdPipe()).toBeDefined();
6 | });
7 | });
8 |
--------------------------------------------------------------------------------
/src/common/mongo-id.pipe.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ArgumentMetadata,
3 | Injectable,
4 | PipeTransform,
5 | BadRequestException,
6 | } from '@nestjs/common';
7 | import { isMongoId } from 'class-validator';
8 |
9 | @Injectable()
10 | export class MongoIdPipe implements PipeTransform {
11 | transform(value: string, metadata: ArgumentMetadata) {
12 | if (!isMongoId(value)) {
13 | throw new BadRequestException(`${value} not is a mongoId`);
14 | }
15 | return value;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/common/parse-int.pipe.spec.ts:
--------------------------------------------------------------------------------
1 | import { ParseIntPipe } from './parse-int.pipe';
2 |
3 | describe('ParseIntPipe', () => {
4 | it('should be defined', () => {
5 | expect(new ParseIntPipe()).toBeDefined();
6 | });
7 | });
8 |
--------------------------------------------------------------------------------
/src/common/parse-int.pipe.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ArgumentMetadata,
3 | Injectable,
4 | PipeTransform,
5 | BadRequestException,
6 | } from '@nestjs/common';
7 |
8 | @Injectable()
9 | export class ParseIntPipe implements PipeTransform {
10 | transform(value: string, metadata: ArgumentMetadata) {
11 | const val = parseInt(value, 10);
12 | if (isNaN(val)) {
13 | throw new BadRequestException(`${value} is not an number`);
14 | }
15 | return val;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/config.ts:
--------------------------------------------------------------------------------
1 | import { registerAs } from '@nestjs/config';
2 |
3 | export default registerAs('config', () => {
4 | return {
5 | database: {
6 | name: process.env.DATABASE_NAME,
7 | port: process.env.DATABASE_PORT,
8 | },
9 | mongo: {
10 | dbName: process.env.MONGO_DB,
11 | user: process.env.MONGO_INITDB_ROOT_USERNAME,
12 | password: process.env.MONGO_INITDB_ROOT_PASSWORD,
13 | port: parseInt(process.env.MONGO_PORT, 10),
14 | host: process.env.MONGO_HOST,
15 | connection: process.env.MONGO_CONNECTION,
16 | },
17 | apiKey: process.env.API_KEY,
18 | };
19 | });
20 |
--------------------------------------------------------------------------------
/src/database/database.module.ts:
--------------------------------------------------------------------------------
1 | import { Module, Global } from '@nestjs/common';
2 | import { ConfigType } from '@nestjs/config';
3 | import { MongooseModule } from '@nestjs/mongoose';
4 | import { MongoClient } from 'mongodb';
5 |
6 | import config from '../config';
7 |
8 | const API_KEY = '12345634';
9 | const API_KEY_PROD = 'PROD1212121SA';
10 |
11 | // const taskCollection = database.collection('tasks');
12 | // const tasks = await taskCollection.find().toArray();
13 |
14 | @Global()
15 | @Module({
16 | imports: [
17 | // MongooseModule.forRoot('mongodb://localhost:27017', {
18 | // user: 'root',
19 | // pass: 'root',
20 | // dbName: 'platzi-store',
21 | // }),
22 | MongooseModule.forRootAsync({
23 | useFactory: (configService: ConfigType) => {
24 | const {
25 | connection,
26 | user,
27 | password,
28 | host,
29 | port,
30 | dbName,
31 | } = configService.mongo;
32 | return {
33 | uri: `${connection}://${host}:${port}`,
34 | user,
35 | pass: password,
36 | dbName,
37 | };
38 | },
39 | inject: [config.KEY],
40 | }),
41 | ],
42 | providers: [
43 | {
44 | provide: 'API_KEY',
45 | useValue: process.env.NODE_ENV === 'prod' ? API_KEY_PROD : API_KEY,
46 | },
47 | {
48 | provide: 'MONGO',
49 | useFactory: async (configService: ConfigType) => {
50 | const {
51 | connection,
52 | user,
53 | password,
54 | host,
55 | port,
56 | dbName,
57 | } = configService.mongo;
58 | const uri = `${connection}://${user}:${password}@${host}:${port}/?authSource=admin&readPreference=primary`;
59 | const client = new MongoClient(uri);
60 | await client.connect();
61 | const database = client.db(dbName);
62 | return database;
63 | },
64 | inject: [config.KEY],
65 | },
66 | ],
67 | exports: ['API_KEY', 'MONGO', MongooseModule],
68 | })
69 | export class DatabaseModule {}
70 |
--------------------------------------------------------------------------------
/src/enviroments.ts:
--------------------------------------------------------------------------------
1 | export const enviroments = {
2 | dev: '.env',
3 | stag: '.stag.env',
4 | prod: '.prod.env',
5 | };
6 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import { NestFactory } from '@nestjs/core';
2 | import { ValidationPipe } from '@nestjs/common';
3 | import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
4 | import { AppModule } from './app.module';
5 |
6 | async function bootstrap() {
7 | const app = await NestFactory.create(AppModule);
8 | app.useGlobalPipes(
9 | new ValidationPipe({
10 | whitelist: true,
11 | forbidNonWhitelisted: true,
12 | transformOptions: {
13 | enableImplicitConversion: true,
14 | },
15 | }),
16 | );
17 |
18 | const config = new DocumentBuilder()
19 | .setTitle('API')
20 | .setDescription('PLATZI STORE')
21 | .setVersion('1.0')
22 | .build();
23 | const document = SwaggerModule.createDocument(app, config);
24 | SwaggerModule.setup('docs', app, document);
25 | await app.listen(3000);
26 | }
27 | bootstrap();
28 |
--------------------------------------------------------------------------------
/src/products/controllers/brands.controller.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Controller,
3 | Get,
4 | Param,
5 | Post,
6 | Body,
7 | Put,
8 | Delete,
9 | } from '@nestjs/common';
10 | import { ApiTags } from '@nestjs/swagger';
11 |
12 | import { BrandsService } from '../services/brands.service';
13 | import { CreateBrandDto, UpdateBrandDto } from '../dtos/brand.dtos';
14 |
15 | @ApiTags('brands')
16 | @Controller('brands')
17 | export class BrandsController {
18 | constructor(private brandsService: BrandsService) {}
19 |
20 | @Get()
21 | findAll() {
22 | return this.brandsService.findAll();
23 | }
24 |
25 | @Get(':id')
26 | get(@Param('id') id: string) {
27 | return this.brandsService.findOne(id);
28 | }
29 |
30 | @Post()
31 | create(@Body() payload: CreateBrandDto) {
32 | return this.brandsService.create(payload);
33 | }
34 |
35 | @Put(':id')
36 | update(@Param('id') id: string, @Body() payload: UpdateBrandDto) {
37 | return this.brandsService.update(id, payload);
38 | }
39 |
40 | @Delete(':id')
41 | remove(@Param('id') id: string) {
42 | return this.brandsService.remove(id);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/products/controllers/categories.controller.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Controller,
3 | Get,
4 | Param,
5 | Post,
6 | Body,
7 | Put,
8 | Delete,
9 | ParseIntPipe,
10 | } from '@nestjs/common';
11 |
12 | import { CategoriesService } from '../services/categories.service';
13 | import { CreateCategoryDto, UpdateCategoryDto } from './../dtos/category.dtos';
14 |
15 | @Controller('categories')
16 | export class CategoriesController {
17 | constructor(private categoriesService: CategoriesService) {}
18 |
19 | @Get()
20 | findAll() {
21 | return this.categoriesService.findAll();
22 | }
23 |
24 | @Get(':id')
25 | get(@Param('id', ParseIntPipe) id: number) {
26 | return this.categoriesService.findOne(id);
27 | }
28 |
29 | @Post()
30 | create(@Body() payload: CreateCategoryDto) {
31 | return this.categoriesService.create(payload);
32 | }
33 |
34 | @Put(':id')
35 | update(
36 | @Param('id', ParseIntPipe) id: number,
37 | @Body() payload: UpdateCategoryDto,
38 | ) {
39 | return this.categoriesService.update(id, payload);
40 | }
41 |
42 | @Delete(':id')
43 | remove(@Param('id', ParseIntPipe) id: number) {
44 | return this.categoriesService.remove(+id);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/products/controllers/products.controller.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Controller,
3 | Get,
4 | Query,
5 | Param,
6 | Post,
7 | Body,
8 | Put,
9 | Delete,
10 | HttpStatus,
11 | HttpCode,
12 | Res,
13 | // ParseIntPipe,
14 | } from '@nestjs/common';
15 | import { Response } from 'express';
16 | import { ApiTags, ApiOperation } from '@nestjs/swagger';
17 |
18 | import { ParseIntPipe } from '../../common/parse-int.pipe';
19 | import { MongoIdPipe } from './../../common/mongo-id.pipe';
20 | import {
21 | CreateProductDto,
22 | UpdateProductDto,
23 | FilterProductsDto,
24 | } from '../dtos/products.dtos';
25 | import { ProductsService } from './../services/products.service';
26 |
27 | @ApiTags('products')
28 | @Controller('products')
29 | export class ProductsController {
30 | constructor(private productsService: ProductsService) {}
31 |
32 | @Get()
33 | @ApiOperation({ summary: 'List of products' })
34 | getProducts(@Query() params: FilterProductsDto) {
35 | return this.productsService.findAll(params);
36 | }
37 |
38 | @Get('filter')
39 | getProductFilter() {
40 | return `yo soy un filter`;
41 | }
42 |
43 | @Get(':productId')
44 | @HttpCode(HttpStatus.ACCEPTED)
45 | getOne(@Param('productId', MongoIdPipe) productId: string) {
46 | return this.productsService.findOne(productId);
47 | }
48 |
49 | @Post()
50 | create(@Body() payload: CreateProductDto) {
51 | return this.productsService.create(payload);
52 | }
53 |
54 | @Put(':id')
55 | update(@Param('id') id: string, @Body() payload: UpdateProductDto) {
56 | return this.productsService.update(id, payload);
57 | }
58 |
59 | @Delete(':id')
60 | delete(@Param('id') id: string) {
61 | return this.productsService.remove(id);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/products/dtos/brand.dtos.ts:
--------------------------------------------------------------------------------
1 | import { IsString, IsUrl, IsNotEmpty } from 'class-validator';
2 | import { PartialType } from '@nestjs/swagger';
3 |
4 | export class CreateBrandDto {
5 | @IsString()
6 | @IsNotEmpty()
7 | readonly name: string;
8 |
9 | @IsUrl()
10 | @IsNotEmpty()
11 | readonly image: string;
12 | }
13 |
14 | export class UpdateBrandDto extends PartialType(CreateBrandDto) {}
15 |
--------------------------------------------------------------------------------
/src/products/dtos/category.dtos.ts:
--------------------------------------------------------------------------------
1 | import { IsString, IsNotEmpty, IsUrl } from 'class-validator';
2 | import { PartialType } from '@nestjs/swagger';
3 |
4 | export class CreateCategoryDto {
5 | @IsString()
6 | @IsNotEmpty()
7 | readonly name: string;
8 |
9 | @IsUrl()
10 | @IsNotEmpty()
11 | readonly image: string;
12 | }
13 |
14 | export class UpdateCategoryDto extends PartialType(CreateCategoryDto) {}
15 |
--------------------------------------------------------------------------------
/src/products/dtos/products.dtos.ts:
--------------------------------------------------------------------------------
1 | import {
2 | IsString,
3 | IsNumber,
4 | IsUrl,
5 | IsNotEmpty,
6 | IsPositive,
7 | IsOptional,
8 | Min,
9 | ValidateIf,
10 | ValidateNested,
11 | IsMongoId,
12 | } from 'class-validator';
13 | import { ApiProperty, PartialType } from '@nestjs/swagger';
14 |
15 | import { CreateCategoryDto } from './category.dtos';
16 |
17 | export class CreateProductDto {
18 | @IsString()
19 | @IsNotEmpty()
20 | @ApiProperty({ description: `product's name` })
21 | readonly name: string;
22 |
23 | @IsString()
24 | @IsNotEmpty()
25 | @ApiProperty()
26 | readonly description: string;
27 |
28 | @IsNumber()
29 | @IsNotEmpty()
30 | @IsPositive()
31 | @ApiProperty()
32 | readonly price: number;
33 |
34 | @IsNumber()
35 | @IsNotEmpty()
36 | @ApiProperty()
37 | readonly stock: number;
38 |
39 | @IsUrl()
40 | @IsNotEmpty()
41 | @ApiProperty()
42 | readonly image: string;
43 |
44 | @IsNotEmpty()
45 | @ValidateNested()
46 | @ApiProperty()
47 | readonly category: CreateCategoryDto;
48 |
49 | @IsNotEmpty()
50 | @IsMongoId()
51 | readonly brand: string;
52 | }
53 |
54 | export class UpdateProductDto extends PartialType(CreateProductDto) {}
55 |
56 | export class FilterProductsDto {
57 | @IsOptional()
58 | @IsPositive()
59 | limit: number;
60 |
61 | @IsOptional()
62 | @Min(0)
63 | offset: number;
64 |
65 | @IsOptional()
66 | @Min(0)
67 | minPrice: number;
68 |
69 | @ValidateIf((params) => params.minPrice)
70 | @IsPositive()
71 | maxPrice: number;
72 | }
73 |
--------------------------------------------------------------------------------
/src/products/entities/brand.entity.ts:
--------------------------------------------------------------------------------
1 | import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
2 | import { Document } from 'mongoose';
3 |
4 | @Schema()
5 | export class Brand extends Document {
6 | @Prop({ required: true, unique: true })
7 | name: string;
8 |
9 | @Prop()
10 | image: string;
11 | }
12 |
13 | export const BrandSchema = SchemaFactory.createForClass(Brand);
14 |
--------------------------------------------------------------------------------
/src/products/entities/category.entity.ts:
--------------------------------------------------------------------------------
1 | export class Category {
2 | id: number;
3 | name: string;
4 | }
5 |
--------------------------------------------------------------------------------
/src/products/entities/product.entity.ts:
--------------------------------------------------------------------------------
1 | import { Prop, Schema, SchemaFactory, raw } from '@nestjs/mongoose';
2 | import { Document, Types } from 'mongoose';
3 |
4 | import { Brand } from './brand.entity';
5 |
6 | @Schema()
7 | export class Product extends Document {
8 | @Prop({ required: true })
9 | name: string;
10 |
11 | @Prop()
12 | description: string;
13 |
14 | @Prop({ type: Number, index: true })
15 | price: number;
16 |
17 | @Prop({ type: Number })
18 | stock: number;
19 |
20 | @Prop()
21 | image: string;
22 |
23 | @Prop(
24 | raw({
25 | name: { type: String },
26 | image: { type: String },
27 | }),
28 | )
29 | category: Record;
30 |
31 | @Prop({ type: Types.ObjectId, ref: Brand.name })
32 | brand: Brand | Types.ObjectId;
33 | }
34 |
35 | export const ProductSchema = SchemaFactory.createForClass(Product);
36 | ProductSchema.index({ price: 1, stock: -1 });
37 |
--------------------------------------------------------------------------------
/src/products/products.module.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { MongooseModule } from '@nestjs/mongoose';
3 |
4 | import { ProductsController } from './controllers/products.controller';
5 | import { BrandsController } from './controllers/brands.controller';
6 | import { Brand, BrandSchema } from './entities/brand.entity';
7 | import { CategoriesController } from './controllers/categories.controller';
8 | import { ProductsService } from './services/products.service';
9 | import { BrandsService } from './services/brands.service';
10 | import { CategoriesService } from './services/categories.service';
11 | import { Product, ProductSchema } from './entities/product.entity';
12 |
13 | @Module({
14 | imports: [
15 | MongooseModule.forFeature([
16 | {
17 | name: Product.name,
18 | schema: ProductSchema,
19 | },
20 | {
21 | name: Brand.name,
22 | schema: BrandSchema,
23 | },
24 | ]),
25 | ],
26 | controllers: [ProductsController, CategoriesController, BrandsController],
27 | providers: [ProductsService, BrandsService, CategoriesService],
28 | exports: [ProductsService],
29 | })
30 | export class ProductsModule {}
31 |
--------------------------------------------------------------------------------
/src/products/services/brands.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable, NotFoundException } from '@nestjs/common';
2 | import { Model } from 'mongoose';
3 | import { InjectModel } from '@nestjs/mongoose';
4 |
5 | import { Brand } from '../entities/brand.entity';
6 | import { CreateBrandDto, UpdateBrandDto } from '../dtos/brand.dtos';
7 |
8 | @Injectable()
9 | export class BrandsService {
10 | constructor(@InjectModel(Brand.name) private brandModel: Model) {}
11 |
12 | findAll() {
13 | return this.brandModel.find().exec();
14 | }
15 |
16 | async findOne(id: string) {
17 | const product = await this.brandModel.findOne({ _id: id }).exec();
18 | if (!product) {
19 | throw new NotFoundException(`Brand #${id} not found`);
20 | }
21 | return product;
22 | }
23 |
24 | create(data: CreateBrandDto) {
25 | const newBrand = new this.brandModel(data);
26 | return newBrand.save();
27 | }
28 |
29 | async update(id: string, changes: UpdateBrandDto) {
30 | const product = await this.brandModel
31 | .findByIdAndUpdate(id, { $set: changes }, { new: true })
32 | .exec();
33 | if (!product) {
34 | throw new NotFoundException(`Brand #${id} not found`);
35 | }
36 | return product;
37 | }
38 |
39 | remove(id: string) {
40 | return this.brandModel.findByIdAndDelete(id);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/products/services/categories.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable, NotFoundException } from '@nestjs/common';
2 |
3 | import { Category } from '../entities/category.entity';
4 | import { CreateCategoryDto, UpdateCategoryDto } from '../dtos/category.dtos';
5 |
6 | @Injectable()
7 | export class CategoriesService {
8 | private counterId = 1;
9 | private categories: Category[] = [
10 | {
11 | id: 1,
12 | name: 'Category 1',
13 | },
14 | ];
15 |
16 | findAll() {
17 | return this.categories;
18 | }
19 |
20 | findOne(id: number) {
21 | const category = this.categories.find((item) => item.id === id);
22 | if (!category) {
23 | throw new NotFoundException(`Category #${id} not found`);
24 | }
25 | return category;
26 | }
27 |
28 | create(data: CreateCategoryDto) {
29 | this.counterId = this.counterId + 1;
30 | const newCategory = {
31 | id: this.counterId,
32 | ...data,
33 | };
34 | this.categories.push(newCategory);
35 | return newCategory;
36 | }
37 |
38 | update(id: number, changes: UpdateCategoryDto) {
39 | const category = this.findOne(id);
40 | const index = this.categories.findIndex((item) => item.id === id);
41 | this.categories[index] = {
42 | ...category,
43 | ...changes,
44 | };
45 | return this.categories[index];
46 | }
47 |
48 | remove(id: number) {
49 | const index = this.categories.findIndex((item) => item.id === id);
50 | if (index === -1) {
51 | throw new NotFoundException(`Category #${id} not found`);
52 | }
53 | this.categories.splice(index, 1);
54 | return true;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/products/services/products.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable, NotFoundException } from '@nestjs/common';
2 | import { InjectModel } from '@nestjs/mongoose';
3 | import { Model, FilterQuery } from 'mongoose';
4 |
5 | import { Product } from './../entities/product.entity';
6 | import {
7 | CreateProductDto,
8 | UpdateProductDto,
9 | FilterProductsDto,
10 | } from './../dtos/products.dtos';
11 |
12 | @Injectable()
13 | export class ProductsService {
14 | constructor(
15 | @InjectModel(Product.name) private productModel: Model,
16 | ) {}
17 |
18 | findAll(params?: FilterProductsDto) {
19 | if (params) {
20 | const filters: FilterQuery = {};
21 | const { limit, offset } = params;
22 | const { minPrice, maxPrice } = params;
23 | if (minPrice && maxPrice) {
24 | filters.price = { $gte: minPrice, $lte: maxPrice };
25 | }
26 | return this.productModel
27 | .find(filters)
28 | .populate('brand')
29 | .skip(offset)
30 | .limit(limit)
31 | .exec();
32 | }
33 | return this.productModel.find().populate('brand').exec();
34 | }
35 |
36 | async findOne(id: string) {
37 | const product = await this.productModel.findById(id).exec();
38 | if (!product) {
39 | throw new NotFoundException(`Product #${id} not found`);
40 | }
41 | return product;
42 | }
43 |
44 | create(data: CreateProductDto) {
45 | const newProduct = new this.productModel(data);
46 | return newProduct.save();
47 | }
48 |
49 | update(id: string, changes: UpdateProductDto) {
50 | const product = this.productModel
51 | .findByIdAndUpdate(id, { $set: changes }, { new: true })
52 | .exec();
53 | if (!product) {
54 | throw new NotFoundException(`Product #${id} not found`);
55 | }
56 | return product;
57 | }
58 |
59 | remove(id: string) {
60 | return this.productModel.findByIdAndDelete(id);
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/recap.ts:
--------------------------------------------------------------------------------
1 | const myName = 'Nicolas';
2 | const myAge = 12;
3 | const suma = (a: number, b: number) => {
4 | return a + b;
5 | };
6 | suma(12, 23);
7 |
8 | class Persona {
9 | constructor(private age: number, private name: string) {}
10 |
11 | getSummary() {
12 | return `my name is ${this.name}, ${this.age}`;
13 | }
14 | }
15 |
16 | const nicolas = new Persona(15, 'nicolas');
17 | nicolas.getSummary();
18 |
--------------------------------------------------------------------------------
/src/users/controllers/customers.controller.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Controller,
3 | Get,
4 | Param,
5 | Post,
6 | Body,
7 | Put,
8 | Delete,
9 | } from '@nestjs/common';
10 |
11 | import { CustomersService } from '../services/customers.service';
12 | import { CreateCustomerDto, UpdateCustomerDto } from '../dtos/customer.dto';
13 |
14 | @Controller('customers')
15 | export class CustomerController {
16 | constructor(private customersService: CustomersService) {}
17 |
18 | @Get()
19 | findAll() {
20 | return this.customersService.findAll();
21 | }
22 |
23 | @Get(':id')
24 | get(@Param('id') id: string) {
25 | return this.customersService.findOne(id);
26 | }
27 |
28 | @Post()
29 | create(@Body() payload: CreateCustomerDto) {
30 | return this.customersService.create(payload);
31 | }
32 |
33 | @Put(':id')
34 | update(@Param('id') id: string, @Body() payload: UpdateCustomerDto) {
35 | return this.customersService.update(id, payload);
36 | }
37 |
38 | @Delete(':id')
39 | remove(@Param('id') id: string) {
40 | return this.customersService.remove(id);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/users/controllers/orders.controller.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Controller,
3 | Get,
4 | Param,
5 | Post,
6 | Body,
7 | Put,
8 | Delete,
9 | } from '@nestjs/common';
10 | import { ApiTags } from '@nestjs/swagger';
11 |
12 | import { OrdersService } from '../services/orders.service';
13 | import {
14 | CreateOrderDto,
15 | UpdateOrderDto,
16 | AddProductsToOrderDto,
17 | } from '../dtos/order.dto';
18 |
19 | @ApiTags('orders')
20 | @Controller('orders')
21 | export class OrdersController {
22 | constructor(private ordersService: OrdersService) {}
23 |
24 | @Get()
25 | findAll() {
26 | return this.ordersService.findAll();
27 | }
28 |
29 | @Get(':id')
30 | get(@Param('id') id: string) {
31 | return this.ordersService.findOne(id);
32 | }
33 |
34 | @Post()
35 | create(@Body() payload: CreateOrderDto) {
36 | return this.ordersService.create(payload);
37 | }
38 |
39 | @Put(':id')
40 | update(@Param('id') id: string, @Body() payload: UpdateOrderDto) {
41 | return this.ordersService.update(id, payload);
42 | }
43 |
44 | @Put(':id/products')
45 | updateProducts(
46 | @Param('id') id: string,
47 | @Body() payload: AddProductsToOrderDto,
48 | ) {
49 | return this.ordersService.addProducts(id, payload.productsIds);
50 | }
51 |
52 | @Delete(':id')
53 | remove(@Param('id') id: string) {
54 | return this.ordersService.remove(id);
55 | }
56 |
57 | @Delete(':id/product/:productId')
58 | removeProduct(
59 | @Param('id') id: string,
60 | @Param('productId') productId: string,
61 | ) {
62 | return this.ordersService.removeProduct(id, productId);
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/users/controllers/users.controller.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Controller,
3 | Get,
4 | Param,
5 | Post,
6 | Body,
7 | Put,
8 | Delete,
9 | } from '@nestjs/common';
10 | import { ApiOperation, ApiTags } from '@nestjs/swagger';
11 |
12 | import { UsersService } from '../services/users.service';
13 | import { CreateUserDto, UpdateUserDto } from '../dtos/user.dto';
14 |
15 | @ApiTags('users')
16 | @Controller('users')
17 | export class UsersController {
18 | constructor(private usersService: UsersService) {}
19 |
20 | @Get()
21 | @ApiOperation({
22 | summary: 'List of users',
23 | })
24 | findAll() {
25 | return this.usersService.findAll();
26 | }
27 |
28 | @Get('tasks')
29 | tasks() {
30 | return this.usersService.getTasks();
31 | }
32 |
33 | @Get(':id')
34 | get(@Param('id') id: string) {
35 | return this.usersService.findOne(id);
36 | }
37 |
38 | @Get(':id/orders')
39 | getOrders(@Param('id') id: string) {
40 | return this.usersService.getOrdersByUser(id);
41 | }
42 |
43 | @Post()
44 | create(@Body() payload: CreateUserDto) {
45 | return this.usersService.create(payload);
46 | }
47 |
48 | @Put(':id')
49 | update(@Param('id') id: string, @Body() payload: UpdateUserDto) {
50 | return this.usersService.update(id, payload);
51 | }
52 |
53 | @Delete(':id')
54 | remove(@Param('id') id: string) {
55 | return this.usersService.remove(id);
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/users/dtos/customer.dto.ts:
--------------------------------------------------------------------------------
1 | import {
2 | IsString,
3 | IsNotEmpty,
4 | IsPhoneNumber,
5 | IsArray,
6 | ValidateNested,
7 | } from 'class-validator';
8 | import { PartialType } from '@nestjs/swagger';
9 |
10 | export class CreateCustomerDto {
11 | @IsString()
12 | @IsNotEmpty()
13 | readonly name: string;
14 |
15 | @IsString()
16 | @IsNotEmpty()
17 | readonly lastName: string;
18 |
19 | @IsPhoneNumber()
20 | @IsNotEmpty()
21 | readonly phone: string;
22 |
23 | @IsArray()
24 | @IsNotEmpty()
25 | readonly skills: any;
26 | }
27 |
28 | export class UpdateCustomerDto extends PartialType(CreateCustomerDto) {}
29 |
--------------------------------------------------------------------------------
/src/users/dtos/order.dto.ts:
--------------------------------------------------------------------------------
1 | import { IsMongoId, IsNotEmpty, IsDate, IsArray } from 'class-validator';
2 | import { OmitType, PartialType } from '@nestjs/swagger';
3 |
4 | export class CreateOrderDto {
5 | @IsNotEmpty()
6 | @IsMongoId()
7 | readonly customer: string;
8 |
9 | @IsDate()
10 | @IsNotEmpty()
11 | readonly date: Date;
12 |
13 | @IsArray()
14 | @IsNotEmpty()
15 | readonly products: string[];
16 | }
17 |
18 | export class UpdateOrderDto extends PartialType(
19 | OmitType(CreateOrderDto, ['products']),
20 | ) {}
21 |
22 | export class AddProductsToOrderDto {
23 | @IsArray()
24 | @IsNotEmpty()
25 | readonly productsIds: string[];
26 | }
27 |
--------------------------------------------------------------------------------
/src/users/dtos/user.dto.ts:
--------------------------------------------------------------------------------
1 | import { IsString, IsNotEmpty, IsEmail, Length } from 'class-validator';
2 | import { PartialType, ApiProperty } from '@nestjs/swagger';
3 |
4 | export class CreateUserDto {
5 | @IsString()
6 | @IsEmail()
7 | @ApiProperty({ description: "the user' email" })
8 | readonly email: string;
9 |
10 | @IsString()
11 | @IsNotEmpty()
12 | @Length(6)
13 | @ApiProperty({ description: "the user' password", deprecated: true })
14 | readonly password: string;
15 |
16 | @IsNotEmpty()
17 | readonly role: string;
18 | }
19 |
20 | export class UpdateUserDto extends PartialType(CreateUserDto) {}
21 |
--------------------------------------------------------------------------------
/src/users/entities/customer.entity.ts:
--------------------------------------------------------------------------------
1 | import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
2 | import { Document, Types } from 'mongoose';
3 |
4 | @Schema()
5 | export class Customer extends Document {
6 | @Prop({ required: true })
7 | name: string;
8 |
9 | @Prop({ required: true })
10 | lastName: string;
11 |
12 | @Prop()
13 | phone: string;
14 |
15 | @Prop({
16 | type: [{ name: { type: String }, color: { type: String } }],
17 | })
18 | skills: Types.Array>;
19 | }
20 |
21 | export const CustomerSchema = SchemaFactory.createForClass(Customer);
22 |
--------------------------------------------------------------------------------
/src/users/entities/order.entity.ts:
--------------------------------------------------------------------------------
1 | import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
2 | import { Document, Types } from 'mongoose';
3 |
4 | import { Customer } from './customer.entity';
5 | import { Product } from '../../products/entities/product.entity';
6 |
7 | @Schema()
8 | export class Order extends Document {
9 | @Prop({ type: Date })
10 | date: Date;
11 |
12 | @Prop({ type: Types.ObjectId, ref: Customer.name, required: true })
13 | customer: Customer | Types.ObjectId;
14 |
15 | @Prop({ type: [{ type: Types.ObjectId, ref: Product.name }] })
16 | products: Types.Array;
17 | }
18 |
19 | export const OrderSchema = SchemaFactory.createForClass(Order);
20 |
--------------------------------------------------------------------------------
/src/users/entities/user.entity.ts:
--------------------------------------------------------------------------------
1 | import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
2 | import { Document } from 'mongoose';
3 |
4 | @Schema()
5 | export class User extends Document {
6 | @Prop({ required: true, unique: true })
7 | email: string;
8 |
9 | @Prop({ required: true })
10 | password: string;
11 |
12 | @Prop({ required: true })
13 | role: string;
14 | }
15 |
16 | export const UserSchema = SchemaFactory.createForClass(User);
17 |
--------------------------------------------------------------------------------
/src/users/services/customers.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@nestjs/common';
2 | import { Model } from 'mongoose';
3 | import { InjectModel } from '@nestjs/mongoose';
4 |
5 | import { Customer } from '../entities/customer.entity';
6 | import { CreateCustomerDto, UpdateCustomerDto } from '../dtos/customer.dto';
7 |
8 | @Injectable()
9 | export class CustomersService {
10 | constructor(
11 | @InjectModel(Customer.name) private customerModel: Model,
12 | ) {}
13 |
14 | findAll() {
15 | return this.customerModel.find().exec();
16 | }
17 |
18 | async findOne(id: string) {
19 | return this.customerModel.findById(id);
20 | }
21 |
22 | create(data: CreateCustomerDto) {
23 | console.log(data);
24 | const newModel = new this.customerModel(data);
25 | return newModel.save();
26 | }
27 |
28 | update(id: string, changes: UpdateCustomerDto) {
29 | return this.customerModel
30 | .findByIdAndUpdate(id, { $set: changes }, { new: true })
31 | .exec();
32 | }
33 |
34 | remove(id: string) {
35 | return this.customerModel.findByIdAndDelete(id);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/users/services/orders.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@nestjs/common';
2 | import { Model } from 'mongoose';
3 | import { InjectModel } from '@nestjs/mongoose';
4 |
5 | import { Order } from '../entities/order.entity';
6 | import { CreateOrderDto, UpdateOrderDto } from '../dtos/order.dto';
7 |
8 | @Injectable()
9 | export class OrdersService {
10 | constructor(@InjectModel(Order.name) private orderModel: Model) {}
11 |
12 | findAll() {
13 | return this.orderModel
14 | .find()
15 | .populate('customer')
16 | .populate('products')
17 | .exec();
18 | }
19 |
20 | async findOne(id: string) {
21 | return this.orderModel.findById(id);
22 | }
23 |
24 | create(data: CreateOrderDto) {
25 | const newModel = new this.orderModel(data);
26 | return newModel.save();
27 | }
28 |
29 | update(id: string, changes: UpdateOrderDto) {
30 | return this.orderModel
31 | .findByIdAndUpdate(id, { $set: changes }, { new: true })
32 | .exec();
33 | }
34 |
35 | remove(id: string) {
36 | return this.orderModel.findByIdAndDelete(id);
37 | }
38 |
39 | async removeProduct(id: string, productId: string) {
40 | const order = await this.orderModel.findById(id);
41 | order.products.pull(productId);
42 | return order.save();
43 | }
44 |
45 | async addProducts(id: string, productsIds: string[]) {
46 | const order = await this.orderModel.findById(id);
47 | productsIds.forEach((pId) => order.products.push(pId));
48 | return order.save();
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/users/services/users.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable, Inject } from '@nestjs/common';
2 | import { Db } from 'mongodb';
3 | import { Model } from 'mongoose';
4 | import { InjectModel } from '@nestjs/mongoose';
5 |
6 | import { User } from '../entities/user.entity';
7 | import { CreateUserDto, UpdateUserDto } from '../dtos/user.dto';
8 | import { ProductsService } from '../../products/services/products.service';
9 |
10 | @Injectable()
11 | export class UsersService {
12 | constructor(
13 | private productsService: ProductsService,
14 | @Inject('MONGO') private databaseMongo: Db,
15 | @InjectModel(User.name) private userModel: Model,
16 | ) {}
17 |
18 | findAll() {
19 | return this.userModel.find().exec();
20 | }
21 |
22 | getTasks() {
23 | const tasksCollection = this.databaseMongo.collection('tasks');
24 | return tasksCollection.find().toArray();
25 | }
26 |
27 | async findOne(id: string) {
28 | return this.userModel.findById(id);
29 | }
30 |
31 | async getOrdersByUser(userId: string) {
32 | const user = await this.findOne(userId);
33 | return {
34 | date: new Date(),
35 | user,
36 | // products: this.productsService.findAll(),
37 | products: [],
38 | };
39 | }
40 |
41 | create(data: CreateUserDto) {
42 | const newModel = new this.userModel(data);
43 | return newModel.save();
44 | }
45 |
46 | update(id: string, changes: UpdateUserDto) {
47 | return this.userModel
48 | .findByIdAndUpdate(id, { $set: changes }, { new: true })
49 | .exec();
50 | }
51 |
52 | remove(id: string) {
53 | return this.userModel.findByIdAndDelete(id);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/users/users.module.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { MongooseModule } from '@nestjs/mongoose';
3 |
4 | import { CustomerController } from './controllers/customers.controller';
5 | import { CustomersService } from './services/customers.service';
6 | import { Customer, CustomerSchema } from './entities/customer.entity';
7 | import { UsersController } from './controllers/users.controller';
8 | import { UsersService } from './services/users.service';
9 | import { User, UserSchema } from './entities/user.entity';
10 | import { OrdersController } from './controllers/orders.controller';
11 | import { OrdersService } from './services/orders.service';
12 | import { Order, OrderSchema } from './entities/order.entity';
13 |
14 | import { ProductsModule } from './../products/products.module';
15 |
16 | @Module({
17 | imports: [
18 | ProductsModule,
19 | MongooseModule.forFeature([
20 | {
21 | name: Customer.name,
22 | schema: CustomerSchema,
23 | },
24 | {
25 | name: User.name,
26 | schema: UserSchema,
27 | },
28 | {
29 | name: Order.name,
30 | schema: OrderSchema,
31 | },
32 | ]),
33 | ],
34 | controllers: [CustomerController, UsersController, OrdersController],
35 | providers: [CustomersService, UsersService, OrdersService],
36 | })
37 | export class UsersModule {}
38 |
--------------------------------------------------------------------------------
/test/app.e2e-spec.ts:
--------------------------------------------------------------------------------
1 | import { Test, TestingModule } from '@nestjs/testing';
2 | import { INestApplication } from '@nestjs/common';
3 | import * as request from 'supertest';
4 | import { AppModule } from './../src/app.module';
5 |
6 | describe('AppController (e2e)', () => {
7 | let app: INestApplication;
8 |
9 | beforeEach(async () => {
10 | const moduleFixture: TestingModule = await Test.createTestingModule({
11 | imports: [AppModule],
12 | }).compile();
13 |
14 | app = moduleFixture.createNestApplication();
15 | await app.init();
16 | });
17 |
18 | it('/ (GET)', () => {
19 | return request(app.getHttpServer())
20 | .get('/')
21 | .expect(200)
22 | .expect('Hello World!');
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/test/jest-e2e.json:
--------------------------------------------------------------------------------
1 | {
2 | "moduleFileExtensions": ["js", "json", "ts"],
3 | "rootDir": ".",
4 | "testEnvironment": "node",
5 | "testRegex": ".e2e-spec.ts$",
6 | "transform": {
7 | "^.+\\.(t|j)s$": "ts-jest"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "declaration": true,
5 | "removeComments": true,
6 | "emitDecoratorMetadata": true,
7 | "experimentalDecorators": true,
8 | "allowSyntheticDefaultImports": true,
9 | "target": "es2017",
10 | "sourceMap": true,
11 | "outDir": "./dist",
12 | "baseUrl": "./",
13 | "incremental": true
14 | }
15 | }
16 |
--------------------------------------------------------------------------------