├── .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 |
3 |
4 |
5 |
6 |
7 |
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 |
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 |
--------------------------------------------------------------------------------