@mbc-cqrs-serverless/cli 0.1.4-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 (65) hide show
  1. package/package.json +39 -0
  2. package/templates/.env.local +54 -0
  3. package/templates/.envrc +3 -0
  4. package/templates/.eslintrc.js +50 -0
  5. package/templates/.prettierrc +8 -0
  6. package/templates/README.md +168 -0
  7. package/templates/gitignore +46 -0
  8. package/templates/infra-local/appsync-simulator/.dockerignore +1 -0
  9. package/templates/infra-local/appsync-simulator/Dockerfile +8 -0
  10. package/templates/infra-local/appsync-simulator/package-lock.json +7179 -0
  11. package/templates/infra-local/appsync-simulator/package.json +30 -0
  12. package/templates/infra-local/appsync-simulator/src/main.ts +61 -0
  13. package/templates/infra-local/appsync-simulator/src/resolversConfig.ts +19 -0
  14. package/templates/infra-local/appsync-simulator/src/schema.graphql +28 -0
  15. package/templates/infra-local/appsync-simulator/src/schema.ts +7 -0
  16. package/templates/infra-local/appsync-simulator/src/vtl/readVTL.ts +6 -0
  17. package/templates/infra-local/appsync-simulator/src/vtl/sendMessage.req.vtl +4 -0
  18. package/templates/infra-local/appsync-simulator/src/vtl/sendMessage.res.vtl +1 -0
  19. package/templates/infra-local/cognito-local/.dockerignore +1 -0
  20. package/templates/infra-local/cognito-local/Dockerfile +9 -0
  21. package/templates/infra-local/cognito-local/db/clients.json +17 -0
  22. package/templates/infra-local/cognito-local/db/local_2G7noHgW.json +282 -0
  23. package/templates/infra-local/cognito-local/package-lock.json +2321 -0
  24. package/templates/infra-local/cognito-local/package.json +17 -0
  25. package/templates/infra-local/cognito-local/patches/cognito-local+3.23.2.patch +57 -0
  26. package/templates/infra-local/docker-compose.yml +91 -0
  27. package/templates/infra-local/elasticmq.conf +23 -0
  28. package/templates/infra-local/resources.sh +11 -0
  29. package/templates/infra-local/scripts/trigger_ddb_stream.sh +69 -0
  30. package/templates/infra-local/serverless.yml +306 -0
  31. package/templates/jest.config.js +4 -0
  32. package/templates/nest-cli.json +16 -0
  33. package/templates/package.json +118 -0
  34. package/templates/prisma/ddb.ts +232 -0
  35. package/templates/prisma/dynamodbs/cqrs.json +1 -0
  36. package/templates/prisma/dynamodbs/cqrs_desc.json +18 -0
  37. package/templates/prisma/dynamodbs/sequences.json +14 -0
  38. package/templates/prisma/dynamodbs/tasks.json +18 -0
  39. package/templates/prisma/schema.prisma +45 -0
  40. package/templates/src/event-factory.ts +7 -0
  41. package/templates/src/helpers/get-order.ts +19 -0
  42. package/templates/src/helpers/index.ts +1 -0
  43. package/templates/src/main.module.ts +26 -0
  44. package/templates/src/main.ts +7 -0
  45. package/templates/src/master/dto/master-attributes.dto.ts +6 -0
  46. package/templates/src/master/dto/master-command.dto.ts +12 -0
  47. package/templates/src/master/entity/master-command.entity.ts +13 -0
  48. package/templates/src/master/entity/master-data-list.entity.ts +13 -0
  49. package/templates/src/master/entity/master-data.entity.ts +13 -0
  50. package/templates/src/master/handler/master-rds.handler.ts +59 -0
  51. package/templates/src/master/master.controller.ts +83 -0
  52. package/templates/src/master/master.module.ts +19 -0
  53. package/templates/src/master/master.service.ts +58 -0
  54. package/templates/src/prisma/index.ts +5 -0
  55. package/templates/src/prisma/interfaces/index.ts +1 -0
  56. package/templates/src/prisma/interfaces/prisma-module-options.interface.ts +50 -0
  57. package/templates/src/prisma/prisma.constants.ts +2 -0
  58. package/templates/src/prisma/prisma.logging.middleware.ts +20 -0
  59. package/templates/src/prisma/prisma.module.ts +75 -0
  60. package/templates/src/prisma/prisma.service.ts +45 -0
  61. package/templates/src/repl.ts +21 -0
  62. package/templates/test/api.http +42 -0
  63. package/templates/test/jest-e2e.json +9 -0
  64. package/templates/tsconfig.build.json +4 -0
  65. package/templates/tsconfig.json +25 -0
