Skip to content

Commit

Permalink
feat: 🎸 adds instruments crud
Browse files Browse the repository at this point in the history
Adds functionality to create, update and list Instruments. Adds the
seeder functionality to the project with the instruments seeder.

βœ… Closes: #16
  • Loading branch information
MattZ6 committed Jan 5, 2021
1 parent c5631a5 commit 4d352f8
Show file tree
Hide file tree
Showing 30 changed files with 1,064 additions and 226 deletions.
1 change: 1 addition & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
],
"rules": {
"no-useless-constructor": "off",
"no-plusplus": "off",
"@typescript-eslint/naming-convention": [
"error",
{
Expand Down
1 change: 1 addition & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
require('dotenv/config');
const { pathsToModuleNameMapper } = require('ts-jest/utils');
const { compilerOptions } = require('./tsconfig.json');

Expand Down
37 changes: 20 additions & 17 deletions ormconfig.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
{
"type": "postgres",
"host": "localhost",
"port": 5432,
"username": "postgres",
"password": "docker",
"database": "hub",
"entities": [
"./src/modules/*/infra/typeorm/entities/*.ts"
],
"migrations": [
"./src/shared/infra/typeorm/migrations/*.ts"
],
"cli": {
"migrationsDir": "./src/shared/infra/typeorm/migrations"
}
}
{
"type": "postgres",
"host": "localhost",
"port": 5432,
"username": "postgres",
"password": "docker",
"database": "hub",
"entities": [
"./src/modules/*/infra/typeorm/entities/*.ts"
],
"migrations": [
"./src/shared/infra/typeorm/migrations/*.ts"
],
"cli": {
"migrationsDir": "./src/shared/infra/typeorm/migrations"
},
"seeds": [
"./src/shared/infra/typeorm/seeders/*.ts"
]
}
125 changes: 64 additions & 61 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,61 +1,64 @@
{
"name": "hub-api",
"version": "1.0.0",
"description": "API for Musics hub application.",
"main": "src/server.ts",
"author": {
"email": "[email protected]",
"name": "Matheus Felipe Zanin",
"url": "https://github.com/MattZ6"
},
"license": "MIT",
"scripts": {
"build": "tsc",
"dev:server": "tsnd -r tsconfig-paths/register --inspect --transpile-only --ignore-watch node_modules src/shared/infra/http/server.ts",
"typeorm": "tsnd -r tsconfig-paths/register ./node_modules/typeorm/cli.js",
"test": "jest"
},
"devDependencies": {
"@types/bcryptjs": "2.4.2",
"@types/cors": "2.8.9",
"@types/express": "4.17.9",
"@types/faker": "5.1.5",
"@types/jest": "26.0.19",
"@types/jsonwebtoken": "8.5.0",
"@types/nodemailer": "6.4.0",
"@types/uuid": "8.3.0",
"@typescript-eslint/eslint-plugin": "4.11.1",
"@typescript-eslint/parser": "4.11.1",
"eslint": "7.17.0",
"eslint-config-airbnb-base": "14.2.1",
"eslint-config-prettier": "7.1.0",
"eslint-import-resolver-typescript": "2.3.0",
"eslint-plugin-import": "2.22.1",
"eslint-plugin-prettier": "3.3.0",
"jest": "26.6.3",
"prettier": "2.2.1",
"ts-jest": "26.4.4",
"ts-node-dev": "1.1.1",
"tsconfig-paths": "3.9.0",
"typescript": "4.1.3"
},
"dependencies": {
"bcryptjs": "^2.4.3",
"celebrate": "^13.0.4",
"class-transformer": "^0.3.1",
"cors": "^2.8.5",
"date-fns": "^2.16.1",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"express-async-errors": "^3.1.1",
"faker": "^5.1.0",
"handlebars": "^4.7.6",
"jsonwebtoken": "^8.5.1",
"nodemailer": "^6.4.17",
"pg": "^8.5.1",
"reflect-metadata": "^0.1.13",
"tsyringe": "^4.4.0",
"typeorm": "^0.2.29",
"uuid": "^8.3.2"
}
}
{
"name": "hub-api",
"version": "1.0.0",
"description": "API for Musics hub application.",
"main": "src/server.ts",
"author": {
"email": "[email protected]",
"name": "Matheus Felipe Zanin",
"url": "https://github.com/MattZ6"
},
"license": "MIT",
"scripts": {
"build": "tsc",
"dev:server": "tsnd -r tsconfig-paths/register --inspect --transpile-only --ignore-watch node_modules src/shared/infra/http/server.ts",
"typeorm": "tsnd -r tsconfig-paths/register ./node_modules/typeorm/cli.js",
"test": "jest",
"db:seed": "tsnd -r tsconfig-paths/register ./node_modules/typeorm-seeding/dist/cli.js seed",
"db:config": "yarn typeorm migration:run && db:seed"
},
"devDependencies": {
"@types/bcryptjs": "2.4.2",
"@types/cors": "2.8.9",
"@types/express": "4.17.9",
"@types/faker": "5.1.5",
"@types/jest": "26.0.19",
"@types/jsonwebtoken": "8.5.0",
"@types/nodemailer": "6.4.0",
"@types/uuid": "8.3.0",
"@typescript-eslint/eslint-plugin": "4.11.1",
"@typescript-eslint/parser": "4.11.1",
"eslint": "7.17.0",
"eslint-config-airbnb-base": "14.2.1",
"eslint-config-prettier": "7.1.0",
"eslint-import-resolver-typescript": "2.3.0",
"eslint-plugin-import": "2.22.1",
"eslint-plugin-prettier": "3.3.0",
"jest": "26.6.3",
"prettier": "2.2.1",
"ts-jest": "26.4.4",
"ts-node-dev": "1.1.1",
"tsconfig-paths": "3.9.0",
"typescript": "4.1.3"
},
"dependencies": {
"bcryptjs": "^2.4.3",
"celebrate": "^13.0.4",
"class-transformer": "^0.3.1",
"cors": "^2.8.5",
"date-fns": "^2.16.1",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"express-async-errors": "^3.1.1",
"faker": "^5.1.0",
"handlebars": "^4.7.6",
"jsonwebtoken": "^8.5.1",
"nodemailer": "^6.4.17",
"pg": "^8.5.1",
"reflect-metadata": "^0.1.13",
"tsyringe": "^4.4.0",
"typeorm": "^0.2.29",
"typeorm-seeding": "^1.6.1",
"uuid": "^8.3.2"
}
}
4 changes: 4 additions & 0 deletions src/modules/instruments/dtos/ICreateInstrumentDTO.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export default interface ICreateInstrumentDTO {
name: string;
label: string;
}
4 changes: 4 additions & 0 deletions src/modules/instruments/dtos/IListInstrumentsDTO.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export default interface IListIntrumentsDTO {
field: 'name' | 'label' | 'created_at';
order: 'ASC' | 'DESC';
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { Request, Response } from 'express';
import { container } from 'tsyringe';

import { EnumStatusCode } from '@shared/errors/AppError';

import ListInstrumentsService from '@modules/instruments/services/ListInstrumentsService';
import CreateInstrumentService from '@modules/instruments/services/CreateInstrumentService';
import UpdateInstrumentService from '@modules/instruments/services/UpdateInstrumentService';

type IIndexRequestQuery = {
order_by: 'name' | 'label' | 'created_at';
order: 'ASC' | 'DESC';
};

interface ICreateRequest {
name: string;
label: string;
}

interface IUpdateRequest {
name: string;
label: string;
}

export default class InstrumentController {
public async index(request: Request, response: Response): Promise<Response> {
const { order, order_by } = request.query as IIndexRequestQuery;

const listInstruments = container.resolve(ListInstrumentsService);

const instruments = await listInstruments.execute({
field: order_by,
order,
});

return response.json(instruments);
}

public async create(request: Request, response: Response): Promise<Response> {
const { name, label } = request.body as ICreateRequest;

const createInstrument = container.resolve(CreateInstrumentService);

const instrument = await createInstrument.execute({ name, label });

return response.status(EnumStatusCode.Created).json(instrument);
}

public async update(request: Request, response: Response): Promise<Response> {
const { name, label } = request.body as IUpdateRequest;
const { id: instrument_id } = request.params;

const updateInstrument = container.resolve(UpdateInstrumentService);

const instrument = await updateInstrument.execute({
instrument_id,
name,
label,
});

return response.json(instrument);
}
}
37 changes: 37 additions & 0 deletions src/modules/instruments/infra/http/routes/instruments.routes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Router } from 'express';
import { celebrate, Joi } from 'celebrate';

import ensureAuthenticated from '@modules/users/infra/http/middlewares/ensureAuthenticated';

import InstrumentController from '@modules/instruments/infra/http/controllers/InstrumentController';

const router = Router();
const instrumentController = new InstrumentController();

router.use(ensureAuthenticated);

router.get('', instrumentController.index);

router.post(
'',
celebrate({
body: Joi.object().keys({
name: Joi.string().trim().required(),
label: Joi.string().trim().required(),
}),
}),
instrumentController.create
);

router.put(
'/:id',
celebrate({
body: Joi.object().keys({
name: Joi.string().trim().required(),
label: Joi.string().trim().required(),
}),
}),
instrumentController.update
);

export default router;
29 changes: 29 additions & 0 deletions src/modules/instruments/infra/typeorm/entities/Instrument.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {
Entity,
Column,
PrimaryGeneratedColumn,
CreateDateColumn,
UpdateDateColumn,
} from 'typeorm';

export const INSTRUMENTS_TABLE_NAME = 'instruments';

@Entity(INSTRUMENTS_TABLE_NAME)
class Instrument {
@PrimaryGeneratedColumn('uuid')
id: string;

@Column()
name: string;

@Column()
label: string;

@CreateDateColumn()
created_at: Date;

@UpdateDateColumn()
updated_at: Date;
}

export default Instrument;
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { getRepository, Repository } from 'typeorm';

import Instrument from '@modules/instruments/infra/typeorm/entities/Instrument';

import ICreateInstrumentDTO from '@modules/instruments/dtos/ICreateInstrumentDTO';
import IListInstrumentsDTO from '@modules/instruments/dtos/IListInstrumentsDTO';
import IInstrumentsRepository from '@modules/instruments/repositories/IIntrumentsRepository';

class InstrumentsRepository implements IInstrumentsRepository {
private repository: Repository<Instrument>;

constructor() {
this.repository = getRepository(Instrument);
}

public async create({
name,
label,
}: ICreateInstrumentDTO): Promise<Instrument> {
const instrument = this.repository.create({
name,
label,
});

return this.repository.save(instrument);
}

public async update(instrument: Instrument): Promise<Instrument> {
return this.repository.save(instrument);
}

public async findById(id: string): Promise<Instrument | undefined> {
return this.repository.findOne({
where: { id },
});
}

public async findByName(name: string): Promise<Instrument | undefined> {
return this.repository
.createQueryBuilder('instrument')
.where(`LOWER(instrument.name) = LOWER('${name}')`)
.getOne();
}

public async find({
field = 'name',
order = 'ASC',
}: IListInstrumentsDTO): Promise<Instrument[]> {
return this.repository.find({
order: {
[field]: order,
},
});
}
}

export default InstrumentsRepository;
14 changes: 14 additions & 0 deletions src/modules/instruments/repositories/IIntrumentsRepository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import Instrument from '@modules/instruments/infra/typeorm/entities/Instrument';

import ICreateInstrumentDTO from '@modules/instruments/dtos/ICreateInstrumentDTO';
import IListInstrumentsDTO from '@modules/instruments/dtos/IListInstrumentsDTO';

export const INSTRUMENTS_REPOSITORY_INDENTIFIER = 'InstrumentsRepository';

export default interface IInstrumentsRepository {
create(data: ICreateInstrumentDTO): Promise<Instrument>;
update(data: Instrument): Promise<Instrument>;
find(data: IListInstrumentsDTO): Promise<Instrument[]>;
findById(id: string): Promise<Instrument | undefined>;
findByName(name: string): Promise<Instrument | undefined>;
}
Loading

0 comments on commit 4d352f8

Please sign in to comment.