586 lines
16 KiB
TypeScript
586 lines
16 KiB
TypeScript
|
|
/**
|
||
|
|
* Data Migration Script
|
||
|
|
*
|
||
|
|
* Migrates data from legacy SQL Server database to PostgreSQL
|
||
|
|
*
|
||
|
|
* Usage: npx ts-node scripts/migrate-data.ts
|
||
|
|
*/
|
||
|
|
|
||
|
|
import sql from 'mssql';
|
||
|
|
import { PrismaClient } from '@prisma/client';
|
||
|
|
import * as bcrypt from 'bcryptjs';
|
||
|
|
|
||
|
|
const prisma = new PrismaClient();
|
||
|
|
|
||
|
|
// SQL Server configuration (legacy database)
|
||
|
|
const legacyConfig: sql.config = {
|
||
|
|
server: process.env.MSSQL_HOST || '',
|
||
|
|
database: process.env.PORTAL_DB_NAME || 'VorteqPortal',
|
||
|
|
user: process.env.MSSQL_USER || '',
|
||
|
|
password: process.env.MSSQL_PASSWORD || '',
|
||
|
|
options: {
|
||
|
|
encrypt: false,
|
||
|
|
trustServerCertificate: true,
|
||
|
|
enableArithAbort: true,
|
||
|
|
},
|
||
|
|
pool: {
|
||
|
|
max: 10,
|
||
|
|
min: 0,
|
||
|
|
idleTimeoutMillis: 30000,
|
||
|
|
},
|
||
|
|
};
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Migration Statistics
|
||
|
|
*/
|
||
|
|
const stats = {
|
||
|
|
auth_domain: { expected: 0, migrated: 0 },
|
||
|
|
auth_user_type: { expected: 0, migrated: 0 },
|
||
|
|
auth_user: { expected: 0, migrated: 0 },
|
||
|
|
auth_permission_group: { expected: 0, migrated: 0 },
|
||
|
|
auth_permission_rule: { expected: 0, migrated: 0 },
|
||
|
|
auth_permission_rule_category: { expected: 0, migrated: 0 },
|
||
|
|
quest_user: { expected: 0, migrated: 0 },
|
||
|
|
quest_company: { expected: 0, migrated: 0 },
|
||
|
|
quest_user_company: { expected: 0, migrated: 0 },
|
||
|
|
quest_plant: { expected: 0, migrated: 0 },
|
||
|
|
quest_inventory_type: { expected: 0, migrated: 0 },
|
||
|
|
quest_email_event: { expected: 0, migrated: 0 },
|
||
|
|
ship_request: { expected: 0, migrated: 0 },
|
||
|
|
ship_request_detail: { expected: 0, migrated: 0 },
|
||
|
|
alloc_request: { expected: 0, migrated: 0 },
|
||
|
|
alloc_request_detail: { expected: 0, migrated: 0 },
|
||
|
|
};
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Connect to legacy SQL Server database
|
||
|
|
*/
|
||
|
|
async function connectToLegacy(): Promise<sql.ConnectionPool> {
|
||
|
|
console.log('Connecting to legacy SQL Server database...');
|
||
|
|
const pool = await sql.connect(legacyConfig);
|
||
|
|
console.log('✓ Connected to legacy database');
|
||
|
|
return pool;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Migrate auth_domain table
|
||
|
|
*/
|
||
|
|
async function migrateAuthDomains(pool: sql.ConnectionPool) {
|
||
|
|
console.log('\nMigrating auth_domain...');
|
||
|
|
|
||
|
|
const result = await pool.request().query(`
|
||
|
|
SELECT ID, Name, Description, IsActive, CreatedAt, UpdatedAt
|
||
|
|
FROM auth_domain
|
||
|
|
`);
|
||
|
|
|
||
|
|
stats.auth_domain.expected = result.recordset.length;
|
||
|
|
|
||
|
|
for (const row of result.recordset) {
|
||
|
|
await prisma.auth_domain.upsert({
|
||
|
|
where: { id: row.ID },
|
||
|
|
update: {},
|
||
|
|
create: {
|
||
|
|
id: row.ID,
|
||
|
|
name: row.Name,
|
||
|
|
description: row.Description,
|
||
|
|
is_active: row.IsActive,
|
||
|
|
created_at: row.CreatedAt,
|
||
|
|
updated_at: row.UpdatedAt,
|
||
|
|
},
|
||
|
|
});
|
||
|
|
stats.auth_domain.migrated++;
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log(
|
||
|
|
`✓ Migrated ${stats.auth_domain.migrated}/${stats.auth_domain.expected} auth_domain records`
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Migrate auth_user_type table
|
||
|
|
*/
|
||
|
|
async function migrateAuthUserTypes(pool: sql.ConnectionPool) {
|
||
|
|
console.log('\nMigrating auth_user_type...');
|
||
|
|
|
||
|
|
const result = await pool.request().query(`
|
||
|
|
SELECT ID, Name, Description, IsAdmin, IsCustomer, IsInternal, CreatedAt, UpdatedAt
|
||
|
|
FROM auth_user_type
|
||
|
|
`);
|
||
|
|
|
||
|
|
stats.auth_user_type.expected = result.recordset.length;
|
||
|
|
|
||
|
|
for (const row of result.recordset) {
|
||
|
|
await prisma.auth_user_type.upsert({
|
||
|
|
where: { id: row.ID },
|
||
|
|
update: {},
|
||
|
|
create: {
|
||
|
|
id: row.ID,
|
||
|
|
name: row.Name,
|
||
|
|
description: row.Description,
|
||
|
|
is_admin: row.IsAdmin,
|
||
|
|
is_customer: row.IsCustomer,
|
||
|
|
is_internal: row.IsInternal,
|
||
|
|
created_at: row.CreatedAt,
|
||
|
|
updated_at: row.UpdatedAt,
|
||
|
|
},
|
||
|
|
});
|
||
|
|
stats.auth_user_type.migrated++;
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log(
|
||
|
|
`✓ Migrated ${stats.auth_user_type.migrated}/${stats.auth_user_type.expected} auth_user_type records`
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Migrate auth_user table
|
||
|
|
*/
|
||
|
|
async function migrateAuthUsers(pool: sql.ConnectionPool) {
|
||
|
|
console.log('\nMigrating auth_user...');
|
||
|
|
|
||
|
|
const result = await pool.request().query(`
|
||
|
|
SELECT
|
||
|
|
ID, Email, EmailVerified, Name, Image, CreatedAt, UpdatedAt,
|
||
|
|
PasswordHash, Deactivated, DeactivatedAt, DeactivationReason,
|
||
|
|
LoginCount, FailedLoginCount, LastLoginAt, LastLoginIP, LastFailedLoginAt,
|
||
|
|
TwoFactorEnabled, TwoFactorSecret, TwoFactorBackupCodes,
|
||
|
|
SSOProvider, SSOID, AuthUserTypeID, AuthDomainID
|
||
|
|
FROM auth_user
|
||
|
|
`);
|
||
|
|
|
||
|
|
stats.auth_user.expected = result.recordset.length;
|
||
|
|
|
||
|
|
for (const row of result.recordset) {
|
||
|
|
await prisma.auth_user.upsert({
|
||
|
|
where: { id: row.ID },
|
||
|
|
update: {},
|
||
|
|
create: {
|
||
|
|
id: row.ID,
|
||
|
|
email: row.Email,
|
||
|
|
email_verified: row.EmailVerified,
|
||
|
|
name: row.Name,
|
||
|
|
image: row.Image,
|
||
|
|
created_at: row.CreatedAt,
|
||
|
|
updated_at: row.UpdatedAt,
|
||
|
|
password_hash: row.PasswordHash,
|
||
|
|
deactivated: row.Deactivated,
|
||
|
|
deactivated_at: row.DeactivatedAt,
|
||
|
|
deactivation_reason: row.DeactivationReason,
|
||
|
|
login_count: row.LoginCount,
|
||
|
|
failed_login_count: row.FailedLoginCount,
|
||
|
|
last_login_at: row.LastLoginAt,
|
||
|
|
last_login_ip: row.LastLoginIP,
|
||
|
|
last_failed_login_at: row.LastFailedLoginAt,
|
||
|
|
two_factor_enabled: row.TwoFactorEnabled,
|
||
|
|
two_factor_secret: row.TwoFactorSecret,
|
||
|
|
two_factor_backup_codes: row.TwoFactorBackupCodes,
|
||
|
|
sso_provider: row.SSOProvider,
|
||
|
|
sso_id: row.SSOID,
|
||
|
|
auth_user_type_id: row.AuthUserTypeID,
|
||
|
|
auth_domain_id: row.AuthDomainID,
|
||
|
|
},
|
||
|
|
});
|
||
|
|
stats.auth_user.migrated++;
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log(
|
||
|
|
`✓ Migrated ${stats.auth_user.migrated}/${stats.auth_user.expected} auth_user records`
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Migrate auth_permission_rule_category table
|
||
|
|
*/
|
||
|
|
async function migratePermissionRuleCategories(pool: sql.ConnectionPool) {
|
||
|
|
console.log('\nMigrating auth_permission_rule_category...');
|
||
|
|
|
||
|
|
const result = await pool.request().query(`
|
||
|
|
SELECT ID, Name, Description, CreatedAt, UpdatedAt
|
||
|
|
FROM auth_permission_rule_category
|
||
|
|
`);
|
||
|
|
|
||
|
|
stats.auth_permission_rule_category.expected = result.recordset.length;
|
||
|
|
|
||
|
|
for (const row of result.recordset) {
|
||
|
|
await prisma.auth_permission_rule_category.upsert({
|
||
|
|
where: { id: row.ID },
|
||
|
|
update: {},
|
||
|
|
create: {
|
||
|
|
id: row.ID,
|
||
|
|
name: row.Name,
|
||
|
|
description: row.Description,
|
||
|
|
created_at: row.CreatedAt,
|
||
|
|
updated_at: row.UpdatedAt,
|
||
|
|
},
|
||
|
|
});
|
||
|
|
stats.auth_permission_rule_category.migrated++;
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log(
|
||
|
|
`✓ Migrated ${stats.auth_permission_rule_category.migrated}/${stats.auth_permission_rule_category.expected} auth_permission_rule_category records`
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Migrate auth_permission_rule table
|
||
|
|
*/
|
||
|
|
async function migratePermissionRules(pool: sql.ConnectionPool) {
|
||
|
|
console.log('\nMigrating auth_permission_rule...');
|
||
|
|
|
||
|
|
const result = await pool.request().query(`
|
||
|
|
SELECT ID, Name, Description, AuthPermissionRuleCategoryID, CreatedAt, UpdatedAt
|
||
|
|
FROM auth_permission_rule
|
||
|
|
`);
|
||
|
|
|
||
|
|
stats.auth_permission_rule.expected = result.recordset.length;
|
||
|
|
|
||
|
|
for (const row of result.recordset) {
|
||
|
|
await prisma.auth_permission_rule.upsert({
|
||
|
|
where: { id: row.ID },
|
||
|
|
update: {},
|
||
|
|
create: {
|
||
|
|
id: row.ID,
|
||
|
|
name: row.Name,
|
||
|
|
description: row.Description,
|
||
|
|
auth_permission_rule_category_id: row.AuthPermissionRuleCategoryID,
|
||
|
|
created_at: row.CreatedAt,
|
||
|
|
updated_at: row.UpdatedAt,
|
||
|
|
},
|
||
|
|
});
|
||
|
|
stats.auth_permission_rule.migrated++;
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log(
|
||
|
|
`✓ Migrated ${stats.auth_permission_rule.migrated}/${stats.auth_permission_rule.expected} auth_permission_rule records`
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Migrate auth_permission_group table
|
||
|
|
*/
|
||
|
|
async function migratePermissionGroups(pool: sql.ConnectionPool) {
|
||
|
|
console.log('\nMigrating auth_permission_group...');
|
||
|
|
|
||
|
|
const result = await pool.request().query(`
|
||
|
|
SELECT ID, Name, Description, IsActive, CreatedAt, UpdatedAt
|
||
|
|
FROM auth_permission_group
|
||
|
|
`);
|
||
|
|
|
||
|
|
stats.auth_permission_group.expected = result.recordset.length;
|
||
|
|
|
||
|
|
for (const row of result.recordset) {
|
||
|
|
await prisma.auth_permission_group.upsert({
|
||
|
|
where: { id: row.ID },
|
||
|
|
update: {},
|
||
|
|
create: {
|
||
|
|
id: row.ID,
|
||
|
|
name: row.Name,
|
||
|
|
description: row.Description,
|
||
|
|
is_active: row.IsActive,
|
||
|
|
created_at: row.CreatedAt,
|
||
|
|
updated_at: row.UpdatedAt,
|
||
|
|
},
|
||
|
|
});
|
||
|
|
stats.auth_permission_group.migrated++;
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log(
|
||
|
|
`✓ Migrated ${stats.auth_permission_group.migrated}/${stats.auth_permission_group.expected} auth_permission_group records`
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Migrate auth_permission_group_rule junction table
|
||
|
|
*/
|
||
|
|
async function migratePermissionGroupRules(pool: sql.ConnectionPool) {
|
||
|
|
console.log('\nMigrating auth_permission_group_rule...');
|
||
|
|
|
||
|
|
const result = await pool.request().query(`
|
||
|
|
SELECT ID, AuthPermissionGroupID, AuthPermissionRuleID, CreatedAt
|
||
|
|
FROM auth_permission_group_rule
|
||
|
|
`);
|
||
|
|
|
||
|
|
for (const row of result.recordset) {
|
||
|
|
await prisma.auth_permission_group_rule.upsert({
|
||
|
|
where: { id: row.ID },
|
||
|
|
update: {},
|
||
|
|
create: {
|
||
|
|
id: row.ID,
|
||
|
|
auth_permission_group_id: row.AuthPermissionGroupID,
|
||
|
|
auth_permission_rule_id: row.AuthPermissionRuleID,
|
||
|
|
created_at: row.CreatedAt,
|
||
|
|
},
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log(
|
||
|
|
`✓ Migrated ${result.recordset.length} auth_permission_group_rule records`
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Migrate quest_company table
|
||
|
|
*/
|
||
|
|
async function migrateQuestCompanies(pool: sql.ConnectionPool) {
|
||
|
|
console.log('\nMigrating quest_company...');
|
||
|
|
|
||
|
|
const result = await pool.request().query(`
|
||
|
|
SELECT
|
||
|
|
ID, EpicorCustID, DisplayName, CanAccessInvoices,
|
||
|
|
InvoicingEmail, OrderAckEmail, ReceivesSOEmails, IsActive,
|
||
|
|
CreatedAt, UpdatedAt
|
||
|
|
FROM quest_company
|
||
|
|
`);
|
||
|
|
|
||
|
|
stats.quest_company.expected = result.recordset.length;
|
||
|
|
|
||
|
|
for (const row of result.recordset) {
|
||
|
|
await prisma.quest_company.upsert({
|
||
|
|
where: { id: row.ID },
|
||
|
|
update: {},
|
||
|
|
create: {
|
||
|
|
id: row.ID,
|
||
|
|
epicor_cust_id: row.EpicorCustID,
|
||
|
|
display_name: row.DisplayName,
|
||
|
|
can_access_invoices: row.CanAccessInvoices,
|
||
|
|
invoicing_email: row.InvoicingEmail,
|
||
|
|
order_ack_email: row.OrderAckEmail,
|
||
|
|
receives_so_emails: row.ReceivesSOEmails,
|
||
|
|
is_active: row.IsActive,
|
||
|
|
created_at: row.CreatedAt,
|
||
|
|
updated_at: row.UpdatedAt,
|
||
|
|
},
|
||
|
|
});
|
||
|
|
stats.quest_company.migrated++;
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log(
|
||
|
|
`✓ Migrated ${stats.quest_company.migrated}/${stats.quest_company.expected} quest_company records`
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Migrate quest_user table
|
||
|
|
*/
|
||
|
|
async function migrateQuestUsers(pool: sql.ConnectionPool) {
|
||
|
|
console.log('\nMigrating quest_user...');
|
||
|
|
|
||
|
|
const result = await pool.request().query(`
|
||
|
|
SELECT
|
||
|
|
ID, AuthUserID, IsSubUser, APIToken, APITokenExpiresAt,
|
||
|
|
CreatedAt, UpdatedAt
|
||
|
|
FROM quest_user
|
||
|
|
`);
|
||
|
|
|
||
|
|
stats.quest_user.expected = result.recordset.length;
|
||
|
|
|
||
|
|
for (const row of result.recordset) {
|
||
|
|
await prisma.quest_user.upsert({
|
||
|
|
where: { id: row.ID },
|
||
|
|
update: {},
|
||
|
|
create: {
|
||
|
|
id: row.ID,
|
||
|
|
auth_user_id: row.AuthUserID,
|
||
|
|
is_sub_user: row.IsSubUser,
|
||
|
|
api_token: row.APIToken,
|
||
|
|
api_token_expires_at: row.APITokenExpiresAt,
|
||
|
|
created_at: row.CreatedAt,
|
||
|
|
updated_at: row.UpdatedAt,
|
||
|
|
},
|
||
|
|
});
|
||
|
|
stats.quest_user.migrated++;
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log(
|
||
|
|
`✓ Migrated ${stats.quest_user.migrated}/${stats.quest_user.expected} quest_user records`
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Migrate quest_user_company junction table
|
||
|
|
*/
|
||
|
|
async function migrateQuestUserCompanies(pool: sql.ConnectionPool) {
|
||
|
|
console.log('\nMigrating quest_user_company...');
|
||
|
|
|
||
|
|
const result = await pool.request().query(`
|
||
|
|
SELECT ID, QuestUserID, QuestCompanyID, IsActive, CreatedAt
|
||
|
|
FROM quest_user_company
|
||
|
|
`);
|
||
|
|
|
||
|
|
stats.quest_user_company.expected = result.recordset.length;
|
||
|
|
|
||
|
|
for (const row of result.recordset) {
|
||
|
|
await prisma.quest_user_company.upsert({
|
||
|
|
where: { id: row.ID },
|
||
|
|
update: {},
|
||
|
|
create: {
|
||
|
|
id: row.ID,
|
||
|
|
quest_user_id: row.QuestUserID,
|
||
|
|
quest_company_id: row.QuestCompanyID,
|
||
|
|
is_active_company: row.IsActive,
|
||
|
|
created_at: row.CreatedAt,
|
||
|
|
},
|
||
|
|
});
|
||
|
|
stats.quest_user_company.migrated++;
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log(
|
||
|
|
`✓ Migrated ${stats.quest_user_company.migrated}/${stats.quest_user_company.expected} quest_user_company records`
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Migrate quest_plant table
|
||
|
|
*/
|
||
|
|
async function migrateQuestPlants(pool: sql.ConnectionPool) {
|
||
|
|
console.log('\nMigrating quest_plant...');
|
||
|
|
|
||
|
|
const result = await pool.request().query(`
|
||
|
|
SELECT ID, Name, Code, IsActive, CreatedAt, UpdatedAt
|
||
|
|
FROM quest_plant
|
||
|
|
`);
|
||
|
|
|
||
|
|
stats.quest_plant.expected = result.recordset.length;
|
||
|
|
|
||
|
|
for (const row of result.recordset) {
|
||
|
|
await prisma.quest_plant.upsert({
|
||
|
|
where: { id: row.ID },
|
||
|
|
update: {},
|
||
|
|
create: {
|
||
|
|
id: row.ID,
|
||
|
|
name: row.Name,
|
||
|
|
code: row.Code,
|
||
|
|
is_active: row.IsActive,
|
||
|
|
created_at: row.CreatedAt,
|
||
|
|
updated_at: row.UpdatedAt,
|
||
|
|
},
|
||
|
|
});
|
||
|
|
stats.quest_plant.migrated++;
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log(
|
||
|
|
`✓ Migrated ${stats.quest_plant.migrated}/${stats.quest_plant.expected} quest_plant records`
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Migrate quest_inventory_type table
|
||
|
|
*/
|
||
|
|
async function migrateQuestInventoryTypes(pool: sql.ConnectionPool) {
|
||
|
|
console.log('\nMigrating quest_inventory_type...');
|
||
|
|
|
||
|
|
const result = await pool.request().query(`
|
||
|
|
SELECT ID, Name, Code, Description, IsActive, SortOrder, CreatedAt, UpdatedAt
|
||
|
|
FROM quest_inventory_type
|
||
|
|
`);
|
||
|
|
|
||
|
|
stats.quest_inventory_type.expected = result.recordset.length;
|
||
|
|
|
||
|
|
for (const row of result.recordset) {
|
||
|
|
await prisma.quest_inventory_type.upsert({
|
||
|
|
where: { id: row.ID },
|
||
|
|
update: {},
|
||
|
|
create: {
|
||
|
|
id: row.ID,
|
||
|
|
name: row.Name,
|
||
|
|
code: row.Code,
|
||
|
|
description: row.Description,
|
||
|
|
is_active: row.IsActive,
|
||
|
|
sort_order: row.SortOrder || 0,
|
||
|
|
created_at: row.CreatedAt,
|
||
|
|
updated_at: row.UpdatedAt,
|
||
|
|
},
|
||
|
|
});
|
||
|
|
stats.quest_inventory_type.migrated++;
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log(
|
||
|
|
`✓ Migrated ${stats.quest_inventory_type.migrated}/${stats.quest_inventory_type.expected} quest_inventory_type records`
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Migrate quest_email_event table
|
||
|
|
*/
|
||
|
|
async function migrateQuestEmailEvents(pool: sql.ConnectionPool) {
|
||
|
|
console.log('\nMigrating quest_email_event...');
|
||
|
|
|
||
|
|
const result = await pool.request().query(`
|
||
|
|
SELECT ID, Name, Description, CreatedAt, UpdatedAt
|
||
|
|
FROM quest_email_event
|
||
|
|
`);
|
||
|
|
|
||
|
|
stats.quest_email_event.expected = result.recordset.length;
|
||
|
|
|
||
|
|
for (const row of result.recordset) {
|
||
|
|
await prisma.quest_email_event.upsert({
|
||
|
|
where: { id: row.ID },
|
||
|
|
update: {},
|
||
|
|
create: {
|
||
|
|
id: row.ID,
|
||
|
|
name: row.Name,
|
||
|
|
description: row.Description,
|
||
|
|
created_at: row.CreatedAt,
|
||
|
|
updated_at: row.UpdatedAt,
|
||
|
|
},
|
||
|
|
});
|
||
|
|
stats.quest_email_event.migrated++;
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log(
|
||
|
|
`✓ Migrated ${stats.quest_email_event.migrated}/${stats.quest_email_event.expected} quest_email_event records`
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Main migration function
|
||
|
|
*/
|
||
|
|
async function main() {
|
||
|
|
console.log('=== Vorteq Quest Portal Data Migration ===\n');
|
||
|
|
console.log('Source: SQL Server (VorteqPortal)');
|
||
|
|
console.log('Target: PostgreSQL (via Prisma)\n');
|
||
|
|
|
||
|
|
try {
|
||
|
|
const pool = await connectToLegacy();
|
||
|
|
|
||
|
|
// Migrate auth domain
|
||
|
|
await migrateAuthDomains(pool);
|
||
|
|
await migrateAuthUserTypes(pool);
|
||
|
|
await migrateAuthUsers(pool);
|
||
|
|
await migratePermissionRuleCategories(pool);
|
||
|
|
await migratePermissionRules(pool);
|
||
|
|
await migratePermissionGroups(pool);
|
||
|
|
await migratePermissionGroupRules(pool);
|
||
|
|
|
||
|
|
// Migrate quest domain
|
||
|
|
await migrateQuestCompanies(pool);
|
||
|
|
await migrateQuestUsers(pool);
|
||
|
|
await migrateQuestUserCompanies(pool);
|
||
|
|
await migrateQuestPlants(pool);
|
||
|
|
await migrateQuestInventoryTypes(pool);
|
||
|
|
await migrateQuestEmailEvents(pool);
|
||
|
|
|
||
|
|
// Close connections
|
||
|
|
await pool.close();
|
||
|
|
|
||
|
|
// Print summary
|
||
|
|
console.log('\n=== Migration Summary ===\n');
|
||
|
|
for (const [table, { expected, migrated }] of Object.entries(stats)) {
|
||
|
|
if (expected > 0) {
|
||
|
|
const status = expected === migrated ? '✓' : '⚠';
|
||
|
|
console.log(`${status} ${table}: ${migrated}/${expected}`);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log('\n✓ Migration completed successfully!');
|
||
|
|
} catch (error) {
|
||
|
|
console.error('\n✗ Migration failed:', error);
|
||
|
|
process.exit(1);
|
||
|
|
} finally {
|
||
|
|
await prisma.$disconnect();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Run migration
|
||
|
|
main();
|