@lenne.tech/nest-server 11.3.0 → 11.4.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/bin/migrate.js +40 -0
- package/dist/core/modules/migrate/cli/migrate-cli.d.ts +3 -0
- package/dist/core/modules/migrate/cli/migrate-cli.js +221 -0
- package/dist/core/modules/migrate/cli/migrate-cli.js.map +1 -0
- package/dist/core/modules/migrate/helpers/migration.helper.d.ts +12 -0
- package/dist/core/modules/migrate/helpers/migration.helper.js +57 -0
- package/dist/core/modules/migrate/helpers/migration.helper.js.map +1 -0
- package/dist/core/modules/migrate/helpers/ts-compiler.d.ts +2 -0
- package/dist/core/modules/migrate/helpers/ts-compiler.js +3 -0
- package/dist/core/modules/migrate/helpers/ts-compiler.js.map +1 -0
- package/dist/core/modules/migrate/index.d.ts +4 -0
- package/dist/core/modules/migrate/index.js +21 -0
- package/dist/core/modules/migrate/index.js.map +1 -0
- package/dist/core/modules/migrate/migration-runner.d.ts +26 -0
- package/dist/core/modules/migrate/migration-runner.js +124 -0
- package/dist/core/modules/migrate/migration-runner.js.map +1 -0
- package/dist/core/modules/migrate/mongo-state-store.d.ts +30 -0
- package/dist/core/modules/migrate/mongo-state-store.js +105 -0
- package/dist/core/modules/migrate/mongo-state-store.js.map +1 -0
- package/dist/core/modules/migrate/templates/migration-with-helper.template.d.ts +2 -0
- package/dist/core/modules/migrate/templates/migration-with-helper.template.js +10 -0
- package/dist/core/modules/migrate/templates/migration-with-helper.template.js.map +1 -0
- package/dist/core/modules/migrate/templates/migration.template.d.ts +2 -0
- package/dist/core/modules/migrate/templates/migration.template.js +15 -0
- package/dist/core/modules/migrate/templates/migration.template.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +7 -2
- package/src/core/modules/migrate/MIGRATION_FROM_NODEPIT.md +219 -0
- package/src/core/modules/migrate/README.md +452 -0
- package/src/core/modules/migrate/cli/migrate-cli.ts +319 -0
- package/src/core/modules/migrate/helpers/migration.helper.ts +117 -0
- package/src/core/modules/migrate/helpers/ts-compiler.js +14 -0
- package/src/core/modules/migrate/index.ts +41 -0
- package/src/core/modules/migrate/migration-runner.ts +230 -0
- package/src/core/modules/migrate/mongo-state-store.ts +283 -0
- package/src/core/modules/migrate/templates/migration-with-helper.template.ts +72 -0
- package/src/core/modules/migrate/templates/migration.template.ts +59 -0
- package/src/index.ts +9 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lenne.tech/nest-server",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.4.0",
|
|
4
4
|
"description": "Modern, fast, powerful Node.js web framework in TypeScript based on Nest with a GraphQL API and a connection to MongoDB (or other databases).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"node",
|
|
@@ -182,9 +182,14 @@
|
|
|
182
182
|
},
|
|
183
183
|
"main": "dist/index.js",
|
|
184
184
|
"types": "dist/index.d.ts",
|
|
185
|
+
"bin": {
|
|
186
|
+
"nest-migrate": "./bin/migrate.js",
|
|
187
|
+
"migrate": "./bin/migrate.js"
|
|
188
|
+
},
|
|
185
189
|
"files": [
|
|
186
190
|
"dist/**/*",
|
|
187
|
-
"src/**/*"
|
|
191
|
+
"src/**/*",
|
|
192
|
+
"bin/**/*"
|
|
188
193
|
],
|
|
189
194
|
"watch": {
|
|
190
195
|
"build:dev": "src"
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# Migration from @nodepit/migrate-state-store-mongodb
|
|
2
|
+
|
|
3
|
+
This guide provides step-by-step instructions to migrate from `@nodepit/migrate-state-store-mongodb` to the built-in nest-server migration system.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
Current state of nest-server-starter projects:
|
|
8
|
+
- Using `@nodepit/migrate-state-store-mongodb` for state storage
|
|
9
|
+
- Using external `migrate` package for CLI
|
|
10
|
+
- Custom migration utilities in `migrations-utils/`
|
|
11
|
+
|
|
12
|
+
## Migration Steps
|
|
13
|
+
|
|
14
|
+
### Step 1: Update Dependencies
|
|
15
|
+
|
|
16
|
+
**File:** `package.json`
|
|
17
|
+
|
|
18
|
+
Remove old migration packages:
|
|
19
|
+
```bash
|
|
20
|
+
npm uninstall migrate @nodepit/migrate-state-store-mongodb ts-migrate-mongoose
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Ensure latest nest-server is installed:
|
|
24
|
+
```bash
|
|
25
|
+
npm install @lenne.tech/nest-server@latest
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Step 2: Update Migration State Store
|
|
29
|
+
|
|
30
|
+
**File:** `migrations-utils/migrate.js`
|
|
31
|
+
|
|
32
|
+
**Before:**
|
|
33
|
+
```javascript
|
|
34
|
+
import config from '../src/config.env';
|
|
35
|
+
const migrate = require('migrate');
|
|
36
|
+
const { MongoStateStore } = require('@nodepit/migrate-state-store-mongodb');
|
|
37
|
+
|
|
38
|
+
const MONGO_URL = config.mongoose.uri;
|
|
39
|
+
const COLLECTION_NAME = 'migrations';
|
|
40
|
+
|
|
41
|
+
module.exports = class MyMongoStateStore extends MongoStateStore {
|
|
42
|
+
constructor() {
|
|
43
|
+
super({ uri: MONGO_URL, collectionName: COLLECTION_NAME });
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**After:**
|
|
49
|
+
```javascript
|
|
50
|
+
const { createMigrationStore } = require('@lenne.tech/nest-server');
|
|
51
|
+
const config = require('../src/config.env');
|
|
52
|
+
|
|
53
|
+
module.exports = createMigrationStore(
|
|
54
|
+
config.default.mongoose.uri,
|
|
55
|
+
'migrations' // optional, default is 'migrations'
|
|
56
|
+
);
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Step 3: Update Database Helper
|
|
60
|
+
|
|
61
|
+
**File:** `migrations-utils/db.ts`
|
|
62
|
+
|
|
63
|
+
**Before:**
|
|
64
|
+
```typescript
|
|
65
|
+
import * as fs from 'fs';
|
|
66
|
+
import { GridFSBucket, MongoClient, ObjectId } from 'mongodb';
|
|
67
|
+
import * as path from 'path';
|
|
68
|
+
import config from '../src/config.env';
|
|
69
|
+
|
|
70
|
+
const MONGO_URL = config.mongoose.uri;
|
|
71
|
+
|
|
72
|
+
export const getDb = async () => {
|
|
73
|
+
const client: MongoClient = await MongoClient.connect(MONGO_URL);
|
|
74
|
+
return client.db();
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export const uploadFile = async (
|
|
78
|
+
relativePath,
|
|
79
|
+
options?: { bucketName?: string; filename?: string },
|
|
80
|
+
): Promise<ObjectId> => {
|
|
81
|
+
// ... implementation
|
|
82
|
+
};
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**After:**
|
|
86
|
+
```typescript
|
|
87
|
+
import config from '../src/config.env';
|
|
88
|
+
import { getDb as getDbHelper, uploadFileToGridFS } from '@lenne.tech/nest-server';
|
|
89
|
+
import { Db, ObjectId } from 'mongodb';
|
|
90
|
+
|
|
91
|
+
const MONGO_URL = config.mongoose.uri;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Get database connection
|
|
95
|
+
*/
|
|
96
|
+
export const getDb = async (): Promise<Db> => {
|
|
97
|
+
return getDbHelper(MONGO_URL);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Upload file to GridFS
|
|
102
|
+
*/
|
|
103
|
+
export const uploadFile = async (
|
|
104
|
+
relativePath: string,
|
|
105
|
+
options?: { bucketName?: string; filename?: string }
|
|
106
|
+
): Promise<ObjectId> => {
|
|
107
|
+
return uploadFileToGridFS(MONGO_URL, relativePath, options);
|
|
108
|
+
};
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Step 4: Verify package.json Scripts
|
|
112
|
+
|
|
113
|
+
**File:** `package.json`
|
|
114
|
+
|
|
115
|
+
Scripts should remain unchanged - they will work with the built-in CLI:
|
|
116
|
+
|
|
117
|
+
```json
|
|
118
|
+
{
|
|
119
|
+
"scripts": {
|
|
120
|
+
"migrate:create": "migrate create --template-file ./migrations-utils/template.ts --migrations-dir=\"./migrations\" --compiler=\"ts:./migrations-utils/ts-compiler.js\"",
|
|
121
|
+
"migrate:up": "migrate --store=./migrations-utils/migrate.js --migrations-dir=\"./migrations\" --compiler=\"ts:./migrations-utils/ts-compiler.js\" up",
|
|
122
|
+
"migrate:develop:up": "NODE_ENV=develop migrate --store=./migrations-utils/migrate.js --migrations-dir=\"./migrations\" --compiler=\"ts:./migrations-utils/ts-compiler.js\" up",
|
|
123
|
+
"migrate:test:up": "NODE_ENV=test migrate --store=./migrations-utils/migrate.js --migrations-dir=\"./migrations\" --compiler=\"ts:./migrations-utils/ts-compiler.js\" up",
|
|
124
|
+
"migrate:preview:up": "NODE_ENV=preview migrate --store=./migrations-utils/migrate.js --migrations-dir=\"./migrations\" --compiler=\"ts:./migrations-utils/ts-compiler.js\" up",
|
|
125
|
+
"migrate:prod:up": "NODE_ENV=production migrate --store=./migrations-utils/migrate.js --migrations-dir=\"./migrations\" --compiler=\"ts:./migrations-utils/ts-compiler.js\" up"
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Note: The `migrate` command now comes from `@lenne.tech/nest-server` - no external package needed.
|
|
131
|
+
|
|
132
|
+
### Step 5: Test Migration
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
# Install dependencies
|
|
136
|
+
npm install
|
|
137
|
+
|
|
138
|
+
# Test migration creation
|
|
139
|
+
npm run migrate:create -- test-migration
|
|
140
|
+
|
|
141
|
+
# Test migration execution (if safe in current environment)
|
|
142
|
+
npm run migrate:up
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Verification Checklist
|
|
146
|
+
|
|
147
|
+
- [ ] `migrate` package removed from package.json
|
|
148
|
+
- [ ] `@nodepit/migrate-state-store-mongodb` removed from package.json
|
|
149
|
+
- [ ] `ts-migrate-mongoose` removed from package.json
|
|
150
|
+
- [ ] `migrations-utils/migrate.js` updated to use `createMigrationStore`
|
|
151
|
+
- [ ] `migrations-utils/db.ts` updated to use nest-server helpers
|
|
152
|
+
- [ ] `npm install` completed successfully
|
|
153
|
+
- [ ] `npm run migrate:create -- test` works
|
|
154
|
+
- [ ] Existing migrations still in database (no data loss)
|
|
155
|
+
|
|
156
|
+
## What Stays the Same
|
|
157
|
+
|
|
158
|
+
- ✅ All migration files in `migrations/` folder
|
|
159
|
+
- ✅ All migration data in MongoDB
|
|
160
|
+
- ✅ All npm scripts in package.json
|
|
161
|
+
- ✅ Migration file format (up/down functions)
|
|
162
|
+
- ✅ Template files (if using custom templates)
|
|
163
|
+
|
|
164
|
+
## What Changes
|
|
165
|
+
|
|
166
|
+
- ✅ `migrations-utils/migrate.js` - simplified (3 lines)
|
|
167
|
+
- ✅ `migrations-utils/db.ts` - uses nest-server helpers
|
|
168
|
+
- ✅ package.json dependencies - 2-3 packages removed
|
|
169
|
+
- ✅ CLI comes from nest-server instead of external package
|
|
170
|
+
|
|
171
|
+
## Rollback (if needed)
|
|
172
|
+
|
|
173
|
+
If you need to rollback:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
# Reinstall old packages
|
|
177
|
+
npm install --save-dev migrate @nodepit/migrate-state-store-mongodb
|
|
178
|
+
|
|
179
|
+
# Revert migrations-utils/migrate.js to old version from git
|
|
180
|
+
git checkout migrations-utils/migrate.js
|
|
181
|
+
|
|
182
|
+
# Revert migrations-utils/db.ts to old version from git
|
|
183
|
+
git checkout migrations-utils/db.ts
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## Benefits After Migration
|
|
187
|
+
|
|
188
|
+
1. **One less dependency** - No external `migrate` package needed
|
|
189
|
+
2. **Simplified code** - ~90% less boilerplate in migrations-utils
|
|
190
|
+
3. **Better TypeScript** - Native TypeScript implementation
|
|
191
|
+
4. **MongoDB 7.x support** - Works with latest MongoDB versions
|
|
192
|
+
5. **Central maintenance** - Updates come with nest-server
|
|
193
|
+
|
|
194
|
+
## Support
|
|
195
|
+
|
|
196
|
+
If issues occur during migration:
|
|
197
|
+
- Check that `@lenne.tech/nest-server` is at version 11.3.0 or higher
|
|
198
|
+
- Verify `ts-node` is installed as devDependency
|
|
199
|
+
- Ensure `migrations-utils/migrate.js` exports the state store correctly
|
|
200
|
+
- Test with `migrate --help` to verify CLI is available
|
|
201
|
+
|
|
202
|
+
## File Structure After Migration
|
|
203
|
+
|
|
204
|
+
```
|
|
205
|
+
project-root/
|
|
206
|
+
├── migrations/ # Unchanged
|
|
207
|
+
│ └── TIMESTAMP-*.ts # Your migrations
|
|
208
|
+
├── migrations-utils/
|
|
209
|
+
│ ├── migrate.js # Updated (3 lines)
|
|
210
|
+
│ ├── db.ts # Updated (uses nest-server helpers)
|
|
211
|
+
│ ├── template.ts # Unchanged (optional)
|
|
212
|
+
│ └── ts-compiler.js # Unchanged (optional, can be removed)
|
|
213
|
+
└── package.json # Dependencies removed
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Note: `ts-compiler.js` can optionally be removed and replaced with:
|
|
217
|
+
```
|
|
218
|
+
--compiler="ts:./node_modules/@lenne.tech/nest-server/dist/core/modules/migrate/helpers/ts-compiler.js"
|
|
219
|
+
```
|
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
# MongoDB State Store for Migrations
|
|
2
|
+
|
|
3
|
+
This module provides a MongoDB-based state storage for migration frameworks, offering a modern TypeScript implementation that is fully compatible with `@nodepit/migrate-state-store-mongodb`.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- ✅ **Full Backward Compatibility**: Drop-in replacement for `@nodepit/migrate-state-store-mongodb`
|
|
8
|
+
- ✅ **MongoDB 6+ Support**: Works with MongoDB 6.x, 7.x and newer versions
|
|
9
|
+
- ✅ **Modern TypeScript**: Written in modern TypeScript with full type safety
|
|
10
|
+
- ✅ **Cluster Support**: Built-in locking mechanism for clustered environments
|
|
11
|
+
- ✅ **Dual API**: Supports both callback-based and Promise-based APIs
|
|
12
|
+
- ✅ **No External Dependencies**: Uses only MongoDB driver already included in nest-server
|
|
13
|
+
- ✅ **Fully Tested**: Comprehensive E2E test suite with 25+ test cases
|
|
14
|
+
|
|
15
|
+
## Migration from @nodepit/migrate-state-store-mongodb
|
|
16
|
+
|
|
17
|
+
If you're currently using `@nodepit/migrate-state-store-mongodb`, you can migrate seamlessly:
|
|
18
|
+
|
|
19
|
+
### 1. Remove the old package
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm uninstall @nodepit/migrate-state-store-mongodb
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### 2. Update your imports
|
|
26
|
+
|
|
27
|
+
**Before:**
|
|
28
|
+
```typescript
|
|
29
|
+
import { MongoStateStore, synchronizedUp } from '@nodepit/migrate-state-store-mongodb';
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**After:**
|
|
33
|
+
```typescript
|
|
34
|
+
import { MongoStateStore, synchronizedUp } from '@lenne.tech/nest-server';
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
That's it! Your existing migrations will continue to work without any changes.
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
If you're using `@lenne.tech/nest-server`, the migration functionality is already included:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm install @lenne.tech/nest-server
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Usage
|
|
48
|
+
|
|
49
|
+
### Basic Usage
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
import { MongoStateStore } from '@lenne.tech/nest-server';
|
|
53
|
+
|
|
54
|
+
// Simple string URI
|
|
55
|
+
const stateStore = new MongoStateStore('mongodb://localhost/mydb');
|
|
56
|
+
|
|
57
|
+
// Or with options
|
|
58
|
+
const stateStore = new MongoStateStore({
|
|
59
|
+
uri: 'mongodb://localhost/mydb',
|
|
60
|
+
collectionName: 'custom_migrations', // optional, defaults to 'migrations'
|
|
61
|
+
lockCollectionName: 'migration_lock' // optional, for cluster environments
|
|
62
|
+
});
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### With Callback API
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
// Load migration state
|
|
69
|
+
stateStore.load((err, state) => {
|
|
70
|
+
if (err) {
|
|
71
|
+
console.error('Failed to load migration state:', err);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
console.log('Current migration state:', state);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Save migration state
|
|
78
|
+
const migrationState = {
|
|
79
|
+
migrations: [
|
|
80
|
+
{ title: '1234-my-migration.js', timestamp: Date.now() }
|
|
81
|
+
],
|
|
82
|
+
lastRun: '1234-my-migration.js'
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
stateStore.save(migrationState, (err) => {
|
|
86
|
+
if (err) {
|
|
87
|
+
console.error('Failed to save migration state:', err);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
console.log('Migration state saved successfully');
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### With Promise/Async API
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
// Load migration state
|
|
98
|
+
try {
|
|
99
|
+
const state = await stateStore.loadAsync();
|
|
100
|
+
console.log('Current migration state:', state);
|
|
101
|
+
} catch (err) {
|
|
102
|
+
console.error('Failed to load migration state:', err);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Save migration state
|
|
106
|
+
try {
|
|
107
|
+
await stateStore.saveAsync(migrationState);
|
|
108
|
+
console.log('Migration state saved successfully');
|
|
109
|
+
} catch (err) {
|
|
110
|
+
console.error('Failed to save migration state:', err);
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Synchronized Migrations (Cluster Support)
|
|
115
|
+
|
|
116
|
+
For clustered environments where multiple instances might try to run migrations simultaneously:
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
import { MongoStateStore, synchronizedMigration, synchronizedUp } from '@lenne.tech/nest-server';
|
|
120
|
+
|
|
121
|
+
const migrationOptions = {
|
|
122
|
+
stateStore: new MongoStateStore({
|
|
123
|
+
uri: 'mongodb://localhost/mydb',
|
|
124
|
+
lockCollectionName: 'migration_lock' // Required for synchronized migrations
|
|
125
|
+
}),
|
|
126
|
+
migrationsDirectory: './migrations'
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
// Custom migration logic
|
|
130
|
+
await synchronizedMigration(migrationOptions, async (migrationSet) => {
|
|
131
|
+
// Only one instance at a time will execute this code
|
|
132
|
+
console.log('Running migrations...');
|
|
133
|
+
await promisify(migrationSet.up).call(migrationSet);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// Or use the convenience function to run all pending migrations
|
|
137
|
+
await synchronizedUp(migrationOptions);
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## API Reference
|
|
141
|
+
|
|
142
|
+
### MongoStateStore
|
|
143
|
+
|
|
144
|
+
#### Constructor
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
new MongoStateStore(options: string | MongoStateStoreOptions)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**Parameters:**
|
|
151
|
+
- `options`: MongoDB URI string or configuration object
|
|
152
|
+
- `uri`: MongoDB connection URI (required)
|
|
153
|
+
- `collectionName`: Name of the collection to store migration state (default: 'migrations')
|
|
154
|
+
- `lockCollectionName`: Collection name for locking mechanism (optional)
|
|
155
|
+
|
|
156
|
+
#### Methods
|
|
157
|
+
|
|
158
|
+
##### load(callback)
|
|
159
|
+
|
|
160
|
+
Loads the migration state from MongoDB (callback-based).
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
load(fn: (err?: Error, set?: MigrationSet) => void): void
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
##### loadAsync()
|
|
167
|
+
|
|
168
|
+
Loads the migration state from MongoDB (promise-based).
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
loadAsync(): Promise<MigrationSet>
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
##### save(set, callback)
|
|
175
|
+
|
|
176
|
+
Saves the migration state to MongoDB (callback-based).
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
save(set: MigrationSet, fn: (err?: Error) => void): void
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
##### saveAsync(set)
|
|
183
|
+
|
|
184
|
+
Saves the migration state to MongoDB (promise-based).
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
saveAsync(set: MigrationSet): Promise<void>
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Helper Functions
|
|
191
|
+
|
|
192
|
+
#### synchronizedMigration
|
|
193
|
+
|
|
194
|
+
Wraps migrations with a lock to prevent simultaneous execution in clustered environments.
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
async function synchronizedMigration(
|
|
198
|
+
opts: MigrationOptions,
|
|
199
|
+
callback: (set: MigrationSet) => Promise<void>
|
|
200
|
+
): Promise<void>
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
#### synchronizedUp
|
|
204
|
+
|
|
205
|
+
Convenience function that executes all pending migrations in a synchronized manner.
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
async function synchronizedUp(opts: MigrationOptions): Promise<void>
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## How It Works
|
|
212
|
+
|
|
213
|
+
### State Storage
|
|
214
|
+
|
|
215
|
+
The migration state is stored in a MongoDB collection (default: `migrations`) as a single document containing:
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
{
|
|
219
|
+
migrations: [
|
|
220
|
+
{
|
|
221
|
+
title: 'migration-name.js',
|
|
222
|
+
timestamp: 1234567890,
|
|
223
|
+
description: 'Migration description'
|
|
224
|
+
}
|
|
225
|
+
],
|
|
226
|
+
lastRun: 'last-migration-name.js'
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Locking Mechanism
|
|
231
|
+
|
|
232
|
+
When using `synchronizedMigration` or `synchronizedUp`:
|
|
233
|
+
|
|
234
|
+
1. A unique index is created on the lock collection
|
|
235
|
+
2. The migration process attempts to insert a lock document
|
|
236
|
+
3. Only one instance can successfully insert (others wait)
|
|
237
|
+
4. After migration completes, the lock is released
|
|
238
|
+
5. Waiting instances can then proceed
|
|
239
|
+
|
|
240
|
+
This ensures that in a cluster with multiple nodes, migrations run on only one machine at a time.
|
|
241
|
+
|
|
242
|
+
## Examples
|
|
243
|
+
|
|
244
|
+
### Example: Migration File
|
|
245
|
+
|
|
246
|
+
Create a migration file in your migrations directory:
|
|
247
|
+
|
|
248
|
+
```javascript
|
|
249
|
+
// migrations/1234567890-add-user-email.js
|
|
250
|
+
|
|
251
|
+
'use strict';
|
|
252
|
+
|
|
253
|
+
const { MongoClient } = require('mongodb');
|
|
254
|
+
const { promisify } = require('util');
|
|
255
|
+
const { callbackify } = require('util');
|
|
256
|
+
|
|
257
|
+
const mongoUrl = process.env.MONGODB_URL;
|
|
258
|
+
|
|
259
|
+
module.exports.up = function (next) {
|
|
260
|
+
callbackify(async () => {
|
|
261
|
+
const client = await MongoClient.connect(mongoUrl);
|
|
262
|
+
try {
|
|
263
|
+
await client.db().collection('users').updateMany(
|
|
264
|
+
{ email: { $exists: false } },
|
|
265
|
+
{ $set: { email: '' } }
|
|
266
|
+
);
|
|
267
|
+
} finally {
|
|
268
|
+
await client.close();
|
|
269
|
+
}
|
|
270
|
+
})(next);
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
module.exports.down = function (next) {
|
|
274
|
+
callbackify(async () => {
|
|
275
|
+
const client = await MongoClient.connect(mongoUrl);
|
|
276
|
+
try {
|
|
277
|
+
await client.db().collection('users').updateMany(
|
|
278
|
+
{},
|
|
279
|
+
{ $unset: { email: '' } }
|
|
280
|
+
);
|
|
281
|
+
} finally {
|
|
282
|
+
await client.close();
|
|
283
|
+
}
|
|
284
|
+
})(next);
|
|
285
|
+
};
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Example: Running Migrations in Your Application
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
import { MongoStateStore, synchronizedUp } from '@lenne.tech/nest-server';
|
|
292
|
+
import path from 'path';
|
|
293
|
+
|
|
294
|
+
async function runMigrations() {
|
|
295
|
+
const migrationOptions = {
|
|
296
|
+
stateStore: new MongoStateStore({
|
|
297
|
+
uri: process.env.MONGODB_URL || 'mongodb://localhost/mydb',
|
|
298
|
+
lockCollectionName: 'migration_lock'
|
|
299
|
+
}),
|
|
300
|
+
migrationsDirectory: path.join(__dirname, 'migrations')
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
try {
|
|
304
|
+
await synchronizedUp(migrationOptions);
|
|
305
|
+
console.log('Migrations completed successfully');
|
|
306
|
+
} catch (err) {
|
|
307
|
+
console.error('Migration failed:', err);
|
|
308
|
+
process.exit(1);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// Run migrations on application startup
|
|
313
|
+
runMigrations().catch(console.error);
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
## Differences from @nodepit/migrate-state-store-mongodb
|
|
317
|
+
|
|
318
|
+
While maintaining full API compatibility, this implementation offers:
|
|
319
|
+
|
|
320
|
+
1. **Better TypeScript Support**: Full type definitions and modern TypeScript syntax
|
|
321
|
+
2. **MongoDB 7.x Support**: Works with latest MongoDB versions
|
|
322
|
+
3. **Async/Await**: Modern async patterns instead of callback-heavy code
|
|
323
|
+
4. **Better Error Handling**: More descriptive error messages
|
|
324
|
+
5. **No Additional Dependencies**: Uses only what's already in nest-server
|
|
325
|
+
|
|
326
|
+
## Testing
|
|
327
|
+
|
|
328
|
+
The module includes a comprehensive test suite with 25+ test cases covering:
|
|
329
|
+
|
|
330
|
+
- Initialization and configuration
|
|
331
|
+
- Error handling
|
|
332
|
+
- Loading and saving state
|
|
333
|
+
- Callback and Promise APIs
|
|
334
|
+
- Locking mechanism
|
|
335
|
+
- Parallel execution
|
|
336
|
+
- Backward compatibility
|
|
337
|
+
- MongoDB 7.x features
|
|
338
|
+
|
|
339
|
+
Run the tests:
|
|
340
|
+
|
|
341
|
+
```bash
|
|
342
|
+
npm test -- tests/migrate/mongo-state-store.e2e-spec.ts
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
## Migration Utilities
|
|
346
|
+
|
|
347
|
+
In addition to the state store, this module provides helpful utilities for managing migrations:
|
|
348
|
+
|
|
349
|
+
### createMigrationStore()
|
|
350
|
+
|
|
351
|
+
Factory function to create a migration store class for use with the migrate CLI:
|
|
352
|
+
|
|
353
|
+
```javascript
|
|
354
|
+
// migrations-utils/migrate.js
|
|
355
|
+
const { createMigrationStore } = require('@lenne.tech/nest-server');
|
|
356
|
+
const config = require('../src/config.env');
|
|
357
|
+
|
|
358
|
+
module.exports = createMigrationStore(
|
|
359
|
+
config.default.mongoose.uri,
|
|
360
|
+
'migrations', // optional collection name
|
|
361
|
+
'migration_lock' // optional lock collection for clusters
|
|
362
|
+
);
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### getDb()
|
|
366
|
+
|
|
367
|
+
Helper function to get a database connection in your migrations:
|
|
368
|
+
|
|
369
|
+
```typescript
|
|
370
|
+
import { getDb } from '@lenne.tech/nest-server';
|
|
371
|
+
|
|
372
|
+
const db = await getDb('mongodb://localhost/mydb');
|
|
373
|
+
await db.collection('users').updateMany(...);
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### uploadFileToGridFS()
|
|
377
|
+
|
|
378
|
+
Helper function to upload files to GridFS during migrations:
|
|
379
|
+
|
|
380
|
+
```typescript
|
|
381
|
+
import { uploadFileToGridFS } from '@lenne.tech/nest-server';
|
|
382
|
+
|
|
383
|
+
const fileId = await uploadFileToGridFS(
|
|
384
|
+
'mongodb://localhost/mydb',
|
|
385
|
+
'../assets/image.png',
|
|
386
|
+
{ bucketName: 'images', filename: 'logo.png' }
|
|
387
|
+
);
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### Migration Templates
|
|
391
|
+
|
|
392
|
+
Pre-built templates for creating new migrations:
|
|
393
|
+
|
|
394
|
+
1. **Basic Template**: `dist/core/modules/migrate/templates/migration.template.js`
|
|
395
|
+
2. **With Helper Template**: `dist/core/modules/migrate/templates/migration-with-helper.template.js`
|
|
396
|
+
|
|
397
|
+
### TypeScript Compiler
|
|
398
|
+
|
|
399
|
+
Pre-configured TypeScript compiler for migrate CLI:
|
|
400
|
+
|
|
401
|
+
```bash
|
|
402
|
+
migrate --compiler="ts:./node_modules/@lenne.tech/nest-server/dist/core/modules/migrate/helpers/ts-compiler.js"
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
## Complete Setup Guide
|
|
406
|
+
|
|
407
|
+
For a complete step-by-step guide on setting up migrations in your project, see [MIGRATION_GUIDE.md](./MIGRATION_GUIDE.md).
|
|
408
|
+
|
|
409
|
+
### Quick Setup (No External Dependencies!) 🚀
|
|
410
|
+
|
|
411
|
+
**No need to install the `migrate` package!** nest-server now includes a built-in migration CLI.
|
|
412
|
+
|
|
413
|
+
1. Install ts-node (dev dependency): `npm install --save-dev ts-node`
|
|
414
|
+
2. Create `migrations-utils/migrate.js` using `createMigrationStore()`
|
|
415
|
+
3. Add migration scripts to your `package.json`
|
|
416
|
+
4. Run migrations using the built-in CLI
|
|
417
|
+
|
|
418
|
+
**Example package.json scripts:**
|
|
419
|
+
```json
|
|
420
|
+
{
|
|
421
|
+
"scripts": {
|
|
422
|
+
"migrate:create": "migrate create --template-file ./migrations-utils/template.ts --migrations-dir=\"./migrations\" --compiler=\"ts:./migrations-utils/ts-compiler.js\"",
|
|
423
|
+
"migrate:up": "migrate --store=./migrations-utils/migrate.js --migrations-dir=\"./migrations\" --compiler=\"ts:./migrations-utils/ts-compiler.js\" up",
|
|
424
|
+
"migrate:down": "migrate --store=./migrations-utils/migrate.js --migrations-dir=\"./migrations\" --compiler=\"ts:./migrations-utils/ts-compiler.js\" down"
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
The `migrate` command comes from `@lenne.tech/nest-server` - no external package needed!
|
|
430
|
+
|
|
431
|
+
See the [Migration Guide](./MIGRATION_GUIDE.md) for detailed instructions.
|
|
432
|
+
|
|
433
|
+
## Project Integration
|
|
434
|
+
|
|
435
|
+
The migration utilities are designed to minimize boilerplate in your projects. Instead of copying multiple utility files, you can:
|
|
436
|
+
|
|
437
|
+
1. Use `createMigrationStore()` for your store configuration
|
|
438
|
+
2. Use the built-in TypeScript compiler
|
|
439
|
+
3. Optionally use the provided templates
|
|
440
|
+
4. Only maintain project-specific migration files
|
|
441
|
+
|
|
442
|
+
This significantly reduces the amount of migration-related code in each project.
|
|
443
|
+
|
|
444
|
+
## License
|
|
445
|
+
|
|
446
|
+
MIT
|
|
447
|
+
|
|
448
|
+
## Support
|
|
449
|
+
|
|
450
|
+
For issues and questions:
|
|
451
|
+
- GitHub: https://github.com/lenneTech/nest-server/issues
|
|
452
|
+
- Documentation: https://nest-server.lenne.tech
|