Files
kls/cmd/pg2sqlite/main.go
Kyle Isom 0fa85cb300 migrate to SQLite and prepare for MCP deployment
Switch from PostgreSQL to SQLite (modernc.org/sqlite, pure Go) for
simpler deployment on the MCP platform. Fix URL normalization to
preserve query parameters so sites like YouTube deduplicate correctly.
Add Dockerfile, Makefile, and MCP service definition. Add pg2sqlite
migration tool. Support $PORT env var for MCP port assignment.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 16:18:37 -07:00

95 lines
2.1 KiB
Go

package main
import (
"context"
"database/sql"
"flag"
"fmt"
"log"
"os"
"time"
"github.com/jackc/pgx/v4"
_ "modernc.org/sqlite"
)
func main() {
pgConn := flag.String("pg", "", "postgres connection string (e.g. postgres://user:pass@host:5432/kls?sslmode=verify-full)")
out := flag.String("out", "kls.db", "output sqlite file path")
flag.Parse()
if *pgConn == "" {
fmt.Fprintln(os.Stderr, "usage: pg2sqlite -pg <postgres-url> [-out kls.db]")
os.Exit(1)
}
ctx := context.Background()
// Connect to Postgres
pg, err := pgx.Connect(ctx, *pgConn)
if err != nil {
log.Fatalf("postgres: %v", err)
}
defer pg.Close(ctx)
// Open SQLite
os.Remove(*out)
lite, err := sql.Open("sqlite", *out)
if err != nil {
log.Fatalf("sqlite open: %v", err)
}
defer lite.Close()
_, err = lite.ExecContext(ctx, `CREATE TABLE urls (
id TEXT PRIMARY KEY,
url TEXT NOT NULL,
nurl TEXT NOT NULL,
short TEXT NOT NULL UNIQUE,
created_at TEXT NOT NULL
)`)
if err != nil {
log.Fatalf("sqlite create table: %v", err)
}
// Read from Postgres
rows, err := pg.Query(ctx, `SELECT id, url, nurl, short, created_at FROM urls ORDER BY created_at`)
if err != nil {
log.Fatalf("postgres query: %v", err)
}
defer rows.Close()
tx, err := lite.BeginTx(ctx, nil)
if err != nil {
log.Fatalf("sqlite begin: %v", err)
}
stmt, err := tx.PrepareContext(ctx, `INSERT INTO urls (id, url, nurl, short, created_at) VALUES (?, ?, ?, ?, ?)`)
if err != nil {
log.Fatalf("sqlite prepare: %v", err)
}
defer stmt.Close()
var n int
for rows.Next() {
var id, url, nurl, short string
var createdAt time.Time
if err := rows.Scan(&id, &url, &nurl, &short, &createdAt); err != nil {
log.Fatalf("postgres scan: %v", err)
}
if _, err := stmt.ExecContext(ctx, id, url, nurl, short, createdAt.Format(time.RFC3339)); err != nil {
log.Fatalf("sqlite insert: %v", err)
}
n++
}
if err := rows.Err(); err != nil {
log.Fatalf("postgres rows: %v", err)
}
if err := tx.Commit(); err != nil {
log.Fatalf("sqlite commit: %v", err)
}
log.Printf("migrated %d rows to %s", n, *out)
}