@mbc-cqrs-serverless/cli 0.1.50-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.
Files changed (108) hide show
  1. package/dist/actions/generate.action.js +44 -0
  2. package/dist/actions/new.action.get-package-version.spec.js +29 -0
  3. package/dist/actions/new.action.is-latest-version.spec.js +36 -0
  4. package/dist/actions/new.action.js +12 -6
  5. package/dist/actions/new.action.spec.js +84 -0
  6. package/dist/actions/new.action.update-env-local.spec.js +35 -0
  7. package/dist/actions/new.action.use-package-version.spec.js +46 -0
  8. package/dist/actions/ui.action.js +7 -5
  9. package/dist/commands/command.input.js +2 -0
  10. package/dist/commands/generate.command.js +24 -0
  11. package/dist/commands/index.js +2 -0
  12. package/dist/index.js +13 -2
  13. package/dist/runners/abstract.runner.js +44 -0
  14. package/dist/runners/schematic.runner.js +21 -0
  15. package/dist/schematics/collection.json +34 -0
  16. package/dist/schematics/index.js +17 -0
  17. package/dist/schematics/lib/controller/controller.factory.js +40 -0
  18. package/dist/schematics/lib/controller/controller.factory.spec.js +79 -0
  19. package/dist/schematics/lib/controller/files/__name@dasherize__.controller.ts +11 -0
  20. package/dist/schematics/lib/controller/schema.json +18 -0
  21. package/dist/schematics/lib/controller/units/__name@dasherize__.controller.__specFileSuffix__.ts +19 -0
  22. package/dist/schematics/lib/dto/dto.factory.js +32 -0
  23. package/dist/schematics/lib/dto/dto.factory.spec.js +128 -0
  24. package/dist/schematics/lib/dto/files/dto/__name@dasherize__-attributes.dto.ts +6 -0
  25. package/dist/schematics/lib/dto/files/dto/__name@dasherize__-command.dto.ts +16 -0
  26. package/dist/schematics/lib/dto/files/dto/__name@dasherize__-create.dto.ts +18 -0
  27. package/dist/schematics/lib/dto/files/dto/__name@dasherize__-search.dto.ts +2 -0
  28. package/dist/schematics/lib/dto/files/dto/__name@dasherize__-update.dto.ts +34 -0
  29. package/dist/schematics/lib/dto/schema.json +18 -0
  30. package/dist/schematics/lib/entity/entity.factory.js +30 -0
  31. package/dist/schematics/lib/entity/entity.factory.spec.js +86 -0
  32. package/dist/schematics/lib/entity/files/entity/__name@dasherize__-command.entity.ts +12 -0
  33. package/dist/schematics/lib/entity/files/entity/__name@dasherize__-data-list.entity.ts +12 -0
  34. package/dist/schematics/lib/entity/files/entity/__name@dasherize__-data.entity.ts +12 -0
  35. package/dist/schematics/lib/entity/schema.json +18 -0
  36. package/dist/schematics/lib/module/files/async/__name@dasherize__.controller.ts +74 -0
  37. package/dist/schematics/lib/module/files/async/__name@dasherize__.module.ts +19 -0
  38. package/dist/schematics/lib/module/files/async/__name@dasherize__.service.ts +164 -0
  39. package/dist/schematics/lib/module/files/async/dto/__name@dasherize__-attributes.dto.ts +6 -0
  40. package/dist/schematics/lib/module/files/async/dto/__name@dasherize__-command.dto.ts +16 -0
  41. package/dist/schematics/lib/module/files/async/dto/__name@dasherize__-create.dto.ts +18 -0
  42. package/dist/schematics/lib/module/files/async/dto/__name@dasherize__-search.dto.ts +2 -0
  43. package/dist/schematics/lib/module/files/async/dto/__name@dasherize__-update.dto.ts +34 -0
  44. package/dist/schematics/lib/module/files/async/entity/__name@dasherize__-command.entity.ts +12 -0
  45. package/dist/schematics/lib/module/files/async/entity/__name@dasherize__-data-list.entity.ts +12 -0
  46. package/dist/schematics/lib/module/files/async/entity/__name@dasherize__-data.entity.ts +12 -0
  47. package/dist/schematics/lib/module/files/async/handler/__name@dasherize__-rds.handler.ts +62 -0
  48. package/dist/schematics/lib/module/files/sync/__name@dasherize__.controller.ts +74 -0
  49. package/dist/schematics/lib/module/files/sync/__name@dasherize__.module.ts +19 -0
  50. package/dist/schematics/lib/module/files/sync/__name@dasherize__.service.ts +164 -0
  51. package/dist/schematics/lib/module/files/sync/dto/__name@dasherize__-attributes.dto.ts +6 -0
  52. package/dist/schematics/lib/module/files/sync/dto/__name@dasherize__-command.dto.ts +16 -0
  53. package/dist/schematics/lib/module/files/sync/dto/__name@dasherize__-create.dto.ts +18 -0
  54. package/dist/schematics/lib/module/files/sync/dto/__name@dasherize__-search.dto.ts +2 -0
  55. package/dist/schematics/lib/module/files/sync/dto/__name@dasherize__-update.dto.ts +34 -0
  56. package/dist/schematics/lib/module/files/sync/entity/__name@dasherize__-command.entity.ts +12 -0
  57. package/dist/schematics/lib/module/files/sync/entity/__name@dasherize__-data-list.entity.ts +12 -0
  58. package/dist/schematics/lib/module/files/sync/entity/__name@dasherize__-data.entity.ts +12 -0
  59. package/dist/schematics/lib/module/files/sync/handler/__name@dasherize__-rds.handler.ts +62 -0
  60. package/dist/schematics/lib/module/module.factory.js +204 -0
  61. package/dist/schematics/lib/module/module.factory.spec.js +188 -0
  62. package/dist/schematics/lib/module/schema.json +28 -0
  63. package/dist/schematics/lib/module/units/__name@dasherize__.controller.__specFileSuffix__.ts +19 -0
  64. package/dist/schematics/lib/module/units/__name@dasherize__.service.__specFileSuffix__.ts +19 -0
  65. package/dist/schematics/lib/service/files/__name@dasherize__.service.ts +12 -0
  66. package/dist/schematics/lib/service/schema.json +18 -0
  67. package/dist/schematics/lib/service/service.factory.js +40 -0
  68. package/dist/schematics/lib/service/service.factory.spec.js +81 -0
  69. package/dist/schematics/lib/service/units/__name@dasherize__.service.__specFileSuffix__.ts +19 -0
  70. package/dist/schematics/schematic.colection.js +60 -0
  71. package/dist/schematics/schematic.option.js +44 -0
  72. package/dist/schematics/utils/check-files-exist.js +13 -0
  73. package/dist/schematics/utils/index.js +17 -0
  74. package/dist/ui/index.js +18 -0
  75. package/dist/ui/logger.js +54 -0
  76. package/dist/ui/message.js +6 -0
  77. package/dist/utils/formatting.js +18 -0
  78. package/dist/utils/index.js +18 -0
  79. package/dist/utils/local-binaries.js +20 -0
  80. package/package.json +13 -4
  81. package/templates/.env.local +1 -1
  82. package/templates/README.md +1 -1
  83. package/templates/infra/README.md +6 -1
  84. package/templates/infra/libs/infra-stack.ts +1 -1
  85. package/templates/infra-local/docker-compose.yml +1 -1
  86. package/templates/infra-local/serverless.yml +19 -21
  87. package/templates/infra-local/swagger.json +396 -0
  88. package/templates/package.json +1 -0
  89. package/templates/prisma/dynamodbs/cqrs.json +1 -1
  90. package/templates/prisma/schema.prisma +4 -7
  91. package/templates/src/helpers/id.ts +12 -0
  92. package/templates/src/helpers/index.ts +1 -0
  93. package/templates/src/main.module.ts +2 -2
  94. package/templates/src/{master/dto/master-attributes.dto.ts → sample/dto/sample-attributes.dto.ts} +2 -2
  95. package/templates/src/{master/dto/master-command.dto.ts → sample/dto/sample-command.dto.ts} +4 -4
  96. package/templates/src/sample/entity/sample-command.entity.ts +13 -0
  97. package/templates/src/sample/entity/sample-data-list.entity.ts +13 -0
  98. package/templates/src/sample/entity/sample-data.entity.ts +13 -0
  99. package/templates/src/{master/handler/master-rds.handler.ts → sample/handler/sample-rds.handler.ts} +5 -7
  100. package/templates/src/{master/master.controller.ts → sample/sample.controller.ts} +22 -22
  101. package/templates/src/sample/sample.module.ts +19 -0
  102. package/templates/src/{master/master.service.ts → sample/sample.service.ts} +12 -12
  103. package/templates/test/api.http +25 -0
  104. package/templates/tsconfig.json +1 -1
  105. package/templates/src/master/entity/master-command.entity.ts +0 -13
  106. package/templates/src/master/entity/master-data-list.entity.ts +0 -13
  107. package/templates/src/master/entity/master-data.entity.ts +0 -13
  108. 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.publishAsync(<%= 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.publishPartialUpdateAsync(
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.publishPartialUpdateAsync(
158
+ commandDto,
159
+ opts,
160
+ )
161
+
162
+ return new <%= classify(name) %>DataEntity(item as any)
163
+ }
164
+ }
@@ -0,0 +1,6 @@
1
+ import { IsObject } from 'class-validator'
2
+
3
+ export class <%= classify(name) %>Attributes {
4
+ @IsObject()
5
+ value: object
6
+ }
@@ -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,2 @@
1
+ import { SearchDto } from '@mbc-cqrs-serverless/core'
2
+ export class <%= classify(name) %>SearchDto extends SearchDto {}
@@ -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,74 @@
1
+ import {
2
+ DetailDto,
3
+ getUserContext,
4
+ IInvoke,
5
+ INVOKE_CONTEXT,
6
+ SearchDto,
7
+ } from '@mbc-cqrs-serverless/core'
8
+ import {
9
+ Body,
10
+ Controller,
11
+ Delete,
12
+ Get,
13
+ Logger,
14
+ Param,
15
+ Patch,
16
+ Post,
17
+ Query,
18
+ } from '@nestjs/common'
19
+ import { ApiTags } from '@nestjs/swagger'
20
+
21
+ import { <%= classify(name) %>Service } from './<%= dasherize(name) %>.service'
22
+ import { <%= classify(name) %>CreateDto } from './dto/<%= dasherize(name) %>-create.dto'
23
+ import { <%= classify(name) %>UpdateDto } from './dto/<%= dasherize(name) %>-update.dto'
24
+ import { <%= classify(name) %>DataEntity } from './entity/<%= dasherize(name) %>-data.entity'
25
+
26
+ @Controller('api/<%= dasherize(name) %>')
27
+ @ApiTags('<%= dasherize(name) %>')
28
+ export class <%= classify(name) %>Controller {
29
+ private readonly logger = new Logger(<%= classify(name) %>Controller.name)
30
+
31
+ constructor(private readonly <%= camelize(name) %>Service: <%= classify(name) %>Service) {}
32
+
33
+ @Post('/')
34
+ async create(
35
+ @INVOKE_CONTEXT() invokeContext: IInvoke,
36
+ @Body() createDto: <%= classify(name) %>CreateDto,
37
+ ): Promise<<%= classify(name) %>DataEntity> {
38
+ this.logger.debug('createDto:', createDto)
39
+ return this.<%= camelize(name) %>Service.create(createDto, { invokeContext })
40
+ }
41
+
42
+ <% if (schema) { %>@Get('/')
43
+ async findAll(
44
+ @INVOKE_CONTEXT() invokeContext: IInvoke,
45
+ @Query() searchDto: SearchDto,
46
+ ) {
47
+ this.logger.debug('searchDto:', searchDto)
48
+ const { tenantCode } = getUserContext(invokeContext)
49
+ return await this.<%= camelize(name) %>Service.findAll(tenantCode, searchDto)
50
+ }<% } %>
51
+
52
+ @Get('/:pk/:sk')
53
+ async findOne(@Param() detailDto: DetailDto): Promise<<%= classify(name) %>DataEntity> {
54
+ return this.<%= camelize(name) %>Service.findOne(detailDto)
55
+ }
56
+
57
+ @Patch('/:pk/:sk')
58
+ async update(
59
+ @INVOKE_CONTEXT() invokeContext: IInvoke,
60
+ @Param() detailDto: DetailDto,
61
+ @Body() updateDto: <%= classify(name) %>UpdateDto,
62
+ ) {
63
+ this.logger.debug('updateDto:', updateDto)
64
+ return this.<%= camelize(name) %>Service.update(detailDto, updateDto, { invokeContext })
65
+ }
66
+
67
+ @Delete('/:pk/:sk')
68
+ async remove(
69
+ @INVOKE_CONTEXT() invokeContext: IInvoke,
70
+ @Param() detailDto: DetailDto,
71
+ ) {
72
+ return this.<%= camelize(name) %>Service.remove(detailDto, { invokeContext })
73
+ }
74
+ }
@@ -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,6 @@
1
+ import { IsObject } from 'class-validator'
2
+
3
+ export class <%= classify(name) %>Attributes {
4
+ @IsObject()
5
+ value: object
6
+ }
@@ -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,2 @@
1
+ import { SearchDto } from '@mbc-cqrs-serverless/core'
2
+ export class <%= classify(name) %>SearchDto extends SearchDto {}