jarvis-arch-hexagonal-gen 1.0.12 → 1.0.14
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/dist/plugins/bundles/resource/manifest.json +1 -1
- package/dist/plugins/repository/templates/interface.ejs +1 -1
- package/dist/plugins/repository/templates/repository.ejs +1 -1
- package/dist/plugins/tests/manifest.json +5 -5
- package/dist/plugins/tests/templates/usecases/create.spec.ejs +35 -0
- package/dist/plugins/tests/templates/usecases/delete.spec.ejs +34 -0
- package/dist/plugins/tests/templates/usecases/find-all.spec.ejs +51 -0
- package/dist/plugins/tests/templates/usecases/find-by-id.spec.ejs +48 -0
- package/dist/plugins/tests/templates/usecases/update.spec.ejs +39 -0
- package/dist/plugins/typeorm-entity/hooks.js +1 -0
- package/dist/plugins/typeorm-entity/manifest.json +12 -0
- package/dist/plugins/typeorm-entity/templates/entity.ejs +35 -0
- package/dist/plugins/usecases/templates/create.ejs +1 -1
- package/dist/plugins/usecases/templates/find-all.ejs +1 -1
- package/dist/plugins/usecases/templates/find-by-id.ejs +1 -1
- package/dist/plugins/usecases/templates/update.ejs +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "resource",
|
|
3
3
|
"description": "Gera um CRUD completo",
|
|
4
|
-
"dependencies": ["dto", "controller", "repository", "usecases", "routes", "tests"],
|
|
4
|
+
"dependencies": ["dto", "controller", "repository", "usecases", "routes", "typeorm-entity", "tests"],
|
|
5
5
|
"files": []
|
|
6
6
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { <%= entity %> } from '
|
|
1
|
+
import { <%= entity %> } from '../../../../../adapters/outbound/persistence/typeorm/entities/<%= entityLower %>.entity';
|
|
2
2
|
|
|
3
3
|
export interface I<%= entity %>Repository {
|
|
4
4
|
create(data: Omit<<%= entity %>, 'id'>): Promise<<%= entity %>>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { <%= entity %> } from '../entities/<%= entityLower %>.entity';
|
|
2
|
-
import { I<%= entity %>Repository } from '../../../../../core/ports/outbound/repositories/i<%=
|
|
2
|
+
import { I<%= entity %>Repository } from '../../../../../core/ports/outbound/repositories/i<%= entityLower %>.repository';
|
|
3
3
|
|
|
4
4
|
export class <%= entity %>Repository implements I<%= entity %>Repository {
|
|
5
5
|
private items: <%= entity %>[] = [];
|
|
@@ -4,23 +4,23 @@
|
|
|
4
4
|
"dependencies": [],
|
|
5
5
|
"files": [
|
|
6
6
|
{
|
|
7
|
-
"template": "
|
|
7
|
+
"template": "usecases/create.spec.ejs",
|
|
8
8
|
"output": "tests/unit/<%= entityLower %>/create-<%= entityLower %>.usecase.spec.ts"
|
|
9
9
|
},
|
|
10
10
|
{
|
|
11
|
-
"template": "
|
|
11
|
+
"template": "usecases/update.spec.ejs",
|
|
12
12
|
"output": "tests/unit/<%= entityLower %>/update-<%= entityLower %>.usecase.spec.ts"
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
|
-
"template": "
|
|
15
|
+
"template": "usecases/delete.spec.ejs",
|
|
16
16
|
"output": "tests/unit/<%= entityLower %>/delete-<%= entityLower %>.usecase.spec.ts"
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
|
-
"template": "
|
|
19
|
+
"template": "usecases/find-by-id.spec.ejs",
|
|
20
20
|
"output": "tests/unit/<%= entityLower %>/find-<%= entityLower %>-by-id.usecase.spec.ts"
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
|
-
"template": "
|
|
23
|
+
"template": "usecases/find-all.spec.ejs",
|
|
24
24
|
"output": "tests/unit/<%= entityLower %>/find-all-<%= pluralLower %>.usecase.spec.ts"
|
|
25
25
|
},
|
|
26
26
|
{
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Create<%= entity %>UseCase } from '../../../src/core/usecases/<%= entityLower %>/create-<%= entityLower %>.usecase';
|
|
2
|
+
import { I<%= entity %>Repository } from '../../../src/core/ports/outbound/repositories/i<%= entityLower %>.repository';
|
|
3
|
+
|
|
4
|
+
describe('Create<%= entity %>UseCase', () => {
|
|
5
|
+
let useCase: Create<%= entity %>UseCase;
|
|
6
|
+
let mockRepo: jest.Mocked<I<%= entity %>Repository>;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
mockRepo = {
|
|
10
|
+
create: jest.fn(),
|
|
11
|
+
update: jest.fn(),
|
|
12
|
+
delete: jest.fn(),
|
|
13
|
+
findById: jest.fn(),
|
|
14
|
+
findAll: jest.fn(),
|
|
15
|
+
};
|
|
16
|
+
useCase = new Create<%= entity %>UseCase(mockRepo);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should create a new <%= entityLower %> successfully', async () => {
|
|
20
|
+
const input = {
|
|
21
|
+
<% columns.filter(c => !c.primary).forEach(c => { %> <%= c.name %>: '<%= c.type === 'number' ? 123 : 'test' %>',
|
|
22
|
+
<% }) %> };
|
|
23
|
+
const expected = { id: 1, ...input };
|
|
24
|
+
mockRepo.create.mockResolvedValue(expected);
|
|
25
|
+
|
|
26
|
+
const result = await useCase.execute(input);
|
|
27
|
+
expect(result).toEqual(expected);
|
|
28
|
+
expect(mockRepo.create).toHaveBeenCalledWith(input);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should throw error if repository fails', async () => {
|
|
32
|
+
mockRepo.create.mockRejectedValue(new Error('Database error'));
|
|
33
|
+
await expect(useCase.execute({})).rejects.toThrow('Database error');
|
|
34
|
+
});
|
|
35
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Delete<%= entity %>UseCase } from '../../../src/core/usecases/<%= entityLower %>/delete-<%= entityLower %>.usecase';
|
|
2
|
+
import { I<%= entity %>Repository } from '../../../src/core/ports/outbound/repositories/i<%= entityLower %>.repository';
|
|
3
|
+
|
|
4
|
+
describe('Delete<%= entity %>UseCase', () => {
|
|
5
|
+
let useCase: Delete<%= entity %>UseCase;
|
|
6
|
+
let mockRepo: jest.Mocked<I<%= entity %>Repository>;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
mockRepo = {
|
|
10
|
+
create: jest.fn(),
|
|
11
|
+
update: jest.fn(),
|
|
12
|
+
delete: jest.fn(),
|
|
13
|
+
findById: jest.fn(),
|
|
14
|
+
findAll: jest.fn(),
|
|
15
|
+
};
|
|
16
|
+
useCase = new Delete<%= entity %>UseCase(mockRepo);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should delete an existing <%= entityLower %> successfully', async () => {
|
|
20
|
+
const id = 1;
|
|
21
|
+
mockRepo.delete.mockResolvedValue(undefined);
|
|
22
|
+
|
|
23
|
+
await expect(useCase.execute(id)).resolves.toBeUndefined();
|
|
24
|
+
expect(mockRepo.delete).toHaveBeenCalledWith(id);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('should throw error if repository fails', async () => {
|
|
28
|
+
const id = 999;
|
|
29
|
+
mockRepo.delete.mockRejectedValue(new Error('Delete failed'));
|
|
30
|
+
|
|
31
|
+
await expect(useCase.execute(id)).rejects.toThrow('Delete failed');
|
|
32
|
+
expect(mockRepo.delete).toHaveBeenCalledWith(id);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { FindAll<%= entity %>UseCase } from '../../../src/core/usecases/<%= entityLower %>/find-all-<%= entityLower %>.usecase';
|
|
2
|
+
import { I<%= entity %>Repository } from '../../../src/core/ports/outbound/repositories/i<%= entityLower %>.repository';
|
|
3
|
+
|
|
4
|
+
describe('FindAll<%= entity %>UseCase', () => {
|
|
5
|
+
let useCase: FindAll<%= entity %>UseCase;
|
|
6
|
+
let mockRepo: jest.Mocked<I<%= entity %>Repository>;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
mockRepo = {
|
|
10
|
+
create: jest.fn(),
|
|
11
|
+
update: jest.fn(),
|
|
12
|
+
delete: jest.fn(),
|
|
13
|
+
findById: jest.fn(),
|
|
14
|
+
findAll: jest.fn(),
|
|
15
|
+
};
|
|
16
|
+
useCase = new FindAll<%= entity %>UseCase(mockRepo);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should return an array of <%= entityLower %>s', async () => {
|
|
20
|
+
const expected = [
|
|
21
|
+
{
|
|
22
|
+
id: 1,
|
|
23
|
+
<% columns.filter(c => !c.primary).forEach(c => { %> <%= c.name %>: '<%= c.type === 'number' ? 123 : 'test1' %>',
|
|
24
|
+
<% }) %> },
|
|
25
|
+
{
|
|
26
|
+
id: 2,
|
|
27
|
+
<% columns.filter(c => !c.primary).forEach(c => { %> <%= c.name %>: '<%= c.type === 'number' ? 456 : 'test2' %>',
|
|
28
|
+
<% }) %> },
|
|
29
|
+
];
|
|
30
|
+
mockRepo.findAll.mockResolvedValue(expected);
|
|
31
|
+
|
|
32
|
+
const result = await useCase.execute();
|
|
33
|
+
expect(result).toEqual(expected);
|
|
34
|
+
expect(mockRepo.findAll).toHaveBeenCalled();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should return empty array when no records found', async () => {
|
|
38
|
+
mockRepo.findAll.mockResolvedValue([]);
|
|
39
|
+
|
|
40
|
+
const result = await useCase.execute();
|
|
41
|
+
expect(result).toEqual([]);
|
|
42
|
+
expect(mockRepo.findAll).toHaveBeenCalled();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('should throw error if repository fails', async () => {
|
|
46
|
+
mockRepo.findAll.mockRejectedValue(new Error('Database error'));
|
|
47
|
+
|
|
48
|
+
await expect(useCase.execute()).rejects.toThrow('Database error');
|
|
49
|
+
expect(mockRepo.findAll).toHaveBeenCalled();
|
|
50
|
+
});
|
|
51
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Find<%= entity %>ByIdUseCase } from '../../../src/core/usecases/<%= entityLower %>/find-<%= entityLower %>-by-id.usecase';
|
|
2
|
+
import { I<%= entity %>Repository } from '../../../src/core/ports/outbound/repositories/i<%= entityLower %>.repository';
|
|
3
|
+
|
|
4
|
+
describe('Find<%= entity %>ByIdUseCase', () => {
|
|
5
|
+
let useCase: Find<%= entity %>ByIdUseCase;
|
|
6
|
+
let mockRepo: jest.Mocked<I<%= entity %>Repository>;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
mockRepo = {
|
|
10
|
+
create: jest.fn(),
|
|
11
|
+
update: jest.fn(),
|
|
12
|
+
delete: jest.fn(),
|
|
13
|
+
findById: jest.fn(),
|
|
14
|
+
findAll: jest.fn(),
|
|
15
|
+
};
|
|
16
|
+
useCase = new Find<%= entity %>ByIdUseCase(mockRepo);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should return the <%= entityLower %> when found', async () => {
|
|
20
|
+
const id = 1;
|
|
21
|
+
const expected = {
|
|
22
|
+
id,
|
|
23
|
+
<% columns.filter(c => !c.primary).forEach(c => { %> <%= c.name %>: '<%= c.type === 'number' ? 123 : 'test' %>',
|
|
24
|
+
<% }) %> };
|
|
25
|
+
mockRepo.findById.mockResolvedValue(expected);
|
|
26
|
+
|
|
27
|
+
const result = await useCase.execute(id);
|
|
28
|
+
expect(result).toEqual(expected);
|
|
29
|
+
expect(mockRepo.findById).toHaveBeenCalledWith(id);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should return null if <%= entityLower %> not found', async () => {
|
|
33
|
+
const id = 999;
|
|
34
|
+
mockRepo.findById.mockResolvedValue(null);
|
|
35
|
+
|
|
36
|
+
const result = await useCase.execute(id);
|
|
37
|
+
expect(result).toBeNull();
|
|
38
|
+
expect(mockRepo.findById).toHaveBeenCalledWith(id);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should throw error if repository fails', async () => {
|
|
42
|
+
const id = 1;
|
|
43
|
+
mockRepo.findById.mockRejectedValue(new Error('Database error'));
|
|
44
|
+
|
|
45
|
+
await expect(useCase.execute(id)).rejects.toThrow('Database error');
|
|
46
|
+
expect(mockRepo.findById).toHaveBeenCalledWith(id);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Update<%= entity %>UseCase } from '../../../src/core/usecases/<%= entityLower %>/update-<%= entityLower %>.usecase';
|
|
2
|
+
import { I<%= entity %>Repository } from '../../../src/core/ports/outbound/repositories/i<%= entityLower %>.repository';
|
|
3
|
+
|
|
4
|
+
describe('Update<%= entity %>UseCase', () => {
|
|
5
|
+
let useCase: Update<%= entity %>UseCase;
|
|
6
|
+
let mockRepo: jest.Mocked<I<%= entity %>Repository>;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
mockRepo = {
|
|
10
|
+
create: jest.fn(),
|
|
11
|
+
update: jest.fn(),
|
|
12
|
+
delete: jest.fn(),
|
|
13
|
+
findById: jest.fn(),
|
|
14
|
+
findAll: jest.fn(),
|
|
15
|
+
};
|
|
16
|
+
useCase = new Update<%= entity %>UseCase(mockRepo);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should update an existing <%= entityLower %> successfully', async () => {
|
|
20
|
+
const input = {
|
|
21
|
+
id: 1,
|
|
22
|
+
<% columns.filter(c => !c.primary && !c.generated).forEach(c => { %> <%= c.name %>: '<%= c.type === 'number' ? 123 : 'updated' %>',
|
|
23
|
+
<% }) %> };
|
|
24
|
+
const expected = { id: input.id, ...input };
|
|
25
|
+
mockRepo.update.mockResolvedValue(expected);
|
|
26
|
+
|
|
27
|
+
const result = await useCase.execute(input);
|
|
28
|
+
expect(result).toEqual(expected);
|
|
29
|
+
expect(mockRepo.update).toHaveBeenCalledWith(input);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should throw error if repository fails', async () => {
|
|
33
|
+
const input = { id: 1 };
|
|
34
|
+
mockRepo.update.mockRejectedValue(new Error('Update failed'));
|
|
35
|
+
|
|
36
|
+
await expect(useCase.execute(input)).rejects.toThrow('Update failed');
|
|
37
|
+
expect(mockRepo.update).toHaveBeenCalledWith(input);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "typeorm-entity",
|
|
3
|
+
"description": "Gera uma entidade TypeORM com base nos campos informados",
|
|
4
|
+
"dependencies": [],
|
|
5
|
+
"files": [
|
|
6
|
+
{
|
|
7
|
+
"template": "entity.ejs",
|
|
8
|
+
"output": "src/adapters/outbound/entities/persistence/typeorm/<%= entity %>.entity.ts"
|
|
9
|
+
}
|
|
10
|
+
],
|
|
11
|
+
"hooks": {}
|
|
12
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Entity,
|
|
3
|
+
PrimaryGeneratedColumn,
|
|
4
|
+
Column,
|
|
5
|
+
CreateDateColumn,
|
|
6
|
+
UpdateDateColumn
|
|
7
|
+
} from 'typeorm';
|
|
8
|
+
|
|
9
|
+
// Função auxiliar para converter camelCase para snake_case
|
|
10
|
+
function toSnakeCase(str) {
|
|
11
|
+
return str.replace(/([A-Z])/g, '_$1').toLowerCase();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@Entity({ name: 'tb_<%= pluralLower %>' })
|
|
15
|
+
export class <%= entity %> {
|
|
16
|
+
@PrimaryGeneratedColumn()
|
|
17
|
+
id: number;
|
|
18
|
+
|
|
19
|
+
<% columns.forEach(column => { %>
|
|
20
|
+
@Column({
|
|
21
|
+
name: '<%= toSnakeCase(column.name) %>',
|
|
22
|
+
type: '<%= column.type === 'number' ? 'int' : 'varchar' %>'<%= column.type === 'string' ? ', length: 255' : '' %>
|
|
23
|
+
})
|
|
24
|
+
<%= column.name %>: <%= column.type %>;
|
|
25
|
+
<% }) %>
|
|
26
|
+
|
|
27
|
+
@CreateDateColumn({ name: 'created_at' })
|
|
28
|
+
createdAt: Date;
|
|
29
|
+
|
|
30
|
+
@UpdateDateColumn({ name: 'updated_at' })
|
|
31
|
+
updatedAt: Date;
|
|
32
|
+
|
|
33
|
+
@DeleteDateColumn({ name: 'deleted_at' })
|
|
34
|
+
deletedAt: Date | null;
|
|
35
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { <%= entity %> } from '
|
|
1
|
+
import { <%= entity %> } from '../../../adapters/outbound/persistence/typeorm/entities/<%= entityLower %>.entity';
|
|
2
2
|
import { I<%= entity %>Repository } from '../../ports/outbound/repositories/i<%= entityLower %>.repository';
|
|
3
3
|
|
|
4
4
|
export class Create<%= entity %>UseCase {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { <%= entity %> } from '
|
|
1
|
+
import { <%= entity %> } from '../../../adapters/outbound/persistence/typeorm/entities/<%= entityLower %>.entity';
|
|
2
2
|
import { I<%= entity %>Repository } from '../../ports/outbound/repositories/i<%= entityLower %>.repository';
|
|
3
3
|
|
|
4
4
|
export class FindAll<%= plural %>UseCase {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { <%= entity %> } from '
|
|
1
|
+
import { <%= entity %> } from '../../../adapters/outbound/persistence/typeorm/entities/<%= entityLower %>.entity';
|
|
2
2
|
import { I<%= entity %>Repository } from '../../ports/outbound/repositories/i<%= entityLower %>.repository';
|
|
3
3
|
|
|
4
4
|
export class Find<%= entity %>ByIdUseCase {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { <%= entity %> } from '
|
|
1
|
+
import { <%= entity %> } from '../../../adapters/outbound/persistence/typeorm/entities/<%= entityLower %>.entity';
|
|
2
2
|
import { I<%= entity %>Repository } from '../../ports/outbound/repositories/i<%= entityLower %>.repository';
|
|
3
3
|
|
|
4
4
|
export class Update<%= entity %>UseCase {
|