const { expect } = require('chai') const sqlite3 = require('sqlite3') const { normalizeJson, isIntegerCompatible, findOverlongVarcharValues, findIntegerTypeIssues } = require('../../../server/scripts/migrateSqliteToPostgres') function openMemoryDb() { return new Promise((resolve, reject) => { const db = new sqlite3.Database(':memory:', (error) => { if (error) return reject(error) resolve(db) }) }) } function run(db, sql, params = []) { return new Promise((resolve, reject) => { db.run(sql, params, (error) => { if (error) return reject(error) resolve() }) }) } function close(db) { return new Promise((resolve, reject) => { db.close((error) => { if (error) return reject(error) resolve() }) }) } describe('migrateSqliteToPostgres script helpers', () => { it('should keep malformed JSON payloads insertable by returning valid JSON text', () => { const malformed = '"{"x",1}"' const normalized = normalizeJson(malformed) expect(() => JSON.parse(normalized)).to.not.throw() expect(JSON.parse(normalized)).to.equal('"{"x",1}"') }) it('should detect overlong varchar values before migration', async () => { const db = await openMemoryDb() try { await run(db, 'CREATE TABLE books (subtitle TEXT)') await run(db, 'INSERT INTO books (subtitle) VALUES (?)', ['x'.repeat(300)]) await run(db, 'INSERT INTO books (subtitle) VALUES (?)', ['ok']) const tablesToMigrate = [{ sqliteTable: 'books', postgresTable: 'books' }] const pgColumnsByTable = new Map([ [ 'books', new Map([ [ 'subtitle', { column_name: 'subtitle', data_type: 'character varying', character_maximum_length: 255 } ] ]) ] ]) const issues = await findOverlongVarcharValues(db, tablesToMigrate, pgColumnsByTable) expect(issues).to.have.length(1) expect(issues[0]).to.include({ sqliteTable: 'books', sqliteColumn: 'subtitle', postgresTable: 'books', postgresColumn: 'subtitle', maxLength: 255, actualMaxLength: 300, overCount: 1 }) } finally { await close(db) } }) it('should detect non-integer values for integer target columns', async () => { const db = await openMemoryDb() try { await run(db, 'CREATE TABLE playbackSessions (timeListening REAL)') await run(db, 'INSERT INTO playbackSessions (timeListening) VALUES (?)', [25.802536999999997]) await run(db, 'INSERT INTO playbackSessions (timeListening) VALUES (?)', [42]) const tablesToMigrate = [{ sqliteTable: 'playbackSessions', postgresTable: 'playbackSessions' }] const pgColumnsByTable = new Map([ [ 'playbackSessions', new Map([ [ 'timelistening', { column_name: 'timeListening', data_type: 'integer' } ] ]) ] ]) const issues = await findIntegerTypeIssues(db, tablesToMigrate, pgColumnsByTable) expect(issues).to.have.length(1) expect(issues[0].sqliteTable).to.equal('playbackSessions') expect(issues[0].sqliteColumn).to.equal('timeListening') expect(issues[0].postgresType).to.equal('integer') expect(issues[0].badCount).to.equal(1) } finally { await close(db) } }) it('should only accept integer-compatible values for integer columns', () => { expect(isIntegerCompatible(10)).to.equal(true) expect(isIntegerCompatible('10')).to.equal(true) expect(isIntegerCompatible(10.5)).to.equal(false) expect(isIntegerCompatible('10.5')).to.equal(false) }) })