diff --git a/README.md b/README.md index 7c1ee99..0c37808 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,11 @@ # Getlab ## Injeção de dependências + Como registrar suas dependências, direcionando responsabilidades ### Simples + Classe sem dependência nem substituto concreto ```ts @@ -15,6 +17,7 @@ register({ for: MeuService }); ``` ### Com dependência + Classe contendo uma dependência Veja que primeiro registramos `DependenciaDoMeuService`, em seguida registramos `MeuServiceComDependencia` indicando para adicionar `DependenciaDoMeuService`, pois ela depende dele pra funcionar corretamente. @@ -38,6 +41,7 @@ register( ``` ### Direcionando responsabilidade + Classe abstrata e classe concreta Primeiro criamos uma abstração sem implementação, desta forma: @@ -69,6 +73,7 @@ register({ ``` ### Direcionando responsabilidade com dependências + Classe abstrata e classe concreta que depende de outras classes Em seguida, criamos a classe concreta, que implementa o contrato da abstração: @@ -103,6 +108,7 @@ const meuOutroServico = inject(MeuOutroService); # Exemplos reais ## Organizando + UseCases precisam da infra registrada e Facades precisas dos UseCases registrados, então precisamos começar registradno a infra ```ts @@ -159,15 +165,16 @@ import { Component } from '@angular/core'; @Component({ standalone: true, selector: 'getlab-root', - providers: [ transfer() ], + providers: [transfer()], template: `
       {{ facade.data$ | async | json }}
