@ftschopp/dynatable-migrations 1.1.0 → 1.2.1

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.
Files changed (49) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +98 -134
  3. package/USAGE.md +195 -60
  4. package/dist/cli.js +7 -3
  5. package/dist/cli.js.map +1 -1
  6. package/dist/commands/down.d.ts +1 -1
  7. package/dist/commands/down.d.ts.map +1 -1
  8. package/dist/commands/down.js +5 -20
  9. package/dist/commands/down.js.map +1 -1
  10. package/dist/commands/status.d.ts.map +1 -1
  11. package/dist/commands/status.js +2 -17
  12. package/dist/commands/status.js.map +1 -1
  13. package/dist/commands/up.d.ts +1 -1
  14. package/dist/commands/up.d.ts.map +1 -1
  15. package/dist/commands/up.js +5 -20
  16. package/dist/commands/up.js.map +1 -1
  17. package/dist/core/client.d.ts +7 -0
  18. package/dist/core/client.d.ts.map +1 -0
  19. package/dist/core/client.js +25 -0
  20. package/dist/core/client.js.map +1 -0
  21. package/dist/core/loader.d.ts +8 -0
  22. package/dist/core/loader.d.ts.map +1 -1
  23. package/dist/core/loader.js +76 -43
  24. package/dist/core/loader.js.map +1 -1
  25. package/dist/core/runner.d.ts +6 -2
  26. package/dist/core/runner.d.ts.map +1 -1
  27. package/dist/core/runner.js +124 -67
  28. package/dist/core/runner.js.map +1 -1
  29. package/dist/core/tracker.d.ts +20 -1
  30. package/dist/core/tracker.d.ts.map +1 -1
  31. package/dist/core/tracker.js +273 -83
  32. package/dist/core/tracker.js.map +1 -1
  33. package/dist/index.d.ts +2 -1
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +3 -1
  36. package/dist/index.js.map +1 -1
  37. package/dist/types/index.d.ts +10 -1
  38. package/dist/types/index.d.ts.map +1 -1
  39. package/package.json +1 -3
  40. package/src/cli.ts +8 -3
  41. package/src/commands/down.ts +6 -22
  42. package/src/commands/status.ts +2 -19
  43. package/src/commands/up.ts +9 -22
  44. package/src/core/client.ts +24 -0
  45. package/src/core/loader.ts +86 -46
  46. package/src/core/runner.ts +149 -78
  47. package/src/core/tracker.ts +305 -94
  48. package/src/index.ts +2 -1
  49. package/src/types/index.ts +13 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## @ftschopp/dynatable-migrations [1.2.1](https://github.com/ftschopp/dynatable/compare/@ftschopp/dynatable-migrations@1.2.0...@ftschopp/dynatable-migrations@1.2.1) (2026-04-29)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * get keyname for attribute index ([5bd47c3](https://github.com/ftschopp/dynatable/commit/5bd47c38585c78153ff51f5e457777e928d6e667))
7
+
8
+ # @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)
9
+
10
+
11
+ ### Features
12
+
13
+ * add migrations playground ([660acf8](https://github.com/ftschopp/dynatable/commit/660acf84d5ddbedba87b86310b1a9f70886c6fde))
14
+
1
15
  # @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
16
 
3
17
 
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
- - 🚀 **Single Table Design** - Built specifically for DynamoDB single table design patterns
8
- - 📊 **Schema Versioning** - Track schema evolution over time within your DynamoDB table
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
- - 🎯 **TypeScript First** - Full TypeScript support with type safety
12
- - 🛠️ **CLI Tool** - Easy-to-use command-line interface with beautiful UI (ora, chalk)
13
- - 📦 **Minimal Dependencies** - Only requires AWS SDK and CLI tools (commander, ora, chalk)
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/v0001_add_user_email.ts`
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: 'v0001',
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({ client, tableName, dynamodb }) {
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({ client, tableName, dynamodb }) {
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 v0001 v0001 applied 2025-03-29T10:00:00Z
217
- _SCHEMA#VERSION v0002 v0002 applied 2025-03-29T11:00:00Z
218
- _SCHEMA#VERSION#CURRENT _SCHEMA#VERSION v0002 - 2025-03-29T11:00:00Z
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,59 @@ interface MigrationConfig {
382
326
  You can also use the migration runner programmatically:
383
327
 
384
328
  ```typescript
385
- import { MigrationRunner, loadConfig } from '@ftschopp/dynatable-migrations';
386
- import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
387
- import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
329
+ import { MigrationRunner, loadConfig, createDynamoDBClient } from '@ftschopp/dynatable-migrations';
388
330
 
389
331
  const config = await loadConfig();
390
- const client = DynamoDBDocumentClient.from(
391
- new DynamoDBClient({
392
- region: config.client.region,
393
- endpoint: config.client.endpoint,
394
- })
395
- );
332
+ const client = createDynamoDBClient(config);
396
333
 
397
334
  const runner = new MigrationRunner(client, config);
398
335
 
399
336
  // Run migrations
400
337
  await runner.up();
401
338
 
339
+ // Run with options
340
+ await runner.up({ limit: 1, dryRun: true });
341
+
402
342
  // Get status
403
343
  const status = await runner.status();
404
344
 
405
345
  // Rollback
406
- await runner.down(1);
346
+ await runner.down({ steps: 1 });
347
+ ```
348
+
349
+ ### Available Exports
350
+
351
+ ```typescript
352
+ // Core classes
353
+ export { MigrationRunner } from './core/runner';
354
+ export { MigrationLoader } from './core/loader';
355
+ export { DynamoDBMigrationTracker } from './core/tracker';
356
+
357
+ // Config
358
+ export { loadConfig, ConfigLoader } from './core/config';
359
+ export { createDynamoDBClient } from './core/client';
360
+
361
+ // Commands (for programmatic use)
362
+ export { createMigration } from './commands/create';
363
+ export { runMigrations } from './commands/up';
364
+ export { rollbackMigrations } from './commands/down';
365
+ export { showStatus } from './commands/status';
366
+ export { initProject } from './commands/init';
367
+
368
+ // Types
369
+ export * from './types';
407
370
  ```
408
371
 
409
372
  ## Best Practices
410
373
 
411
374
  1. **Always write down() functions** - Even if you think you won't need to rollback
412
375
  2. **Test migrations locally first** - Use DynamoDB Local
413
- 3. **Backup before running** - Use DynamoDB point-in-time recovery
414
- 4. **One change per migration** - Keep migrations focused
415
- 5. **Don't modify applied migrations** - Create a new migration instead
416
- 6. **Use transactions** - For multi-step changes that must be atomic
417
- 7. **Document schema changes** - Use the schema snapshot field
376
+ 3. **Use dry-run mode** - Preview changes before applying: `dynatable-migrate up --dry-run`
377
+ 4. **Backup before running** - Use DynamoDB point-in-time recovery
378
+ 5. **One change per migration** - Keep migrations focused
379
+ 6. **Don't modify applied migrations** - Create a new migration instead
380
+ 7. **Use transactions** - For multi-step changes that must be atomic
381
+ 8. **Use semantic versioning** - major for breaking changes, minor for features, patch for fixes
418
382
 
419
383
  ## License
420
384