@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,118 @@
1
+ {
2
+ "name": "cqrs-sls",
3
+ "version": "0.0.1",
4
+ "description": "",
5
+ "author": "",
6
+ "private": true,
7
+ "license": "UNLICENSED",
8
+ "main": "./dist/main.js",
9
+ "scripts": {
10
+ "postinstall": "prisma generate",
11
+ "build": "nest build --watch",
12
+ "build:prod": "nest build",
13
+ "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
14
+ "start:repl": "nest start --watch --entryFile repl",
15
+ "offline:docker:build": "cd infra-local && docker compose up --build --remove-orphans",
16
+ "offline:docker": "cd infra-local && mkdir -p docker-data/.cognito && cp -r cognito-local/db docker-data/.cognito && docker compose up --remove-orphans",
17
+ "offline:sls": "/bin/bash ./infra-local/scripts/trigger_ddb_stream.sh & ln -f .env $PWD/infra-local/.env && cd infra-local && NODE_ENV=development AWS_ACCESS_KEY_ID=DUMMYIDEXAMPLE AWS_SECRET_ACCESS_KEY=DUMMYEXAMPLEKEY SLS_DEBUG=* serverless offline start",
18
+ "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
19
+ "test": "jest",
20
+ "test:watch": "jest --watch",
21
+ "test:cov": "jest --coverage",
22
+ "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
23
+ "test:e2e": "jest --config ./test/jest-e2e.json",
24
+ "migrate:dev": "prisma migrate dev",
25
+ "migrate:rds": "prisma migrate deploy",
26
+ "migrate:ddb": "ts-node prisma/ddb.ts",
27
+ "migrate": "npm run migrate:rds && npm run migrate:ddb"
28
+ },
29
+ "dependencies": {
30
+ "@mbc-cqrs-sererless/core": "",
31
+ "@prisma/client": "^5.7.1"
32
+ },
33
+ "devDependencies": {
34
+ "@aws-sdk/client-dynamodb": "^3.478.0",
35
+ "@aws-sdk/client-s3": "^3.478.0",
36
+ "@aws-sdk/client-sesv2": "^3.478.0",
37
+ "@aws-sdk/client-sfn": "^3.478.0",
38
+ "@aws-sdk/client-sns": "^3.478.0",
39
+ "@aws-sdk/client-sqs": "^3.478.0",
40
+ "@aws-sdk/credential-provider-node": "^3.451.0",
41
+ "@aws-sdk/lib-storage": "^3.478.0",
42
+ "@aws-sdk/s3-request-presigner": "^3.478.0",
43
+ "@aws-sdk/signature-v4": "^3.374.0",
44
+ "@aws-sdk/util-create-request": "^3.468.0",
45
+ "@aws-sdk/util-dynamodb": "^3.360.0",
46
+ "@mbc-cqrs-sererless/cli": "",
47
+ "@nestjs/cli": "^10.2.1",
48
+ "@nestjs/common": "^10.3.0",
49
+ "@nestjs/core": "^10.3.0",
50
+ "@nestjs/schematics": "^10.0.3",
51
+ "@nestjs/swagger": "^7.1.17",
52
+ "@nestjs/testing": "^10.3.0",
53
+ "@types/aws-lambda": "^8.10.130",
54
+ "@types/express": "^4.17.21",
55
+ "@types/jest": "^29.5.11",
56
+ "@types/node": "^20.10.5",
57
+ "@types/node-fetch": "^2.6.9",
58
+ "@types/supertest": "^6.0.1",
59
+ "@typescript-eslint/eslint-plugin": "^6.15.0",
60
+ "@typescript-eslint/parser": "^6.15.0",
61
+ "class-transformer": "^0.5.1",
62
+ "class-validator": "^0.14.0",
63
+ "eslint": "^8.56.0",
64
+ "eslint-config-prettier": "^9.1.0",
65
+ "eslint-plugin-import": "^2.29.1",
66
+ "eslint-plugin-prettier": "^5.1.2",
67
+ "eslint-plugin-simple-import-sort": "^10.0.0",
68
+ "jest": "^29.7.0",
69
+ "nestjs-spelunker": "^1.3.0",
70
+ "prettier": "^3.1.1",
71
+ "prisma": "^5.7.1",
72
+ "serverless": "^3.38.0",
73
+ "serverless-dynamodb": "^0.2.47",
74
+ "serverless-localstack": "^1.1.2",
75
+ "serverless-offline": "^13.3.2",
76
+ "serverless-offline-aws-eventbridge": "^2.1.0",
77
+ "serverless-offline-dynamodb-streams": "^7.0.0",
78
+ "serverless-offline-lambda": "^1.0.6",
79
+ "serverless-offline-local-authorizers-plugin": "^1.2.0",
80
+ "serverless-offline-scheduler": "^0.5.0",
81
+ "serverless-offline-ses-v2": "^1.0.4",
82
+ "serverless-offline-sns": "^0.77.2",
83
+ "serverless-offline-sqs": "^8.0.0",
84
+ "serverless-offline-ssm": "^6.2.0",
85
+ "serverless-offline-watcher": "^1.1.0",
86
+ "serverless-plugin-offline-dynamodb-stream": "^1.0.20",
87
+ "serverless-s3-local": "^0.8.1",
88
+ "serverless-step-functions": "^3.18.0",
89
+ "serverless-step-functions-local": "^0.5.1",
90
+ "source-map-support": "^0.5.21",
91
+ "supertest": "^6.3.3",
92
+ "terser-webpack-plugin": "^5.3.9",
93
+ "ts-jest": "^29.1.1",
94
+ "ts-loader": "^9.5.1",
95
+ "ts-node": "^10.9.2",
96
+ "tsconfig-paths": "4.2.0",
97
+ "typescript": "^5.3.3",
98
+ "ulid": "^2.3.0",
99
+ "webpack": "^5.88.2"
100
+ },
101
+ "jest": {
102
+ "moduleFileExtensions": [
103
+ "js",
104
+ "json",
105
+ "ts"
106
+ ],
107
+ "rootDir": "src",
108
+ "testRegex": ".*\\.spec\\.ts$",
109
+ "transform": {
110
+ "^.+\\.(t|j)s$": "ts-jest"
111
+ },
112
+ "collectCoverageFrom": [
113
+ "**/*.(t|j)s"
114
+ ],
115
+ "coverageDirectory": "../coverage",
116
+ "testEnvironment": "node"
117
+ }
118
+ }
@@ -0,0 +1,232 @@
1
+ import {
2
+ CreateTableCommand,
3
+ CreateTableCommandInput,
4
+ DescribeContinuousBackupsCommand,
5
+ DescribeTableCommand,
6
+ DescribeTimeToLiveCommand,
7
+ DynamoDBClient,
8
+ ResourceNotFoundException,
9
+ UpdateContinuousBackupsCommand,
10
+ UpdateTimeToLiveCommand,
11
+ } from '@aws-sdk/client-dynamodb'
12
+ import dotenv from 'dotenv'
13
+ import { appendFileSync, readFileSync, readdirSync, writeFileSync } from 'fs'
14
+ import path from 'path'
15
+
16
+ dotenv.config()
17
+
18
+ const envFilePath = './.env'
19
+ const tableDir = path.join(__dirname, 'dynamodbs')
20
+ const cqrsModuleFname = 'cqrs.json'
21
+ const cqrsTableDecsFname = 'cqrs_desc.json'
22
+
23
+ const tablePrefix = `${process.env.NODE_ENV}-${process.env.APP_NAME}-`
24
+
25
+ const client = new DynamoDBClient({
26
+ endpoint: process.env.DYNAMODB_ENDPOINT,
27
+ region: process.env.DYNAMODB_REGION,
28
+ })
29
+
30
+ main().catch((e) => {
31
+ console.error(e)
32
+ process.exit(1)
33
+ })
34
+
35
+ let cnt = 0
36
+
37
+ async function main() {
38
+ // clear table stream arn in .env
39
+ clearTableStreamArnInEnv()
40
+ // create cqrs tables
41
+ await createCqrsTables()
42
+ // create other tables
43
+ await Promise.all(
44
+ readdirSync(tableDir)
45
+ .filter(
46
+ (fname) => fname !== cqrsModuleFname && fname !== cqrsTableDecsFname,
47
+ )
48
+ .map((fname) =>
49
+ createTable(
50
+ JSON.parse(readFileSync(path.join(tableDir, fname)).toString()),
51
+ ),
52
+ ),
53
+ )
54
+ if (cnt) {
55
+ console.log('\n' + cnt + ' tables were created successfully')
56
+ } else {
57
+ console.log('\nNo tables were created')
58
+ }
59
+ }
60
+
61
+ async function createCqrsTables() {
62
+ const cqrsModules: string[] =
63
+ JSON.parse(readFileSync(path.join(tableDir, cqrsModuleFname)).toString()) ||
64
+ []
65
+ const desc: CreateTableCommandInput = JSON.parse(
66
+ readFileSync(path.join(tableDir, cqrsTableDecsFname)).toString(),
67
+ )
68
+
69
+ for (const name of cqrsModules) {
70
+ const cmdDesc = { ...desc, TableName: name + '-command' }
71
+ const dataDecs = {
72
+ ...cmdDesc,
73
+ StreamSpecification: undefined,
74
+ TableName: name + '-data',
75
+ }
76
+ const historyDesc = { ...dataDecs, TableName: name + '-history' }
77
+ await Promise.all([cmdDesc, dataDecs, historyDesc].map(createTable))
78
+ }
79
+ }
80
+
81
+ async function createTable(config: CreateTableCommandInput) {
82
+ // random wait
83
+ if (process.env.NODE_ENV !== 'local') {
84
+ await new Promise((r) =>
85
+ setTimeout(r, 200 + Math.floor(Math.random() * 5000)),
86
+ )
87
+ }
88
+
89
+ const originName = config.TableName as string
90
+ console.log('\ncreating table:', originName)
91
+
92
+ // add table prefix
93
+ config.TableName = tablePrefix + config.TableName
94
+
95
+ // check table is already created
96
+ try {
97
+ const tableDesc = await client.send(
98
+ new DescribeTableCommand({ TableName: config.TableName }),
99
+ )
100
+ if (tableDesc.Table?.TableArn) {
101
+ console.log(
102
+ 'table exists:',
103
+ tableDesc.Table.TableArn,
104
+ ' => stream:',
105
+ tableDesc.Table.LatestStreamArn,
106
+ )
107
+
108
+ await updateTable(config.TableName)
109
+
110
+ if (tableDesc.Table.LatestStreamArn) {
111
+ appendTableStreamArnToEnv(originName, tableDesc.Table.LatestStreamArn)
112
+ }
113
+
114
+ return tableDesc.Table.TableArn
115
+ }
116
+ } catch (error) {
117
+ if (!(error instanceof ResourceNotFoundException)) {
118
+ throw error
119
+ }
120
+ }
121
+
122
+ // create table
123
+ const table = await client.send(new CreateTableCommand(config))
124
+ if (table.TableDescription?.TableArn) {
125
+ console.log(
126
+ 'table created with arn: `',
127
+ table.TableDescription?.TableArn,
128
+ '`, and stream arn:`',
129
+ table.TableDescription?.LatestStreamArn,
130
+ '`',
131
+ )
132
+ cnt++
133
+
134
+ if (table.TableDescription?.LatestStreamArn) {
135
+ appendTableStreamArnToEnv(
136
+ originName,
137
+ table.TableDescription?.LatestStreamArn,
138
+ )
139
+ }
140
+ }
141
+ return table.TableDescription?.TableArn
142
+ }
143
+
144
+ async function updateTable(TableName: string) {
145
+ try {
146
+ // Time to live
147
+ const ttlDesc = await client.send(
148
+ new DescribeTimeToLiveCommand({ TableName }),
149
+ )
150
+ if (ttlDesc.TimeToLiveDescription?.TimeToLiveStatus === 'DISABLED') {
151
+ console.log('enable time to live for table:', TableName)
152
+
153
+ await client.send(
154
+ new UpdateTimeToLiveCommand({
155
+ TableName,
156
+ TimeToLiveSpecification: {
157
+ Enabled: true,
158
+ AttributeName: 'ttl',
159
+ },
160
+ }),
161
+ )
162
+
163
+ // random wait
164
+ if (process.env.NODE_ENV !== 'local') {
165
+ await new Promise((r) =>
166
+ setTimeout(r, Math.floor(Math.random() * 5000)),
167
+ )
168
+ }
169
+ }
170
+
171
+ // Point-in-time recovery for production
172
+ if (process.env.NODE_ENV !== 'local') {
173
+ const pitDesc = await client.send(
174
+ new DescribeContinuousBackupsCommand({ TableName }),
175
+ )
176
+ if (
177
+ pitDesc.ContinuousBackupsDescription?.PointInTimeRecoveryDescription
178
+ ?.PointInTimeRecoveryStatus === 'DISABLED'
179
+ ) {
180
+ console.log('enable point-in-time recovery for table:', TableName)
181
+
182
+ await client.send(
183
+ new UpdateContinuousBackupsCommand({
184
+ TableName,
185
+ PointInTimeRecoverySpecification: {
186
+ PointInTimeRecoveryEnabled: true,
187
+ },
188
+ }),
189
+ )
190
+
191
+ // random wait
192
+ if (process.env.NODE_ENV !== 'local') {
193
+ await new Promise((r) =>
194
+ setTimeout(r, Math.floor(Math.random() * 5000)),
195
+ )
196
+ }
197
+ }
198
+ }
199
+ } catch (error) {
200
+ console.error(error)
201
+ }
202
+ }
203
+
204
+ function appendTableStreamArnToEnv(name: string, streamArn: string) {
205
+ if (process.env.NODE_ENV !== 'local') {
206
+ return
207
+ }
208
+
209
+ try {
210
+ appendFileSync(
211
+ envFilePath,
212
+ `\nLOCAL_DDB_${name
213
+ .replace('-command', '')
214
+ .toUpperCase()}_STREAM=${streamArn}`,
215
+ )
216
+ } catch (error) {
217
+ console.error('Write to .env error!', error)
218
+ }
219
+ }
220
+
221
+ function clearTableStreamArnInEnv() {
222
+ if (process.env.NODE_ENV !== 'local') {
223
+ return
224
+ }
225
+
226
+ console.log('Clear table stream arn in .env')
227
+ const lines = readFileSync(envFilePath, 'utf-8').split('\n')
228
+ const newLines = lines.filter(
229
+ (line) => !line.match(/^LOCAL_DDB_.*_STREAM.*$/),
230
+ )
231
+ writeFileSync(envFilePath, newLines.join('\n'))
232
+ }
@@ -0,0 +1 @@
1
+ ["master"]
@@ -0,0 +1,18 @@
1
+ {
2
+ "TableName": "",
3
+ "AttributeDefinitions": [
4
+ { "AttributeName": "pk", "AttributeType": "S" },
5
+ { "AttributeName": "sk", "AttributeType": "S" }
6
+ ],
7
+ "KeySchema": [
8
+ { "AttributeName": "pk", "KeyType": "HASH" },
9
+ { "AttributeName": "sk", "KeyType": "RANGE" }
10
+ ],
11
+ "BillingMode": "PAY_PER_REQUEST",
12
+ "StreamSpecification": {
13
+ "StreamEnabled": true,
14
+ "StreamViewType": "NEW_IMAGE"
15
+ },
16
+ "TableClass": "STANDARD",
17
+ "DeletionProtectionEnabled": true
18
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "TableName": "sequences",
3
+ "AttributeDefinitions": [
4
+ { "AttributeName": "pk", "AttributeType": "S" },
5
+ { "AttributeName": "sk", "AttributeType": "S" }
6
+ ],
7
+ "KeySchema": [
8
+ { "AttributeName": "pk", "KeyType": "HASH" },
9
+ { "AttributeName": "sk", "KeyType": "RANGE" }
10
+ ],
11
+ "BillingMode": "PAY_PER_REQUEST",
12
+ "TableClass": "STANDARD",
13
+ "DeletionProtectionEnabled": true
14
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "TableName": "tasks",
3
+ "AttributeDefinitions": [
4
+ { "AttributeName": "pk", "AttributeType": "S" },
5
+ { "AttributeName": "sk", "AttributeType": "S" }
6
+ ],
7
+ "KeySchema": [
8
+ { "AttributeName": "pk", "KeyType": "HASH" },
9
+ { "AttributeName": "sk", "KeyType": "RANGE" }
10
+ ],
11
+ "BillingMode": "PAY_PER_REQUEST",
12
+ "StreamSpecification": {
13
+ "StreamEnabled": true,
14
+ "StreamViewType": "NEW_IMAGE"
15
+ },
16
+ "TableClass": "STANDARD",
17
+ "DeletionProtectionEnabled": true
18
+ }
@@ -0,0 +1,45 @@
1
+ // This is your Prisma schema file,
2
+ // learn more about it in the docs: https://pris.ly/d/prisma-schema
3
+
4
+ generator client {
5
+ provider = "prisma-client-js"
6
+ binaryTargets = ["native", "linux-arm64-openssl-1.0.x"]
7
+ // binaryTargets = ["native", "rhel-openssl-1.0.x"]
8
+ }
9
+
10
+ datasource db {
11
+ provider = "mysql"
12
+ url = env("DATABASE_URL")
13
+ relationMode = "prisma"
14
+ }
15
+
16
+ model Master {
17
+ id String @id
18
+ cpk String // コマンド用PK
19
+ csk String // コマンド用SK
20
+ pk String // データ用PK, MASTER#unigrab (テナントコード)
21
+ sk String // データ用SK, マスタ種別コード#マスタコード
22
+ masterTypeCode String @map("master_type_code") // マスタ種別コード, 【共通マスタ】 or 【テナント固有マスタ】
23
+ masterCode String @map("master_code") // マスタコード
24
+ tenantCode String @map("tenant_code") // テナントコード, 【テナントコードマスタ】
25
+ seq Int @default(0) // 並び順, 採番機能を使用する
26
+ code String // レコードのコード, マスタ種別コード#マスタコード
27
+ name String // レコード名, 名前
28
+ version Int // バージョン
29
+ isDeleted Boolean @default(false) @map("is_deleted") // 削除フラグ
30
+ createdBy String @default("") @map("created_by") // 作成者
31
+ createdIp String @default("") @map("created_ip") // 作成IP, IPv6も考慮する
32
+ createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(0) // 作成日時
33
+ updatedBy String @default("") @map("updated_by") // 更新者
34
+ updatedIp String @default("") @map("updated_ip") // 更新IP, IPv6も考慮する
35
+ updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamp(0) // 更新日時
36
+
37
+ atttributesMaster Json? @map("atttributes_master")
38
+
39
+ @@unique([cpk, csk])
40
+ @@unique([pk, sk])
41
+ @@unique([tenantCode, code])
42
+ @@unique([tenantCode, masterTypeCode, masterCode])
43
+ @@index([tenantCode, name])
44
+ @@map("masters")
45
+ }
@@ -0,0 +1,7 @@
1
+ import { DefaultEventFactory, EventFactory } from '@mbc-cqrs-sererless/core'
2
+ import { Logger } from '@nestjs/common'
3
+
4
+ @EventFactory()
5
+ export class CustomEventFactory extends DefaultEventFactory {
6
+ private readonly logger = new Logger(CustomEventFactory.name)
7
+ }
@@ -0,0 +1,19 @@
1
+ import { Prisma } from '@prisma/client'
2
+
3
+ export function getOrderBy(order: string) {
4
+ let orderValue: Prisma.SortOrder = Prisma.SortOrder.asc,
5
+ orderKey = order
6
+ if (order.startsWith('-')) {
7
+ orderValue = Prisma.SortOrder.desc
8
+ orderKey = order.slice(1)
9
+ }
10
+
11
+ return { [orderKey]: orderValue }
12
+ }
13
+
14
+ export function getOrderBys<T>(orders: string[]): T[] {
15
+ if (!orders) {
16
+ return undefined
17
+ }
18
+ return orders.map((order) => getOrderBy(order)) as T[]
19
+ }
@@ -0,0 +1 @@
1
+ export * from './get-order'
@@ -0,0 +1,26 @@
1
+ import { Module } from '@nestjs/common'
2
+
3
+ import { CustomEventFactory } from './event-factory'
4
+ import { MasterModule } from './master/master.module'
5
+ import { prismaLoggingMiddleware, PrismaModule } from './prisma'
6
+
7
+ @Module({
8
+ imports: [
9
+ PrismaModule.forRoot({
10
+ isGlobal: true,
11
+ prismaServiceOptions: {
12
+ middlewares: [prismaLoggingMiddleware()],
13
+ prismaOptions: {
14
+ log:
15
+ process.env.NODE_ENV !== 'local'
16
+ ? ['error']
17
+ : ['info', 'error', 'warn', 'query'],
18
+ },
19
+ explicitConnect: false,
20
+ },
21
+ }),
22
+ MasterModule,
23
+ ],
24
+ providers: [CustomEventFactory],
25
+ })
26
+ export class MainModule {}
@@ -0,0 +1,7 @@
1
+ import { createHandler } from '@mbc-cqrs-sererless/core'
2
+
3
+ import { MainModule } from './main.module'
4
+
5
+ export const handler = createHandler({
6
+ rootModule: MainModule,
7
+ })
@@ -0,0 +1,6 @@
1
+ import { IsObject } from 'class-validator'
2
+
3
+ export class MasterAttributes {
4
+ @IsObject()
5
+ master: object
6
+ }
@@ -0,0 +1,12 @@
1
+ import { CommandDto } from '@mbc-cqrs-sererless/core'
2
+ import { Type } from 'class-transformer'
3
+ import { IsOptional, ValidateNested } from 'class-validator'
4
+
5
+ import { MasterAttributes } from './master-attributes.dto'
6
+
7
+ export class MasterCommandDto extends CommandDto {
8
+ @Type(() => MasterAttributes)
9
+ @ValidateNested()
10
+ @IsOptional()
11
+ attributes: MasterAttributes
12
+ }
@@ -0,0 +1,13 @@
1
+ import { CommandEntity } from '@mbc-cqrs-sererless/core'
2
+
3
+ import { MasterAttributes } from '../dto/master-attributes.dto'
4
+
5
+ export class MasterCommandEntity extends CommandEntity {
6
+ attributes: MasterAttributes
7
+
8
+ constructor(partial: Partial<MasterCommandEntity>) {
9
+ super()
10
+
11
+ Object.assign(this, partial)
12
+ }
13
+ }
@@ -0,0 +1,13 @@
1
+ import { DataListEntity } from '@mbc-cqrs-sererless/core'
2
+
3
+ import { MasterDataEntity } from './master-data.entity'
4
+
5
+ export class MasterDataListEntity extends DataListEntity {
6
+ items: MasterDataEntity[]
7
+
8
+ constructor(partial: Partial<MasterDataListEntity>) {
9
+ super(partial)
10
+
11
+ Object.assign(this, partial)
12
+ }
13
+ }
@@ -0,0 +1,13 @@
1
+ import { DataEntity } from '@mbc-cqrs-sererless/core'
2
+
3
+ import { MasterAttributes } from '../dto/master-attributes.dto'
4
+
5
+ export class MasterDataEntity extends DataEntity {
6
+ attributes: MasterAttributes
7
+
8
+ constructor(partial: Partial<MasterDataEntity>) {
9
+ super(partial)
10
+
11
+ Object.assign(this, partial)
12
+ }
13
+ }
@@ -0,0 +1,59 @@
1
+ import {
2
+ CommandModel,
3
+ IDataSyncHandler,
4
+ removeSortKeyVersion,
5
+ } from '@mbc-cqrs-sererless/core'
6
+ import { Injectable, Logger } from '@nestjs/common'
7
+ import { PrismaService } from 'src/prisma'
8
+
9
+ @Injectable()
10
+ export class MasterDataSyncRdsHandler implements IDataSyncHandler {
11
+ private readonly logger = new Logger(MasterDataSyncRdsHandler.name)
12
+
13
+ constructor(private readonly prismaService: PrismaService) {}
14
+
15
+ async up(cmd: CommandModel): Promise<any> {
16
+ this.logger.debug(cmd)
17
+ const sk = removeSortKeyVersion(cmd.sk)
18
+ await this.prismaService.master.upsert({
19
+ where: {
20
+ id: cmd.id,
21
+ },
22
+ update: {
23
+ csk: cmd.sk,
24
+ name: cmd.name,
25
+ version: cmd.version,
26
+ seq: cmd.seq,
27
+ atttributesMaster: cmd.attributes?.master,
28
+ isDeleted: cmd.isDeleted || false,
29
+ updatedAt: cmd.updatedAt,
30
+ updatedBy: cmd.updatedBy,
31
+ updatedIp: cmd.updatedIp,
32
+ },
33
+ create: {
34
+ id: cmd.id,
35
+ cpk: cmd.pk,
36
+ csk: cmd.sk,
37
+ pk: cmd.pk,
38
+ sk,
39
+ masterTypeCode: sk.substring(0, sk.indexOf('#')),
40
+ masterCode: sk.substring(sk.indexOf('#') + 1),
41
+ code: sk,
42
+ name: cmd.name,
43
+ version: cmd.version,
44
+ tenantCode: cmd.tenantCode,
45
+ seq: cmd.seq,
46
+ atttributesMaster: cmd.attributes?.master,
47
+ createdAt: cmd.createdAt,
48
+ createdBy: cmd.createdBy,
49
+ createdIp: cmd.createdIp,
50
+ updatedAt: cmd.updatedAt,
51
+ updatedBy: cmd.updatedBy,
52
+ updatedIp: cmd.updatedIp,
53
+ },
54
+ })
55
+ }
56
+ async down(cmd: CommandModel): Promise<any> {
57
+ this.logger.debug(cmd)
58
+ }
59
+ }