├── .eslintrc.js ├── .github └── workflows │ ├── codeql-analysis.yml │ └── testing.yml ├── .gitignore ├── .prettierrc ├── README.md ├── README_FR.md ├── images └── banner.png ├── nest-cli.json ├── package-lock.json ├── package.json ├── renovate.json ├── src ├── app.controller.spec.ts ├── app.controller.ts ├── app.module.ts ├── app.service.ts ├── config │ └── configuration.ts ├── main.ts ├── migrations-utils │ ├── db.ts │ ├── template.ts │ └── ts-compiler.js └── migrations │ └── 1605213505980-test.ts ├── test ├── app.e2e-spec.ts └── jest-e2e.json ├── tsconfig.build.json └── tsconfig.json /.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 | 'prettier/@typescript-eslint', 11 | 'plugin:prettier/recommended', 12 | ], 13 | root: true, 14 | env: { 15 | node: true, 16 | jest: true, 17 | }, 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 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | name: "CodeQL" 7 | 8 | on: 9 | push: 10 | branches: [master] 11 | pull_request: 12 | # The branches below must be a subset of the branches above 13 | branches: [master] 14 | schedule: 15 | - cron: '0 16 * * 6' 16 | 17 | jobs: 18 | analyze: 19 | name: Analyze 20 | runs-on: ubuntu-latest 21 | 22 | strategy: 23 | fail-fast: false 24 | matrix: 25 | # Override automatic language detection by changing the below list 26 | # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] 27 | language: ['javascript'] 28 | # Learn more... 29 | # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection 30 | 31 | steps: 32 | - name: Checkout repository 33 | uses: actions/checkout@v2 34 | with: 35 | # We must fetch at least the immediate parents so that if this is 36 | # a pull request then we can checkout the head. 37 | fetch-depth: 2 38 | 39 | # If this run was triggered by a pull request event, then checkout 40 | # the head of the pull request instead of the merge commit. 41 | - run: git checkout HEAD^2 42 | if: ${{ github.event_name == 'pull_request' }} 43 | 44 | # Initializes the CodeQL tools for scanning. 45 | - name: Initialize CodeQL 46 | uses: github/codeql-action/init@v1 47 | with: 48 | languages: ${{ matrix.language }} 49 | # If you wish to specify custom queries, you can do so here or in a config file. 50 | # By default, queries listed here will override any specified in a config file. 51 | # Prefix the list here with "+" to use these queries and those in the config file. 52 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 53 | 54 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 55 | # If this step fails, then you should remove it and run the build manually (see below) 56 | - name: Autobuild 57 | uses: github/codeql-action/autobuild@v1 58 | 59 | # ℹ️ Command-line programs to run using the OS shell. 60 | # 📚 https://git.io/JvXDl 61 | 62 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 63 | # and modify them (or add more) to build your code if your project 64 | # uses a compiled language 65 | 66 | #- run: | 67 | # make bootstrap 68 | # make release 69 | 70 | - name: Perform CodeQL Analysis 71 | uses: github/codeql-action/analyze@v1 72 | -------------------------------------------------------------------------------- /.github/workflows/testing.yml: -------------------------------------------------------------------------------- 1 | name: Testing 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | branches: [master] 8 | 9 | jobs: 10 | 11 | build: 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | 17 | - name: install 18 | run: npm ci 19 | 20 | - name: test 21 | run: | 22 | npm test 23 | npm run test:e2e 24 | npm run test:cov 25 | services: 26 | mongodb: 27 | image: mongo:3.7.9 28 | ports: 29 | - 27017:27017 30 | -------------------------------------------------------------------------------- /.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 | # Migrations 37 | .migrate 38 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all" 4 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![banner](images/banner.png) 2 | 3 | # Building a mongodb migration system for NestJS with mongoose 4 | 5 | This tutorial is assuming: 6 | - You have a working NestJS project 7 | - You are using MongoDB and mongoose 8 | 9 | In the recent past, I had an urge to do a bit of refactoring on my discord game. 10 | Still a work in progress, but I couldn't stand anymore the fact that houses were named homes... 11 | I already can hear you, 'just change labels displayed no one care!'. 12 | 13 | ![FAUX](https://media.giphy.com/media/4ObtlO6BjidKE/giphy.gif) 14 | 15 | I do care about the consistency of naming in my codebases. If homes are houses then the next thing you know is: 16 | Canons will become wooden swords and wolves are dogs... 17 | 18 | I spent some time online looking for solutions and I finally built something I like. 19 | Let me present to you the result of my work. 20 | 21 | I chose to use the [`migrate`](https://www.npmjs.com/package/migrate) library since it is database agnostic, offers an easy up/down logic, and can store the migration status in any form. 22 | 23 | Enough speaking about me, let me guide you through this journey. 24 | 25 | ## Install [`migrate`](https://www.npmjs.com/package/migrate) 26 | 27 | Go on install the bad guy! 28 | ```bash 29 | npm i --save migrate 30 | ``` 31 | 32 | ## Create a folder to store your migrations! 33 | 34 | You will new two folders: 35 | ```bash 36 | mkdir src/migrations 37 | mkdir src/migrations-utils 38 | ``` 39 | 40 | The first one will store the update scripts and the seconds will store some utilities. 41 | Let's look into the seconds. 42 | 43 | ## Some little helpers 44 | 45 | In the introduction, I told you that migrate is database agnostic. 46 | Therefore you need to write a little mongodb connector: 47 | ```typescript 48 | import { MongoClient } from 'mongodb'; 49 | import { configs } from '../config/configuration'; 50 | 51 | const MONGO_URL = configs.mongoUrl; 52 | 53 | export const getDb = async () => { 54 | const client: any = await MongoClient.connect(MONGO_URL, { useUnifiedTopology: true }); 55 | return client.db(); 56 | }; 57 | ``` 58 | 59 | Nice! let's keep going. 60 | 61 | ![antilope break](https://media.giphy.com/media/Zd1BUb0qs6nwjeMUBu/giphy.gif) 62 | 63 | Migrate is a tool made in javascript. 64 | And we use typescript, the best thing to do is have a little template with the database already connected. 65 | ```typescript 66 | import { getDb } from '../migrations-utils/db'; 67 | 68 | export const up = async () => { 69 | const db = await getDb(); 70 | /* 71 | Code your update script here! 72 | */ 73 | }; 74 | 75 | export const down = async () => { 76 | const db = await getDb(); 77 | /* 78 | Code you downgrade script here! 79 | */ 80 | }; 81 | ``` 82 | 83 | I had some trouble with `ts-node/register` in migrate command line. 84 | This little helper solved my transpilation errors! 85 | Do the same! now! do it! 86 | ```js 87 | // eslint-disable-next-line @typescript-eslint/no-var-requires 88 | const tsNode = require('ts-node'); 89 | module.exports = tsNode.register; 90 | ``` 91 | 92 | ## Update `package.json` 93 | 94 | it's time for you to update the `package.json` of your project in order to have easy to use scripts for the future! 95 | 96 | ### A script to generate migration files 97 | 98 | Add this sweet line in the `package.json`, in the script section! 99 | ``` 100 | "migrate:create": "migrate create --template-file ./src/migrations-utils/template.ts --migrations-dir=\"./src/migrations\" --compiler=\"ts:./src/migrations-utils/ts-compiler.js\"", 101 | ``` 102 | 103 | `--template-file ./src/migrations-utils/template.ts` provide a template file, it's a necessary thing since we are in a typescript repo. 104 | It also provides you an easy way to bootstrap migration just the way you like it! 105 | 106 | `--migrations-dir=\"./src/migrations\"` Tell migrate where your migration scripts are stored. 107 | By default, it's at the project root. 108 | 109 | `--compiler=\"ts:./src/migrations-utils/ts-compiler.js\"` Explain to migrate how to handle typescript files. 110 | 111 | Now, you just need to run this command to create an empty typescript migration file in the correct folder! 112 | 113 | ``` 114 | npm run migrate:create -- 115 | ``` 116 | 117 | ### A script for upgrades and a script for downgrades 118 | 119 | AAAAAAnd two more lines in the `package.json`, again in the scripts section! 120 | ``` 121 | "migrate:up": "migrate --migrations-dir=\"./src/migrations\" --compiler=\"ts:./src/migrations-utils/ts-compiler.js\" up", 122 | "migrate:down": "migrate --migrations-dir=\"./src/migrations\" --compiler=\"ts:./src/migrations-utils/ts-compiler.js\" down" 123 | ``` 124 | 125 | No new options here, I already explained them but refreshing is nice. 126 | 127 | `--migrations-dir=\"./src/migrations\"` Tells migrate where to find your migrations! 128 | 129 | `--compiler=\"ts:./src/migrations-utils/ts-compiler.js\"` Tells migrate how to handle typescript... 130 | 131 | You can now run update script: `npm run migrate:up` or downgrade script `npm run migrate:down` 132 | 133 | ## What will happen when you run a migration? 134 | 135 | Migrate will store your migration state in a file at the project root. 136 | This file is called `migrate.json`. 137 | It looks like this: 138 | ```json 139 | { 140 | "lastRun": "1605197159478-test.ts", 141 | "migrations": [ 142 | { 143 | "title": "1605197159478-test.ts", 144 | "timestamp": 1605197181474 145 | } 146 | ] 147 | } 148 | ``` 149 | 150 | **DO NOT COMMIT `migrate.json`** 151 | 152 | 153 | ## Questions? 154 | 155 | ![questions](https://media.giphy.com/media/5XRB3Ay93FZw4/giphy.gif) 156 | 157 | I'll be glad to answers questions in the comments. 158 | 159 | If you liked my discord consider joining my coding lair! 160 | :phone:[Webeleon coding lair on discord](https://discord.gg/h7HzYzD82p) 161 | 162 | You can also email me and offer me a contract :moneybag: 163 | :envelope:[Email me!](julien@webeleon.dev) 164 | 165 | And since I'm a nice guy, here, take this sample repo containing a working codebase! 166 | :gift:[Get the code of the tuto from github](https://github.com/Webeleon/-Building-a-mongodb-migration-system-for-NestJS-with-mongoose.git) 167 | 168 | Buy Me A Coffee 169 | 170 | ## Documentation 171 | 172 | ![documentation](https://media.giphy.com/media/3o6ozkeXSb0Cm25CzS/giphy.gif) 173 | 174 | - [NestJS](https://nestjs.com/) 175 | - [Install mongoose with nest](https://docs.nestjs.com/techniques/mongodb) 176 | - [Migrate](https://github.com/tj/node-migrate#readme) 177 | 178 | 179 | -------------------------------------------------------------------------------- /README_FR.md: -------------------------------------------------------------------------------- 1 | ![banner](images/banner.png) 2 | 3 | # Coder un système de migration pour NestJS avec mongoos 4 | 5 | Prérequis: 6 | - Un projet NestJS fonctionel 7 | - Utiliser MongoDB et mongoose 8 | 9 | Récemment, j'ai ressenti le besoin pressant de refactorer mon jeu discord. 10 | C'est un projet en cours, loin d'être fini mais je ne supportais plus que les maisons soient appelées `homes` au lieu de `houses`. 11 | Oh j'en entends déjà me dire : 'Change les labels affichés, c'est pareil!'. 12 | 13 | ![FAUX](https://media.giphy.com/media/4ObtlO6BjidKE/giphy.gif) 14 | 15 | Je me soucis de la consistance du nommage dans mes projets! Si les maisons sont des appartements, "c'est la porte ouverte à toutes les fenêtres". 16 | 17 | Bref, j'enfile ma veste de chercheur et je me lance armé de mon meilleur google-fu. 18 | Aujourd'hui, je vous présente le résultat de mon travail. 19 | 20 | 21 | J'ai choisi d'utiliser la bibliothèque [`migrate`](https://www.npmjs.com/package/migrate). 22 | Un outil agnostique de tout type de base de données offrant une logique simple de script de migration et de retour en arrière. 23 | De plus, le statut des migrations peut être stocké sous n'importe quel support (en base, un fichier json, ???). 24 | 25 | Assez parlé de moi, laissez-moi vous guider. 26 | 27 | ## Installation [`migrate`](https://www.npmjs.com/package/migrate) 28 | 29 | Installons ce coquin! 30 | ```bash 31 | npm i --save migrate 32 | ``` 33 | 34 | ## Crée un dossier pour stocker les scripts de migrations! 35 | 36 | On aura besoin de deux dossiers: 37 | ```bash 38 | mkdir src/migrations 39 | mkdir src/migrations-utils 40 | ``` 41 | 42 | Le premier contiendra nos scripts de migration et le second sera notre boîte à outils. 43 | Commencons par le second! 44 | 45 | ## Quelques outils 46 | 47 | Dans l'intro, nous avons vu que l'outil `migrate` fait fi du type de nos bases de données. 48 | Nous avons donc besoin d'un script pour nous connecter à mongodb: 49 | ```typescript 50 | import { MongoClient } from 'mongodb'; 51 | import { configs } from '../config/configuration'; 52 | 53 | const MONGO_URL = configs.mongoUrl; 54 | 55 | export const getDb = async () => { 56 | const client: any = await MongoClient.connect(MONGO_URL, { useUnifiedTopology: true }); 57 | return client.db(); 58 | }; 59 | ``` 60 | 61 | Cool! Continuons! 62 | 63 | ![antilope break](https://media.giphy.com/media/Zd1BUb0qs6nwjeMUBu/giphy.gif) 64 | 65 | Migrate est un outil écrit en javascript. 66 | Et comme nous utilisons Typescript, la meilleur chose à faire est de créer un template déjà connecté à notre mongo. 67 | ```typescript 68 | import { getDb } from '../migrations-utils/db'; 69 | 70 | export const up = async () => { 71 | const db = await getDb(); 72 | /* 73 | La migration va ici. 74 | */ 75 | }; 76 | 77 | export const down = async () => { 78 | const db = await getDb(); 79 | /* 80 | Et ici, c'est pour le retour en arrière. 81 | */ 82 | }; 83 | ``` 84 | 85 | 86 | J'ai rencontré quelques soucis avec `ts-node/register` en utilisant `migrate` en ligne de commande... 87 | Ce petit script m'a sauvé la mise! 88 | Vas-y! Maintenant! Ajoute-le! 89 | ```js 90 | // eslint-disable-next-line @typescript-eslint/no-var-requires 91 | const tsNode = require('ts-node'); 92 | module.exports = tsNode.register; 93 | ``` 94 | 95 | ## Mise à jour du `package.json` 96 | 97 | Il est temps de mettre à jour le `package.json` de notre projet afin d'avoir une jolie collection de script facile à utiliser! 98 | 99 | ### Un script pour générer les fichiers de migration 100 | 101 | Ajoutons cette ligne dans la section script du fichier `package.json` 102 | ``` 103 | "migrate:create": "migrate create --template-file ./src/migrations-utils/template.ts --migrations-dir=\"./src/migrations\" --compiler=\"ts:./src/migrations-utils/ts-compiler.js\"", 104 | ``` 105 | 106 | `--template-file ./src/migrations-utils/template.ts` fourni le template, simple et efficace pour notre projet en typescript. 107 | Le template est une façon rapide de créer la base de nos script de migration! 108 | 109 | `--migrations-dir=\"./src/migrations\"` Explique à `migrate` où sont sensés être les scripts de migration. 110 | Par défaut, c'est à la racine du projet... 111 | 112 | `--compiler=\"ts:./src/migrations-utils/ts-compiler.js\"` Explique à `migrate` comment gérer les fichiers typescript. 113 | 114 | 115 | Il suffit de lancer cette commande pour créer une migration vide en typescript dans le bon dossier! 116 | ``` 117 | npm run migrate:create -- 118 | ``` 119 | 120 | ### Un script pour les migrations et un script pour revenir en arrière! 121 | 122 | EEEEEeeet deux lignes de plus dans le `package.json`, toujours dans la section script! 123 | ``` 124 | "migrate:up": "migrate --migrations-dir=\"./src/migrations\" --compiler=\"ts:./src/migrations-utils/ts-compiler.js\" up", 125 | "migrate:down": "migrate --migrations-dir=\"./src/migrations\" --compiler=\"ts:./src/migrations-utils/ts-compiler.js\" down" 126 | ``` 127 | 128 | Pas de nouvelle option ici, tout est expliqué au-dessus mais comme je suis sympa voila un petit rappel. 129 | 130 | `--migrations-dir=\"./src/migrations\"` Explique à `migrate` où sont nos scripts de migration... 131 | 132 | `--compiler=\"ts:./src/migrations-utils/ts-compiler.js\"` Explique à `migrate` comment gérer les fichiers typescript... 133 | 134 | On peut maintenant exécuter le script `npm run migrate:up` pour les migrations et le script `npm run migrate:down` pour revenir en arrière. 135 | 136 | ## Mais que se passe-t-il quand nous exécutons une migration? 137 | 138 | Migrate va stocker l'état des migrations dans un fichier à la racine du projet. 139 | Ce fichier est: `migrate.json`. 140 | Il ressemble à ça: 141 | ```json 142 | { 143 | "lastRun": "1605197159478-test.ts", 144 | "migrations": [ 145 | { 146 | "title": "1605197159478-test.ts", 147 | "timestamp": 1605197181474 148 | } 149 | ] 150 | } 151 | ``` 152 | 153 | **NE PAS COMMITER `migrate.json`** 154 | 155 | 156 | ## Questions? 157 | 158 | ![questions](https://media.giphy.com/media/5XRB3Ay93FZw4/giphy.gif) 159 | 160 | Je serais heureux de répondre aux questions en commentaires. 161 | 162 | Si cette article t'as plu, n'hésite pas à me rejoindre sur le discord Webeleon! 163 | :phone:[Webeleon coding lair on discord](https://discord.gg/h7HzYzD82p) 164 | 165 | Tu peux aussi me contacter par mail si tu cherches un freelance sympa et efficace :moneybag: 166 | :envelope:[Email me!](contact@webeleon.dev) 167 | 168 | Et comme je suis partageur, tu trouveras les sources sur github! 169 | :gift:[Get the code of the tuto from github](https://github.com/Webeleon/-Building-a-mongodb-migration-system-for-NestJS-with-mongoose.git) 170 | 171 | Buy Me A Coffee 172 | 173 | ## Documentation 174 | 175 | ![documentation](https://media.giphy.com/media/3o6ozkeXSb0Cm25CzS/giphy.gif) 176 | 177 | - [NestJS](https://nestjs.com/) 178 | - [Install mongoose with nest](https://docs.nestjs.com/techniques/mongodb) 179 | - [Migrate](https://github.com/tj/node-migrate#readme) 180 | 181 | 182 | -------------------------------------------------------------------------------- /images/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webeleon/-Building-a-mongodb-migration-system-for-NestJS-with-mongoose/940fe93241b80f210bbf5ea89807bf26a629e8f9/images/banner.png -------------------------------------------------------------------------------- /nest-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "collection": "@nestjs/schematics", 3 | "sourceRoot": "src" 4 | } 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "building-a-mongodb-migration-system-for-nestjs-with-mongoose", 3 | "version": "0.0.1", 4 | "description": "Tutorial: How to build a database migration system in nestjs with mongoose", 5 | "author": "Webeleon ", 6 | "repository": { 7 | "url": "https://github.com/Webeleon/-Building-a-mongodb-migration-system-for-NestJS-with-mongoose.git", 8 | "type": "git" 9 | }, 10 | "license": "MIT", 11 | "scripts": { 12 | "prebuild": "rimraf dist", 13 | "build": "nest build", 14 | "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", 15 | "start": "nest start", 16 | "start:dev": "nest start --watch", 17 | "start:debug": "nest start --debug --watch", 18 | "start:prod": "node dist/main", 19 | "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", 20 | "test": "jest", 21 | "test:watch": "jest --watch", 22 | "test:cov": "jest --coverage", 23 | "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", 24 | "test:e2e": "jest --config ./test/jest-e2e.json", 25 | "migrate:create": "migrate create --template-file ./src/migrations-utils/template.ts --migrations-dir=\"./src/migrations\" --compiler=\"ts:./src/migrations-utils/ts-compiler.js\"", 26 | "migrate:up": "migrate --migrations-dir=\"./src/migrations\" --compiler=\"ts:./src/migrations-utils/ts-compiler.js\" up", 27 | "migrate:down": "migrate --migrations-dir=\"./src/migrations\" --compiler=\"ts:./src/migrations-utils/ts-compiler.js\" down" 28 | }, 29 | "dependencies": { 30 | "@nestjs/common": "7.6.18", 31 | "@nestjs/core": "7.6.18", 32 | "@nestjs/platform-express": "7.6.18", 33 | "dotenv": "8.6.0", 34 | "reflect-metadata": "0.1.13", 35 | "rimraf": "3.0.2", 36 | "rxjs": "6.6.7" 37 | }, 38 | "devDependencies": { 39 | "@nestjs/cli": "7.6.0", 40 | "@nestjs/schematics": "7.3.1", 41 | "@nestjs/testing": "7.6.18", 42 | "@types/express": "4.17.21", 43 | "@types/jest": "26.0.24", 44 | "@types/node": "14.18.63", 45 | "@types/supertest": "2.0.16", 46 | "@typescript-eslint/eslint-plugin": "4.33.0", 47 | "@typescript-eslint/parser": "4.33.0", 48 | "eslint": "7.32.0", 49 | "eslint-config-prettier": "6.15.0", 50 | "eslint-plugin-prettier": "3.4.1", 51 | "jest": "26.6.3", 52 | "prettier": "2.8.8", 53 | "supertest": "6.3.3", 54 | "ts-jest": "26.5.6", 55 | "ts-loader": "8.4.0", 56 | "ts-node": "9.1.1", 57 | "tsconfig-paths": "3.15.0", 58 | "typescript": "4.9.5" 59 | }, 60 | "jest": { 61 | "moduleFileExtensions": [ 62 | "js", 63 | "json", 64 | "ts" 65 | ], 66 | "rootDir": "src", 67 | "testRegex": ".*\\.spec\\.ts$", 68 | "transform": { 69 | "^.+\\.(t|j)s$": "ts-jest" 70 | }, 71 | "collectCoverageFrom": [ 72 | "**/*.(t|j)s" 73 | ], 74 | "coverageDirectory": "../coverage", 75 | "testEnvironment": "node" 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["config:base", "schedule:earlyMondays"], 3 | "packageRules": [ 4 | { 5 | "updateTypes": ["minor", "patch", "pin", "digest"], 6 | "gitLabAutomerge": true, 7 | "automerge": true 8 | } 9 | ], 10 | "commitMessageAction": "update" 11 | } 12 | -------------------------------------------------------------------------------- /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 } 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 | -------------------------------------------------------------------------------- /src/app.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { AppController } from './app.controller'; 3 | import { AppService } from './app.service'; 4 | 5 | @Module({ 6 | imports: [], 7 | controllers: [AppController], 8 | providers: [AppService], 9 | }) 10 | export class AppModule {} 11 | -------------------------------------------------------------------------------- /src/app.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | 3 | @Injectable() 4 | export class AppService { 5 | getHello(): string { 6 | return 'Hello World!'; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/config/configuration.ts: -------------------------------------------------------------------------------- 1 | import { config } from 'dotenv'; 2 | config(); 3 | 4 | export const configs = { 5 | mongoUrl: process.env.MONGO_URL || 'mongodb://localhost/building-a-migration-system-with-nest-and-mongoose', 6 | } 7 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { NestFactory } from '@nestjs/core'; 2 | import { AppModule } from './app.module'; 3 | 4 | async function bootstrap() { 5 | const app = await NestFactory.create(AppModule); 6 | await app.listen(3000); 7 | } 8 | bootstrap(); 9 | -------------------------------------------------------------------------------- /src/migrations-utils/db.ts: -------------------------------------------------------------------------------- 1 | import { MongoClient } from 'mongodb'; 2 | import { configs } from '../config/configuration'; 3 | 4 | const MONGO_URL = configs.mongoUrl; 5 | 6 | export const getDb = async () => { 7 | const client: any = await MongoClient.connect(MONGO_URL, { useUnifiedTopology: true }); 8 | return client.db(); 9 | }; 10 | -------------------------------------------------------------------------------- /src/migrations-utils/template.ts: -------------------------------------------------------------------------------- 1 | import { getDb } from '../migrations-utils/db'; 2 | 3 | export const up = async () => { 4 | const db = await getDb(); 5 | /* 6 | Code your update script here! 7 | */ 8 | }; 9 | 10 | export const down = async () => { 11 | const db = await getDb(); 12 | /* 13 | Code you downgrade script here! 14 | */ 15 | }; 16 | -------------------------------------------------------------------------------- /src/migrations-utils/ts-compiler.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/no-var-requires 2 | const tsNode = require('ts-node'); 3 | module.exports = tsNode.register; 4 | -------------------------------------------------------------------------------- /src/migrations/1605213505980-test.ts: -------------------------------------------------------------------------------- 1 | import { getDb } from '../migrations-utils/db'; 2 | 3 | export const up = async () => { 4 | const db = await getDb(); 5 | /* 6 | Code your update script here! 7 | */ 8 | }; 9 | 10 | export const down = async () => { 11 | const db = await getDb(); 12 | /* 13 | Code you downgrade script here! 14 | */ 15 | }; 16 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------