@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.
- package/package.json +39 -0
- package/templates/.env.local +54 -0
- package/templates/.envrc +3 -0
- package/templates/.eslintrc.js +50 -0
- package/templates/.prettierrc +8 -0
- package/templates/README.md +168 -0
- package/templates/gitignore +46 -0
- package/templates/infra-local/appsync-simulator/.dockerignore +1 -0
- package/templates/infra-local/appsync-simulator/Dockerfile +8 -0
- package/templates/infra-local/appsync-simulator/package-lock.json +7179 -0
- package/templates/infra-local/appsync-simulator/package.json +30 -0
- package/templates/infra-local/appsync-simulator/src/main.ts +61 -0
- package/templates/infra-local/appsync-simulator/src/resolversConfig.ts +19 -0
- package/templates/infra-local/appsync-simulator/src/schema.graphql +28 -0
- package/templates/infra-local/appsync-simulator/src/schema.ts +7 -0
- package/templates/infra-local/appsync-simulator/src/vtl/readVTL.ts +6 -0
- package/templates/infra-local/appsync-simulator/src/vtl/sendMessage.req.vtl +4 -0
- package/templates/infra-local/appsync-simulator/src/vtl/sendMessage.res.vtl +1 -0
- package/templates/infra-local/cognito-local/.dockerignore +1 -0
- package/templates/infra-local/cognito-local/Dockerfile +9 -0
- package/templates/infra-local/cognito-local/db/clients.json +17 -0
- package/templates/infra-local/cognito-local/db/local_2G7noHgW.json +282 -0
- package/templates/infra-local/cognito-local/package-lock.json +2321 -0
- package/templates/infra-local/cognito-local/package.json +17 -0
- package/templates/infra-local/cognito-local/patches/cognito-local+3.23.2.patch +57 -0
- package/templates/infra-local/docker-compose.yml +91 -0
- package/templates/infra-local/elasticmq.conf +23 -0
- package/templates/infra-local/resources.sh +11 -0
- package/templates/infra-local/scripts/trigger_ddb_stream.sh +69 -0
- package/templates/infra-local/serverless.yml +306 -0
- package/templates/jest.config.js +4 -0
- package/templates/nest-cli.json +16 -0
- package/templates/package.json +118 -0
- package/templates/prisma/ddb.ts +232 -0
- package/templates/prisma/dynamodbs/cqrs.json +1 -0
- package/templates/prisma/dynamodbs/cqrs_desc.json +18 -0
- package/templates/prisma/dynamodbs/sequences.json +14 -0
- package/templates/prisma/dynamodbs/tasks.json +18 -0
- package/templates/prisma/schema.prisma +45 -0
- package/templates/src/event-factory.ts +7 -0
- package/templates/src/helpers/get-order.ts +19 -0
- package/templates/src/helpers/index.ts +1 -0
- package/templates/src/main.module.ts +26 -0
- package/templates/src/main.ts +7 -0
- package/templates/src/master/dto/master-attributes.dto.ts +6 -0
- package/templates/src/master/dto/master-command.dto.ts +12 -0
- package/templates/src/master/entity/master-command.entity.ts +13 -0
- package/templates/src/master/entity/master-data-list.entity.ts +13 -0
- package/templates/src/master/entity/master-data.entity.ts +13 -0
- package/templates/src/master/handler/master-rds.handler.ts +59 -0
- package/templates/src/master/master.controller.ts +83 -0
- package/templates/src/master/master.module.ts +19 -0
- package/templates/src/master/master.service.ts +58 -0
- package/templates/src/prisma/index.ts +5 -0
- package/templates/src/prisma/interfaces/index.ts +1 -0
- package/templates/src/prisma/interfaces/prisma-module-options.interface.ts +50 -0
- package/templates/src/prisma/prisma.constants.ts +2 -0
- package/templates/src/prisma/prisma.logging.middleware.ts +20 -0
- package/templates/src/prisma/prisma.module.ts +75 -0
- package/templates/src/prisma/prisma.service.ts +45 -0
- package/templates/src/repl.ts +21 -0
- package/templates/test/api.http +42 -0
- package/templates/test/jest-e2e.json +9 -0
- package/templates/tsconfig.build.json +4 -0
- 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,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
|
+
}
|