@mbc-cqrs-serverless/cli 0.1.49-beta.0 → 0.1.51-beta.0
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/README.md +94 -63
- package/dist/actions/generate.action.js +44 -0
- package/dist/actions/new.action.get-package-version.spec.js +29 -0
- package/dist/actions/new.action.is-latest-version.spec.js +36 -0
- package/dist/actions/new.action.js +12 -6
- package/dist/actions/new.action.spec.js +84 -0
- package/dist/actions/new.action.update-env-local.spec.js +35 -0
- package/dist/actions/new.action.use-package-version.spec.js +46 -0
- package/dist/actions/ui.action.js +7 -5
- package/dist/commands/command.input.js +2 -0
- package/dist/commands/generate.command.js +24 -0
- package/dist/commands/index.js +2 -0
- package/dist/index.js +13 -2
- package/dist/runners/abstract.runner.js +44 -0
- package/dist/runners/schematic.runner.js +21 -0
- package/dist/schematics/collection.json +34 -0
- package/dist/schematics/index.js +17 -0
- package/dist/schematics/lib/controller/controller.factory.js +40 -0
- package/dist/schematics/lib/controller/controller.factory.spec.js +79 -0
- package/dist/schematics/lib/controller/files/__name@dasherize__.controller.ts +11 -0
- package/dist/schematics/lib/controller/schema.json +18 -0
- package/dist/schematics/lib/controller/units/__name@dasherize__.controller.__specFileSuffix__.ts +19 -0
- package/dist/schematics/lib/dto/dto.factory.js +32 -0
- package/dist/schematics/lib/dto/dto.factory.spec.js +128 -0
- package/dist/schematics/lib/dto/files/dto/__name@dasherize__-attributes.dto.ts +6 -0
- package/dist/schematics/lib/dto/files/dto/__name@dasherize__-command.dto.ts +16 -0
- package/dist/schematics/lib/dto/files/dto/__name@dasherize__-create.dto.ts +18 -0
- package/dist/schematics/lib/dto/files/dto/__name@dasherize__-search.dto.ts +2 -0
- package/dist/schematics/lib/dto/files/dto/__name@dasherize__-update.dto.ts +34 -0
- package/dist/schematics/lib/dto/schema.json +18 -0
- package/dist/schematics/lib/entity/entity.factory.js +30 -0
- package/dist/schematics/lib/entity/entity.factory.spec.js +86 -0
- package/dist/schematics/lib/entity/files/entity/__name@dasherize__-command.entity.ts +12 -0
- package/dist/schematics/lib/entity/files/entity/__name@dasherize__-data-list.entity.ts +12 -0
- package/dist/schematics/lib/entity/files/entity/__name@dasherize__-data.entity.ts +12 -0
- package/dist/schematics/lib/entity/schema.json +18 -0
- package/dist/schematics/lib/module/files/async/__name@dasherize__.controller.ts +74 -0
- package/dist/schematics/lib/module/files/async/__name@dasherize__.module.ts +19 -0
- package/dist/schematics/lib/module/files/async/__name@dasherize__.service.ts +164 -0
- package/dist/schematics/lib/module/files/async/dto/__name@dasherize__-attributes.dto.ts +6 -0
- package/dist/schematics/lib/module/files/async/dto/__name@dasherize__-command.dto.ts +16 -0
- package/dist/schematics/lib/module/files/async/dto/__name@dasherize__-create.dto.ts +18 -0
- package/dist/schematics/lib/module/files/async/dto/__name@dasherize__-search.dto.ts +2 -0
- package/dist/schematics/lib/module/files/async/dto/__name@dasherize__-update.dto.ts +34 -0
- package/dist/schematics/lib/module/files/async/entity/__name@dasherize__-command.entity.ts +12 -0
- package/dist/schematics/lib/module/files/async/entity/__name@dasherize__-data-list.entity.ts +12 -0
- package/dist/schematics/lib/module/files/async/entity/__name@dasherize__-data.entity.ts +12 -0
- package/dist/schematics/lib/module/files/async/handler/__name@dasherize__-rds.handler.ts +62 -0
- package/dist/schematics/lib/module/files/sync/__name@dasherize__.controller.ts +74 -0
- package/dist/schematics/lib/module/files/sync/__name@dasherize__.module.ts +19 -0
- package/dist/schematics/lib/module/files/sync/__name@dasherize__.service.ts +164 -0
- package/dist/schematics/lib/module/files/sync/dto/__name@dasherize__-attributes.dto.ts +6 -0
- package/dist/schematics/lib/module/files/sync/dto/__name@dasherize__-command.dto.ts +16 -0
- package/dist/schematics/lib/module/files/sync/dto/__name@dasherize__-create.dto.ts +18 -0
- package/dist/schematics/lib/module/files/sync/dto/__name@dasherize__-search.dto.ts +2 -0
- package/dist/schematics/lib/module/files/sync/dto/__name@dasherize__-update.dto.ts +34 -0
- package/dist/schematics/lib/module/files/sync/entity/__name@dasherize__-command.entity.ts +12 -0
- package/dist/schematics/lib/module/files/sync/entity/__name@dasherize__-data-list.entity.ts +12 -0
- package/dist/schematics/lib/module/files/sync/entity/__name@dasherize__-data.entity.ts +12 -0
- package/dist/schematics/lib/module/files/sync/handler/__name@dasherize__-rds.handler.ts +62 -0
- package/dist/schematics/lib/module/module.factory.js +204 -0
- package/dist/schematics/lib/module/module.factory.spec.js +188 -0
- package/dist/schematics/lib/module/schema.json +28 -0
- package/dist/schematics/lib/module/units/__name@dasherize__.controller.__specFileSuffix__.ts +19 -0
- package/dist/schematics/lib/module/units/__name@dasherize__.service.__specFileSuffix__.ts +19 -0
- package/dist/schematics/lib/service/files/__name@dasherize__.service.ts +12 -0
- package/dist/schematics/lib/service/schema.json +18 -0
- package/dist/schematics/lib/service/service.factory.js +40 -0
- package/dist/schematics/lib/service/service.factory.spec.js +81 -0
- package/dist/schematics/lib/service/units/__name@dasherize__.service.__specFileSuffix__.ts +19 -0
- package/dist/schematics/schematic.colection.js +60 -0
- package/dist/schematics/schematic.option.js +44 -0
- package/dist/schematics/utils/check-files-exist.js +13 -0
- package/dist/schematics/utils/index.js +17 -0
- package/dist/ui/index.js +18 -0
- package/dist/ui/logger.js +54 -0
- package/dist/ui/message.js +6 -0
- package/dist/utils/formatting.js +18 -0
- package/dist/utils/index.js +18 -0
- package/dist/utils/local-binaries.js +20 -0
- package/package.json +14 -5
- package/templates/.env.local +1 -1
- package/templates/README.md +1 -1
- package/templates/infra/README.md +6 -1
- package/templates/infra/libs/infra-stack.ts +1 -1
- package/templates/infra-local/docker-compose.yml +1 -1
- package/templates/infra-local/serverless.yml +19 -21
- package/templates/infra-local/swagger.json +396 -0
- package/templates/package.json +1 -0
- package/templates/prisma/dynamodbs/cqrs.json +1 -1
- package/templates/prisma/schema.prisma +4 -7
- package/templates/src/helpers/id.ts +12 -0
- package/templates/src/helpers/index.ts +1 -0
- package/templates/src/main.module.ts +2 -2
- package/templates/src/{master/dto/master-attributes.dto.ts → sample/dto/sample-attributes.dto.ts} +2 -2
- package/templates/src/{master/dto/master-command.dto.ts → sample/dto/sample-command.dto.ts} +4 -4
- package/templates/src/sample/entity/sample-command.entity.ts +13 -0
- package/templates/src/sample/entity/sample-data-list.entity.ts +13 -0
- package/templates/src/sample/entity/sample-data.entity.ts +13 -0
- package/templates/src/{master/handler/master-rds.handler.ts → sample/handler/sample-rds.handler.ts} +5 -7
- package/templates/src/{master/master.controller.ts → sample/sample.controller.ts} +22 -22
- package/templates/src/sample/sample.module.ts +19 -0
- package/templates/src/{master/master.service.ts → sample/sample.service.ts} +12 -12
- package/templates/test/api.http +25 -0
- package/templates/tsconfig.json +1 -1
- package/templates/src/master/entity/master-command.entity.ts +0 -13
- package/templates/src/master/entity/master-data-list.entity.ts +0 -13
- package/templates/src/master/entity/master-data.entity.ts +0 -13
- package/templates/src/master/master.module.ts +0 -19
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { CommandModule } from '@mbc-cqrs-serverless/core'
|
|
2
|
+
import { Module } from '@nestjs/common'
|
|
3
|
+
|
|
4
|
+
<% if (schema) { %>import { <%= classify(name) %>DataSyncRdsHandler } from './handler/<%= dasherize(name) %>-rds.handler'<% } %>
|
|
5
|
+
import { <%= classify(name) %>Controller } from './<%= dasherize(name) %>.controller'
|
|
6
|
+
import { <%= classify(name) %>Service } from './<%= dasherize(name) %>.service'
|
|
7
|
+
|
|
8
|
+
@Module({
|
|
9
|
+
imports: [
|
|
10
|
+
CommandModule.register({
|
|
11
|
+
tableName: '<%= dasherize(name) %>',
|
|
12
|
+
<% if (schema) { %>dataSyncHandlers: [<%= classify(name) %>DataSyncRdsHandler],<% }
|
|
13
|
+
else { %>dataSyncHandlers: [],<% } %>
|
|
14
|
+
}),
|
|
15
|
+
],
|
|
16
|
+
controllers: [<%= classify(name) %>Controller],
|
|
17
|
+
providers: [<%= classify(name) %>Service],
|
|
18
|
+
})
|
|
19
|
+
export class <%= classify(name) %>Module {}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CommandPartialInputModel,
|
|
3
|
+
CommandService,
|
|
4
|
+
DataService,
|
|
5
|
+
DetailDto,
|
|
6
|
+
generateId,
|
|
7
|
+
getUserContext,
|
|
8
|
+
IInvoke,
|
|
9
|
+
toISOStringWithTimezone,
|
|
10
|
+
VERSION_FIRST,
|
|
11
|
+
} from '@mbc-cqrs-serverless/core'
|
|
12
|
+
import { KEY_SEPARATOR } from '@mbc-cqrs-serverless/core'
|
|
13
|
+
import {
|
|
14
|
+
BadRequestException,
|
|
15
|
+
Injectable,
|
|
16
|
+
Logger,
|
|
17
|
+
NotFoundException,
|
|
18
|
+
} from '@nestjs/common'
|
|
19
|
+
import { Prisma } from '@prisma/client'
|
|
20
|
+
import { getOrderBys, parsePk } from 'src/helpers'
|
|
21
|
+
import { PrismaService } from 'src/prisma'
|
|
22
|
+
import { ulid } from 'ulid'
|
|
23
|
+
|
|
24
|
+
import { <%= classify(name) %>CommandDto } from './dto/<%= dasherize(name) %>-command.dto'
|
|
25
|
+
import { <%= classify(name) %>CreateDto } from './dto/<%= dasherize(name) %>-create.dto'
|
|
26
|
+
import { <%= classify(name) %>SearchDto } from './dto/<%= dasherize(name) %>-search.dto'
|
|
27
|
+
import { <%= classify(name) %>UpdateDto } from './dto/<%= dasherize(name) %>-update.dto'
|
|
28
|
+
import { <%= classify(name) %>DataEntity } from './entity/<%= dasherize(name) %>-data.entity'
|
|
29
|
+
import { <%= classify(name) %>DataListEntity } from './entity/<%= dasherize(name) %>-data-list.entity'
|
|
30
|
+
|
|
31
|
+
@Injectable()
|
|
32
|
+
export class <%= classify(name) %>Service {
|
|
33
|
+
private readonly logger = new Logger(<%= classify(name) %>Service.name)
|
|
34
|
+
|
|
35
|
+
constructor(
|
|
36
|
+
private readonly commandService: CommandService,
|
|
37
|
+
private readonly dataService: DataService,
|
|
38
|
+
<% if (schema) { %>private readonly prismaService: PrismaService,<% } %>
|
|
39
|
+
) {}
|
|
40
|
+
|
|
41
|
+
async create(
|
|
42
|
+
createDto: <%= classify(name) %>CreateDto,
|
|
43
|
+
opts: { invokeContext: IInvoke },
|
|
44
|
+
): Promise<<%= classify(name) %>DataEntity> {
|
|
45
|
+
const { tenantCode } = getUserContext(opts.invokeContext)
|
|
46
|
+
const pk = `<%= name.toUpperCase() %>${KEY_SEPARATOR}${tenantCode}`
|
|
47
|
+
const sk = ulid()
|
|
48
|
+
const <%= camelize(name) %> = new <%= classify(name) %>CommandDto({
|
|
49
|
+
pk,
|
|
50
|
+
sk,
|
|
51
|
+
id: generateId(pk, sk),
|
|
52
|
+
tenantCode,
|
|
53
|
+
code: sk,
|
|
54
|
+
type: '<%= name.toUpperCase() %>',
|
|
55
|
+
version: VERSION_FIRST,
|
|
56
|
+
name: createDto.name,
|
|
57
|
+
attributes: createDto.attributes,
|
|
58
|
+
})
|
|
59
|
+
const item = await this.commandService.publishSync(<%= camelize(name) %>, opts)
|
|
60
|
+
return new <%= classify(name) %>DataEntity(item as <%= classify(name) %>DataEntity)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async findOne(detailDto: DetailDto): Promise<<%= classify(name) %>DataEntity> {
|
|
64
|
+
const item = await this.dataService.getItem(detailDto)
|
|
65
|
+
if (!item) {
|
|
66
|
+
throw new NotFoundException('<%= classify(name) %> not found!')
|
|
67
|
+
}
|
|
68
|
+
this.logger.debug('item:', item)
|
|
69
|
+
return new <%= classify(name) %>DataEntity(item as <%= classify(name) %>DataEntity)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
<% if (schema) { %>async findAll(
|
|
73
|
+
tenantCode: string,
|
|
74
|
+
searchDto: <%= classify(name) %>SearchDto,
|
|
75
|
+
): Promise<<%= classify(name) %>DataListEntity> {
|
|
76
|
+
const where: Prisma.<%= classify(name) %>WhereInput = {
|
|
77
|
+
isDeleted: false,
|
|
78
|
+
tenantCode,
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const { pageSize = 10, page = 1, orderBys = ['-createdAt'] } = searchDto
|
|
82
|
+
|
|
83
|
+
const [total, items] = await Promise.all([
|
|
84
|
+
this.prismaService.<%= camelize(name) %>.count({ where }),
|
|
85
|
+
this.prismaService.<%= camelize(name) %>.findMany({
|
|
86
|
+
where,
|
|
87
|
+
take: pageSize,
|
|
88
|
+
skip: pageSize * (page - 1),
|
|
89
|
+
orderBy: getOrderBys<Prisma.<%= classify(name) %>OrderByWithRelationInput>(orderBys),
|
|
90
|
+
}),
|
|
91
|
+
])
|
|
92
|
+
|
|
93
|
+
return new <%= classify(name) %>DataListEntity({
|
|
94
|
+
total,
|
|
95
|
+
items: items.map(
|
|
96
|
+
(item) =>
|
|
97
|
+
new <%= classify(name) %>DataEntity({
|
|
98
|
+
...item,
|
|
99
|
+
attributes: {
|
|
100
|
+
value: item.attributes as object,
|
|
101
|
+
},
|
|
102
|
+
}),
|
|
103
|
+
),
|
|
104
|
+
})
|
|
105
|
+
}<% } %>
|
|
106
|
+
|
|
107
|
+
async update(
|
|
108
|
+
detailDto: DetailDto,
|
|
109
|
+
updateDto: <%= classify(name) %>UpdateDto,
|
|
110
|
+
opts: { invokeContext: IInvoke },
|
|
111
|
+
): Promise<<%= classify(name) %>DataEntity> {
|
|
112
|
+
const userContext = getUserContext(opts.invokeContext)
|
|
113
|
+
const { tenantCode } = parsePk(detailDto.pk)
|
|
114
|
+
if (userContext.tenantCode !== tenantCode) {
|
|
115
|
+
throw new BadRequestException('Invalid tenant code')
|
|
116
|
+
}
|
|
117
|
+
const data = (await this.dataService.getItem(detailDto)) as <%= classify(name) %>DataEntity
|
|
118
|
+
if (!data) {
|
|
119
|
+
throw new NotFoundException('<%= classify(name) %> not found!')
|
|
120
|
+
}
|
|
121
|
+
const commandDto = new <%= classify(name) %>CommandDto({
|
|
122
|
+
pk: data.pk,
|
|
123
|
+
sk: data.sk,
|
|
124
|
+
version: data.version,
|
|
125
|
+
name: updateDto.name ?? data.name,
|
|
126
|
+
isDeleted: updateDto.isDeleted ?? data.isDeleted,
|
|
127
|
+
attributes: {
|
|
128
|
+
...data.attributes,
|
|
129
|
+
...updateDto.attributes,
|
|
130
|
+
},
|
|
131
|
+
})
|
|
132
|
+
const item = await this.commandService.publishPartialUpdateSync(
|
|
133
|
+
commandDto,
|
|
134
|
+
opts,
|
|
135
|
+
)
|
|
136
|
+
return new <%= classify(name) %>DataEntity(item as <%= classify(name) %>DataEntity)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async remove(key: DetailDto, opts: { invokeContext: IInvoke }) {
|
|
140
|
+
const userContext = getUserContext(opts.invokeContext)
|
|
141
|
+
const { tenantCode } = parsePk(key.pk)
|
|
142
|
+
|
|
143
|
+
if (userContext.tenantCode !== tenantCode) {
|
|
144
|
+
throw new BadRequestException('Invalid tenant code')
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const data = (await this.dataService.getItem(key)) as <%= classify(name) %>DataEntity
|
|
148
|
+
if (!data) {
|
|
149
|
+
throw new NotFoundException()
|
|
150
|
+
}
|
|
151
|
+
const commandDto: CommandPartialInputModel = {
|
|
152
|
+
pk: data.pk,
|
|
153
|
+
sk: data.sk,
|
|
154
|
+
version: data.version,
|
|
155
|
+
isDeleted: true,
|
|
156
|
+
}
|
|
157
|
+
const item = await this.commandService.publishPartialUpdateSync(
|
|
158
|
+
commandDto,
|
|
159
|
+
opts,
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
return new <%= classify(name) %>DataEntity(item as any)
|
|
163
|
+
}
|
|
164
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { CommandDto } from '@mbc-cqrs-serverless/core'
|
|
2
|
+
import { Type } from 'class-transformer'
|
|
3
|
+
import { ValidateNested } from 'class-validator'
|
|
4
|
+
|
|
5
|
+
import { <%= classify(name) %>Attributes } from './<%= dasherize(name) %>-attributes.dto'
|
|
6
|
+
|
|
7
|
+
export class <%= classify(name) %>CommandDto extends CommandDto {
|
|
8
|
+
@Type(() => <%= classify(name) %>Attributes)
|
|
9
|
+
@ValidateNested()
|
|
10
|
+
attributes: <%= classify(name) %>Attributes
|
|
11
|
+
|
|
12
|
+
constructor(partial: Partial<<%= classify(name) %>CommandDto>) {
|
|
13
|
+
super()
|
|
14
|
+
Object.assign(this, partial)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Type } from 'class-transformer'
|
|
2
|
+
import { IsOptional, IsString, ValidateNested } from 'class-validator'
|
|
3
|
+
|
|
4
|
+
import { <%= classify(name) %>Attributes } from './<%= dasherize(name) %>-attributes.dto'
|
|
5
|
+
|
|
6
|
+
export class <%= classify(name) %>CreateDto {
|
|
7
|
+
@IsString()
|
|
8
|
+
name: string
|
|
9
|
+
|
|
10
|
+
@Type(() => <%= classify(name) %>Attributes)
|
|
11
|
+
@ValidateNested()
|
|
12
|
+
@IsOptional()
|
|
13
|
+
attributes?: <%= classify(name) %>Attributes
|
|
14
|
+
|
|
15
|
+
constructor(partial: Partial<<%= classify(name) %>CreateDto>) {
|
|
16
|
+
Object.assign(this, partial)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { PartialType } from '@nestjs/swagger'
|
|
2
|
+
import { Transform, Type } from 'class-transformer'
|
|
3
|
+
import {
|
|
4
|
+
IsBoolean,
|
|
5
|
+
IsOptional,
|
|
6
|
+
IsString,
|
|
7
|
+
ValidateNested,
|
|
8
|
+
} from 'class-validator'
|
|
9
|
+
|
|
10
|
+
import { <%= classify(name) %>Attributes } from './<%= dasherize(name) %>-attributes.dto'
|
|
11
|
+
|
|
12
|
+
export class <%= classify(name) %>UpdateAttributes extends PartialType(<%= classify(name) %>Attributes) {}
|
|
13
|
+
|
|
14
|
+
export class <%= classify(name) %>UpdateDto {
|
|
15
|
+
@IsString()
|
|
16
|
+
@IsOptional()
|
|
17
|
+
name?: string
|
|
18
|
+
|
|
19
|
+
@IsBoolean()
|
|
20
|
+
@Transform(({ value }) =>
|
|
21
|
+
value === 'true' ? true : value === 'false' ? false : value,
|
|
22
|
+
)
|
|
23
|
+
@IsOptional()
|
|
24
|
+
isDeleted?: boolean
|
|
25
|
+
|
|
26
|
+
@Type(() => <%= classify(name) %>UpdateAttributes)
|
|
27
|
+
@ValidateNested()
|
|
28
|
+
@IsOptional()
|
|
29
|
+
attributes?: <%= classify(name) %>UpdateAttributes
|
|
30
|
+
|
|
31
|
+
constructor(partial: Partial<<%= classify(name) %>UpdateDto>) {
|
|
32
|
+
Object.assign(this, partial)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { CommandEntity } from '@mbc-cqrs-serverless/core'
|
|
2
|
+
|
|
3
|
+
import { <%= classify(name) %>Attributes } from '../dto/<%= dasherize(name) %>-attributes.dto'
|
|
4
|
+
|
|
5
|
+
export class <%= classify(name) %>CommandEntity extends CommandEntity {
|
|
6
|
+
attributes: <%= classify(name) %>Attributes
|
|
7
|
+
|
|
8
|
+
constructor(partial: Partial<<%= classify(name) %>CommandEntity>) {
|
|
9
|
+
super()
|
|
10
|
+
Object.assign(this, partial)
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { DataListEntity } from '@mbc-cqrs-serverless/core'
|
|
2
|
+
|
|
3
|
+
import { <%= classify(name) %>DataEntity } from './<%= dasherize(name) %>-data.entity'
|
|
4
|
+
|
|
5
|
+
export class <%= classify(name) %>DataListEntity extends DataListEntity {
|
|
6
|
+
items: <%= classify(name) %>DataEntity[]
|
|
7
|
+
|
|
8
|
+
constructor(partial: Partial<<%= classify(name) %>DataListEntity>) {
|
|
9
|
+
super(partial)
|
|
10
|
+
Object.assign(this, partial)
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { DataEntity } from '@mbc-cqrs-serverless/core'
|
|
2
|
+
|
|
3
|
+
import { <%= classify(name) %>Attributes } from '../dto/<%= dasherize(name) %>-attributes.dto'
|
|
4
|
+
|
|
5
|
+
export class <%= classify(name) %>DataEntity extends DataEntity {
|
|
6
|
+
attributes: <%= classify(name) %>Attributes
|
|
7
|
+
|
|
8
|
+
constructor(partial: Partial<<%= classify(name) %>DataEntity>) {
|
|
9
|
+
super(partial)
|
|
10
|
+
Object.assign(this, partial)
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CommandModel,
|
|
3
|
+
IDataSyncHandler,
|
|
4
|
+
removeSortKeyVersion,
|
|
5
|
+
} from '@mbc-cqrs-serverless/core'
|
|
6
|
+
import { Injectable, Logger } from '@nestjs/common'
|
|
7
|
+
import { PrismaService } from 'src/prisma'
|
|
8
|
+
|
|
9
|
+
import { <%= classify(name) %>Attributes } from '../dto/<%= dasherize(name) %>-attributes.dto'
|
|
10
|
+
|
|
11
|
+
@Injectable()
|
|
12
|
+
export class <%= classify(name) %>DataSyncRdsHandler implements IDataSyncHandler {
|
|
13
|
+
private readonly logger = new Logger(<%= classify(name) %>DataSyncRdsHandler.name)
|
|
14
|
+
|
|
15
|
+
constructor(private readonly prismaService: PrismaService) {}
|
|
16
|
+
|
|
17
|
+
async up(cmd: CommandModel): Promise<any> {
|
|
18
|
+
this.logger.debug(cmd)
|
|
19
|
+
const sk = removeSortKeyVersion(cmd.sk)
|
|
20
|
+
const attrs = cmd.attributes as <%= classify(name) %>Attributes
|
|
21
|
+
await this.prismaService.<%= camelize(name) %>.upsert({
|
|
22
|
+
where: {
|
|
23
|
+
id: cmd.id,
|
|
24
|
+
},
|
|
25
|
+
update: {
|
|
26
|
+
csk: cmd.sk,
|
|
27
|
+
name: cmd.name,
|
|
28
|
+
version: cmd.version,
|
|
29
|
+
seq: cmd.seq,
|
|
30
|
+
isDeleted: cmd.isDeleted || false,
|
|
31
|
+
updatedAt: cmd.updatedAt,
|
|
32
|
+
updatedBy: cmd.updatedBy,
|
|
33
|
+
updatedIp: cmd.updatedIp,
|
|
34
|
+
// attributes
|
|
35
|
+
attributes: attrs.value,
|
|
36
|
+
},
|
|
37
|
+
create: {
|
|
38
|
+
id: cmd.id,
|
|
39
|
+
cpk: cmd.pk,
|
|
40
|
+
csk: cmd.sk,
|
|
41
|
+
pk: cmd.pk,
|
|
42
|
+
sk,
|
|
43
|
+
code: sk,
|
|
44
|
+
name: cmd.name,
|
|
45
|
+
version: cmd.version,
|
|
46
|
+
tenantCode: cmd.tenantCode,
|
|
47
|
+
seq: cmd.seq,
|
|
48
|
+
createdAt: cmd.createdAt,
|
|
49
|
+
createdBy: cmd.createdBy,
|
|
50
|
+
createdIp: cmd.createdIp,
|
|
51
|
+
updatedAt: cmd.updatedAt,
|
|
52
|
+
updatedBy: cmd.updatedBy,
|
|
53
|
+
updatedIp: cmd.updatedIp,
|
|
54
|
+
// attributes
|
|
55
|
+
attributes: attrs.value,
|
|
56
|
+
},
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
async down(cmd: CommandModel): Promise<any> {
|
|
60
|
+
this.logger.debug(cmd)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.main = main;
|
|
37
|
+
const core_1 = require("@angular-devkit/core");
|
|
38
|
+
const schematics_1 = require("@angular-devkit/schematics");
|
|
39
|
+
const ts = __importStar(require("typescript"));
|
|
40
|
+
const yaml_1 = require("yaml");
|
|
41
|
+
function main(options) {
|
|
42
|
+
return (tree, _context) => {
|
|
43
|
+
const filePath = (0, core_1.normalize)(`/src/${core_1.strings.dasherize(options.name)}/${core_1.strings.dasherize(options.name)}.module.ts`);
|
|
44
|
+
const isFileExists = tree.exists(filePath);
|
|
45
|
+
if (isFileExists) {
|
|
46
|
+
_context.logger.info(`Module file already exists at: ${filePath}`);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
updateMainModule(tree, options);
|
|
50
|
+
updateCdkInfraStack(tree, options);
|
|
51
|
+
updateCqrsTable(tree, options);
|
|
52
|
+
updateServerlessYaml(tree, options);
|
|
53
|
+
if (options.schema) {
|
|
54
|
+
updatePrismaSchema(tree, options);
|
|
55
|
+
}
|
|
56
|
+
return (0, schematics_1.chain)([createModule(options), createUnitTest(options)]);
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
// create rule
|
|
60
|
+
function createModule(options) {
|
|
61
|
+
return (0, schematics_1.mergeWith)((0, schematics_1.apply)((0, schematics_1.url)(`./files/${options.mode}`), [
|
|
62
|
+
options.schema ? (0, schematics_1.noop)() : (0, schematics_1.filter)((path) => !path.endsWith('.handler.ts')),
|
|
63
|
+
(0, schematics_1.template)({
|
|
64
|
+
...core_1.strings,
|
|
65
|
+
...options,
|
|
66
|
+
}),
|
|
67
|
+
(0, schematics_1.move)((0, core_1.normalize)(`/src/${core_1.strings.dasherize(options.name)}`)),
|
|
68
|
+
]));
|
|
69
|
+
}
|
|
70
|
+
function createUnitTest(options) {
|
|
71
|
+
return (0, schematics_1.mergeWith)((0, schematics_1.apply)((0, schematics_1.url)('./units'), [
|
|
72
|
+
(0, schematics_1.template)({
|
|
73
|
+
...core_1.strings,
|
|
74
|
+
...options,
|
|
75
|
+
specFileSuffix: 'spec',
|
|
76
|
+
}),
|
|
77
|
+
(0, schematics_1.move)((0, core_1.normalize)(`/test/unit/${core_1.strings.dasherize(options.name)}`)),
|
|
78
|
+
]));
|
|
79
|
+
}
|
|
80
|
+
// modify main.module.ts
|
|
81
|
+
function updateMainModule(tree, options) {
|
|
82
|
+
const mainModulePath = 'src/main.module.ts';
|
|
83
|
+
const isMainModulePathExists = tree.exists(mainModulePath);
|
|
84
|
+
if (isMainModulePathExists) {
|
|
85
|
+
const fileBuffer = tree.read(mainModulePath);
|
|
86
|
+
const content = fileBuffer.toString('utf-8');
|
|
87
|
+
const lines = content.split('\n');
|
|
88
|
+
lines.splice(5, 0, `import { ${core_1.strings.classify(options.name)}Module } from './${core_1.strings.dasherize(options.name)}/${core_1.strings.dasherize(options.name)}.module'`);
|
|
89
|
+
lines.splice(23, 0, ` ${core_1.strings.classify(options.name)}Module,`);
|
|
90
|
+
const newContent = lines.join('\n');
|
|
91
|
+
tree.overwrite(mainModulePath, newContent);
|
|
92
|
+
return tree;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// modify infra cdk
|
|
96
|
+
function updateCdkInfraStack(tree, options) {
|
|
97
|
+
const infraStackPath = 'infra/libs/infra-stack.ts';
|
|
98
|
+
const isInfraStackExists = tree.exists(infraStackPath);
|
|
99
|
+
if (isInfraStackExists) {
|
|
100
|
+
const fileBuffer = tree.read(infraStackPath);
|
|
101
|
+
const content = fileBuffer.toString('utf-8');
|
|
102
|
+
const sourceFile = ts.createSourceFile(infraStackPath, content, ts.ScriptTarget.Latest, true);
|
|
103
|
+
const updatedContent = updateTableNamesArray(sourceFile, [`${core_1.strings.dasherize(options.name)}-command`], content);
|
|
104
|
+
tree.overwrite(infraStackPath, updatedContent);
|
|
105
|
+
return tree;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function updateTableNamesArray(sourceFile, newTableNames, content) {
|
|
109
|
+
let updatedContent = content;
|
|
110
|
+
const visit = (node) => {
|
|
111
|
+
if (ts.isVariableDeclaration(node) &&
|
|
112
|
+
node.name.getText() === 'tableNames' &&
|
|
113
|
+
ts.isArrayLiteralExpression(node.initializer)) {
|
|
114
|
+
// Extract existing table names
|
|
115
|
+
const existingElements = node.initializer.elements.map((element) => element.getText().replace(/['"]/g, ''));
|
|
116
|
+
// Append new table names, ensuring no duplicates
|
|
117
|
+
const updatedTableNames = Array.from(new Set([...existingElements, ...newTableNames]));
|
|
118
|
+
// Generate the updated array string
|
|
119
|
+
const newArray = `[${updatedTableNames.map((name) => `'${name}'`).join(', ')}]`;
|
|
120
|
+
// Replace the existing array with the new array
|
|
121
|
+
updatedContent =
|
|
122
|
+
updatedContent.slice(0, node.initializer.getStart()) +
|
|
123
|
+
newArray +
|
|
124
|
+
updatedContent.slice(node.initializer.getEnd());
|
|
125
|
+
}
|
|
126
|
+
ts.forEachChild(node, visit);
|
|
127
|
+
};
|
|
128
|
+
visit(sourceFile);
|
|
129
|
+
return updatedContent;
|
|
130
|
+
}
|
|
131
|
+
// modify cqrs.json
|
|
132
|
+
function updateCqrsTable(tree, options) {
|
|
133
|
+
const cqrsTablePath = 'prisma/dynamodbs/cqrs.json';
|
|
134
|
+
const isCqrsTableExists = tree.exists(cqrsTablePath);
|
|
135
|
+
if (isCqrsTableExists) {
|
|
136
|
+
const fileContent = tree.read(cqrsTablePath)?.toString();
|
|
137
|
+
const jsonContent = JSON.parse(fileContent.toString());
|
|
138
|
+
jsonContent.push(core_1.strings.dasherize(options.name));
|
|
139
|
+
tree.overwrite(cqrsTablePath, JSON.stringify(jsonContent, null, 2));
|
|
140
|
+
return tree;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// modify prisma.schema
|
|
144
|
+
function updatePrismaSchema(tree, options) {
|
|
145
|
+
const schemaPath = 'prisma/schema.prisma';
|
|
146
|
+
const isSchemaExists = tree.exists(schemaPath);
|
|
147
|
+
if (isSchemaExists) {
|
|
148
|
+
const fileContent = tree.read(schemaPath)?.toString('utf-8');
|
|
149
|
+
const stringToAppend = generateModelTemplate(options.name);
|
|
150
|
+
const updatedContent = fileContent + stringToAppend;
|
|
151
|
+
tree.overwrite(schemaPath, updatedContent);
|
|
152
|
+
return tree;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// modify serverless.yaml
|
|
156
|
+
function updateServerlessYaml(tree, options) {
|
|
157
|
+
const serverlessPath = 'infra-local/serverless.yml';
|
|
158
|
+
const isServerlessExists = tree.exists(serverlessPath);
|
|
159
|
+
if (isServerlessExists) {
|
|
160
|
+
const fileContent = tree.read(serverlessPath)?.toString('utf-8');
|
|
161
|
+
const newStreamEvent = {
|
|
162
|
+
type: 'dynamodb',
|
|
163
|
+
maximumRetryAttempts: 10,
|
|
164
|
+
arn: '${env:LOCAL_DDB_%%TABLE_NAME%%_STREAM}'.replace('%%TABLE_NAME%%', options.name.toUpperCase()),
|
|
165
|
+
filterPatterns: [{ eventName: ['INSERT'] }],
|
|
166
|
+
};
|
|
167
|
+
const doc = (0, yaml_1.parseDocument)(fileContent);
|
|
168
|
+
const mainFunction = doc.getIn(['functions', 'main']);
|
|
169
|
+
const events = mainFunction.get('events');
|
|
170
|
+
events.items.push({ stream: newStreamEvent });
|
|
171
|
+
const updatedYamlContent = (0, yaml_1.stringify)(doc);
|
|
172
|
+
tree.overwrite(serverlessPath, updatedYamlContent);
|
|
173
|
+
return tree;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
const generateModelTemplate = (name) => `
|
|
177
|
+
model ${core_1.strings.classify(name)} {
|
|
178
|
+
id String @id
|
|
179
|
+
cpk String // コマンド用PK
|
|
180
|
+
csk String // コマンド用SK
|
|
181
|
+
pk String // データ用PK, ${name.toUpperCase()}#tenantCode (テナントコード)
|
|
182
|
+
sk String // データ用SK, マスタ種別コード#マスタコード
|
|
183
|
+
tenantCode String @map("tenant_code") // テナントコード, 【テナントコードマスタ】
|
|
184
|
+
seq Int @default(0) // 並び順, 採番機能を使用する
|
|
185
|
+
code String // レコードのコード, マスタ種別コード#マスタコード
|
|
186
|
+
name String // レコード名, 名前
|
|
187
|
+
version Int // バージョン
|
|
188
|
+
isDeleted Boolean @default(false) @map("is_deleted") // 削除フラグ
|
|
189
|
+
createdBy String @default("") @map("created_by") // 作成者
|
|
190
|
+
createdIp String @default("") @map("created_ip") // 作成IP, IPv6も考慮する
|
|
191
|
+
createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(0) // 作成日時
|
|
192
|
+
updatedBy String @default("") @map("updated_by") // 更新者
|
|
193
|
+
updatedIp String @default("") @map("updated_ip") // 更新IP, IPv6も考慮する
|
|
194
|
+
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamp(0) // 更新日時
|
|
195
|
+
|
|
196
|
+
attributes Json? @map("attributes")
|
|
197
|
+
|
|
198
|
+
@@unique([cpk, csk])
|
|
199
|
+
@@unique([pk, sk])
|
|
200
|
+
@@unique([tenantCode, code])
|
|
201
|
+
@@index([tenantCode, name])
|
|
202
|
+
@@map("${core_1.strings.underscore(name)}s")
|
|
203
|
+
}
|
|
204
|
+
`;
|