81 lines
2.3 KiB
JavaScript
81 lines
2.3 KiB
JavaScript
import 'dotenv/config';
|
|
import split2 from 'split2';
|
|
import { from as copyFrom } from 'pg-copy-streams';
|
|
import { createReadStream } from 'node:fs';
|
|
import { Transform } from 'node:stream';
|
|
import { pipeline } from 'node:stream/promises';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { getPool, close } from './index.js';
|
|
|
|
const FIXTURE = fileURLToPath(new URL('./fixtures/notes.jsonl', import.meta.url));
|
|
|
|
const COLUMNS = ['id', 'text', 'x', 'y', 'author', 'color'];
|
|
|
|
const DEFAULTS = { x: 0, y: 0, color: 'yellow' };
|
|
|
|
const csvField = (value) => {
|
|
if (value === null || value === undefined) return '';
|
|
return `"${String(value).replaceAll('"', '""')}"`;
|
|
};
|
|
|
|
const toCsvRows = () => new Transform({
|
|
writableObjectMode: true,
|
|
transform(line, _encoding, callback) {
|
|
if (line.trim().length === 0) {
|
|
callback();
|
|
return;
|
|
}
|
|
|
|
let note;
|
|
try {
|
|
note = JSON.parse(line);
|
|
} catch {
|
|
callback(new Error(`Fixture contains a malformed JSON line: ${line.slice(0, 80)}`));
|
|
return;
|
|
}
|
|
|
|
const row = COLUMNS.map((col) => csvField(note[col] ?? DEFAULTS[col]));
|
|
callback(null, `${row.join(',')}\n`);
|
|
},
|
|
});
|
|
|
|
const run = async () => {
|
|
const client = await getPool().connect();
|
|
|
|
try {
|
|
await client.query('BEGIN');
|
|
|
|
// COPY has no ON CONFLICT, so land the fixture in a temp table first and
|
|
// let a single INSERT ... SELECT apply the existing idempotency.
|
|
await client.query(
|
|
'CREATE TEMP TABLE notes_import (LIKE notes INCLUDING DEFAULTS) ON COMMIT DROP'
|
|
);
|
|
|
|
const copy = client.query(
|
|
copyFrom(`COPY notes_import (${COLUMNS.join(', ')}) FROM STDIN WITH (FORMAT csv)`)
|
|
);
|
|
|
|
await pipeline(createReadStream(FIXTURE), split2(), toCsvRows(), copy);
|
|
|
|
const { rowCount: staged } = await client.query('SELECT 1 FROM notes_import');
|
|
const { rowCount: inserted } = await client.query(
|
|
`INSERT INTO notes (${COLUMNS.join(', ')})
|
|
SELECT ${COLUMNS.join(', ')} FROM notes_import
|
|
ON CONFLICT (id) DO NOTHING`
|
|
);
|
|
|
|
await client.query('COMMIT');
|
|
|
|
console.log(`Seed complete — ${inserted} notes inserted (${staged - inserted} already existed).`);
|
|
} catch (err) {
|
|
await client.query('ROLLBACK').catch(() => {});
|
|
console.error('Seed failed:', err.message);
|
|
process.exitCode = 1;
|
|
} finally {
|
|
client.release();
|
|
await close();
|
|
}
|
|
};
|
|
|
|
run();
|