59 lines
1.9 KiB
JavaScript
59 lines
1.9 KiB
JavaScript
// 2026-03-21 — js-idempotent: INSERT с проверкой по idempotency_key.
|
||
// Повторный вызов с тем же key НЕ создаёт дубль — возвращает существующую запись.
|
||
// Тестирует: идемпотентность через SELECT ... FOR UPDATE + условный INSERT.
|
||
const { Client } = require('pg');
|
||
|
||
async function run(event) {
|
||
const key = String(event.idempotency_key ?? `auto-${Date.now()}`).slice(0, 200);
|
||
const title = String(event.title ?? key).slice(0, 255);
|
||
|
||
const client = new Client({
|
||
host: process.env.PGHOST,
|
||
port: parseInt(process.env.PGPORT ?? '5432'),
|
||
database: process.env.PGDATABASE,
|
||
user: process.env.PGUSER,
|
||
password: process.env.PGPASSWORD,
|
||
ssl: { rejectUnauthorized: false },
|
||
});
|
||
await client.connect();
|
||
|
||
try {
|
||
await client.query('BEGIN');
|
||
|
||
// Ищем существующую запись по title (используем как idempotency key)
|
||
const existing = await client.query(
|
||
'SELECT id, title, created_at FROM terraform_demo_table WHERE title = $1 LIMIT 1 FOR UPDATE',
|
||
[key]
|
||
);
|
||
|
||
let action, row;
|
||
if (existing.rows.length > 0) {
|
||
action = 'existing';
|
||
row = existing.rows[0];
|
||
} else {
|
||
const ins = await client.query(
|
||
'INSERT INTO terraform_demo_table (title) VALUES ($1) RETURNING id, title, created_at',
|
||
[key]
|
||
);
|
||
action = 'created';
|
||
row = ins.rows[0];
|
||
}
|
||
|
||
await client.query('COMMIT');
|
||
return {
|
||
action,
|
||
id: row.id,
|
||
title: row.title,
|
||
created_at: row.created_at,
|
||
idempotency_key: key,
|
||
};
|
||
} catch (e) {
|
||
await client.query('ROLLBACK');
|
||
throw e;
|
||
} finally {
|
||
await client.end();
|
||
}
|
||
}
|
||
|
||
module.exports = { run };
|