hindki/hindki/scripts/migrate-sqlite-to-postgres.ts
ryan 8c924ed54f
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 5s
Migrate postgres
2025-10-02 12:19:51 -07:00

110 lines
3.4 KiB
TypeScript

import Database from 'better-sqlite3';
import { drizzle as sqliteDrizzle } from 'drizzle-orm/better-sqlite3';
import { drizzle as postgresDrizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';
import { words, examples, tags, wordTags, seeAlso } from '../src/lib/db/schema';
import 'dotenv/config';
const connectionString = process.env.DATABASE_URL || '';
if (!connectionString) {
console.error('DATABASE_URL environment variable is required');
process.exit(1);
}
async function migrate() {
console.log('Starting SQLite to PostgreSQL migration...\n');
// Connect to SQLite
const sqlite = new Database('./data.db');
const sqliteDb = sqliteDrizzle(sqlite);
// Connect to PostgreSQL
const pgClient = postgres(connectionString);
const pgDb = postgresDrizzle(pgClient, { schema: { words, examples, tags, wordTags, seeAlso } });
try {
// Migrate tags first
console.log('Migrating tags...');
const sqliteTags = sqlite.prepare('SELECT * FROM tags').all() as any[];
for (const tag of sqliteTags) {
await pgDb.insert(tags).values({
name: tag.name,
description: tag.description,
});
}
console.log(`✅ Migrated ${sqliteTags.length} tags\n`);
// Get tag ID mapping (SQLite ID -> PostgreSQL ID)
const pgTags = await pgDb.select().from(tags);
const tagIdMap = new Map<number, number>();
for (let i = 0; i < sqliteTags.length; i++) {
const sqliteTag = sqliteTags[i];
const pgTag = pgTags.find(t => t.name === sqliteTag.name);
if (pgTag) {
tagIdMap.set(sqliteTag.id, pgTag.id);
}
}
// Migrate words
console.log('Migrating words...');
const sqliteWords = sqlite.prepare('SELECT * FROM words').all() as any[];
for (const word of sqliteWords) {
const [insertedWord] = await pgDb.insert(words).values({
hindi: word.hindi,
english: word.english,
type: word.type,
gender: word.gender,
note: word.note,
}).returning();
// Migrate word_tags associations
const wordTagsData = sqlite.prepare('SELECT * FROM word_tags WHERE word_id = ?').all(word.id) as any[];
for (const wt of wordTagsData) {
const newTagId = tagIdMap.get(wt.tag_id);
if (newTagId) {
await pgDb.insert(wordTags).values({
wordId: insertedWord.id,
tagId: newTagId,
});
}
}
// Migrate examples
const examplesData = sqlite.prepare('SELECT * FROM examples WHERE word_id = ?').all(word.id) as any[];
for (const example of examplesData) {
await pgDb.insert(examples).values({
wordId: insertedWord.id,
hindi: example.hindi,
english: example.english,
note: example.note,
});
}
// Migrate see_also
const seeAlsoData = sqlite.prepare('SELECT * FROM see_also WHERE word_id = ?').all(word.id) as any[];
for (const sa of seeAlsoData) {
await pgDb.insert(seeAlso).values({
wordId: insertedWord.id,
reference: sa.reference,
note: sa.note,
});
}
}
console.log(`✅ Migrated ${sqliteWords.length} words with all relations\n`);
console.log('Migration complete! 🎉');
} catch (error) {
console.error('Migration failed:', error);
process.exit(1);
} finally {
sqlite.close();
await pgClient.end();
}
}
migrate();