Skip to content

Commit f4e657b

Browse files
committed
Update code
1 parent e879b71 commit f4e657b

File tree

8 files changed

+285
-36
lines changed

8 files changed

+285
-36
lines changed

typescript/postgres-lambda/.gitignore

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
!jest.config.js
33
*.d.ts
44
node_modules
5-
# Allow node_modules in Lambda directories
6-
!lambda/*/node_modules
5+
**/node_modules
6+
77
!lambda/*/*.js
88

99
# CDK asset staging directory
@@ -12,11 +12,6 @@ cdk.out
1212

1313
# Yarn specific
1414
.yarn/*
15-
!.yarn/patches
16-
!.yarn/plugins
17-
!.yarn/releases
18-
!.yarn/sdks
19-
!.yarn/versions
2015
.pnp.*
2116
yarn-debug.log*
2217
yarn-error.log*
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
const { Client } = require('pg');
2+
const { SecretsManager } = require('@aws-sdk/client-secrets-manager');
3+
4+
const secretsManager = new SecretsManager();
5+
6+
/**
7+
* Lambda function that connects to PostgreSQL and executes a query
8+
*/
9+
exports.handler = async (event) => {
10+
console.log('Event received:', JSON.stringify(event));
11+
12+
try {
13+
// Get database credentials from Secrets Manager
14+
const secretArn = process.env.DB_SECRET_ARN;
15+
const dbName = process.env.DB_NAME;
16+
17+
console.log(`Retrieving secret from ${secretArn}`);
18+
const secretResponse = await secretsManager.getSecretValue({ SecretId: secretArn });
19+
const secret = JSON.parse(secretResponse.SecretString);
20+
21+
// Create PostgreSQL client
22+
const client = new Client({
23+
host: secret.host,
24+
port: secret.port,
25+
database: dbName,
26+
user: secret.username,
27+
password: secret.password,
28+
ssl: {
29+
rejectUnauthorized: false, // For demo purposes only, consider proper SSL setup in production
30+
},
31+
connectionTimeoutMillis: 5000,
32+
});
33+
34+
// Connect to the database
35+
console.log('Connecting to PostgreSQL database...');
36+
await client.connect();
37+
38+
// Check if our demo table exists, if not create it
39+
console.log('Creating demo table if it does not exist...');
40+
await client.query(`
41+
CREATE TABLE IF NOT EXISTS demo_table (
42+
id SERIAL PRIMARY KEY,
43+
message TEXT NOT NULL,
44+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
45+
)
46+
`);
47+
48+
// Insert a record
49+
const message = event.message || 'Hello from Lambda!';
50+
console.log(`Inserting message: ${message}`);
51+
await client.query('INSERT INTO demo_table (message) VALUES ($1)', [message]);
52+
53+
// Query the records
54+
console.log('Querying records...');
55+
const result = await client.query('SELECT * FROM demo_table ORDER BY created_at DESC LIMIT 10');
56+
57+
// Close the connection
58+
await client.end();
59+
60+
// Return the results
61+
return {
62+
statusCode: 200,
63+
body: JSON.stringify({
64+
message: 'Query executed successfully',
65+
records: result.rows,
66+
}),
67+
};
68+
} catch (error) {
69+
console.error('Error:', error);
70+
return {
71+
statusCode: 500,
72+
body: JSON.stringify({
73+
message: 'Error executing query',
74+
error: error.message,
75+
}),
76+
};
77+
}
78+
};
Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,9 @@
11
{
2-
"name": "@lambda/lambda-to-postgres",
2+
"name": "lambda-to-postgres",
33
"version": "1.0.0",
44
"description": "Lambda function that connects to PostgreSQL",
55
"main": "index.js",
6-
"scripts": {
7-
"build": "echo 'No build needed for JavaScript files'",
8-
"test": "echo \"Error: no test specified\" && exit 1"
9-
},
106
"dependencies": {
11-
"pg": "^8.16.3",
12-
"aws-sdk": "^2.1377.0"
7+
"pg": "^8.11.0"
138
}
149
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
const { Client } = require('pg');
2+
const { SecretsManagerClient, GetSecretValueCommand } = require('@aws-sdk/client-secrets-manager');
3+
4+
const secretsManager = new SecretsManagerClient();
5+
6+
exports.handler = async (event) => {
7+
console.log('Event:', JSON.stringify(event, null, 2));
8+
9+
if (event.RequestType === 'Delete') {
10+
return sendResponse(event, 'SUCCESS', 'Delete operation completed');
11+
}
12+
13+
try {
14+
const { DB_SECRET_ARN, DB_NAME, POSTGRES_FUNCTION_NAME, AWS_REGION } = process.env;
15+
16+
// Get database credentials
17+
const secretResponse = await secretsManager.send(
18+
new GetSecretValueCommand({ SecretId: DB_SECRET_ARN })
19+
);
20+
const secret = JSON.parse(secretResponse.SecretString);
21+
22+
// Connect to PostgreSQL
23+
const client = new Client({
24+
host: secret.host,
25+
port: secret.port,
26+
database: DB_NAME,
27+
user: secret.username,
28+
password: secret.password,
29+
ssl: { rejectUnauthorized: false }
30+
});
31+
32+
await client.connect();
33+
34+
// Execute setup SQL
35+
const setupSQL = `
36+
CREATE EXTENSION IF NOT EXISTS aws_lambda CASCADE;
37+
38+
CREATE OR REPLACE FUNCTION process_data(data JSONB)
39+
RETURNS JSONB AS $$
40+
SELECT payload FROM aws_lambda.invoke(
41+
aws_commons.create_lambda_function_arn('${POSTGRES_FUNCTION_NAME}', '${AWS_REGION}'),
42+
json_build_object('action', 'process', 'data', data)::text,
43+
'Event'
44+
);
45+
$$ LANGUAGE SQL;
46+
47+
CREATE OR REPLACE FUNCTION transform_data(data JSONB)
48+
RETURNS JSONB AS $$
49+
SELECT payload FROM aws_lambda.invoke(
50+
aws_commons.create_lambda_function_arn('${POSTGRES_FUNCTION_NAME}', '${AWS_REGION}'),
51+
json_build_object('action', 'transform', 'data', data)::text,
52+
'Event'
53+
);
54+
$$ LANGUAGE SQL;
55+
56+
CREATE OR REPLACE FUNCTION validate_data(data JSONB)
57+
RETURNS JSONB AS $$
58+
SELECT payload FROM aws_lambda.invoke(
59+
aws_commons.create_lambda_function_arn('${POSTGRES_FUNCTION_NAME}', '${AWS_REGION}'),
60+
json_build_object('action', 'validate', 'data', data)::text,
61+
'Event'
62+
);
63+
$$ LANGUAGE SQL;
64+
`;
65+
66+
await client.query(setupSQL);
67+
await client.end();
68+
69+
return sendResponse(event, 'SUCCESS', 'PostgreSQL setup completed successfully');
70+
71+
} catch (error) {
72+
console.error('Error:', error);
73+
return sendResponse(event, 'FAILED', error.message);
74+
}
75+
};
76+
77+
async function sendResponse(event, status, reason) {
78+
const response = {
79+
Status: status,
80+
Reason: reason,
81+
PhysicalResourceId: 'postgres-setup-' + Date.now(),
82+
StackId: event.StackId,
83+
RequestId: event.RequestId,
84+
LogicalResourceId: event.LogicalResourceId
85+
};
86+
87+
console.log('Response:', JSON.stringify(response, null, 2));
88+
89+
const fetch = (await import('node-fetch')).default;
90+
await fetch(event.ResponseURL, {
91+
method: 'PUT',
92+
headers: { 'Content-Type': '' },
93+
body: JSON.stringify(response)
94+
});
95+
96+
return response;
97+
}
Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,9 @@
11
{
2-
"name": "@lambda/postgres-setup",
2+
"name": "postgres-setup",
33
"version": "1.0.0",
4-
"description": "Lambda function for automated PostgreSQL setup",
4+
"description": "Lambda function for PostgreSQL setup",
55
"main": "index.js",
6-
"scripts": {
7-
"build": "echo 'No build needed for JavaScript files'",
8-
"test": "echo \"Error: no test specified\" && exit 1"
9-
},
106
"dependencies": {
11-
"pg": "^8.16.3",
12-
"aws-sdk": "^2.1377.0"
7+
"pg": "^8.11.0"
138
}
149
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/**
2+
* Lambda function that is called by PostgreSQL
3+
*
4+
* This function can be invoked from PostgreSQL using the aws_lambda extension
5+
* Example SQL:
6+
*
7+
* SELECT * FROM aws_lambda.invoke(
8+
* aws_commons.create_lambda_function_arn('PostgresFunction', 'us-east-1'),
9+
* '{"action": "process", "data": {"id": 123, "value": "test"}}',
10+
* 'Event'
11+
* );
12+
*/
13+
exports.handler = async (event) => {
14+
console.log('Event received from PostgreSQL:', JSON.stringify(event));
15+
16+
try {
17+
// Process the event data
18+
const action = event.action || 'default';
19+
const data = event.data || {};
20+
21+
let result;
22+
23+
// Perform different actions based on the event
24+
switch (action) {
25+
case 'process':
26+
result = processData(data);
27+
break;
28+
case 'transform':
29+
result = transformData(data);
30+
break;
31+
case 'validate':
32+
result = validateData(data);
33+
break;
34+
default:
35+
result = { status: 'success', message: 'Default action performed', data };
36+
}
37+
38+
return {
39+
statusCode: 200,
40+
body: result,
41+
};
42+
} catch (error) {
43+
console.error('Error:', error);
44+
return {
45+
statusCode: 500,
46+
body: {
47+
status: 'error',
48+
message: error.message,
49+
},
50+
};
51+
}
52+
};
53+
54+
/**
55+
* Process data from PostgreSQL
56+
*/
57+
function processData(data) {
58+
console.log('Processing data:', data);
59+
return {
60+
status: 'success',
61+
message: 'Data processed successfully',
62+
processedData: {
63+
...data,
64+
processed: true,
65+
timestamp: new Date().toISOString(),
66+
},
67+
};
68+
}
69+
70+
/**
71+
* Transform data from PostgreSQL
72+
*/
73+
function transformData(data) {
74+
console.log('Transforming data:', data);
75+
return {
76+
status: 'success',
77+
message: 'Data transformed successfully',
78+
transformedData: {
79+
...data,
80+
transformed: true,
81+
uppercase: data.value ? data.value.toUpperCase() : null,
82+
timestamp: new Date().toISOString(),
83+
},
84+
};
85+
}
86+
87+
/**
88+
* Validate data from PostgreSQL
89+
*/
90+
function validateData(data) {
91+
console.log('Validating data:', data);
92+
const isValid = data.id && data.value;
93+
return {
94+
status: isValid ? 'success' : 'error',
95+
message: isValid ? 'Data is valid' : 'Data is invalid',
96+
validationResult: {
97+
isValid,
98+
missingFields: !data.id ? ['id'] : !data.value ? ['value'] : [],
99+
timestamp: new Date().toISOString(),
100+
},
101+
};
102+
}

typescript/postgres-lambda/lib/postgres-lambda-stack.ts

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,6 @@ export class PostgresLambdaStack extends cdk.Stack {
3939
image: cdk.DockerImage.fromRegistry('public.ecr.aws/sam/build-nodejs18.x'),
4040
command: [
4141
'bash', '-c', [
42-
'cp -r . /tmp',
43-
'cd /tmp',
44-
'npm init -y',
45-
'npm install pg',
4642
'cp -r . /asset-output/'
4743
].join(' && ')
4844
],
@@ -75,9 +71,6 @@ export class PostgresLambdaStack extends cdk.Stack {
7571
image: cdk.DockerImage.fromRegistry('public.ecr.aws/sam/build-nodejs18.x'),
7672
command: [
7773
'bash', '-c', [
78-
'cp -r . /tmp',
79-
'cd /tmp',
80-
'npm init -y',
8174
'cp -r . /asset-output/'
8275
].join(' && ')
8376
],
@@ -121,10 +114,6 @@ export class PostgresLambdaStack extends cdk.Stack {
121114
image: cdk.DockerImage.fromRegistry('public.ecr.aws/sam/build-nodejs18.x'),
122115
command: [
123116
'bash', '-c', [
124-
'cp -r . /tmp',
125-
'cd /tmp',
126-
'npm init -y',
127-
'npm install pg',
128117
'cp -r . /asset-output/'
129118
].join(' && ')
130119
],

typescript/postgres-lambda/package.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@
66
".",
77
"lambda/*"
88
],
9-
"bin": {
10-
"postgres-lambda": "bin/postgres-lambda.js"
11-
},
9+
"bin": "bin/postgres-lambda.js",
1210
"scripts": {
1311
"build": "tsc && yarn workspaces foreach -v -A run build",
1412
"build:lambda": "yarn workspaces foreach -v -A run build",

0 commit comments

Comments
 (0)