
Code Generation: Exploring Generative AI for Database Workloads
My code generation experience using a "Productive AI" tool built on Amazon Bedrock leveraging its foundation models.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
-- Create schemas
CREATE SCHEMA inventory;
CREATE SCHEMA sales;
CREATE SCHEMA users;
-- Inventory Schema
CREATE TABLE inventory.products (
product_id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
description TEXT,
price DECIMAL(10, 2) NOT NULL,
stock_quantity INTEGER NOT NULL
);
CREATE TABLE inventory.categories (
category_id SERIAL PRIMARY KEY,
name VARCHAR(50) NOT NULL
);
CREATE TABLE inventory.product_categories (
product_id INTEGER REFERENCES inventory.products(product_id),
category_id INTEGER REFERENCES inventory.categories(category_id),
PRIMARY KEY (product_id, category_id)
);
-- Sales Schema
CREATE TABLE sales.orders (
order_id SERIAL PRIMARY KEY,
user_id INTEGER,
order_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
total_amount DECIMAL(10, 2) NOT NULL
);
CREATE TABLE sales.order_items (
order_item_id SERIAL PRIMARY KEY,
order_id INTEGER REFERENCES sales.orders(order_id),
product_id INTEGER REFERENCES inventory.products(product_id),
quantity INTEGER NOT NULL,
price DECIMAL(10, 2) NOT NULL
);
CREATE TABLE sales.payments (
payment_id SERIAL PRIMARY KEY,
order_id INTEGER REFERENCES sales.orders(order_id),
payment_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
amount DECIMAL(10, 2) NOT NULL,
payment_method VARCHAR(50)
);
-- Users Schema
CREATE TABLE users.customers (
user_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE users.addresses (
address_id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users.customers(user_id),
address_line1 VARCHAR(100) NOT NULL,
address_line2 VARCHAR(100),
city VARCHAR(50) NOT NULL,
state VARCHAR(50),
country VARCHAR(50) NOT NULL,
postal_code VARCHAR(20)
);
-- Create indexes for performance
CREATE INDEX idx_products_name ON inventory.products(name);
CREATE INDEX idx_orders_user_id ON sales.orders(user_id);
CREATE INDEX idx_order_items_order_id ON sales.order_items(order_id);
CREATE INDEX idx_customers_email ON users.customers(email);
-- Add some sample data
INSERT INTO inventory.categories (name) VALUES ('Electronics'), ('Books'), ('Clothing');
INSERT INTO inventory.products (name, description, price, stock_quantity) VALUES
('Smartphone', 'Latest model smartphone', 699.99, 100),
('Laptop', 'High-performance laptop', 1299.99, 50),
('T-shirt', 'Cotton T-shirt', 19.99, 200);
INSERT INTO inventory.product_categories (product_id, category_id) VALUES
(1, 1), (2, 1), (3, 3);
INSERT INTO users.customers (first_name, last_name, email, password_hash) VALUES
('John', 'Doe', 'john@example.com', 'hashed_password_here'),
('Jane', 'Smith', 'jane@example.com', 'hashed_password_here');
INSERT INTO sales.orders (user_id, total_amount) VALUES
(1, 719.98),
(2, 1299.99);
INSERT INTO sales.order_items (order_id, product_id, quantity, price) VALUES
(1, 1, 1, 699.99),
(1, 3, 1, 19.99),
(2, 2, 1, 1299.99);
INSERT INTO sales.payments (order_id, amount, payment_method) VALUES
(1, 719.98, 'Credit Card'),
(2, 1299.99, 'PayPal');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
-- Create schemas
CREATE SCHEMA academics;
CREATE SCHEMA staff;
CREATE SCHEMA facilities;
CREATE SCHEMA research;
-- Academics Schema
CREATE TABLE academics.departments (
department_id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
code VARCHAR(10) UNIQUE NOT NULL
);
CREATE TABLE academics.courses (
course_id SERIAL PRIMARY KEY,
department_id INTEGER REFERENCES academics.departments(department_id),
code VARCHAR(20) UNIQUE NOT NULL,
title VARCHAR(200) NOT NULL,
credits INTEGER NOT NULL
);
CREATE TABLE academics.students (
student_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
date_of_birth DATE NOT NULL,
enrollment_date DATE NOT NULL,
major_department_id INTEGER REFERENCES academics.departments(department_id)
);
CREATE TABLE academics.enrollments (
enrollment_id SERIAL PRIMARY KEY,
student_id INTEGER REFERENCES academics.students(student_id),
course_id INTEGER REFERENCES academics.courses(course_id),
semester VARCHAR(20) NOT NULL,
year INTEGER NOT NULL,
grade CHAR(2)
);
-- Staff Schema
CREATE TABLE staff.employees (
employee_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
hire_date DATE NOT NULL,
position VARCHAR(100) NOT NULL
);
CREATE TABLE staff.salaries (
salary_id SERIAL PRIMARY KEY,
employee_id INTEGER REFERENCES staff.employees(employee_id),
amount DECIMAL(10, 2) NOT NULL,
effective_date DATE NOT NULL
);
-- Facilities Schema
CREATE TABLE facilities.buildings (
building_id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
address VARCHAR(200) NOT NULL,
construction_year INTEGER
);
CREATE TABLE facilities.rooms (
room_id SERIAL PRIMARY KEY,
building_id INTEGER REFERENCES facilities.buildings(building_id),
room_number VARCHAR(20) NOT NULL,
capacity INTEGER,
room_type VARCHAR(50) NOT NULL
);
CREATE TABLE facilities.equipment (
equipment_id SERIAL PRIMARY KEY,
room_id INTEGER REFERENCES facilities.rooms(room_id),
name VARCHAR(100) NOT NULL,
purchase_date DATE,
last_maintenance_date DATE
);
-- Research Schema
CREATE TABLE research.projects (
project_id SERIAL PRIMARY KEY,
title VARCHAR(200) NOT NULL,
description TEXT,
start_date DATE,
end_date DATE,
funding_amount DECIMAL(12, 2)
);
CREATE TABLE research.publications (
publication_id SERIAL PRIMARY KEY,
title VARCHAR(200) NOT NULL,
authors TEXT NOT NULL,
publication_date DATE,
journal VARCHAR(200),
doi VARCHAR(100)
);
CREATE TABLE research.project_members (
project_id INTEGER REFERENCES research.projects(project_id),
employee_id INTEGER REFERENCES staff.employees(employee_id),
role VARCHAR(50) NOT NULL,
PRIMARY KEY (project_id, employee_id)
);
-- Create indexes for performance
CREATE INDEX idx_courses_department ON academics.courses(department_id);
CREATE INDEX idx_enrollments_student ON academics.enrollments(student_id);
CREATE INDEX idx_enrollments_course ON academics.enrollments(course_id);
CREATE INDEX idx_salaries_employee ON staff.salaries(employee_id);
CREATE INDEX idx_rooms_building ON facilities.rooms(building_id);
CREATE INDEX idx_equipment_room ON facilities.equipment(room_id);
CREATE INDEX idx_project_members_project ON research.project_members(project_id);
CREATE INDEX idx_project_members_employee ON research.project_members(employee_id);
-- Add some sample data
INSERT INTO academics.departments (name, code) VALUES
('Computer Science', 'CS'),
('Physics', 'PHY'),
('Biology', 'BIO');
INSERT INTO academics.courses (department_id, code, title, credits) VALUES
(1, 'CS101', 'Introduction to Programming', 3),
(2, 'PHY201', 'Classical Mechanics', 4),
(3, 'BIO301', 'Genetics', 4);
INSERT INTO academics.students (first_name, last_name, date_of_birth, enrollment_date, major_department_id) VALUES
('Alice', 'Johnson', '2000-05-15', '2022-09-01', 1),
('Bob', 'Smith', '2001-03-22', '2022-09-01', 2);
INSERT INTO staff.employees (first_name, last_name, email, hire_date, position) VALUES
('John', 'Doe', 'john.doe@university.edu', '2015-08-01', 'Professor'),
('Jane', 'Doe', 'jane.doe@university.edu', '2018-01-15', 'Associate Professor');
INSERT INTO facilities.buildings (name, address, construction_year) VALUES
('Science Building', '123 University Ave', 1985),
('Library', '456 Campus Road', 1990);
INSERT INTO research.projects (title, description, start_date, end_date, funding_amount) VALUES
('AI in Education', 'Exploring AI applications in higher education', '2023-01-01', '2025-12-31', 500000.00),
('Quantum Computing Advances', 'Research on quantum algorithms', '2022-07-01', '2024-06-30', 750000.00);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
Academics API
Departments:
GET /api/academics/departments - List all departments
GET /api/academics/departments/{id} - Get department details
POST /api/academics/departments - Create a new department
PUT /api/academics/departments/{id} - Update department information
DELETE /api/academics/departments/{id} - Delete a department
Courses:
GET /api/academics/courses - List all courses
GET /api/academics/courses/{id} - Get course details
POST /api/academics/courses - Create a new course
PUT /api/academics/courses/{id} - Update course information
DELETE /api/academics/courses/{id} - Delete a course
GET /api/academics/departments/{id}/courses - List courses in a department
Students:
GET /api/academics/students - List all students
GET /api/academics/students/{id} - Get student details
POST /api/academics/students - Register a new student
PUT /api/academics/students/{id} - Update student information
DELETE /api/academics/students/{id} - Remove a student
GET /api/academics/departments/{id}/students - List students in a department
Enrollments:
GET /api/academics/enrollments - List all enrollments
GET /api/academics/enrollments/{id} - Get enrollment details
POST /api/academics/enrollments - Create a new enrollment
PUT /api/academics/enrollments/{id} - Update enrollment (e.g., grade)
DELETE /api/academics/enrollments/{id} - Delete an enrollment
GET /api/academics/students/{id}/enrollments - Get a student's enrollments
GET /api/academics/courses/{id}/enrollments - Get enrollments for a course
Staff API
Employees:
GET /api/staff/employees - List all employees
GET /api/staff/employees/{id} - Get employee details
POST /api/staff/employees - Add a new employee
PUT /api/staff/employees/{id} - Update employee information
DELETE /api/staff/employees/{id} - Remove an employee
Salaries:
GET /api/staff/salaries - List all salaries
GET /api/staff/salaries/{id} - Get salary details
POST /api/staff/salaries - Add a new salary record
PUT /api/staff/salaries/{id} - Update salary information
DELETE /api/staff/salaries/{id} - Delete a salary record
GET /api/staff/employees/{id}/salaries - Get salary history for an employee
Facilities API
Buildings:
GET /api/facilities/buildings - List all buildings
GET /api/facilities/buildings/{id} - Get building details
POST /api/facilities/buildings - Add a new building
PUT /api/facilities/buildings/{id} - Update building information
DELETE /api/facilities/buildings/{id} - Remove a building
Rooms:
GET /api/facilities/rooms - List all rooms
GET /api/facilities/rooms/{id} - Get room details
POST /api/facilities/rooms - Add a new room
PUT /api/facilities/rooms/{id} - Update room information
DELETE /api/facilities/rooms/{id} - Remove a room
GET /api/facilities/buildings/{id}/rooms - List rooms in a building
Equipment:
GET /api/facilities/equipment - List all equipment
GET /api/facilities/equipment/{id} - Get equipment details
POST /api/facilities/equipment - Add new equipment
PUT /api/facilities/equipment/{id} - Update equipment information
DELETE /api/facilities/equipment/{id} - Remove equipment
GET /api/facilities/rooms/{id}/equipment - List equipment in a room
Research API
Projects:
GET /api/research/projects - List all research projects
GET /api/research/projects/{id} - Get project details
POST /api/research/projects - Create a new project
PUT /api/research/projects/{id} - Update project information
DELETE /api/research/projects/{id} - Remove a project
Publications:
GET /api/research/publications - List all publications
GET /api/research/publications/{id} - Get publication details
POST /api/research/publications - Add a new publication
PUT /api/research/publications/{id} - Update publication information
DELETE /api/research/publications/{id} - Remove a publication
Project Members:
GET /api/research/project-members - List all project members
GET /api/research/project-members/{projectId}/{employeeId} - Get project member details
POST /api/research/project-members - Add a member to a project
PUT /api/research/project-members/{projectId}/{employeeId} - Update member role
DELETE /api/research/project-members/{projectId}/{employeeId} - Remove a member from a project
GET /api/research/projects/{id}/members - List members of a project
GET /api/staff/employees/{id}/projects - List projects for an employee
Additional Useful APIs:
GET /api/academics/students/{id}/transcript - Generate a student's transcript
GET /api/academics/departments/{id}/faculty - List faculty in a department
GET /api/facilities/rooms/available - List available rooms (for scheduling)
GET /api/research/projects/active - List active research projects
GET /api/staff/employees/by-position/{position} - List employees by position
These APIs cover the basic CRUD operations for each entity in the database, as well as some more specific operations that might be useful in a university management system. Depending on the specific needs of the application, you might want to add more specialized endpoints or combine some of these for efficiency.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
openapi: 3.0.0
info:
title: University Management System API
version: 1.0.0
description: API for managing university departments, courses, students, staff, facilities, and research projects.
servers:
- url: https://api.university.edu/v1
paths:
/academics/departments:
get:
summary: List all departments
responses:
'200':
description: Successful response
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Department'
post:
summary: Create a new department
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Department'
responses:
'201':
description: Created
/academics/departments/{id}:
get:
summary: Get department details
parameters:
- in: path
name: id
required: true
schema:
type: integer
responses:
'200':
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/Department'
/academics/courses:
get:
summary: List all courses
responses:
'200':
description: Successful response
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Course'
post:
summary: Create a new course
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Course'
responses:
'201':
description: Created
/academics/students:
get:
summary: List all students
responses:
'200':
description: Successful response
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Student'
post:
summary: Register a new student
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Student'
responses:
'201':
description: Created
/staff/employees:
get:
summary: List all employees
responses:
'200':
description: Successful response
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Employee'
post:
summary: Add a new employee
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Employee'
responses:
'201':
description: Created
/facilities/buildings:
get:
summary: List all buildings
responses:
'200':
description: Successful response
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Building'
post:
summary: Add a new building
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Building'
responses:
'201':
description: Created
/research/projects:
get:
summary: List all research projects
responses:
'200':
description: Successful response
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Project'
post:
summary: Create a new project
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Project'
responses:
'201':
description: Created
components:
schemas:
Department:
type: object
properties:
id:
type: integer
name:
type: string
code:
type: string
Course:
type: object
properties:
id:
type: integer
department_id:
type: integer
code:
type: string
title:
type: string
credits:
type: integer
Student:
type: object
properties:
id:
type: integer
first_name:
type: string
last_name:
type: string
date_of_birth:
type: string
format: date
enrollment_date:
type: string
format: date
major_department_id:
type: integer
Employee:
type: object
properties:
id:
type: integer
first_name:
type: string
last_name:
type: string
email:
type: string
hire_date:
type: string
format: date
position:
type: string
Building:
type: object
properties:
id:
type: integer
name:
type: string
address:
type: string
construction_year:
type: integer
Project:
type: object
properties:
id:
type: integer
title:
type: string
description:
type: string
start_date:
type: string
format: date
end_date:
type: string
format: date
funding_amount:
type: number
format: float
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
import json
import os
import boto3
from botocore.exceptions import ClientError
# Initialize clients
rds_data = boto3.client("rds-data")
# Environment variables
DB_CLUSTER_ARN = os.environ["DB_CLUSTER_ARN"]
DB_SECRET_ARN = os.environ["DB_SECRET_ARN"]
DATABASE_NAME = os.environ["DB_NAME"]
def execute_statement(sql, params=[]):
try:
response = rds_data.execute_statement(
resourceArn=DB_CLUSTER_ARN,
secretArn=DB_SECRET_ARN,
database=DATABASE_NAME,
sql=sql,
parameters=params,
)
# Check if the response has a "records" attribute
if "records" in response:
return response["records"]
# If "records" is not present, check for a "numberOfRecordsUpdated" attribute
elif "numberOfRecordsUpdated" in response:
return response["numberOfRecordsUpdated"]
# If neither "records" nor "numberOfRecordsUpdated" are present, return None
else:
return None
except ClientError as e:
print(f"An error occurred: {e}")
return None
def handle_academics_request(action, entity, data=None):
if entity == "departments":
if action == "GET":
records = execute_statement("SELECT * FROM academics.departments")
return [dict(zip(["id", "name", "code"], record)) for record in records]
elif action == "POST":
execute_statement(
"INSERT INTO academics.departments (name, code) VALUES (:name, :code)",
[
{"name": "name", "value": {"stringValue": data["name"]}},
{"name": "code", "value": {"stringValue": data["code"]}},
],
)
return {"message": "Department created successfully"}
elif entity == "courses":
if action == "GET":
records = execute_statement("SELECT * FROM academics.courses")
return [
dict(zip(["id", "department_id", "code", "title", "credits"], record))
for record in records
]
elif action == "POST":
execute_statement(
"INSERT INTO academics.courses (department_id, code, title, credits) VALUES (:dept_id, :code, :title, :credits)",
[
{"name": "dept_id", "value": {"longValue": data["department_id"]}},
{"name": "code", "value": {"stringValue": data["code"]}},
{"name": "title", "value": {"stringValue": data["title"]}},
{"name": "credits", "value": {"longValue": data["credits"]}},
],
)
return {"message": "Course created successfully"}
# Add more entities and actions as needed
def handle_staff_request(action, entity, data=None):
if entity == "employees":
if action == "GET":
records = execute_statement("SELECT * FROM staff.employees")
return [
dict(
zip(
[
"id",
"first_name",
"last_name",
"email",
"hire_date",
"position",
],
record,
)
)
for record in records
]
elif action == "POST":
execute_statement(
"INSERT INTO staff.employees (first_name, last_name, email, hire_date, position) VALUES (:fname, :lname, :email, CAST(:hire_date AS DATE), :position)",
[
{"name": "fname", "value": {"stringValue": data["first_name"]}},
{"name": "lname", "value": {"stringValue": data["last_name"]}},
{"name": "email", "value": {"stringValue": data["email"]}},
{"name": "hire_date", "value": {"stringValue": data["hire_date"]}},
{"name": "position", "value": {"stringValue": data["position"]}},
],
)
return {"message": "Employee added successfully"}
# Add more entities and actions as needed
def handle_facilities_request(action, entity, data=None):
if entity == "buildings":
if action == "GET":
records = execute_statement("SELECT * FROM facilities.buildings")
return [
dict(zip(["id", "name", "address", "construction_year"], record))
for record in records
]
elif action == "POST":
execute_statement(
"INSERT INTO facilities.buildings (name, address, construction_year) VALUES (:name, :address, :year)",
[
{"name": "name", "value": {"stringValue": data["name"]}},
{"name": "address", "value": {"stringValue": data["address"]}},
{"name": "year", "value": {"longValue": data["construction_year"]}},
],
)
return {"message": "Building added successfully"}
# Add more entities and actions as needed
def handle_research_request(action, entity, data=None):
if entity == "projects":
if action == "GET":
records = execute_statement("SELECT * FROM research.projects")
return [
dict(
zip(
[
"id",
"title",
"description",
"start_date",
"end_date",
"funding_amount",
],
record,
)
)
for record in records
]
elif action == "POST":
execute_statement(
"INSERT INTO research.projects (title, description, start_date, end_date, funding_amount) VALUES (:title, :desc, CAST(:start AS DATE), CAST(:end AS DATE), :funding)",
[
{"name": "title", "value": {"stringValue": data["title"]}},
{"name": "desc", "value": {"stringValue": data["description"]}},
{"name": "start", "value": {"stringValue": data["start_date"]}},
{"name": "end", "value": {"stringValue": data["end_date"]}},
{
"name": "funding",
"value": {"doubleValue": data["funding_amount"]},
},
],
)
return {"message": "Project created successfully"}
# Add more entities and actions as needed
def handler(event, context):
try:
# Parse the incoming request
body = None
if "body" in event and event["body"]:
body = json.loads(event["body"])
action = event["httpMethod"]
path = event["path"].split("/")
domain = path[1]
entity = path[2]
# Route the request to the appropriate handler
if domain == "academics":
result = handle_academics_request(
action, entity, body if action == "POST" else None
)
elif domain == "staff":
result = handle_staff_request(
action, entity, body if action == "POST" else None
)
elif domain == "facilities":
result = handle_facilities_request(
action, entity, body if action == "POST" else None
)
elif domain == "research":
result = handle_research_request(
action, entity, body if action == "POST" else None
)
else:
return {"statusCode": 400, "body": json.dumps({"error": "Invalid domain"})}
return {"statusCode": 200, "body": json.dumps(result)}
except Exception as e:
print(f"An error occurred: {e}")
return {
"statusCode": 500,
"body": json.dumps({"error": "Internal server error"}),
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import os
from aws_cdk import (
Stack,
aws_ec2 as ec2,
aws_rds as rds,
aws_lambda as _lambda,
aws_iam as iam,
aws_secretsmanager as secretsmanager,
aws_apigateway as apigateway,
CfnOutput,
Duration,
)
from constructs import Construct
class UniversityManagementStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
# Create VPC
vpc = ec2.Vpc(self, "UniversityVPC", max_azs=2)
# Create Aurora Serverless v2 PostgreSQL cluster
db_cluster = rds.DatabaseCluster(self, "UniversityDatabase",
engine=rds.DatabaseClusterEngine.aurora_postgres(version=rds.AuroraPostgresEngineVersion.VER_13_7),
instance_props=rds.InstanceProps(
vpc=vpc,
vpc_subnets=ec2.SubnetSelection(subnet_type=ec2.SubnetType.PRIVATE_WITH_NAT),
instance_type=ec2.InstanceType.of(ec2.InstanceClass.R6G, ec2.InstanceSize.LARGE)
),
instances=1,
default_database_name="university",
serverless_v2_scaling_configuration=rds.ServerlessV2ScalingConfiguration(
min_capacity=0.5,
max_capacity=4
),
enable_data_api=True,
)
# Add a Serverless v2 instance to the cluster
serverless_instance = rds.CfnDBInstance(self, "ServerlessInstance",
db_instance_class="db.serverless",
engine="aurora-postgresql",
db_cluster_identifier=db_cluster.cluster_identifier,
)
# Ensure the instance is created after the cluster
serverless_instance.add_dependency(db_cluster)
# Create a secret for database credentials
db_secret = db_cluster.secret
# Lambda function role for schema creation
schema_creation_role = iam.Role(self, "SchemaCreationRole",
assumed_by=iam.ServicePrincipal("lambda.amazonaws.com"),
managed_policies=[
iam.ManagedPolicy.from_aws_managed_policy_name("service-role/AWSLambdaBasicExecutionRole"),
iam.ManagedPolicy.from_aws_managed_policy_name("AmazonRDSDataFullAccess"),
]
)
# Lambda function for schema creation
schema_creation_lambda = _lambda.Function(self, "SchemaCreationLambda",
runtime=_lambda.Runtime.PYTHON_3_9,
handler="index.handler",
code=_lambda.Code.from_asset("schema_creation_lambda"),
environment={
"DB_CLUSTER_ARN": db_cluster.cluster_arn,
"DB_SECRET_ARN": db_secret.secret_arn,
"DB_NAME": "university",
},
timeout=Duration.seconds(300),
role=schema_creation_role,
)
# Grant permissions to the schema creation Lambda function
db_cluster.grant_data_api_access(schema_creation_lambda)
db_secret.grant_read(schema_creation_lambda)
# Lambda function role for API
api_lambda_role = iam.Role(self, "APILambdaRole",
assumed_by=iam.ServicePrincipal("lambda.amazonaws.com"),
managed_policies=[
iam.ManagedPolicy.from_aws_managed_policy_name("service-role/AWSLambdaBasicExecutionRole"),
iam.ManagedPolicy.from_aws_managed_policy_name("AmazonRDSDataFullAccess"),
]
)
# Lambda function for API
api_lambda_function = _lambda.Function(self, "UniversityAPIFunction",
runtime=_lambda.Runtime.PYTHON_3_9,
handler="index.lambda_handler",
code=_lambda.Code.from_asset("api_lambda"),
environment={
"DB_CLUSTER_ARN": db_cluster.cluster_arn,
"DB_SECRET_ARN": db_secret.secret_arn,
"DATABASE_NAME": "university"
},
timeout=Duration.seconds(30),
role=api_lambda_role,
)
# Grant permissions to the API Lambda function
db_cluster.grant_data_api_access(api_lambda_function)
db_secret.grant_read(api_lambda_function)
# API Gateway
api = apigateway.LambdaRestApi(self, "UniversityAPI",
handler=lambda_function,
proxy=False
)
academics = api.root.add_resource("academics")
academics.add_resource("departments").add_method("GET")
academics.add_resource("departments").add_method("POST")
academics.add_resource("courses").add_method("GET")
academics.add_resource("courses").add_method("POST")
staff = api.root.add_resource("staff")
staff.add_resource("employees").add_method("GET")
staff.add_resource("employees").add_method("POST")
facilities = api.root.add_resource("facilities")
facilities.add_resource("buildings").add_method("GET")
facilities.add_resource("buildings").add_method("POST")
research = api.root.add_resource("research")
research.add_resource("projects").add_method("GET")
research.add_resource("projects").add_method("POST")
# Output the API URL and Database Endpoint
CfnOutput(self, "APIUrl", value=api.url)
CfnOutput(self, "DBEndpoint", value=db_cluster.cluster_endpoint.hostname)
CfnOutput(self, "DBSecretName", value=db_secret.secret_name)
- It is mixing up the Serverless cluster configurations with the provisioned configuration
- The API resource creation can lead to duplicate resources errors.
- It has not used all the APIs identified originally. Let us ignore it for now. But you can prompt it to include all the needed APIs.
add_resource
method potentially causing errors due to existing resources. To fix this, we can modify the API Gateway setup to ensure we don't try to add the same resource twice. Here's an updated version of the CDK code:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
from aws_cdk import (
Stack,
aws_ec2 as ec2,
aws_rds as rds,
aws_lambda as lambda_,
aws_apigateway as apigw,
SecretValue,
CfnOutput,
Duration,
)
from constructs import Construct
class UniversityManagementStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
# Create VPC
vpc = ec2.Vpc(self, "UniversityVPC", max_azs=2)
# Create Aurora PostgreSQL cluster
cluster = rds.DatabaseCluster(self, "Database",
engine=rds.DatabaseClusterEngine.aurora_postgres(version=rds.AuroraPostgresEngineVersion.VER_16_2),
instance_props=rds.InstanceProps(
instance_type=ec2.InstanceType.of(ec2.InstanceClass.R6G, ec2.InstanceSize.LARGE),
vpc_subnets=ec2.SubnetSelection(subnet_type=ec2.SubnetType.PRIVATE_WITH_NAT),
vpc=vpc
),
instances=1,
credentials=rds.Credentials.from_generated_secret("clusteradmin"),
default_database_name="university",
enable_data_api=True # This enables the RDS Data API
)
# Create Lambda function for schema creation
schema_lambda = lambda_.Function(self, "SchemaCreationLambda",
runtime=lambda_.Runtime.PYTHON_3_9,
handler="index.handler",
code=lambda_.Code.from_asset("lambda/schema"),
environment={
"DB_SECRET_ARN": cluster.secret.secret_arn,
"DB_NAME": "university",
"CLUSTER_ENDPOINT": cluster.cluster_endpoint.hostname,
},
timeout=Duration.seconds(300),
vpc=vpc,
vpc_subnets=ec2.SubnetSelection(subnet_type=ec2.SubnetType.PRIVATE_WITH_NAT),
)
# Grant permissions to the schema Lambda
cluster.secret.grant_read(schema_lambda)
cluster.connections.allow_default_port_from(schema_lambda)
# Create Lambda function for API
api_lambda = lambda_.Function(self, "APILambda",
runtime=lambda_.Runtime.PYTHON_3_9,
handler="index.handler",
code=lambda_.Code.from_asset("lambda/api"),
environment={
"DB_SECRET_ARN": cluster.secret.secret_arn,
"DB_NAME": "university",
"DB_CLUSTER_ARN": cluster.cluster_arn,
},
timeout=Duration.seconds(30),
vpc=vpc,
vpc_subnets=ec2.SubnetSelection(subnet_type=ec2.SubnetType.PRIVATE_WITH_NAT),
)
# Grant permissions to the API Lambda
cluster.secret.grant_read(api_lambda)
cluster.connections.allow_default_port_from(api_lambda)
# Create API Gateway
api = apigw.LambdaRestApi(self, "UniversityAPI",
handler=api_lambda,
proxy=False
)
# Add resources and methods to API Gateway
academics = api.root.add_resource("academics")
departments = academics.add_resource("departments")
departments.add_method("GET")
departments.add_method("POST")
courses = academics.add_resource("courses")
courses.add_method("GET")
courses.add_method("POST")
staff = api.root.add_resource("staff")
employees = staff.add_resource("employees")
employees.add_method("GET")
employees.add_method("POST")
facilities = api.root.add_resource("facilities")
buildings = facilities.add_resource("buildings")
buildings.add_method("GET")
buildings.add_method("POST")
research = api.root.add_resource("research")
projects = research.add_resource("projects")
projects.add_method("GET")
projects.add_method("POST")
# Outputs
CfnOutput(self, "DatabaseEndpoint", value=cluster.cluster_endpoint.hostname)
CfnOutput(self, "DatabaseSecretArn", value=cluster.secret.secret_arn)
CfnOutput(self, "APIUrl", value=api.url)
- API Lambda (
lambda/api/index.py
): (Use the python code created in the earlier step) - Schema Creation Lambda (
lambda/schema/index.py
):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import os
import json
import boto3
import cfnresponse
rds_data = boto3.client("rds-data")
def execute_statement(sql):
response = rds_data.execute_statement(
resourceArn=os.environ["DB_CLUSTER_ARN"],
secretArn=os.environ["DB_SECRET_ARN"],
database=os.environ["DB_NAME"],
sql=sql,
)
return response
def create_schema():
schemas = [
"CREATE SCHEMA IF NOT EXISTS academics;",
"CREATE SCHEMA IF NOT EXISTS staff;",
"CREATE SCHEMA IF NOT EXISTS facilities;",
"CREATE SCHEMA IF NOT EXISTS research;",
]
tables = [
"""
CREATE TABLE IF NOT EXISTS academics.departments (
department_id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
code VARCHAR(10) UNIQUE NOT NULL
);
""",
"""
CREATE TABLE IF NOT EXISTS academics.courses (
course_id SERIAL PRIMARY KEY,
department_id INTEGER REFERENCES academics.departments(department_id),
code VARCHAR(20) UNIQUE NOT NULL,
title VARCHAR(200) NOT NULL,
credits INTEGER NOT NULL
);
""",
"""
CREATE TABLE IF NOT EXISTS academics.students (
student_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
date_of_birth DATE NOT NULL,
enrollment_date DATE NOT NULL,
major_department_id INTEGER REFERENCES academics.departments(department_id)
);
""",
"""
CREATE TABLE IF NOT EXISTS staff.employees (
employee_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
hire_date DATE NOT NULL,
position VARCHAR(100) NOT NULL
);
""",
"""
CREATE TABLE IF NOT EXISTS facilities.buildings (
building_id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
address VARCHAR(200) NOT NULL,
construction_year INTEGER
);
""",
"""
CREATE TABLE IF NOT EXISTS research.projects (
project_id SERIAL PRIMARY KEY,
title VARCHAR(200) NOT NULL,
description TEXT,
start_date DATE,
end_date DATE,
funding_amount DECIMAL(12, 2)
);
""",
]
for schema in schemas:
execute_statement(schema)
for table in tables:
execute_statement(table)
def handler(event, context):
try:
if event["RequestType"] in ["Create", "Update"]:
create_schema()
cfnresponse.send(event, context, cfnresponse.SUCCESS, {})
except Exception as e:
print(f"Error: {str(e)}")
cfnresponse.send(event, context, cfnresponse.FAILED, {})
- Ensure you have Node.js installed (v10.13.0 or later)
- Install AWS CDK:
npm install -g aws-cdk
- Configure AWS CLI with your credentials:
aws configure
- Create a new directory:
mkdir university-management-system
- Navigate to the directory:
cd university-management-system
- Initialize a new CDK project:
cdk init app --language python
- Create a virtual environment:
python -m venv .venv
- Activate the virtual environment:
- On Windows:
.venv\Scripts\activate
- On macOS and Linux:
source .venv/bin/activate
pip install -r requirements.tx
- Add the following to your requirements.tx file and reinstall:
aws-cdk.aws-ec2
aws-cdk.aws-rds
aws-cdk.aws-lambda
aws-cdk.aws-apigateway
- Replace the content of university_management_system/university_management_system_stack.py with the CDK code provided earlier.
- Create directories:
mkdir -p lambda/schema lambda/api
- Create
lambda/schema/index.py
and add the schema creation Lambda code - Create
lambda/api/index.py
and add the API Lambda code
- Run
cdk synth
in your project root directory
- Run
cdk deploy
in your project root directory - Confirm the deployment when prompted
- The CDK will provide updates on the deployment progress
- Once complete, it will output the API Gateway URL, Database Endpoint, and Database Secret ARN
- Use the provided API Gateway URL to test your endpoints
- You can use tools like Postman or curl to send requests to your API
- As you develop your application, you may need to update the Lambda functions or add new API routes
- After making changes, redeploy using
cdk deploy
- To avoid incurring unnecessary costs, run
cdk destroy
to remove all created resources
- Ensure you have sufficient permissions in your AWS account to create and manage the required resources.
- The first deployment might take some time as it creates the Aurora cluster and other resources.
- Always monitor your AWS costs and resources to avoid unexpected charges.
- For production use, consider implementing additional security measures, such as API key authentication for your API Gateway.
- Regularly update and patch your Lambda functions and database to maintain security.
cdk deploy
command working (refer screenshot below) without having to do any changes to the code. In less than 600 seconds, the deploy completed creating all the required resources in AWS. ( Aurora PostgreSQL Cluster, Lambda functions, API Gateway resources etc ).- The schema creation lambda appears to be generated as a custom resource to be invoked during the deployment of the resources through CDK/CloudFormation. For testing purposes, I simply comment off the
#cfnresponse.send()
calls so that I can quickly test from the new Lambda function VS Code IDE. You can also get it updated such that it is invoked during the resource deployment when you run thecdk deploy
. - Next I also wanted the schema generation code to include sample data creation as well and had to run through another prompt to get it added using the next prompt.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
import os
import json
import boto3
#import cfnresponse
from datetime import datetime, timedelta
rds_data = boto3.client("rds-data")
def execute_statement(sql, parameters=[]):
response = rds_data.execute_statement(
resourceArn=os.environ["DB_CLUSTER_ARN"],
secretArn=os.environ["DB_SECRET_ARN"],
database=os.environ["DB_NAME"],
sql=sql,
parameters=parameters
)
return response
def create_schema_and_ingest_data():
schemas = [
"CREATE SCHEMA IF NOT EXISTS academics;",
"CREATE SCHEMA IF NOT EXISTS staff;",
"CREATE SCHEMA IF NOT EXISTS facilities;",
"CREATE SCHEMA IF NOT EXISTS research;",
]
tables = [
"""
CREATE TABLE IF NOT EXISTS academics.departments (
department_id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
code VARCHAR(10) UNIQUE NOT NULL
);
""",
"""
CREATE TABLE IF NOT EXISTS academics.courses (
course_id SERIAL PRIMARY KEY,
department_id INTEGER REFERENCES academics.departments(department_id),
code VARCHAR(20) UNIQUE NOT NULL,
title VARCHAR(200) NOT NULL,
credits INTEGER NOT NULL
);
""",
"""
CREATE TABLE IF NOT EXISTS academics.students (
student_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
date_of_birth DATE NOT NULL,
enrollment_date DATE NOT NULL,
major_department_id INTEGER REFERENCES academics.departments(department_id)
);
""",
"""
CREATE TABLE IF NOT EXISTS staff.employees (
employee_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
hire_date DATE NOT NULL,
position VARCHAR(100) NOT NULL
);
""",
"""
CREATE TABLE IF NOT EXISTS facilities.buildings (
building_id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
address VARCHAR(200) NOT NULL,
construction_year INTEGER
);
""",
"""
CREATE TABLE IF NOT EXISTS research.projects (
project_id SERIAL PRIMARY KEY,
title VARCHAR(200) NOT NULL,
description TEXT,
start_date DATE,
end_date DATE,
funding_amount DECIMAL(12, 2)
);
""",
]
for schema in schemas:
execute_statement(schema)
for table in tables:
execute_statement(table)
# Sample data insertion
sample_data = [
("INSERT INTO academics.departments (name, code) VALUES (:name, :code)",
[
[{'name': 'name', 'value': {'stringValue': 'Computer Science'}}, {'name': 'code', 'value': {'stringValue': 'CS'}}],
[{'name': 'name', 'value': {'stringValue': 'Physics'}}, {'name': 'code', 'value': {'stringValue': 'PHY'}}],
[{'name': 'name', 'value': {'stringValue': 'Mathematics'}}, {'name': 'code', 'value': {'stringValue': 'MATH'}}]
]),
("INSERT INTO academics.courses (department_id, code, title, credits) VALUES (:dept_id, :code, :title, :credits)",
[
[{'name': 'dept_id', 'value': {'longValue': 1}}, {'name': 'code', 'value': {'stringValue': 'CS101'}}, {'name': 'title', 'value': {'stringValue': 'Introduction to Programming'}}, {'name': 'credits', 'value': {'longValue': 3}}],
[{'name': 'dept_id', 'value': {'longValue': 2}}, {'name': 'code', 'value': {'stringValue': 'PHY201'}}, {'name': 'title', 'value': {'stringValue': 'Classical Mechanics'}}, {'name': 'credits', 'value': {'longValue': 4}}],
[{'name': 'dept_id', 'value': {'longValue': 3}}, {'name': 'code', 'value': {'stringValue': 'MATH301'}}, {'name': 'title', 'value': {'stringValue': 'Linear Algebra'}}, {'name': 'credits', 'value': {'longValue': 3}}]
]),
("INSERT INTO academics.students (first_name, last_name, date_of_birth, enrollment_date, major_department_id) VALUES (:fname, :lname, CAST(:dob AS DATE), CAST(:enroll_date AS DATE), :dept_id)",
[
[{'name': 'fname', 'value': {'stringValue': 'John'}}, {'name': 'lname', 'value': {'stringValue': 'Doe'}}, {'name': 'dob', 'value': {'stringValue': '2000-01-15'}}, {'name': 'enroll_date', 'value': {'stringValue': '2022-09-01'}}, {'name': 'dept_id', 'value': {'longValue': 1}}],
[{'name': 'fname', 'value': {'stringValue': 'Jane'}}, {'name': 'lname', 'value': {'stringValue': 'Smith'}}, {'name': 'dob', 'value': {'stringValue': '2001-03-22'}}, {'name': 'enroll_date', 'value': {'stringValue': '2022-09-01'}}, {'name': 'dept_id', 'value': {'longValue': 2}}],
[{'name': 'fname', 'value': {'stringValue': 'Alice'}}, {'name': 'lname', 'value': {'stringValue': 'Johnson'}}, {'name': 'dob', 'value': {'stringValue': '2000-07-30'}}, {'name': 'enroll_date', 'value': {'stringValue': '2022-09-01'}}, {'name': 'dept_id', 'value': {'longValue': 3}}]
]),
("INSERT INTO staff.employees (first_name, last_name, email, hire_date, position) VALUES (:fname, :lname, :email, CAST(:hire_date AS DATE), :position)",
[
[{'name': 'fname', 'value': {'stringValue': 'Robert'}}, {'name': 'lname', 'value': {'stringValue': 'Brown'}}, {'name': 'email', 'value': {'stringValue': 'robert.brown@university.edu'}}, {'name': 'hire_date', 'value': {'stringValue': '2015-08-15'}}, {'name': 'position', 'value': {'stringValue': 'Professor'}}],
[{'name': 'fname', 'value': {'stringValue': 'Emily'}}, {'name': 'lname', 'value': {'stringValue': 'Davis'}}, {'name': 'email', 'value': {'stringValue': 'emily.davis@university.edu'}}, {'name': 'hire_date', 'value': {'stringValue': '2018-01-10'}}, {'name': 'position', 'value': {'stringValue': 'Associate Professor'}}],
[{'name': 'fname', 'value': {'stringValue': 'Michael'}}, {'name': 'lname', 'value': {'stringValue': 'Wilson'}}, {'name': 'email', 'value': {'stringValue': 'michael.wilson@university.edu'}}, {'name': 'hire_date', 'value': {'stringValue': '2020-07-01'}}, {'name': 'position', 'value': {'stringValue': 'Assistant Professor'}}]
]),
("INSERT INTO facilities.buildings (name, address, construction_year) VALUES (:name, :address, :year)",
[
[{'name': 'name', 'value': {'stringValue': 'Science Building'}}, {'name': 'address', 'value': {'stringValue': '123 University Ave'}}, {'name': 'year', 'value': {'longValue': 1985}}],
[{'name': 'name', 'value': {'stringValue': 'Library'}}, {'name': 'address', 'value': {'stringValue': '456 College St'}}, {'name': 'year', 'value': {'longValue': 1990}}],
[{'name': 'name', 'value': {'stringValue': 'Student Center'}}, {'name': 'address', 'value': {'stringValue': '789 Campus Rd'}}, {'name': 'year', 'value': {'longValue': 2005}}]
]),
("INSERT INTO research.projects (title, description, start_date, end_date, funding_amount) VALUES (:title, :desc, CAST(:start AS DATE), CAST(:end AS DATE), :amount)",
[
[{'name': 'title', 'value': {'stringValue': 'AI in Education'}}, {'name': 'desc', 'value': {'stringValue': 'Exploring AI applications in higher education'}}, {'name': 'start', 'value': {'stringValue': '2023-01-01'}}, {'name': 'end', 'value': {'stringValue': '2025-12-31'}}, {'name': 'amount', 'value': {'doubleValue': 500000.00}}],
[{'name': 'title', 'value': {'stringValue': 'Quantum Computing Advances'}}, {'name': 'desc', 'value': {'stringValue': 'Research on quantum algorithms'}}, {'name': 'start', 'value': {'stringValue': '2022-07-01'}}, {'name': 'end', 'value': {'stringValue': '2024-06-30'}}, {'name': 'amount', 'value': {'doubleValue': 750000.00}}],
[{'name': 'title', 'value': {'stringValue': 'Climate Change Mitigation'}}, {'name': 'desc', 'value': {'stringValue': 'Studying effective climate change mitigation strategies'}}, {'name': 'start', 'value': {'stringValue': '2023-03-15'}}, {'name': 'end', 'value': {'stringValue': '2026-03-14'}}, {'name': 'amount', 'value': {'doubleValue': 1000000.00}}]
])
]
for sql, data in sample_data:
for item in data:
execute_statement(sql, item)
def handler(event, context):
try:
if event["RequestType"] in ["Create", "Update"]:
create_schema_and_ingest_data()
print("Schema and tables created with sample data !! ")
#cfnresponse.send(event, context, cfnresponse.SUCCESS, {})
except Exception as e:
print(f"Error: {str(e)}")
#cfnresponse.send(event, context, cfnresponse.FAILED, {})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
from aws_cdk import (
Stack,
aws_ec2 as ec2,
aws_rds as rds,
aws_iam as iam,
aws_lambda as lambda_,
aws_apigateway as apigw,
SecretValue,
CfnOutput,
Duration,
CustomResource,
aws_logs as logs,
)
from constructs import Construct
class UniversityManagementStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
# Create VPC
vpc = ec2.Vpc(self, "UniversityVPC", max_azs=2)
# Create Aurora PostgreSQL cluster
cluster = rds.DatabaseCluster(
self,
"Database",
engine=rds.DatabaseClusterEngine.aurora_postgres(
version=rds.AuroraPostgresEngineVersion.VER_16_2
),
instance_props=rds.InstanceProps(
instance_type=ec2.InstanceType.of(
ec2.InstanceClass.R6G, ec2.InstanceSize.LARGE
),
vpc_subnets=ec2.SubnetSelection(
subnet_type=ec2.SubnetType.PRIVATE_WITH_NAT
),
vpc=vpc,
),
instances=1,
credentials=rds.Credentials.from_generated_secret("clusteradmin"),
default_database_name="university",
enable_data_api=True, # This enables the RDS Data API
)
# Create IAM role for schema creation Lambda
schema_lambda_role = iam.Role(
self,
"SchemaLambdaRole",
assumed_by=iam.ServicePrincipal("lambda.amazonaws.com"),
description="Role for Schema Creation Lambda",
)
# Add policies to the role
schema_lambda_role.add_managed_policy(
iam.ManagedPolicy.from_aws_managed_policy_name(
"service-role/AWSLambdaVPCAccessExecutionRole"
)
)
schema_lambda_role.add_to_policy(
iam.PolicyStatement(
actions=["rds-data:ExecuteStatement"], resources=[cluster.cluster_arn]
)
)
schema_lambda_role.add_to_policy(
iam.PolicyStatement(
actions=["secretsmanager:GetSecretValue"],
resources=[cluster.secret.secret_arn],
)
)
# Create Lambda function for schema creation
schema_lambda = lambda_.Function(
self,
"SchemaCreationLambda",
runtime=lambda_.Runtime.PYTHON_3_9,
handler="index.handler",
code=lambda_.Code.from_asset("lambda/schema"),
environment={
"DB_SECRET_ARN": cluster.secret.secret_arn,
"DB_NAME": "university",
"DB_CLUSTER_ARN": cluster.cluster_arn,
},
timeout=Duration.seconds(300),
vpc=vpc,
vpc_subnets=ec2.SubnetSelection(
subnet_type=ec2.SubnetType.PRIVATE_WITH_NAT
),
role=schema_lambda_role, # Assign the role to the Lambda function
)
# Grant permissions to the schema Lambda
cluster.secret.grant_read(schema_lambda)
cluster.connections.allow_default_port_from(schema_lambda)
# Create IAM role for schema creation Lambda
api_lambda_role = iam.Role(
self,
"APILambdaRole",
assumed_by=iam.ServicePrincipal("lambda.amazonaws.com"),
description="Role for API Lambda",
)
# Add policies to the role
api_lambda_role.add_managed_policy(
iam.ManagedPolicy.from_aws_managed_policy_name(
"service-role/AWSLambdaVPCAccessExecutionRole"
)
)
api_lambda_role.add_to_policy(
iam.PolicyStatement(
actions=["rds-data:ExecuteStatement"], resources=[cluster.cluster_arn]
)
)
api_lambda_role.add_to_policy(
iam.PolicyStatement(
actions=["secretsmanager:GetSecretValue"],
resources=[cluster.secret.secret_arn],
)
)
# Create Lambda function for API
api_lambda = lambda_.Function(
self,
"APILambda",
runtime=lambda_.Runtime.PYTHON_3_9,
handler="index.handler",
code=lambda_.Code.from_asset("lambda/api"),
environment={
"DB_SECRET_ARN": cluster.secret.secret_arn,
"DB_NAME": "university",
"DB_CLUSTER_ARN": cluster.cluster_arn,
},
timeout=Duration.seconds(30),
vpc=vpc,
vpc_subnets=ec2.SubnetSelection(
subnet_type=ec2.SubnetType.PRIVATE_WITH_NAT
),
role=api_lambda_role, # Assign the role to the Lambda function
)
# Grant permissions to the API Lambda
cluster.secret.grant_read(api_lambda)
cluster.connections.allow_default_port_from(api_lambda)
# Create API Gateway
api = apigw.LambdaRestApi(
self, "UniversityAPI", handler=api_lambda, proxy=False
)
# Add resources and methods to API Gateway
academics = api.root.add_resource("academics")
departments = academics.add_resource("departments")
departments.add_method("GET")
departments.add_method("POST")
courses = academics.add_resource("courses")
courses.add_method("GET")
courses.add_method("POST")
staff = api.root.add_resource("staff")
employees = staff.add_resource("employees")
employees.add_method("GET")
employees.add_method("POST")
facilities = api.root.add_resource("facilities")
buildings = facilities.add_resource("buildings")
buildings.add_method("GET")
buildings.add_method("POST")
research = api.root.add_resource("research")
projects = research.add_resource("projects")
projects.add_method("GET")
projects.add_method("POST")
# Outputs
CfnOutput(self, "DatabaseEndpoint", value=cluster.cluster_endpoint.hostname)
CfnOutput(self, "DatabaseSecretArn", value=cluster.secret.secret_arn)
CfnOutput(self, "APIUrl", value=api.url)
cdk deploy
for the new changes in the CDK code (IAM role for Lambda) to be updated and now I can test the Lambda function to confirm that it can create the schema successfully.Any opinions in this post are those of the individual author and may not reflect the opinions of AWS.