memento-mcp-server 1.16.3-a → 1.16.3-c
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/dist/domains/search/algorithms/vector-search-engine-migration.d.ts +13 -8
- package/dist/domains/search/algorithms/vector-search-engine-migration.d.ts.map +1 -1
- package/dist/domains/search/algorithms/vector-search-engine-migration.js +19 -41
- package/dist/domains/search/algorithms/vector-search-engine-migration.js.map +1 -1
- package/dist/domains/search/algorithms/vector-search-engine.d.ts +17 -36
- package/dist/domains/search/algorithms/vector-search-engine.d.ts.map +1 -1
- package/dist/domains/search/algorithms/vector-search-engine.js +94 -481
- package/dist/domains/search/algorithms/vector-search-engine.js.map +1 -1
- package/dist/domains/search/repositories/vector-search.repository.d.ts.map +1 -1
- package/dist/domains/search/repositories/vector-search.repository.js +28 -12
- package/dist/domains/search/repositories/vector-search.repository.js.map +1 -1
- package/dist/domains/search/services/vector-search/vector-performance-tester.js +1 -1
- package/dist/domains/search/services/vector-search/vector-performance-tester.js.map +1 -1
- package/dist/domains/search/services/vector-search/vector-search-container.d.ts +1 -1
- package/dist/domains/search/services/vector-search/vector-search-container.d.ts.map +1 -1
- package/dist/domains/search/services/vector-search/vector-search-container.js +1 -1
- package/dist/domains/search/services/vector-search/vector-search-container.js.map +1 -1
- package/dist/domains/search/services/vector-search/vector-search-facade.js +3 -3
- package/dist/domains/search/services/vector-search/vector-search-facade.js.map +1 -1
- package/dist/domains/search/services/vector-search/vector-search.service.js +1 -1
- package/dist/domains/search/services/vector-search/vector-search.service.js.map +1 -1
- package/dist/server/http-server.d.ts.map +1 -1
- package/dist/server/http-server.js +2 -7
- package/dist/server/http-server.js.map +1 -1
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +33 -7
- package/dist/server/index.js.map +1 -1
- package/dist/server/server-factory.d.ts +65 -0
- package/dist/server/server-factory.d.ts.map +1 -0
- package/dist/server/server-factory.js +40 -0
- package/dist/server/server-factory.js.map +1 -0
- package/dist/server/servers/sse-server.d.ts +33 -0
- package/dist/server/servers/sse-server.d.ts.map +1 -0
- package/dist/server/servers/sse-server.js +48 -0
- package/dist/server/servers/sse-server.js.map +1 -0
- package/dist/server/servers/stdio-server.d.ts +34 -0
- package/dist/server/servers/stdio-server.d.ts.map +1 -0
- package/dist/server/servers/stdio-server.js +58 -0
- package/dist/server/servers/stdio-server.js.map +1 -0
- package/dist/server/simple-mcp-server.d.ts +5 -0
- package/dist/server/simple-mcp-server.d.ts.map +1 -1
- package/dist/server/simple-mcp-server.js +17 -7
- package/dist/server/simple-mcp-server.js.map +1 -1
- package/dist/server/sse-server-impl.d.ts +22 -0
- package/dist/server/sse-server-impl.d.ts.map +1 -0
- package/dist/server/sse-server-impl.js +39 -0
- package/dist/server/sse-server-impl.js.map +1 -0
- package/dist/server/stdio-server-impl.d.ts +12 -0
- package/dist/server/stdio-server-impl.d.ts.map +1 -0
- package/dist/server/stdio-server-impl.js +19 -0
- package/dist/server/stdio-server-impl.js.map +1 -0
- package/dist/shared/types/vector-search.types.d.ts +1 -0
- package/dist/shared/types/vector-search.types.d.ts.map +1 -1
- package/package.json +1 -1
- package/scripts/__tests__/check-db-integrity.integration.spec.ts +163 -0
- package/scripts/__tests__/fix-migration.integration.spec.ts +203 -0
- package/scripts/__tests__/migrate-embedding-data.integration.spec.ts +219 -0
- package/scripts/__tests__/regenerate-embeddings.integration.spec.ts +192 -0
- package/scripts/backup-embeddings.js +52 -61
- package/scripts/check-db-integrity.js +49 -25
- package/scripts/check-file-sizes.ts +4 -4
- package/scripts/check-pii-masking.ts +0 -3
- package/scripts/check-sql-injection.ts +0 -12
- package/scripts/debug-embeddings.js +74 -93
- package/scripts/fix-migration.js +115 -80
- package/scripts/fix-vector-dimensions.js +70 -89
- package/scripts/migrate-embedding-data.js +111 -25
- package/scripts/regenerate-embeddings.js +31 -15
- package/scripts/run-migration.js +144 -107
- package/scripts/safe-migration.js +192 -142
- package/scripts/save-work-memory.ts +6 -7
- package/scripts/simple-migrate.js +66 -34
- package/scripts/simple-update.js +147 -109
- package/dist/domains/search/algorithms/vector-search-engine-refactored.d.ts +0 -56
- package/dist/domains/search/algorithms/vector-search-engine-refactored.d.ts.map +0 -1
- package/dist/domains/search/algorithms/vector-search-engine-refactored.js +0 -101
- package/dist/domains/search/algorithms/vector-search-engine-refactored.js.map +0 -1
|
@@ -3,12 +3,21 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* 임베딩 데이터 마이그레이션 스크립트
|
|
5
5
|
* 기존 임베딩 데이터를 새로운 통합 시스템으로 마이그레이션
|
|
6
|
+
*
|
|
7
|
+
* 리팩토링: 공통 모듈(initializeDatabase)을 사용하여 일관된 DB 초기화 보장
|
|
8
|
+
*
|
|
9
|
+
* 사용법:
|
|
10
|
+
* - 개발 환경: npx tsx scripts/migrate-embedding-data.js migrate
|
|
11
|
+
* - 프로덕션: npm run build && node dist/scripts/migrate-embedding-data.js migrate
|
|
6
12
|
*/
|
|
7
13
|
|
|
14
|
+
// TypeScript 소스를 직접 import (tsx로 실행 시)
|
|
15
|
+
// 빌드된 파일을 사용하려면 '../dist/infrastructure/database/database/init.js'로 변경
|
|
16
|
+
import { initializeDatabase, closeDatabase } from '../src/infrastructure/database/database/init.js';
|
|
8
17
|
import Database from 'better-sqlite3';
|
|
9
18
|
import { fileURLToPath } from 'url';
|
|
10
19
|
import { dirname, join } from 'path';
|
|
11
|
-
import { readFileSync } from 'fs';
|
|
20
|
+
import { readFileSync, copyFileSync } from 'fs';
|
|
12
21
|
import { existsSync } from 'fs';
|
|
13
22
|
|
|
14
23
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -16,17 +25,21 @@ const __dirname = dirname(__filename);
|
|
|
16
25
|
|
|
17
26
|
class EmbeddingMigration {
|
|
18
27
|
constructor() {
|
|
19
|
-
|
|
20
|
-
|
|
28
|
+
// DB 경로는 initializeDatabase가 환경 변수에서 가져옴
|
|
29
|
+
// 백업 경로는 data 디렉토리에 생성
|
|
30
|
+
this.backupPath = join(process.cwd(), 'data', `memory-backup-${Date.now()}.db`);
|
|
21
31
|
this.db = null;
|
|
22
32
|
}
|
|
23
33
|
|
|
24
34
|
/**
|
|
25
35
|
* 데이터베이스 연결
|
|
36
|
+
* 공통 모듈을 사용하여 일관된 초기화 보장
|
|
26
37
|
*/
|
|
27
|
-
connect() {
|
|
38
|
+
async connect() {
|
|
28
39
|
try {
|
|
29
|
-
|
|
40
|
+
// 공통 모듈을 사용하여 데이터베이스 초기화
|
|
41
|
+
// initializeDatabase는 DB 파일이 없으면 자동으로 생성하고 초기화함
|
|
42
|
+
this.db = await initializeDatabase();
|
|
30
43
|
console.log('✅ 데이터베이스 연결 성공');
|
|
31
44
|
} catch (error) {
|
|
32
45
|
console.error('❌ 데이터베이스 연결 실패:', error);
|
|
@@ -39,9 +52,19 @@ class EmbeddingMigration {
|
|
|
39
52
|
*/
|
|
40
53
|
createBackup() {
|
|
41
54
|
try {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
55
|
+
if (!this.db) {
|
|
56
|
+
throw new Error('데이터베이스가 연결되지 않았습니다. connect()를 먼저 호출하세요.');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 백업 디렉토리 생성
|
|
60
|
+
const backupDir = dirname(this.backupPath);
|
|
61
|
+
if (!existsSync(backupDir)) {
|
|
62
|
+
const { mkdirSync } = require('fs');
|
|
63
|
+
mkdirSync(backupDir, { recursive: true });
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 백업 생성
|
|
67
|
+
this.db.backup(this.backupPath);
|
|
45
68
|
console.log(`✅ 백업 생성 완료: ${this.backupPath}`);
|
|
46
69
|
} catch (error) {
|
|
47
70
|
console.error('❌ 백업 생성 실패:', error);
|
|
@@ -76,11 +99,14 @@ class EmbeddingMigration {
|
|
|
76
99
|
|
|
77
100
|
} catch (error) {
|
|
78
101
|
console.error('❌ 마이그레이션 실패:', error);
|
|
79
|
-
|
|
102
|
+
if (error.stack) {
|
|
103
|
+
console.error(' 스택 트레이스:', error.stack);
|
|
104
|
+
}
|
|
105
|
+
console.log(`🔄 백업에서 복원하려면: cp ${this.backupPath} ${join(process.cwd(), 'data', 'memory.db')}`);
|
|
80
106
|
throw error;
|
|
81
107
|
} finally {
|
|
82
108
|
if (this.db) {
|
|
83
|
-
this.db
|
|
109
|
+
closeDatabase(this.db);
|
|
84
110
|
}
|
|
85
111
|
}
|
|
86
112
|
}
|
|
@@ -122,11 +148,36 @@ class EmbeddingMigration {
|
|
|
122
148
|
*/
|
|
123
149
|
async runDirectMigration() {
|
|
124
150
|
try {
|
|
151
|
+
if (!this.db) {
|
|
152
|
+
throw new Error('데이터베이스가 연결되지 않았습니다.');
|
|
153
|
+
}
|
|
154
|
+
|
|
125
155
|
// 1. 새로운 컬럼 추가
|
|
126
156
|
console.log('📝 컬럼 추가 중...');
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
157
|
+
try {
|
|
158
|
+
this.db.exec('ALTER TABLE memory_embedding ADD COLUMN embedding_provider TEXT');
|
|
159
|
+
} catch (error) {
|
|
160
|
+
// 컬럼이 이미 존재할 수 있음
|
|
161
|
+
if (!error.message.includes('duplicate column')) {
|
|
162
|
+
throw error;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
try {
|
|
167
|
+
this.db.exec('ALTER TABLE memory_embedding ADD COLUMN dimensions INTEGER');
|
|
168
|
+
} catch (error) {
|
|
169
|
+
if (!error.message.includes('duplicate column')) {
|
|
170
|
+
throw error;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
this.db.exec('ALTER TABLE memory_embedding ADD COLUMN created_by TEXT DEFAULT "migration"');
|
|
176
|
+
} catch (error) {
|
|
177
|
+
if (!error.message.includes('duplicate column')) {
|
|
178
|
+
throw error;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
130
181
|
|
|
131
182
|
// 2. 기존 데이터 업데이트
|
|
132
183
|
console.log('📝 기존 데이터 업데이트 중...');
|
|
@@ -160,6 +211,10 @@ class EmbeddingMigration {
|
|
|
160
211
|
* 기존 데이터 분석
|
|
161
212
|
*/
|
|
162
213
|
analyzeExistingData() {
|
|
214
|
+
if (!this.db) {
|
|
215
|
+
throw new Error('데이터베이스가 연결되지 않았습니다.');
|
|
216
|
+
}
|
|
217
|
+
|
|
163
218
|
const analysis = {};
|
|
164
219
|
|
|
165
220
|
// 차원별 분포
|
|
@@ -206,6 +261,10 @@ class EmbeddingMigration {
|
|
|
206
261
|
* 메타데이터 업데이트
|
|
207
262
|
*/
|
|
208
263
|
updateMetadata() {
|
|
264
|
+
if (!this.db) {
|
|
265
|
+
throw new Error('데이터베이스가 연결되지 않았습니다.');
|
|
266
|
+
}
|
|
267
|
+
|
|
209
268
|
const updateStmt = this.db.prepare(`
|
|
210
269
|
UPDATE memory_embedding
|
|
211
270
|
SET
|
|
@@ -240,6 +299,10 @@ class EmbeddingMigration {
|
|
|
240
299
|
* 마이그레이션 검증
|
|
241
300
|
*/
|
|
242
301
|
validateMigration() {
|
|
302
|
+
if (!this.db) {
|
|
303
|
+
throw new Error('데이터베이스가 연결되지 않았습니다.');
|
|
304
|
+
}
|
|
305
|
+
|
|
243
306
|
console.log('🔍 마이그레이션 검증 중...');
|
|
244
307
|
|
|
245
308
|
const validation = this.db.prepare(`
|
|
@@ -265,41 +328,64 @@ class EmbeddingMigration {
|
|
|
265
328
|
*/
|
|
266
329
|
rollback() {
|
|
267
330
|
try {
|
|
268
|
-
const
|
|
269
|
-
|
|
331
|
+
const dbPath = join(process.cwd(), 'data', 'memory.db');
|
|
332
|
+
copyFileSync(this.backupPath, dbPath);
|
|
270
333
|
console.log('🔄 백업에서 복원 완료');
|
|
271
334
|
} catch (error) {
|
|
272
335
|
console.error('❌ 롤백 실패:', error);
|
|
336
|
+
throw error;
|
|
273
337
|
}
|
|
274
338
|
}
|
|
275
339
|
}
|
|
276
340
|
|
|
277
341
|
// CLI 실행
|
|
278
|
-
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
342
|
+
if (import.meta.url === `file://${process.argv[1]}` || import.meta.url.endsWith(process.argv[1])) {
|
|
279
343
|
const migration = new EmbeddingMigration();
|
|
280
344
|
|
|
281
345
|
const command = process.argv[2];
|
|
282
346
|
|
|
283
347
|
switch (command) {
|
|
284
348
|
case 'migrate':
|
|
285
|
-
migration.connect()
|
|
286
|
-
|
|
349
|
+
migration.connect().then(() => {
|
|
350
|
+
migration.migrate().catch((error) => {
|
|
351
|
+
console.error('❌ 마이그레이션 실행 중 오류:', error);
|
|
352
|
+
process.exit(1);
|
|
353
|
+
});
|
|
354
|
+
}).catch((error) => {
|
|
355
|
+
console.error('❌ 데이터베이스 연결 중 오류:', error);
|
|
356
|
+
process.exit(1);
|
|
357
|
+
});
|
|
287
358
|
break;
|
|
288
359
|
case 'rollback':
|
|
289
360
|
migration.rollback();
|
|
290
361
|
break;
|
|
291
362
|
case 'analyze':
|
|
292
|
-
migration.connect()
|
|
293
|
-
|
|
294
|
-
|
|
363
|
+
migration.connect().then(() => {
|
|
364
|
+
try {
|
|
365
|
+
const analysis = migration.analyzeExistingData();
|
|
366
|
+
console.log('📊 데이터 분석 결과:', JSON.stringify(analysis, null, 2));
|
|
367
|
+
if (migration.db) {
|
|
368
|
+
closeDatabase(migration.db);
|
|
369
|
+
}
|
|
370
|
+
} catch (error) {
|
|
371
|
+
console.error('❌ 분석 중 오류:', error);
|
|
372
|
+
if (migration.db) {
|
|
373
|
+
closeDatabase(migration.db);
|
|
374
|
+
}
|
|
375
|
+
process.exit(1);
|
|
376
|
+
}
|
|
377
|
+
}).catch((error) => {
|
|
378
|
+
console.error('❌ 데이터베이스 연결 중 오류:', error);
|
|
379
|
+
process.exit(1);
|
|
380
|
+
});
|
|
295
381
|
break;
|
|
296
382
|
default:
|
|
297
383
|
console.log(`
|
|
298
384
|
사용법:
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
385
|
+
npx tsx scripts/migrate-embedding-data.js migrate # 마이그레이션 실행
|
|
386
|
+
npx tsx scripts/migrate-embedding-data.js rollback # 백업에서 복원
|
|
387
|
+
npx tsx scripts/migrate-embedding-data.js analyze # 데이터 분석만
|
|
388
|
+
npx tsx scripts/migrate-embedding-data.js migrate --regenerate # 임베딩 재생성 모드
|
|
303
389
|
`);
|
|
304
390
|
}
|
|
305
391
|
}
|
|
@@ -3,27 +3,31 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* 임베딩 재생성 스크립트
|
|
5
5
|
* 모든 기억에 대해 새로운 벡터값을 생성하는 스크립트
|
|
6
|
+
*
|
|
7
|
+
* 리팩토링: 공통 모듈(initializeDatabase)을 사용하여 일관된 DB 초기화 보장
|
|
8
|
+
*
|
|
9
|
+
* 사용법:
|
|
10
|
+
* - 개발 환경: npx tsx scripts/regenerate-embeddings.js
|
|
11
|
+
* - 프로덕션: npm run build && node dist/scripts/regenerate-embeddings.js
|
|
6
12
|
*/
|
|
7
13
|
|
|
8
|
-
import
|
|
9
|
-
|
|
10
|
-
import {
|
|
14
|
+
// TypeScript 소스를 직접 import (tsx로 실행 시)
|
|
15
|
+
// 빌드된 파일을 사용하려면 '../dist/infrastructure/database/database/init.js'로 변경
|
|
16
|
+
import { initializeDatabase, closeDatabase } from '../src/infrastructure/database/database/init.js';
|
|
11
17
|
import { EmbeddingService } from '../dist/services/embedding-service.js';
|
|
12
18
|
|
|
13
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
14
|
-
const __dirname = path.dirname(__filename);
|
|
15
|
-
|
|
16
|
-
// 데이터베이스 경로 설정
|
|
17
|
-
const dbPath = process.env.DB_PATH || path.join(__dirname, '..', 'data', 'memory.db');
|
|
18
|
-
|
|
19
19
|
async function regenerateEmbeddings() {
|
|
20
20
|
console.log('🔄 임베딩 재생성 시작...');
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
const db = new Database(dbPath);
|
|
24
|
-
const embeddingService = new EmbeddingService();
|
|
22
|
+
let db = null;
|
|
25
23
|
|
|
26
24
|
try {
|
|
25
|
+
// 공통 모듈을 사용하여 데이터베이스 초기화
|
|
26
|
+
// initializeDatabase는 DB 파일이 없으면 자동으로 생성하고 초기화함
|
|
27
|
+
db = await initializeDatabase();
|
|
28
|
+
|
|
29
|
+
const embeddingService = new EmbeddingService();
|
|
30
|
+
|
|
27
31
|
// 임베딩 서비스 사용 가능 여부 확인
|
|
28
32
|
if (!embeddingService.isAvailable()) {
|
|
29
33
|
console.error('❌ 임베딩 서비스가 사용 불가능합니다.');
|
|
@@ -90,6 +94,9 @@ async function regenerateEmbeddings() {
|
|
|
90
94
|
|
|
91
95
|
} catch (error) {
|
|
92
96
|
console.error(`${progress} ❌ 오류: ${memory.id}`, error.message);
|
|
97
|
+
if (error.stack) {
|
|
98
|
+
console.error(' 스택 트레이스:', error.stack);
|
|
99
|
+
}
|
|
93
100
|
errorCount++;
|
|
94
101
|
}
|
|
95
102
|
}
|
|
@@ -130,15 +137,24 @@ async function regenerateEmbeddings() {
|
|
|
130
137
|
|
|
131
138
|
} catch (error) {
|
|
132
139
|
console.error('❌ 재생성 실패:', error);
|
|
140
|
+
if (error.stack) {
|
|
141
|
+
console.error(' 스택 트레이스:', error.stack);
|
|
142
|
+
}
|
|
133
143
|
process.exit(1);
|
|
134
144
|
} finally {
|
|
135
|
-
|
|
145
|
+
// 데이터베이스 연결 종료
|
|
146
|
+
if (db) {
|
|
147
|
+
closeDatabase(db);
|
|
148
|
+
}
|
|
136
149
|
}
|
|
137
150
|
}
|
|
138
151
|
|
|
139
152
|
// 스크립트 실행
|
|
140
|
-
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
141
|
-
regenerateEmbeddings().catch(
|
|
153
|
+
if (import.meta.url === `file://${process.argv[1]}` || import.meta.url.endsWith(process.argv[1])) {
|
|
154
|
+
regenerateEmbeddings().catch((error) => {
|
|
155
|
+
console.error('❌ 스크립트 실행 중 오류 발생:', error);
|
|
156
|
+
process.exit(1);
|
|
157
|
+
});
|
|
142
158
|
}
|
|
143
159
|
|
|
144
160
|
export { regenerateEmbeddings };
|
package/scripts/run-migration.js
CHANGED
|
@@ -1,122 +1,159 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* 마이그레이션 실행 스크립트
|
|
5
|
+
* 임베딩 메타데이터 마이그레이션
|
|
6
|
+
*
|
|
7
|
+
* 리팩토링: 공통 모듈(initializeDatabase)을 사용하여 일관된 DB 초기화 보장
|
|
8
|
+
*
|
|
9
|
+
* 사용법:
|
|
10
|
+
* - 개발 환경: npx tsx scripts/run-migration.js
|
|
11
|
+
* - 프로덕션: npm run build && node dist/scripts/run-migration.js
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
// TypeScript 소스를 직접 import (tsx로 실행 시)
|
|
15
|
+
// 빌드된 파일을 사용하려면 '../dist/infrastructure/database/database/init.js'로 변경
|
|
16
|
+
import { initializeDatabase, closeDatabase } from '../src/infrastructure/database/database/init.js';
|
|
4
17
|
import { join } from 'path';
|
|
5
18
|
import { existsSync, copyFileSync } from 'fs';
|
|
6
19
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
console.log('🚀 임베딩 데이터 마이그레이션 시작...');
|
|
11
|
-
|
|
12
|
-
try {
|
|
13
|
-
// 1. 백업 생성
|
|
14
|
-
console.log('💾 백업 생성 중...');
|
|
15
|
-
copyFileSync(dbPath, backupPath);
|
|
16
|
-
console.log(`✅ 백업 생성 완료: ${backupPath}`);
|
|
20
|
+
async function runMigration() {
|
|
21
|
+
console.log('🚀 임베딩 데이터 마이그레이션 시작...');
|
|
17
22
|
|
|
18
|
-
const
|
|
23
|
+
const dbPath = process.env.DB_PATH || join(process.cwd(), 'data', 'memory.db');
|
|
24
|
+
const backupPath = join(process.cwd(), 'data', `memory-backup-${Date.now()}.db`);
|
|
19
25
|
|
|
20
|
-
|
|
21
|
-
console.log('📝 새로운 컬럼 추가 중...');
|
|
26
|
+
let db = null;
|
|
22
27
|
|
|
23
28
|
try {
|
|
24
|
-
|
|
25
|
-
console.log('
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
console.log(
|
|
29
|
-
} else {
|
|
30
|
-
throw error;
|
|
29
|
+
// 1. 백업 생성
|
|
30
|
+
console.log('💾 백업 생성 중...');
|
|
31
|
+
if (existsSync(dbPath)) {
|
|
32
|
+
copyFileSync(dbPath, backupPath);
|
|
33
|
+
console.log(`✅ 백업 생성 완료: ${backupPath}`);
|
|
31
34
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
db
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
35
|
+
|
|
36
|
+
// 2. 공통 모듈을 사용하여 데이터베이스 초기화
|
|
37
|
+
// initializeDatabase는 DB 파일이 없으면 자동으로 생성하고 초기화함
|
|
38
|
+
db = await initializeDatabase();
|
|
39
|
+
|
|
40
|
+
// 3. 새로운 컬럼 추가
|
|
41
|
+
console.log('📝 새로운 컬럼 추가 중...');
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
db.exec('ALTER TABLE memory_embedding ADD COLUMN embedding_provider TEXT');
|
|
45
|
+
console.log('✅ embedding_provider 컬럼 추가');
|
|
46
|
+
} catch (error) {
|
|
47
|
+
if (error.message.includes('duplicate column name')) {
|
|
48
|
+
console.log('ℹ️ embedding_provider 컬럼이 이미 존재합니다');
|
|
49
|
+
} else {
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
42
52
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
db.exec('ALTER TABLE memory_embedding ADD COLUMN dimensions INTEGER');
|
|
56
|
+
console.log('✅ dimensions 컬럼 추가');
|
|
57
|
+
} catch (error) {
|
|
58
|
+
if (error.message.includes('duplicate column name')) {
|
|
59
|
+
console.log('ℹ️ dimensions 컬럼이 이미 존재합니다');
|
|
60
|
+
} else {
|
|
61
|
+
throw error;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
db.exec('ALTER TABLE memory_embedding ADD COLUMN created_by TEXT DEFAULT "migration"');
|
|
67
|
+
console.log('✅ created_by 컬럼 추가');
|
|
68
|
+
} catch (error) {
|
|
69
|
+
if (error.message.includes('duplicate column name')) {
|
|
70
|
+
console.log('ℹ️ created_by 컬럼이 이미 존재합니다');
|
|
71
|
+
} else {
|
|
72
|
+
throw error;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// 4. 기존 데이터 업데이트
|
|
77
|
+
console.log('🔄 기존 데이터 업데이트 중...');
|
|
78
|
+
|
|
79
|
+
const updateResult = db.prepare(`
|
|
80
|
+
UPDATE memory_embedding
|
|
81
|
+
SET
|
|
82
|
+
embedding_provider = CASE
|
|
83
|
+
WHEN model = 'lightweight-hybrid' THEN 'tfidf'
|
|
84
|
+
WHEN model IS NULL OR model = '' THEN 'tfidf'
|
|
85
|
+
ELSE 'unknown'
|
|
86
|
+
END,
|
|
87
|
+
dimensions = dim,
|
|
88
|
+
created_by = 'legacy'
|
|
89
|
+
WHERE embedding_provider IS NULL
|
|
90
|
+
`).run();
|
|
91
|
+
|
|
92
|
+
console.log(`✅ ${updateResult.changes}개 레코드 업데이트 완료`);
|
|
93
|
+
|
|
94
|
+
// 5. 인덱스 추가
|
|
95
|
+
console.log('📝 인덱스 추가 중...');
|
|
96
|
+
|
|
97
|
+
db.exec('CREATE INDEX IF NOT EXISTS idx_memory_embedding_provider ON memory_embedding(embedding_provider)');
|
|
98
|
+
db.exec('CREATE INDEX IF NOT EXISTS idx_memory_embedding_dimensions ON memory_embedding(dimensions)');
|
|
99
|
+
db.exec('CREATE INDEX IF NOT EXISTS idx_memory_embedding_created_by ON memory_embedding(created_by)');
|
|
100
|
+
|
|
101
|
+
console.log('✅ 인덱스 추가 완료');
|
|
102
|
+
|
|
103
|
+
// 6. 검증
|
|
104
|
+
console.log('🔍 마이그레이션 검증 중...');
|
|
105
|
+
|
|
106
|
+
const validation = db.prepare(`
|
|
107
|
+
SELECT
|
|
108
|
+
COUNT(*) as total,
|
|
109
|
+
COUNT(CASE WHEN embedding_provider IS NOT NULL THEN 1 END) as with_provider,
|
|
110
|
+
COUNT(CASE WHEN dimensions IS NOT NULL THEN 1 END) as with_dimensions,
|
|
111
|
+
COUNT(CASE WHEN created_by IS NOT NULL THEN 1 END) as with_created_by
|
|
112
|
+
FROM memory_embedding
|
|
113
|
+
`).get();
|
|
114
|
+
|
|
115
|
+
console.log('📊 검증 결과:');
|
|
116
|
+
console.table(validation);
|
|
117
|
+
|
|
118
|
+
// 7. 최종 결과 확인
|
|
119
|
+
const finalAnalysis = db.prepare(`
|
|
120
|
+
SELECT
|
|
121
|
+
embedding_provider,
|
|
122
|
+
dimensions,
|
|
123
|
+
COUNT(*) as count
|
|
124
|
+
FROM memory_embedding
|
|
125
|
+
GROUP BY embedding_provider, dimensions
|
|
126
|
+
ORDER BY count DESC
|
|
127
|
+
`).all();
|
|
128
|
+
|
|
129
|
+
console.log('\n📊 최종 데이터 분포:');
|
|
130
|
+
console.table(finalAnalysis);
|
|
131
|
+
|
|
132
|
+
console.log('\n🎉 마이그레이션 완료!');
|
|
133
|
+
console.log(`💾 백업 파일: ${backupPath}`);
|
|
134
|
+
console.log('🔄 롤백이 필요한 경우: cp ' + backupPath + ' ' + dbPath);
|
|
135
|
+
|
|
48
136
|
} catch (error) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
137
|
+
console.error('❌ 마이그레이션 실패:', error.message);
|
|
138
|
+
if (error.stack) {
|
|
139
|
+
console.error(' 스택 트레이스:', error.stack);
|
|
140
|
+
}
|
|
141
|
+
console.log(`🔄 백업에서 복원하려면: cp ${backupPath} ${dbPath}`);
|
|
142
|
+
process.exit(1);
|
|
143
|
+
} finally {
|
|
144
|
+
// 데이터베이스 연결 종료
|
|
145
|
+
if (db) {
|
|
146
|
+
closeDatabase(db);
|
|
53
147
|
}
|
|
54
148
|
}
|
|
55
|
-
|
|
56
|
-
// 3. 기존 데이터 업데이트
|
|
57
|
-
console.log('🔄 기존 데이터 업데이트 중...');
|
|
58
|
-
|
|
59
|
-
const updateResult = db.prepare(`
|
|
60
|
-
UPDATE memory_embedding
|
|
61
|
-
SET
|
|
62
|
-
embedding_provider = CASE
|
|
63
|
-
WHEN model = 'lightweight-hybrid' THEN 'tfidf'
|
|
64
|
-
WHEN model IS NULL OR model = '' THEN 'tfidf'
|
|
65
|
-
ELSE 'unknown'
|
|
66
|
-
END,
|
|
67
|
-
dimensions = dim,
|
|
68
|
-
created_by = 'legacy'
|
|
69
|
-
WHERE embedding_provider IS NULL
|
|
70
|
-
`).run();
|
|
71
|
-
|
|
72
|
-
console.log(`✅ ${updateResult.changes}개 레코드 업데이트 완료`);
|
|
73
|
-
|
|
74
|
-
// 4. 인덱스 추가
|
|
75
|
-
console.log('📝 인덱스 추가 중...');
|
|
76
|
-
|
|
77
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_memory_embedding_provider ON memory_embedding(embedding_provider)');
|
|
78
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_memory_embedding_dimensions ON memory_embedding(dimensions)');
|
|
79
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_memory_embedding_created_by ON memory_embedding(created_by)');
|
|
80
|
-
|
|
81
|
-
console.log('✅ 인덱스 추가 완료');
|
|
82
|
-
|
|
83
|
-
// 5. 검증
|
|
84
|
-
console.log('🔍 마이그레이션 검증 중...');
|
|
85
|
-
|
|
86
|
-
const validation = db.prepare(`
|
|
87
|
-
SELECT
|
|
88
|
-
COUNT(*) as total,
|
|
89
|
-
COUNT(CASE WHEN embedding_provider IS NOT NULL THEN 1 END) as with_provider,
|
|
90
|
-
COUNT(CASE WHEN dimensions IS NOT NULL THEN 1 END) as with_dimensions,
|
|
91
|
-
COUNT(CASE WHEN created_by IS NOT NULL THEN 1 END) as with_created_by
|
|
92
|
-
FROM memory_embedding
|
|
93
|
-
`).get();
|
|
94
|
-
|
|
95
|
-
console.log('📊 검증 결과:');
|
|
96
|
-
console.table(validation);
|
|
97
|
-
|
|
98
|
-
// 6. 최종 결과 확인
|
|
99
|
-
const finalAnalysis = db.prepare(`
|
|
100
|
-
SELECT
|
|
101
|
-
embedding_provider,
|
|
102
|
-
dimensions,
|
|
103
|
-
COUNT(*) as count
|
|
104
|
-
FROM memory_embedding
|
|
105
|
-
GROUP BY embedding_provider, dimensions
|
|
106
|
-
ORDER BY count DESC
|
|
107
|
-
`).all();
|
|
108
|
-
|
|
109
|
-
console.log('\n📊 최종 데이터 분포:');
|
|
110
|
-
console.table(finalAnalysis);
|
|
111
|
-
|
|
112
|
-
db.close();
|
|
113
|
-
|
|
114
|
-
console.log('\n🎉 마이그레이션 완료!');
|
|
115
|
-
console.log(`💾 백업 파일: ${backupPath}`);
|
|
116
|
-
console.log('🔄 롤백이 필요한 경우: cp ' + backupPath + ' ' + dbPath);
|
|
117
|
-
|
|
118
|
-
} catch (error) {
|
|
119
|
-
console.error('❌ 마이그레이션 실패:', error.message);
|
|
120
|
-
console.log(`🔄 백업에서 복원하려면: cp ${backupPath} ${dbPath}`);
|
|
121
|
-
process.exit(1);
|
|
122
149
|
}
|
|
150
|
+
|
|
151
|
+
// 스크립트 실행
|
|
152
|
+
if (import.meta.url === `file://${process.argv[1]}` || import.meta.url.endsWith(process.argv[1])) {
|
|
153
|
+
runMigration().catch((error) => {
|
|
154
|
+
console.error('❌ 스크립트 실행 중 오류 발생:', error);
|
|
155
|
+
process.exit(1);
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export { runMigration };
|