Skip to content

Commit 3daf948

Browse files
committed
📚 examples
1 parent 0b46ae1 commit 3daf948

13 files changed

Lines changed: 9573 additions & 1 deletion

File tree

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ dist
44
local
55
.vscode
66
.DS_Store
7-
examples
7+
.serverless
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
LOCALSTACK_URL=http://localstack:4566
2+
LOCALSTACK_HOSTNAME=localstack
3+
DEPLOYMENT_STAGE=local
4+
AWS_REGION=us-east-1
5+
AWS_ACCESS_KEY_ID=dummy
6+
AWS_SECRET_ACCESS_KEY=dummy
7+
AWS_SESSION_TOKEN=dummy
8+
AWS_CUSTOM_ENDPOINT=http://localhost:4566
9+
LOG_LEVEL=DEBUG
10+
PREPARATION_DATA_BUCKET=transformations-preparation-data-local
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// Adding a new field "hasWikiPage"
2+
// "hasWikiPage" is a boolean field that is set to true if the item has a wiki page
3+
// It is calculated with a prepare function that fetches the wiki page status for each item
4+
5+
const { utils } = require('dynamo-data-transform');
6+
7+
const userAgentHeader = {
8+
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36',
9+
};
10+
11+
const fetch = (...args) => import('node-fetch').then(({ default: nodeFetch }) => nodeFetch(
12+
...args,
13+
{
14+
headers: userAgentHeader,
15+
},
16+
));
17+
18+
const TABLE_NAME = 'UsersExample';
19+
20+
const transformUp = async ({ ddb, preparationData, isDryRun }) => {
21+
const addHasWikiPage = (hasWikiDict) => (item) => {
22+
const valueFromPreparation = hasWikiDict[`${item.PK}-${item.SK}`];
23+
const updatedItem = valueFromPreparation ? {
24+
...item,
25+
hasWikiPage: valueFromPreparation,
26+
} : item;
27+
return updatedItem;
28+
};
29+
30+
return utils.transformItems(
31+
ddb,
32+
TABLE_NAME,
33+
addHasWikiPage(JSON.parse(preparationData)),
34+
isDryRun,
35+
);
36+
};
37+
38+
const transformDown = async ({ ddb, isDryRun }) => {
39+
const removeHasWikiPage = (item) => {
40+
const { hasWikiPage, ...oldItem } = item;
41+
return oldItem;
42+
};
43+
44+
return utils.transformItems(ddb, TABLE_NAME, removeHasWikiPage, isDryRun);
45+
};
46+
47+
const prepare = async ({ ddb }) => {
48+
let lastEvalKey;
49+
let preparationData = {};
50+
51+
let scannedAllItems = false;
52+
53+
while (!scannedAllItems) {
54+
const { Items, LastEvaluatedKey } = await utils.getItems(ddb, lastEvalKey, TABLE_NAME);
55+
lastEvalKey = LastEvaluatedKey;
56+
57+
const currentPreparationData = await Promise.all(Items.map(async (item) => {
58+
const wikiItemUrl = `https://en.wikipedia.org/wiki/${item.name}`;
59+
const currWikiResponse = await fetch(wikiItemUrl);
60+
return {
61+
[`${item.PK}-${item.SK}`]: currWikiResponse.status === 200,
62+
};
63+
}));
64+
65+
preparationData = {
66+
...preparationData,
67+
...currentPreparationData.reduce((acc, item) => ({ ...acc, ...item }), {}),
68+
};
69+
70+
scannedAllItems = !lastEvalKey;
71+
}
72+
73+
return preparationData;
74+
};
75+
76+
module.exports = {
77+
transformUp,
78+
transformDown,
79+
prepare,
80+
transformationNumber: 4,
81+
};
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# This repository shows the usage of the dynamo-data-transform package.
2+
3+
## Quick Start
4+
5+
### Initialize localstack container and dynamodb GUI
6+
*Please make sure you have installed and running docker on your machine.
7+
Run:
8+
```bash
9+
docker compose up
10+
```
11+
12+
### Install dependencies
13+
```bash
14+
npm install
15+
```
16+
17+
### Deploy service to localstack
18+
```bash
19+
npm start
20+
```
21+
22+
Note that after running the above command, all the transformation scripts in data-transformations folder will be executed.
23+
See the UsersExample table here:
24+
http://localhost:8001/
25+
26+
27+
28+
#### Serverless Plugin
29+
```bash
30+
npx sls dynamodt --help
31+
```
32+
33+
#### Interactive Cli
34+
```bash
35+
npm install -g dynamo-data-transform
36+
37+
ddt -i
38+
```
39+
40+
#### Standalone npm package usage:
41+
init - `ddt init -tableNames "Users"`
42+
up - `ddt up`
43+
down - `ddt down -t Users`
44+
prepare - `ddt prepare -t Users --tNumber 3`
45+
history - `ddt history -t Users`
46+
```
47+
48+
49+
50+
## Exercises:
51+
1. For understanding how to prepare data for transformation, take a look at "v4_using_preparation_data.js"
52+
Move the file "v4_using_preparation_data.js" to the data-transformations folder.
53+
```bash
54+
mv EXERCISE-prepare-data/v4_using_preparation_data.js data-transformations/UsersExample
55+
```
56+
Let's check the prepare script results
57+
```bash
58+
npx sls dynamodt prepare --table UsersExample --tNumber 4 --dry
59+
```
60+
The results in the console should be:
61+
```js
62+
{
63+
'USER#21-NAME#Bradley Wiggins: true,
64+
'USER#34-NAME#Chaos': true,
65+
'USER#32-NAME#Knuckles': true,
66+
'USER#29-NAME#Plankton': true,
67+
...
68+
}
69+
```
70+
Now lets prepare some data for the transformation. Run the same command as before but without --dry.
71+
```bash
72+
npx sls dynamodt prepare --table UsersExample --tNumber 4
73+
```
74+
Let's run the pending transformation script, currently it is "v4_using_preparation_data.js"
75+
```bash
76+
npx sls dynamodt up --stage local
77+
```
78+
Now open the dynamodb GUI and check the data.
79+
http://localhost:8001/
80+
81+
2. Rollback the last transformation
82+
```bash
83+
npx sls dynamodt down --stage local --table UsersExample --dry
84+
```
85+
Now you will see in the console that "hasWikiPage" field was removed from each item.
86+
Lets rollback the last transformation for real.
87+
```bash
88+
npx sls dynamodt down --stage local --table UsersExample
89+
```
90+
Now open the dynamodb GUI and check the data.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Seed users data transformation
2+
const { utils } = require('dynamo-data-transform');
3+
4+
const { USERS_DATA } = require('../../usersData');
5+
6+
const TABLE_NAME = 'UsersExample';
7+
8+
/**
9+
* @param {DynamoDBDocumentClient} ddb - dynamo db document client https://github.com/aws/aws-sdk-js-v3/tree/main/clients/client-dynamodb
10+
* @param {boolean} isDryRun - true if this is a dry run
11+
*/
12+
const transformUp = async ({ ddb, isDryRun }) => {
13+
return utils.insertItems(ddb, TABLE_NAME, USERS_DATA, isDryRun);
14+
};
15+
16+
const transformDown = async ({ ddb, isDryRun }) => {
17+
return utils.deleteItems(ddb, TABLE_NAME, USERS_DATA, isDryRun);
18+
};
19+
20+
module.exports = {
21+
transformUp,
22+
transformDown,
23+
transformationNumber: 1,
24+
};
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Adding a "randotNumber" field to each item
2+
const { utils } = require('dynamo-data-transform');
3+
4+
const TABLE_NAME = 'UsersExample';
5+
6+
const transformUp = async ({ ddb, isDryRun }) => {
7+
const addRandotNumberField = (item) => {
8+
const updatedItem = { ...item, randotNumber: Math.random() };
9+
return updatedItem;
10+
};
11+
return utils.transformItems(ddb, TABLE_NAME, addRandotNumberField, isDryRun);
12+
};
13+
14+
const transformDown = async ({ ddb, isDryRun }) => {
15+
const removeRandotNumberField = (item) => {
16+
const { randotNumber, ...oldItem } = item;
17+
return oldItem;
18+
};
19+
return utils.transformItems(ddb, TABLE_NAME, removeRandotNumberField, isDryRun);
20+
};
21+
22+
module.exports = {
23+
transformUp,
24+
transformDown,
25+
// prepare, // pass this function only if you need preparation data for the transformation
26+
transformationNumber: 2,
27+
};
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Split full name of every record into first and last name
2+
const { utils } = require('dynamo-data-transform');
3+
4+
const TABLE_NAME = 'UsersExample';
5+
6+
const transformUp = async ({ ddb, isDryRun }) => {
7+
const addFirstAndLastName = (item) => {
8+
// Just for the example:
9+
// Assume that the FullName has one space between first and last name
10+
const [firstName, ...lastName] = item.name.split(' ');
11+
return {
12+
...item,
13+
firstName,
14+
lastName: lastName.join(' '),
15+
};
16+
};
17+
return utils.transformItems(ddb, TABLE_NAME, addFirstAndLastName, isDryRun);
18+
};
19+
20+
const transformDown = async ({ ddb, isDryRun }) => {
21+
const removeFirstAndLastName = (item) => {
22+
const { firstName, lastName, ...oldItem } = item;
23+
return oldItem;
24+
};
25+
return utils.transformItems(ddb, TABLE_NAME, removeFirstAndLastName, isDryRun);
26+
};
27+
28+
module.exports = {
29+
transformUp,
30+
transformDown,
31+
transformationNumber: 3,
32+
};
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
version: '3.9'
2+
3+
services:
4+
dynamodb:
5+
image: aaronshaf/dynamodb-admin
6+
ports:
7+
- "8001:8001"
8+
environment:
9+
- DYNAMO_ENDPOINT=http://localstack:4566
10+
networks:
11+
- localstack-net
12+
13+
localstack:
14+
image: localstack/localstack:0.14.2
15+
ports:
16+
- "4566-4583:4566-4583"
17+
- "${PORT_WEB_UI-4666}:${PORT_WEB_UI-8080}"
18+
- "8080:8080"
19+
- "4510:4510"
20+
environment:
21+
- SERVICES=${SERVICES-iam,s3,s3api,lambda,apigateway,apigatewaymanagementapi,cloudwatch,events,cloudformation,sts,cognito,secretsmanager,dynamodb,ecr,sqs,ssm,sns}
22+
- DATA_DIR=${DATA_DIR- }
23+
- LOCALSTACK_API_KEY=${LOCALSTACK_API_KEY- }
24+
- PORT_WEB_UI=8080
25+
- START_WEB=0
26+
- LAMBDA_REMOTE_DOCKER=true
27+
- LAMBDA_EXECUTOR=docker-reuse
28+
- LAMBDA_REMOVE_CONTAINERS=true
29+
- DOCKER_HOST=unix:///var/run/docker.sock
30+
- LAMBDA_DOCKER_NETWORK=localstack-net
31+
- KINESIS_ERROR_PROBABILITY=${KINESIS_ERROR_PROBABILITY- }
32+
- LS_LOG=info
33+
- DEBUG=0
34+
- TMPDIR=./tmp/localstack
35+
- HOST_TMP_FOLDER=${TMPDIR}
36+
volumes:
37+
- "/var/run/docker.sock:/var/run/docker.sock"
38+
- "${TMPDIR:-/tmp/localstack}"
39+
networks:
40+
- localstack-net
41+
42+
networks:
43+
localstack-net:
44+
name: localstack-net

examples/serverless-localstack/index.js

Whitespace-only changes.

0 commit comments

Comments
 (0)