Skip to content

Commit 3587a07

Browse files
committed
💥 Change data transformation script function parameters
1 parent 7228193 commit 3587a07

10 files changed

Lines changed: 62 additions & 30 deletions

File tree

README.md

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ dynamodb-data-migrations <command> --help
105105
```
106106

107107
## What it does behind the scenes
108-
- When migration is running for the first time a Record in your table is created. \
108+
- When a data migration is running for the first time a Record in your table is created. \
109109
This record is for tracking the executed migrations on a specific table.
110110

111111

@@ -131,13 +131,13 @@ Implement these functions:
131131

132132
1. Preparing data from external resources for the migration can be done by using `sls migration prepare`
133133

134-
Run `sls migration prepare -p $(pwd)/migrations/{{YOUR_TABLE_NAME}}/v1.js`\
134+
Run `sls migration prepare --mNumber <migration_number> --table <table>`\
135135
The data will be stored encrypted in this format: {{FILE_VERSION}}.{{ENV}}.encrypted (e.g v1.local.encrypted) \
136136
The data will be decrypted while running the migration script.
137137

138138
1. **Final Step** Create a pull request. \
139139
Note that the migration runs after an sls deploy command it is integrated \
140-
with lifecycle hooks of serverless `after:deploy:deploy` hook.
140+
with lifecycle of serverless `after:deploy:deploy` hook.
141141

142142
#### The Third Phase (Use The New Resources/Data):
143143
1. Adjust your code to work with the new data. \
@@ -160,6 +160,19 @@ To be continued
160160

161161

162162
### Examples
163+
Examples of data migration code:
164+
165+
#### Insert records
166+
https://github.com/jitsecurity/dynamodb-data-migrations/tree/main/examples/demo/data-migrations/v1_insert_users.js
167+
168+
#### Add a new field to each record
169+
https://github.com/jitsecurity/dynamodb-data-migrations/tree/main/examples/demo/data-migrations/v2_add_random_number_field.js
170+
171+
#### Add field using preparation data (s3 bucket)
172+
https://github.com/jitsecurity/dynamodb-data-migrations/tree/main/examples/demo/data-migrations/v3_using_preparation_data.js
173+
174+
#### Split fullname into first and last name
175+
https://github.com/jitsecurity/dynamodb-data-migrations/tree/main/examples/demo/data-migrations/v4_split_fullname.js
163176

164177
- Required functions to implement by the plugin user examples
165178
1. async transformUp
@@ -206,5 +219,3 @@ const transformDown = async (ddb, isDryRun) => {
206219
} while (lastEvalKey)
207220
}
208221
```
209-
- To be continued
210-
<!-- - `sls migration up --stage local` - -->

src/command-handlers/down.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ const down = async ({ table, dry: isDryRun }) => {
2828
console.info('Running data migration script using preparation data');
2929
}
3030

31-
await transformDown(ddb, preparationData, isDryRun);
31+
await transformDown({ ddb, preparationData, isDryRun });
3232

