├── .editorconfig ├── .eslintignore ├── .eslintrc.json ├── .gitignore ├── README.md ├── jest.config.js ├── ormconfig.json ├── package.json ├── prettier.config.js ├── src ├── __tests__ │ ├── Transaction.spec.ts │ └── import_template.csv ├── app.ts ├── database │ └── index.ts ├── errors │ └── AppError.ts ├── models │ ├── Category.ts │ └── Transaction.ts ├── repositories │ └── TransactionsRepository.ts ├── routes │ ├── index.ts │ └── transactions.routes.ts ├── server.ts └── services │ ├── CreateTransactionService.ts │ ├── DeleteTransactionService.ts │ └── ImportTransactionsService.ts ├── tmp └── .gitkeep ├── tsconfig.json └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | indent_style = space 6 | indent_size = 2 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /*.js 2 | node_modules 3 | dist 4 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "es6": true, 4 | "node": true, 5 | "jest": true 6 | }, 7 | "extends": [ 8 | "airbnb-base", 9 | "plugin:@typescript-eslint/recommended", 10 | "prettier/@typescript-eslint", 11 | "plugin:prettier/recommended" 12 | ], 13 | "globals": { 14 | "Atomics": "readonly", 15 | "SharedArrayBuffer": "readonly" 16 | }, 17 | "parser": "@typescript-eslint/parser", 18 | "parserOptions": { 19 | "ecmaVersion": 2018, 20 | "sourceType": "module" 21 | }, 22 | "plugins": [ 23 | "@typescript-eslint", 24 | "prettier" 25 | ], 26 | "rules": { 27 | "no-underscore-dangle": "off", 28 | "prettier/prettier": "error", 29 | "class-methods-use-this": "off", 30 | "@typescript-eslint/camelcase": "off", 31 | "@typescript-eslint/no-unused-vars": ["error", { 32 | "argsIgnorePattern": "_" 33 | }], 34 | "import/extensions": [ 35 | "error", 36 | "ignorePackages", 37 | { 38 | "ts": "never" 39 | } 40 | ] 41 | }, 42 | "settings": { 43 | "import/resolver": { 44 | "typescript": {} 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ 3 | node_modules/ 4 | build/ 5 | temp/ 6 | 7 | tmp/* 8 | !tmp/.gitkeep 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Rocketseat Education 3 |

4 | 5 |

6 | Rocketseat Project 7 | License 8 |

9 | 10 | 11 | ## 💻 Projeto 12 | 13 | gostack-template-typeorm-upload 14 | 15 | ## 📝 Licença 16 | 17 | Esse projeto está sob a licença MIT. Veja o arquivo [LICENSE](LICENSE) para mais detalhes. 18 | 19 | --- 20 | 21 |

22 | Feito com 💜 by Rocketseat 23 |

24 | 25 | 26 | 27 | 28 |
29 |
30 | 31 |

32 | 33 | banner 34 | 35 |

36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // All imported modules in your tests should be mocked automatically 3 | // automock: false, 4 | 5 | // Stop running tests after `n` failures 6 | // bail: 0, 7 | 8 | // Respect "browser" field in package.json when resolving modules 9 | // browser: false, 10 | 11 | // The directory where Jest should store its cached dependency information 12 | // cacheDirectory: "/private/var/folders/qv/s8ph22xx2fnfxdh3pq14t4d40000gn/T/jest_dx", 13 | 14 | // Automatically clear mock calls and instances between every test 15 | clearMocks: true, 16 | 17 | // Indicates whether the coverage information should be collected while executing the test 18 | // collectCoverage: false, 19 | 20 | // An array of glob patterns indicating a set of files for which coverage information should be collected 21 | // collectCoverageFrom: undefined, 22 | 23 | // The directory where Jest should output its coverage files 24 | // coverageDirectory: undefined, 25 | 26 | // An array of regexp pattern strings used to skip coverage collection 27 | // coveragePathIgnorePatterns: [ 28 | // "/node_modules/" 29 | // ], 30 | 31 | // A list of reporter names that Jest uses when writing coverage reports 32 | // coverageReporters: [ 33 | // "json", 34 | // "text", 35 | // "lcov", 36 | // "clover" 37 | // ], 38 | 39 | // An object that configures minimum threshold enforcement for coverage results 40 | // coverageThreshold: undefined, 41 | 42 | // A path to a custom dependency extractor 43 | // dependencyExtractor: undefined, 44 | 45 | // Make calling deprecated APIs throw helpful error messages 46 | // errorOnDeprecated: false, 47 | 48 | // Force coverage collection from ignored files using an array of glob patterns 49 | // forceCoverageMatch: [], 50 | 51 | // A path to a module which exports an async function that is triggered once before all test suites 52 | // globalSetup: undefined, 53 | 54 | // A path to a module which exports an async function that is triggered once after all test suites 55 | // globalTeardown: undefined, 56 | 57 | // A set of global variables that need to be available in all test environments 58 | // globals: {}, 59 | 60 | // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. 61 | // maxWorkers: "50%", 62 | 63 | // An array of directory names to be searched recursively up from the requiring module's location 64 | // moduleDirectories: [ 65 | // "node_modules" 66 | // ], 67 | 68 | // An array of file extensions your modules use 69 | // moduleFileExtensions: [ 70 | // "js", 71 | // "json", 72 | // "jsx", 73 | // "ts", 74 | // "tsx", 75 | // "node" 76 | // ], 77 | 78 | // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module 79 | // moduleNameMapper: {}, 80 | 81 | // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader 82 | // modulePathIgnorePatterns: [], 83 | 84 | // Activates notifications for test results 85 | // notify: false, 86 | 87 | // An enum that specifies notification mode. Requires { notify: true } 88 | // notifyMode: "failure-change", 89 | 90 | // A preset that is used as a base for Jest's configuration 91 | preset: 'ts-jest', 92 | 93 | // Run tests from one or more projects 94 | // projects: undefined, 95 | 96 | // Use this configuration option to add custom reporters to Jest 97 | // reporters: undefined, 98 | 99 | // Automatically reset mock state between every test 100 | // resetMocks: false, 101 | 102 | // Reset the module registry before running each individual test 103 | // resetModules: false, 104 | 105 | // A path to a custom resolver 106 | // resolver: undefined, 107 | 108 | // Automatically restore mock state between every test 109 | // restoreMocks: false, 110 | 111 | // The root directory that Jest should scan for tests and modules within 112 | // rootDir: undefined, 113 | 114 | // A list of paths to directories that Jest should use to search for files in 115 | // roots: [ 116 | // "" 117 | // ], 118 | 119 | // Allows you to use a custom runner instead of Jest's default test runner 120 | // runner: "jest-runner", 121 | 122 | // The paths to modules that run some code to configure or set up the testing environment before each test 123 | // setupFiles: [], 124 | 125 | // A list of paths to modules that run some code to configure or set up the testing framework before each test 126 | // setupFilesAfterEnv: [], 127 | 128 | // A list of paths to snapshot serializer modules Jest should use for snapshot testing 129 | // snapshotSerializers: [], 130 | 131 | // The test environment that will be used for testing 132 | testEnvironment: 'node', 133 | 134 | // Options that will be passed to the testEnvironment 135 | // testEnvironmentOptions: {}, 136 | 137 | // Adds a location field to test results 138 | // testLocationInResults: false, 139 | 140 | // The glob patterns Jest uses to detect test files 141 | // testMatch: [ 142 | // "**/__tests__/**/*.[jt]s?(x)", 143 | // "**/?(*.)+(spec|test).[tj]s?(x)" 144 | // ], 145 | 146 | // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped 147 | // testPathIgnorePatterns: [ 148 | // "/node_modules/" 149 | // ], 150 | 151 | // The regexp pattern or array of patterns that Jest uses to detect test files 152 | // testRegex: [], 153 | 154 | // This option allows the use of a custom results processor 155 | // testResultsProcessor: undefined, 156 | 157 | // This option allows use of a custom test runner 158 | // testRunner: "jasmine2", 159 | 160 | // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href 161 | // testURL: "http://localhost", 162 | 163 | // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" 164 | // timers: "real", 165 | 166 | // A map from regular expressions to paths to transformers 167 | // transform: undefined, 168 | 169 | // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation 170 | // transformIgnorePatterns: [ 171 | // "/node_modules/" 172 | // ], 173 | 174 | // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them 175 | // unmockedModulePathPatterns: undefined, 176 | 177 | // Indicates whether each individual test should be reported during the run 178 | // verbose: undefined, 179 | 180 | // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode 181 | // watchPathIgnorePatterns: [], 182 | 183 | // Whether to use watchman for file crawling 184 | // watchman: true, 185 | }; 186 | -------------------------------------------------------------------------------- /ormconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "postgres", 3 | "host": "localhost", 4 | "port": 5432, 5 | "username": "postgres", 6 | "password": "docker", 7 | "database": "gostack_desafio06", 8 | "entities": ["./src/models/*.ts"], 9 | "migrations": ["./src/database/migrations/*.ts"], 10 | "cli": { 11 | "migrationsDir": "./src/database/migrations" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "desafio-06", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "build": "tsc", 8 | "dev:server": "ts-node-dev --inspect --transpileOnly --ignore-watch node_modules src/server.ts", 9 | "start": "ts-node src/index.ts", 10 | "typeorm": "ts-node-dev ./node_modules/typeorm/cli.js", 11 | "test": "cross-env NODE_ENV=test jest" 12 | }, 13 | "dependencies": { 14 | "@types/csv-parse": "^1.2.2", 15 | "csv-parse": "^4.8.8", 16 | "dotenv": "^8.2.0", 17 | "express": "^4.17.1", 18 | "express-async-errors": "^3.1.1", 19 | "multer": "^1.4.2", 20 | "pg": "^8.3.0", 21 | "reflect-metadata": "^0.1.13", 22 | "typeorm": "^0.2.24" 23 | }, 24 | "devDependencies": { 25 | "@types/express": "4.17.3", 26 | "@types/express-serve-static-core": "4.17.2", 27 | "@types/jest": "^25.2.1", 28 | "@types/multer": "^1.4.2", 29 | "@types/supertest": "^2.0.8", 30 | "@typescript-eslint/eslint-plugin": "^2.27.0", 31 | "@typescript-eslint/parser": "^2.27.0", 32 | "cross-env": "^7.0.2", 33 | "eslint": "^6.8.0", 34 | "eslint-config-airbnb-base": "^14.1.0", 35 | "eslint-config-prettier": "^6.10.1", 36 | "eslint-import-resolver-typescript": "^2.0.0", 37 | "eslint-plugin-import": "^2.20.1", 38 | "eslint-plugin-prettier": "^3.1.2", 39 | "jest": "^25.3.0", 40 | "prettier": "^2.0.4", 41 | "supertest": "^4.0.2", 42 | "ts-jest": "^25.3.1", 43 | "ts-node": "3.3.0", 44 | "ts-node-dev": "^1.0.0-pre.44", 45 | "typescript": "^3.8.3" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | singleQuote: true, 3 | trailingComma: "all", 4 | arrowParens: "avoid", 5 | }; 6 | -------------------------------------------------------------------------------- /src/__tests__/Transaction.spec.ts: -------------------------------------------------------------------------------- 1 | import request from 'supertest'; 2 | import path from 'path'; 3 | import { Connection, getRepository, getConnection } from 'typeorm'; 4 | import createConnection from '../database'; 5 | 6 | import Transaction from '../models/Transaction'; 7 | import Category from '../models/Category'; 8 | 9 | import app from '../app'; 10 | 11 | let connection: Connection; 12 | 13 | describe('Transaction', () => { 14 | beforeAll(async () => { 15 | connection = await createConnection('test-connection'); 16 | 17 | await connection.query('DROP TABLE IF EXISTS transactions'); 18 | await connection.query('DROP TABLE IF EXISTS categories'); 19 | await connection.query('DROP TABLE IF EXISTS migrations'); 20 | 21 | await connection.runMigrations(); 22 | }); 23 | 24 | beforeEach(async () => { 25 | await connection.query('DELETE FROM transactions'); 26 | await connection.query('DELETE FROM categories'); 27 | }); 28 | 29 | afterAll(async () => { 30 | const mainConnection = getConnection(); 31 | 32 | await connection.close(); 33 | await mainConnection.close(); 34 | }); 35 | 36 | it('should be able to list transactions', async () => { 37 | await request(app).post('/transactions').send({ 38 | title: 'March Salary', 39 | type: 'income', 40 | value: 4000, 41 | category: 'Salary', 42 | }); 43 | 44 | await request(app).post('/transactions').send({ 45 | title: 'April Salary', 46 | type: 'income', 47 | value: 4000, 48 | category: 'Salary', 49 | }); 50 | 51 | await request(app).post('/transactions').send({ 52 | title: 'Macbook', 53 | type: 'outcome', 54 | value: 6000, 55 | category: 'Eletronics', 56 | }); 57 | 58 | const response = await request(app).get('/transactions'); 59 | 60 | expect(response.body.transactions).toHaveLength(3); 61 | expect(response.body.balance).toMatchObject({ 62 | income: 8000, 63 | outcome: 6000, 64 | total: 2000, 65 | }); 66 | }); 67 | 68 | it('should be able to create new transaction', async () => { 69 | const transactionsRepository = getRepository(Transaction); 70 | 71 | const response = await request(app).post('/transactions').send({ 72 | title: 'March Salary', 73 | type: 'income', 74 | value: 4000, 75 | category: 'Salary', 76 | }); 77 | 78 | const transaction = await transactionsRepository.findOne({ 79 | where: { 80 | title: 'March Salary', 81 | }, 82 | }); 83 | 84 | expect(transaction).toBeTruthy(); 85 | 86 | expect(response.body).toMatchObject( 87 | expect.objectContaining({ 88 | id: expect.any(String), 89 | }), 90 | ); 91 | }); 92 | 93 | it('should create tags when inserting new transactions', async () => { 94 | const transactionsRepository = getRepository(Transaction); 95 | const categoriesRepository = getRepository(Category); 96 | 97 | const response = await request(app).post('/transactions').send({ 98 | title: 'March Salary', 99 | type: 'income', 100 | value: 4000, 101 | category: 'Salary', 102 | }); 103 | 104 | const category = await categoriesRepository.findOne({ 105 | where: { 106 | title: 'Salary', 107 | }, 108 | }); 109 | 110 | expect(category).toBeTruthy(); 111 | 112 | const transaction = await transactionsRepository.findOne({ 113 | where: { 114 | title: 'March Salary', 115 | category_id: category?.id, 116 | }, 117 | }); 118 | 119 | expect(transaction).toBeTruthy(); 120 | 121 | expect(response.body).toMatchObject( 122 | expect.objectContaining({ 123 | id: expect.any(String), 124 | }), 125 | ); 126 | }); 127 | 128 | it('should not create tags when they already exists', async () => { 129 | const transactionsRepository = getRepository(Transaction); 130 | const categoriesRepository = getRepository(Category); 131 | 132 | const { identifiers } = await categoriesRepository.insert({ 133 | title: 'Salary', 134 | }); 135 | 136 | const insertedCategoryId = identifiers[0].id; 137 | 138 | await request(app).post('/transactions').send({ 139 | title: 'March Salary', 140 | type: 'income', 141 | value: 4000, 142 | category: 'Salary', 143 | }); 144 | 145 | const transaction = await transactionsRepository.findOne({ 146 | where: { 147 | title: 'March Salary', 148 | category_id: insertedCategoryId, 149 | }, 150 | }); 151 | 152 | const categoriesCount = await categoriesRepository.find(); 153 | 154 | expect(categoriesCount).toHaveLength(1); 155 | expect(transaction).toBeTruthy(); 156 | }); 157 | 158 | it('should not be able to create outcome transaction without a valid balance', async () => { 159 | await request(app).post('/transactions').send({ 160 | title: 'March Salary', 161 | type: 'income', 162 | value: 4000, 163 | category: 'Salary', 164 | }); 165 | 166 | const response = await request(app).post('/transactions').send({ 167 | title: 'iPhone', 168 | type: 'outcome', 169 | value: 4500, 170 | category: 'Eletronics', 171 | }); 172 | 173 | expect(response.status).toBe(400); 174 | expect(response.body).toMatchObject( 175 | expect.objectContaining({ 176 | status: 'error', 177 | message: expect.any(String), 178 | }), 179 | ); 180 | }); 181 | 182 | it('should be able to delete a transaction', async () => { 183 | const transactionsRepository = getRepository(Transaction); 184 | 185 | const response = await request(app).post('/transactions').send({ 186 | title: 'March Salary', 187 | type: 'income', 188 | value: 4000, 189 | category: 'Salary', 190 | }); 191 | 192 | await request(app).delete(`/transactions/${response.body.id}`); 193 | 194 | const transaction = await transactionsRepository.findOne(response.body.id); 195 | 196 | expect(transaction).toBeFalsy(); 197 | }); 198 | 199 | it('should be able to import transactions', async () => { 200 | const transactionsRepository = getRepository(Transaction); 201 | const categoriesRepository = getRepository(Category); 202 | 203 | const importCSV = path.resolve(__dirname, 'import_template.csv'); 204 | 205 | await request(app).post('/transactions/import').attach('file', importCSV); 206 | 207 | const transactions = await transactionsRepository.find(); 208 | const categories = await categoriesRepository.find(); 209 | 210 | expect(categories).toHaveLength(2); 211 | expect(categories).toEqual( 212 | expect.arrayContaining([ 213 | expect.objectContaining({ 214 | title: 'Others', 215 | }), 216 | expect.objectContaining({ 217 | title: 'Food', 218 | }), 219 | ]), 220 | ); 221 | 222 | expect(transactions).toHaveLength(3); 223 | expect(transactions).toEqual( 224 | expect.arrayContaining([ 225 | expect.objectContaining({ 226 | title: 'Loan', 227 | type: 'income', 228 | }), 229 | expect.objectContaining({ 230 | title: 'Website Hosting', 231 | type: 'outcome', 232 | }), 233 | expect.objectContaining({ 234 | title: 'Ice cream', 235 | type: 'outcome', 236 | }), 237 | ]), 238 | ); 239 | }); 240 | }); 241 | -------------------------------------------------------------------------------- /src/__tests__/import_template.csv: -------------------------------------------------------------------------------- 1 | title, type, value, category 2 | Loan, income, 1500, Others 3 | Website Hosting, outcome, 50, Others 4 | Ice cream, outcome, 3, Food 5 | -------------------------------------------------------------------------------- /src/app.ts: -------------------------------------------------------------------------------- 1 | import 'reflect-metadata'; 2 | import 'dotenv/config'; 3 | 4 | import express, { Request, Response, NextFunction } from 'express'; 5 | import 'express-async-errors'; 6 | 7 | import routes from './routes'; 8 | import AppError from './errors/AppError'; 9 | 10 | import createConnection from './database'; 11 | 12 | createConnection(); 13 | const app = express(); 14 | 15 | app.use(express.json()); 16 | app.use(routes); 17 | 18 | app.use((err: Error, request: Request, response: Response, _: NextFunction) => { 19 | if (err instanceof AppError) { 20 | return response.status(err.statusCode).json({ 21 | status: 'error', 22 | message: err.message, 23 | }); 24 | } 25 | 26 | console.error(err); 27 | 28 | return response.status(500).json({ 29 | status: 'error', 30 | message: 'Internal server error', 31 | }); 32 | }); 33 | 34 | export default app; 35 | -------------------------------------------------------------------------------- /src/database/index.ts: -------------------------------------------------------------------------------- 1 | import { createConnection, getConnectionOptions, Connection } from 'typeorm'; 2 | 3 | export default async (name = 'default'): Promise => { 4 | const defaultOptions = await getConnectionOptions(); 5 | 6 | return createConnection( 7 | Object.assign(defaultOptions, { 8 | name, 9 | database: 10 | process.env.NODE_ENV === 'test' 11 | ? 'gostack_desafio06_tests' 12 | : defaultOptions.database, 13 | }), 14 | ); 15 | }; 16 | -------------------------------------------------------------------------------- /src/errors/AppError.ts: -------------------------------------------------------------------------------- 1 | class AppError { 2 | public readonly message: string; 3 | 4 | public readonly statusCode: number; 5 | 6 | constructor(message: string, statusCode = 400) { 7 | this.message = message; 8 | this.statusCode = statusCode; 9 | } 10 | } 11 | 12 | export default AppError; 13 | -------------------------------------------------------------------------------- /src/models/Category.ts: -------------------------------------------------------------------------------- 1 | class Category { 2 | id: string; 3 | 4 | title: string; 5 | 6 | created_at: Date; 7 | 8 | updated_at: Date; 9 | } 10 | 11 | export default Category; 12 | -------------------------------------------------------------------------------- /src/models/Transaction.ts: -------------------------------------------------------------------------------- 1 | class Transaction { 2 | id: string; 3 | 4 | title: string; 5 | 6 | type: 'income' | 'outcome'; 7 | 8 | value: number; 9 | 10 | category_id: string; 11 | 12 | created_at: Date; 13 | 14 | updated_at: Date; 15 | } 16 | 17 | export default Transaction; 18 | -------------------------------------------------------------------------------- /src/repositories/TransactionsRepository.ts: -------------------------------------------------------------------------------- 1 | import { EntityRepository, Repository } from 'typeorm'; 2 | 3 | import Transaction from '../models/Transaction'; 4 | 5 | interface Balance { 6 | income: number; 7 | outcome: number; 8 | total: number; 9 | } 10 | 11 | @EntityRepository(Transaction) 12 | class TransactionsRepository extends Repository { 13 | public async getBalance(): Promise { 14 | // TODO 15 | } 16 | } 17 | 18 | export default TransactionsRepository; 19 | -------------------------------------------------------------------------------- /src/routes/index.ts: -------------------------------------------------------------------------------- 1 | import { Router } from 'express'; 2 | 3 | import transactionsRouter from './transactions.routes'; 4 | 5 | const routes = Router(); 6 | 7 | routes.use('/transactions', transactionsRouter); 8 | 9 | export default routes; 10 | -------------------------------------------------------------------------------- /src/routes/transactions.routes.ts: -------------------------------------------------------------------------------- 1 | import { Router } from 'express'; 2 | 3 | // import TransactionsRepository from '../repositories/TransactionsRepository'; 4 | // import CreateTransactionService from '../services/CreateTransactionService'; 5 | // import DeleteTransactionService from '../services/DeleteTransactionService'; 6 | // import ImportTransactionsService from '../services/ImportTransactionsService'; 7 | 8 | const transactionsRouter = Router(); 9 | 10 | transactionsRouter.get('/', async (request, response) => { 11 | // TODO 12 | }); 13 | 14 | transactionsRouter.post('/', async (request, response) => { 15 | // TODO 16 | }); 17 | 18 | transactionsRouter.delete('/:id', async (request, response) => { 19 | // TODO 20 | }); 21 | 22 | transactionsRouter.post('/import', async (request, response) => { 23 | // TODO 24 | }); 25 | 26 | export default transactionsRouter; 27 | -------------------------------------------------------------------------------- /src/server.ts: -------------------------------------------------------------------------------- 1 | import app from './app'; 2 | 3 | app.listen(3333, () => { 4 | console.log('🚀 Server started on port 3333!'); 5 | }); 6 | -------------------------------------------------------------------------------- /src/services/CreateTransactionService.ts: -------------------------------------------------------------------------------- 1 | // import AppError from '../errors/AppError'; 2 | 3 | import Transaction from '../models/Transaction'; 4 | 5 | class CreateTransactionService { 6 | public async execute(): Promise { 7 | // TODO 8 | } 9 | } 10 | 11 | export default CreateTransactionService; 12 | -------------------------------------------------------------------------------- /src/services/DeleteTransactionService.ts: -------------------------------------------------------------------------------- 1 | // import AppError from '../errors/AppError'; 2 | 3 | class DeleteTransactionService { 4 | public async execute(): Promise { 5 | // TODO 6 | } 7 | } 8 | 9 | export default DeleteTransactionService; 10 | -------------------------------------------------------------------------------- /src/services/ImportTransactionsService.ts: -------------------------------------------------------------------------------- 1 | import Transaction from '../models/Transaction'; 2 | 3 | class ImportTransactionsService { 4 | async execute(): Promise { 5 | // TODO 6 | } 7 | } 8 | 9 | export default ImportTransactionsService; 10 | -------------------------------------------------------------------------------- /tmp/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rocketseat-education/gostack-template-typeorm-upload/64b5964e8afdbc241f89f67ef66f4652ceaf8d70/tmp/.gitkeep -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | // "incremental": true, /* Enable incremental compilation */ 5 | "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ 6 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ 7 | // "lib": [], /* Specify library files to be included in the compilation. */ 8 | "allowJs": true, /* Allow javascript files to be compiled. */ 9 | // "checkJs": true, /* Report errors in .js files. */ 10 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 11 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 12 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 13 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 14 | // "outFile": "./", /* Concatenate and emit output to single file. */ 15 | "outDir": "./dist", /* Redirect output structure to the directory. */ 16 | "rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 17 | // "composite": true, /* Enable project compilation */ 18 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ 19 | // "removeComments": true, /* Do not emit comments to output. */ 20 | // "noEmit": true, /* Do not emit outputs. */ 21 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 22 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 23 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 24 | 25 | /* Strict Type-Checking Options */ 26 | "strict": true, /* Enable all strict type-checking options. */ 27 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 28 | // "strictNullChecks": true, /* Enable strict null checks. */ 29 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 30 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 31 | "strictPropertyInitialization": false, /* Enable strict checking of property initialization in classes. */ 32 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 33 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 34 | 35 | /* Additional Checks */ 36 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 37 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 38 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 39 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 40 | 41 | /* Module Resolution Options */ 42 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 43 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 44 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 45 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 46 | // "typeRoots": [], /* List of folders to include type definitions from. */ 47 | // "types": [], /* Type declaration files to be included in compilation. */ 48 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 49 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 50 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 51 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 52 | 53 | /* Source Map Options */ 54 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 55 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 56 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 57 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 58 | 59 | /* Experimental Options */ 60 | "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 61 | "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 62 | 63 | /* Advanced Options */ 64 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 65 | } 66 | } 67 | --------------------------------------------------------------------------------