@@ -0,0 +1,83 @@
1
+ import {
2
+ CommandService,
3
+ DataService,
4
+ DetailDto,
5
+ IInvoke,
6
+ INVOKE_CONTEXT,
7
+ SearchDto,
8
+ } from '@mbc-cqrs-sererless/core'
9
+ import {
10
+ Body,
11
+ Controller,
12
+ Get,
13
+ Logger,
14
+ NotFoundException,
15
+ Param,
16
+ Post,
17
+ Query,
18
+ } from '@nestjs/common'
19
+ import { ApiTags } from '@nestjs/swagger'
20
+
21
+ import { MasterCommandDto } from './dto/master-command.dto'
22
+ import { MasterCommandEntity } from './entity/master-command.entity'
23
+ import { MasterDataEntity } from './entity/master-data.entity'
24
+ import { MasterDataListEntity } from './entity/master-data-list.entity'
25
+ import { MasterService } from './master.service'
26
+
27
+ @Controller('api/master')
28
+ @ApiTags('master')
29
+ export class MasterController {
30
+ private readonly logger = new Logger(MasterController.name)
31
+
32
+ constructor(
33
+ private readonly commandService: CommandService,
34
+ private readonly dataService: DataService,
35
+ private readonly masterService: MasterService,
36
+ ) {}
37
+
38
+ @Post('/')
39
+ async publishCommand(
40
+ @INVOKE_CONTEXT() invokeContext: IInvoke,
41
+ @Body() masterDto: MasterCommandDto,
42
+ ): Promise<MasterDataEntity> {
43
+ this.logger.debug('cmd:', masterDto)
44
+ this.logger.debug('commandService:' + this.commandService.tableName)
45
+ const item = await this.commandService.publish(masterDto, { invokeContext })
46
+ return new MasterDataEntity(item as MasterDataEntity)
47
+ }
48
+
49
+ @Get('command/:pk/:sk')
50
+ async getCommand(
51
+ @Param() detailDto: DetailDto,
52
+ ): Promise<MasterCommandEntity> {
53
+ this.logger.debug('commandService:' + this.commandService.tableName)
54
+ const item = await this.commandService.getItem(detailDto)
55
+ if (!item) {
56
+ throw new NotFoundException()
57
+ }
58
+ this.logger.debug('item:', item)
59
+ return new MasterCommandEntity(item as MasterCommandEntity)
60
+ }
61
+
62
+ @Get('data/:pk/:sk')
63
+ async getData(@Param() detailDto: DetailDto): Promise<MasterDataEntity> {
64
+ this.logger.debug('dataService:' + this.dataService.tableName)
65
+ const item = await this.dataService.getItem(detailDto)
66
+ if (!item) {
67
+ throw new NotFoundException()
68
+ }
69
+ this.logger.debug('item:', item)
70
+ return new MasterDataEntity(item as MasterDataEntity)
71
+ }
72
+
73
+ @Get('data/:pk')
74
+ async listDataByPk(@Param('pk') pk: string): Promise<MasterDataListEntity> {
75
+ const res = await this.dataService.listItemsByPk(pk)
76
+ return new MasterDataListEntity(res as MasterDataListEntity)
77
+ }
78
+
79
+ @Get('data')
80
+ async searchData(@Query() searchDto: SearchDto) {
81
+ return await this.masterService.searchData(searchDto)
82
+ }
83
+ }
@@ -0,0 +1,19 @@
1
+ import { CommandModule } from '@mbc-cqrs-sererless/core'
2
+ import { Module } from '@nestjs/common'
3
+
4
+ import { MasterDataSyncRdsHandler } from './handler/master-rds.handler'
5
+ import { MasterController } from './master.controller'
6
+ import { MasterService } from './master.service'
7
+
8
+ @Module({
9
+ imports: [
10
+ CommandModule.register({
11
+ tableName: 'master',
12
+ dataSyncHandlers: [MasterDataSyncRdsHandler],
13
+ }),
14
+ ],
15
+ controllers: [MasterController],
16
+ providers: [MasterService],
17
+ exports: [MasterService],
18
+ })
19
+ export class MasterModule {}
@@ -0,0 +1,58 @@
1
+ import { SearchDto } from '@mbc-cqrs-sererless/core'
2
+ import { Injectable, Logger } from '@nestjs/common'
3
+ import { Prisma } from '@prisma/client'
4
+ import { getOrderBys } from 'src/helpers'
5
+ import { PrismaService } from 'src/prisma'
6
+
7
+ import { MasterDataEntity } from './entity/master-data.entity'
8
+ import { MasterDataListEntity } from './entity/master-data-list.entity'
9
+
10
+ @Injectable()
11
+ export class MasterService {
12
+ private readonly logger = new Logger(MasterService.name)
13
+
14
+ constructor(private readonly prismaService: PrismaService) {}
15
+
16
+ async searchData(searchDto: SearchDto): Promise<MasterDataListEntity> {
17
+ const where: Prisma.MasterWhereInput = {
18
+ isDeleted: false,
19
+ }
20
+ if (searchDto.keyword?.trim()) {
21
+ where.name = { contains: searchDto.keyword.trim() }
22
+ }
23
+ if (searchDto.id) {
24
+ where.id = searchDto.id
25
+ }
26
+ if (searchDto.pk) {
27
+ where.pk = searchDto.pk
28
+ }
29
+ if (searchDto.sk) {
30
+ where.sk = searchDto.sk
31
+ }
32
+
33
+ const { pageSize = 10, page = 1, orderBys = ['-createdAt'] } = searchDto
34
+
35
+ const [total, items] = await Promise.all([
36
+ this.prismaService.master.count({ where }),
37
+ this.prismaService.master.findMany({
38
+ where,
39
+ take: pageSize,
40
+ skip: pageSize * (page - 1),
41
+ orderBy: getOrderBys<Prisma.MasterOrderByWithRelationInput>(orderBys),
42
+ }),
43
+ ])
44
+
45
+ return new MasterDataListEntity({
46
+ total,
47
+ items: items.map(
48
+ (item) =>
49
+ new MasterDataEntity({
50
+ ...item,
51
+ attributes: {
52
+ master: item.atttributesMaster as object,
53
+ },
54
+ }),
55
+ ),
56
+ })
57
+ }
58
+ }
@@ -0,0 +1,5 @@
1
+ export * from './interfaces'
2
+ export * from './prisma.constants'
3
+ export * from './prisma.logging.middleware'
4
+ export * from './prisma.module'
5
+ export * from './prisma.service'
@@ -0,0 +1 @@
1
+ export * from './prisma-module-options.interface'
@@ -0,0 +1,50 @@
1
+ import { ModuleMetadata, Type } from '@nestjs/common'
2
+ import { Prisma } from '@prisma/client'
3
+
4
+ export interface PrismaModuleOptions {
5
+ /**
6
+ * If "true", registers `PrismaModule` as a global module.
7
+ * See: https://docs.nestjs.com/modules#global-modules
8
+ */
9
+ isGlobal?: boolean
10
+
11
+ prismaServiceOptions?: PrismaServiceOptions
12
+ }
13
+
14
+ export interface PrismaServiceOptions {
15
+ /**
16
+ * Pass options directly to the `PrismaClient`.
17
+ * See: https://www.prisma.io/docs/reference/api-reference/prisma-client-reference/#prismaclient
18
+ */
19
+ prismaOptions?: Prisma.PrismaClientOptions
20
+
21
+ /**
22
+ * If "true", `PrismaClient` explicitly creates a connection pool and your first query will respond instantly.
23
+ *
24
+ * For most use cases the lazy connect behavior of `PrismaClient` will do. The first query of `PrismaClient` creates the connection pool.
25
+ * See: https://www.prisma.io/docs/concepts/components/prisma-client/working-with-prismaclient/connection-management
26
+ */
27
+ explicitConnect?: boolean
28
+
29
+ /**
30
+ * Apply Prisma middlewares to perform actions before or after db queries.
31
+ *
32
+ * See: https://www.prisma.io/docs/concepts/components/prisma-client/middleware
33
+ */
34
+ middlewares?: Array<Prisma.Middleware>
35
+ }
36
+
37
+ export interface PrismaOptionsFactory {
38
+ createPrismaOptions(): Promise<PrismaServiceOptions> | PrismaServiceOptions
39
+ }
40
+
41
+ export interface PrismaModuleAsyncOptions
42
+ extends Pick<ModuleMetadata, 'imports'> {
43
+ isGlobal?: boolean
44
+ useExisting?: Type<PrismaOptionsFactory>
45
+ useClass?: Type<PrismaOptionsFactory>
46
+ useFactory?: (
47
+ ...args: any[]
48
+ ) => Promise<PrismaServiceOptions> | PrismaServiceOptions
49
+ inject?: any[]
50
+ }
@@ -0,0 +1,2 @@
1
+ export const PRISMA_SERVICE_OPTIONS = 'PRISMA_SERVICE_OPTIONS'
2
+ export const PRISMA_EXPLICIT_CONNECT = 'PRISMA_EXPLICIT_CONNECT'
@@ -0,0 +1,20 @@
1
+ import { Logger } from '@nestjs/common'
2
+ import { Prisma } from '@prisma/client'
3
+
4
+ const logger = new Logger('Prisma')
5
+
6
+ export function prismaLoggingMiddleware(): Prisma.Middleware {
7
+ return async (params, next) => {
8
+ const before = Date.now()
9
+
10
+ const result = await next(params)
11
+
12
+ const after = Date.now()
13
+
14
+ logger.debug(
15
+ `Query ${params.model}.${params.action} took ${after - before}ms`,
16
+ )
17
+
18
+ return result
19
+ }
20
+ }
@@ -0,0 +1,75 @@
1
+ import { DynamicModule, Module, Provider } from '@nestjs/common'
2
+
3
+ import {
4
+ PrismaModuleAsyncOptions,
5
+ PrismaModuleOptions,
6
+ PrismaOptionsFactory,
7
+ } from './interfaces'
8
+ import { PRISMA_SERVICE_OPTIONS } from './prisma.constants'
9
+ import { PrismaService } from './prisma.service'
10
+
11
+ @Module({
12
+ providers: [PrismaService],
13
+ exports: [PrismaService],
14
+ })
15
+ export class PrismaModule {
16
+ static forRoot(options: PrismaModuleOptions = {}): DynamicModule {
17
+ return {
18
+ global: options.isGlobal,
19
+ module: PrismaModule,
20
+ providers: [
21
+ {
22
+ provide: PRISMA_SERVICE_OPTIONS,
23
+ useValue: options.prismaServiceOptions,
24
+ },
25
+ ],
26
+ }
27
+ }
28
+
29
+ static forRootAsync(options: PrismaModuleAsyncOptions): DynamicModule {
30
+ return {
31
+ global: options.isGlobal,
32
+ module: PrismaModule,
33
+ imports: options.imports || [],
34
+ providers: this.createAsyncProviders(options),
35
+ }
36
+ }
37
+
38
+ private static createAsyncProviders(
39
+ options: PrismaModuleAsyncOptions,
40
+ ): Provider[] {
41
+ if (options.useExisting || options.useFactory) {
42
+ return this.createAsyncOptionsProvider(options)
43
+ }
44
+
45
+ return [
46
+ ...this.createAsyncOptionsProvider(options),
47
+ {
48
+ provide: options.useClass,
49
+ useClass: options.useClass,
50
+ },
51
+ ]
52
+ }
53
+
54
+ private static createAsyncOptionsProvider(
55
+ options: PrismaModuleAsyncOptions,
56
+ ): Provider[] {
57
+ if (options.useFactory) {
58
+ return [
59
+ {
60
+ provide: PRISMA_SERVICE_OPTIONS,
61
+ useFactory: options.useFactory,
62
+ inject: options.inject || [],
63
+ },
64
+ ]
65
+ }
66
+ return [
67
+ {
68
+ provide: PRISMA_SERVICE_OPTIONS,
69
+ useFactory: async (optionsFactory: PrismaOptionsFactory) =>
70
+ await optionsFactory.createPrismaOptions(),
71
+ inject: [options.useExisting || options.useClass],
72
+ },
73
+ ]
74
+ }
75
+ }
@@ -0,0 +1,45 @@
1
+ import {
2
+ Inject,
3
+ Injectable,
4
+ Logger,
5
+ OnModuleInit,
6
+ Optional,
7
+ } from '@nestjs/common'
8
+ import { Prisma, PrismaClient } from '@prisma/client'
9
+
10
+ import { PrismaServiceOptions } from './interfaces'
11
+ import { PRISMA_SERVICE_OPTIONS } from './prisma.constants'
12
+
13
+ @Injectable()
14
+ export class PrismaService
15
+ extends PrismaClient<Prisma.PrismaClientOptions, 'query' | 'error'>
16
+ implements OnModuleInit
17
+ {
18
+ private readonly logger = new Logger(PrismaService.name)
19
+
20
+ constructor(
21
+ @Optional()
22
+ @Inject(PRISMA_SERVICE_OPTIONS)
23
+ private readonly prismaServiceOptions: PrismaServiceOptions = {},
24
+ ) {
25
+ super(prismaServiceOptions.prismaOptions)
26
+
27
+ if (this.prismaServiceOptions.middlewares) {
28
+ this.prismaServiceOptions.middlewares.forEach((middleware) =>
29
+ this.$use(middleware),
30
+ )
31
+ }
32
+
33
+ this.$on('query', (e) => {
34
+ this.logger.debug('Query: ' + e.query)
35
+ this.logger.debug('Params: ' + e.params)
36
+ this.logger.debug('Duration: ' + e.duration + 'ms')
37
+ })
38
+ }
39
+
40
+ async onModuleInit() {
41
+ if (this.prismaServiceOptions.explicitConnect) {
42
+ await this.$connect()
43
+ }
44
+ }
45
+ }
@@ -0,0 +1,21 @@
1
+ /* eslint-disable no-console */
2
+ import { repl } from '@nestjs/core'
3
+ import { AppModule } from '@mbc-cqrs-sererless/core'
4
+
5
+ import { MainModule } from './main.module'
6
+
7
+ async function bootstrap() {
8
+ const replServer = await repl(
9
+ AppModule.forRoot({
10
+ rootModule: MainModule,
11
+ }),
12
+ )
13
+ replServer.setupHistory('.nestjs_repl_history', (err) => {
14
+ if (err) {
15
+ console.error(err)
16
+ }
17
+ })
18
+ }
19
+ bootstrap()
20
+
21
+ // npm run start -- --watch --entryFile repl
@@ -0,0 +1,42 @@
1
+ @endpoint = http://localhost:3000
2
+ @cognitoEndpoint = http://localhost:9229
3
+ @clientId = dnk8y7ii3wled35p3lw0l2cd7
4
+ # account's username
5
+ @username = admin2
6
+ # account's password
7
+ @password = admin1234
8
+ # account's email
9
+ @email = admin2@example.com
10
+
11
+ @apiBaseUrl = {{endpoint}}/api
12
+ @eventBaseUrl = {{endpoint}}/event
13
+
14
+ ###
15
+ GET {{endpoint}} HTTP/1.1
16
+
17
+ ###
18
+ # login
19
+ # @name login_cognito
20
+ POST {{cognitoEndpoint}}
21
+ Accept: application/json
22
+ Content-Type: application/x-amz-json-1.1
23
+ X-Amz-Target: AWSCognitoIdentityProviderService.InitiateAuth
24
+
25
+ {
26
+ "AuthFlow": "USER_PASSWORD_AUTH",
27
+ "ClientId": "{{clientId}}",
28
+ "AuthParameters": {
29
+ "USERNAME": "{{username}}",
30
+ "PASSWORD": "{{password}}"
31
+ },
32
+ "ClientMetadata": {}
33
+ }
34
+
35
+ ###
36
+ @token = {{login_cognito.response.body.AuthenticationResult.IdToken}}
37
+ ###
38
+
39
+ # Health
40
+ GET {{endpoint}}
41
+ Accept: application/json
42
+ Authorization: {{token}}
@@ -0,0 +1,9 @@
1
+ {
2
+ "moduleFileExtensions": ["js", "json", "ts"],
3
+ "rootDir": ".",
4
+ "testEnvironment": "node",
5
+ "testRegex": ".e2e-spec.ts$",
6
+ "transform": {
7
+ "^.+\\.(t|j)s$": "ts-jest"
8
+ }
9
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
4
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "compilerOptions": {
3
+ "module": "commonjs",
4
+ "declaration": false,
5
+ "removeComments": true,
6
+ "emitDecoratorMetadata": true,
7
+ "experimentalDecorators": true,
8
+ "allowSyntheticDefaultImports": true,
9
+ "target": "ES2021",
10
+ "sourceMap": true,
11
+ "outDir": "./dist",
12
+ "baseUrl": "./",
13
+ "incremental": true,
14
+ "skipLibCheck": true,
15
+ "strictNullChecks": false,
16
+ "noImplicitAny": false,
17
+ "strictBindCallApply": false,
18
+ "forceConsistentCasingInFileNames": false,
19
+ "noFallthroughCasesInSwitch": false,
20
+ "esModuleInterop": true,
21
+ "noLib": false,
22
+ "noUnusedLocals": false
23
+ },
24
+ "include": ["src/*", "src/**/*"]
25
+ }