3333
if (!isDryRun) {
3434
await rollbackMigration(ddb, latestDataMigrationNumber, table);

src/command-handlers/prepare.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const prepareHandler = async ({ table, mNumber, dry: isDryRun }) => {
1414

1515
const ddb = getDynamoDBClient();
1616
const prepatationDataPath = `${table}/${MIGRATION_NUMBER_PREFIX}${mNumber}`;
17-
const preparationData = await prepare(ddb, isDryRun);
17+
const preparationData = await prepare({ ddb, isDryRun });
1818
if (isDryRun) {
1919
console.info(preparationData, 'preparationData');
2020
console.info("It's a dry run");

src/command-handlers/up.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const executeDataMigration = async (ddb, migration, table, isDryRun) => {
2020
console.info('Running data migration script using preparation data');
2121
}
2222

23-
const transformationResponse = await transformUp(ddb, preparationData, isDryRun);
23+
const transformationResponse = await transformUp({ ddb, preparationData, isDryRun });
2424
if (!isDryRun) {
2525
await syncMigrationRecord(ddb, migrationNumber, table, transformationResponse?.transformed);
2626
} else {

src/config/constants.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@ const MIGRATION_SCRIPT_EXTENSION = '.js';
44
const MIGRATION_NUMBER_PREFIX = 'v';
55
const MIGRATION_NAME_SEPARATOR = '_';
66

7+
const DATA_MIGRATIONS_KEY_ID = 'DataMigrations';
8+
79
module.exports = {
810
DATA_MIGRATIONS_FOLDER_NAME,
911
BASE_MIGRATIONS_FOLDER_PATH,
1012
MIGRATION_SCRIPT_EXTENSION,
1113
MIGRATION_NUMBER_PREFIX,
1214
MIGRATION_NAME_SEPARATOR,
15+
DATA_MIGRATIONS_KEY_ID,
1316
};

src/config/migration-template-file.js

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,28 @@ const { utils } = require('@jitsecurity/dynamodb-data-migrations');
22

33
const TABLE_NAME = '{{YOUR_TABLE_NAME}}';
44

5-
const up = (item) => {
6-
// Adding a new field to the item example
7-
const updatedItem = { ...item, newField: 'value' };
8-
return updatedItem;
5+
/**
6+
* @param {DynamoDBDocumentClient} ddb - dynamo db client of @aws-sdk https://github.com/aws/aws-sdk-js-v3/tree/main/clients/client-dynamodb
7+
* @param {boolean} isDryRun
8+
* @returns {{transformed: number}}
9+
*
10+
*/
11+
const transformUp = async ({ ddb, isDryRun }) => {
12+
// Replace this with your own logic
13+
const addNewFieldToItem = (item) => {
14+
const updatedItem = { ...item, newField: 'value' };
15+
return updatedItem;
16+
};
17+
return utils.transformItems(ddb, isDryRun, TABLE_NAME, addNewFieldToItem);
918
};
1019

11-
const transformUp = async (ddb, preparationData, isDryRun) => {
12-
return utils.transformItems(ddb, isDryRun, TABLE_NAME, up);
13-
};
14-
15-
const down = (item) => {
16-
const { newField, ...oldItem } = item;
17-
return oldItem;
18-
};
19-
20-
const transformDown = async (ddb, isDryRun) => {
21-
return utils.transformItems(ddb, isDryRun, TABLE_NAME, down);
20+
const transformDown = async ({ ddb, isDryRun }) => {
21+
// Replace this function with your own logic
22+
const removeFieldFromItem = (item) => {
23+
const { newField, ...oldItem } = item;
24+
return oldItem;
25+
};
26+
return utils.transformItems(ddb, isDryRun, TABLE_NAME, removeFieldFromItem);
2227
};
2328

2429
module.exports = {
@@ -27,3 +32,9 @@ module.exports = {
2732
// prepare, // pass this function only if you need preparation data for the migration
2833
migrationNumber: 1,
2934
};
35+
36+
/**
37+
* For more data migration scripts examples, see:
38+
* https://github.com/jitsecurity/dynamodb-data-migrations/tree/main/examples
39+
*
40+
*/

src/services/dynamodb/migrations-executions-manager.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
const { GetCommand, PutCommand } = require('@aws-sdk/lib-dynamodb');
2+
const { DATA_MIGRATIONS_KEY_ID } = require('../../config/constants');
23
const getTableKeySchema = require('../../utils/getTableKeySchema');
34

4-
const DATA_MIGRATIONS_KEY_ID = 'DataMigrations';
5-
65
const getDataMigrationKey = async (table) => {
76
const keySchema = await getTableKeySchema(table);
87
const dataMigrationKey = keySchema.reduce((acc, val) => ({

src/utils/getItems.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
const { ScanCommand } = require('@aws-sdk/lib-dynamodb');
2+
const { DATA_MIGRATIONS_KEY_ID } = require('../config/constants');
3+
4+
const filterMigrationRecord = (items) => {
5+
return items.filter((item) => !Object.values(item).includes(DATA_MIGRATIONS_KEY_ID));
6+
};
27

38
const getItems = async (ddb, lastEvalKey, tableName) => {
49
const params = {
@@ -8,7 +13,10 @@ const getItems = async (ddb, lastEvalKey, tableName) => {
813
};
914

1015
const scanCommand = new ScanCommand(params);
11-
return ddb.send(scanCommand);
16+
const scanResponse = await ddb.send(scanCommand);
17+
scanResponse.Items = filterMigrationRecord(scanResponse.Items);
18+
19+
return scanResponse;
1220
};
1321

1422
module.exports = getItems;

src/utils/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ const getItems = require('./getItems');
22
const transformItems = require('./transformItems');
33
const transactWriteItems = require('./transactWriteItems');
44
const batchWriteItems = require('./batchWriteItems');
5-
const seedItems = require('./seedItems');
5+
const insertItems = require('./insertItems');
66
const deleteItems = require('./deleteItems');
77

88
module.exports = {
99
getItems,
1010
transactWriteItems,
1111
transformItems,
1212
batchWriteItems,
13-
seedItems,
13+
insertItems,
1414
deleteItems,
1515
};
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const { getUnprocessedItems } = require('./responseUtils');
33

44
const MAX_ITEMS_PER_BATCH = 25;
55

6-
const seedItems = async (ddb, tableName, items, isDryRun) => {
6+
const insertItems = async (ddb, tableName, items, isDryRun) => {
77
if (isDryRun) {
88
console.info(`Dry run: would have seeded ${items.length} items to ${tableName}`, items);
99
return;
@@ -31,4 +31,4 @@ const seedItems = async (ddb, tableName, items, isDryRun) => {
3131
}
3232
};
3333

34-
module.exports = seedItems;
34+
module.exports = insertItems;

0 commit comments

Comments
 (0)