162 lines
5.3 KiB
JavaScript
162 lines
5.3 KiB
JavaScript
const betterSqlite3 = require('better-sqlite3');
|
|
const { Pool } = require('pg');
|
|
const path = require('path');
|
|
|
|
const sqlitePath = path.join(__dirname, '.tmp/data.db');
|
|
const sqliteDb = new betterSqlite3(sqlitePath);
|
|
|
|
const pgPool = new Pool({
|
|
host: process.env.DATABASE_HOST || '127.0.0.1',
|
|
port: parseInt(process.env.DATABASE_PORT || '9543', 10),
|
|
user: process.env.DATABASE_USERNAME || 'strapi',
|
|
password: process.env.DATABASE_PASSWORD || 'strapi_password_9000',
|
|
database: process.env.DATABASE_NAME || 'strapi',
|
|
});
|
|
|
|
async function migrate() {
|
|
console.log('Connecting to PostgreSQL...');
|
|
const client = await pgPool.connect();
|
|
|
|
try {
|
|
console.log('Disabling constraints temporarily for migration...');
|
|
await client.query("SET session_replication_role = 'replica';");
|
|
|
|
// 1. Get all public tables in Postgres and TRUNCATE them
|
|
const allTablesRes = await client.query(`
|
|
SELECT table_name
|
|
FROM information_schema.tables
|
|
WHERE table_schema = 'public' AND table_type = 'BASE TABLE';
|
|
`);
|
|
const pgTables = allTablesRes.rows.map(r => r.table_name);
|
|
|
|
for (const t of pgTables) {
|
|
await client.query(`TRUNCATE TABLE "${t}" CASCADE;`);
|
|
}
|
|
console.log(`Truncated all ${pgTables.length} PostgreSQL tables.`);
|
|
|
|
// 2. Migrate tables from SQLite
|
|
const tablesToMigrate = [
|
|
'strapi_database_schema',
|
|
'strapi_migrations_internal',
|
|
'strapi_core_store_settings',
|
|
'i18n_locale',
|
|
'files',
|
|
'files_related_mph',
|
|
'job_roles',
|
|
'blogs',
|
|
'blogs_author_lnk',
|
|
'blogs_editor_lnk',
|
|
'admin_roles',
|
|
'admin_users',
|
|
'admin_users_roles_lnk',
|
|
'admin_permissions',
|
|
'admin_permissions_role_lnk',
|
|
'up_roles',
|
|
'up_permissions',
|
|
'up_permissions_role_lnk',
|
|
'strapi_api_tokens',
|
|
'strapi_sessions',
|
|
];
|
|
|
|
for (const table of tablesToMigrate) {
|
|
if (!pgTables.includes(table)) {
|
|
console.log(`Table ${table} does not exist in Postgres, skipping.`);
|
|
continue;
|
|
}
|
|
|
|
const colInfoRes = await client.query(
|
|
`SELECT column_name, data_type FROM information_schema.columns WHERE table_name = $1;`,
|
|
[table]
|
|
);
|
|
const colDataTypes = {};
|
|
colInfoRes.rows.forEach(r => {
|
|
colDataTypes[r.column_name] = r.data_type;
|
|
});
|
|
|
|
const rows = sqliteDb.prepare(`SELECT * FROM "${table}"`).all();
|
|
console.log(`Migrating table: ${table} (${rows.length} rows)`);
|
|
|
|
if (rows.length === 0) continue;
|
|
|
|
const columns = Object.keys(rows[0]);
|
|
const colNames = columns.map((c) => `"${c}"`).join(', ');
|
|
|
|
for (let index = 0; index < rows.length; index++) {
|
|
const row = rows[index];
|
|
const values = columns.map((col) => {
|
|
let val = row[col];
|
|
const dt = colDataTypes[col];
|
|
|
|
if ((dt === 'timestamp with time zone' || dt === 'timestamp without time zone') && val !== null) {
|
|
if (typeof val === 'number' || (typeof val === 'string' && /^\d+$/.test(val))) {
|
|
val = new Date(Number(val)).toISOString();
|
|
}
|
|
}
|
|
|
|
if (dt === 'json' || dt === 'jsonb') {
|
|
if (val === '' || val === undefined) {
|
|
val = null;
|
|
} else if (typeof val === 'object') {
|
|
val = JSON.stringify(val);
|
|
}
|
|
}
|
|
|
|
if (dt === 'boolean' && val !== null) {
|
|
if (val === 1 || val === '1' || val === 'true') val = true;
|
|
if (val === 0 || val === '0' || val === 'false') val = false;
|
|
}
|
|
|
|
return val;
|
|
});
|
|
|
|
const placeholders = values.map((_, i) => `$${i + 1}`).join(', ');
|
|
const query = `INSERT INTO "${table}" (${colNames}) VALUES (${placeholders});`;
|
|
await client.query(query, values);
|
|
}
|
|
|
|
if (columns.includes('id')) {
|
|
const seqRes = await client.query(`
|
|
SELECT pg_get_serial_sequence('"${table}"', 'id') AS seq;
|
|
`);
|
|
const seqName = seqRes.rows[0]?.seq;
|
|
if (seqName) {
|
|
await client.query(`
|
|
SELECT setval('${seqName}', COALESCE((SELECT MAX(id) FROM "${table}"), 1));
|
|
`);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 3. Fix ordinals for all link tables
|
|
console.log('Fixing ordinals for link tables...');
|
|
await client.query(`
|
|
UPDATE public.admin_users_roles_lnk a SET user_ord = b.inv_order FROM (
|
|
SELECT id, ROW_NUMBER() OVER (PARTITION BY role_id ORDER BY id) as inv_order FROM public.admin_users_roles_lnk
|
|
) b WHERE a.id = b.id;
|
|
`);
|
|
await client.query(`
|
|
UPDATE public.admin_permissions_role_lnk a SET permission_ord = b.inv_order FROM (
|
|
SELECT id, ROW_NUMBER() OVER (PARTITION BY role_id ORDER BY id) as inv_order FROM public.admin_permissions_role_lnk
|
|
) b WHERE a.id = b.id;
|
|
`);
|
|
await client.query(`
|
|
UPDATE public.up_permissions_role_lnk a SET permission_ord = b.inv_order FROM (
|
|
SELECT id, ROW_NUMBER() OVER (PARTITION BY role_id ORDER BY id) as inv_order FROM public.up_permissions_role_lnk
|
|
) b WHERE a.id = b.id;
|
|
`);
|
|
|
|
console.log('Re-enabling constraints...');
|
|
await client.query("SET session_replication_role = 'origin';");
|
|
|
|
console.log('Migration completed successfully!');
|
|
} catch (err) {
|
|
console.error('Migration failed:', err);
|
|
} finally {
|
|
client.release();
|
|
await pgPool.end();
|
|
sqliteDb.close();
|
|
}
|
|
}
|
|
|
|
migrate();
|