cdk-rds-sql 6.1.0 → 6.1.2
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/.jsii +3 -3
- package/.pre-commit-config.yaml +1 -1
- package/CLAUDE.md +117 -0
- package/lambda/engine.abstract.ts +30 -12
- package/lambda/engine.factory.ts +1 -1
- package/lambda/engine.mysql.test.ts +35 -10
- package/lambda/engine.mysql.ts +39 -25
- package/lambda/engine.postgresql.test.ts +21 -9
- package/lambda/engine.postgresql.ts +43 -25
- package/lambda/handler.mysql.test.ts +22 -20
- package/lambda/handler.postgresql.test.ts +6 -6
- package/lambda/handler.test.ts +164 -0
- package/lambda/handler.ts +81 -14
- package/lambda/types.ts +29 -14
- package/lambda/util.ts +2 -2
- package/lib/database.js +1 -1
- package/lib/handler/handler.js +11209 -11157
- package/lib/provider.js +5 -4
- package/lib/role.custom-resource.js +2 -2
- package/lib/role.js +1 -1
- package/lib/schema.js +1 -1
- package/lib/sql.js +1 -1
- package/package.json +3 -3
package/.jsii
CHANGED
|
@@ -4172,7 +4172,7 @@
|
|
|
4172
4172
|
},
|
|
4173
4173
|
"locationInModule": {
|
|
4174
4174
|
"filename": "src/provider.ts",
|
|
4175
|
-
"line":
|
|
4175
|
+
"line": 133
|
|
4176
4176
|
},
|
|
4177
4177
|
"name": "newCustomResourceHandler",
|
|
4178
4178
|
"parameters": [
|
|
@@ -5013,6 +5013,6 @@
|
|
|
5013
5013
|
"symbolId": "src/sql:SqlProps"
|
|
5014
5014
|
}
|
|
5015
5015
|
},
|
|
5016
|
-
"version": "6.1.
|
|
5017
|
-
"fingerprint": "
|
|
5016
|
+
"version": "6.1.2",
|
|
5017
|
+
"fingerprint": "FQIXsw6jGjZF4hbnqoBdGnn4gH67Zc1OmM9Xs2QqDoQ="
|
|
5018
5018
|
}
|
package/.pre-commit-config.yaml
CHANGED
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
This is a CDK construct library for creating databases, schemas, and roles in Aurora Serverless v2, RDS Database Cluster, or Database Instance. It supports both PostgreSQL and MySQL databases and is designed for enterprise environments with isolated subnets.
|
|
8
|
+
|
|
9
|
+
## Key Architecture
|
|
10
|
+
|
|
11
|
+
### Core Components
|
|
12
|
+
|
|
13
|
+
- **Provider**: Main construct that creates a Lambda function handler to execute database operations
|
|
14
|
+
- **Role**: Creates database users/roles with optional IAM authentication
|
|
15
|
+
- **Database**: Creates databases with optional ownership assignment
|
|
16
|
+
- **Schema**: Creates database schemas with role permissions
|
|
17
|
+
- **Sql**: Executes arbitrary SQL statements
|
|
18
|
+
|
|
19
|
+
### Lambda Handler Architecture
|
|
20
|
+
|
|
21
|
+
- **Engine Factory Pattern**: `lambda/engine.factory.ts` creates database-specific engines
|
|
22
|
+
- **Abstract Engine**: `lambda/engine.abstract.ts` defines common interface
|
|
23
|
+
- **Concrete Engines**: `lambda/engine.postgresql.ts` and `lambda/engine.mysql.ts`
|
|
24
|
+
- **Main Handler**: `lambda/handler.ts` orchestrates CloudFormation custom resource operations
|
|
25
|
+
|
|
26
|
+
The Lambda handler supports both PostgreSQL and MySQL databases, auto-detecting the engine type from the cluster/instance configuration.
|
|
27
|
+
|
|
28
|
+
## Development Commands
|
|
29
|
+
|
|
30
|
+
### Build and Test
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# Build the project
|
|
34
|
+
npm run build
|
|
35
|
+
|
|
36
|
+
# Run all tests
|
|
37
|
+
npm run test
|
|
38
|
+
|
|
39
|
+
# Run tests in watch mode
|
|
40
|
+
npm run test:watch
|
|
41
|
+
|
|
42
|
+
# Run linting
|
|
43
|
+
npm run eslint
|
|
44
|
+
|
|
45
|
+
# Build only the Lambda handler
|
|
46
|
+
npm run build:handler
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Integration Testing
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# Deploy PostgreSQL serverless test stack
|
|
53
|
+
npm run integ:deploy:postgresql:serverless
|
|
54
|
+
|
|
55
|
+
# Deploy MySQL serverless test stack
|
|
56
|
+
npm run integ:deploy:mysql:serverless
|
|
57
|
+
|
|
58
|
+
# Destroy test stack
|
|
59
|
+
npm run integ:destroy:serverless
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Package Management
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# Package for distribution
|
|
66
|
+
npm run package
|
|
67
|
+
|
|
68
|
+
# Build all packages
|
|
69
|
+
npm run package-all
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Testing Setup
|
|
73
|
+
|
|
74
|
+
- **Framework**: Jest with TypeScript support
|
|
75
|
+
- **Test Files**: Located in `test/` and `lambda/` directories
|
|
76
|
+
- **Configuration**: Max 2 concurrent workers for database tests
|
|
77
|
+
- **Coverage**: Enabled with multiple reporters (json, lcov, clover, cobertura, text)
|
|
78
|
+
|
|
79
|
+
## Database Engine Support
|
|
80
|
+
|
|
81
|
+
### PostgreSQL
|
|
82
|
+
|
|
83
|
+
- Uses `pg` library for connections
|
|
84
|
+
- Supports schemas, roles, and databases
|
|
85
|
+
- IAM authentication supported
|
|
86
|
+
|
|
87
|
+
### MySQL
|
|
88
|
+
|
|
89
|
+
- Uses `mysql2` library for connections
|
|
90
|
+
- Creates users with '%' host for VPC compatibility
|
|
91
|
+
- IAM authentication supported
|
|
92
|
+
|
|
93
|
+
## Build Process
|
|
94
|
+
|
|
95
|
+
The project uses projen for build management. Do not change files managed by projen, but instead change `.projenrc.ts`
|
|
96
|
+
|
|
97
|
+
Projen tasks:
|
|
98
|
+
|
|
99
|
+
1. `pre-compile`: Transpiles Lambda handler using esbuild
|
|
100
|
+
2. `compile`: TypeScript compilation
|
|
101
|
+
3. `post-compile`: Copies handler to lib directory
|
|
102
|
+
4. `eslint`: Runs linter
|
|
103
|
+
5. `typecheck`: Runs typecheck
|
|
104
|
+
|
|
105
|
+
## SSL/TLS Configuration
|
|
106
|
+
|
|
107
|
+
- SSL is enabled by default
|
|
108
|
+
- Global RDS certificate bundle is automatically downloaded during build
|
|
109
|
+
- Can be disabled via `ssl: false` in Provider props
|
|
110
|
+
|
|
111
|
+
## Key Dependencies
|
|
112
|
+
|
|
113
|
+
- **AWS CDK**: v2.171.1
|
|
114
|
+
- **Node.js**: >= 22.14
|
|
115
|
+
- **TypeScript**: ~5.8
|
|
116
|
+
- **Database Drivers**: pg (PostgreSQL), mysql2 (MySQL)
|
|
117
|
+
- **AWS SDKs**: secrets-manager, ssm clients
|
|
@@ -3,6 +3,12 @@ import {
|
|
|
3
3
|
SecretsManagerClient,
|
|
4
4
|
GetSecretValueCommand,
|
|
5
5
|
} from "@aws-sdk/client-secrets-manager"
|
|
6
|
+
import {
|
|
7
|
+
EngineDatabaseProperties,
|
|
8
|
+
EngineRoleProperties,
|
|
9
|
+
EngineSchemaProperties,
|
|
10
|
+
EngineSqlProperties,
|
|
11
|
+
} from "./types"
|
|
6
12
|
|
|
7
13
|
export interface EngineConnectionConfig {
|
|
8
14
|
host: string
|
|
@@ -23,38 +29,50 @@ export abstract class AbstractEngine {
|
|
|
23
29
|
: (_message?: any, ..._optionalParams: any[]) => {}
|
|
24
30
|
}
|
|
25
31
|
|
|
26
|
-
abstract createDatabase(
|
|
32
|
+
abstract createDatabase(
|
|
33
|
+
resourceId: string,
|
|
34
|
+
props: EngineDatabaseProperties
|
|
35
|
+
): string | string[]
|
|
27
36
|
abstract updateDatabase(
|
|
28
37
|
resourceId: string,
|
|
29
38
|
oldResourceId: string,
|
|
30
|
-
props
|
|
39
|
+
props: EngineDatabaseProperties
|
|
31
40
|
): string | string[]
|
|
32
41
|
abstract deleteDatabase(resourceId: string, masterUser: string): string | string[]
|
|
33
42
|
|
|
34
|
-
abstract createRole(
|
|
43
|
+
abstract createRole(
|
|
44
|
+
resourceId: string,
|
|
45
|
+
props: EngineRoleProperties
|
|
46
|
+
): Promise<string | string[]>
|
|
35
47
|
abstract updateRole(
|
|
36
48
|
resourceId: string,
|
|
37
49
|
oldResourceId: string,
|
|
38
|
-
props
|
|
39
|
-
oldProps
|
|
50
|
+
props: EngineRoleProperties,
|
|
51
|
+
oldProps: EngineRoleProperties
|
|
40
52
|
): Promise<string | string[]>
|
|
41
|
-
abstract deleteRole(resourceId: string, props
|
|
53
|
+
abstract deleteRole(resourceId: string, props: EngineRoleProperties): string | string[]
|
|
42
54
|
|
|
43
|
-
abstract createSchema(
|
|
55
|
+
abstract createSchema(
|
|
56
|
+
resourceId: string,
|
|
57
|
+
props: EngineSchemaProperties
|
|
58
|
+
): string | string[]
|
|
44
59
|
abstract updateSchema(
|
|
45
60
|
resourceId: string,
|
|
46
61
|
oldResourceId: string,
|
|
47
|
-
props
|
|
62
|
+
props: EngineSchemaProperties
|
|
63
|
+
): string | string[]
|
|
64
|
+
abstract deleteSchema(
|
|
65
|
+
resourceId: string,
|
|
66
|
+
props: EngineSchemaProperties
|
|
48
67
|
): string | string[]
|
|
49
|
-
abstract deleteSchema(resourceId: string, props?: any): string | string[]
|
|
50
68
|
|
|
51
|
-
abstract createSql(resourceId: string, props
|
|
69
|
+
abstract createSql(resourceId: string, props: EngineSqlProperties): string | string[]
|
|
52
70
|
abstract updateSql(
|
|
53
71
|
resourceId: string,
|
|
54
72
|
oldResourceId: string,
|
|
55
|
-
props
|
|
73
|
+
props: EngineSqlProperties
|
|
56
74
|
): string | string[]
|
|
57
|
-
abstract deleteSql(resourceId: string, props
|
|
75
|
+
abstract deleteSql(resourceId: string, props: EngineSqlProperties): string | string[]
|
|
58
76
|
|
|
59
77
|
abstract executeSQL(
|
|
60
78
|
sql: string | string[],
|
package/lambda/engine.factory.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AbstractEngine } from "./engine.abstract"
|
|
2
|
-
import { PostgresqlEngine } from "./engine.postgresql"
|
|
3
2
|
import { MysqlEngine } from "./engine.mysql"
|
|
3
|
+
import { PostgresqlEngine } from "./engine.postgresql"
|
|
4
4
|
|
|
5
5
|
export class EngineFactory {
|
|
6
6
|
static createEngine(engine: string): AbstractEngine {
|
|
@@ -39,9 +39,14 @@ describe("MySQL Engine", () => {
|
|
|
39
39
|
// Mock getPassword implementation
|
|
40
40
|
jest.spyOn(engine as any, "getPassword").mockResolvedValue("test-password")
|
|
41
41
|
|
|
42
|
-
const sql = await engine.updateRole(
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
const sql = await engine.updateRole(
|
|
43
|
+
"newrole",
|
|
44
|
+
"oldrole",
|
|
45
|
+
{
|
|
46
|
+
PasswordArn: "arn:aws:secretsmanager:region:account:secret:name",
|
|
47
|
+
},
|
|
48
|
+
{}
|
|
49
|
+
)
|
|
45
50
|
|
|
46
51
|
expect(Array.isArray(sql)).toBe(true)
|
|
47
52
|
expect(sql[0]).toContain("CREATE USER IF NOT EXISTS")
|
|
@@ -99,7 +104,9 @@ describe("MySQL Engine", () => {
|
|
|
99
104
|
const sql = await engine.createRole("iamuser", props)
|
|
100
105
|
|
|
101
106
|
expect(Array.isArray(sql)).toBe(true)
|
|
102
|
-
expect(sql[0]).toContain(
|
|
107
|
+
expect(sql[0]).toContain(
|
|
108
|
+
"CREATE USER IF NOT EXISTS 'iamuser'@'%' IDENTIFIED WITH AWSAuthenticationPlugin as 'RDS'"
|
|
109
|
+
)
|
|
103
110
|
expect(sql[1]).toContain("GRANT ALL PRIVILEGES ON `testdb`.* TO 'iamuser'@'%'")
|
|
104
111
|
expect(sql[2]).toBe("FLUSH PRIVILEGES")
|
|
105
112
|
})
|
|
@@ -116,8 +123,12 @@ describe("MySQL Engine", () => {
|
|
|
116
123
|
const sql = await engine.createRole("passworduser", props)
|
|
117
124
|
|
|
118
125
|
expect(Array.isArray(sql)).toBe(true)
|
|
119
|
-
expect(sql[0]).toContain(
|
|
120
|
-
|
|
126
|
+
expect(sql[0]).toContain(
|
|
127
|
+
"CREATE USER IF NOT EXISTS 'passworduser'@'%' IDENTIFIED BY 'test-password'"
|
|
128
|
+
)
|
|
129
|
+
expect(sql[1]).toContain(
|
|
130
|
+
"GRANT ALL PRIVILEGES ON `testdb`.* TO 'passworduser'@'%'"
|
|
131
|
+
)
|
|
121
132
|
expect(sql[2]).toBe("FLUSH PRIVILEGES")
|
|
122
133
|
})
|
|
123
134
|
|
|
@@ -132,11 +143,18 @@ describe("MySQL Engine", () => {
|
|
|
132
143
|
DatabaseName: "testdb",
|
|
133
144
|
}
|
|
134
145
|
|
|
135
|
-
const sql = await engine.updateRole(
|
|
146
|
+
const sql = await engine.updateRole(
|
|
147
|
+
"switchuser",
|
|
148
|
+
"switchuser",
|
|
149
|
+
newProps,
|
|
150
|
+
oldProps
|
|
151
|
+
)
|
|
136
152
|
|
|
137
153
|
expect(Array.isArray(sql)).toBe(true)
|
|
138
154
|
expect(sql[0]).toContain("DROP USER IF EXISTS 'switchuser'@'%'")
|
|
139
|
-
expect(sql[1]).toContain(
|
|
155
|
+
expect(sql[1]).toContain(
|
|
156
|
+
"CREATE USER 'switchuser'@'%' IDENTIFIED WITH AWSAuthenticationPlugin as 'RDS'"
|
|
157
|
+
)
|
|
140
158
|
expect(sql[2]).toContain("GRANT ALL PRIVILEGES ON `testdb`.* TO 'switchuser'@'%'")
|
|
141
159
|
expect(sql[3]).toBe("FLUSH PRIVILEGES")
|
|
142
160
|
})
|
|
@@ -154,11 +172,18 @@ describe("MySQL Engine", () => {
|
|
|
154
172
|
DatabaseName: "testdb",
|
|
155
173
|
}
|
|
156
174
|
|
|
157
|
-
const sql = await engine.updateRole(
|
|
175
|
+
const sql = await engine.updateRole(
|
|
176
|
+
"switchuser",
|
|
177
|
+
"switchuser",
|
|
178
|
+
newProps,
|
|
179
|
+
oldProps
|
|
180
|
+
)
|
|
158
181
|
|
|
159
182
|
expect(Array.isArray(sql)).toBe(true)
|
|
160
183
|
expect(sql[0]).toContain("DROP USER IF EXISTS 'switchuser'@'%'")
|
|
161
|
-
expect(sql[1]).toContain(
|
|
184
|
+
expect(sql[1]).toContain(
|
|
185
|
+
"CREATE USER 'switchuser'@'%' IDENTIFIED BY 'new-password'"
|
|
186
|
+
)
|
|
162
187
|
expect(sql[2]).toContain("GRANT ALL PRIVILEGES ON `testdb`.* TO 'switchuser'@'%'")
|
|
163
188
|
expect(sql[3]).toBe("FLUSH PRIVILEGES")
|
|
164
189
|
})
|
package/lambda/engine.mysql.ts
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import * as fs from "fs"
|
|
2
2
|
import { AbstractEngine, EngineConnectionConfig } from "./engine.abstract"
|
|
3
|
+
import {
|
|
4
|
+
EngineDatabaseProperties,
|
|
5
|
+
EngineRoleProperties,
|
|
6
|
+
EngineSchemaProperties,
|
|
7
|
+
EngineSqlProperties,
|
|
8
|
+
} from "./types"
|
|
3
9
|
|
|
4
10
|
export class MysqlEngine extends AbstractEngine {
|
|
5
|
-
createDatabase(resourceId: string, props
|
|
11
|
+
createDatabase(resourceId: string, props: EngineDatabaseProperties): string[] {
|
|
6
12
|
const sql = [`CREATE DATABASE IF NOT EXISTS \`${resourceId}\``]
|
|
7
13
|
|
|
8
|
-
if (props
|
|
14
|
+
if (props.Owner) {
|
|
9
15
|
sql.push(`GRANT ALL PRIVILEGES ON \`${resourceId}\`.* TO '${props.Owner}'@'%'`)
|
|
10
|
-
sql.push(
|
|
16
|
+
sql.push("FLUSH PRIVILEGES")
|
|
11
17
|
}
|
|
12
18
|
|
|
13
19
|
return sql
|
|
@@ -21,9 +27,9 @@ export class MysqlEngine extends AbstractEngine {
|
|
|
21
27
|
return [`DROP DATABASE IF EXISTS \`${resourceId}\``]
|
|
22
28
|
}
|
|
23
29
|
|
|
24
|
-
async createRole(resourceId: string, props
|
|
30
|
+
async createRole(resourceId: string, props: EngineRoleProperties): Promise<string[]> {
|
|
25
31
|
const sql: string[] = []
|
|
26
|
-
|
|
32
|
+
|
|
27
33
|
if (props.EnableIamAuth) {
|
|
28
34
|
// Create user for IAM authentication
|
|
29
35
|
sql.push(
|
|
@@ -34,7 +40,7 @@ export class MysqlEngine extends AbstractEngine {
|
|
|
34
40
|
if (!props.PasswordArn) throw new Error("No PasswordArn provided")
|
|
35
41
|
const password = await this.getPassword(props.PasswordArn)
|
|
36
42
|
if (!password) throw `Cannot parse password from ${props.PasswordArn}`
|
|
37
|
-
|
|
43
|
+
|
|
38
44
|
sql.push(
|
|
39
45
|
`CREATE USER IF NOT EXISTS '${resourceId}'@'%' IDENTIFIED BY '${password}'`
|
|
40
46
|
)
|
|
@@ -45,22 +51,22 @@ export class MysqlEngine extends AbstractEngine {
|
|
|
45
51
|
`GRANT ALL PRIVILEGES ON \`${props.DatabaseName}\`.* TO '${resourceId}'@'%'`
|
|
46
52
|
)
|
|
47
53
|
}
|
|
48
|
-
|
|
49
|
-
sql.push(
|
|
54
|
+
|
|
55
|
+
sql.push("FLUSH PRIVILEGES")
|
|
50
56
|
return sql
|
|
51
57
|
}
|
|
52
58
|
|
|
53
59
|
async updateRole(
|
|
54
60
|
resourceId: string,
|
|
55
61
|
oldResourceId: string,
|
|
56
|
-
props
|
|
57
|
-
oldProps
|
|
62
|
+
props: EngineRoleProperties,
|
|
63
|
+
oldProps: EngineRoleProperties
|
|
58
64
|
): Promise<string[]> {
|
|
59
65
|
const sql: string[] = []
|
|
60
66
|
|
|
61
67
|
if (oldResourceId !== resourceId) {
|
|
62
68
|
// MySQL doesn't allow renaming users directly, we need to create a new one and drop the old one
|
|
63
|
-
if (props
|
|
69
|
+
if (props.EnableIamAuth) {
|
|
64
70
|
// Create new user with IAM auth
|
|
65
71
|
sql.push(
|
|
66
72
|
`CREATE USER IF NOT EXISTS '${resourceId}'@'%' IDENTIFIED WITH AWSAuthenticationPlugin as 'RDS'`
|
|
@@ -124,13 +130,13 @@ export class MysqlEngine extends AbstractEngine {
|
|
|
124
130
|
}
|
|
125
131
|
|
|
126
132
|
if (sql.length > 0) {
|
|
127
|
-
sql.push(
|
|
133
|
+
sql.push("FLUSH PRIVILEGES")
|
|
128
134
|
}
|
|
129
135
|
|
|
130
136
|
return sql
|
|
131
137
|
}
|
|
132
138
|
|
|
133
|
-
deleteRole(resourceId: string, props
|
|
139
|
+
deleteRole(resourceId: string, props: EngineRoleProperties): string[] {
|
|
134
140
|
const sql: string[] = []
|
|
135
141
|
|
|
136
142
|
if (props?.DatabaseName) {
|
|
@@ -140,33 +146,41 @@ export class MysqlEngine extends AbstractEngine {
|
|
|
140
146
|
}
|
|
141
147
|
|
|
142
148
|
sql.push(`DROP USER IF EXISTS '${resourceId}'@'%'`)
|
|
143
|
-
sql.push(
|
|
149
|
+
sql.push("FLUSH PRIVILEGES")
|
|
144
150
|
|
|
145
151
|
return sql
|
|
146
152
|
}
|
|
147
153
|
|
|
148
|
-
createSchema(_resourceId: string, _props
|
|
154
|
+
createSchema(_resourceId: string, _props: EngineSchemaProperties): string[] {
|
|
149
155
|
throw new Error("Schemas are not supported in MySQL/MariaDB")
|
|
150
156
|
}
|
|
151
157
|
|
|
152
|
-
updateSchema(
|
|
158
|
+
updateSchema(
|
|
159
|
+
_resourceId: string,
|
|
160
|
+
_oldResourceId: string,
|
|
161
|
+
_props: EngineSchemaProperties
|
|
162
|
+
): string[] {
|
|
153
163
|
throw new Error("Schemas are not supported in MySQL/MariaDB")
|
|
154
164
|
}
|
|
155
165
|
|
|
156
|
-
deleteSchema(_resourceId: string, _props
|
|
166
|
+
deleteSchema(_resourceId: string, _props: EngineSchemaProperties): string[] {
|
|
157
167
|
throw new Error("Schemas are not supported in MySQL/MariaDB")
|
|
158
168
|
}
|
|
159
169
|
|
|
160
|
-
createSql(_resourceId: string, props
|
|
161
|
-
return props
|
|
170
|
+
createSql(_resourceId: string, props: EngineSqlProperties): string {
|
|
171
|
+
return props?.Statement || ""
|
|
162
172
|
}
|
|
163
173
|
|
|
164
|
-
updateSql(
|
|
165
|
-
|
|
174
|
+
updateSql(
|
|
175
|
+
_resourceId: string,
|
|
176
|
+
_oldResourceId: string,
|
|
177
|
+
props: EngineSqlProperties
|
|
178
|
+
): string {
|
|
179
|
+
return props?.Statement || ""
|
|
166
180
|
}
|
|
167
181
|
|
|
168
|
-
deleteSql(_resourceId: string, props
|
|
169
|
-
return props
|
|
182
|
+
deleteSql(_resourceId: string, props: EngineSqlProperties): string {
|
|
183
|
+
return props?.Rollback || ""
|
|
170
184
|
}
|
|
171
185
|
|
|
172
186
|
async executeSQL(sql: string | string[], config: EngineConnectionConfig): Promise<any> {
|
|
@@ -207,9 +221,9 @@ export class MysqlEngine extends AbstractEngine {
|
|
|
207
221
|
const connection = await createConnection(connectionConfig)
|
|
208
222
|
try {
|
|
209
223
|
if (typeof sql === "string") {
|
|
210
|
-
return connection.query(sql)
|
|
224
|
+
return await connection.query(sql)
|
|
211
225
|
} else if (sql) {
|
|
212
|
-
return Promise.all(sql.map((statement) => connection.query(statement)))
|
|
226
|
+
return await Promise.all(sql.map((statement) => connection.query(statement)))
|
|
213
227
|
}
|
|
214
228
|
} finally {
|
|
215
229
|
await connection.end()
|
|
@@ -58,8 +58,8 @@ describe("PostgreSQL Engine", () => {
|
|
|
58
58
|
|
|
59
59
|
expect(Array.isArray(sql)).toBe(true)
|
|
60
60
|
expect(sql[0]).toBe("start transaction")
|
|
61
|
-
expect(sql).toContain(
|
|
62
|
-
expect(sql).toContain(
|
|
61
|
+
expect(sql).toContain("create role iamrole with login")
|
|
62
|
+
expect(sql).toContain("grant rds_iam to iamrole")
|
|
63
63
|
expect(sql[sql.length - 1]).toBe("commit")
|
|
64
64
|
})
|
|
65
65
|
|
|
@@ -76,7 +76,9 @@ describe("PostgreSQL Engine", () => {
|
|
|
76
76
|
|
|
77
77
|
expect(Array.isArray(sql)).toBe(true)
|
|
78
78
|
expect(sql[0]).toBe("start transaction")
|
|
79
|
-
expect(sql).toContain(
|
|
79
|
+
expect(sql).toContain(
|
|
80
|
+
"create role passwordrole with login password 'test-password'"
|
|
81
|
+
)
|
|
80
82
|
expect(sql[sql.length - 1]).toBe("commit")
|
|
81
83
|
})
|
|
82
84
|
|
|
@@ -90,11 +92,16 @@ describe("PostgreSQL Engine", () => {
|
|
|
90
92
|
EnableIamAuth: true,
|
|
91
93
|
}
|
|
92
94
|
|
|
93
|
-
const sql = await engine.updateRole(
|
|
95
|
+
const sql = await engine.updateRole(
|
|
96
|
+
"switchrole",
|
|
97
|
+
"switchrole",
|
|
98
|
+
newProps,
|
|
99
|
+
oldProps
|
|
100
|
+
)
|
|
94
101
|
|
|
95
102
|
expect(Array.isArray(sql)).toBe(true)
|
|
96
103
|
expect(sql[0]).toBe("start transaction")
|
|
97
|
-
expect(sql).toContain(
|
|
104
|
+
expect(sql).toContain("grant rds_iam to switchrole")
|
|
98
105
|
expect(sql[sql.length - 1]).toBe("commit")
|
|
99
106
|
})
|
|
100
107
|
|
|
@@ -110,12 +117,17 @@ describe("PostgreSQL Engine", () => {
|
|
|
110
117
|
PasswordArn: "arn:aws:secretsmanager:region:account:secret:name",
|
|
111
118
|
}
|
|
112
119
|
|
|
113
|
-
const sql = await engine.updateRole(
|
|
120
|
+
const sql = await engine.updateRole(
|
|
121
|
+
"switchrole",
|
|
122
|
+
"switchrole",
|
|
123
|
+
newProps,
|
|
124
|
+
oldProps
|
|
125
|
+
)
|
|
114
126
|
|
|
115
127
|
expect(Array.isArray(sql)).toBe(true)
|
|
116
128
|
expect(sql[0]).toBe("start transaction")
|
|
117
|
-
expect(sql).toContain(
|
|
118
|
-
expect(sql).toContain(
|
|
129
|
+
expect(sql).toContain("revoke rds_iam from switchrole")
|
|
130
|
+
expect(sql).toContain("alter role switchrole with password 'new-password'")
|
|
119
131
|
expect(sql[sql.length - 1]).toBe("commit")
|
|
120
132
|
})
|
|
121
133
|
})
|
|
@@ -125,7 +137,7 @@ describe("PostgreSQL Engine", () => {
|
|
|
125
137
|
describe("Database", () => {
|
|
126
138
|
it("should generate correct SQL for creating a database", () => {
|
|
127
139
|
const sql = engine.createDatabase("testdb", {})
|
|
128
|
-
expect(sql).toContain(
|
|
140
|
+
expect(sql).toContain("create database testdb")
|
|
129
141
|
})
|
|
130
142
|
})
|
|
131
143
|
|