@koalarx/nest-cli 3.0.2 → 3.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/commands/new-project/index.js +70 -0
- package/commands/new-project/new-project.js +69 -0
- package/index.js +39 -0
- package/package.json +9 -3
- package/templates/startup-project/.prettierrc.json +9 -0
- package/templates/startup-project/eslint.config.mts +85 -0
- package/templates/{root-files-folders → startup-project}/package.json +1 -1
- package/templates/startup-project/prisma/migrations/20250320165043_init/migration.sql +19 -0
- package/templates/startup-project/prisma/migrations/20250320171528_aplicando_map_de_tabelas_e_colunas/migration.sql +35 -0
- package/templates/startup-project/prisma/migrations/20250321190248_incluindo_status_ao_person/migration.sql +2 -0
- package/templates/startup-project/prisma/migrations/20250326185507_incluindo_tabela_de_endereco/migration.sql +19 -0
- package/templates/startup-project/prisma/migrations/20250326195627_aplicando_on_delete_cascade/migration.sql +5 -0
- package/templates/startup-project/prisma/migrations/20250326200821_removendo_ondelete_cascade/migration.sql +5 -0
- package/templates/startup-project/prisma/migrations/migration_lock.toml +3 -0
- package/templates/startup-project/prisma/schema.prisma +39 -0
- package/templates/startup-project/prisma.config.ts +8 -0
- package/templates/startup-project/src/application/mapping/mapping.profile.ts +10 -0
- package/templates/startup-project/src/application/mapping/person.mapping.ts +39 -0
- package/templates/startup-project/src/application/person/common/persist-person.request.ts +28 -0
- package/templates/startup-project/src/application/person/create/create-person.handler.spec.ts +22 -0
- package/templates/startup-project/src/application/person/create/create-person.handler.ts +39 -0
- package/templates/startup-project/src/application/person/create/create-person.request.ts +11 -0
- package/templates/startup-project/src/application/person/create/create-person.response.ts +3 -0
- package/templates/startup-project/src/application/person/create/create-person.validator.ts +19 -0
- package/templates/startup-project/src/application/person/create-person-job/create-person-job.ts +58 -0
- package/templates/startup-project/src/application/person/delete/delete-person.handler.spec.ts +24 -0
- package/templates/startup-project/src/application/person/delete/delete-person.handler.ts +33 -0
- package/templates/startup-project/src/application/person/delete-inative-job/delete-inactive-job.ts +49 -0
- package/templates/startup-project/src/application/person/events/inactive-person/inactive-person-event.ts +3 -0
- package/templates/startup-project/src/application/person/events/inactive-person/inactive-person-handler.ts +27 -0
- package/templates/startup-project/src/application/person/events/person-event.job.ts +11 -0
- package/templates/startup-project/src/application/person/read/read-person.handler.spec.ts +28 -0
- package/templates/startup-project/src/application/person/read/read-person.handler.ts +37 -0
- package/templates/startup-project/src/application/person/read/read-person.response.ts +44 -0
- package/templates/startup-project/src/application/person/read-many/read-many-person.handler.spec.ts +67 -0
- package/templates/startup-project/src/application/person/read-many/read-many-person.handler.ts +47 -0
- package/templates/startup-project/src/application/person/read-many/read-many-person.request.ts +21 -0
- package/templates/startup-project/src/application/person/read-many/read-many-person.response.ts +16 -0
- package/templates/startup-project/src/application/person/read-many/read-many.validator.ts +16 -0
- package/templates/startup-project/src/application/person/update/update-person.handler.spec.ts +47 -0
- package/templates/startup-project/src/application/person/update/update-person.handler.ts +57 -0
- package/templates/startup-project/src/application/person/update/update-person.request.ts +36 -0
- package/templates/startup-project/src/application/person/update/update-person.validator.ts +21 -0
- package/templates/startup-project/src/core/env.ts +6 -0
- package/templates/startup-project/src/domain/dtos/read-many-person.dto.ts +16 -0
- package/templates/startup-project/src/domain/entities/person/person-address.ts +12 -0
- package/templates/startup-project/src/domain/entities/person/person-phone.ts +12 -0
- package/templates/startup-project/src/domain/entities/person/person.ts +24 -0
- package/templates/startup-project/src/domain/repositories/iperson.repository.ts +10 -0
- package/templates/startup-project/src/host/app.module.ts +19 -0
- package/templates/startup-project/src/host/controllers/controller.module.ts +16 -0
- package/templates/startup-project/src/host/controllers/person/create-person.controller.ts +30 -0
- package/templates/startup-project/src/host/controllers/person/delete-person.controller.ts +22 -0
- package/templates/startup-project/src/host/controllers/person/person.controller.e2e-spec.ts +158 -0
- package/templates/startup-project/src/host/controllers/person/person.module.ts +37 -0
- package/templates/startup-project/src/host/controllers/person/read-many-person.controller.ts +29 -0
- package/templates/startup-project/src/host/controllers/person/read-person.controller.ts +26 -0
- package/templates/startup-project/src/host/controllers/person/router.config.ts +9 -0
- package/templates/startup-project/src/host/controllers/person/update-person.controller.ts +30 -0
- package/templates/startup-project/src/host/main.ts +38 -0
- package/templates/startup-project/src/infra/database/db-transaction-context.ts +24 -0
- package/templates/startup-project/src/infra/database/repositories/person.repository.ts +54 -0
- package/templates/startup-project/src/infra/database/repositories/repositories.module.ts +15 -0
- package/templates/startup-project/src/infra/infra.module.ts +8 -0
- package/templates/startup-project/src/test/create-e2e-test-app.ts +27 -0
- package/templates/startup-project/src/test/create-unit-test-app.ts +24 -0
- package/templates/startup-project/src/test/mockup/person/create-person-request.mockup.ts +9 -0
- package/templates/startup-project/src/test/repositories/person.repository.ts +36 -0
- package/templates/startup-project/src/test/setup-e2e.ts +12 -0
- package/templates/startup-project/tsconfig.app.json +8 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/CHANGELOG.md +0 -11
- package/src/commands/new-project/index.ts +0 -99
- package/src/commands/new-project/new-project.ts +0 -91
- package/src/index.ts +0 -51
- package/tsconfig.json +0 -14
- /package/templates/{root-files-folders → startup-project}/.dockerignore +0 -0
- /package/templates/{root-files-folders → startup-project}/.gitattributes +0 -0
- /package/templates/{root-files-folders → startup-project}/.vscode/launch.json +0 -0
- /package/templates/{root-files-folders → startup-project}/.vscode/mcp.json +0 -0
- /package/templates/{root-files-folders → startup-project}/.vscode/settings.json +0 -0
- /package/templates/{root-files-folders → startup-project}/.vscode/tasks.json +0 -0
- /package/templates/{root-files-folders → startup-project}/Dockerfile +0 -0
- /package/templates/{root-files-folders → startup-project}/README.md +0 -0
- /package/templates/{root-files-folders → startup-project}/bunfig.toml +0 -0
- /package/templates/{root-files-folders → startup-project}/nest-cli.json +0 -0
- /package/templates/{root-files-folders → startup-project}/tsconfig.build.json +0 -0
- /package/templates/{root-files-folders → startup-project}/tsconfig.json +0 -0
- /package/templates/{root-files-folders → startup-project}/tsconfig.prisma.json +0 -0
package/templates/startup-project/src/application/person/create-person-job/create-person-job.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { IPersonRepository } from '@/domain/repositories/iperson.repository'
|
|
2
|
+
import {
|
|
3
|
+
CronJobHandlerBase,
|
|
4
|
+
CronJobResponse,
|
|
5
|
+
CronJobSettings,
|
|
6
|
+
} from '@koalarx/nest/core/backgroud-services/cron-service/cron-job.handler.base'
|
|
7
|
+
import { EventQueue } from '@koalarx/nest/core/backgroud-services/event-service/event-queue'
|
|
8
|
+
import { ok } from '@koalarx/nest/core/request-overflow/request-result'
|
|
9
|
+
import { ILoggingService } from '@koalarx/nest/services/logging/ilogging.service'
|
|
10
|
+
import { IRedLockService } from '@koalarx/nest/services/redlock/ired-lock.service'
|
|
11
|
+
import { Injectable } from '@nestjs/common'
|
|
12
|
+
import { CreatePersonHandler } from '../create/create-person.handler'
|
|
13
|
+
import { InactivePersonEvent } from '../events/inactive-person/inactive-person-event'
|
|
14
|
+
import { PersonEventJob } from '../events/person-event.job'
|
|
15
|
+
|
|
16
|
+
@Injectable()
|
|
17
|
+
export class CreatePersonJob extends CronJobHandlerBase {
|
|
18
|
+
constructor(
|
|
19
|
+
redlockService: IRedLockService,
|
|
20
|
+
loggingService: ILoggingService,
|
|
21
|
+
private readonly createPerson: CreatePersonHandler,
|
|
22
|
+
private readonly repository: IPersonRepository,
|
|
23
|
+
) {
|
|
24
|
+
super(redlockService, loggingService)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
protected async settings(): Promise<CronJobSettings> {
|
|
28
|
+
return {
|
|
29
|
+
isActive: true,
|
|
30
|
+
timeInMinutes: 1,
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
protected async run(): Promise<CronJobResponse> {
|
|
35
|
+
const result = await this.createPerson.handle({
|
|
36
|
+
name: 'John Doe',
|
|
37
|
+
phones: [{ phone: '22999999999' }],
|
|
38
|
+
address: { address: 'Street 1' },
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
if (result.isOk()) {
|
|
42
|
+
const person = await this.repository.read(result.value.id)
|
|
43
|
+
|
|
44
|
+
if (person) {
|
|
45
|
+
const jobs = new PersonEventJob()
|
|
46
|
+
jobs.addEvent(new InactivePersonEvent())
|
|
47
|
+
|
|
48
|
+
EventQueue.dispatchEventsForAggregate(jobs._id)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
console.log('Person created with id:', result.value.id)
|
|
52
|
+
} else {
|
|
53
|
+
console.error('Error creating person:', result.value)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return ok(null)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { createUnitTestApp } from '@/test/create-unit-test-app'
|
|
2
|
+
import { createPersonRequestMockup } from '@/test/mockup/person/create-person-request.mockup'
|
|
3
|
+
import { CreatePersonHandler } from '../create/create-person.handler'
|
|
4
|
+
import { DeletePersonHandler } from './delete-person.handler'
|
|
5
|
+
|
|
6
|
+
describe('DeletePersonHandler', () => {
|
|
7
|
+
const app = createUnitTestApp()
|
|
8
|
+
|
|
9
|
+
it('should delete a person', async () => {
|
|
10
|
+
const createResult = await app
|
|
11
|
+
.get(CreatePersonHandler)
|
|
12
|
+
.handle(createPersonRequestMockup)
|
|
13
|
+
|
|
14
|
+
expect(createResult.isOk()).toBeTruthy()
|
|
15
|
+
|
|
16
|
+
if (createResult.isOk()) {
|
|
17
|
+
const result = await app
|
|
18
|
+
.get(DeletePersonHandler)
|
|
19
|
+
.handle(createResult.value.id)
|
|
20
|
+
|
|
21
|
+
expect(result.isOk()).toBeTruthy()
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
})
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { IPersonRepository } from '@/domain/repositories/iperson.repository'
|
|
2
|
+
import { ResourceNotFoundError } from '@koalarx/nest/core/errors/resource-not-found.error'
|
|
3
|
+
import { RequestHandlerBase } from '@koalarx/nest/core/request-overflow/request-handler.base'
|
|
4
|
+
import {
|
|
5
|
+
failure,
|
|
6
|
+
ok,
|
|
7
|
+
RequestResult,
|
|
8
|
+
} from '@koalarx/nest/core/request-overflow/request-result'
|
|
9
|
+
import { Injectable } from '@nestjs/common'
|
|
10
|
+
|
|
11
|
+
@Injectable()
|
|
12
|
+
export class DeletePersonHandler extends RequestHandlerBase<
|
|
13
|
+
number,
|
|
14
|
+
RequestResult<ResourceNotFoundError, null>
|
|
15
|
+
> {
|
|
16
|
+
constructor(private readonly repository: IPersonRepository) {
|
|
17
|
+
super()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async handle(
|
|
21
|
+
id: number,
|
|
22
|
+
): Promise<RequestResult<ResourceNotFoundError, null>> {
|
|
23
|
+
const person = await this.repository.read(id)
|
|
24
|
+
|
|
25
|
+
if (!person) {
|
|
26
|
+
return failure(new ResourceNotFoundError('Pessoa'))
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
await this.repository.delete(id)
|
|
30
|
+
|
|
31
|
+
return ok(null)
|
|
32
|
+
}
|
|
33
|
+
}
|
package/templates/startup-project/src/application/person/delete-inative-job/delete-inactive-job.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { ReadManyPersonDto } from '@/domain/dtos/read-many-person.dto'
|
|
2
|
+
import {
|
|
3
|
+
CronJobHandlerBase,
|
|
4
|
+
CronJobResponse,
|
|
5
|
+
CronJobSettings,
|
|
6
|
+
} from '@koalarx/nest/core/backgroud-services/cron-service/cron-job.handler.base'
|
|
7
|
+
import { ok } from '@koalarx/nest/core/request-overflow/request-result'
|
|
8
|
+
import { ILoggingService } from '@koalarx/nest/services/logging/ilogging.service'
|
|
9
|
+
import { IRedLockService } from '@koalarx/nest/services/redlock/ired-lock.service'
|
|
10
|
+
import { Injectable } from '@nestjs/common'
|
|
11
|
+
import { DeletePersonHandler } from '../delete/delete-person.handler'
|
|
12
|
+
import { ReadManyPersonHandler } from '../read-many/read-many-person.handler'
|
|
13
|
+
|
|
14
|
+
@Injectable()
|
|
15
|
+
export class DeleteInactiveJob extends CronJobHandlerBase {
|
|
16
|
+
constructor(
|
|
17
|
+
redlockService: IRedLockService,
|
|
18
|
+
loggingService: ILoggingService,
|
|
19
|
+
private readonly readManyPerson: ReadManyPersonHandler,
|
|
20
|
+
private readonly deletePerson: DeletePersonHandler,
|
|
21
|
+
) {
|
|
22
|
+
super(redlockService, loggingService)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
protected async settings(): Promise<CronJobSettings> {
|
|
26
|
+
return {
|
|
27
|
+
isActive: true,
|
|
28
|
+
timeInMinutes: 1,
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
protected async run(): Promise<CronJobResponse> {
|
|
33
|
+
const result = await this.readManyPerson.handle(
|
|
34
|
+
new ReadManyPersonDto({ active: false }),
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
if (result.isOk()) {
|
|
38
|
+
for (const person of result.value.items) {
|
|
39
|
+
await this.deletePerson.handle(person.id)
|
|
40
|
+
|
|
41
|
+
console.log('Person with id was deleted:', person.id)
|
|
42
|
+
}
|
|
43
|
+
} else {
|
|
44
|
+
console.error('Error to search inactive people:', result.value)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return ok(null)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ReadManyPersonDto } from '@/domain/dtos/read-many-person.dto'
|
|
2
|
+
import { IPersonRepository } from '@/domain/repositories/iperson.repository'
|
|
3
|
+
import { EventHandlerBase } from '@koalarx/nest/core/backgroud-services/event-service/event-handler.base'
|
|
4
|
+
import { Injectable } from '@nestjs/common'
|
|
5
|
+
import { InactivePersonEvent } from './inactive-person-event'
|
|
6
|
+
|
|
7
|
+
@Injectable()
|
|
8
|
+
export class InactivePersonHandler extends EventHandlerBase {
|
|
9
|
+
constructor(private readonly repository: IPersonRepository) {
|
|
10
|
+
super(InactivePersonEvent)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async handleEvent(): Promise<void> {
|
|
14
|
+
const result = await this.repository.readMany(
|
|
15
|
+
new ReadManyPersonDto({ active: true }),
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
for (const person of result.items) {
|
|
19
|
+
person.active = false
|
|
20
|
+
await this.repository.save(person)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
console.log(
|
|
24
|
+
'InactivePersonHandler: Registros ativos inativados com sucesso!',
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Person } from '@/domain/entities/person/person'
|
|
2
|
+
import { EventHandlerBase } from '@koalarx/nest/core/backgroud-services/event-service/event-handler.base'
|
|
3
|
+
import { EventJob } from '@koalarx/nest/core/backgroud-services/event-service/event-job'
|
|
4
|
+
import { Type } from '@nestjs/common'
|
|
5
|
+
import { InactivePersonHandler } from './inactive-person/inactive-person-handler'
|
|
6
|
+
|
|
7
|
+
export class PersonEventJob extends EventJob<Person> {
|
|
8
|
+
defineHandlers(): Type<EventHandlerBase>[] {
|
|
9
|
+
return [InactivePersonHandler]
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { createUnitTestApp } from '@/test/create-unit-test-app'
|
|
2
|
+
import { createPersonRequestMockup } from '@/test/mockup/person/create-person-request.mockup'
|
|
3
|
+
import { CreatePersonHandler } from '../create/create-person.handler'
|
|
4
|
+
import { ReadPersonHandler } from './read-person.handler'
|
|
5
|
+
|
|
6
|
+
describe('ReadPersonHandler', () => {
|
|
7
|
+
const app = createUnitTestApp()
|
|
8
|
+
|
|
9
|
+
it('should get a person by id', async () => {
|
|
10
|
+
const createResult = await app
|
|
11
|
+
.get(CreatePersonHandler)
|
|
12
|
+
.handle(createPersonRequestMockup)
|
|
13
|
+
|
|
14
|
+
expect(createResult.isOk()).toBeTruthy()
|
|
15
|
+
|
|
16
|
+
if (createResult.isOk()) {
|
|
17
|
+
const result = await app
|
|
18
|
+
.get(ReadPersonHandler)
|
|
19
|
+
.handle(createResult.value.id)
|
|
20
|
+
|
|
21
|
+
expect(result.isOk()).toBeTruthy()
|
|
22
|
+
|
|
23
|
+
if (result.isOk()) {
|
|
24
|
+
expect(result.value.id).toBe(createResult.value.id)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
})
|
|
28
|
+
})
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Person } from '@/domain/entities/person/person'
|
|
2
|
+
import { IPersonRepository } from '@/domain/repositories/iperson.repository'
|
|
3
|
+
import { ResourceNotFoundError } from '@koalarx/nest/core/errors/resource-not-found.error'
|
|
4
|
+
import { AutoMappingService } from '@koalarx/nest/core/mapping/auto-mapping.service'
|
|
5
|
+
import { RequestHandlerBase } from '@koalarx/nest/core/request-overflow/request-handler.base'
|
|
6
|
+
import {
|
|
7
|
+
failure,
|
|
8
|
+
ok,
|
|
9
|
+
RequestResult,
|
|
10
|
+
} from '@koalarx/nest/core/request-overflow/request-result'
|
|
11
|
+
import { Injectable } from '@nestjs/common'
|
|
12
|
+
import { ReadPersonResponse } from './read-person.response'
|
|
13
|
+
|
|
14
|
+
@Injectable()
|
|
15
|
+
export class ReadPersonHandler extends RequestHandlerBase<
|
|
16
|
+
number,
|
|
17
|
+
RequestResult<ResourceNotFoundError, ReadPersonResponse>
|
|
18
|
+
> {
|
|
19
|
+
constructor(
|
|
20
|
+
private readonly mapper: AutoMappingService,
|
|
21
|
+
private readonly repository: IPersonRepository,
|
|
22
|
+
) {
|
|
23
|
+
super()
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async handle(
|
|
27
|
+
id: number,
|
|
28
|
+
): Promise<RequestResult<ResourceNotFoundError, ReadPersonResponse>> {
|
|
29
|
+
const person = await this.repository.read(id)
|
|
30
|
+
|
|
31
|
+
if (!person) {
|
|
32
|
+
return failure(new ResourceNotFoundError('Pessoa'))
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return ok(this.mapper.map(person, Person, ReadPersonResponse))
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { AutoMap } from '@koalarx/nest/core/mapping/auto-mapping.decorator'
|
|
2
|
+
import { ApiProperty } from '@nestjs/swagger'
|
|
3
|
+
|
|
4
|
+
export class ReadPersonAddressResponse {
|
|
5
|
+
@ApiProperty()
|
|
6
|
+
@AutoMap()
|
|
7
|
+
id: number
|
|
8
|
+
|
|
9
|
+
@ApiProperty({ example: 'Street 1' })
|
|
10
|
+
@AutoMap()
|
|
11
|
+
address: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class ReadPersonPhoneResponse {
|
|
15
|
+
@ApiProperty()
|
|
16
|
+
@AutoMap()
|
|
17
|
+
id: number
|
|
18
|
+
|
|
19
|
+
@ApiProperty({ example: '22999999999' })
|
|
20
|
+
@AutoMap()
|
|
21
|
+
phone: string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class ReadPersonResponse {
|
|
25
|
+
@ApiProperty()
|
|
26
|
+
@AutoMap()
|
|
27
|
+
id: number
|
|
28
|
+
|
|
29
|
+
@ApiProperty({ example: 'John Doe' })
|
|
30
|
+
@AutoMap()
|
|
31
|
+
name: string
|
|
32
|
+
|
|
33
|
+
@ApiProperty({ type: [ReadPersonPhoneResponse] })
|
|
34
|
+
@AutoMap({ type: () => ReadPersonPhoneResponse, isArray: true })
|
|
35
|
+
phones: Array<ReadPersonPhoneResponse>
|
|
36
|
+
|
|
37
|
+
@ApiProperty({ type: ReadPersonAddressResponse })
|
|
38
|
+
@AutoMap({ type: () => ReadPersonAddressResponse })
|
|
39
|
+
address: ReadPersonAddressResponse
|
|
40
|
+
|
|
41
|
+
@ApiProperty()
|
|
42
|
+
@AutoMap()
|
|
43
|
+
active: boolean
|
|
44
|
+
}
|
package/templates/startup-project/src/application/person/read-many/read-many-person.handler.spec.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { createUnitTestApp } from '@/test/create-unit-test-app'
|
|
2
|
+
import { createPersonRequestMockup } from '@/test/mockup/person/create-person-request.mockup'
|
|
3
|
+
import { RequestResult } from '@koalarx/nest/core/request-overflow/request-result'
|
|
4
|
+
import { CreatePersonHandler } from '../create/create-person.handler'
|
|
5
|
+
import { CreatePersonResponse } from '../create/create-person.response'
|
|
6
|
+
import { ReadManyPersonHandler } from './read-many-person.handler'
|
|
7
|
+
import { ReadManyPersonRequest } from './read-many-person.request'
|
|
8
|
+
|
|
9
|
+
describe('ReadManyPersonHandler', () => {
|
|
10
|
+
const app = createUnitTestApp()
|
|
11
|
+
const person = createPersonRequestMockup
|
|
12
|
+
|
|
13
|
+
let personId: number
|
|
14
|
+
let createResult: RequestResult<Error, CreatePersonResponse>
|
|
15
|
+
|
|
16
|
+
beforeAll(async () => {
|
|
17
|
+
createResult = await app
|
|
18
|
+
.get(CreatePersonHandler)
|
|
19
|
+
.handle(createPersonRequestMockup)
|
|
20
|
+
|
|
21
|
+
expect(createResult.isOk()).toBeTruthy()
|
|
22
|
+
|
|
23
|
+
if (createResult.isOk()) {
|
|
24
|
+
personId = createResult.value.id
|
|
25
|
+
}
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
it('should get all persons', async () => {
|
|
29
|
+
const result = await app
|
|
30
|
+
.get(ReadManyPersonHandler)
|
|
31
|
+
.handle(new ReadManyPersonRequest())
|
|
32
|
+
|
|
33
|
+
expect(result.isOk()).toBeTruthy()
|
|
34
|
+
|
|
35
|
+
if (result.isOk()) {
|
|
36
|
+
expect(result.value.items).toHaveLength(1)
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it('should get persons by name', async () => {
|
|
41
|
+
const result = await app.get(ReadManyPersonHandler).handle(
|
|
42
|
+
new ReadManyPersonRequest({
|
|
43
|
+
name: person.name,
|
|
44
|
+
}),
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
expect(result.isOk()).toBeTruthy()
|
|
48
|
+
|
|
49
|
+
if (result.isOk()) {
|
|
50
|
+
expect(result.value.items[0].name).toBe(person.name)
|
|
51
|
+
expect(result.value.items).toHaveLength(1)
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
it('should get persons by status', async () => {
|
|
56
|
+
const result = await app.get(ReadManyPersonHandler).handle(
|
|
57
|
+
new ReadManyPersonRequest({
|
|
58
|
+
active: true,
|
|
59
|
+
}),
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
expect(result.value).toEqual({
|
|
63
|
+
items: [],
|
|
64
|
+
count: 0,
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
})
|
package/templates/startup-project/src/application/person/read-many/read-many-person.handler.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { ReadManyPersonDto } from '@/domain/dtos/read-many-person.dto'
|
|
2
|
+
import { Person } from '@/domain/entities/person/person'
|
|
3
|
+
import { IPersonRepository } from '@/domain/repositories/iperson.repository'
|
|
4
|
+
import { ResourceNotFoundError } from '@koalarx/nest/core/errors/resource-not-found.error'
|
|
5
|
+
import { AutoMappingService } from '@koalarx/nest/core/mapping/auto-mapping.service'
|
|
6
|
+
import { RequestHandlerBase } from '@koalarx/nest/core/request-overflow/request-handler.base'
|
|
7
|
+
import {
|
|
8
|
+
ok,
|
|
9
|
+
RequestResult,
|
|
10
|
+
} from '@koalarx/nest/core/request-overflow/request-result'
|
|
11
|
+
import { Injectable } from '@nestjs/common'
|
|
12
|
+
import { ReadPersonResponse } from '../read/read-person.response'
|
|
13
|
+
import { ReadManyPersonRequest } from './read-many-person.request'
|
|
14
|
+
import { ReadManyPersonResponse } from './read-many-person.response'
|
|
15
|
+
import { ReadManyPersonValidator } from './read-many.validator'
|
|
16
|
+
|
|
17
|
+
@Injectable()
|
|
18
|
+
export class ReadManyPersonHandler extends RequestHandlerBase<
|
|
19
|
+
ReadManyPersonRequest,
|
|
20
|
+
RequestResult<ResourceNotFoundError, ReadManyPersonResponse>
|
|
21
|
+
> {
|
|
22
|
+
constructor(
|
|
23
|
+
private readonly mapper: AutoMappingService,
|
|
24
|
+
private readonly repository: IPersonRepository,
|
|
25
|
+
) {
|
|
26
|
+
super()
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async handle(
|
|
30
|
+
query: ReadManyPersonRequest,
|
|
31
|
+
): Promise<RequestResult<ResourceNotFoundError, ReadManyPersonResponse>> {
|
|
32
|
+
const listOfPerson = await this.repository.readMany(
|
|
33
|
+
this.mapper.map(
|
|
34
|
+
new ReadManyPersonValidator(query).validate(),
|
|
35
|
+
ReadManyPersonRequest,
|
|
36
|
+
ReadManyPersonDto,
|
|
37
|
+
),
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
return ok({
|
|
41
|
+
...listOfPerson,
|
|
42
|
+
items: listOfPerson.items.map((person) =>
|
|
43
|
+
this.mapper.map(person, Person, ReadPersonResponse),
|
|
44
|
+
),
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
}
|
package/templates/startup-project/src/application/person/read-many/read-many-person.request.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PaginatedRequestProps,
|
|
3
|
+
PaginationRequest,
|
|
4
|
+
} from '@koalarx/nest/core/controllers/pagination.request'
|
|
5
|
+
import { AutoMap } from '@koalarx/nest/core/mapping/auto-mapping.decorator'
|
|
6
|
+
import { ApiProperty } from '@nestjs/swagger'
|
|
7
|
+
|
|
8
|
+
export class ReadManyPersonRequest extends PaginationRequest {
|
|
9
|
+
@ApiProperty({ required: false })
|
|
10
|
+
@AutoMap()
|
|
11
|
+
name?: string
|
|
12
|
+
|
|
13
|
+
@ApiProperty({ required: false })
|
|
14
|
+
@AutoMap()
|
|
15
|
+
active?: boolean
|
|
16
|
+
|
|
17
|
+
constructor(props?: PaginatedRequestProps<ReadManyPersonRequest>) {
|
|
18
|
+
super()
|
|
19
|
+
Object.assign(this, props)
|
|
20
|
+
}
|
|
21
|
+
}
|
package/templates/startup-project/src/application/person/read-many/read-many-person.response.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ListResponse } from '@koalarx/nest/core'
|
|
2
|
+
import { AutoMap } from '@koalarx/nest/core/mapping/auto-mapping.decorator'
|
|
3
|
+
import { ApiProperty } from '@nestjs/swagger'
|
|
4
|
+
import { ReadPersonResponse } from '../read/read-person.response'
|
|
5
|
+
|
|
6
|
+
export class ReadManyPersonResponse
|
|
7
|
+
implements ListResponse<ReadPersonResponse>
|
|
8
|
+
{
|
|
9
|
+
@ApiProperty({ type: [ReadPersonResponse] })
|
|
10
|
+
@AutoMap()
|
|
11
|
+
items: ReadPersonResponse[]
|
|
12
|
+
|
|
13
|
+
@ApiProperty()
|
|
14
|
+
@AutoMap()
|
|
15
|
+
count: number
|
|
16
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { booleanSchema } from '@koalarx/nest/core/controllers/schemas/boolean.schema'
|
|
2
|
+
import { LIST_QUERY_SCHEMA } from '@koalarx/nest/core/controllers/schemas/list-query.schema'
|
|
3
|
+
import { RequestValidatorBase } from '@koalarx/nest/core/request-overflow/request-validator.base'
|
|
4
|
+
import { z, ZodType, ZodTypeDef } from 'zod'
|
|
5
|
+
import { ReadManyPersonRequest } from './read-many-person.request'
|
|
6
|
+
|
|
7
|
+
export class ReadManyPersonValidator extends RequestValidatorBase<ReadManyPersonRequest> {
|
|
8
|
+
protected get schema(): ZodType<any, ZodTypeDef, any> {
|
|
9
|
+
return LIST_QUERY_SCHEMA.merge(
|
|
10
|
+
z.object({
|
|
11
|
+
name: z.string().optional().nullable(),
|
|
12
|
+
active: booleanSchema().optional().nullable(),
|
|
13
|
+
}),
|
|
14
|
+
)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { createUnitTestApp } from '@/test/create-unit-test-app'
|
|
2
|
+
import { createPersonRequestMockup } from '@/test/mockup/person/create-person-request.mockup'
|
|
3
|
+
import { CreatePersonHandler } from '../create/create-person.handler'
|
|
4
|
+
import { ReadPersonHandler } from '../read/read-person.handler'
|
|
5
|
+
import { UpdatePersonHandler } from './update-person.handler'
|
|
6
|
+
|
|
7
|
+
describe('UpdatePersonHandler', () => {
|
|
8
|
+
const app = createUnitTestApp()
|
|
9
|
+
|
|
10
|
+
it('should update a person by id', async () => {
|
|
11
|
+
const person = createPersonRequestMockup
|
|
12
|
+
const createResult = await app
|
|
13
|
+
.get(CreatePersonHandler)
|
|
14
|
+
.handle(createPersonRequestMockup)
|
|
15
|
+
|
|
16
|
+
expect(createResult.isOk()).toBeTruthy()
|
|
17
|
+
|
|
18
|
+
if (createResult.isOk()) {
|
|
19
|
+
const updateResult = await app.get(UpdatePersonHandler).handle({
|
|
20
|
+
id: createResult.value.id,
|
|
21
|
+
data: {
|
|
22
|
+
...person,
|
|
23
|
+
address: {
|
|
24
|
+
id: 1,
|
|
25
|
+
...person.address,
|
|
26
|
+
},
|
|
27
|
+
active: true,
|
|
28
|
+
},
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
expect(updateResult.isOk()).toBeTruthy()
|
|
32
|
+
|
|
33
|
+
const result = await app
|
|
34
|
+
.get(ReadPersonHandler)
|
|
35
|
+
.handle(createResult.value.id)
|
|
36
|
+
|
|
37
|
+
expect(result.isOk()).toBeTruthy()
|
|
38
|
+
|
|
39
|
+
if (result.isOk()) {
|
|
40
|
+
expect(result.value.name).toEqual(person.name)
|
|
41
|
+
expect(result.value.active).toEqual(true)
|
|
42
|
+
expect(result.value.address.address).toEqual(person.address.address)
|
|
43
|
+
expect(result.value.phones[0].phone).toEqual(person.phones[0].phone)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
})
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Person } from '@/domain/entities/person/person'
|
|
2
|
+
import { IPersonRepository } from '@/domain/repositories/iperson.repository'
|
|
3
|
+
import { ResourceNotFoundError } from '@koalarx/nest/core/errors/resource-not-found.error'
|
|
4
|
+
import { AutoMappingService } from '@koalarx/nest/core/mapping/auto-mapping.service'
|
|
5
|
+
import { RequestHandlerBase } from '@koalarx/nest/core/request-overflow/request-handler.base'
|
|
6
|
+
import {
|
|
7
|
+
failure,
|
|
8
|
+
ok,
|
|
9
|
+
RequestResult,
|
|
10
|
+
} from '@koalarx/nest/core/request-overflow/request-result'
|
|
11
|
+
import { Injectable } from '@nestjs/common'
|
|
12
|
+
import { UpdatePersonRequest } from './update-person.request'
|
|
13
|
+
import { UpdatePersonValidator } from './update-person.validator'
|
|
14
|
+
|
|
15
|
+
type UpdatePersonHandleRequest = {
|
|
16
|
+
id: number
|
|
17
|
+
data: UpdatePersonRequest
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@Injectable()
|
|
21
|
+
export class UpdatePersonHandler extends RequestHandlerBase<
|
|
22
|
+
UpdatePersonHandleRequest,
|
|
23
|
+
RequestResult<ResourceNotFoundError, null>
|
|
24
|
+
> {
|
|
25
|
+
constructor(
|
|
26
|
+
private readonly mapper: AutoMappingService,
|
|
27
|
+
private readonly repository: IPersonRepository,
|
|
28
|
+
) {
|
|
29
|
+
super()
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async handle({
|
|
33
|
+
id,
|
|
34
|
+
data,
|
|
35
|
+
}: UpdatePersonHandleRequest): Promise<RequestResult<Error, null>> {
|
|
36
|
+
const personInBd = await this.repository.read(id)
|
|
37
|
+
|
|
38
|
+
if (!personInBd) {
|
|
39
|
+
return failure(new ResourceNotFoundError('Person'))
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const person = this.mapper.map(
|
|
43
|
+
new UpdatePersonValidator(data).validate(),
|
|
44
|
+
UpdatePersonRequest,
|
|
45
|
+
Person,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
personInBd.name = person.name
|
|
49
|
+
personInBd.active = person.active
|
|
50
|
+
personInBd.address.address = person.address.address
|
|
51
|
+
personInBd.phones.update(person.phones.toArray())
|
|
52
|
+
|
|
53
|
+
await this.repository.save(personInBd)
|
|
54
|
+
|
|
55
|
+
return ok(null)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { AutoMap } from '@koalarx/nest/core/mapping/auto-mapping.decorator'
|
|
2
|
+
import { ApiProperty } from '@nestjs/swagger'
|
|
3
|
+
import {
|
|
4
|
+
PersistPersonAddressRequest,
|
|
5
|
+
PersistPersonPhoneRequest,
|
|
6
|
+
} from '../common/persist-person.request'
|
|
7
|
+
|
|
8
|
+
export class UpdatePersonAddressRequest extends PersistPersonAddressRequest {
|
|
9
|
+
@ApiProperty()
|
|
10
|
+
@AutoMap()
|
|
11
|
+
id: number
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class UpdatePersonPhoneRequest extends PersistPersonPhoneRequest {
|
|
15
|
+
@ApiProperty({ required: false })
|
|
16
|
+
@AutoMap()
|
|
17
|
+
id?: number
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class UpdatePersonRequest {
|
|
21
|
+
@ApiProperty({ example: 'Mark Willians' })
|
|
22
|
+
@AutoMap()
|
|
23
|
+
name: string
|
|
24
|
+
|
|
25
|
+
@ApiProperty({ example: false })
|
|
26
|
+
@AutoMap()
|
|
27
|
+
active: boolean
|
|
28
|
+
|
|
29
|
+
@ApiProperty({ type: [UpdatePersonPhoneRequest] })
|
|
30
|
+
@AutoMap({ type: () => UpdatePersonPhoneRequest, isArray: true })
|
|
31
|
+
phones: Array<UpdatePersonPhoneRequest>
|
|
32
|
+
|
|
33
|
+
@ApiProperty({ type: UpdatePersonAddressRequest })
|
|
34
|
+
@AutoMap({ type: () => UpdatePersonAddressRequest })
|
|
35
|
+
address: UpdatePersonAddressRequest
|
|
36
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { RequestValidatorBase } from '@koalarx/nest/core/request-overflow/request-validator.base'
|
|
2
|
+
import { z, ZodType, ZodTypeDef } from 'zod'
|
|
3
|
+
import { UpdatePersonRequest } from './update-person.request'
|
|
4
|
+
|
|
5
|
+
export class UpdatePersonValidator extends RequestValidatorBase<UpdatePersonRequest> {
|
|
6
|
+
protected get schema(): ZodType<any, ZodTypeDef, any> {
|
|
7
|
+
return z.object({
|
|
8
|
+
name: z.string(),
|
|
9
|
+
phones: z.array(
|
|
10
|
+
z.object({
|
|
11
|
+
id: z.number().nullable().optional(),
|
|
12
|
+
phone: z.string(),
|
|
13
|
+
}),
|
|
14
|
+
),
|
|
15
|
+
address: z.object({
|
|
16
|
+
id: z.number(),
|
|
17
|
+
address: z.string(),
|
|
18
|
+
}),
|
|
19
|
+
})
|
|
20
|
+
}
|
|
21
|
+
}
|