@ftschopp/dynatable-migrations 1.1.0 → 1.2.0
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/CHANGELOG.md +7 -0
- package/README.md +102 -134
- package/USAGE.md +199 -60
- package/dist/cli.js +7 -3
- package/dist/cli.js.map +1 -1
- package/dist/commands/down.d.ts +1 -1
- package/dist/commands/down.d.ts.map +1 -1
- package/dist/commands/down.js +5 -20
- package/dist/commands/down.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +2 -17
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/up.d.ts +1 -1
- package/dist/commands/up.d.ts.map +1 -1
- package/dist/commands/up.js +5 -20
- package/dist/commands/up.js.map +1 -1
- package/dist/core/client.d.ts +7 -0
- package/dist/core/client.d.ts.map +1 -0
- package/dist/core/client.js +25 -0
- package/dist/core/client.js.map +1 -0
- package/dist/core/loader.d.ts +8 -0
- package/dist/core/loader.d.ts.map +1 -1
- package/dist/core/loader.js +76 -43
- package/dist/core/loader.js.map +1 -1
- package/dist/core/runner.d.ts +6 -2
- package/dist/core/runner.d.ts.map +1 -1
- package/dist/core/runner.js +124 -67
- package/dist/core/runner.js.map +1 -1
- package/dist/core/tracker.d.ts +20 -1
- package/dist/core/tracker.d.ts.map +1 -1
- package/dist/core/tracker.js +273 -83
- package/dist/core/tracker.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/types/index.d.ts +10 -1
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -3
- package/src/cli.ts +8 -3
- package/src/commands/down.ts +6 -22
- package/src/commands/status.ts +2 -19
- package/src/commands/up.ts +9 -22
- package/src/core/client.ts +24 -0
- package/src/core/loader.ts +88 -46
- package/src/core/runner.ts +151 -78
- package/src/core/tracker.ts +306 -94
- package/src/index.ts +2 -1
- package/src/types/index.ts +13 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# @ftschopp/dynatable-migrations [1.2.0](https://github.com/ftschopp/dynatable/compare/@ftschopp/dynatable-migrations@1.1.0...@ftschopp/dynatable-migrations@1.2.0) (2026-03-06)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* add migrations playground ([660acf8](https://github.com/ftschopp/dynatable/commit/660acf84d5ddbedba87b86310b1a9f70886c6fde))
|
|
7
|
+
|
|
1
8
|
# @ftschopp/dynatable-migrations [1.1.0](https://github.com/ftschopp/dynatable/compare/@ftschopp/dynatable-migrations@1.0.0...@ftschopp/dynatable-migrations@1.1.0) (2026-01-20)
|
|
2
9
|
|
|
3
10
|
|
package/README.md
CHANGED
|
@@ -4,13 +4,14 @@ DynamoDB migration tool for single table design with schema versioning.
|
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
7
|
+
- **Single Table Design** - Built specifically for DynamoDB single table design patterns
|
|
8
|
+
- **Semantic Versioning** - Migrations use semver (0.1.0, 0.2.0, 1.0.0) for clear version tracking
|
|
9
|
+
- **Up/Down Migrations** - Support for both applying and rolling back migrations
|
|
10
|
+
- **Migration History** - All migration records stored in your DynamoDB table using Single Table Design
|
|
11
|
+
- **Distributed Locking** - Prevents concurrent migrations with automatic lock expiration
|
|
12
|
+
- **Dry Run Mode** - Preview changes before applying them
|
|
13
|
+
- **TypeScript First** - Full TypeScript support with type safety
|
|
14
|
+
- **CLI Tool** - Easy-to-use command-line interface
|
|
14
15
|
|
|
15
16
|
## Installation
|
|
16
17
|
|
|
@@ -58,10 +59,18 @@ module.exports = {
|
|
|
58
59
|
### 3. Create Migration
|
|
59
60
|
|
|
60
61
|
```bash
|
|
62
|
+
# Create with auto-incremented patch version (default)
|
|
61
63
|
npx dynatable-migrate create add_user_email
|
|
64
|
+
|
|
65
|
+
# Create with specific bump type
|
|
66
|
+
npx dynatable-migrate create add_feature --type minor
|
|
67
|
+
npx dynatable-migrate create breaking_change --type major
|
|
68
|
+
|
|
69
|
+
# Create with explicit version
|
|
70
|
+
npx dynatable-migrate create custom_version --explicit 2.0.0
|
|
62
71
|
```
|
|
63
72
|
|
|
64
|
-
This creates a file like `migrations/
|
|
73
|
+
This creates a file like `migrations/0.1.0_add_user_email.ts`
|
|
65
74
|
|
|
66
75
|
### 4. Edit Migration
|
|
67
76
|
|
|
@@ -69,11 +78,12 @@ This creates a file like `migrations/v0001_add_user_email.ts`
|
|
|
69
78
|
import { Migration } from '@ftschopp/dynatable-migrations';
|
|
70
79
|
|
|
71
80
|
export const migration: Migration = {
|
|
72
|
-
version: '
|
|
81
|
+
version: '0.1.0',
|
|
73
82
|
name: 'add_user_email',
|
|
74
83
|
description: 'Add email field to User entity',
|
|
75
84
|
|
|
76
|
-
async up(
|
|
85
|
+
async up(context) {
|
|
86
|
+
const { client, tableName, dynamodb } = context;
|
|
77
87
|
const { ScanCommand, UpdateCommand } = dynamodb;
|
|
78
88
|
|
|
79
89
|
// Scan all users
|
|
@@ -101,7 +111,8 @@ export const migration: Migration = {
|
|
|
101
111
|
}
|
|
102
112
|
},
|
|
103
113
|
|
|
104
|
-
async down(
|
|
114
|
+
async down(context) {
|
|
115
|
+
const { client, tableName, dynamodb } = context;
|
|
105
116
|
const { ScanCommand, UpdateCommand } = dynamodb;
|
|
106
117
|
|
|
107
118
|
const result = await client.send(
|
|
@@ -128,20 +139,26 @@ export const migration: Migration = {
|
|
|
128
139
|
### 5. Run Migrations
|
|
129
140
|
|
|
130
141
|
```bash
|
|
142
|
+
# Check status
|
|
143
|
+
npx dynatable-migrate status
|
|
144
|
+
|
|
145
|
+
# Preview changes (dry run)
|
|
146
|
+
npx dynatable-migrate up --dry-run
|
|
147
|
+
|
|
131
148
|
# Apply all pending migrations
|
|
132
149
|
npx dynatable-migrate up
|
|
133
150
|
|
|
134
151
|
# Apply only 1 migration
|
|
135
152
|
npx dynatable-migrate up --limit 1
|
|
136
153
|
|
|
137
|
-
# Check status
|
|
138
|
-
npx dynatable-migrate status
|
|
139
|
-
|
|
140
154
|
# Rollback last migration
|
|
141
155
|
npx dynatable-migrate down
|
|
142
156
|
|
|
143
157
|
# Rollback last 2 migrations
|
|
144
158
|
npx dynatable-migrate down --steps 2
|
|
159
|
+
|
|
160
|
+
# Preview rollback
|
|
161
|
+
npx dynatable-migrate down --dry-run
|
|
145
162
|
```
|
|
146
163
|
|
|
147
164
|
## CLI Commands
|
|
@@ -165,6 +182,24 @@ dynatable-migrate create add_user_profile
|
|
|
165
182
|
Options:
|
|
166
183
|
|
|
167
184
|
- `-c, --config <path>` - Custom config file path
|
|
185
|
+
- `-t, --type <type>` - Version bump type: `major`, `minor`, or `patch` (default: patch)
|
|
186
|
+
- `-e, --explicit <version>` - Explicit version (e.g., 2.0.0)
|
|
187
|
+
|
|
188
|
+
Examples:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
# Patch bump: 0.1.0 -> 0.1.1
|
|
192
|
+
dynatable-migrate create fix_typo
|
|
193
|
+
|
|
194
|
+
# Minor bump: 0.1.1 -> 0.2.0
|
|
195
|
+
dynatable-migrate create add_notifications --type minor
|
|
196
|
+
|
|
197
|
+
# Major bump: 0.2.0 -> 1.0.0
|
|
198
|
+
dynatable-migrate create breaking_schema_change --type major
|
|
199
|
+
|
|
200
|
+
# Explicit version
|
|
201
|
+
dynatable-migrate create hotfix --explicit 0.1.2
|
|
202
|
+
```
|
|
168
203
|
|
|
169
204
|
### `up`
|
|
170
205
|
|
|
@@ -178,6 +213,7 @@ Options:
|
|
|
178
213
|
|
|
179
214
|
- `-c, --config <path>` - Custom config file path
|
|
180
215
|
- `-l, --limit <number>` - Limit number of migrations to run
|
|
216
|
+
- `-d, --dry-run` - Preview what would be done without making changes
|
|
181
217
|
|
|
182
218
|
### `down`
|
|
183
219
|
|
|
@@ -191,6 +227,7 @@ Options:
|
|
|
191
227
|
|
|
192
228
|
- `-c, --config <path>` - Custom config file path
|
|
193
229
|
- `-s, --steps <number>` - Number of migrations to rollback (default: 1)
|
|
230
|
+
- `-d, --dry-run` - Preview what would be done without making changes
|
|
194
231
|
|
|
195
232
|
### `status`
|
|
196
233
|
|
|
@@ -213,17 +250,9 @@ All migration tracking happens **within your DynamoDB table** using Single Table
|
|
|
213
250
|
```
|
|
214
251
|
PK SK version status appliedAt
|
|
215
252
|
-----------------------------------------------------------------------
|
|
216
|
-
_SCHEMA#VERSION
|
|
217
|
-
_SCHEMA#VERSION
|
|
218
|
-
_SCHEMA#VERSION#CURRENT _SCHEMA#VERSION
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
A GSI (GSI1) is used to quickly find the current version:
|
|
222
|
-
|
|
223
|
-
```
|
|
224
|
-
GSI1PK GSI1SK
|
|
225
|
-
---------------------------
|
|
226
|
-
_SCHEMA#CURRENT v0002
|
|
253
|
+
_SCHEMA#VERSION 0.1.0 0.1.0 applied 2025-03-29T10:00:00Z
|
|
254
|
+
_SCHEMA#VERSION 0.2.0 0.2.0 applied 2025-03-29T11:00:00Z
|
|
255
|
+
_SCHEMA#VERSION#CURRENT _SCHEMA#VERSION 0.2.0 - 2025-03-29T11:00:00Z
|
|
227
256
|
```
|
|
228
257
|
|
|
229
258
|
### Migration Context
|
|
@@ -236,9 +265,17 @@ interface MigrationContext {
|
|
|
236
265
|
tableName: string; // Your table name
|
|
237
266
|
tracker: MigrationTracker; // Track schema changes
|
|
238
267
|
config: MigrationConfig; // Your config
|
|
268
|
+
dynamodb: DynamoDBCommands; // Pre-imported DynamoDB commands
|
|
239
269
|
}
|
|
240
270
|
```
|
|
241
271
|
|
|
272
|
+
The `dynamodb` object includes all common commands:
|
|
273
|
+
|
|
274
|
+
- `ScanCommand`, `QueryCommand`
|
|
275
|
+
- `GetCommand`, `PutCommand`, `UpdateCommand`, `DeleteCommand`
|
|
276
|
+
- `BatchGetCommand`, `BatchWriteCommand`
|
|
277
|
+
- `TransactWriteCommand`, `TransactGetCommand`
|
|
278
|
+
|
|
242
279
|
### Schema Change Tracking
|
|
243
280
|
|
|
244
281
|
Track what changed in each migration:
|
|
@@ -254,99 +291,6 @@ await tracker.recordSchemaChange({
|
|
|
254
291
|
});
|
|
255
292
|
```
|
|
256
293
|
|
|
257
|
-
## Migration Examples
|
|
258
|
-
|
|
259
|
-
### Add New Entity Type
|
|
260
|
-
|
|
261
|
-
```typescript
|
|
262
|
-
export const migration: Migration = {
|
|
263
|
-
version: 'v0003',
|
|
264
|
-
name: 'add_comment_entity',
|
|
265
|
-
|
|
266
|
-
async up({ client, tableName }) {
|
|
267
|
-
// In Single Table Design, you typically don't need to do anything
|
|
268
|
-
// Just document the schema change
|
|
269
|
-
console.log('Comment entity added to schema');
|
|
270
|
-
},
|
|
271
|
-
|
|
272
|
-
async down({ client, tableName }) {
|
|
273
|
-
// Delete all comments if rolling back
|
|
274
|
-
const { ScanCommand, DeleteCommand } = await import('@aws-sdk/lib-dynamodb');
|
|
275
|
-
|
|
276
|
-
const result = await client.send(
|
|
277
|
-
new ScanCommand({
|
|
278
|
-
TableName: tableName,
|
|
279
|
-
FilterExpression: 'begins_with(PK, :pk)',
|
|
280
|
-
ExpressionAttributeValues: { ':pk': 'COMMENT#' },
|
|
281
|
-
})
|
|
282
|
-
);
|
|
283
|
-
|
|
284
|
-
for (const item of result.Items || []) {
|
|
285
|
-
await client.send(
|
|
286
|
-
new DeleteCommand({
|
|
287
|
-
TableName: tableName,
|
|
288
|
-
Key: { PK: item.PK, SK: item.SK },
|
|
289
|
-
})
|
|
290
|
-
);
|
|
291
|
-
}
|
|
292
|
-
},
|
|
293
|
-
};
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
### Change Key Structure
|
|
297
|
-
|
|
298
|
-
```typescript
|
|
299
|
-
export const migration: Migration = {
|
|
300
|
-
version: 'v0004',
|
|
301
|
-
name: 'change_photo_sort_key',
|
|
302
|
-
|
|
303
|
-
async up({ client, tableName }) {
|
|
304
|
-
// Change from SK: "PHOTO#${id}" to SK: "PHOTO#${timestamp}#${id}"
|
|
305
|
-
const { ScanCommand, TransactWriteCommand } = await import('@aws-sdk/lib-dynamodb');
|
|
306
|
-
|
|
307
|
-
const result = await client.send(
|
|
308
|
-
new ScanCommand({
|
|
309
|
-
TableName: tableName,
|
|
310
|
-
FilterExpression: 'begins_with(SK, :sk)',
|
|
311
|
-
ExpressionAttributeValues: { ':sk': 'PHOTO#' },
|
|
312
|
-
})
|
|
313
|
-
);
|
|
314
|
-
|
|
315
|
-
for (const photo of result.Items || []) {
|
|
316
|
-
const timestamp = new Date(photo.createdAt).getTime();
|
|
317
|
-
const photoId = photo.SK.replace('PHOTO#', '');
|
|
318
|
-
|
|
319
|
-
await client.send(
|
|
320
|
-
new TransactWriteCommand({
|
|
321
|
-
TransactItems: [
|
|
322
|
-
{
|
|
323
|
-
Delete: {
|
|
324
|
-
TableName: tableName,
|
|
325
|
-
Key: { PK: photo.PK, SK: photo.SK },
|
|
326
|
-
},
|
|
327
|
-
},
|
|
328
|
-
{
|
|
329
|
-
Put: {
|
|
330
|
-
TableName: tableName,
|
|
331
|
-
Item: {
|
|
332
|
-
...photo,
|
|
333
|
-
SK: `PHOTO#${timestamp}#${photoId}`,
|
|
334
|
-
},
|
|
335
|
-
},
|
|
336
|
-
},
|
|
337
|
-
],
|
|
338
|
-
})
|
|
339
|
-
);
|
|
340
|
-
}
|
|
341
|
-
},
|
|
342
|
-
|
|
343
|
-
async down({ client, tableName }) {
|
|
344
|
-
// Reverse the change
|
|
345
|
-
// ... similar logic but reverse
|
|
346
|
-
},
|
|
347
|
-
};
|
|
348
|
-
```
|
|
349
|
-
|
|
350
294
|
## Configuration
|
|
351
295
|
|
|
352
296
|
### Config File Options
|
|
@@ -372,7 +316,7 @@ interface MigrationConfig {
|
|
|
372
316
|
// Optional: Tracking prefix (default: _SCHEMA#VERSION)
|
|
373
317
|
trackingPrefix?: string;
|
|
374
318
|
|
|
375
|
-
// Optional: GSI name (default: GSI1)
|
|
319
|
+
// Optional: GSI name for queries (default: GSI1)
|
|
376
320
|
gsi1Name?: string;
|
|
377
321
|
}
|
|
378
322
|
```
|
|
@@ -382,39 +326,63 @@ interface MigrationConfig {
|
|
|
382
326
|
You can also use the migration runner programmatically:
|
|
383
327
|
|
|
384
328
|
```typescript
|
|
385
|
-
import {
|
|
386
|
-
|
|
387
|
-
|
|
329
|
+
import {
|
|
330
|
+
MigrationRunner,
|
|
331
|
+
loadConfig,
|
|
332
|
+
createDynamoDBClient,
|
|
333
|
+
} from '@ftschopp/dynatable-migrations';
|
|
388
334
|
|
|
389
335
|
const config = await loadConfig();
|
|
390
|
-
const client =
|
|
391
|
-
new DynamoDBClient({
|
|
392
|
-
region: config.client.region,
|
|
393
|
-
endpoint: config.client.endpoint,
|
|
394
|
-
})
|
|
395
|
-
);
|
|
336
|
+
const client = createDynamoDBClient(config);
|
|
396
337
|
|
|
397
338
|
const runner = new MigrationRunner(client, config);
|
|
398
339
|
|
|
399
340
|
// Run migrations
|
|
400
341
|
await runner.up();
|
|
401
342
|
|
|
343
|
+
// Run with options
|
|
344
|
+
await runner.up({ limit: 1, dryRun: true });
|
|
345
|
+
|
|
402
346
|
// Get status
|
|
403
347
|
const status = await runner.status();
|
|
404
348
|
|
|
405
349
|
// Rollback
|
|
406
|
-
await runner.down(1);
|
|
350
|
+
await runner.down({ steps: 1 });
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### Available Exports
|
|
354
|
+
|
|
355
|
+
```typescript
|
|
356
|
+
// Core classes
|
|
357
|
+
export { MigrationRunner } from './core/runner';
|
|
358
|
+
export { MigrationLoader } from './core/loader';
|
|
359
|
+
export { DynamoDBMigrationTracker } from './core/tracker';
|
|
360
|
+
|
|
361
|
+
// Config
|
|
362
|
+
export { loadConfig, ConfigLoader } from './core/config';
|
|
363
|
+
export { createDynamoDBClient } from './core/client';
|
|
364
|
+
|
|
365
|
+
// Commands (for programmatic use)
|
|
366
|
+
export { createMigration } from './commands/create';
|
|
367
|
+
export { runMigrations } from './commands/up';
|
|
368
|
+
export { rollbackMigrations } from './commands/down';
|
|
369
|
+
export { showStatus } from './commands/status';
|
|
370
|
+
export { initProject } from './commands/init';
|
|
371
|
+
|
|
372
|
+
// Types
|
|
373
|
+
export * from './types';
|
|
407
374
|
```
|
|
408
375
|
|
|
409
376
|
## Best Practices
|
|
410
377
|
|
|
411
378
|
1. **Always write down() functions** - Even if you think you won't need to rollback
|
|
412
379
|
2. **Test migrations locally first** - Use DynamoDB Local
|
|
413
|
-
3. **
|
|
414
|
-
4. **
|
|
415
|
-
5. **
|
|
416
|
-
6. **
|
|
417
|
-
7. **
|
|
380
|
+
3. **Use dry-run mode** - Preview changes before applying: `dynatable-migrate up --dry-run`
|
|
381
|
+
4. **Backup before running** - Use DynamoDB point-in-time recovery
|
|
382
|
+
5. **One change per migration** - Keep migrations focused
|
|
383
|
+
6. **Don't modify applied migrations** - Create a new migration instead
|
|
384
|
+
7. **Use transactions** - For multi-step changes that must be atomic
|
|
385
|
+
8. **Use semantic versioning** - major for breaking changes, minor for features, patch for fixes
|
|
418
386
|
|
|
419
387
|
## License
|
|
420
388
|
|