You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
senzapaura_es/scripts/db/sembrar-glosario.mjs

103 lines
2.9 KiB

/**
* Carga el glosario del taller.
*
* npm run db:glosario
*
* Veintiocho términos con sus acepciones numeradas y las formas con las que
* aparecen de verdad en el texto. Es lo que hace posible el marcado: sin las
* variantes, «sinalefas» en plural no se reconocería y nadie echaría en falta
* el globo que no salió.
*
* Idempotente por slug: reimportar una definición corregida actualiza. Las
* acepciones se rehacen enteras —se borran y se vuelven a poner— porque su
* número es su identidad y renumerar a mano dejaría huecos.
*/
import fs from 'node:fs';
import pg from 'pg';
const SEMILLA = JSON.parse(fs.readFileSync('scripts/db/semilla-glosario.json', 'utf8'));
const slugificar = (t) =>
t
.toLowerCase()
.normalize('NFD')
.replace(/[̀-ͯ]/g, '')
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-+|-+$/g, '');
const c = new pg.Client({ connectionString: process.env.DATABASE_URL, query_timeout: 60_000 });
await c.connect();
await c.query('BEGIN');
const contado = { termino: 0, acepcion: 0, variante: 0 };
const avisos = [];
try {
const vistos = new Set();
for (const t of SEMILLA.terminos) {
const slug = slugificar(t.termino);
if (vistos.has(slug)) {
avisos.push(`«${t.termino}» sale dos veces en la semilla`);
continue;
}
vistos.add(slug);
const { rows } = await c.query(
`INSERT INTO termino (id, slug, termino) VALUES ($1,$2,$3)
ON CONFLICT (slug) DO UPDATE SET termino = EXCLUDED.termino
RETURNING id`,
[crypto.randomUUID(), slug, t.termino]
);
const terminoId = rows[0].id;
contado.termino++;
await c.query('DELETE FROM acepcion WHERE termino_id = $1', [terminoId]);
for (const [i, a] of t.acepciones.entries()) {
await c.query(
`INSERT INTO acepcion (id, termino_id, numero, categoria, definicion, ampliacion, ejemplo)
VALUES ($1,$2,$3,$4,$5,$6,$7)`,
[
crypto.randomUUID(),
terminoId,
i + 1,
a.categoria,
a.definicion,
a.ampliacion ?? null,
a.ejemplo ?? null
]
);
contado.acepcion++;
}
/*
* El propio término también es una forma buscable, así no hay que
* repetirlo en la lista de variantes de los veintiocho.
*/
await c.query('DELETE FROM termino_variante WHERE termino_id = $1', [terminoId]);
for (const forma of new Set([t.termino, ...(t.variantes ?? [])])) {
await c.query(
'INSERT INTO termino_variante (termino_id, forma) VALUES ($1,$2) ON CONFLICT DO NOTHING',
[terminoId, forma.toLowerCase()]
);
contado.variante++;
}
}
await c.query('COMMIT');
} catch (fallo) {
await c.query('ROLLBACK').catch(() => {});
console.error('Falló, no se ha escrito nada:');
console.error(' ' + fallo.message);
await c.end();
process.exit(1);
}
await c.end();
for (const [que, n] of Object.entries(contado)) console.log(` ${que.padEnd(10)} ${n}`);
for (const aviso of avisos) console.log(` aviso: ${aviso}`);
console.log('');
console.log('Glosario cargado.');

Powered by TurnKey Linux.