-    
+ `, }) export class AppComponent { - facade = inject(TeamFacade) + facade = inject(TeamFacade); } ``` diff --git a/apps/server/src/app/app.module.ts b/apps/server/src/app/app.module.ts index 18edb77..e51e087 100644 --- a/apps/server/src/app/app.module.ts +++ b/apps/server/src/app/app.module.ts @@ -18,6 +18,6 @@ import { UsersModule } from './users/users.module'; UsersModule, TeamsModule, SchedulesModule, - ] + ], }) export class AppModule {} diff --git a/apps/server/src/app/schedules/infrastructure/index.ts b/apps/server/src/app/schedules/infrastructure/index.ts index fc87d4b..e8f75bd 100644 --- a/apps/server/src/app/schedules/infrastructure/index.ts +++ b/apps/server/src/app/schedules/infrastructure/index.ts @@ -1,2 +1,2 @@ -export * from './schedules.service.impl'; -export * from './schedules.service'; +export * from './schedules.service.impl'; +export * from './schedules.service'; diff --git a/apps/server/src/app/schedules/infrastructure/schedules.service.impl.ts b/apps/server/src/app/schedules/infrastructure/schedules.service.impl.ts index 0e0a5fe..296b436 100644 --- a/apps/server/src/app/schedules/infrastructure/schedules.service.impl.ts +++ b/apps/server/src/app/schedules/infrastructure/schedules.service.impl.ts @@ -30,6 +30,6 @@ export class SchedulesServiceImpl implements SchedulesService { } remove(id: string) { - return this.scheduleModel.findOneAndRemove({ id }); + return this.scheduleModel.findByIdAndRemove(id); } } diff --git a/apps/server/src/app/teams/infrastructure/index.ts b/apps/server/src/app/teams/infrastructure/index.ts index e4c69cb..c6f4204 100644 --- a/apps/server/src/app/teams/infrastructure/index.ts +++ b/apps/server/src/app/teams/infrastructure/index.ts @@ -1,2 +1,2 @@ -export * from './teams.service.impl'; -export * from './teams.service'; +export * from './teams.service.impl'; +export * from './teams.service'; diff --git a/apps/server/src/app/teams/infrastructure/teams.service.impl.ts b/apps/server/src/app/teams/infrastructure/teams.service.impl.ts index b803268..b09f834 100644 --- a/apps/server/src/app/teams/infrastructure/teams.service.impl.ts +++ b/apps/server/src/app/teams/infrastructure/teams.service.impl.ts @@ -25,6 +25,6 @@ export class TeamsServiceImpl implements TeamsService { } async remove(id: string) { - return this.teamModel.findOneAndRemove({ id }); + return this.teamModel.findByIdAndRemove(id); } } diff --git a/apps/server/src/app/users/infrastructure/index.ts b/apps/server/src/app/users/infrastructure/index.ts index 4e4dcfb..404e9c0 100644 --- a/apps/server/src/app/users/infrastructure/index.ts +++ b/apps/server/src/app/users/infrastructure/index.ts @@ -1,2 +1,2 @@ -export * from './users.service.impl'; -export * from './users.service'; +export * from './users.service.impl'; +export * from './users.service'; diff --git a/apps/server/src/app/users/infrastructure/users.service.impl.ts b/apps/server/src/app/users/infrastructure/users.service.impl.ts index 97704de..f9136d5 100644 --- a/apps/server/src/app/users/infrastructure/users.service.impl.ts +++ b/apps/server/src/app/users/infrastructure/users.service.impl.ts @@ -25,6 +25,6 @@ export class UsersServiceImpl implements UsersService { } async remove(id: string) { - return this.userModel.findOneAndRemove({ id }); + return this.userModel.findByIdAndRemove(id); } } diff --git a/libs/data-access/src/lib/application/index.ts b/libs/data-access/src/lib/application/index.ts index 8523441..c9a66b8 100644 --- a/libs/data-access/src/lib/application/index.ts +++ b/libs/data-access/src/lib/application/index.ts @@ -1,4 +1,4 @@ -export * from './schedule.facade'; -export * from './spreadsheet.facade'; -export * from './team.facade'; -export * from './user.facade'; +export * from './schedule.facade'; +export * from './spreadsheet.facade'; +export * from './team.facade'; +export * from './user.facade'; diff --git a/libs/data-access/src/lib/application/schedule.facade.ts b/libs/data-access/src/lib/application/schedule.facade.ts index 55acc07..3cbd2d0 100644 --- a/libs/data-access/src/lib/application/schedule.facade.ts +++ b/libs/data-access/src/lib/application/schedule.facade.ts @@ -13,6 +13,7 @@ import { Store } from '../base/store'; interface ScheduleState { data: Schedule[]; + error: string | null; schedule: Schedule | null; filtered: Schedule[]; loading: boolean; @@ -34,6 +35,7 @@ export class ScheduleFacade extends Store { ) { super({ data: [], + error: null, filtered: [], schedule: null, loading: false, @@ -41,36 +43,52 @@ export class ScheduleFacade extends Store { } load() { - this.findAllUseCase.execute().then((data) => this.setState({ data })); + this.catch( + this.findAllUseCase.execute().then((data) => this.setState({ data })) + ); } findSchedule(id: string) { - this.findOneUseCase - .execute(id) - .then((schedule) => this.setState({ schedule })); + this.catch( + this.findOneUseCase + .execute(id) + .then((schedule) => this.setState({ schedule })) + ); } findSchedules(...ids: string[]) { - this.findManyUseCase - .execute(...ids) - .then((filtered) => this.setState({ filtered })); + this.catch( + this.findManyUseCase + .execute(...ids) + .then((filtered) => this.setState({ filtered })) + ); } createSchedule(schedule: CreateScheduleDto) { - this.createUseCase.execute(schedule).then(() => { - this.setState({ schedule: null }); - this.load(); - }); + this.catch( + this.createUseCase.execute(schedule).then(() => { + this.setState({ schedule: null }); + this.load(); + }) + ); } updateSchedule(schedule: UpdateScheduleDto) { - this.updateUseCase.execute(schedule).then(() => { - this.setState({ schedule: null }); - this.load(); - }); + this.catch( + this.updateUseCase.execute(schedule).then(() => { + this.setState({ schedule: null }); + this.load(); + }) + ); } removeSchedule(id: string) { - this.removeByIdUseCase.execute(id).then(() => this.load()); + this.catch(this.removeByIdUseCase.execute(id).then(() => this.load())); + } + + catch>(promise: T) { + promise.catch((error) => { + this.setState({ error: error.message }); + }); } } diff --git a/libs/data-access/src/lib/application/spreadsheet.facade.ts b/libs/data-access/src/lib/application/spreadsheet.facade.ts index a527efc..ea0b954 100644 --- a/libs/data-access/src/lib/application/spreadsheet.facade.ts +++ b/libs/data-access/src/lib/application/spreadsheet.facade.ts @@ -12,6 +12,7 @@ interface SpreadsheetState { data: SpreadsheetRow[]; loading: boolean; parsed: string; + error: string | null; } export class SpreadsheetFacade extends Store { @@ -27,23 +28,34 @@ export class SpreadsheetFacade extends Store { super({ data: [], parsed: '', + error: null, loading: false, }); } build(value: BuildSpreadsheetDto) { - this.buildUseCase.execute(value).then((data) => { - this.setState({ data }); - }); + this.catch( + this.buildUseCase.execute(value).then((data) => { + this.setState({ data }); + }) + ); } parse(value: ParseSpreadsheetDto) { - this.parseUseCase.execute(value).then((parsed) => { - this.setState({ parsed }); - }); + this.catch( + this.parseUseCase.execute(value).then((parsed) => { + this.setState({ parsed }); + }) + ); } download() { - this.downloadUseCase.execute(this.state.data); + this.catch(this.downloadUseCase.execute(this.state.data)); + } + + catch>(promise: T) { + promise.catch((error) => { + this.setState({ error: error.message }); + }); } } diff --git a/libs/data-access/src/lib/application/team.facade.ts b/libs/data-access/src/lib/application/team.facade.ts index de3dcef..e94a0bc 100644 --- a/libs/data-access/src/lib/application/team.facade.ts +++ b/libs/data-access/src/lib/application/team.facade.ts @@ -13,6 +13,7 @@ import { Store } from '../base/store'; interface TeamState { data: Team[]; team: Team | null; + error: string | null; loading: boolean; } @@ -34,33 +35,48 @@ export class TeamFacade extends Store { super({ data: [], team: null, + error: null, loading: false, }); } load() { - this.findAllUseCase.execute().then((data) => this.setState({ data })); + this.catch( + this.findAllUseCase.execute().then((data) => this.setState({ data })) + ); } findTeam(id: string) { - this.findOneUseCase.execute(id).then((team) => this.setState({ team })); + this.catch( + this.findOneUseCase.execute(id).then((team) => this.setState({ team })) + ); } createTeam(team: CreateTeamDto) { - this.createUseCase.execute(team).then(() => { - this.setState({ team: null }); - this.load(); - }); + this.catch( + this.createUseCase.execute(team).then(() => { + this.setState({ team: null }); + this.load(); + }) + ); } updateTeam(team: UpdateTeamDto) { - this.updateUseCase.execute(team).then(() => { - this.setState({ team: null }); - this.load(); - }); + this.catch( + this.updateUseCase.execute(team).then(() => { + this.setState({ team: null }); + this.load(); + }) + ); } removeTeam(id: string) { - this.removeByIdUseCase.execute(id).then(() => this.load()); + this.catch(this.removeByIdUseCase.execute(id).then(() => this.load())); + } + + catch>(promise: T) { + promise.catch((error) => { + this.setState({ error: error.message }); + }); } } diff --git a/libs/data-access/src/lib/application/user.facade.ts b/libs/data-access/src/lib/application/user.facade.ts index 5b586b6..aca7630 100644 --- a/libs/data-access/src/lib/application/user.facade.ts +++ b/libs/data-access/src/lib/application/user.facade.ts @@ -12,6 +12,7 @@ import { Store } from '../base/store'; interface UserState { data: User[]; + error: string | null; user: User | null; loading: boolean; } @@ -19,6 +20,7 @@ interface UserState { export class UserFacade extends Store { loading$ = this.select((state) => state.loading); user$ = this.select((state) => state.user); + error$ = this.select((state) => state.error); data$ = this.select((state) => state.data); hasNoUsers$ = this.select((state) => { return state.data.length === 0; @@ -34,23 +36,30 @@ export class UserFacade extends Store { super({ data: [], user: null, + error: null, loading: false, }); } load() { - this.findAllUseCase.execute().then((data) => this.setState({ data })); + this.catch( + this.findAllUseCase.execute().then((data) => this.setState({ data })) + ); } findUser(id: string) { - this.findOneUseCase.execute(id).then((user) => this.setState({ user })); + this.catch( + this.findOneUseCase.execute(id).then((user) => this.setState({ user })) + ); } createUser(user: CreateUserDto) { - this.createUseCase.execute(user).then(() => { - this.setState({ user: null }); - this.load(); - }); + this.catch( + this.createUseCase.execute(user).then(() => { + this.setState({ user: null }); + this.load(); + }) + ); } clearUser() { @@ -58,13 +67,21 @@ export class UserFacade extends Store { } updateUser(user: UpdateUserDto) { - this.updateUseCase.execute(user).then(() => { - this.setState({ user: null }); - this.load(); - }); + this.catch( + this.updateUseCase.execute(user).then(() => { + this.setState({ user: null }); + this.load(); + }) + ); } removeUser(id: string) { - this.removeByIdUseCase.execute(id).then(() => this.load()); + this.catch(this.removeByIdUseCase.execute(id).then(() => this.load())); + } + + catch>(promise: T) { + promise.catch((error) => { + this.setState({ error: error.message }); + }); } } diff --git a/libs/data-access/src/lib/data-access.spec.ts b/libs/data-access/src/lib/data-access.spec.ts index 8e448fe..edf37c7 100644 --- a/libs/data-access/src/lib/data-access.spec.ts +++ b/libs/data-access/src/lib/data-access.spec.ts @@ -1,11 +1,14 @@ import { Token, inject, register } from '@getlab/util-core'; import { - ScheduleMockRepositoryImpl, + UserMockRepositoryImpl, TeamMockRepositoryImpl, + ScheduleMockRepositoryImpl, } from './infrastructure'; import { + User, Team, Schedule, + UserRepository, TeamRepository, ScheduleRepository, } from '@getlab/domain'; @@ -13,8 +16,17 @@ import { TeamFacade } from './application/team.facade'; import { providers } from './providers'; const TEAM_MOCK_TOKEN = new Token('team.mock'); +const USER_MOCK_TOKEN = new Token('user.mock'); const SCHEDULE_MOCK_TOKEN = new Token('schedule.mock'); +const USERS = [ + { + id: '1', + name: 'Guilherme', + ref: '5345', + }, +]; + const TEAMS = [ { id: '1', @@ -37,6 +49,10 @@ const SCHEDULES: Schedule[] = [ ]; register( + { + for: USER_MOCK_TOKEN, + use: USERS, + }, { for: TEAM_MOCK_TOKEN, use: TEAMS, @@ -45,6 +61,11 @@ register( for: SCHEDULE_MOCK_TOKEN, use: SCHEDULES, }, + { + for: UserRepository, + use: UserMockRepositoryImpl, + add: [USER_MOCK_TOKEN], + }, { for: TeamRepository, use: TeamMockRepositoryImpl, diff --git a/libs/data-access/src/lib/infrastructure/index.ts b/libs/data-access/src/lib/infrastructure/index.ts index 51e566e..ad7b13e 100644 --- a/libs/data-access/src/lib/infrastructure/index.ts +++ b/libs/data-access/src/lib/infrastructure/index.ts @@ -1,11 +1,11 @@ -export * from './mock.repository'; -export * from './schedule-http.repository.impl'; -export * from './schedule-mock.repository.impl'; -export * from './schedule-storage.repository.impl'; -export * from './storage.repository'; -export * from './team-http.repository'; -export * from './team-mock.repository.impl'; -export * from './team-storage.repository.impl'; -export * from './user-http.repository.impl'; -export * from './user-mock.repository.impl'; -export * from './user-storage.repository.impl'; +export * from './mock.repository'; +export * from './schedule-http.repository.impl'; +export * from './schedule-mock.repository.impl'; +export * from './schedule-storage.repository.impl'; +export * from './storage.repository'; +export * from './team-http.repository'; +export * from './team-mock.repository.impl'; +export * from './team-storage.repository.impl'; +export * from './user-http.repository.impl'; +export * from './user-mock.repository.impl'; +export * from './user-storage.repository.impl'; diff --git a/libs/data-access/src/lib/infrastructure/user-storage.repository.impl.ts b/libs/data-access/src/lib/infrastructure/user-storage.repository.impl.ts index 4561ff6..beb2484 100644 --- a/libs/data-access/src/lib/infrastructure/user-storage.repository.impl.ts +++ b/libs/data-access/src/lib/infrastructure/user-storage.repository.impl.ts @@ -44,7 +44,7 @@ export class UserStorageRepositoryImpl } findAll() { - let data = this.read(); + const data = this.read(); return Promise.resolve(data); } diff --git a/libs/domain/src/lib/dtos/index.ts b/libs/domain/src/lib/dtos/index.ts index 6e04b0a..c8c15dd 100644 --- a/libs/domain/src/lib/dtos/index.ts +++ b/libs/domain/src/lib/dtos/index.ts @@ -1,9 +1,9 @@ -export * from './build-spreadsheet.dto'; -export * from './create-schedule.dto'; -export * from './create-team.dto'; -export * from './create-user.dto'; -export * from './date-range.dto'; -export * from './parse-spreadsheet.dto'; -export * from './update-schedule.dto'; -export * from './update-team.dto'; -export * from './update-user.dto'; +export * from './build-spreadsheet.dto'; +export * from './create-schedule.dto'; +export * from './create-team.dto'; +export * from './create-user.dto'; +export * from './date-range.dto'; +export * from './parse-spreadsheet.dto'; +export * from './update-schedule.dto'; +export * from './update-team.dto'; +export * from './update-user.dto'; diff --git a/libs/domain/src/lib/entities/index.ts b/libs/domain/src/lib/entities/index.ts index b0dac06..4611237 100644 --- a/libs/domain/src/lib/entities/index.ts +++ b/libs/domain/src/lib/entities/index.ts @@ -1,5 +1,5 @@ -export * from './schedule'; -export * from './spreadsheet-row'; -export * from './team'; -export * from './time'; -export * from './user'; +export * from './schedule'; +export * from './spreadsheet-row'; +export * from './team'; +export * from './time'; +export * from './user'; diff --git a/libs/domain/src/lib/mapper/index.ts b/libs/domain/src/lib/mapper/index.ts index 5c2a49e..f84607c 100644 --- a/libs/domain/src/lib/mapper/index.ts +++ b/libs/domain/src/lib/mapper/index.ts @@ -1 +1 @@ -export * from './format-row'; +export * from './format-row'; diff --git a/libs/domain/src/lib/usecases/user/index.ts b/libs/domain/src/lib/usecases/user/index.ts index 79f0860..0bb92f0 100644 --- a/libs/domain/src/lib/usecases/user/index.ts +++ b/libs/domain/src/lib/usecases/user/index.ts @@ -1,5 +1,5 @@ -export * from './create-user'; -export * from './find-all-users'; -export * from './find-user-by-id'; -export * from './remove-user-by-id'; -export * from './update-user'; +export * from './create-user'; +export * from './find-all-users'; +export * from './find-user-by-id'; +export * from './remove-user-by-id'; +export * from './update-user'; diff --git a/libs/domain/src/lib/usecases/user/update-user.ts b/libs/domain/src/lib/usecases/user/update-user.ts index 80b643e..418be87 100644 --- a/libs/domain/src/lib/usecases/user/update-user.ts +++ b/libs/domain/src/lib/usecases/user/update-user.ts @@ -11,7 +11,7 @@ export class UpdateUserUseCase implements UseCase { const user = await this.repository.findOne(input.id); return this.repository.updateOne(input.id, { ...user, ...input }); } catch (err) { - throw `Não foi possível alterar a turma ${input.id}`; + throw `Não foi possível alterar o usuário ${input.id}`; } } } diff --git a/libs/feature/src/lib/containers/user/user.container.html b/libs/feature/src/lib/containers/user/user.container.html index 2c9c83e..8dc5cd6 100644 --- a/libs/feature/src/lib/containers/user/user.container.html +++ b/libs/feature/src/lib/containers/user/user.container.html @@ -2,6 +2,8 @@

Usuários

+

{{error}}

+
@@ -47,7 +49,7 @@

Usuários

novalidate [formGroup]="form" class="col min-300" - (submit)="onSubmit('users')" + (submit)="onSubmit('usuarios')" > diff --git a/libs/feature/src/lib/containers/user/user.container.ts b/libs/feature/src/lib/containers/user/user.container.ts index 8819243..46db6ac 100644 --- a/libs/feature/src/lib/containers/user/user.container.ts +++ b/libs/feature/src/lib/containers/user/user.container.ts @@ -6,6 +6,7 @@ import { } from '@getlab/data-access'; import { Component, DestroyRef, OnInit, inject } from '@angular/core'; import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { map, shareReplay, takeUntil } from 'rxjs'; import { ActivatedRoute } from '@angular/router'; import { ConfirmDialog } from '../../components'; @@ -45,18 +46,22 @@ export class UserContainer extends EntityContainer implements OnInit { this.userFacade.clearUser(); }); - this.userFacade.user$.pipe(takeUntil(this.subject)).subscribe((user) => { - if (user) { - this.form.patchValue(user); - this.formEl.scrollIntoView({ - behavior: 'smooth', - }); - } - }); + this.userFacade.user$ + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe((user) => { + if (user) { + this.form.patchValue(user); + this.formEl.scrollIntoView({ + behavior: 'smooth', + }); + } + }); - this.route.params.pipe(takeUntil(this.subject)).subscribe(({ id }) => { - if (id) this.userFacade.findUser(id); - }); + this.route.params + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe(({ id }) => { + if (id) this.userFacade.findUser(id); + }); } @ConfirmDialog({ diff --git a/libs/feature/src/lib/forms/index.ts b/libs/feature/src/lib/forms/index.ts index dbe5e7c..80b17b9 100644 --- a/libs/feature/src/lib/forms/index.ts +++ b/libs/feature/src/lib/forms/index.ts @@ -1,4 +1,4 @@ -export * from './schedule.form'; -export * from './spreadsheet.form'; -export * from './team.form'; -export * from './user.form'; +export * from './schedule.form'; +export * from './spreadsheet.form'; +export * from './team.form'; +export * from './user.form'; diff --git a/libs/feature/src/lib/forms/user.form.ts b/libs/feature/src/lib/forms/user.form.ts index 055bad8..84220c4 100644 --- a/libs/feature/src/lib/forms/user.form.ts +++ b/libs/feature/src/lib/forms/user.form.ts @@ -12,6 +12,6 @@ export class UserForm extends EntityForm { } init() { - this.patchValue({ }); + this.patchValue({}); } } diff --git a/nx.json b/nx.json index 789a2cd..19b2999 100644 --- a/nx.json +++ b/nx.json @@ -1,9 +1,6 @@ { "namedInputs": { - "default": [ - "{projectRoot}/**/*", - "sharedGlobals" - ], + "default": ["{projectRoot}/**/*", "sharedGlobals"], "production": [ "default", "!{projectRoot}/.eslintrc.json", @@ -15,13 +12,8 @@ }, "targetDefaults": { "build": { - "dependsOn": [ - "^build" - ], - "inputs": [ - "production", - "^production" - ] + "dependsOn": ["^build"], + "inputs": ["production", "^production"] }, "lint": { "inputs": [ @@ -31,24 +23,14 @@ ] }, "test": { - "inputs": [ - "default", - "^production", - "{workspaceRoot}/jest.preset.js" - ] + "inputs": ["default", "^production", "{workspaceRoot}/jest.preset.js"] } }, "tasksRunnerOptions": { "default": { "runner": "nx-cloud", "options": { - "cacheableOperations": [ - "build", - "lint", - "test", - "e2e", - "compodoc" - ], + "cacheableOperations": ["build", "lint", "test", "e2e", "compodoc"], "accessToken": "ODNjY2RiMzEtNDA2Yy00NGVmLTk0MmMtMDVlNjFjMGY4YmRifHJlYWQtd3JpdGU=" } }