Files
Apiflow/src/routes/schema.js
T
MichaelandClaude Sonnet 4.6 d565ed9f10 Initial commit : API Node.js + PostgreSQL + sync service Docker
- API Express/pg connectée à PostgreSQL (converti depuis mssql)
- 8 routes : articles, fournisseurs, commandes, stock, mouvements, performance, schema, sync
- Service sync nightly (mssql → pg, cron 3h00)
- Docker Compose : postgres + api + sync + frpc (tunnel sortant)
- Schéma PostgreSQL 17 tables dans postgres/init.sql

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 10:10:47 +01:00

137 lines
4.3 KiB
JavaScript

const express = require('express');
const router = express.Router();
const { getPool } = require('../config/database');
// GET /api/schema - Structure complète de la base de données
router.get('/', async (req, res) => {
try {
const pool = getPool();
const result = await pool.query(`
SELECT
table_schema AS TABLE_SCHEMA,
table_name AS TABLE_NAME,
table_type AS TABLE_TYPE,
column_name AS COLUMN_NAME,
ordinal_position AS ORDINAL_POSITION,
data_type AS DATA_TYPE,
character_maximum_length AS CHARACTER_MAXIMUM_LENGTH,
numeric_precision AS NUMERIC_PRECISION,
numeric_scale AS NUMERIC_SCALE,
is_nullable AS IS_NULLABLE,
column_default AS COLUMN_DEFAULT
FROM information_schema.tables
JOIN information_schema.columns USING (table_schema, table_name)
WHERE table_schema = 'public'
ORDER BY table_name, ordinal_position
`);
const schema = {};
for (const row of result.rows) {
const key = `${row.table_schema}.${row.table_name}`;
if (!schema[key]) {
schema[key] = {
schema: row.table_schema,
table: row.table_name,
type: row.table_type,
columns: [],
};
}
schema[key].columns.push({
name: row.column_name,
position: row.ordinal_position,
type: row.data_type,
maxLength: row.character_maximum_length,
precision: row.numeric_precision,
scale: row.numeric_scale,
nullable: row.is_nullable === 'YES',
default: row.column_default,
});
}
const tables = Object.values(schema);
res.json({
database: process.env.PG_DB,
server: process.env.PG_HOST,
tableCount: tables.filter(t => t.type === 'BASE TABLE').length,
viewCount: tables.filter(t => t.type === 'VIEW').length,
tables,
});
} catch (err) {
res.status(500).json({ error: 'Erreur connexion base de données', detail: err.message });
}
});
// GET /api/schema/tables?search= - Liste des tables avec nombre de lignes (estimé)
router.get('/tables', async (req, res) => {
try {
const pool = getPool();
const search = req.query.search || '';
const result = await pool.query(`
SELECT
schemaname AS TABLE_SCHEMA,
tablename AS TABLE_NAME,
'BASE TABLE' AS TABLE_TYPE,
n_live_tup AS ROW_COUNT
FROM pg_stat_user_tables
WHERE tablename LIKE $1
ORDER BY n_live_tup DESC, tablename
`, [`%${search}%`]);
res.json({ count: result.rows.length, tables: result.rows });
} catch (err) {
res.status(500).json({ error: 'Erreur connexion base de données', detail: err.message });
}
});
// GET /api/schema/top?limit= - Top tables par nombre de lignes
router.get('/top', async (req, res) => {
try {
const pool = getPool();
const limitNum = Math.max(1, Math.min(parseInt(req.query.limit) || 50, 200));
const result = await pool.query(`
SELECT tablename AS TABLE_NAME, 'BASE TABLE' AS TABLE_TYPE, n_live_tup AS ROW_COUNT
FROM pg_stat_user_tables
ORDER BY n_live_tup DESC
LIMIT $1
`, [limitNum]);
res.json({ tables: result.rows });
} catch (err) {
res.status(500).json({ error: 'Erreur connexion base de données', detail: err.message });
}
});
// GET /api/schema/tables/:tableName - Colonnes d'une table
router.get('/tables/:tableName', async (req, res) => {
try {
const pool = getPool();
const result = await pool.query(`
SELECT
column_name AS COLUMN_NAME,
ordinal_position AS ORDINAL_POSITION,
data_type AS DATA_TYPE,
character_maximum_length AS CHARACTER_MAXIMUM_LENGTH,
numeric_precision AS NUMERIC_PRECISION,
numeric_scale AS NUMERIC_SCALE,
is_nullable AS IS_NULLABLE,
column_default AS COLUMN_DEFAULT
FROM information_schema.columns
WHERE table_name = $1 AND table_schema = 'public'
ORDER BY ordinal_position
`, [req.params.tableName]);
if (!result.rows.length)
return res.status(404).json({ error: `Table '${req.params.tableName}' introuvable` });
res.json({ table: req.params.tableName, columns: result.rows });
} catch (err) {
res.status(500).json({ error: 'Erreur connexion base de données', detail: err.message });
}
});
module.exports = router;