diff --git a/package-lock.json b/package-lock.json index c1436b3..3135512 100644 --- a/package-lock.json +++ b/package-lock.json @@ -55,6 +55,11 @@ "uuid": "3.3.2" } }, + "@nestjs/mongoose": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@nestjs/mongoose/-/mongoose-6.1.2.tgz", + "integrity": "sha512-BkbkguvaPPGbL/41lK6P22DaQodBC9Yv9rUAmNlQVShChtwss7/cGj68AKC3jEoidrx75wCyDO3P8Tp6pggE4w==" + }, "@nestjs/platform-express": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-6.3.1.tgz", @@ -95,6 +100,15 @@ "@types/node": "*" } }, + "@types/bson": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.0.tgz", + "integrity": "sha512-pq/rqJwJWkbS10crsG5bgnrisL8pML79KlMKQMoQwLUjlPAkrUHMvHJ3oGwE7WHR61Lv/nadMwXVAD2b+fpD8Q==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/connect": { "version": "3.4.32", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.32.tgz", @@ -149,6 +163,26 @@ "integrity": "sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw==", "dev": true }, + "@types/mongodb": { + "version": "3.1.28", + "resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.1.28.tgz", + "integrity": "sha512-tG+QqJ/hir2p0069ee28t2O9tlGRJKDq1WFZC2QYMlU47LGdldLL8tepfTq6aFLvP58OpwSoxaJ/qjW93ob1NQ==", + "dev": true, + "requires": { + "@types/bson": "*", + "@types/node": "*" + } + }, + "@types/mongoose": { + "version": "5.5.6", + "resolved": "https://registry.npmjs.org/@types/mongoose/-/mongoose-5.5.6.tgz", + "integrity": "sha512-Duco8iiwOEGB756eIyafsrFbsAxjXQPkb/nplZtbxGOhfmsA90rXjO/GbDsBYbUz5nkGOCRHuNfxOJzoVAMHMg==", + "dev": true, + "requires": { + "@types/mongodb": "*", + "@types/node": "*" + } + }, "@types/node": { "version": "10.14.9", "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.9.tgz", @@ -686,7 +720,6 @@ "version": "2.6.2", "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", - "dev": true, "requires": { "lodash": "^4.17.11" } @@ -1116,6 +1149,11 @@ "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", "dev": true }, + "bluebird": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", + "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" + }, "body-parser": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", @@ -1227,6 +1265,11 @@ "node-int64": "^0.4.0" } }, + "bson": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.1.tgz", + "integrity": "sha512-jCGVYLoYMHDkOsbwJZBCqwMHyH4c+wzgI9hG7Z6SZJRXWr+x58pdIbm2i9a/jFGCkRJqRUr8eoI7lDWa0hTkxg==" + }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", @@ -4646,6 +4689,11 @@ "verror": "1.10.0" } }, + "kareem": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.0.tgz", + "integrity": "sha512-6hHxsp9e6zQU8nXsP+02HGWXwTkOEw6IROhF2ZA28cYbUk4eJ6QbtZvdqZOdD9YPKghG3apk5eOCvs+tLl3lRg==" + }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -4752,8 +4800,7 @@ "lodash": { "version": "4.17.11", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", - "dev": true + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" }, "lodash.sortby": { "version": "4.7.0", @@ -4879,6 +4926,12 @@ "timers-ext": "^0.1.5" } }, + "memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "optional": true + }, "merge": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz", @@ -5023,6 +5076,75 @@ "minimist": "0.0.8" } }, + "mongodb": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.2.7.tgz", + "integrity": "sha512-2YdWrdf1PJgxcCrT1tWoL6nHuk6hCxhddAAaEh8QJL231ci4+P9FLyqopbTm2Z2sAU6mhCri+wd9r1hOcHdoMw==", + "requires": { + "mongodb-core": "3.2.7", + "safe-buffer": "^5.1.2" + } + }, + "mongodb-core": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-3.2.7.tgz", + "integrity": "sha512-WypKdLxFNPOH/Jy6i9z47IjG2wIldA54iDZBmHMINcgKOUcWJh8og+Wix76oGd7EyYkHJKssQ2FAOw5Su/n4XQ==", + "requires": { + "bson": "^1.1.1", + "require_optional": "^1.0.1", + "safe-buffer": "^5.1.2", + "saslprep": "^1.0.0" + } + }, + "mongoose": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.6.1.tgz", + "integrity": "sha512-/EBoXS+fZv8dYf0VKMXwhTEVYUI+6EbmVhmV2DzO9BGacTSgStQprU09rZYfVxe8EmLhmTrSV5eCIRLBYuXGag==", + "requires": { + "async": "2.6.2", + "bson": "~1.1.1", + "kareem": "2.3.0", + "mongodb": "3.2.7", + "mongodb-core": "3.2.7", + "mongoose-legacy-pluralize": "1.0.2", + "mpath": "0.6.0", + "mquery": "3.2.1", + "ms": "2.1.2", + "regexp-clone": "1.0.0", + "safe-buffer": "5.1.2", + "sift": "7.0.1", + "sliced": "1.0.1" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "mongoose-legacy-pluralize": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz", + "integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ==" + }, + "mpath": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.6.0.tgz", + "integrity": "sha512-i75qh79MJ5Xo/sbhxrDrPSEG0H/mr1kcZXJ8dH6URU5jD/knFxCVqVC/gVSW7GIXL/9hHWlT9haLbCXWOll3qw==" + }, + "mquery": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.1.tgz", + "integrity": "sha512-kY/K8QToZWTTocm0U+r8rqcJCp5PRl6e8tPmoDs5OeSO3DInZE2rAL6AYH+V406JTo8305LdASOQcxRDqHojyw==", + "requires": { + "bluebird": "3.5.1", + "debug": "3.1.0", + "regexp-clone": "^1.0.0", + "safe-buffer": "5.1.2", + "sliced": "1.0.1" + } + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -6236,6 +6358,11 @@ "safe-regex": "^1.1.0" } }, + "regexp-clone": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz", + "integrity": "sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw==" + }, "registry-auth-token": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz", @@ -6366,6 +6493,22 @@ "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", "dev": true }, + "require_optional": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", + "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==", + "requires": { + "resolve-from": "^2.0.0", + "semver": "^5.1.0" + }, + "dependencies": { + "resolve-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", + "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=" + } + } + }, "resolve": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.0.tgz", @@ -6763,6 +6906,15 @@ } } }, + "saslprep": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", + "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", + "optional": true, + "requires": { + "sparse-bitfield": "^3.0.3" + } + }, "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", @@ -6772,8 +6924,7 @@ "semver": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", - "dev": true + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" }, "semver-diff": { "version": "2.1.0", @@ -6892,6 +7043,11 @@ "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", "dev": true }, + "sift": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/sift/-/sift-7.0.1.tgz", + "integrity": "sha512-oqD7PMJ+uO6jV9EQCl0LrRw1OwsiPsiFQR5AR30heR+4Dl7jBBbDLnNvWiak20tzZlSE1H7RB30SX/1j/YYT7g==" + }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", @@ -6910,6 +7066,11 @@ "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", "dev": true }, + "sliced": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", + "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" + }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -7061,6 +7222,15 @@ "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", "dev": true }, + "sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", + "optional": true, + "requires": { + "memory-pager": "^1.0.2" + } + }, "spawn-command": { "version": "0.0.2-1", "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", diff --git a/package.json b/package.json index ba857b6..9f62635 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,9 @@ "dependencies": { "@nestjs/common": "^6.0.0", "@nestjs/core": "^6.0.0", + "@nestjs/mongoose": "^6.1.2", "@nestjs/platform-express": "^6.0.0", + "mongoose": "^5.6.1", "reflect-metadata": "^0.1.12", "rimraf": "^2.6.2", "rxjs": "^6.3.3" @@ -31,6 +33,7 @@ "@nestjs/testing": "^6.0.0", "@types/express": "^4.16.0", "@types/jest": "^23.3.13", + "@types/mongoose": "^5.5.6", "@types/node": "^10.12.18", "@types/supertest": "^2.0.7", "concurrently": "^4.1.0", diff --git a/src/app.module.ts b/src/app.module.ts index 77f65b8..e0c038c 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,11 +1,17 @@ import { Module } from '@nestjs/common'; +import { MongooseModule } from '@nestjs/mongoose'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { ProductsModule } from './products/products.module'; @Module({ - imports: [ProductsModule], + imports: [ + ProductsModule, + MongooseModule.forRoot( + 'mongodb+srv://maximilian:B3dqPzooRLzFiVYm@cluster0-ntrwp.mongodb.net/nestjs-demo?retryWrites=true&w=majority', + ), + ], controllers: [AppController], providers: [AppService], }) diff --git a/src/products/product.model.ts b/src/products/product.model.ts index cef15a2..bbdce97 100644 --- a/src/products/product.model.ts +++ b/src/products/product.model.ts @@ -1,8 +1,14 @@ -export class Product { - constructor( - public id: string, - public title: string, - public description: string, - public price: number, - ) {} +import * as mongoose from 'mongoose'; + +export const ProductSchema = new mongoose.Schema({ + title: { type: String, required: true }, + description: { type: String, required: true }, + price: { type: Number, required: true }, +}); + +export interface Product extends mongoose.Document { + id: string; + title: string; + description: string; + price: number; } diff --git a/src/products/products.controller.ts b/src/products/products.controller.ts index 33ed525..0eabb4e 100644 --- a/src/products/products.controller.ts +++ b/src/products/products.controller.ts @@ -15,12 +15,12 @@ export class ProductsController { constructor(private readonly productsService: ProductsService) {} @Post() - addProduct( + async addProduct( @Body('title') prodTitle: string, @Body('description') prodDesc: string, @Body('price') prodPrice: number, ) { - const generatedId = this.productsService.insertProduct( + const generatedId = await this.productsService.insertProduct( prodTitle, prodDesc, prodPrice, @@ -29,8 +29,9 @@ export class ProductsController { } @Get() - getAllProducts() { - return this.productsService.getProducts(); + async getAllProducts() { + const products = await this.productsService.getProducts(); + return products; } @Get(':id') @@ -39,19 +40,19 @@ export class ProductsController { } @Patch(':id') - updateProduct( + async updateProduct( @Param('id') prodId: string, @Body('title') prodTitle: string, @Body('description') prodDesc: string, @Body('price') prodPrice: number, ) { - this.productsService.updateProduct(prodId, prodTitle, prodDesc, prodPrice); + await this.productsService.updateProduct(prodId, prodTitle, prodDesc, prodPrice); return null; } @Delete(':id') - removeProduct(@Param('id') prodId: string) { - this.productsService.deleteProduct(prodId); + async removeProduct(@Param('id') prodId: string) { + await this.productsService.deleteProduct(prodId); return null; } } diff --git a/src/products/products.module.ts b/src/products/products.module.ts index 1759868..69aec6f 100644 --- a/src/products/products.module.ts +++ b/src/products/products.module.ts @@ -1,10 +1,15 @@ import { Module } from '@nestjs/common'; +import { MongooseModule } from '@nestjs/mongoose'; import { ProductsController } from './products.controller'; import { ProductsService } from './products.service'; +import { ProductSchema } from './product.model'; @Module({ - controllers: [ProductsController], - providers: [ProductsService], + imports: [ + MongooseModule.forFeature([{ name: 'Product', schema: ProductSchema }]), + ], + controllers: [ProductsController], + providers: [ProductsService], }) export class ProductsModule {} diff --git a/src/products/products.service.ts b/src/products/products.service.ts index 5f7a375..ed9da8d 100644 --- a/src/products/products.service.ts +++ b/src/products/products.service.ts @@ -1,30 +1,52 @@ import { Injectable, NotFoundException } from '@nestjs/common'; +import { InjectModel } from '@nestjs/mongoose'; +import { Model } from 'mongoose'; import { Product } from './product.model'; @Injectable() export class ProductsService { - private products: Product[] = []; + constructor( + @InjectModel('Product') private readonly productModel: Model, + ) {} - insertProduct(title: string, desc: string, price: number) { - const prodId = Math.random().toString(); - const newProduct = new Product(prodId, title, desc, price); - this.products.push(newProduct); - return prodId; + async insertProduct(title: string, desc: string, price: number) { + const newProduct = new this.productModel({ + title, + description: desc, + price, + }); + const result = await newProduct.save(); + return result.id as string; } - getProducts() { - return [...this.products]; + async getProducts() { + const products = await this.productModel.find().exec(); + return products.map(prod => ({ + id: prod.id, + title: prod.title, + description: prod.description, + price: prod.price, + })); } - getSingleProduct(productId: string) { - const product = this.findProduct(productId)[0]; - return { ...product }; + async getSingleProduct(productId: string) { + const product = await this.findProduct(productId); + return { + id: product.id, + title: product.title, + description: product.description, + price: product.price, + }; } - updateProduct(productId: string, title: string, desc: string, price: number) { - const [product, index] = this.findProduct(productId); - const updatedProduct = { ...product }; + async updateProduct( + productId: string, + title: string, + desc: string, + price: number, + ) { + const updatedProduct = await this.findProduct(productId); if (title) { updatedProduct.title = title; } @@ -34,20 +56,26 @@ export class ProductsService { if (price) { updatedProduct.price = price; } - this.products[index] = updatedProduct; + updatedProduct.save(); } - deleteProduct(prodId: string) { - const index = this.findProduct(prodId)[1]; - this.products.splice(index, 1); + async deleteProduct(prodId: string) { + const result = await this.productModel.deleteOne({_id: prodId}).exec(); + if (result.n === 0) { + throw new NotFoundException('Could not find product.'); + } } - private findProduct(id: string): [Product, number] { - const productIndex = this.products.findIndex(prod => prod.id === id); - const product = this.products[productIndex]; + private async findProduct(id: string): Promise { + let product; + try { + product = await this.productModel.findById(id).exec(); + } catch (error) { + throw new NotFoundException('Could not find product.'); + } if (!product) { throw new NotFoundException('Could not find product.'); } - return [product, productIndex]; + return product; } }