This commit is contained in:
KS Jannette
2026-08-01 01:42:43 -04:00
parent 62477d009c
commit 7b47e46852
3 changed files with 181 additions and 184 deletions

View File

@@ -7,105 +7,104 @@ import { batch } from '../lib/streams.js';
const SELECT_NOTES = 'SELECT id, text, x, y, author, color FROM notes ORDER BY id';
// Postgres caps a statement at 65535 bind parameters; six columns per note
// leaves 10922 as the hard ceiling, so stay well under it.
// leaves 10922 as the hard ceiling.
const INSERT_BATCH_SIZE = 1000;
export const getAllNotes = async () => {
const { rows } = await query(SELECT_NOTES);
return rows;
const { rows } = await query(SELECT_NOTES);
return rows;
};
/**
* Streams every note as an object-mode Readable. The pooled client is checked
* out for the life of the stream and released once it ends, errors, or is
* destroyed early by a consumer.
* Streams every note as an object-mode Readable. The pooled client is released on end, error, or
* destruction by consumer.
*
* @returns {Promise<import('node:stream').Readable>}
*/
export const streamAllNotes = async () => {
const client = await getPool().connect();
const client = await getPool().connect();
let released = false;
const release = () => {
if (released) return;
released = true;
client.release();
};
let released = false;
const release = () => {
if (released) return;
released = true;
client.release();
};
try {
const rows = client.query(new QueryStream(SELECT_NOTES));
rows.once('end', release);
rows.once('error', release);
rows.once('close', release);
return rows;
} catch (err) {
release();
throw err;
}
try {
const rows = client.query(new QueryStream(SELECT_NOTES));
rows.once('end', release);
rows.once('error', release);
rows.once('close', release);
return rows;
} catch (err) {
release();
throw err;
}
};
export const getNoteById = async (id) => {
const { rows } = await query(
'SELECT id, text, x, y, author, color FROM notes WHERE id = $1',
[id]
);
return rows[0] || null;
const { rows } = await query(
'SELECT id, text, x, y, author, color FROM notes WHERE id = $1',
[id]
);
return rows[0] || null;
};
export const createNote = async (note) => {
const { rows } = await query(
`INSERT INTO notes (id, text, x, y, author, color)
const { rows } = await query(
`INSERT INTO notes (id, text, x, y, author, color)
VALUES ($1, $2, $3, $4, $5, $6)
RETURNING id, text, x, y, author, color`,
[note.id, note.text, note.x ?? 0, note.y ?? 0, note.author, note.color ?? 'yellow']
);
return rows[0];
[note.id, note.text, note.x ?? 0, note.y ?? 0, note.author, note.color ?? 'yellow']
);
return rows[0];
};
const insertNoteBatch = async (notes) => {
const values = [];
const placeholders = [];
const values = [];
const placeholders = [];
notes.forEach((note, i) => {
const offset = i * 6;
placeholders.push(
`($${offset + 1}, $${offset + 2}, $${offset + 3}, $${offset + 4}, $${offset + 5}, $${offset + 6})`
);
values.push(
note.id,
note.text,
note.x ?? 0,
note.y ?? 0,
note.author,
note.color ?? 'yellow'
);
});
notes.forEach((note, i) => {
const offset = i * 6;
placeholders.push(
`($${offset + 1}, $${offset + 2}, $${offset + 3}, $${offset + 4}, $${offset + 5}, $${offset + 6})`
);
values.push(
note.id,
note.text,
note.x ?? 0,
note.y ?? 0,
note.author,
note.color ?? 'yellow'
);
});
const { rows } = await query(
`INSERT INTO notes (id, text, x, y, author, color)
const { rows } = await query(
`INSERT INTO notes (id, text, x, y, author, color)
VALUES ${placeholders.join(', ')}
RETURNING id, text, x, y, author, color`,
values
);
return rows;
values
);
return rows;
};
export const createNotes = async (notes) => {
if (!notes || notes.length === 0) {
return [];
}
const inserted = [];
await pipeline(
Readable.from(notes, { objectMode: true }),
batch(INSERT_BATCH_SIZE),
async (batches) => {
for await (const chunk of batches) {
inserted.push(...await insertNoteBatch(chunk));
}
if (!notes || notes.length === 0) {
return [];
}
);
return inserted;
const inserted = [];
await pipeline(
Readable.from(notes, { objectMode: true }),
batch(INSERT_BATCH_SIZE),
async (batches) => {
for await (const chunk of batches) {
inserted.push(...await insertNoteBatch(chunk));
}
}
);
return inserted;
};