mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
104 lines
3.9 KiB
JavaScript
104 lines
3.9 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Dev-DB runner for the EDR freight database. psql is NOT installed on this
|
|
* machine; this is the sanctioned way to query, EXPLAIN-validate, and inspect
|
|
* the remote dev DB. Resolves `pg` from apps/edr-freight-api so it runs from
|
|
* anywhere in the repo.
|
|
*
|
|
* node .claude/skills/edr-db/query.cjs "SELECT ... " run SQL (console.table)
|
|
* node .claude/skills/edr-db/query.cjs explain "SELECT..." EXPLAIN-validate only
|
|
* node .claude/skills/edr-db/query.cjs columns <table> list freight.<table> columns
|
|
* node .claude/skills/edr-db/query.cjs migrations [like] freight/iam migration rows
|
|
* node .claude/skills/edr-db/query.cjs drift <table> columns vs entity check helper
|
|
*
|
|
* Connection: DB_HOST/DB_PORT/DB_USER/DB_PASSWORD/DB_NAME env vars, falling
|
|
* back to the shared dev database.
|
|
*/
|
|
const path = require('path');
|
|
const { createRequire } = require('module');
|
|
|
|
const repoRoot = path.resolve(__dirname, '..', '..', '..');
|
|
const apiRequire = createRequire(
|
|
path.join(repoRoot, 'apps', 'edr-freight-api', 'package.json'),
|
|
);
|
|
const { Client } = apiRequire('pg');
|
|
|
|
const cfg = {
|
|
host: process.env.DB_HOST ?? '10.18.7.207',
|
|
port: parseInt(process.env.DB_PORT ?? '5432', 10),
|
|
user: process.env.DB_USER ?? 'postgres',
|
|
password: process.env.DB_PASSWORD ?? 'dcba@1234',
|
|
database: process.env.DB_NAME ?? 'edr_dev',
|
|
};
|
|
|
|
const [, , first, ...rest] = process.argv;
|
|
|
|
async function main() {
|
|
if (!first) {
|
|
console.error('usage: query.cjs "<sql>" | explain "<sql>" | columns <table> | migrations [like] | drift <table>');
|
|
process.exit(2);
|
|
}
|
|
const c = new Client(cfg);
|
|
await c.connect();
|
|
try {
|
|
if (first === 'columns') {
|
|
const r = await c.query(
|
|
`SELECT column_name, data_type, is_nullable, column_default
|
|
FROM information_schema.columns
|
|
WHERE table_schema='freight' AND table_name=$1
|
|
ORDER BY ordinal_position`,
|
|
[rest[0]],
|
|
);
|
|
console.table(r.rows);
|
|
} else if (first === 'migrations') {
|
|
const like = rest[0] ? `%${rest[0]}%` : '%';
|
|
// Histories are split per owner: freight.migrations (this app) and
|
|
// iam.typeorm_migrations (@tria-plc/iamapi-common). public.migrations is the
|
|
// pre-split table, kept for rollback — read it only if the split has not
|
|
// been applied to this DB yet.
|
|
const sources = [
|
|
['freight', 'freight.migrations'],
|
|
['iam', 'iam.typeorm_migrations'],
|
|
['legacy', 'public.migrations'],
|
|
];
|
|
const rows = [];
|
|
for (const [owner, table] of sources) {
|
|
const present = await c.query(`SELECT to_regclass($1) IS NOT NULL AS ok`, [table]);
|
|
if (!present.rows[0].ok) continue;
|
|
const r = await c.query(
|
|
`SELECT id, timestamp, name FROM ${table}
|
|
WHERE name ILIKE $1 ORDER BY id DESC LIMIT 40`,
|
|
[like],
|
|
);
|
|
rows.push(...r.rows.map((row) => ({ owner, ...row })));
|
|
}
|
|
console.table(rows);
|
|
} else if (first === 'drift') {
|
|
// Quick drift signal: DB columns for the table. Compare by eye against
|
|
// the entity's @Column names; a recorded-but-absent column = drift.
|
|
const r = await c.query(
|
|
`SELECT column_name FROM information_schema.columns
|
|
WHERE table_schema='freight' AND table_name=$1 ORDER BY column_name`,
|
|
[rest[0]],
|
|
);
|
|
console.log(r.rows.map((x) => x.column_name).join('\n'));
|
|
} else if (first === 'explain') {
|
|
await c.query('EXPLAIN ' + rest.join(' '));
|
|
console.log('OK — statement is valid against', cfg.database);
|
|
} else {
|
|
const sql = [first, ...rest].join(' ');
|
|
const started = Date.now();
|
|
const r = await c.query(sql);
|
|
if (Array.isArray(r.rows) && r.rows.length) console.table(r.rows);
|
|
console.log(`${r.rowCount ?? 0} row(s), ${Date.now() - started}ms`);
|
|
}
|
|
} finally {
|
|
await c.end();
|
|
}
|
|
}
|
|
|
|
main().catch((e) => {
|
|
console.error('FAIL:', e.message);
|
|
process.exit(1);
|
|
});
|